1/* 2 * This file is part of FFmpeg. 3 * 4 * FFmpeg is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * FFmpeg is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with FFmpeg; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19/** 20* @file 21* VapourSynth demuxer 22* 23* Synthesizes vapour (?) 24*/ 25 26#include <limits.h> 27 28#include <VapourSynth.h> 29#include <VSScript.h> 30 31#include "libavutil/avassert.h" 32#include "libavutil/avstring.h" 33#include "libavutil/eval.h" 34#include "libavutil/imgutils.h" 35#include "libavutil/opt.h" 36#include "libavutil/pixdesc.h" 37#include "avformat.h" 38#include "internal.h" 39 40struct VSState { 41 VSScript *vss; 42}; 43 44typedef struct VSContext { 45 const AVClass *class; 46 47 AVBufferRef *vss_state; 48 49 const VSAPI *vsapi; 50 VSCore *vscore; 51 52 VSNodeRef *outnode; 53 int is_cfr; 54 int current_frame; 55 56 int c_order[4]; 57 58 /* options */ 59 int64_t max_script_size; 60} VSContext; 61 62#define OFFSET(x) offsetof(VSContext, x) 63#define A AV_OPT_FLAG_AUDIO_PARAM 64#define D AV_OPT_FLAG_DECODING_PARAM 65static const AVOption options[] = { 66 {"max_script_size", "set max file size supported (in bytes)", OFFSET(max_script_size), AV_OPT_TYPE_INT64, {.i64 = 1 * 1024 * 1024}, 0, SIZE_MAX - 1, A|D}, 67 {NULL} 68}; 69 70static void free_vss_state(void *opaque, uint8_t *data) 71{ 72 struct VSState *vss = opaque; 73 74 if (vss->vss) { 75 vsscript_freeScript(vss->vss); 76 vsscript_finalize(); 77 } 78} 79 80static av_cold int read_close_vs(AVFormatContext *s) 81{ 82 VSContext *vs = s->priv_data; 83 84 if (vs->outnode) 85 vs->vsapi->freeNode(vs->outnode); 86 87 av_buffer_unref(&vs->vss_state); 88 89 vs->vsapi = NULL; 90 vs->vscore = NULL; 91 vs->outnode = NULL; 92 93 return 0; 94} 95 96static av_cold int is_native_endian(enum AVPixelFormat pixfmt) 97{ 98 enum AVPixelFormat other = av_pix_fmt_swap_endianness(pixfmt); 99 const AVPixFmtDescriptor *pd; 100 if (other == AV_PIX_FMT_NONE || other == pixfmt) 101 return 1; // not affected by byte order 102 pd = av_pix_fmt_desc_get(pixfmt); 103 return pd && (!!HAVE_BIGENDIAN == !!(pd->flags & AV_PIX_FMT_FLAG_BE)); 104} 105 106static av_cold enum AVPixelFormat match_pixfmt(const VSFormat *vsf, int c_order[4]) 107{ 108 static const int yuv_order[4] = {0, 1, 2, 0}; 109 static const int rgb_order[4] = {1, 2, 0, 0}; 110 const AVPixFmtDescriptor *pd; 111 112 for (pd = av_pix_fmt_desc_next(NULL); pd; pd = av_pix_fmt_desc_next(pd)) { 113 int is_rgb, is_yuv, i; 114 const int *order; 115 enum AVPixelFormat pixfmt; 116 117 pixfmt = av_pix_fmt_desc_get_id(pd); 118 119 if (pd->flags & (AV_PIX_FMT_FLAG_BAYER | AV_PIX_FMT_FLAG_ALPHA | 120 AV_PIX_FMT_FLAG_HWACCEL | AV_PIX_FMT_FLAG_BITSTREAM)) 121 continue; 122 123 if (pd->log2_chroma_w != vsf->subSamplingW || 124 pd->log2_chroma_h != vsf->subSamplingH) 125 continue; 126 127 is_rgb = vsf->colorFamily == cmRGB; 128 if (is_rgb != !!(pd->flags & AV_PIX_FMT_FLAG_RGB)) 129 continue; 130 131 is_yuv = vsf->colorFamily == cmYUV || 132 vsf->colorFamily == cmYCoCg || 133 vsf->colorFamily == cmGray; 134 if (!is_rgb && !is_yuv) 135 continue; 136 137 if (vsf->sampleType != ((pd->flags & AV_PIX_FMT_FLAG_FLOAT) ? stFloat : stInteger)) 138 continue; 139 140 if (av_pix_fmt_count_planes(pixfmt) != vsf->numPlanes) 141 continue; 142 143 if (strncmp(pd->name, "xyz", 3) == 0) 144 continue; 145 146 if (!is_native_endian(pixfmt)) 147 continue; 148 149 order = is_yuv ? yuv_order : rgb_order; 150 151 for (i = 0; i < pd->nb_components; i++) { 152 const AVComponentDescriptor *c = &pd->comp[i]; 153 if (order[c->plane] != i || 154 c->offset != 0 || c->shift != 0 || 155 c->step != vsf->bytesPerSample || 156 c->depth != vsf->bitsPerSample) 157 goto cont; 158 } 159 160 // Use it. 161 memcpy(c_order, order, sizeof(int[4])); 162 return pixfmt; 163 164 cont: ; 165 } 166 167 return AV_PIX_FMT_NONE; 168} 169 170static av_cold int read_header_vs(AVFormatContext *s) 171{ 172 AVStream *st; 173 AVIOContext *pb = s->pb; 174 VSContext *vs = s->priv_data; 175 int64_t sz = avio_size(pb); 176 char *buf = NULL; 177 char dummy; 178 const VSVideoInfo *info; 179 struct VSState *vss_state; 180 int err = 0; 181 182 vss_state = av_mallocz(sizeof(*vss_state)); 183 if (!vss_state) { 184 err = AVERROR(ENOMEM); 185 goto done; 186 } 187 188 vs->vss_state = av_buffer_create(NULL, 0, free_vss_state, vss_state, 0); 189 if (!vs->vss_state) { 190 err = AVERROR(ENOMEM); 191 av_free(vss_state); 192 goto done; 193 } 194 195 if (!vsscript_init()) { 196 av_log(s, AV_LOG_ERROR, "Failed to initialize VSScript (possibly PYTHONPATH not set).\n"); 197 err = AVERROR_EXTERNAL; 198 goto done; 199 } 200 201 if (vsscript_createScript(&vss_state->vss)) { 202 av_log(s, AV_LOG_ERROR, "Failed to create script instance.\n"); 203 err = AVERROR_EXTERNAL; 204 vsscript_finalize(); 205 goto done; 206 } 207 208 if (sz < 0 || sz > vs->max_script_size) { 209 if (sz < 0) 210 av_log(s, AV_LOG_WARNING, "Could not determine file size\n"); 211 sz = vs->max_script_size; 212 } 213 214 buf = av_malloc(sz + 1); 215 if (!buf) { 216 err = AVERROR(ENOMEM); 217 goto done; 218 } 219 sz = avio_read(pb, buf, sz); 220 221 if (sz < 0) { 222 av_log(s, AV_LOG_ERROR, "Could not read script.\n"); 223 err = sz; 224 goto done; 225 } 226 227 // Data left means our buffer (the max_script_size option) is too small 228 if (avio_read(pb, &dummy, 1) == 1) { 229 av_log(s, AV_LOG_ERROR, "File size is larger than max_script_size option " 230 "value %"PRIi64", consider increasing the max_script_size option\n", 231 vs->max_script_size); 232 err = AVERROR_BUFFER_TOO_SMALL; 233 goto done; 234 } 235 236 buf[sz] = '\0'; 237 if (vsscript_evaluateScript(&vss_state->vss, buf, s->url, 0)) { 238 const char *msg = vsscript_getError(vss_state->vss); 239 av_log(s, AV_LOG_ERROR, "Failed to parse script: %s\n", msg ? msg : "(unknown)"); 240 err = AVERROR_EXTERNAL; 241 goto done; 242 } 243 244 vs->vsapi = vsscript_getVSApi(); 245 vs->vscore = vsscript_getCore(vss_state->vss); 246 247 vs->outnode = vsscript_getOutput(vss_state->vss, 0); 248 if (!vs->outnode) { 249 av_log(s, AV_LOG_ERROR, "Could not get script output node.\n"); 250 err = AVERROR_EXTERNAL; 251 goto done; 252 } 253 254 st = avformat_new_stream(s, NULL); 255 if (!st) { 256 err = AVERROR(ENOMEM); 257 goto done; 258 } 259 260 info = vs->vsapi->getVideoInfo(vs->outnode); 261 262 if (!info->format || !info->width || !info->height) { 263 av_log(s, AV_LOG_ERROR, "Non-constant input format not supported.\n"); 264 err = AVERROR_PATCHWELCOME; 265 goto done; 266 } 267 268 if (info->fpsDen) { 269 vs->is_cfr = 1; 270 avpriv_set_pts_info(st, 64, info->fpsDen, info->fpsNum); 271 st->duration = info->numFrames; 272 } else { 273 // VFR. Just set "something". 274 avpriv_set_pts_info(st, 64, 1, AV_TIME_BASE); 275 s->ctx_flags |= AVFMTCTX_UNSEEKABLE; 276 } 277 278 st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; 279 st->codecpar->codec_id = AV_CODEC_ID_WRAPPED_AVFRAME; 280 st->codecpar->width = info->width; 281 st->codecpar->height = info->height; 282 st->codecpar->format = match_pixfmt(info->format, vs->c_order); 283 284 if (st->codecpar->format == AV_PIX_FMT_NONE) { 285 av_log(s, AV_LOG_ERROR, "Unsupported VS pixel format %s\n", info->format->name); 286 err = AVERROR_EXTERNAL; 287 goto done; 288 } 289 av_log(s, AV_LOG_VERBOSE, "VS format %s -> pixfmt %s\n", info->format->name, 290 av_get_pix_fmt_name(st->codecpar->format)); 291 292 if (info->format->colorFamily == cmYCoCg) 293 st->codecpar->color_space = AVCOL_SPC_YCGCO; 294 295done: 296 av_free(buf); 297 return err; 298} 299 300static void free_frame(void *opaque, uint8_t *data) 301{ 302 AVFrame *frame = (AVFrame *)data; 303 304 av_frame_free(&frame); 305} 306 307static int get_vs_prop_int(AVFormatContext *s, const VSMap *map, const char *name, int def) 308{ 309 VSContext *vs = s->priv_data; 310 int64_t res; 311 int err = 1; 312 313 res = vs->vsapi->propGetInt(map, name, 0, &err); 314 return err || res < INT_MIN || res > INT_MAX ? def : res; 315} 316 317struct vsframe_ref_data { 318 const VSAPI *vsapi; 319 const VSFrameRef *frame; 320 AVBufferRef *vss_state; 321}; 322 323static void free_vsframe_ref(void *opaque, uint8_t *data) 324{ 325 struct vsframe_ref_data *d = opaque; 326 327 if (d->frame) 328 d->vsapi->freeFrame(d->frame); 329 330 av_buffer_unref(&d->vss_state); 331 332 av_free(d); 333} 334 335static int read_packet_vs(AVFormatContext *s, AVPacket *pkt) 336{ 337 VSContext *vs = s->priv_data; 338 AVStream *st = s->streams[0]; 339 AVFrame *frame = NULL; 340 char vserr[80]; 341 const VSFrameRef *vsframe; 342 const VSVideoInfo *info = vs->vsapi->getVideoInfo(vs->outnode); 343 const VSMap *props; 344 const AVPixFmtDescriptor *desc; 345 AVBufferRef *vsframe_ref = NULL; 346 struct vsframe_ref_data *ref_data; 347 int err = 0; 348 int i; 349 350 if (vs->current_frame >= info->numFrames) 351 return AVERROR_EOF; 352 353 ref_data = av_mallocz(sizeof(*ref_data)); 354 if (!ref_data) { 355 err = AVERROR(ENOMEM); 356 goto end; 357 } 358 359 // (the READONLY flag is important because the ref is reused for plane data) 360 vsframe_ref = av_buffer_create(NULL, 0, free_vsframe_ref, ref_data, AV_BUFFER_FLAG_READONLY); 361 if (!vsframe_ref) { 362 err = AVERROR(ENOMEM); 363 av_free(ref_data); 364 goto end; 365 } 366 367 vsframe = vs->vsapi->getFrame(vs->current_frame, vs->outnode, vserr, sizeof(vserr)); 368 if (!vsframe) { 369 av_log(s, AV_LOG_ERROR, "Error getting frame: %s\n", vserr); 370 err = AVERROR_EXTERNAL; 371 goto end; 372 } 373 374 ref_data->vsapi = vs->vsapi; 375 ref_data->frame = vsframe; 376 377 ref_data->vss_state = av_buffer_ref(vs->vss_state); 378 if (!ref_data->vss_state) { 379 err = AVERROR(ENOMEM); 380 goto end; 381 } 382 383 props = vs->vsapi->getFramePropsRO(vsframe); 384 385 frame = av_frame_alloc(); 386 if (!frame) { 387 err = AVERROR(ENOMEM); 388 goto end; 389 } 390 391 frame->format = st->codecpar->format; 392 frame->width = st->codecpar->width; 393 frame->height = st->codecpar->height; 394 frame->colorspace = st->codecpar->color_space; 395 396 // Values according to ISO/IEC 14496-10. 397 frame->colorspace = get_vs_prop_int(s, props, "_Matrix", frame->colorspace); 398 frame->color_primaries = get_vs_prop_int(s, props, "_Primaries", frame->color_primaries); 399 frame->color_trc = get_vs_prop_int(s, props, "_Transfer", frame->color_trc); 400 401 if (get_vs_prop_int(s, props, "_ColorRange", 1) == 0) 402 frame->color_range = AVCOL_RANGE_JPEG; 403 404 frame->sample_aspect_ratio.num = get_vs_prop_int(s, props, "_SARNum", 0); 405 frame->sample_aspect_ratio.den = get_vs_prop_int(s, props, "_SARDen", 1); 406 407 av_assert0(vs->vsapi->getFrameWidth(vsframe, 0) == frame->width); 408 av_assert0(vs->vsapi->getFrameHeight(vsframe, 0) == frame->height); 409 410 desc = av_pix_fmt_desc_get(frame->format); 411 412 for (i = 0; i < info->format->numPlanes; i++) { 413 int p = vs->c_order[i]; 414 ptrdiff_t plane_h = frame->height; 415 416 frame->data[i] = (void *)vs->vsapi->getReadPtr(vsframe, p); 417 frame->linesize[i] = vs->vsapi->getStride(vsframe, p); 418 419 frame->buf[i] = av_buffer_ref(vsframe_ref); 420 if (!frame->buf[i]) { 421 err = AVERROR(ENOMEM); 422 goto end; 423 } 424 425 // Each plane needs an AVBufferRef that indicates the correct plane 426 // memory range. VapourSynth doesn't even give us the memory range, 427 // so make up a bad guess to make FFmpeg happy (even if almost nothing 428 // checks the memory range). 429 if (i == 1 || i == 2) 430 plane_h = AV_CEIL_RSHIFT(plane_h, desc->log2_chroma_h); 431 frame->buf[i]->data = frame->data[i]; 432 frame->buf[i]->size = frame->linesize[i] * plane_h; 433 } 434 435 pkt->buf = av_buffer_create((uint8_t*)frame, sizeof(*frame), 436 free_frame, NULL, 0); 437 if (!pkt->buf) { 438 err = AVERROR(ENOMEM); 439 goto end; 440 } 441 442 frame = NULL; // pkt owns it now 443 444 pkt->data = pkt->buf->data; 445 pkt->size = pkt->buf->size; 446 pkt->flags |= AV_PKT_FLAG_TRUSTED; 447 448 if (vs->is_cfr) 449 pkt->pts = vs->current_frame; 450 451 vs->current_frame++; 452 453end: 454 av_frame_free(&frame); 455 av_buffer_unref(&vsframe_ref); 456 return err; 457} 458 459static int read_seek_vs(AVFormatContext *s, int stream_idx, int64_t ts, int flags) 460{ 461 VSContext *vs = s->priv_data; 462 463 if (!vs->is_cfr) 464 return AVERROR(ENOSYS); 465 466 vs->current_frame = FFMIN(FFMAX(0, ts), s->streams[0]->duration); 467 return 0; 468} 469 470static av_cold int probe_vs(const AVProbeData *p) 471{ 472 // Explicitly do not support this. VS scripts are written in Python, and 473 // can run arbitrary code on the user's system. 474 return 0; 475} 476 477static const AVClass class_vs = { 478 .class_name = "VapourSynth demuxer", 479 .item_name = av_default_item_name, 480 .option = options, 481 .version = LIBAVUTIL_VERSION_INT, 482}; 483 484const AVInputFormat ff_vapoursynth_demuxer = { 485 .name = "vapoursynth", 486 .long_name = NULL_IF_CONFIG_SMALL("VapourSynth demuxer"), 487 .priv_data_size = sizeof(VSContext), 488 .flags_internal = FF_FMT_INIT_CLEANUP, 489 .read_probe = probe_vs, 490 .read_header = read_header_vs, 491 .read_packet = read_packet_vs, 492 .read_close = read_close_vs, 493 .read_seek = read_seek_vs, 494 .priv_class = &class_vs, 495}; 496