Guest User

Untitled

a guest
Jul 2nd, 2018
224
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. From cdc09db23b9a82500809c4ca9a370901d0e4b44a Mon Sep 17 00:00:00 2001
  2. From: "he.who.shall.not.be.named" <notreply@example.com>
  3. Date: Mon, 2 Apr 2018 22:13:58 -0700
  4. Subject: [PATCH] lavf: add vapoursynth demuxer
  5.  
  6. ---
  7.  configure                 |   4 +
  8.  libavformat/Makefile      |   1 +
  9.  libavformat/allformats.c  |   1 +
  10.  libavformat/vapoursynth.c | 372 ++++++++++++++++++++++++++++++++++++++++++++++
  11.  4 files changed, 378 insertions(+)
  12.  create mode 100644 libavformat/vapoursynth.c
  13.  
  14. diff --git a/configure b/configure
  15. index 08d6fc5983..921e09d1ca 100755
  16. --- a/configure
  17. +++ b/configure
  18. @@ -303,6 +303,7 @@ External library support:
  19.    --disable-sdl2           disable sdl2 [autodetect]
  20.    --disable-securetransport disable Secure Transport, needed for TLS support
  21.                             on OSX if openssl and gnutls are not used [autodetect]
  22. +  --enable-vapoursynth     enable reading of VapourSynth script files [no]
  23.    --disable-xlib           disable xlib [autodetect]
  24.    --disable-zlib           disable zlib [autodetect]
  25.  
  26. @@ -1724,6 +1725,7 @@ EXTERNAL_LIBRARY_LIST="
  27.     mediacodec
  28.     openal
  29.     opengl
  30. +    vapoursynth
  31. "
  32.  
  33.  HWACCEL_AUTODETECT_LIBRARY_LIST="
  34. @@ -3085,6 +3087,7 @@ libx265_encoder_deps="libx265"
  35. libxavs_encoder_deps="libxavs"
  36. libxvid_encoder_deps="libxvid"
  37. libzvbi_teletext_decoder_deps="libzvbi"
  38. +vapoursynth_demuxer_deps="vapoursynth"
  39. videotoolbox_suggest="coreservices"
  40. videotoolbox_deps="corefoundation coremedia corevideo"
  41. videotoolbox_encoder_deps="videotoolbox VTCompressionSessionPrepareToEncodeFrames"
  42. @@ -6122,6 +6125,7 @@ enabled rkmpp             && { require_pkg_config rkmpp rockchip_mpp  rockchip/r
  43.                                { enabled libdrm ||
  44.                                  die "ERROR: rkmpp requires --enable-libdrm"; }
  45.                              }
  46. +enabled vapoursynth       && require_pkg_config vapoursynth "vapoursynth-script >= 43" vapoursynth/VSScript.h vsscript_init
  47.  
  48. if enabled gcrypt; then
  49.     GCRYPT_CONFIG="${cross_prefix}libgcrypt-config"
  50. diff --git a/libavformat/Makefile b/libavformat/Makefile
  51. index af0823a7db..2cdbdcab07 100644
  52. --- a/libavformat/Makefile
  53. +++ b/libavformat/Makefile
  54. @@ -569,6 +569,7 @@ OBJS-$(CONFIG_LIBRTMPTE_PROTOCOL)        += librtmp.o
  55. OBJS-$(CONFIG_LIBSRT_PROTOCOL)           += libsrt.o
  56. OBJS-$(CONFIG_LIBSSH_PROTOCOL)           += libssh.o
  57. OBJS-$(CONFIG_LIBSMBCLIENT_PROTOCOL)     += libsmbclient.o
  58. +OBJS-$(CONFIG_VAPOURSYNTH_DEMUXER)       += vapoursynth.o
  59.  
  60. # protocols I/O
  61. OBJS-$(CONFIG_ASYNC_PROTOCOL)            += async.o
  62. diff --git a/libavformat/allformats.c b/libavformat/allformats.c
  63. index d8d733735a..c358dff671 100644
  64. --- a/libavformat/allformats.c
  65. +++ b/libavformat/allformats.c
  66. @@ -408,6 +408,7 @@ extern AVInputFormat  ff_txd_demuxer;
  67. extern AVInputFormat  ff_tty_demuxer;
  68. extern AVInputFormat  ff_ty_demuxer;
  69. extern AVOutputFormat ff_uncodedframecrc_muxer;
  70. +extern AVInputFormat  ff_vapoursynth_demuxer;
  71. extern AVInputFormat  ff_v210_demuxer;
  72. extern AVInputFormat  ff_v210x_demuxer;
  73. extern AVInputFormat  ff_vag_demuxer;
  74. diff --git a/libavformat/vapoursynth.c b/libavformat/vapoursynth.c
  75. new file mode 100644
  76. index 0000000000..ea07e1558e
  77. --- /dev/null
  78. +++ b/libavformat/vapoursynth.c
  79. @@ -0,0 +1,372 @@
  80. +/*
  81. + * VapourSynth support
  82. + * Copyright (c) 2020 Fredrik Melbin
  83. + *
  84. + * This file is part of FFmpeg
  85. + *
  86. + * FFmpeg is free software; you can redistribute it and/or
  87. + * modify it under the terms of the GNU Lesser General Public
  88. + * License as published by the Free Software Foundation; either
  89. + * version 2.1 of the License, or (at your option) any later version.
  90. + *
  91. + * FFmpeg is distributed in the hope that it will be useful,
  92. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  93. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  94. + * Lesser General Public License for more details.
  95. + *
  96. + * You should have received a copy of the GNU Lesser General Public
  97. + * License along with FFmpeg; if not, write to the Free Software
  98. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  99. + */
  100. +
  101. +#include <stdatomic.h>
  102. +
  103. +#include "libavutil/attributes.h"
  104. +#include "libavutil/cpu.h"
  105. +#include "libavutil/internal.h"
  106. +#include "libavutil/time.h"
  107. +
  108. +#include "libavcodec/internal.h"
  109. +
  110. +#include "avformat.h"
  111. +#include "internal.h"
  112. +#include "config.h"
  113. +
  114. +#include <vapoursynth/VSScript.h>
  115. +#include <vapoursynth/VSHelper.h>
  116. +
  117. +typedef struct VapourSynthContext {
  118. +    const VSAPI *vsapi;
  119. +    VSScript *script;
  120. +    VSNodeRef *node;
  121. +    const VSVideoInfo *vi;
  122. +    int curr_frame;
  123. +    int ncpu;
  124. +    int async_pending;
  125. +} VapourSynthContext;
  126. +
  127. +static void VS_CC async_callback(void *user_data, const VSFrameRef *f, int n,
  128. +                                 VSNodeRef *node, const char *error_msg)
  129. +{
  130. +    AVFormatContext *s = user_data;
  131. +    VapourSynthContext *vs = s->priv_data;
  132. +
  133. +    if (!f) {
  134. +        av_log(s, AV_LOG_WARNING, "async frame request failed: %s\n",
  135. +               error_msg);
  136. +    }
  137. +
  138. +    vs->vsapi->freeFrame(f);
  139. +    atomic_fetch_sub(&vs->async_pending, 1);
  140. +}
  141. +
  142. +static av_cold int map_vsformat(AVFormatContext *s, AVStream *st,
  143. +                                const VSFormat *vsformat)
  144. +{
  145. +    if (vsformat->subSamplingW > 2 || vsformat->subSamplingH > 2)
  146. +        return AV_PIX_FMT_NONE;
  147. +
  148. +    switch (vsformat->colorFamily) {
  149. +    case cmGray:
  150. +        switch (vsformat->bitsPerSample) {
  151. +        case 8: return AV_PIX_FMT_GRAY8;
  152. +        case 9: return AV_PIX_FMT_GRAY9;
  153. +        case 10: return AV_PIX_FMT_GRAY10;
  154. +        case 12: return AV_PIX_FMT_GRAY12;
  155. +        case 16: return AV_PIX_FMT_GRAY16;
  156. +        default: return AV_PIX_FMT_NONE;
  157. +        }
  158. +    case cmRGB:
  159. +        switch (vsformat->bitsPerSample) {
  160. +        case 8: return AV_PIX_FMT_GBRP;
  161. +        case 9: return AV_PIX_FMT_GBRP9;
  162. +        case 10: return AV_PIX_FMT_GBRP10;
  163. +        case 12: return AV_PIX_FMT_GBRP12;
  164. +        case 14: return AV_PIX_FMT_GBRP14;
  165. +        case 16: return AV_PIX_FMT_GBRP16;
  166. +        default: return AV_PIX_FMT_NONE;
  167. +        }
  168. +    case cmYUV:
  169. +    case cmYCoCg:
  170. +        switch ((vsformat->subSamplingW << 2) | vsformat->subSamplingH) {
  171. +        case ((0 << 2) | 0): /* 4:4:4 */
  172. +            switch (vsformat->bitsPerSample) {
  173. +            case 8: return AV_PIX_FMT_YUV444P;
  174. +            case 9: return AV_PIX_FMT_YUV444P9;
  175. +            case 10: return AV_PIX_FMT_YUV444P10;
  176. +            case 12: return AV_PIX_FMT_YUV444P12;
  177. +            case 14: return AV_PIX_FMT_YUV444P14;
  178. +            case 16: return AV_PIX_FMT_YUV444P16;
  179. +            default: return AV_PIX_FMT_NONE;
  180. +            }
  181. +        case ((0 << 2) | 1): /* 4:4:0 */
  182. +            switch (vsformat->bitsPerSample) {
  183. +            case 8: return AV_PIX_FMT_YUV440P;
  184. +            case 10: return AV_PIX_FMT_YUV440P10;
  185. +            case 12: return AV_PIX_FMT_YUV440P12;
  186. +            default: return AV_PIX_FMT_NONE;
  187. +            }
  188. +        case ((1 << 2) | 0): /* 4:2:2 */
  189. +            switch (vsformat->bitsPerSample) {
  190. +            case 8: return AV_PIX_FMT_YUV422P;
  191. +            case 9: return AV_PIX_FMT_YUV422P9;
  192. +            case 10: return AV_PIX_FMT_YUV422P10;
  193. +            case 12: return AV_PIX_FMT_YUV422P12;
  194. +            case 14: return AV_PIX_FMT_YUV422P14;
  195. +            case 16: return AV_PIX_FMT_YUV422P16;
  196. +            default: return AV_PIX_FMT_NONE;
  197. +            }
  198. +        case ((1 << 2) | 1): /* 4:2:0 */
  199. +            switch (vsformat->bitsPerSample) {
  200. +            case 8: return AV_PIX_FMT_YUV420P;
  201. +            case 9: return AV_PIX_FMT_YUV420P9;
  202. +            case 10: return AV_PIX_FMT_YUV420P10;
  203. +            case 12: return AV_PIX_FMT_YUV420P12;
  204. +            case 14: return AV_PIX_FMT_YUV420P14;
  205. +            case 16: return AV_PIX_FMT_YUV420P16;
  206. +            default: return AV_PIX_FMT_NONE;
  207. +            }
  208. +        case ((2 << 2) | 0): /* 4:1:1 */
  209. +            return vsformat->bitsPerSample == 8 ? AV_PIX_FMT_YUV411P
  210. +                                                : AV_PIX_FMT_NONE;
  211. +        case ((2 << 2) | 2): /* 4:1:0 */
  212. +            return vsformat->bitsPerSample == 8 ? AV_PIX_FMT_YUV410P
  213. +                                                : AV_PIX_FMT_NONE;
  214. +        }
  215. +    case cmCompat:
  216. +        switch (vsformat->id) {
  217. +        case pfCompatBGR32: return AV_PIX_FMT_RGB32;
  218. +        case pfCompatYUY2: return AV_PIX_FMT_YUYV422;
  219. +        default: return AV_PIX_FMT_NONE;
  220. +        }
  221. +    default:
  222. +        return AV_PIX_FMT_NONE;
  223. +    }
  224. +}
  225. +
  226. +static av_cold int create_video_stream(AVFormatContext *s)
  227. +{
  228. +    VapourSynthContext *vs = s->priv_data;
  229. +    const VSVideoInfo *vi = vs->vi;
  230. +    AVStream *st;
  231. +    int ret;
  232. +
  233. +    if (!isConstantFormat(vi)) {
  234. +        av_log(s, AV_LOG_ERROR,
  235. +               "can only open scripts with constant output format\n");
  236. +        return AVERROR_INVALIDDATA;
  237. +    }
  238. +
  239. +    if (!(st = avformat_new_stream(s, NULL)))
  240. +        return AVERROR_UNKNOWN;
  241. +
  242. +    st->id = 0;
  243. +    st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
  244. +    st->codecpar->codec_id   = AV_CODEC_ID_RAWVIDEO;
  245. +    st->codecpar->width      = vi->width;
  246. +    st->codecpar->height     = vi->height;
  247. +
  248. +    st->avg_frame_rate    = (AVRational) { vi->fpsNum, vi->fpsDen };
  249. +    st->start_time        = 0;
  250. +    st->duration          = vi->numFrames;
  251. +    st->nb_frames         = vi->numFrames;
  252. +    avpriv_set_pts_info(st, 32, vi->fpsDen, vi->fpsNum);
  253. +
  254. +    if ((ret = map_vsformat(s, st, vi->format)) == AV_PIX_FMT_NONE) {
  255. +        av_log(s, AV_LOG_ERROR, "no matching pixfmt for '%s'\n",
  256. +               vi->format->name);
  257. +        return AVERROR_INVALIDDATA;
  258. +    }
  259. +    st->codecpar->format = ret;
  260. +
  261. +    return 0;
  262. +}
  263. +
  264. +static av_cold int open_script(AVFormatContext *s)
  265. +{
  266. +    VapourSynthContext *vs = s->priv_data;
  267. +    int ret;
  268. +
  269. +    // Locking is required, because vsscript_evaluateScript changes the
  270. +    // process directory internally.
  271. +    if (ret = ff_lock_avformat())
  272. +        return ret;
  273. +
  274. +    if (vsscript_evaluateFile(&vs->script, s->filename, efSetWorkingDir)) {
  275. +        ff_unlock_avformat();
  276. +        av_log(s, AV_LOG_ERROR, "VapourSynth script evaluation failed\n");
  277. +        return AVERROR_EXTERNAL;
  278. +    }
  279. +
  280. +    ff_unlock_avformat();
  281. +
  282. +    if (!(vs->node = vsscript_getOutput(vs->script, 0))) {
  283. +        av_log(s, AV_LOG_ERROR, "script has no output node\n");
  284. +        ret = AVERROR_EXTERNAL;
  285. +        goto fail;
  286. +    }
  287. +
  288. +    vs->vi = vs->vsapi->getVideoInfo(vs->node);
  289. +    if (ret = create_video_stream(s))
  290. +        goto fail;
  291. +
  292. +    return 0;
  293. +fail:
  294. +    vs->vsapi->freeNode(vs->node);
  295. +    vsscript_freeScript(vs->script);
  296. +    return ret;
  297. +}
  298. +
  299. +static av_cold int read_header(AVFormatContext *s)
  300. +{
  301. +    VapourSynthContext *vs = s->priv_data;
  302. +    int ret;
  303. +
  304. +    if (!vsscript_init()) {
  305. +        av_log(s, AV_LOG_ERROR,
  306. +               "could not initialize VapourSynth environment\n");
  307. +        return AVERROR_EXTERNAL;
  308. +    }
  309. +
  310. +    if ((ret = vsscript_getApiVersion()) < VSSCRIPT_API_VERSION) {
  311. +        av_log(s, AV_LOG_ERROR, "VSScript API too old: %d vs %d\n", ret,
  312. +               VSSCRIPT_API_VERSION);
  313. +        ret = AVERROR_EXTERNAL;
  314. +        goto fail;
  315. +    }
  316. +
  317. +    if (!(vs->vsapi = vsscript_getVSApi2(VAPOURSYNTH_API_VERSION))) {
  318. +        av_log(s, AV_LOG_ERROR, "VapourSynth API too old: %d required\n",
  319. +               VAPOURSYNTH_API_VERSION);
  320. +        ret = AVERROR_EXTERNAL;
  321. +        goto fail;
  322. +    }
  323. +
  324. +    if (ret = open_script(s))
  325. +        goto fail;
  326. +
  327. +    vs->ncpu = av_cpu_count();
  328. +    return 0;
  329. +fail:
  330. +    vsscript_finalize();
  331. +    return ret;
  332. +}
  333. +
  334. +static int read_packet(AVFormatContext *s, AVPacket *pkt)
  335. +{
  336. +    static const int gbr_order[3] = { 1, 2, 0 };
  337. +
  338. +    AVStream *st = s->streams[0];
  339. +    VapourSynthContext *vs = s->priv_data;
  340. +    const VSFrameRef *vs_frame = NULL;
  341. +    uint8_t *dst_ptr;
  342. +    char errbuf[256];
  343. +    int i, n, plane, ret;
  344. +
  345. +    if (vs->curr_frame >= vs->vi->numFrames)
  346. +        return AVERROR_EOF;
  347. +
  348. +    n = vs->curr_frame++;
  349. +    if (st->discard == AVDISCARD_ALL)
  350. +        return 0;
  351. +
  352. +    pkt->size = 0;
  353. +    for (plane = 0; plane < vs->vi->format->numPlanes; ++plane) {
  354. +        int width = vs->vi->width;
  355. +        int height = vs->vi->height;
  356. +
  357. +        if (plane == 1 || plane == 2) {
  358. +            width >>= vs->vi->format->subSamplingW;
  359. +            height >>= vs->vi->format->subSamplingH;
  360. +        }
  361. +
  362. +        pkt->size += (int64_t)width * height * vs->vi->format->bytesPerSample;
  363. +    }
  364. +
  365. +    if ((ret = av_new_packet(pkt, pkt->size)) < 0)
  366. +        return ret;
  367. +
  368. +    pkt->pts = n;
  369. +    pkt->dts = n;
  370. +    pkt->duration = 1;
  371. +    pkt->stream_index = 0;
  372. +
  373. +    vs_frame = vs->vsapi->getFrame(n, vs->node, errbuf, sizeof(errbuf));
  374. +    if (!vs_frame) {
  375. +        av_log(s, AV_LOG_ERROR, "error retrieving frame %d: %s\n", n, errbuf);
  376. +        ret = AVERROR_EXTERNAL;
  377. +        goto fail;
  378. +    }
  379. +
  380. +    /* Prefetch the subsequent frames. */
  381. +    for (i = 0; i < vs->ncpu; ++i) {
  382. +        if (i >= vs->vi->numFrames - n)
  383. +            break;
  384. +        vs->vsapi->getFrameAsync(n + i, vs->node, async_callback, s);
  385. +        atomic_fetch_add(&vs->async_pending, 1);
  386. +    }
  387. +
  388. +    dst_ptr = pkt->data;
  389. +    for (plane = 0; plane < vs->vi->format->numPlanes; ++plane) {
  390. +        int src_plane = vs->vi->format->colorFamily == cmRGB ? gbr_order[plane]
  391. +                                                             : plane;
  392. +        const uint8_t *src_ptr = vs->vsapi->getReadPtr(vs_frame, src_plane);
  393. +        int width = vs->vsapi->getFrameWidth(vs_frame, src_plane);
  394. +        int height = vs->vsapi->getFrameHeight(vs_frame, src_plane);
  395. +        int stride = vs->vsapi->getStride(vs_frame, src_plane);
  396. +        int row_size = width * vs->vi->format->bytesPerSample;
  397. +
  398. +        if (vs->vi->format->id == pfCompatBGR32) {
  399. +            src_ptr += (int64_t)(height - 1) * stride;
  400. +            stride = -stride;
  401. +        }
  402. +
  403. +        vs_bitblt(dst_ptr, row_size, src_ptr, stride, row_size, height);
  404. +        dst_ptr += (int64_t)row_size * height;
  405. +    }
  406. +
  407. +    vs->vsapi->freeFrame(vs_frame);
  408. +    return 0;
  409. +fail:
  410. +    vs->vsapi->freeFrame(vs_frame);
  411. +    av_packet_unref(pkt);
  412. +    return ret;
  413. +}
  414. +
  415. +static av_cold int read_close(AVFormatContext *s)
  416. +{
  417. +    VapourSynthContext *vs = s->priv_data;
  418. +
  419. +    /* Wait for any async requests to complete. */
  420. +    while (atomic_load(&vs->async_pending)) {
  421. +        av_usleep(1000);
  422. +    }
  423. +
  424. +    vs->vsapi->freeNode(vs->node);
  425. +    vsscript_freeScript(vs->script);
  426. +    vsscript_finalize();
  427. +    return 0;
  428. +}
  429. +
  430. +static int read_seek(AVFormatContext *s, int stream_index, int64_t timestamp,
  431. +                     int flags)
  432. +{
  433. +    VapourSynthContext *vs = s->priv_data;
  434. +
  435. +    if (timestamp < 0 || timestamp > INT_MAX || timestamp >= vs->vi->numFrames)
  436. +        return AVERROR_EOF;
  437. +
  438. +    vs->curr_frame = timestamp;
  439. +    return 0;
  440. +}
  441. +
  442. +AVInputFormat ff_vapoursynth_demuxer = {
  443. +    .name           = "vapoursynth",
  444. +    .long_name      = NULL_IF_CONFIG_SMALL("VapourSynth script"),
  445. +    .priv_data_size = sizeof(VapourSynthContext),
  446. +    .read_header    = read_header,
  447. +    .read_packet    = read_packet,
  448. +    .read_close     = read_close,
  449. +    .read_seek      = read_seek,
  450. +    .extensions     = "vpy",
  451. +};
  452. --
  453. 2.15.1
RAW Paste Data

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×