SHARE
TWEET

Untitled

a guest Jul 2nd, 2018 155 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
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top