[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