[FFmpeg-devel] [PATCH] avformat: add vapoursynth wrapper

James Almer jamrial at gmail.com
Sat Apr 28 21:28:13 EEST 2018


On 4/28/2018 2:05 PM, wm4 wrote:
> This can "demux" .vpy files.
> 
> Some minor code copied from other LGPL parts of FFmpeg.
> 
> I did not found a good way to test a few of the more obscure features,
> like VFR nodes, compat pixel formats, or nodes with dynamic size/format
> changes. These can be easily implemented on demand.
> ---
>  configure                 |   5 +
>  libavformat/Makefile      |   1 +
>  libavformat/allformats.c  |   1 +
>  libavformat/vapoursynth.c | 421 ++++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 428 insertions(+)
>  create mode 100644 libavformat/vapoursynth.c

[...]

> +static int read_packet_vs(AVFormatContext *s, AVPacket *pkt)
> +{
> +    VSContext *vs = s->priv_data;
> +    AVStream *st = s->streams[0];
> +    AVFrame *frame = NULL;
> +    char vserr[80];
> +    const VSFrameRef *vsframe = NULL;
> +    const VSVideoInfo *info = vs->vsapi->getVideoInfo(vs->outnode);
> +    int err = 0;
> +    const uint8_t *src_data[4];
> +    int src_linesizes[4];
> +    const VSMap *props;
> +    int i;
> +
> +    if (vs->current_frame >= info->numFrames)
> +        return AVERROR_EOF;
> +
> +    vsframe = vs->vsapi->getFrame(vs->current_frame, vs->outnode, vserr, sizeof(vserr));
> +    if (!vsframe) {
> +        av_log(s, AV_LOG_ERROR, "Error getting frame: %s\n", vserr);
> +        err = AVERROR_EXTERNAL;
> +        goto end;
> +    }
> +
> +    props = vs->vsapi->getFramePropsRO(vsframe);
> +
> +    frame = av_frame_alloc();
> +    if (!frame) {
> +        err = AVERROR(ENOMEM);
> +        goto end;
> +    }
> +
> +    frame->format       = st->codecpar->format;
> +    frame->width        = st->codecpar->width;
> +    frame->height       = st->codecpar->height;
> +    frame->colorspace   = st->codecpar->color_space;
> +
> +    // Values according to ISO/IEC 14496-10.
> +    frame->colorspace       = get_vs_prop_int(s, props, "_Matrix",      frame->colorspace);
> +    frame->color_primaries  = get_vs_prop_int(s, props, "_Primaries",   frame->color_primaries);
> +    frame->color_trc        = get_vs_prop_int(s, props, "_Transfer",    frame->color_trc);
> +
> +    if (get_vs_prop_int(s, props, "_ColorRange", 1) == 0)
> +        frame->color_range = AVCOL_RANGE_JPEG;
> +
> +    frame->sample_aspect_ratio.num = get_vs_prop_int(s, props, "_SARNum", 0);
> +    frame->sample_aspect_ratio.den = get_vs_prop_int(s, props, "_SARDen", 1);
> +
> +    av_assert0(vs->vsapi->getFrameWidth(vsframe, 0) == frame->width);
> +    av_assert0(vs->vsapi->getFrameHeight(vsframe, 0) == frame->height);
> +
> +    err = av_frame_get_buffer(frame, 0);
> +    if (err < 0)
> +        goto end;
> +
> +    for (i = 0; i < info->format->numPlanes; i++) {
> +        int p = vs->c_order[i];
> +        src_data[i] = vs->vsapi->getReadPtr(vsframe, p);
> +        src_linesizes[i] = vs->vsapi->getStride(vsframe, p);
> +    }
> +
> +    av_image_copy(frame->data, frame->linesize, src_data, src_linesizes,
> +                  frame->format, frame->width, frame->height);
> +
> +    pkt->buf = av_buffer_create((uint8_t*)frame, sizeof(*frame),
> +                                free_frame, NULL, 0);
> +    if (!pkt->buf) {
> +        err = AVERROR(ENOMEM);
> +        goto end;
> +    }
> +
> +    frame = NULL; // pkt owns it now
> +
> +    pkt->data   = pkt->buf->data;
> +    pkt->size   = pkt->buf->size;
> +    pkt->flags |= AV_PKT_FLAG_TRUSTED;
> +
> +    if (vs->is_cfr)
> +        pkt->pts = vs->current_frame;
> +
> +    vs->current_frame++;
> +
> +end:
> +    if (err < 0)
> +        av_packet_unref(pkt);

Unneeded. Nothing after pkt->buf is initialized can fail right now. And
if av_buffer_create() fails, pkt will be untouched.

> +    av_frame_free(&frame);
> +    vs->vsapi->freeFrame(vsframe);
> +    return err;

Shouldn't you set err to pkt->size right above the end label?

> +}
> +
> +static int read_seek_vs(AVFormatContext *s, int stream_idx, int64_t ts, int flags)
> +{
> +    VSContext *vs = s->priv_data;
> +
> +    if (!vs->is_cfr)
> +        return AVERROR(ENOSYS);
> +
> +    vs->current_frame = FFMIN(FFMAX(0, ts), s->streams[0]->duration);
> +    return 0;
> +}
> +
> +static av_cold int probe_vs(AVProbeData *p)
> +{
> +    // Explicitly do not support this. VS scripts are written in Python, and
> +    // can run arbitrary code on the user's system.
> +    return 0;
> +}
> +
> +static const AVClass class_vs = {
> +    .class_name = "VapourSynth demuxer",
> +    .item_name  = av_default_item_name,
> +    .option     = options,
> +    .version    = LIBAVUTIL_VERSION_INT,
> +};
> +
> +AVInputFormat ff_vapoursynth_demuxer = {
> +    .name           = "vapoursynth",
> +    .long_name      = NULL_IF_CONFIG_SMALL("VapourSynth demuxer"),
> +    .priv_data_size = sizeof(VSContext),
> +    .read_probe     = probe_vs,
> +    .read_header    = read_header_vs,
> +    .read_packet    = read_packet_vs,
> +    .read_close     = read_close_vs,
> +    .read_seek      = read_seek_vs,
> +    .priv_class     = &class_vs,
> +};
> 



More information about the ffmpeg-devel mailing list