int configure_output_filter(struct liveStream *ctx, AVFilterInOut *out) { int ret = 0; AVFilterContext *filter; int pad_idx = out->pad_idx; AVFilterContext *last_filter = out->filter_ctx; ret = avfilter_graph_create_filter(&ctx->out_filter,avfilter_get_by_name("buffersink"),"out", NULL, NULL, ctx->filter_graph); if(ret < 0) return ret; ret = avfilter_graph_create_filter(&filter,avfilter_get_by_name("format"),"format", "yuv420p", NULL, ctx->filter_graph); if(ret < 0) return ret; if ((ret = avfilter_link(last_filter, pad_idx, filter, 0)) < 0) return ret; last_filter = filter; pad_idx = 0; if((ret = avfilter_link(last_filter, pad_idx, ctx->out_filter, 0)) < 0) return ret; return ret; }
bool setup() { avfilter_graph_free(&filter_graph); filter_graph = avfilter_graph_alloc(); //QString sws_flags_str; QString buffersrc_args = QString("video_size=%1x%2:pix_fmt=%3:time_base=%4/%5:sar=1") .arg(width).arg(height).arg(pixfmt).arg(1).arg(AV_TIME_BASE); qDebug("buffersrc_args=%s", buffersrc_args.toUtf8().constData()); AVFilter *buffersrc = avfilter_get_by_name("buffer"); Q_ASSERT(buffersrc); int ret = avfilter_graph_create_filter(&in_filter_ctx, buffersrc, "in", buffersrc_args.toUtf8().constData(), NULL, filter_graph); if (ret < 0) { qWarning("Can not create buffer source: %s", av_err2str(ret)); return false; } /* buffer video sink: to terminate the filter chain. */ AVFilter *buffersink = avfilter_get_by_name("buffersink"); Q_ASSERT(buffersink); if ((ret = avfilter_graph_create_filter(&out_filter_ctx, buffersink, "out", NULL, NULL, filter_graph)) < 0) { qWarning("Can not create buffer sink: %s", av_err2str(ret)); return false; } /* Endpoints for the filter graph. */ AVFilterInOut *outputs = avfilter_inout_alloc(); AVFilterInOut *inputs = avfilter_inout_alloc(); outputs->name = av_strdup("in"); outputs->filter_ctx = in_filter_ctx; outputs->pad_idx = 0; outputs->next = NULL; inputs->name = av_strdup("out"); inputs->filter_ctx = out_filter_ctx; inputs->pad_idx = 0; inputs->next = NULL; //avfilter_graph_parse, avfilter_graph_parse2? if ((ret = avfilter_graph_parse_ptr(filter_graph, options.toUtf8().constData(), &inputs, &outputs, NULL)) < 0) { qWarning("avfilter_graph_parse_ptr fail: %s", av_err2str(ret)); avfilter_inout_free(&outputs); avfilter_inout_free(&inputs); return false; } if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0) { qWarning("avfilter_graph_config fail: %s", av_err2str(ret)); avfilter_inout_free(&outputs); avfilter_inout_free(&inputs); return false; } avfilter_inout_free(&outputs); avfilter_inout_free(&inputs); avframe = av_frame_alloc(); return true; }
void Utility::FilterApplier::initFilters() { int ret=0; filterGraph_=avfilter_graph_alloc(); if(!filterGraph_) { throw std::runtime_error("Could not create filtergraph"); } AVFilter *buffersrc = avfilter_get_by_name("buffer"); AVFilter *buffersink = avfilter_get_by_name("buffersink"); std::string args="video_size="+std::to_string(width_)+"x"+std::to_string( height_)+":pix_fmt="+std::to_string(pixelFormat_)+":time_base=1/1"; ret=avfilter_graph_create_filter(&buffersourceContext_, buffersrc, "in",args.c_str(), NULL, filterGraph_); if(ret<0) { throw std::runtime_error("Could not create the buffersource for the filtergraph."); } ret = avfilter_graph_create_filter(&buffersinkContext_, buffersink, "out",NULL, NULL, filterGraph_); if(ret<0) { throw std::runtime_error("Could not create the buffersink for the filtergraph."); } enum AVPixelFormat pixelFormats[]= {AV_PIX_FMT_RGB24,AV_PIX_FMT_NONE}; ret = av_opt_set_int_list(buffersinkContext_, "pix_fmts", pixelFormats,AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN); if (ret < 0) { throw std::runtime_error("Could net set output pixelformat for the graph"); } AVFilterInOut *outputs = avfilter_inout_alloc(); AVFilterInOut *inputs = avfilter_inout_alloc(); outputs->name = av_strdup("in"); outputs->filter_ctx = buffersourceContext_; outputs->pad_idx = 0; outputs->next = NULL; inputs->name = av_strdup("out"); inputs->filter_ctx = buffersinkContext_; inputs->pad_idx = 0; inputs->next = NULL; ret = avfilter_graph_parse_ptr(filterGraph_, filterDescription_.c_str(), &inputs, &outputs, NULL); if(ret<0) { avfilter_inout_free(&inputs); avfilter_inout_free(&outputs); throw std::runtime_error("Could not parse the filter descritopns."); } ret = avfilter_graph_config(filterGraph_, NULL); if(ret<0) { avfilter_inout_free(&inputs); avfilter_inout_free(&outputs); throw std::runtime_error("Could not configure filtergraph."); } }
static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter, AVFilterInOut *in) { AVFilterContext *first_filter = in->filter_ctx; AVFilter *filter = avfilter_get_by_name("abuffer"); InputStream *ist = ifilter->ist; int pad_idx = in->pad_idx; char args[255], name[255]; int ret; snprintf(args, sizeof(args), "time_base=%d/%d:sample_rate=%d:sample_fmt=%s" ":channel_layout=0x%"PRIx64, 1, ist->st->codec->sample_rate, ist->st->codec->sample_rate, av_get_sample_fmt_name(ist->st->codec->sample_fmt), ist->st->codec->channel_layout); 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, filter, name, args, NULL, fg->graph)) < 0) return ret; if (audio_sync_method > 0) { AVFilterContext *async; char args[256]; int len = 0; av_log(NULL, AV_LOG_WARNING, "-async has been deprecated. Used the " "asyncts audio filter instead.\n"); if (audio_sync_method > 1) len += snprintf(args + len, sizeof(args) - len, "compensate=1:" "max_comp=%d:", audio_sync_method); snprintf(args + len, sizeof(args) - len, "min_delta=%f", audio_drift_threshold); snprintf(name, sizeof(name), "graph %d audio sync for input stream %d:%d", fg->index, ist->file_index, ist->st->index); ret = avfilter_graph_create_filter(&async, avfilter_get_by_name("asyncts"), name, args, NULL, fg->graph); if (ret < 0) return ret; ret = avfilter_link(async, 0, first_filter, pad_idx); if (ret < 0) return ret; first_filter = async; pad_idx = 0; } if ((ret = avfilter_link(ifilter->filter, 0, first_filter, pad_idx)) < 0) return ret; return 0; }
static int init_filters(const char *filters_descr) { char args[512]; int ret; AVFilter *buffersrc = avfilter_get_by_name("buffer"); AVFilter *buffersink = avfilter_get_by_name("buffersink"); AVFilterInOut *outputs = avfilter_inout_alloc(); AVFilterInOut *inputs = avfilter_inout_alloc(); enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE }; AVBufferSinkParams *buffersink_params; filter_graph = avfilter_graph_alloc(); /* buffer video source: the decoded frames from the decoder will be inserted here. */ snprintf(args, sizeof(args), "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d", dec_ctx->width, dec_ctx->height, dec_ctx->pix_fmt, dec_ctx->time_base.num, dec_ctx->time_base.den, dec_ctx->sample_aspect_ratio.num, dec_ctx->sample_aspect_ratio.den); ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in", args, NULL, filter_graph); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot create buffer source\n"); return ret; } /* buffer video sink: to terminate the filter chain. */ buffersink_params = av_buffersink_params_alloc(); buffersink_params->pixel_fmts = pix_fmts; ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out", NULL, buffersink_params, filter_graph); av_free(buffersink_params); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot create buffer sink\n"); return ret; } /* Endpoints for the filter graph. */ outputs->name = av_strdup("in"); outputs->filter_ctx = buffersrc_ctx; outputs->pad_idx = 0; outputs->next = NULL; inputs->name = av_strdup("out"); inputs->filter_ctx = buffersink_ctx; inputs->pad_idx = 0; inputs->next = NULL; if ((ret = avfilter_graph_parse_ptr(filter_graph, filters_descr, &inputs, &outputs, NULL)) < 0) return ret; if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0) return ret; return 0; }
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 sar; char args[255], name[255]; int ret, pad_idx = 0; sar = ist->st->sample_aspect_ratio.num ? ist->st->sample_aspect_ratio : ist->dec_ctx->sample_aspect_ratio; snprintf(args, sizeof(args), "%d:%d:%d:%d:%d:%d:%d", ist->dec_ctx->width, ist->dec_ctx->height, ist->hwaccel_retrieve_data ? ist->hwaccel_retrieved_pix_fmt : ist->dec_ctx->pix_fmt, tb.num, tb.den, sar.num, sar.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, NULL, fg->graph)) < 0) return ret; last_filter = ifilter->filter; 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; } snprintf(name, sizeof(name), "trim for input stream %d:%d", ist->file_index, ist->st->index); ret = insert_trim(((f->start_time == AV_NOPTS_VALUE) || !f->accurate_seek) ? AV_NOPTS_VALUE : 0, 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; }
static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter, AVFilterInOut *in) { AVFilterContext *first_filter = in->filter_ctx; AVFilter *filter = avfilter_get_by_name("buffer"); InputStream *ist = ifilter->ist; AVRational tb = ist->framerate.num ? av_inv_q(ist->framerate) : ist->st->time_base; AVRational sar; char args[255], name[255]; int pad_idx = in->pad_idx; int ret; sar = ist->st->sample_aspect_ratio.num ? ist->st->sample_aspect_ratio : ist->st->codec->sample_aspect_ratio; snprintf(args, sizeof(args), "%d:%d:%d:%d:%d:%d:%d", ist->st->codec->width, ist->st->codec->height, ist->st->codec->pix_fmt, tb.num, tb.den, sar.num, sar.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, filter, name, args, NULL, fg->graph)) < 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(setpts, 0, first_filter, pad_idx)) < 0) return ret; first_filter = setpts; pad_idx = 0; } if ((ret = avfilter_link(ifilter->filter, 0, first_filter, pad_idx)) < 0) return ret; return 0; }
static int create_sink(Stream *st, AVFilterGraph *graph, AVFilterContext *f, int idx) { enum AVMediaType type = avfilter_pad_get_type(f->output_pads, idx); const char *sink_name; int ret; switch (type) { case AVMEDIA_TYPE_VIDEO: sink_name = "buffersink"; break; case AVMEDIA_TYPE_AUDIO: sink_name = "abuffersink"; break; default: av_log(NULL, AV_LOG_ERROR, "Stream type not supported\n"); return AVERROR(EINVAL); } ret = avfilter_graph_create_filter(&st->sink, avfilter_get_by_name(sink_name), NULL, NULL, NULL, graph); if (ret < 0) return ret; ret = avfilter_link(f, idx, st->sink, 0); if (ret < 0) return ret; st->link = st->sink->inputs[0]; return 0; }
static int insert_filter(AVFilterContext **last_filter, int *pad_idx, const char *filter_name, const char *args) { AVFilterGraph *graph = (*last_filter)->graph; AVFilterContext *ctx; int ret; ret = avfilter_graph_create_filter(&ctx, avfilter_get_by_name(filter_name), filter_name, args, NULL, graph); if(ret < 0) { return ret; } ret = avfilter_link(*last_filter, *pad_idx, ctx, 0); if(ret < 0) { return ret; } *last_filter = ctx; *pad_idx = 0; return 0; }
static int query_formats(AVFilterGraph *graph, AVClass *log_ctx) { int i, j, ret; int scaler_count = 0; char inst_name[30]; /* ask all the sub-filters for their supported media formats */ for (i = 0; i < graph->filter_count; i++) { if (graph->filters[i]->filter->query_formats) graph->filters[i]->filter->query_formats(graph->filters[i]); else avfilter_default_query_formats(graph->filters[i]); } /* go through and merge as many format lists as possible */ for (i = 0; i < graph->filter_count; i++) { AVFilterContext *filter = graph->filters[i]; for (j = 0; j < filter->input_count; j++) { AVFilterLink *link = filter->inputs[j]; if (link && link->in_formats != link->out_formats) { if (!avfilter_merge_formats(link->in_formats, link->out_formats)) { AVFilterContext *scale; char scale_args[256]; /* couldn't merge format lists. auto-insert scale filter */ snprintf(inst_name, sizeof(inst_name), "auto-inserted scaler %d", scaler_count++); snprintf(scale_args, sizeof(scale_args), "0:0:%s", graph->scale_sws_opts); if ((ret = avfilter_graph_create_filter(&scale, avfilter_get_by_name("scale"), inst_name, scale_args, NULL, graph)) < 0) return ret; if ((ret = avfilter_insert_filter(link, scale, 0, 0)) < 0) return ret; scale->filter->query_formats(scale); if (((link = scale-> inputs[0]) && !avfilter_merge_formats(link->in_formats, link->out_formats)) || ((link = scale->outputs[0]) && !avfilter_merge_formats(link->in_formats, link->out_formats))) { av_log(log_ctx, AV_LOG_ERROR, "Impossible to convert between the formats supported by the filter " "'%s' and the filter '%s'\n", link->src->name, link->dst->name); return -1; } } } } } return 0; }
static int insert_conv_filter(AVFilterGraph *graph, AVFilterLink *link, const char *filt_name, const char *filt_args) { static int auto_count = 0, ret; char inst_name[32]; AVFilterContext *filt_ctx; if (graph->disable_auto_convert) { av_log(NULL, AV_LOG_ERROR, "The filters '%s' and '%s' do not have a common format " "and automatic conversion is disabled.\n", link->src->name, link->dst->name); return AVERROR(EINVAL); } snprintf(inst_name, sizeof(inst_name), "auto-inserted %s %d", filt_name, auto_count++); if ((ret = avfilter_graph_create_filter(&filt_ctx, avfilter_get_by_name(filt_name), inst_name, filt_args, NULL, graph)) < 0) return ret; if ((ret = avfilter_insert_filter(link, filt_ctx, 0, 0)) < 0) return ret; filter_query_formats(filt_ctx); if ( ((link = filt_ctx-> inputs[0]) && !ff_merge_formats(link->in_formats, link->out_formats)) || ((link = filt_ctx->outputs[0]) && !ff_merge_formats(link->in_formats, link->out_formats)) ) { av_log(NULL, AV_LOG_ERROR, "Impossible to convert between the formats supported by the filter " "'%s' and the filter '%s'\n", link->src->name, link->dst->name); return AVERROR(EINVAL); } if (link->type == AVMEDIA_TYPE_AUDIO && (((link = filt_ctx-> inputs[0]) && !ff_merge_channel_layouts(link->in_channel_layouts, link->out_channel_layouts)) || ((link = filt_ctx->outputs[0]) && !ff_merge_channel_layouts(link->in_channel_layouts, link->out_channel_layouts))) ) { av_log(NULL, AV_LOG_ERROR, "Impossible to convert between the channel layouts formats supported by the filter " "'%s' and the filter '%s'\n", link->src->name, link->dst->name); return AVERROR(EINVAL); } return 0; }
void FilterGraph::pushFilter(Filter& filter) { AVFilterContext* context = NULL; const int err = avfilter_graph_create_filter(&context, &filter.getAVFilter(), filter.getInstanceName().c_str(), filter.getOptions().c_str(), NULL, _graph); filter.setAVFilterContext(context); if(err < 0) { std::string msg("Cannot add filter "); msg += filter.getName(); msg += " (instance="; msg += filter.getInstanceName(); msg += ") to the graph: "; msg += getDescriptionFromErrorCode(err); throw std::runtime_error(msg); } }
static int insert_filter(const char *name, const char* arg, AVFilterContext **last_filter) { AVFilterContext *filt_ctx; int ret; char fltr_name[64] ={0}; _snprintf_s(fltr_name, sizeof(fltr_name), "ffplayer_%s", name); ret = avfilter_graph_create_filter(&filt_ctx, avfilter_get_by_name(name), fltr_name, arg, NULL, filter_graph); if (ret < 0) { printf("Cannot create filter: %s\n", name); return -1; } ret = avfilter_link(filt_ctx, 0, *last_filter, 0); if (ret < 0) { printf("Cannot link filter: %s\n", name); return -1; } *last_filter = filt_ctx; return 0; }
int configure_input_filter(struct liveStream *ctx, long in_id, AVFilterInOut *in) { AVFilter *buffer = avfilter_get_by_name("buffer"); struct lsInput *input = NULL; AVStream *st; AVCodecContext *dec_ctx; AVRational tb; AVBPrint args; int ret = 0; char name[128]; input = get_input_by_id(ctx->inputs,in_id); if(!input) { av_log(NULL,AV_LOG_ERROR,"Invalid input id for inputs list\n"); return -1; } st = input->st; dec_ctx = input->dec_ctx; tb = st->time_base; av_bprint_init(&args, 0, 1); /* buffer video source: the decoded frames from the decoder will be inserted here. */ av_bprintf(&args,"video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d", dec_ctx->width, dec_ctx->height, dec_ctx->pix_fmt, tb.num, tb.den, dec_ctx->sample_aspect_ratio.num, dec_ctx->sample_aspect_ratio.den); snprintf(name, sizeof(name), "Input %ld", in_id); ret = avfilter_graph_create_filter(&input->in_filter, buffer, name, args.str, NULL, ctx->filter_graph); if(ret < 0) return ret; if ((ret = avfilter_link(input->in_filter, 0, in->filter_ctx, in->pad_idx)) < 0) return ret; return ret; }
FilterContext FilterGraph::createFilter(const Filter &filter, const string &filterName, const string &filterArgs, error_code &ec) { clear_if(ec); if (!m_raw || filter.isNull()) { throws_if(ec, Errors::Unallocated); return FilterContext(); } AVFilterContext *ctx = nullptr; int stat = avfilter_graph_create_filter(&ctx, filter.raw(), filterName.c_str(), filterArgs.empty() ? nullptr : filterArgs.c_str(), this, m_raw); if (stat < 0) { throws_if(ec, stat, ffmpeg_category()); return FilterContext(); } return FilterContext(ctx); }
static int graph_insert_fifos(AVFilterGraph *graph, AVClass *log_ctx) { AVFilterContext *f; int i, j, ret; int fifo_count = 0; for (i = 0; i < graph->filter_count; i++) { f = graph->filters[i]; for (j = 0; j < f->nb_inputs; j++) { AVFilterLink *link = f->inputs[j]; AVFilterContext *fifo_ctx; AVFilter *fifo; char name[32]; if (!link->dstpad->needs_fifo) continue; fifo = f->inputs[j]->type == AVMEDIA_TYPE_VIDEO ? avfilter_get_by_name("fifo") : avfilter_get_by_name("afifo"); snprintf(name, sizeof(name), "auto-inserted fifo %d", fifo_count++); ret = avfilter_graph_create_filter(&fifo_ctx, fifo, name, NULL, NULL, graph); if (ret < 0) return ret; ret = avfilter_insert_filter(link, fifo_ctx, 0, 0); if (ret < 0) return ret; } } return 0; }
static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter, AVFilterInOut *in) { AVFilterContext *last_filter; const AVFilter *abuffer_filt = avfilter_get_by_name("abuffer"); InputStream *ist = ifilter->ist; InputFile *f = input_files[ist->file_index]; char args[255], name[255]; int ret, pad_idx = 0; snprintf(args, sizeof(args), "time_base=%d/%d:sample_rate=%d:sample_fmt=%s" ":channel_layout=0x%"PRIx64, 1, ist->dec_ctx->sample_rate, ist->dec_ctx->sample_rate, av_get_sample_fmt_name(ist->dec_ctx->sample_fmt), ist->dec_ctx->channel_layout); 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, abuffer_filt, name, args, NULL, fg->graph)) < 0) return ret; last_filter = ifilter->filter; if (audio_sync_method > 0) { AVFilterContext *async; int len = 0; av_log(NULL, AV_LOG_WARNING, "-async has been deprecated. Used the " "asyncts audio filter instead.\n"); if (audio_sync_method > 1) len += snprintf(args + len, sizeof(args) - len, "compensate=1:" "max_comp=%d:", audio_sync_method); snprintf(args + len, sizeof(args) - len, "min_delta=%f", audio_drift_threshold); snprintf(name, sizeof(name), "graph %d audio sync for input stream %d:%d", fg->index, ist->file_index, ist->st->index); ret = avfilter_graph_create_filter(&async, avfilter_get_by_name("asyncts"), name, args, NULL, fg->graph); if (ret < 0) return ret; ret = avfilter_link(last_filter, 0, async, 0); if (ret < 0) return ret; last_filter = async; } if (audio_volume != 256) { AVFilterContext *volume; av_log(NULL, AV_LOG_WARNING, "-vol has been deprecated. Use the volume " "audio filter instead.\n"); snprintf(args, sizeof(args), "volume=%f", audio_volume / 256.0); snprintf(name, sizeof(name), "graph %d volume for input stream %d:%d", fg->index, ist->file_index, ist->st->index); ret = avfilter_graph_create_filter(&volume, avfilter_get_by_name("volume"), name, args, NULL, fg->graph); if (ret < 0) return ret; ret = avfilter_link(last_filter, 0, volume, 0); if (ret < 0) return ret; last_filter = volume; } snprintf(name, sizeof(name), "trim for input stream %d:%d", ist->file_index, ist->st->index); ret = insert_trim(((f->start_time == AV_NOPTS_VALUE) || !f->accurate_seek) ? AV_NOPTS_VALUE : 0, 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; }
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 sar; char args[255], name[255]; int ret, pad_idx = 0; sar = ist->st->sample_aspect_ratio.num ? ist->st->sample_aspect_ratio : ist->dec_ctx->sample_aspect_ratio; snprintf(args, sizeof(args), "width=%d:height=%d:pix_fmt=%d:time_base=%d/%d:sar=%d/%d", ist->dec_ctx->width, ist->dec_ctx->height, ist->hwaccel_retrieve_data ? ist->hwaccel_retrieved_pix_fmt : ist->dec_ctx->pix_fmt, tb.num, tb.den, sar.num, sar.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, NULL, fg->graph)) < 0) return ret; last_filter = ifilter->filter; if (ist->autorotate) { uint8_t* displaymatrix = av_stream_get_side_data(ist->st, AV_PKT_DATA_DISPLAYMATRIX, NULL); if (displaymatrix) { double rot = av_display_rotation_get((int32_t*) displaymatrix); if (rot < -135 || rot > 135) { ret = insert_filter(&last_filter, &pad_idx, "vflip", NULL); if (ret < 0) return ret; ret = insert_filter(&last_filter, &pad_idx, "hflip", NULL); } else if (rot < -45) { ret = insert_filter(&last_filter, &pad_idx, "transpose", "dir=clock"); } else if (rot > 45) { ret = insert_filter(&last_filter, &pad_idx, "transpose", "dir=cclock"); } 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; } snprintf(name, sizeof(name), "trim for input stream %d:%d", ist->file_index, ist->st->index); ret = insert_trim(((f->start_time == AV_NOPTS_VALUE) || !f->accurate_seek) ? AV_NOPTS_VALUE : 0, 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; }
static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out) { OutputStream *ost = ofilter->ost; OutputFile *of = output_files[ost->file_index]; AVCodecContext *codec = ost->enc_ctx; AVFilterContext *last_filter = out->filter_ctx; int pad_idx = out->pad_idx; char *sample_fmts, *sample_rates, *channel_layouts; char name[255]; int ret; snprintf(name, sizeof(name), "output stream %d:%d", ost->file_index, ost->index); ret = avfilter_graph_create_filter(&ofilter->filter, avfilter_get_by_name("abuffersink"), name, NULL, NULL, fg->graph); if (ret < 0) return ret; if (codec->channels && !codec->channel_layout) codec->channel_layout = av_get_default_channel_layout(codec->channels); sample_fmts = choose_sample_fmts(ost); sample_rates = choose_sample_rates(ost); channel_layouts = choose_channel_layouts(ost); if (sample_fmts || sample_rates || channel_layouts) { AVFilterContext *format; char args[256]; int len = 0; if (sample_fmts) len += snprintf(args + len, sizeof(args) - len, "sample_fmts=%s:", sample_fmts); if (sample_rates) len += snprintf(args + len, sizeof(args) - len, "sample_rates=%s:", sample_rates); if (channel_layouts) len += snprintf(args + len, sizeof(args) - len, "channel_layouts=%s:", channel_layouts); args[len - 1] = 0; av_freep(&sample_fmts); av_freep(&sample_rates); av_freep(&channel_layouts); snprintf(name, sizeof(name), "audio format for output stream %d:%d", ost->file_index, ost->index); ret = avfilter_graph_create_filter(&format, avfilter_get_by_name("aformat"), name, args, NULL, fg->graph); if (ret < 0) return ret; ret = avfilter_link(last_filter, pad_idx, format, 0); if (ret < 0) return ret; last_filter = format; pad_idx = 0; } snprintf(name, sizeof(name), "trim for output stream %d:%d", ost->file_index, ost->index); ret = insert_trim(of->start_time, of->recording_time, &last_filter, &pad_idx, name); if (ret < 0) return ret; if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0) return ret; return 0; }
static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out) { char *pix_fmts; OutputStream *ost = ofilter->ost; OutputFile *of = output_files[ost->file_index]; AVCodecContext *codec = ost->enc_ctx; AVFilterContext *last_filter = out->filter_ctx; int pad_idx = out->pad_idx; int ret; char name[255]; snprintf(name, sizeof(name), "output stream %d:%d", ost->file_index, ost->index); ret = avfilter_graph_create_filter(&ofilter->filter, avfilter_get_by_name("buffersink"), name, NULL, NULL, fg->graph); if (ret < 0) return ret; if (codec->width || codec->height) { char args[255]; AVFilterContext *filter; snprintf(args, sizeof(args), "%d:%d:0x%X", codec->width, codec->height, (unsigned)ost->sws_flags); snprintf(name, sizeof(name), "scaler for output stream %d:%d", ost->file_index, ost->index); if ((ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("scale"), name, args, NULL, fg->graph)) < 0) return ret; if ((ret = avfilter_link(last_filter, pad_idx, filter, 0)) < 0) return ret; last_filter = filter; pad_idx = 0; } if ((pix_fmts = choose_pix_fmts(ost))) { AVFilterContext *filter; snprintf(name, sizeof(name), "pixel format for output stream %d:%d", ost->file_index, ost->index); ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("format"), "format", pix_fmts, NULL, fg->graph); av_freep(&pix_fmts); if (ret < 0) return ret; if ((ret = avfilter_link(last_filter, pad_idx, filter, 0)) < 0) return ret; last_filter = filter; pad_idx = 0; } if (ost->frame_rate.num) { AVFilterContext *fps; char args[255]; snprintf(args, sizeof(args), "fps=%d/%d", ost->frame_rate.num, ost->frame_rate.den); snprintf(name, sizeof(name), "fps for output stream %d:%d", ost->file_index, ost->index); ret = avfilter_graph_create_filter(&fps, avfilter_get_by_name("fps"), name, args, NULL, fg->graph); if (ret < 0) return ret; ret = avfilter_link(last_filter, pad_idx, fps, 0); if (ret < 0) return ret; last_filter = fps; pad_idx = 0; } snprintf(name, sizeof(name), "trim for output stream %d:%d", ost->file_index, ost->index); ret = insert_trim(of->start_time, of->recording_time, &last_filter, &pad_idx, name); if (ret < 0) return ret; if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0) return ret; return 0; }
int CDVDVideoCodecFFmpeg::FilterOpen(const std::string& filters, bool scale) { int result; if (m_pFilterGraph) FilterClose(); if (filters.empty() && !scale) return 0; if (m_pHardware) { CLog::Log(LOGWARNING, "CDVDVideoCodecFFmpeg::FilterOpen - skipped opening filters on hardware decode"); return 0; } if (!(m_pFilterGraph = avfilter_graph_alloc())) { CLog::Log(LOGERROR, "CDVDVideoCodecFFmpeg::FilterOpen - unable to alloc filter graph"); return -1; } AVFilter* srcFilter = avfilter_get_by_name("buffer"); AVFilter* outFilter = avfilter_get_by_name("buffersink"); // should be last filter in the graph for now std::string args = StringUtils::Format("%d:%d:%d:%d:%d:%d:%d", m_pCodecContext->width, m_pCodecContext->height, m_pCodecContext->pix_fmt, m_pCodecContext->time_base.num ? m_pCodecContext->time_base.num : 1, m_pCodecContext->time_base.num ? m_pCodecContext->time_base.den : 1, m_pCodecContext->sample_aspect_ratio.num != 0 ? m_pCodecContext->sample_aspect_ratio.num : 1, m_pCodecContext->sample_aspect_ratio.num != 0 ? m_pCodecContext->sample_aspect_ratio.den : 1); if ((result = avfilter_graph_create_filter(&m_pFilterIn, srcFilter, "src", args.c_str(), NULL, m_pFilterGraph)) < 0) { CLog::Log(LOGERROR, "CDVDVideoCodecFFmpeg::FilterOpen - avfilter_graph_create_filter: src"); return result; } if ((result = avfilter_graph_create_filter(&m_pFilterOut, outFilter, "out", NULL, NULL, m_pFilterGraph)) < 0) { CLog::Log(LOGERROR, "CDVDVideoCodecFFmpeg::FilterOpen - avfilter_graph_create_filter: out"); return result; } if ((result = av_opt_set_int_list(m_pFilterOut, "pix_fmts", &m_formats[0], AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN)) < 0) { CLog::Log(LOGERROR, "CDVDVideoCodecFFmpeg::FilterOpen - failed settings pix formats"); return result; } if (!filters.empty()) { AVFilterInOut* outputs = avfilter_inout_alloc(); AVFilterInOut* inputs = avfilter_inout_alloc(); outputs->name = av_strdup("in"); outputs->filter_ctx = m_pFilterIn; outputs->pad_idx = 0; outputs->next = nullptr; inputs->name = av_strdup("out"); inputs->filter_ctx = m_pFilterOut; inputs->pad_idx = 0; inputs->next = nullptr; if ((result = avfilter_graph_parse_ptr(m_pFilterGraph, (const char*)m_filters.c_str(), &inputs, &outputs, NULL)) < 0) { CLog::Log(LOGERROR, "CDVDVideoCodecFFmpeg::FilterOpen - avfilter_graph_parse"); return result; } avfilter_inout_free(&outputs); avfilter_inout_free(&inputs); } else { if ((result = avfilter_link(m_pFilterIn, 0, m_pFilterOut, 0)) < 0) { CLog::Log(LOGERROR, "CDVDVideoCodecFFmpeg::FilterOpen - avfilter_link"); return result; } } if ((result = avfilter_graph_config(m_pFilterGraph, nullptr)) < 0) { CLog::Log(LOGERROR, "CDVDVideoCodecFFmpeg::FilterOpen - avfilter_graph_config"); return result; } m_filterEof = false; return result; }
/* setup filter chain */ static bool openFilter (player_t * const player) { /* filter setup */ char strbuf[256]; int ret = 0; AVCodecContext * const cctx = player->st->codec; if ((player->fgraph = avfilter_graph_alloc ()) == NULL) { softfail ("graph_alloc"); } /* abuffer */ AVRational time_base = player->st->time_base; /* Workaround for a bug in libav-11, which reports an invalid channel * layout mp3 files */ if (cctx->channel_layout == 0) { cctx->channel_layout = av_get_default_channel_layout (cctx->channels); } snprintf (strbuf, sizeof (strbuf), "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%"PRIx64, time_base.num, time_base.den, cctx->sample_rate, av_get_sample_fmt_name (cctx->sample_fmt), cctx->channel_layout); if ((ret = avfilter_graph_create_filter (&player->fabuf, avfilter_get_by_name ("abuffer"), NULL, strbuf, NULL, player->fgraph)) < 0) { softfail ("create_filter abuffer"); } /* volume */ if ((ret = avfilter_graph_create_filter (&player->fvolume, avfilter_get_by_name ("volume"), NULL, "0dB", NULL, player->fgraph)) < 0) { softfail ("create_filter volume"); } /* aformat: convert float samples into something more usable */ AVFilterContext *fafmt = NULL; snprintf (strbuf, sizeof (strbuf), "sample_fmts=%s", av_get_sample_fmt_name (avformat)); if ((ret = avfilter_graph_create_filter (&fafmt, avfilter_get_by_name ("aformat"), NULL, strbuf, NULL, player->fgraph)) < 0) { softfail ("create_filter aformat"); } /* abuffersink */ if ((ret = avfilter_graph_create_filter (&player->fbufsink, avfilter_get_by_name ("abuffersink"), NULL, NULL, NULL, player->fgraph)) < 0) { softfail ("create_filter abuffersink"); } /* connect filter: abuffer -> volume -> aformat -> abuffersink */ if (avfilter_link (player->fabuf, 0, player->fvolume, 0) != 0 || avfilter_link (player->fvolume, 0, fafmt, 0) != 0 || avfilter_link (fafmt, 0, player->fbufsink, 0) != 0) { softfail ("filter_link"); } if ((ret = avfilter_graph_config (player->fgraph, NULL)) < 0) { softfail ("graph_config"); } return true; }
static int query_formats(AVFilterGraph *graph, AVClass *log_ctx) { int i, j, ret; char filt_args[128]; AVFilterFormats *formats; AVFilterChannelLayouts *chlayouts; AVFilterFormats *samplerates; int scaler_count = 0, resampler_count = 0; for (j = 0; j < 2; j++) { /* ask all the sub-filters for their supported media formats */ for (i = 0; i < graph->filter_count; i++) { /* Call query_formats on sources first. This is a temporary workaround for amerge, until format renegociation is implemented. */ if (!graph->filters[i]->nb_inputs == j) continue; if (graph->filters[i]->filter->query_formats) ret = filter_query_formats(graph->filters[i]); else ret = ff_default_query_formats(graph->filters[i]); if (ret < 0) return ret; } } /* go through and merge as many format lists as possible */ for (i = 0; i < graph->filter_count; i++) { AVFilterContext *filter = graph->filters[i]; for (j = 0; j < filter->nb_inputs; j++) { AVFilterLink *link = filter->inputs[j]; #if 0 if (!link) continue; if (!link->in_formats || !link->out_formats) return AVERROR(EINVAL); if (link->type == AVMEDIA_TYPE_VIDEO && !ff_merge_formats(link->in_formats, link->out_formats)) { /* couldn't merge format lists, auto-insert scale filter */ snprintf(filt_args, sizeof(filt_args), "0:0:%s", graph->scale_sws_opts); if (ret = insert_conv_filter(graph, link, "scale", filt_args)) return ret; } else if (link->type == AVMEDIA_TYPE_AUDIO) { if (!link->in_channel_layouts || !link->out_channel_layouts) return AVERROR(EINVAL); /* Merge all three list before checking: that way, in all * three categories, aconvert will use a common format * whenever possible. */ formats = ff_merge_formats(link->in_formats, link->out_formats); chlayouts = ff_merge_channel_layouts(link->in_channel_layouts , link->out_channel_layouts); samplerates = ff_merge_samplerates (link->in_samplerates, link->out_samplerates); if (!formats || !chlayouts || !samplerates) if (ret = insert_conv_filter(graph, link, "aresample", NULL)) return ret; #else int convert_needed = 0; if (!link) continue; if (link->in_formats != link->out_formats && !ff_merge_formats(link->in_formats, link->out_formats)) convert_needed = 1; if (link->type == AVMEDIA_TYPE_AUDIO) { if (link->in_channel_layouts != link->out_channel_layouts && !ff_merge_channel_layouts(link->in_channel_layouts, link->out_channel_layouts)) convert_needed = 1; if (link->in_samplerates != link->out_samplerates && !ff_merge_samplerates(link->in_samplerates, link->out_samplerates)) convert_needed = 1; } if (convert_needed) { AVFilterContext *convert; AVFilter *filter; AVFilterLink *inlink, *outlink; char scale_args[256]; char inst_name[30]; /* couldn't merge format lists. auto-insert conversion filter */ switch (link->type) { case AVMEDIA_TYPE_VIDEO: if (!(filter = avfilter_get_by_name("scale"))) { av_log(log_ctx, AV_LOG_ERROR, "'scale' filter " "not present, cannot convert pixel formats.\n"); return AVERROR(EINVAL); } snprintf(inst_name, sizeof(inst_name), "auto-inserted scaler %d", scaler_count++); snprintf(scale_args, sizeof(scale_args), "0:0:%s", graph->scale_sws_opts); if ((ret = avfilter_graph_create_filter(&convert, filter, inst_name, scale_args, NULL, graph)) < 0) return ret; break; case AVMEDIA_TYPE_AUDIO: if (!(filter = avfilter_get_by_name("aresample"))) { av_log(log_ctx, AV_LOG_ERROR, "'aresample' filter " "not present, cannot convert audio formats.\n"); return AVERROR(EINVAL); } snprintf(inst_name, sizeof(inst_name), "auto-inserted resampler %d", resampler_count++); if ((ret = avfilter_graph_create_filter(&convert, filter, inst_name, NULL, NULL, graph)) < 0) return ret; break; default: return AVERROR(EINVAL); } if ((ret = avfilter_insert_filter(link, convert, 0, 0)) < 0) return ret; filter_query_formats(convert); inlink = convert->inputs[0]; outlink = convert->outputs[0]; if (!ff_merge_formats( inlink->in_formats, inlink->out_formats) || !ff_merge_formats(outlink->in_formats, outlink->out_formats)) ret |= AVERROR(ENOSYS); if (inlink->type == AVMEDIA_TYPE_AUDIO && (!ff_merge_samplerates(inlink->in_samplerates, inlink->out_samplerates) || !ff_merge_channel_layouts(inlink->in_channel_layouts, inlink->out_channel_layouts))) ret |= AVERROR(ENOSYS); if (outlink->type == AVMEDIA_TYPE_AUDIO && (!ff_merge_samplerates(outlink->in_samplerates, outlink->out_samplerates) || !ff_merge_channel_layouts(outlink->in_channel_layouts, outlink->out_channel_layouts))) ret |= AVERROR(ENOSYS); if (ret < 0) { av_log(log_ctx, AV_LOG_ERROR, "Impossible to convert between the formats supported by the filter " "'%s' and the filter '%s'\n", link->src->name, link->dst->name); return ret; } #endif } } } return 0; } static int pick_format(AVFilterLink *link, AVFilterLink *ref) { if (!link || !link->in_formats) return 0; if (link->type == AVMEDIA_TYPE_VIDEO) { if(ref && ref->type == AVMEDIA_TYPE_VIDEO){ int has_alpha= av_pix_fmt_descriptors[ref->format].nb_components % 2 == 0; enum PixelFormat best= PIX_FMT_NONE; int i; for (i=0; i<link->in_formats->format_count; i++) { enum PixelFormat p = link->in_formats->formats[i]; best= avcodec_find_best_pix_fmt2(best, p, ref->format, has_alpha, NULL); } av_log(link->src,AV_LOG_DEBUG, "picking %s out of %d ref:%s alpha:%d\n", av_get_pix_fmt_name(best), link->in_formats->format_count, av_get_pix_fmt_name(ref->format), has_alpha); link->in_formats->formats[0] = best; } } link->in_formats->format_count = 1; link->format = link->in_formats->formats[0]; if (link->type == AVMEDIA_TYPE_AUDIO) { if (!link->in_samplerates->format_count) { av_log(link->src, AV_LOG_ERROR, "Cannot select sample rate for" " the link between filters %s and %s.\n", link->src->name, link->dst->name); return AVERROR(EINVAL); } link->in_samplerates->format_count = 1; link->sample_rate = link->in_samplerates->formats[0]; if (!link->in_channel_layouts->nb_channel_layouts) { av_log(link->src, AV_LOG_ERROR, "Cannot select channel layout for" "the link between filters %s and %s.\n", link->src->name, link->dst->name); return AVERROR(EINVAL); } link->in_channel_layouts->nb_channel_layouts = 1; link->channel_layout = link->in_channel_layouts->channel_layouts[0]; } ff_formats_unref(&link->in_formats); ff_formats_unref(&link->out_formats); ff_formats_unref(&link->in_samplerates); ff_formats_unref(&link->out_samplerates); ff_channel_layouts_unref(&link->in_channel_layouts); ff_channel_layouts_unref(&link->out_channel_layouts); return 0; } #define REDUCE_FORMATS(fmt_type, list_type, list, var, nb, add_format) \ do { \ for (i = 0; i < filter->nb_inputs; i++) { \ AVFilterLink *link = filter->inputs[i]; \ fmt_type fmt; \ \ if (!link->out_ ## list || link->out_ ## list->nb != 1) \ continue; \ fmt = link->out_ ## list->var[0]; \ \ for (j = 0; j < filter->nb_outputs; j++) { \ AVFilterLink *out_link = filter->outputs[j]; \ list_type *fmts; \ \ if (link->type != out_link->type || \ out_link->in_ ## list->nb == 1) \ continue; \ fmts = out_link->in_ ## list; \ \ if (!out_link->in_ ## list->nb) { \ add_format(&out_link->in_ ##list, fmt); \ break; \ } \ \ for (k = 0; k < out_link->in_ ## list->nb; k++) \ if (fmts->var[k] == fmt) { \ fmts->var[0] = fmt; \ fmts->nb = 1; \ ret = 1; \ break; \ } \ } \ } \ } while (0) static int reduce_formats_on_filter(AVFilterContext *filter) { int i, j, k, ret = 0; REDUCE_FORMATS(int, AVFilterFormats, formats, formats, format_count, ff_add_format); REDUCE_FORMATS(int, AVFilterFormats, samplerates, formats, format_count, ff_add_format); REDUCE_FORMATS(uint64_t, AVFilterChannelLayouts, channel_layouts, channel_layouts, nb_channel_layouts, ff_add_channel_layout); return ret; }
static int init_filters(const char *filters_descr) { char args[512]; int ret = 0; AVFilter *buffersrc = avfilter_get_by_name("buffer"); AVFilter *buffersink = avfilter_get_by_name("buffersink"); AVFilterInOut *outputs = avfilter_inout_alloc(); AVFilterInOut *inputs = avfilter_inout_alloc(); AVRational time_base = fmt_ctx->streams[video_stream_index]->time_base; enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE }; filter_graph = avfilter_graph_alloc(); if (!outputs || !inputs || !filter_graph) { ret = AVERROR(ENOMEM); goto end; } /* buffer video source: the decoded frames from the decoder will be inserted here. */ snprintf(args, sizeof(args), "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d", dec_ctx->width, dec_ctx->height, dec_ctx->pix_fmt, time_base.num, time_base.den, dec_ctx->sample_aspect_ratio.num, dec_ctx->sample_aspect_ratio.den); ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in", args, NULL, filter_graph); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot create buffer source\n"); goto end; } /* buffer video sink: to terminate the filter chain. */ ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out", NULL, NULL, filter_graph); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot create buffer sink\n"); goto end; } ret = av_opt_set_int_list(buffersink_ctx, "pix_fmts", pix_fmts, AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot set output pixel format\n"); goto end; } /* * Set the endpoints for the filter graph. The filter_graph will * be linked to the graph described by filters_descr. */ /* * The buffer source output must be connected to the input pad of * the first filter described by filters_descr; since the first * filter input label is not specified, it is set to "in" by * default. */ outputs->name = av_strdup("in"); outputs->filter_ctx = buffersrc_ctx; outputs->pad_idx = 0; outputs->next = NULL; /* * The buffer sink input must be connected to the output pad of * the last filter described by filters_descr; since the last * filter output label is not specified, it is set to "out" by * default. */ inputs->name = av_strdup("out"); inputs->filter_ctx = buffersink_ctx; inputs->pad_idx = 0; inputs->next = NULL; if ((ret = avfilter_graph_parse_ptr(filter_graph, filters_descr, &inputs, &outputs, NULL)) < 0) goto end; if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0) goto end; end: avfilter_inout_free(&inputs); avfilter_inout_free(&outputs); return ret; }
// 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 init_filter(FilteringContext* fctx, AVCodecContext *dec_ctx, AVCodecContext *enc_ctx, const char *filter_spec) { char args[512]; int ret = 0; AVFilter *bufferSrc = NULL; AVFilter *bufferSink = NULL; AVFilterContext* bufferSrcCtx = NULL; AVFilterContext* bufferSinkCtx = NULL; AVFilterInOut* outputs = avfilter_inout_alloc(); AVFilterInOut* inputs = avfilter_inout_alloc(); AVFilterGraph* filterGraph = avfilter_graph_alloc(); if (!outputs || !inputs || !filterGraph) { ret = AVERROR(ENOMEM); goto end; } if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) { bufferSrc = avfilter_get_by_name("buffer"); bufferSink = avfilter_get_by_name("buffersink"); if (!bufferSrc || !bufferSink) { av_log(NULL, AV_LOG_ERROR, "filtering source or sink element not found\n"); ret = AVERROR_UNKNOWN; goto end; } snprintf(args, sizeof(args), "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d", dec_ctx->width, dec_ctx->height, dec_ctx->pix_fmt, dec_ctx->time_base.num, dec_ctx->time_base.den, dec_ctx->sample_aspect_ratio.num, dec_ctx->sample_aspect_ratio.den); ret = avfilter_graph_create_filter(&bufferSrcCtx, bufferSrc, "in", args, NULL, filterGraph); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot create buffer source\n"); goto end; } ret = avfilter_graph_create_filter(&bufferSinkCtx, bufferSink, "out", NULL, NULL, filterGraph); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot create buffer sink\n"); goto end; } ret = av_opt_set_bin(bufferSinkCtx, "pix_fmts", (uint8_t*)&enc_ctx->pix_fmt, sizeof(enc_ctx->pix_fmt), AV_OPT_SEARCH_CHILDREN); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot set output pixel format\n"); goto end; } } else if (dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) { bufferSrc = avfilter_get_by_name("abuffer"); bufferSink = avfilter_get_by_name("abuffersink"); if (!bufferSrc || !bufferSink) { av_log(NULL, AV_LOG_ERROR, "filtering source or sink element not found\n"); ret = AVERROR_UNKNOWN; goto end; } if (!dec_ctx->channel_layout) { dec_ctx->channel_layout = av_get_default_channel_layout(dec_ctx->channels); } snprintf(args, sizeof(args), "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%"PRIx64, dec_ctx->time_base.num, dec_ctx->time_base.den, dec_ctx->sample_rate, av_get_sample_fmt_name(dec_ctx->sample_fmt), dec_ctx->channel_layout); ret = avfilter_graph_create_filter(&bufferSrcCtx, bufferSrc, "in", args, NULL, filterGraph); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer source\n"); goto end; } ret = avfilter_graph_create_filter(&bufferSinkCtx, bufferSink, "out", NULL, NULL, filterGraph); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer sink\n"); goto end; } ret = av_opt_set_bin(bufferSinkCtx, "sample_fmts", (uint8_t*)&enc_ctx->sample_fmt, sizeof(enc_ctx->sample_fmt), AV_OPT_SEARCH_CHILDREN); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot set output sample format\n"); goto end; } ret = av_opt_set_bin(bufferSinkCtx, "channel_layouts", (uint8_t*)&enc_ctx->channel_layout, sizeof(enc_ctx->channel_layout), AV_OPT_SEARCH_CHILDREN); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot set output channel layout\n"); goto end; } ret = av_opt_set_bin(bufferSinkCtx, "sample_rates", (uint8_t*)&enc_ctx->sample_rate, sizeof(enc_ctx->sample_rate), AV_OPT_SEARCH_CHILDREN); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot set output sample rate\n"); goto end; } } else { ret = AVERROR_UNKNOWN; goto end; } /* Endpoints for the filter graph. */ outputs->name = av_strdup("in"); outputs->filter_ctx = bufferSrcCtx; outputs->pad_idx = 0; outputs->next = NULL; inputs->name = av_strdup("out"); inputs->filter_ctx = bufferSinkCtx; inputs->pad_idx = 0; inputs->next = NULL; if (!outputs->name || !inputs->name) { ret = AVERROR(ENOMEM); goto end; } if ((ret = avfilter_graph_parse_ptr(filterGraph, filter_spec, &inputs, &outputs, NULL)) < 0) goto end; if ((ret = avfilter_graph_config(filterGraph, NULL)) < 0) goto end; /* Fill FilteringContext */ fctx->BuffersrcCtx = bufferSrcCtx; fctx->BuffersinkCtx = bufferSinkCtx; fctx->FilterGraph = filterGraph; end: avfilter_inout_free(&inputs); avfilter_inout_free(&outputs); return ret; }
void MovieDecoder::initializeFilterGraph(const AVRational& timeBase, int size, bool maintainAspectRatio) { static const AVPixelFormat pixelFormats[] = { AV_PIX_FMT_BGRA, AV_PIX_FMT_NONE }; auto del = [] (AVBufferSinkParams* p) { av_freep(p); }; std::unique_ptr<AVBufferSinkParams, decltype(del)> buffersinkParams(av_buffersink_params_alloc(), del); m_pFilterGraph = avfilter_graph_alloc(); assert(m_pFilterGraph); std::stringstream ss; ss << "video_size=" << GetVideoWidth() << "x" << GetVideoHeight() << ":pix_fmt=" << m_pVideoCodecContext->pix_fmt << ":time_base=" << timeBase.num << "/" << timeBase.den << ":pixel_aspect=" << m_pVideoCodecContext->sample_aspect_ratio.num << "/" << FFMAX(m_pVideoCodecContext->sample_aspect_ratio.den, 1); checkRc(avfilter_graph_create_filter(&m_pFilterSource, avfilter_get_by_name("buffer"), "thumb_buffer", ss.str().c_str(), nullptr, m_pFilterGraph), "Failed to create filter source"); buffersinkParams->pixel_fmts = pixelFormats; checkRc(avfilter_graph_create_filter(&m_pFilterSink, avfilter_get_by_name("buffersink"), "thumb_buffersink", nullptr, buffersinkParams.get(), m_pFilterGraph), "Failed to create filter sink"); buffersinkParams.release(); AVFilterContext* yadifFilter = nullptr; if (m_pFrame->interlaced_frame != 0) { checkRc(avfilter_graph_create_filter(&yadifFilter, avfilter_get_by_name("yadif"), "thumb_deint", "deint=1", nullptr, m_pFilterGraph), "Failed to create deinterlace filter"); } AVFilterContext* scaleFilter = nullptr; checkRc(avfilter_graph_create_filter(&scaleFilter, avfilter_get_by_name("scale"), "thumb_scale", createScaleString(size, maintainAspectRatio).c_str(), nullptr, m_pFilterGraph), "Failed to create scale filter"); AVFilterContext* formatFilter = nullptr; checkRc(avfilter_graph_create_filter(&formatFilter, avfilter_get_by_name("format"), "thumb_format", "pix_fmts=bgra", nullptr, m_pFilterGraph), "Failed to create format filter"); AVFilterContext* rotateFilter = nullptr; auto rotation = getStreamRotation(); if (rotation != -1) { checkRc(avfilter_graph_create_filter(&rotateFilter, avfilter_get_by_name("transpose"), "thumb_rotate", to_string(rotation).c_str(), nullptr, m_pFilterGraph), "Failed to create rotate filter"); } checkRc(avfilter_link(rotateFilter ? rotateFilter : formatFilter, 0, m_pFilterSink, 0), "Failed to link final filter"); if (rotateFilter) { checkRc(avfilter_link(formatFilter, 0, rotateFilter, 0), "Failed to link format filter"); } checkRc(avfilter_link(scaleFilter, 0, formatFilter, 0), "Failed to link scale filter"); if (yadifFilter) { checkRc(avfilter_link(yadifFilter, 0, scaleFilter, 0), "Failed to link yadif filter"); } checkRc(avfilter_link(m_pFilterSource, 0, yadifFilter ? yadifFilter : scaleFilter, 0), "Failed to link source filter"); checkRc(avfilter_graph_config(m_pFilterGraph, nullptr), "Failed to configure filter graph"); }
static int init_filters(const char *filters_descr) { char args[512]; int ret = 0; AVFilter *abuffersrc = avfilter_get_by_name("abuffer"); AVFilter *abuffersink = avfilter_get_by_name("abuffersink"); AVFilterInOut *outputs = avfilter_inout_alloc(); AVFilterInOut *inputs = avfilter_inout_alloc(); static const enum AVSampleFormat out_sample_fmts[] = { AV_SAMPLE_FMT_S16, -1 }; static const int64_t out_channel_layouts[] = { AV_CH_LAYOUT_MONO, -1 }; static const int out_sample_rates[] = { 8000, -1 }; const AVFilterLink *outlink; AVRational time_base = fmt_ctx->streams[audio_stream_index]->time_base; filter_graph = avfilter_graph_alloc(); if (!outputs || !inputs || !filter_graph) { ret = AVERROR(ENOMEM); goto end; } /* buffer audio source: the decoded frames from the decoder will be inserted here. */ if (!dec_ctx->channel_layout) dec_ctx->channel_layout = av_get_default_channel_layout(dec_ctx->channels); snprintf(args, sizeof(args), "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%"PRIx64, time_base.num, time_base.den, dec_ctx->sample_rate, av_get_sample_fmt_name(dec_ctx->sample_fmt), dec_ctx->channel_layout); ret = avfilter_graph_create_filter(&buffersrc_ctx, abuffersrc, "in", args, NULL, filter_graph); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer source\n"); goto end; } /* buffer audio sink: to terminate the filter chain. */ ret = avfilter_graph_create_filter(&buffersink_ctx, abuffersink, "out", NULL, NULL, filter_graph); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer sink\n"); goto end; } ret = av_opt_set_int_list(buffersink_ctx, "sample_fmts", out_sample_fmts, -1, AV_OPT_SEARCH_CHILDREN); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot set output sample format\n"); goto end; } ret = av_opt_set_int_list(buffersink_ctx, "channel_layouts", out_channel_layouts, -1, AV_OPT_SEARCH_CHILDREN); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot set output channel layout\n"); goto end; } ret = av_opt_set_int_list(buffersink_ctx, "sample_rates", out_sample_rates, -1, AV_OPT_SEARCH_CHILDREN); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot set output sample rate\n"); goto end; } /* Endpoints for the filter graph. */ outputs->name = av_strdup("in"); outputs->filter_ctx = buffersrc_ctx; outputs->pad_idx = 0; outputs->next = NULL; inputs->name = av_strdup("out"); inputs->filter_ctx = buffersink_ctx; inputs->pad_idx = 0; inputs->next = NULL; if ((ret = avfilter_graph_parse_ptr(filter_graph, filters_descr, &inputs, &outputs, NULL)) < 0) goto end; if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0) goto end; /* Print summary of the sink buffer * Note: args buffer is reused to store channel layout string */ outlink = buffersink_ctx->inputs[0]; av_get_channel_layout_string(args, sizeof(args), -1, outlink->channel_layout); av_log(NULL, AV_LOG_INFO, "Output: srate:%dHz fmt:%s chlayout:%s\n", (int)outlink->sample_rate, (char *)av_x_if_null(av_get_sample_fmt_name(outlink->format), "?"), args); end: avfilter_inout_free(&inputs); avfilter_inout_free(&outputs); return ret; }
void configure_filtergraph() { if (filtergraph_.empty()) { video_graph_.reset(); return; } video_graph_.reset( avfilter_graph_alloc(), [](AVFilterGraph* p) { avfilter_graph_free(&p); }); const auto vsrc_options = (boost::format("video_size=%1%x%2%:pix_fmt=%3%:time_base=%4%/%5%:pixel_aspect=%6%/%7%") % in_width_ % in_height_ % in_pix_format_ % in_time_base_.num % in_time_base_.den % in_sample_aspect_ratio_.num % in_sample_aspect_ratio_.den).str(); AVFilterContext* filt_vsrc = nullptr; FF(avfilter_graph_create_filter( &filt_vsrc, avfilter_get_by_name("buffer"), "filter_buffer", vsrc_options.c_str(), nullptr, video_graph_.get())); AVFilterContext* filt_vsink = nullptr; FF(avfilter_graph_create_filter( &filt_vsink, avfilter_get_by_name("buffersink"), "filter_buffersink", nullptr, nullptr, video_graph_.get())); #pragma warning (push) #pragma warning (disable : 4245) FF(av_opt_set_int_list( filt_vsink, "pix_fmts", out_pix_fmts_.data(), -1, AV_OPT_SEARCH_CHILDREN)); #pragma warning (pop) try { configure_filtergraph( *video_graph_, filtergraph_, *filt_vsrc, *filt_vsink); video_graph_in_ = filt_vsrc; video_graph_out_ = filt_vsink; CASPAR_LOG(trace) << L"Filter configured:\n" << avfilter_graph_dump(video_graph_.get(), nullptr); } catch (...) { CASPAR_LOG(error) << L"Cannot configure filtergraph: " << filtergraph_.c_str(); filtergraph_.clear(); // disable filtering on configure_filtergraph failure } }
static int query_formats(AVFilterGraph *graph, AVClass *log_ctx) { int i, j, ret; int scaler_count = 0, resampler_count = 0; /* ask all the sub-filters for their supported media formats */ for (i = 0; i < graph->filter_count; i++) { if (graph->filters[i]->filter->query_formats) graph->filters[i]->filter->query_formats(graph->filters[i]); else avfilter_default_query_formats(graph->filters[i]); } /* go through and merge as many format lists as possible */ for (i = 0; i < graph->filter_count; i++) { AVFilterContext *filter = graph->filters[i]; for (j = 0; j < filter->input_count; j++) { AVFilterLink *link = filter->inputs[j]; int convert_needed = 0; if (!link) continue; if (link->in_formats != link->out_formats && !avfilter_merge_formats(link->in_formats, link->out_formats)) convert_needed = 1; if (link->type == AVMEDIA_TYPE_AUDIO) { if (link->in_channel_layouts != link->out_channel_layouts && !ff_merge_channel_layouts(link->in_channel_layouts, link->out_channel_layouts)) convert_needed = 1; if (link->in_samplerates != link->out_samplerates && !ff_merge_samplerates(link->in_samplerates, link->out_samplerates)) convert_needed = 1; } if (convert_needed) { AVFilterContext *convert; AVFilter *filter; AVFilterLink *inlink, *outlink; char scale_args[256]; char inst_name[30]; /* couldn't merge format lists. auto-insert conversion filter */ switch (link->type) { case AVMEDIA_TYPE_VIDEO: snprintf(inst_name, sizeof(inst_name), "auto-inserted scaler %d", scaler_count++); snprintf(scale_args, sizeof(scale_args), "0:0:%s", graph->scale_sws_opts); if ((ret = avfilter_graph_create_filter(&convert, avfilter_get_by_name("scale"), inst_name, scale_args, NULL, graph)) < 0) return ret; break; case AVMEDIA_TYPE_AUDIO: if (!(filter = avfilter_get_by_name("resample"))) { av_log(log_ctx, AV_LOG_ERROR, "'resample' filter " "not present, cannot convert audio formats.\n"); return AVERROR(EINVAL); } snprintf(inst_name, sizeof(inst_name), "auto-inserted resampler %d", resampler_count++); if ((ret = avfilter_graph_create_filter(&convert, avfilter_get_by_name("resample"), inst_name, NULL, NULL, graph)) < 0) return ret; break; default: return AVERROR(EINVAL); } if ((ret = avfilter_insert_filter(link, convert, 0, 0)) < 0) return ret; convert->filter->query_formats(convert); inlink = convert->inputs[0]; outlink = convert->outputs[0]; if (!avfilter_merge_formats( inlink->in_formats, inlink->out_formats) || !avfilter_merge_formats(outlink->in_formats, outlink->out_formats)) ret |= AVERROR(ENOSYS); if (inlink->type == AVMEDIA_TYPE_AUDIO && (!ff_merge_samplerates(inlink->in_samplerates, inlink->out_samplerates) || !ff_merge_channel_layouts(inlink->in_channel_layouts, inlink->out_channel_layouts))) ret |= AVERROR(ENOSYS); if (outlink->type == AVMEDIA_TYPE_AUDIO && (!ff_merge_samplerates(outlink->in_samplerates, outlink->out_samplerates) || !ff_merge_channel_layouts(outlink->in_channel_layouts, outlink->out_channel_layouts))) ret |= AVERROR(ENOSYS); if (ret < 0) { av_log(log_ctx, AV_LOG_ERROR, "Impossible to convert between the formats supported by the filter " "'%s' and the filter '%s'\n", link->src->name, link->dst->name); return ret; } } } } return 0; }