// Attempt to initialize all pads. Return true if all are initialized, or // false if more data is needed (or on error). static bool init_pads(struct lavfi *c) { if (!c->graph) goto error; for (int n = 0; n < c->num_out_pads; n++) { struct lavfi_pad *pad = c->out_pads[n]; if (pad->buffer) continue; const AVFilter *dst_filter = NULL; if (pad->type == MP_FRAME_AUDIO) { dst_filter = avfilter_get_by_name("abuffersink"); } else if (pad->type == MP_FRAME_VIDEO) { dst_filter = avfilter_get_by_name("buffersink"); } else { assert(0); } if (!dst_filter) goto error; char name[256]; snprintf(name, sizeof(name), "mpv_sink_%s", pad->name); if (avfilter_graph_create_filter(&pad->buffer, dst_filter, name, NULL, NULL, c->graph) < 0) goto error; if (avfilter_link(pad->filter, pad->filter_pad, pad->buffer, 0) < 0) goto error; } for (int n = 0; n < c->num_in_pads; n++) { struct lavfi_pad *pad = c->in_pads[n]; if (pad->buffer) continue; mp_frame_unref(&pad->in_fmt); read_pad_input(c, pad); // no input data, format unknown, can't init, wait longer. if (!pad->pending.type) return false; if (mp_frame_is_data(pad->pending)) { assert(pad->pending.type == pad->type); pad->in_fmt = mp_frame_ref(pad->pending); if (!pad->in_fmt.type) goto error; if (pad->in_fmt.type == MP_FRAME_VIDEO) mp_image_unref_data(pad->in_fmt.data); if (pad->in_fmt.type == MP_FRAME_AUDIO) mp_aframe_unref_data(pad->in_fmt.data); } if (pad->pending.type == MP_FRAME_EOF && !pad->in_fmt.type) { // libavfilter makes this painful. Init it with a dummy config, // just so we can tell it the stream is EOF. if (pad->type == MP_FRAME_AUDIO) { struct mp_aframe *fmt = mp_aframe_create(); mp_aframe_set_format(fmt, AF_FORMAT_FLOAT); mp_aframe_set_chmap(fmt, &(struct mp_chmap)MP_CHMAP_INIT_STEREO); mp_aframe_set_rate(fmt, 48000); pad->in_fmt = (struct mp_frame){MP_FRAME_AUDIO, fmt}; } if (pad->type == MP_FRAME_VIDEO) { struct mp_image *fmt = talloc_zero(NULL, struct mp_image); mp_image_setfmt(fmt, IMGFMT_420P); mp_image_set_size(fmt, 64, 64); pad->in_fmt = (struct mp_frame){MP_FRAME_VIDEO, fmt}; } } if (pad->in_fmt.type != pad->type) goto error; AVBufferSrcParameters *params = av_buffersrc_parameters_alloc(); if (!params) goto error; pad->timebase = AV_TIME_BASE_Q; char *filter_name = NULL; if (pad->type == MP_FRAME_AUDIO) { struct mp_aframe *fmt = pad->in_fmt.data; params->format = af_to_avformat(mp_aframe_get_format(fmt)); params->sample_rate = mp_aframe_get_rate(fmt); struct mp_chmap chmap = {0}; mp_aframe_get_chmap(fmt, &chmap); params->channel_layout = mp_chmap_to_lavc(&chmap); pad->timebase = (AVRational){1, mp_aframe_get_rate(fmt)}; filter_name = "abuffer"; } else if (pad->type == MP_FRAME_VIDEO) { struct mp_image *fmt = pad->in_fmt.data; params->format = imgfmt2pixfmt(fmt->imgfmt); params->width = fmt->w; params->height = fmt->h; params->sample_aspect_ratio.num = fmt->params.p_w; params->sample_aspect_ratio.den = fmt->params.p_h; params->hw_frames_ctx = fmt->hwctx; params->frame_rate = av_d2q(fmt->nominal_fps, 1000000); filter_name = "buffer"; } else { assert(0); } params->time_base = pad->timebase; const AVFilter *filter = avfilter_get_by_name(filter_name); if (filter) { char name[256]; snprintf(name, sizeof(name), "mpv_src_%s", pad->name); pad->buffer = avfilter_graph_alloc_filter(c->graph, filter, name); } if (!pad->buffer) { av_free(params); goto error; } int ret = av_buffersrc_parameters_set(pad->buffer, params); av_free(params); if (ret < 0) goto error; if (avfilter_init_str(pad->buffer, NULL) < 0) goto error; if (avfilter_link(pad->buffer, 0, pad->filter, pad->filter_pad) < 0) goto error; } return true; error: MP_FATAL(c, "could not initialize filter pads\n"); c->failed = true; mp_filter_internal_mark_failed(c->f); return false; }
static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter, AVFilterInOut *in) { AVFilterContext *last_filter; const AVFilter *buffer_filt = avfilter_get_by_name("buffer"); InputStream *ist = ifilter->ist; InputFile *f = input_files[ist->file_index]; AVRational tb = ist->framerate.num ? av_inv_q(ist->framerate) : ist->st->time_base; AVRational fr = ist->framerate; AVRational sar; AVBPrint args; char name[255]; int ret, pad_idx = 0; int64_t tsoffset = 0; AVBufferSrcParameters *par = av_buffersrc_parameters_alloc(); if(!par) { return AVERROR(ENOMEM); } memset(par, 0, sizeof(*par)); par->format = AV_PIX_FMT_NONE; if(ist->dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) { av_log(NULL, AV_LOG_ERROR, "Cannot connect video filter to audio input\n"); ret = AVERROR(EINVAL); goto fail; } if(!fr.num) { fr = av_guess_frame_rate(input_files[ist->file_index]->ctx, ist->st, NULL); } if(ist->dec_ctx->codec_type == AVMEDIA_TYPE_SUBTITLE) { ret = sub2video_prepare(ist); if(ret < 0) { goto fail; } } sar = ist->st->sample_aspect_ratio.num ? ist->st->sample_aspect_ratio : ist->dec_ctx->sample_aspect_ratio; if(!sar.den) sar = (AVRational) { 0, 1 }; av_bprint_init(&args, 0, 1); av_bprintf(&args, "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:" "pixel_aspect=%d/%d:sws_param=flags=%d", ist->resample_width, ist->resample_height, ist->hwaccel_retrieve_data ? ist->hwaccel_retrieved_pix_fmt : ist->resample_pix_fmt, tb.num, tb.den, sar.num, sar.den, SWS_BILINEAR + ((ist->dec_ctx->flags & AV_CODEC_FLAG_BITEXACT) ? SWS_BITEXACT : 0)); if(fr.num && fr.den) { av_bprintf(&args, ":frame_rate=%d/%d", fr.num, fr.den); } snprintf(name, sizeof(name), "graph %d input from stream %d:%d", fg->index, ist->file_index, ist->st->index); if((ret = avfilter_graph_create_filter(&ifilter->filter, buffer_filt, name, args.str, NULL, fg->graph)) < 0) { goto fail; } par->hw_frames_ctx = ist->hw_frames_ctx; ret = av_buffersrc_parameters_set(ifilter->filter, par); if(ret < 0) { goto fail; } av_freep(&par); last_filter = ifilter->filter; if(ist->autorotate) { double theta = get_rotation(ist->st); if(fabs(theta - 90) < 1.0) { ret = insert_filter(&last_filter, &pad_idx, "transpose", "clock"); } else if(fabs(theta - 180) < 1.0) { ret = insert_filter(&last_filter, &pad_idx, "hflip", NULL); if(ret < 0) { return ret; } ret = insert_filter(&last_filter, &pad_idx, "vflip", NULL); } else if(fabs(theta - 270) < 1.0) { ret = insert_filter(&last_filter, &pad_idx, "transpose", "cclock"); } else if(fabs(theta) > 1.0) { char rotate_buf[64]; snprintf(rotate_buf, sizeof(rotate_buf), "%f*PI/180", theta); ret = insert_filter(&last_filter, &pad_idx, "rotate", rotate_buf); } if(ret < 0) { return ret; } } if(ist->framerate.num) { AVFilterContext *setpts; snprintf(name, sizeof(name), "force CFR for input from stream %d:%d", ist->file_index, ist->st->index); if((ret = avfilter_graph_create_filter(&setpts, avfilter_get_by_name("setpts"), name, "N", NULL, fg->graph)) < 0) { return ret; } if((ret = avfilter_link(last_filter, 0, setpts, 0)) < 0) { return ret; } last_filter = setpts; } if(do_deinterlace) { AVFilterContext *yadif; snprintf(name, sizeof(name), "deinterlace input from stream %d:%d", ist->file_index, ist->st->index); if((ret = avfilter_graph_create_filter(&yadif, avfilter_get_by_name("yadif"), name, "", NULL, fg->graph)) < 0) { return ret; } if((ret = avfilter_link(last_filter, 0, yadif, 0)) < 0) { return ret; } last_filter = yadif; } snprintf(name, sizeof(name), "trim for input stream %d:%d", ist->file_index, ist->st->index); if(copy_ts) { tsoffset = f->start_time == AV_NOPTS_VALUE ? 0 : f->start_time; if(!start_at_zero && f->ctx->start_time != AV_NOPTS_VALUE) { tsoffset += f->ctx->start_time; } } ret = insert_trim(((f->start_time == AV_NOPTS_VALUE) || !f->accurate_seek) ? AV_NOPTS_VALUE : tsoffset, f->recording_time, &last_filter, &pad_idx, name); if(ret < 0) { return ret; } if((ret = avfilter_link(last_filter, 0, in->filter_ctx, in->pad_idx)) < 0) { return ret; } return 0; fail: av_freep(&par); return ret; }