int configure_filtergraph(FilterGraph *fg) { AVFilterInOut *inputs, *outputs, *cur; int ret, i, init = !fg->graph, simple = !fg->graph_desc; const char *graph_desc = simple ? fg->outputs[0]->ost->avfilter : fg->graph_desc; avfilter_graph_free(&fg->graph); if (!(fg->graph = avfilter_graph_alloc())) return AVERROR(ENOMEM); if (simple) { OutputStream *ost = fg->outputs[0]->ost; char args[255]; snprintf(args, sizeof(args), "flags=0x%X", (unsigned)ost->sws_flags); fg->graph->scale_sws_opts = av_strdup(args); } if ((ret = avfilter_graph_parse2(fg->graph, graph_desc, &inputs, &outputs)) < 0) return ret; if (simple && (!inputs || inputs->next || !outputs || outputs->next)) { av_log(NULL, AV_LOG_ERROR, "Simple filtergraph '%s' does not have " "exactly one input and output.\n", graph_desc); return AVERROR(EINVAL); } for (cur = inputs; !simple && init && cur; cur = cur->next) init_input_filter(fg, cur); for (cur = inputs, i = 0; cur; cur = cur->next, i++) if ((ret = configure_input_filter(fg, fg->inputs[i], cur)) < 0) return ret; avfilter_inout_free(&inputs); if (!init || simple) { /* we already know the mappings between lavfi outputs and output streams, * so we can finish the setup */ for (cur = outputs, i = 0; cur; cur = cur->next, i++) configure_output_filter(fg, fg->outputs[i], cur); avfilter_inout_free(&outputs); if ((ret = avfilter_graph_config(fg->graph, NULL)) < 0) return ret; } else { /* wait until output mappings are processed */ for (cur = outputs; cur;) { fg->outputs = grow_array(fg->outputs, sizeof(*fg->outputs), &fg->nb_outputs, fg->nb_outputs + 1); if (!(fg->outputs[fg->nb_outputs - 1] = av_mallocz(sizeof(*fg->outputs[0])))) exit(1); fg->outputs[fg->nb_outputs - 1]->graph = fg; fg->outputs[fg->nb_outputs - 1]->out_tmp = cur; cur = cur->next; fg->outputs[fg->nb_outputs - 1]->out_tmp->next = NULL; } } return 0; }
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 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; }
FilterGraph::FilterGraph(const ICodec& codec) : _graph(avfilter_graph_alloc()) , _filters() , _codec(codec) , _isInit(false) { if(!_graph) throw std::runtime_error("Unable to create filter graph: out of memory."); }
int configure_filtergraph(FilterGraph *fg) { AVFilterInOut *inputs, *outputs, *cur; int ret, i, simple = !fg->graph_desc; const char *graph_desc = simple ? fg->outputs[0]->ost->avfilter : fg->graph_desc; avfilter_graph_free(&fg->graph); if (!(fg->graph = avfilter_graph_alloc())) return AVERROR(ENOMEM); if (simple) { OutputStream *ost = fg->outputs[0]->ost; char args[512]; AVDictionaryEntry *e = NULL; snprintf(args, sizeof(args), "flags=0x%X", (unsigned)ost->sws_flags); fg->graph->scale_sws_opts = av_strdup(args); args[0] = '\0'; while ((e = av_dict_get(fg->outputs[0]->ost->resample_opts, "", e, AV_DICT_IGNORE_SUFFIX))) { av_strlcatf(args, sizeof(args), "%s=%s:", e->key, e->value); } if (strlen(args)) args[strlen(args) - 1] = '\0'; fg->graph->resample_lavr_opts = av_strdup(args); } if ((ret = avfilter_graph_parse2(fg->graph, graph_desc, &inputs, &outputs)) < 0) return ret; if (simple && (!inputs || inputs->next || !outputs || outputs->next)) { av_log(NULL, AV_LOG_ERROR, "Simple filtergraph '%s' does not have " "exactly one input and output.\n", graph_desc); return AVERROR(EINVAL); } for (cur = inputs, i = 0; cur; cur = cur->next, i++) if ((ret = configure_input_filter(fg, fg->inputs[i], cur)) < 0) return ret; avfilter_inout_free(&inputs); for (cur = outputs, i = 0; cur; cur = cur->next, i++) configure_output_filter(fg, fg->outputs[i], cur); avfilter_inout_free(&outputs); if ((ret = avfilter_graph_config(fg->graph, NULL)) < 0) return ret; return 0; }
int configure_filter(struct liveStream *ctx) { int ret = 0; int i = 0; /** Input Id */ long in_id; AVFilterInOut *outputs; AVFilterInOut *inputs; AVFilterInOut *cur; take_filter_lock(&ctx->filter_lock); avfilter_graph_free(&ctx->filter_graph); ctx->filter_graph = avfilter_graph_alloc(); if (NULL == ctx->filter_graph) { av_log(NULL,AV_LOG_ERROR,"Unable to allocate Filter\n"); return -1; } ret = avfilter_graph_parse2(ctx->filter_graph, ctx->graph_desc.str, &inputs, &outputs); if(ret < 0) return ret; for (i = 0,cur = inputs; cur; cur = cur->next,i++) { in_id = strtol(cur->name,NULL,0); if(in_id < 0 || in_id >= ctx->nb_input) { /** Invalid index of video provided */ ret = -1; break; } configure_input_filter(ctx, in_id, cur); } avfilter_inout_free(&inputs); ret = configure_output_filter(ctx,outputs); if(ret < 0) { printf("unable to configure output filter\n"); return ret; } avfilter_inout_free(&outputs); if ((ret = avfilter_graph_config(ctx->filter_graph, NULL)) < 0) return ret; give_filter_lock(&ctx->filter_lock); return 0; }
int init_complex_filtergraph(FilterGraph *fg) { AVFilterInOut *inputs, *outputs, *cur; AVFilterGraph *graph; int ret = 0; /* this graph is only used for determining the kinds of inputs * and outputs we have, and is discarded on exit from this function */ graph = avfilter_graph_alloc(); if(!graph) { return AVERROR(ENOMEM); } ret = avfilter_graph_parse2(graph, fg->graph_desc, &inputs, &outputs); if(ret < 0) { goto fail; } for(cur = inputs; cur; cur = cur->next) { init_input_filter(fg, cur); } for(cur = outputs; cur;) { GROW_ARRAY(fg->outputs, fg->nb_outputs); fg->outputs[fg->nb_outputs - 1] = av_mallocz(sizeof(*fg->outputs[0])); if(!fg->outputs[fg->nb_outputs - 1]) { exit_program(1); } fg->outputs[fg->nb_outputs - 1]->graph = fg; fg->outputs[fg->nb_outputs - 1]->out_tmp = cur; fg->outputs[fg->nb_outputs - 1]->type = avfilter_pad_get_type(cur->filter_ctx->output_pads, cur->pad_idx); cur = cur->next; fg->outputs[fg->nb_outputs - 1]->out_tmp->next = NULL; } fail: avfilter_inout_free(&inputs); avfilter_graph_free(&graph); return ret; }
bool MovieDecoder::initFilterGraph(enum AVPixelFormat pixfmt, int width, int height) { AVFilterInOut *inputs = nullptr, *outputs = nullptr; deleteFilterGraph(); m_filterGraph = avfilter_graph_alloc(); QByteArray arguments("buffer="); arguments += "video_size=" + QByteArray::number(width) + "x" + QByteArray::number(height) + ":"; arguments += "pix_fmt=" + QByteArray::number(pixfmt) + ":"; arguments += "time_base=1/1:pixel_aspect=0/1[in];"; arguments += "[in]yadif[out];"; arguments += "[out]buffersink"; int ret = avfilter_graph_parse2(m_filterGraph, arguments.constData(), &inputs, &outputs); if (ret < 0) { qWarning() << "Unable to parse filter graph"; return false; } if(inputs || outputs) return -1; ret = avfilter_graph_config(m_filterGraph, nullptr); if (ret < 0) { qWarning() << "Unable to validate filter graph"; return false; } m_bufferSourceContext = avfilter_graph_get_filter(m_filterGraph, "Parsed_buffer_0"); m_bufferSinkContext = avfilter_graph_get_filter(m_filterGraph, "Parsed_buffersink_2"); if (!m_bufferSourceContext || !m_bufferSinkContext) { qWarning() << "Unable to get source or sink"; return false; } m_filterFrame = av_frame_alloc(); m_lastWidth = width; m_lastHeight = height; m_lastPixfmt = pixfmt; return true; }
JNIEXPORT jlong JNICALL Java_org_jitsi_impl_neomedia_codec_FFmpeg_avfilter_1graph_1alloc (JNIEnv *env, jclass clazz) { return (jlong) (intptr_t) avfilter_graph_alloc(); }
int main(int argc, char **argv) { char *in_graph_desc, **out_dev_name; int nb_out_dev = 0, nb_streams = 0; AVFilterGraph *in_graph = NULL; Stream *streams = NULL, *st; AVFrame *frame = NULL; int i, j, run = 1, ret; //av_log_set_level(AV_LOG_DEBUG); if (argc < 3) { av_log(NULL, AV_LOG_ERROR, "Usage: %s filter_graph dev:out [dev2:out2...]\n\n" "Examples:\n" "%s movie=file.nut:s=v+a xv:- alsa:default\n" "%s movie=file.nut:s=v+a uncodedframecrc:pipe:0\n", argv[0], argv[0], argv[0]); exit(1); } in_graph_desc = argv[1]; out_dev_name = argv + 2; nb_out_dev = argc - 2; av_register_all(); avdevice_register_all(); avfilter_register_all(); /* Create input graph */ if (!(in_graph = avfilter_graph_alloc())) { ret = AVERROR(ENOMEM); av_log(NULL, AV_LOG_ERROR, "Unable to alloc graph graph: %s\n", av_err2str(ret)); goto fail; } ret = avfilter_graph_parse_ptr(in_graph, in_graph_desc, NULL, NULL, NULL); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Unable to parse graph: %s\n", av_err2str(ret)); goto fail; } nb_streams = 0; for (i = 0; i < in_graph->nb_filters; i++) { AVFilterContext *f = in_graph->filters[i]; for (j = 0; j < f->nb_inputs; j++) { if (!f->inputs[j]) { av_log(NULL, AV_LOG_ERROR, "Graph has unconnected inputs\n"); ret = AVERROR(EINVAL); goto fail; } } for (j = 0; j < f->nb_outputs; j++) if (!f->outputs[j]) nb_streams++; } if (!nb_streams) { av_log(NULL, AV_LOG_ERROR, "Graph has no output stream\n"); ret = AVERROR(EINVAL); goto fail; } if (nb_out_dev != 1 && nb_out_dev != nb_streams) { av_log(NULL, AV_LOG_ERROR, "Graph has %d output streams, %d devices given\n", nb_streams, nb_out_dev); ret = AVERROR(EINVAL); goto fail; } if (!(streams = av_calloc(nb_streams, sizeof(*streams)))) { ret = AVERROR(ENOMEM); av_log(NULL, AV_LOG_ERROR, "Could not allocate streams\n"); } st = streams; for (i = 0; i < in_graph->nb_filters; i++) { AVFilterContext *f = in_graph->filters[i]; for (j = 0; j < f->nb_outputs; j++) { if (!f->outputs[j]) { if ((ret = create_sink(st++, in_graph, f, j)) < 0) goto fail; } } } av_assert0(st - streams == nb_streams); if ((ret = avfilter_graph_config(in_graph, NULL)) < 0) { av_log(NULL, AV_LOG_ERROR, "Failed to configure graph\n"); goto fail; } /* Create output devices */ for (i = 0; i < nb_out_dev; i++) { char *fmt = NULL, *dev = out_dev_name[i]; st = &streams[i]; if ((dev = strchr(dev, ':'))) { *(dev++) = 0; fmt = out_dev_name[i]; } ret = avformat_alloc_output_context2(&st->mux, NULL, fmt, dev); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Failed to allocate output: %s\n", av_err2str(ret)); goto fail; } if (!(st->mux->oformat->flags & AVFMT_NOFILE)) { ret = avio_open2(&st->mux->pb, st->mux->filename, AVIO_FLAG_WRITE, NULL, NULL); if (ret < 0) { av_log(st->mux, AV_LOG_ERROR, "Failed to init output: %s\n", av_err2str(ret)); goto fail; } } } for (; i < nb_streams; i++) streams[i].mux = streams[0].mux; /* Create output device streams */ for (i = 0; i < nb_streams; i++) { st = &streams[i]; if (!(st->stream = avformat_new_stream(st->mux, NULL))) { ret = AVERROR(ENOMEM); av_log(NULL, AV_LOG_ERROR, "Failed to create output stream\n"); goto fail; } st->stream->codec->codec_type = st->link->type; st->stream->time_base = st->stream->codec->time_base = st->link->time_base; switch (st->link->type) { case AVMEDIA_TYPE_VIDEO: st->stream->codec->codec_id = AV_CODEC_ID_RAWVIDEO; st->stream->avg_frame_rate = st->stream-> r_frame_rate = av_buffersink_get_frame_rate(st->sink); st->stream->codec->width = st->link->w; st->stream->codec->height = st->link->h; st->stream->codec->sample_aspect_ratio = st->link->sample_aspect_ratio; st->stream->codec->pix_fmt = st->link->format; break; case AVMEDIA_TYPE_AUDIO: st->stream->codec->channel_layout = st->link->channel_layout; st->stream->codec->channels = avfilter_link_get_channels(st->link); st->stream->codec->sample_rate = st->link->sample_rate; st->stream->codec->sample_fmt = st->link->format; st->stream->codec->codec_id = av_get_pcm_codec(st->stream->codec->sample_fmt, -1); break; default: av_assert0(!"reached"); } } /* Init output devices */ for (i = 0; i < nb_out_dev; i++) { st = &streams[i]; if ((ret = avformat_write_header(st->mux, NULL)) < 0) { av_log(st->mux, AV_LOG_ERROR, "Failed to init output: %s\n", av_err2str(ret)); goto fail; } } /* Check output devices */ for (i = 0; i < nb_streams; i++) { st = &streams[i]; ret = av_write_uncoded_frame_query(st->mux, st->stream->index); if (ret < 0) { av_log(st->mux, AV_LOG_ERROR, "Uncoded frames not supported on stream #%d: %s\n", i, av_err2str(ret)); goto fail; } } while (run) { ret = avfilter_graph_request_oldest(in_graph); if (ret < 0) { if (ret == AVERROR_EOF) { run = 0; } else { av_log(NULL, AV_LOG_ERROR, "Error filtering: %s\n", av_err2str(ret)); break; } } for (i = 0; i < nb_streams; i++) { st = &streams[i]; while (1) { if (!frame && !(frame = av_frame_alloc())) { ret = AVERROR(ENOMEM); av_log(NULL, AV_LOG_ERROR, "Could not allocate frame\n"); goto fail; } ret = av_buffersink_get_frame_flags(st->sink, frame, AV_BUFFERSINK_FLAG_NO_REQUEST); if (ret < 0) { if (ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) av_log(NULL, AV_LOG_WARNING, "Error in sink: %s\n", av_err2str(ret)); break; } if (frame->pts != AV_NOPTS_VALUE) frame->pts = av_rescale_q(frame->pts, st->link ->time_base, st->stream->time_base); ret = av_interleaved_write_uncoded_frame(st->mux, st->stream->index, frame); frame = NULL; if (ret < 0) { av_log(st->stream->codec, AV_LOG_ERROR, "Error writing frame: %s\n", av_err2str(ret)); goto fail; } } } } ret = 0; for (i = 0; i < nb_out_dev; i++) { st = &streams[i]; av_write_trailer(st->mux); } fail: av_frame_free(&frame); avfilter_graph_free(&in_graph); if (streams) { for (i = 0; i < nb_out_dev; i++) { st = &streams[i]; if (st->mux) { if (st->mux->pb) avio_closep(&st->mux->pb); avformat_free_context(st->mux); } } } av_freep(&streams); return ret < 0; }
// abuffer -> volume -> asplit for each audio format // -> aformat -> abuffersink // if the volume gain is > 1.0, we use a compand filter instead // for soft limiting. static int init_filter_graph(struct GroovePlaylist *playlist, struct GrooveFile *file) { struct GroovePlaylistPrivate *p = (struct GroovePlaylistPrivate *) playlist; struct GrooveFilePrivate *f = (struct GrooveFilePrivate *) file; // destruct old graph avfilter_graph_free(&p->filter_graph); // create new graph p->filter_graph = avfilter_graph_alloc(); if (!p->filter_graph) { av_log(NULL, AV_LOG_ERROR, "unable to create filter graph: out of memory\n"); return -1; } AVFilter *abuffer = avfilter_get_by_name("abuffer"); AVFilter *volume = avfilter_get_by_name("volume"); AVFilter *compand = avfilter_get_by_name("compand"); AVFilter *asplit = avfilter_get_by_name("asplit"); AVFilter *aformat = avfilter_get_by_name("aformat"); AVFilter *abuffersink = avfilter_get_by_name("abuffersink"); int err; // create abuffer filter AVCodecContext *avctx = f->audio_st->codec; AVRational time_base = f->audio_st->time_base; snprintf(p->strbuf, sizeof(p->strbuf), "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%"PRIx64, time_base.num, time_base.den, avctx->sample_rate, av_get_sample_fmt_name(avctx->sample_fmt), avctx->channel_layout); av_log(NULL, AV_LOG_INFO, "abuffer: %s\n", p->strbuf); // save these values so we can compare later and check // whether we have to reconstruct the graph p->in_sample_rate = avctx->sample_rate; p->in_channel_layout = avctx->channel_layout; p->in_sample_fmt = avctx->sample_fmt; p->in_time_base = time_base; err = avfilter_graph_create_filter(&p->abuffer_ctx, abuffer, NULL, p->strbuf, NULL, p->filter_graph); if (err < 0) { av_log(NULL, AV_LOG_ERROR, "error initializing abuffer filter\n"); return err; } // as we create filters, this points the next source to link to AVFilterContext *audio_src_ctx = p->abuffer_ctx; // save the volume value so we can compare later and check // whether we have to reconstruct the graph p->filter_volume = p->volume; // if volume is < 1.0, create volume filter // == 1.0, do not create a filter // > 1.0, create a compand filter (for soft limiting) double vol = p->volume; if (vol < 0.0) vol = 0.0; if (vol < 1.0) { snprintf(p->strbuf, sizeof(p->strbuf), "volume=%f", vol); av_log(NULL, AV_LOG_INFO, "volume: %s\n", p->strbuf); err = avfilter_graph_create_filter(&p->volume_ctx, volume, NULL, p->strbuf, NULL, p->filter_graph); if (err < 0) { av_log(NULL, AV_LOG_ERROR, "error initializing volume filter\n"); return err; } err = avfilter_link(audio_src_ctx, 0, p->volume_ctx, 0); if (err < 0) { av_log(NULL, AV_LOG_ERROR, "unable to link filters\n"); return err; } audio_src_ctx = p->volume_ctx; } else if (vol > 1.0) { double attack = 0.1; double decay = 0.2; const char *points = "-2/-2"; double soft_knee = 0.02; double gain = gain_to_dB(vol); double volume_param = 0.0; double delay = 0.2; snprintf(p->strbuf, sizeof(p->strbuf), "%f:%f:%s:%f:%f:%f:%f", attack, decay, points, soft_knee, gain, volume_param, delay); av_log(NULL, AV_LOG_INFO, "compand: %s\n", p->strbuf); err = avfilter_graph_create_filter(&p->compand_ctx, compand, NULL, p->strbuf, NULL, p->filter_graph); if (err < 0) { av_log(NULL, AV_LOG_ERROR, "error initializing compand filter\n"); return err; } err = avfilter_link(audio_src_ctx, 0, p->compand_ctx, 0); if (err < 0) { av_log(NULL, AV_LOG_ERROR, "unable to link filters\n"); return err; } audio_src_ctx = p->compand_ctx; } else { p->volume_ctx = NULL; } // if only one sink, no need for asplit if (p->sink_map_count < 2) { p->asplit_ctx = NULL; } else { snprintf(p->strbuf, sizeof(p->strbuf), "%d", p->sink_map_count); av_log(NULL, AV_LOG_INFO, "asplit: %s\n", p->strbuf); err = avfilter_graph_create_filter(&p->asplit_ctx, asplit, NULL, p->strbuf, NULL, p->filter_graph); if (err < 0) { av_log(NULL, AV_LOG_ERROR, "unable to create asplit filter\n"); return err; } err = avfilter_link(audio_src_ctx, 0, p->asplit_ctx, 0); if (err < 0) { av_log(NULL, AV_LOG_ERROR, "unable to link to asplit\n"); return err; } audio_src_ctx = p->asplit_ctx; } // for each audio format, create aformat and abuffersink filters struct SinkMap *map_item = p->sink_map; int pad_index = 0; while (map_item) { struct GrooveSink *example_sink = map_item->stack_head->sink; struct GrooveAudioFormat *audio_format = &example_sink->audio_format; AVFilterContext *inner_audio_src_ctx = audio_src_ctx; if (example_sink->disable_resample) { map_item->aformat_ctx = NULL; } else { // create aformat filter snprintf(p->strbuf, sizeof(p->strbuf), "sample_fmts=%s:sample_rates=%d:channel_layouts=0x%"PRIx64, av_get_sample_fmt_name((enum AVSampleFormat)audio_format->sample_fmt), audio_format->sample_rate, audio_format->channel_layout); av_log(NULL, AV_LOG_INFO, "aformat: %s\n", p->strbuf); err = avfilter_graph_create_filter(&map_item->aformat_ctx, aformat, NULL, p->strbuf, NULL, p->filter_graph); if (err < 0) { av_strerror(err, p->strbuf, sizeof(p->strbuf)); av_log(NULL, AV_LOG_ERROR, "unable to create aformat filter: %s\n", p->strbuf); return err; } err = avfilter_link(audio_src_ctx, pad_index, map_item->aformat_ctx, 0); if (err < 0) { av_log(NULL, AV_LOG_ERROR, "unable to link filters\n"); return err; } inner_audio_src_ctx = map_item->aformat_ctx; } // create abuffersink filter err = avfilter_graph_create_filter(&map_item->abuffersink_ctx, abuffersink, NULL, NULL, NULL, p->filter_graph); if (err < 0) { av_log(NULL, AV_LOG_ERROR, "unable to create abuffersink filter\n"); return err; } err = avfilter_link(inner_audio_src_ctx, 0, map_item->abuffersink_ctx, 0); if (err < 0) { av_log(NULL, AV_LOG_ERROR, "unable to link filters\n"); return err; } pad_index += 1; map_item = map_item->next; } err = avfilter_graph_config(p->filter_graph, NULL); if (err < 0) { av_strerror(err, p->strbuf, sizeof(p->strbuf)); av_log(NULL, AV_LOG_ERROR, "error configuring the filter graph: %s\n", p->strbuf); return err; } p->rebuild_filter_graph_flag = 0; return 0; }
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 } }
HRESULT CLAVVideo::Filter(LAVFrame *pFrame) { int ret = 0; BOOL bFlush = pFrame->flags & LAV_FRAME_FLAG_FLUSH; if (m_Decoder.IsInterlaced(FALSE) && m_settings.DeintMode != DeintMode_Disable && (m_settings.SWDeintMode == SWDeintMode_YADIF || m_settings.SWDeintMode == SWDeintMode_W3FDIF_Simple || m_settings.SWDeintMode == SWDeintMode_W3FDIF_Complex) && ((bFlush && m_pFilterGraph) || pFrame->format == LAVPixFmt_YUV420 || pFrame->format == LAVPixFmt_YUV422 || pFrame->format == LAVPixFmt_NV12)) { AVPixelFormat ff_pixfmt = (pFrame->format == LAVPixFmt_YUV420) ? AV_PIX_FMT_YUV420P : (pFrame->format == LAVPixFmt_YUV422) ? AV_PIX_FMT_YUV422P : AV_PIX_FMT_NV12; if (!bFlush && (!m_pFilterGraph || pFrame->format != m_filterPixFmt || pFrame->width != m_filterWidth || pFrame->height != m_filterHeight)) { DbgLog((LOG_TRACE, 10, L":Filter()(init) Initializing YADIF deinterlacing filter...")); if (m_pFilterGraph) { avfilter_graph_free(&m_pFilterGraph); m_pFilterBufferSrc = nullptr; m_pFilterBufferSink = nullptr; } m_filterPixFmt = pFrame->format; m_filterWidth = pFrame->width; m_filterHeight = pFrame->height; char args[512]; enum AVPixelFormat pix_fmts[3]; if (ff_pixfmt == AV_PIX_FMT_NV12) { pix_fmts[0] = AV_PIX_FMT_NV12; pix_fmts[1] = AV_PIX_FMT_YUV420P; } else { pix_fmts[0] = ff_pixfmt; pix_fmts[1] = AV_PIX_FMT_NONE; } pix_fmts[2] = AV_PIX_FMT_NONE; AVFilter *buffersrc = avfilter_get_by_name("buffer"); AVFilter *buffersink = avfilter_get_by_name("buffersink"); AVFilterInOut *outputs = avfilter_inout_alloc(); AVFilterInOut *inputs = avfilter_inout_alloc(); m_pFilterGraph = avfilter_graph_alloc(); av_opt_set(m_pFilterGraph, "thread_type", "slice", AV_OPT_SEARCH_CHILDREN); av_opt_set_int(m_pFilterGraph, "threads", FFMAX(1, av_cpu_count() / 2), AV_OPT_SEARCH_CHILDREN); // 0/0 is not a valid value for avfilter, make sure it doesn't happen AVRational aspect_ratio = pFrame->aspect_ratio; if (aspect_ratio.num == 0 || aspect_ratio.den == 0) aspect_ratio = { 0, 1 }; _snprintf_s(args, sizeof(args), "video_size=%dx%d:pix_fmt=%s:time_base=1/10000000:pixel_aspect=%d/%d", pFrame->width, pFrame->height, av_get_pix_fmt_name(ff_pixfmt), pFrame->aspect_ratio.num, pFrame->aspect_ratio.den); ret = avfilter_graph_create_filter(&m_pFilterBufferSrc, buffersrc, "in", args, nullptr, m_pFilterGraph); if (ret < 0) { DbgLog((LOG_TRACE, 10, L"::Filter()(init) Creating the input buffer filter failed with code %d", ret)); avfilter_graph_free(&m_pFilterGraph); goto deliver; } ret = avfilter_graph_create_filter(&m_pFilterBufferSink, buffersink, "out", nullptr, nullptr, m_pFilterGraph); if (ret < 0) { DbgLog((LOG_TRACE, 10, L"::Filter()(init) Creating the buffer sink filter failed with code %d", ret)); avfilter_free(m_pFilterBufferSrc); m_pFilterBufferSrc = nullptr; avfilter_graph_free(&m_pFilterGraph); goto deliver; } /* set allowed pixfmts on the output */ av_opt_set_int_list(m_pFilterBufferSink->priv, "pix_fmts", pix_fmts, AV_PIX_FMT_NONE, 0); /* Endpoints for the filter graph. */ outputs->name = av_strdup("in"); outputs->filter_ctx = m_pFilterBufferSrc; outputs->pad_idx = 0; outputs->next = nullptr; inputs->name = av_strdup("out"); inputs->filter_ctx = m_pFilterBufferSink; inputs->pad_idx = 0; inputs->next = nullptr; if (m_settings.SWDeintMode == SWDeintMode_YADIF) _snprintf_s(args, sizeof(args), "yadif=mode=%s:parity=auto:deint=interlaced", (m_settings.SWDeintOutput == DeintOutput_FramePerField) ? "send_field" : "send_frame"); else if (m_settings.SWDeintMode == SWDeintMode_W3FDIF_Simple) _snprintf_s(args, sizeof(args), "w3fdif=filter=simple:deint=interlaced"); else if (m_settings.SWDeintMode == SWDeintMode_W3FDIF_Complex) _snprintf_s(args, sizeof(args), "w3fdif=filter=complex:deint=interlaced"); else ASSERT(0); if ((ret = avfilter_graph_parse_ptr(m_pFilterGraph, args, &inputs, &outputs, nullptr)) < 0) { DbgLog((LOG_TRACE, 10, L"::Filter()(init) Parsing the graph failed with code %d", ret)); avfilter_graph_free(&m_pFilterGraph); goto deliver; } if ((ret = avfilter_graph_config(m_pFilterGraph, nullptr)) < 0) { DbgLog((LOG_TRACE, 10, L"::Filter()(init) Configuring the graph failed with code %d", ret)); avfilter_graph_free(&m_pFilterGraph); goto deliver; } DbgLog((LOG_TRACE, 10, L":Filter()(init) avfilter Initialization complete")); } if (!m_pFilterGraph) goto deliver; if (pFrame->direct) { HRESULT hr = DeDirectFrame(pFrame, true); if (FAILED(hr)) { ReleaseFrame(&pFrame); return hr; } } AVFrame *in_frame = nullptr; BOOL refcountedFrame = (m_Decoder.HasThreadSafeBuffers() == S_OK); // When flushing, we feed a NULL frame if (!bFlush) { in_frame = av_frame_alloc(); for (int i = 0; i < 4; i++) { in_frame->data[i] = pFrame->data[i]; in_frame->linesize[i] = (int)pFrame->stride[i]; } in_frame->width = pFrame->width; in_frame->height = pFrame->height; in_frame->format = ff_pixfmt; in_frame->pts = pFrame->rtStart; in_frame->interlaced_frame = pFrame->interlaced; in_frame->top_field_first = pFrame->tff; in_frame->sample_aspect_ratio = pFrame->aspect_ratio; if (refcountedFrame) { AVBufferRef *pFrameBuf = av_buffer_create(nullptr, 0, lav_free_lavframe, pFrame, 0); const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get((AVPixelFormat)in_frame->format); int planes = (in_frame->format == AV_PIX_FMT_NV12) ? 2 : desc->nb_components; for (int i = 0; i < planes; i++) { int h_shift = (i == 1 || i == 2) ? desc->log2_chroma_h : 0; int plane_size = (in_frame->height >> h_shift) * in_frame->linesize[i]; AVBufferRef *planeRef = av_buffer_ref(pFrameBuf); in_frame->buf[i] = av_buffer_create(in_frame->data[i], plane_size, lav_unref_frame, planeRef, AV_BUFFER_FLAG_READONLY); } av_buffer_unref(&pFrameBuf); } m_FilterPrevFrame = *pFrame; memset(m_FilterPrevFrame.data, 0, sizeof(m_FilterPrevFrame.data)); m_FilterPrevFrame.destruct = nullptr; } else {
static int init_filters(const char *filters_descr) { char args[512]; int ret; AVFilter *abuffersrc = avfilter_get_by_name("abuffer"); AVFilter *abuffersink = avfilter_get_by_name("abuffersink"); AVFilterInOut *outputs = avfilter_inout_alloc(); AVFilterInOut *inputs = avfilter_inout_alloc(); const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_S16, -1 }; AVABufferSinkParams *abuffersink_params; const AVFilterLink *outlink; AVRational time_base = fmt_ctx->streams[audio_stream_index]->time_base; filter_graph = avfilter_graph_alloc(); /* 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"); return ret; } /* buffer audio sink: to terminate the filter chain. */ abuffersink_params = av_abuffersink_params_alloc(); abuffersink_params->sample_fmts = sample_fmts; ret = avfilter_graph_create_filter(&buffersink_ctx, abuffersink, "out", NULL, abuffersink_params, filter_graph); av_free(abuffersink_params); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Cannot create audio 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(filter_graph, filters_descr, &inputs, &outputs, NULL)) < 0) return ret; if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0) return ret; /* 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); return 0; }
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; }
// Parse the user-provided filter graph, and populate the unlinked filter pads. static void precreate_graph(struct lavfi *c, bool first_init) { assert(!c->graph); c->failed = false; c->graph = avfilter_graph_alloc(); if (!c->graph) abort(); if (mp_set_avopts(c->log, c->graph, c->graph_opts) < 0) goto error; if (c->direct_filter) { AVFilterContext *filter = avfilter_graph_alloc_filter(c->graph, avfilter_get_by_name(c->graph_string), "filter"); if (!filter) { MP_FATAL(c, "filter '%s' not found or failed to allocate\n", c->graph_string); goto error; } if (mp_set_avopts_pos(c->log, filter, filter->priv, c->direct_filter_opts) < 0) goto error; if (avfilter_init_str(filter, NULL) < 0) { MP_FATAL(c, "filter failed to initialize\n"); goto error; } add_pads_direct(c, MP_PIN_IN, filter, filter->input_pads, filter->nb_inputs, first_init); add_pads_direct(c, MP_PIN_OUT, filter, filter->output_pads, filter->nb_outputs, first_init); } else { AVFilterInOut *in = NULL, *out = NULL; if (avfilter_graph_parse2(c->graph, c->graph_string, &in, &out) < 0) { MP_FATAL(c, "parsing the filter graph failed\n"); goto error; } add_pads(c, MP_PIN_IN, in, first_init); add_pads(c, MP_PIN_OUT, out, first_init); avfilter_inout_free(&in); avfilter_inout_free(&out); } for (int n = 0; n < c->num_all_pads; n++) c->failed |= !c->all_pads[n]->filter; if (c->failed) goto error; return; error: free_graph(c); c->failed = true; mp_filter_internal_mark_failed(c->f); return; }
int mix_config(mix_t *mix, const format_t *format) { const char *err; char args[512]; if (format_eq(format, &mix->format)) return 0; mix_shutdown(mix); mix->format = *format; // filter graph err = "failed to alloc filter graph"; mix->graph = avfilter_graph_alloc(); if (!mix->graph) goto err; // amix err = "no amix filter available"; const AVFilter *flt = avfilter_get_by_name("amix"); if (!flt) goto err; snprintf(args, sizeof(args), "inputs=%lu", (unsigned long) NUM_INPUTS); err = "failed to create amix filter context"; if (avfilter_graph_create_filter(&mix->amix_ctx, flt, NULL, args, NULL, mix->graph)) goto err; // inputs err = "no abuffer filter available"; flt = avfilter_get_by_name("abuffer"); if (!flt) goto err; for (int i = 0; i < NUM_INPUTS; i++) { dbg("init input ctx %i", i); snprintf(args, sizeof(args), "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:" "channel_layout=0x%" PRIx64, 1, mix->format.clockrate, mix->format.clockrate, av_get_sample_fmt_name(mix->format.format), av_get_default_channel_layout(mix->format.channels)); err = "failed to create abuffer filter context"; if (avfilter_graph_create_filter(&mix->src_ctxs[i], flt, NULL, args, NULL, mix->graph)) goto err; err = "failed to link abuffer to amix"; if (avfilter_link(mix->src_ctxs[i], 0, mix->amix_ctx, i)) goto err; } // sink err = "no abuffersink filter available"; flt = avfilter_get_by_name("abuffersink"); if (!flt) goto err; err = "failed to create abuffersink filter context"; if (avfilter_graph_create_filter(&mix->sink_ctx, flt, NULL, NULL, NULL, mix->graph)) goto err; err = "failed to link amix to abuffersink"; if (avfilter_link(mix->amix_ctx, 0, mix->sink_ctx, 0)) goto err; // finish up err = "failed to configure filter chain"; if (avfilter_graph_config(mix->graph, NULL)) goto err; return 0; err: mix_shutdown(mix); ilog(LOG_ERR, "Failed to initialize mixer: %s", err); return -1; }
static bool recreate_graph(struct af_instance *af, struct mp_audio *config) { void *tmp = talloc_new(NULL); struct priv *p = af->priv; AVFilterContext *in = NULL, *out = NULL, *f_format = NULL; if (bstr0(p->cfg_graph).len == 0) { MP_FATAL(af, "lavfi: no filter graph set\n"); return false; } destroy_graph(af); MP_VERBOSE(af, "lavfi: create graph: '%s'\n", p->cfg_graph); AVFilterGraph *graph = avfilter_graph_alloc(); if (!graph) goto error; if (mp_set_avopts(af->log, graph, p->cfg_avopts) < 0) goto error; AVFilterInOut *outputs = avfilter_inout_alloc(); AVFilterInOut *inputs = avfilter_inout_alloc(); if (!outputs || !inputs) goto error; // Build list of acceptable output sample formats. libavfilter will insert // conversion filters if needed. static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_U8P, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP, AV_SAMPLE_FMT_NONE }; char *fmtstr = talloc_strdup(tmp, ""); for (int n = 0; sample_fmts[n] != AV_SAMPLE_FMT_NONE; n++) { const char *name = av_get_sample_fmt_name(sample_fmts[n]); if (name) { const char *s = fmtstr[0] ? "|" : ""; fmtstr = talloc_asprintf_append_buffer(fmtstr, "%s%s", s, name); } } char *src_args = talloc_asprintf(tmp, "sample_rate=%d:sample_fmt=%s:time_base=%d/%d:" "channel_layout=0x%"PRIx64, config->rate, av_get_sample_fmt_name(af_to_avformat(config->format)), 1, config->rate, mp_chmap_to_lavc(&config->channels)); if (avfilter_graph_create_filter(&in, avfilter_get_by_name("abuffer"), "src", src_args, NULL, graph) < 0) goto error; if (avfilter_graph_create_filter(&out, avfilter_get_by_name("abuffersink"), "out", NULL, NULL, graph) < 0) goto error; if (avfilter_graph_create_filter(&f_format, avfilter_get_by_name("aformat"), "format", fmtstr, NULL, graph) < 0) goto error; if (avfilter_link(f_format, 0, out, 0) < 0) goto error; outputs->name = av_strdup("in"); outputs->filter_ctx = in; inputs->name = av_strdup("out"); inputs->filter_ctx = f_format; if (graph_parse(graph, p->cfg_graph, inputs, outputs, NULL) < 0) goto error; if (avfilter_graph_config(graph, NULL) < 0) goto error; p->in = in; p->out = out; p->graph = graph; assert(out->nb_inputs == 1); assert(in->nb_outputs == 1); talloc_free(tmp); return true; error: MP_FATAL(af, "Can't configure libavfilter graph.\n"); avfilter_graph_free(&graph); talloc_free(tmp); return false; }
static bool recreate_graph(struct af_instance *af, struct mp_audio *config) { void *tmp = talloc_new(NULL); struct priv *p = af->priv; AVFilterContext *in = NULL, *out = NULL; int r; if (bstr0(p->cfg_graph).len == 0) { mp_msg(MSGT_AFILTER, MSGL_FATAL, "lavfi: no filter graph set\n"); return false; } destroy_graph(af); mp_msg(MSGT_AFILTER, MSGL_V, "lavfi: create graph: '%s'\n", p->cfg_graph); AVFilterGraph *graph = avfilter_graph_alloc(); if (!graph) goto error; if (parse_avopts(graph, p->cfg_avopts) < 0) { mp_msg(MSGT_VFILTER, MSGL_FATAL, "lavfi: could not set opts: '%s'\n", p->cfg_avopts); goto error; } AVFilterInOut *outputs = avfilter_inout_alloc(); AVFilterInOut *inputs = avfilter_inout_alloc(); if (!outputs || !inputs) goto error; char *src_args = talloc_asprintf(tmp, "sample_rate=%d:sample_fmt=%s:channels=%d:time_base=%d/%d:" "channel_layout=0x%"PRIx64, config->rate, av_get_sample_fmt_name(af_to_avformat(config->format)), config->channels.num, 1, config->rate, mp_chmap_to_lavc(&config->channels)); if (avfilter_graph_create_filter(&in, avfilter_get_by_name("abuffer"), "src", src_args, NULL, graph) < 0) goto error; if (avfilter_graph_create_filter(&out, avfilter_get_by_name("abuffersink"), "out", NULL, NULL, graph) < 0) goto error; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_U8P, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP, AV_SAMPLE_FMT_NONE }; r = av_opt_set_int_list(out, "sample_fmts", sample_fmts, AV_SAMPLE_FMT_NONE, AV_OPT_SEARCH_CHILDREN); if (r < 0) goto error; r = av_opt_set_int(out, "all_channel_counts", 1, AV_OPT_SEARCH_CHILDREN); if (r < 0) goto error; outputs->name = av_strdup("in"); outputs->filter_ctx = in; inputs->name = av_strdup("out"); inputs->filter_ctx = out; if (graph_parse(graph, p->cfg_graph, inputs, outputs, NULL) < 0) goto error; if (avfilter_graph_config(graph, NULL) < 0) goto error; p->in = in; p->out = out; p->graph = graph; assert(out->nb_inputs == 1); assert(in->nb_outputs == 1); talloc_free(tmp); return true; error: mp_msg(MSGT_AFILTER, MSGL_FATAL, "Can't configure libavfilter graph.\n"); avfilter_graph_free(&graph); talloc_free(tmp); return false; }
static int apply_filters(AVFormatContext *ifmt_ctx) { char args[512]; int ret; AVFilterInOut *outputs = avfilter_inout_alloc(); if (!outputs) { printf("Cannot alloc output\n"); return -1; } AVFilterInOut *inputs = avfilter_inout_alloc(); if (!inputs) { printf("Cannot alloc input\n"); return -1; } if (filter_graph) avfilter_graph_free(&filter_graph); filter_graph = avfilter_graph_alloc(); if (!filter_graph) { printf("Cannot create filter graph\n"); return -1; } /* 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", ifmt_ctx->streams[0]->codec->width, ifmt_ctx->streams[0]->codec->height, ifmt_ctx->streams[0]->codec->pix_fmt, ifmt_ctx->streams[0]->time_base.num, ifmt_ctx->streams[0]->time_base.den, ifmt_ctx->streams[0]->codec->sample_aspect_ratio.num, ifmt_ctx->streams[0]->codec->sample_aspect_ratio.den); ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in", args, NULL, filter_graph); if (ret < 0) { printf("Cannot create buffer source\n"); return ret; } /* buffer video sink: to terminate the filter chain. */ ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out", NULL, NULL, filter_graph); if (ret < 0) { printf("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, filter_descr, &inputs, &outputs, NULL)) < 0) return ret; if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0) return ret; avfilter_inout_free(&inputs); avfilter_inout_free(&outputs); return 0; }
static int lavfi_open(struct vf_instance *vf, char *args) { AVFilterInOut *outputs; AVFilterInOut *inputs; int ret; avfilter_register_all(); if (!args) { mp_msg(MSGT_VFILTER, MSGL_ERR, "lavfi: filtergraph needed\n"); goto fail; } if (args[0] == '$') { char *e = getenv(args + 1); if (!e) { mp_msg(MSGT_VFILTER, MSGL_ERR, "lavfi: %s not defined\n", args); goto fail; } args = e; } vf->priv = av_mallocz(sizeof(struct vf_priv_s)); if (!vf->priv) return 0; vf->priv->graph = avfilter_graph_alloc(); if (!vf->priv->graph) goto fail; ret = avfilter_graph_create_filter(&vf->priv->in, &mpsrc, "in", NULL, vf, vf->priv->graph); if (ret < 0) goto fail; ret = avfilter_graph_create_filter(&vf->priv->out, &mpsink, "out", NULL, vf, vf->priv->graph); if (ret < 0) return 0; outputs = avfilter_inout_alloc(); inputs = avfilter_inout_alloc(); if (!outputs || !inputs) goto fail; outputs->name = av_strdup("in"); outputs->filter_ctx = vf->priv->in; outputs->pad_idx = 0; outputs->next = NULL; inputs->name = av_strdup("out"); inputs->filter_ctx = vf->priv->out; inputs->pad_idx = 0; inputs->next = NULL; ret = avfilter_graph_parse(vf->priv->graph, args, &inputs, &outputs, NULL); if (ret < 0) goto fail; vf->config = config; vf->uninit = uninit; vf->put_image = put_image; vf->get_image = get_image; return 1; fail: avfilter_inout_free(&inputs); avfilter_inout_free(&outputs); avfilter_graph_free(&vf->priv->graph); av_free(vf->priv); return 0; }
int VideoDecoder::video_thread(void *arg) { VideoState *is = (VideoState *) arg; AVStreamsParser* ps = is->getAVStreamsParser(); AVFrame *frame = av_frame_alloc(); double pts; double duration; int ret; AVRational tb = ps->video_st->time_base; AVRational frame_rate = av_guess_frame_rate(ps->ic, ps->video_st, NULL); #if CONFIG_AVFILTER AVFilterGraph *graph = avfilter_graph_alloc(); AVFilterContext *filt_out = NULL, *filt_in = NULL; int last_w = 0; int last_h = 0; enum AVPixelFormat last_format = (AVPixelFormat) (-2); int last_serial = -1; int last_vfilter_idx = 0; if (!graph) { av_frame_free(&frame); return AVERROR(ENOMEM); } #endif if (!frame) { #if CONFIG_AVFILTER avfilter_graph_free(&graph); #endif return AVERROR(ENOMEM); } for (;;) { ret = is->viddec().get_video_frame(is, frame); if (ret < 0) goto the_end; if (!ret) continue; #if CONFIG_AVFILTER if ( last_w != frame->width || last_h != frame->height || last_format != frame->format || last_serial != is->viddec().pkt_serial || last_vfilter_idx != is->vfilter_idx) { av_log(NULL, AV_LOG_DEBUG, "Video frame changed from size:%dx%d format:%s serial:%d to size:%dx%d format:%s serial:%d\n", last_w, last_h, (const char *)av_x_if_null(av_get_pix_fmt_name(last_format), "none"), last_serial, frame->width, frame->height, (const char *)av_x_if_null(av_get_pix_fmt_name((AVPixelFormat)frame->format), "none"), is->viddec().pkt_serial); avfilter_graph_free(&graph); graph = avfilter_graph_alloc(); if ((ret = configure_video_filters(graph, is,gOptions.vfilters_list ? gOptions.vfilters_list[is->vfilter_idx] : NULL, frame)) < 0) { SDL_Event event; event.type = FF_QUIT_EVENT; event.user.data1 = is; SDL_PushEvent(&event); goto the_end; } filt_in = is->in_video_filter; filt_out = is->out_video_filter; last_w = frame->width; last_h = frame->height; last_format = (AVPixelFormat) frame->format; last_serial = is->viddec().pkt_serial; last_vfilter_idx = is->vfilter_idx; frame_rate = filt_out->inputs[0]->frame_rate; } ret = av_buffersrc_add_frame(filt_in, frame); if (ret < 0) goto the_end; while (ret >= 0) { is->frame_last_returned_time = av_gettime_relative() / 1000000.0; ret = av_buffersink_get_frame_flags(filt_out, frame, 0); if (ret < 0) { if (ret == AVERROR_EOF) is->viddec().finished = is->viddec().pkt_serial; ret = 0; break; } is->frame_last_filter_delay = av_gettime_relative() / 1000000.0 - is->frame_last_returned_time; if (fabs(is->frame_last_filter_delay) > AV_NOSYNC_THRESHOLD / 10.0) is->frame_last_filter_delay = 0; tb = filt_out->inputs[0]->time_base; #endif duration = (frame_rate.num && frame_rate.den ? av_q2d((AVRational){frame_rate.den, frame_rate.num}) : 0); pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb); ret = queue_picture(is, frame, pts, duration, av_frame_get_pkt_pos(frame), is->viddec().pkt_serial); av_frame_unref(frame); #if CONFIG_AVFILTER } #endif if (ret < 0) goto the_end; } the_end: #if CONFIG_AVFILTER avfilter_graph_free(&graph); #endif av_frame_free(&frame); return 0; }
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_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; }
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; }
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; }
int main(int argc, char **argv) { const AVFilter *filter; AVFilterContext *filter_ctx; AVFilterGraph *graph_ctx; const char *filter_name; const char *filter_args = NULL; int i; int ret = 0; av_log_set_level(AV_LOG_DEBUG); if (argc < 2) { fprintf(stderr, "Missing filter name as argument\n"); return 1; } filter_name = argv[1]; if (argc > 2) filter_args = argv[2]; /* allocate graph */ graph_ctx = avfilter_graph_alloc(); if (!graph_ctx) return 1; avfilter_register_all(); /* get a corresponding filter and open it */ if (!(filter = avfilter_get_by_name(filter_name))) { fprintf(stderr, "Unrecognized filter with name '%s'\n", filter_name); return 1; } /* open filter and add it to the graph */ if (!(filter_ctx = avfilter_graph_alloc_filter(graph_ctx, filter, filter_name))) { fprintf(stderr, "Impossible to open filter with name '%s'\n", filter_name); return 1; } if (avfilter_init_str(filter_ctx, filter_args) < 0) { fprintf(stderr, "Impossible to init filter '%s' with arguments '%s'\n", filter_name, filter_args); return 1; } /* create a link for each of the input pads */ for (i = 0; i < filter_ctx->nb_inputs; i++) { AVFilterLink *link = av_mallocz(sizeof(AVFilterLink)); if (!link) { fprintf(stderr, "Unable to allocate memory for filter input link\n"); ret = 1; goto fail; } link->type = avfilter_pad_get_type(filter_ctx->input_pads, i); filter_ctx->inputs[i] = link; } for (i = 0; i < filter_ctx->nb_outputs; i++) { AVFilterLink *link = av_mallocz(sizeof(AVFilterLink)); if (!link) { fprintf(stderr, "Unable to allocate memory for filter output link\n"); ret = 1; goto fail; } link->type = avfilter_pad_get_type(filter_ctx->output_pads, i); filter_ctx->outputs[i] = link; } if (filter->query_formats) filter->query_formats(filter_ctx); else ff_default_query_formats(filter_ctx); print_formats(filter_ctx); fail: avfilter_free(filter_ctx); avfilter_graph_free(&graph_ctx); fflush(stdout); return ret; }
/* 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; }
vod_status_t audio_filter_alloc_state( request_context_t* request_context, media_sequence_t* sequence, media_clip_t* clip, media_track_t* output_track, size_t* cache_buffer_count, void** result) { audio_filter_init_context_t init_context; u_char filter_name[VOD_INT32_LEN + 1]; audio_filter_state_t* state; vod_pool_cleanup_t *cln; AVFilterInOut *outputs = NULL; AVFilterInOut *inputs = NULL; uint32_t initial_alloc_size; vod_status_t rc; int avrc; if (!initialized) { vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0, "audio_filter_alloc_state: module failed to initialize successfully"); return VOD_UNEXPECTED; } // get the source count and graph desc size init_context.request_context = request_context; init_context.graph_desc_size = 0; init_context.source_count = 0; init_context.output_frame_count = 0; rc = audio_filter_walk_filters_prepare_init(&init_context, &clip, 100, 100); if (rc != VOD_OK) { return rc; } if (clip == NULL || init_context.source_count <= 0) { vod_log_error(VOD_LOG_ERR, request_context->log, 0, "audio_filter_alloc_state: unexpected - no sources found"); return VOD_UNEXPECTED; } if (clip->type == MEDIA_CLIP_SOURCE) { // got left with a source, following a mix of a single source, nothing to do return VOD_OK; } if (init_context.output_frame_count > MAX_FRAME_COUNT) { vod_log_error(VOD_LOG_ERR, request_context->log, 0, "audio_filter_alloc_state: expected output frame count %uD too big", init_context.output_frame_count); return VOD_BAD_REQUEST; } // allocate the state state = vod_alloc(request_context->pool, sizeof(*state)); if (state == NULL) { vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0, "audio_filter_alloc_state: vod_alloc failed"); return VOD_ALLOC_FAILED; } vod_memzero(state, sizeof(*state)); // add to the cleanup pool cln = vod_pool_cleanup_add(request_context->pool, 0); if (cln == NULL) { vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0, "audio_filter_alloc_state: vod_pool_cleanup_add failed"); return VOD_ALLOC_FAILED; } cln->handler = audio_filter_free_state; cln->data = state; // allocate the filter graph state->filter_graph = avfilter_graph_alloc(); if (state->filter_graph == NULL) { vod_log_error(VOD_LOG_ERR, state->request_context->log, 0, "audio_filter_alloc_state: avfilter_graph_alloc failed"); return VOD_ALLOC_FAILED; } // allocate the graph desc and sources init_context.graph_desc = vod_alloc(request_context->pool, init_context.graph_desc_size + sizeof(state->sources[0]) * init_context.source_count); if (init_context.graph_desc == NULL) { vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0, "audio_filter_alloc_state: vod_alloc failed (1)"); return VOD_ALLOC_FAILED; } state->sources = (void*)(init_context.graph_desc + init_context.graph_desc_size); state->sources_end = state->sources + init_context.source_count; vod_memzero(state->sources, (u_char*)state->sources_end - (u_char*)state->sources); // initialize the sources and the graph description init_context.filter_graph = state->filter_graph; init_context.outputs = &outputs; init_context.cur_source = state->sources; init_context.graph_desc_pos = init_context.graph_desc; init_context.max_frame_size = 0; init_context.cache_slot_id = 0; rc = audio_filter_init_sources_and_graph_desc(&init_context, clip); if (rc != VOD_OK) { goto end; } *init_context.graph_desc_pos = '\0'; // initialize the sink vod_sprintf(filter_name, "%uD%Z", clip->id); rc = audio_filter_init_sink( request_context, state->filter_graph, output_track, filter_name, &state->sink, &inputs); if (rc != VOD_OK) { goto end; } // parse the graph description avrc = avfilter_graph_parse_ptr(state->filter_graph, (char*)init_context.graph_desc, &inputs, &outputs, NULL); if (avrc < 0) { vod_log_error(VOD_LOG_ERR, request_context->log, 0, "audio_filter_alloc_state: avfilter_graph_parse_ptr failed %d", avrc); rc = VOD_UNEXPECTED; goto end; } // validate and configure the graph avrc = avfilter_graph_config(state->filter_graph, NULL); if (avrc < 0) { vod_log_error(VOD_LOG_ERR, request_context->log, 0, "audio_filter_alloc_state: avfilter_graph_config failed %d", avrc); rc = VOD_UNEXPECTED; goto end; } // set the buffer sink frame size if ((state->sink.encoder->codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE) == 0) { av_buffersink_set_frame_size(state->sink.buffer_sink, state->sink.encoder->frame_size); } // allocate frames state->decoded_frame = av_frame_alloc(); if (state->decoded_frame == NULL) { vod_log_error(VOD_LOG_ERR, request_context->log, 0, "audio_filter_alloc_state: av_frame_alloc failed (1)"); return VOD_ALLOC_FAILED; } state->filtered_frame = av_frame_alloc(); if (state->filtered_frame == NULL) { vod_log_error(VOD_LOG_ERR, request_context->log, 0, "audio_filter_alloc_state: av_frame_alloc failed (2)"); return VOD_ALLOC_FAILED; } // allocate the frame buffer state->frame_buffer = vod_alloc(request_context->pool, init_context.max_frame_size); if (state->frame_buffer == NULL) { vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0, "audio_filter_alloc_state: vod_alloc failed (2)"); rc = VOD_ALLOC_FAILED; goto end; } // initialize the output arrays initial_alloc_size = init_context.output_frame_count + 10; if (vod_array_init(&state->frames_array, request_context->pool, initial_alloc_size, sizeof(input_frame_t)) != VOD_OK) { vod_log_debug0(VOD_LOG_DEBUG_LEVEL, request_context->log, 0, "audio_filter_alloc_state: vod_array_init failed (1)"); return VOD_ALLOC_FAILED; } state->request_context = request_context; state->sequence = sequence; state->output = output_track; state->cur_frame_pos = 0; state->first_time = TRUE; state->cur_source = NULL; *cache_buffer_count = init_context.cache_slot_id; *result = state; end: avfilter_inout_free(&inputs); avfilter_inout_free(&outputs); return rc; }