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; }
JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_codec_FFmpeg_avfilter_1graph_1config (JNIEnv *env, jclass clazz, jlong graph, jlong log_ctx) { return (jint) avfilter_graph_config( (AVFilterGraph *) (intptr_t) graph, (AVClass *) (intptr_t) log_ctx); }
void configure_filtergraph( AVFilterGraph& graph, const std::string& filtergraph, AVFilterContext& source_ctx, AVFilterContext& sink_ctx) { AVFilterInOut* outputs = nullptr; AVFilterInOut* inputs = nullptr; try { if(!filtergraph.empty()) { outputs = avfilter_inout_alloc(); inputs = avfilter_inout_alloc(); CASPAR_VERIFY(outputs && inputs); outputs->name = av_strdup("in"); outputs->filter_ctx = &source_ctx; outputs->pad_idx = 0; outputs->next = nullptr; inputs->name = av_strdup("out"); inputs->filter_ctx = &sink_ctx; inputs->pad_idx = 0; inputs->next = nullptr; FF(avfilter_graph_parse( &graph, filtergraph.c_str(), inputs, outputs, nullptr)); } else { FF(avfilter_link( &source_ctx, 0, &sink_ctx, 0)); } FF(avfilter_graph_config( &graph, nullptr)); } catch(...) { avfilter_inout_free(&outputs); avfilter_inout_free(&inputs); throw; } }
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; }
void FilterGraph::config(error_code &ec) { clear_if(ec); if (!m_raw) { throws_if(ec, Errors::Unallocated); return; } int sts = avfilter_graph_config(m_raw, nullptr); if (sts < 0) { throws_if(ec, sts, ffmpeg_category()); return; } m_configured = true; }
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; }
void FilterGraph::init(const std::vector<IFrame*>& inputs, IFrame& output) { // push filters to the graph addInBuffer(inputs); addOutBuffer(output); for(size_t i = 0; i < _filters.size(); ++i) { pushFilter(*_filters.at(i)); } // connect filters for(size_t index = 0; index < _filters.size() - 1; ++index) { size_t indexOfOutputFilterToConnect = index + 1; size_t indexOfInputPadOfDestinationFilter = 0; // handle cases with several inputs if(index < inputs.size()) { indexOfOutputFilterToConnect = inputs.size(); indexOfInputPadOfDestinationFilter = index; } LOG_INFO("Connect filter " << _filters.at(index)->getName() << " to filter " << _filters.at(indexOfOutputFilterToConnect)->getName()) const int err = avfilter_link(_filters.at(index)->getAVFilterContext(), 0, _filters.at(indexOfOutputFilterToConnect)->getAVFilterContext(), indexOfInputPadOfDestinationFilter); if(err < 0) { throw std::runtime_error("Error when connecting filters."); } } // configuring the graph LOG_INFO("Configuring filter graph.") const int err = avfilter_graph_config(_graph, NULL); if(err < 0) { throw std::runtime_error("Error configuring the filter graph: " + getDescriptionFromErrorCode(err)); } _isInit = true; }
// Initialize the graph if all inputs have formats set. If it's already // initialized, or can't be initialized yet, do nothing. static void init_graph(struct lavfi *c) { assert(!c->initialized); if (!c->graph) precreate_graph(c, false); if (init_pads(c)) { struct mp_stream_info *info = mp_filter_find_stream_info(c->f); if (info && info->hwdec_devs) { struct mp_hwdec_ctx *hwdec = hwdec_devices_get_first(info->hwdec_devs); for (int n = 0; n < c->graph->nb_filters; n++) { AVFilterContext *filter = c->graph->filters[n]; if (hwdec && hwdec->av_device_ref) filter->hw_device_ctx = av_buffer_ref(hwdec->av_device_ref); } } // And here the actual libavfilter initialization happens. if (avfilter_graph_config(c->graph, NULL) < 0) { MP_FATAL(c, "failed to configure the filter graph\n"); free_graph(c); c->failed = true; mp_filter_internal_mark_failed(c->f); return; } // The timebase is available after configuring. for (int n = 0; n < c->num_out_pads; n++) { struct lavfi_pad *pad = c->out_pads[n]; pad->timebase = pad->buffer->inputs[0]->time_base; } c->initialized = true; if (!c->direct_filter) // (output uninteresting for direct filters) dump_graph(c); } }
static int config(struct vf_instance *vf, int w, int h, int dw, int dh, unsigned flags, unsigned fmt) { int ret; AVFilterLink *out; AVRational iar, dar; av_reduce(&iar.num, &iar.den, w, h, INT_MAX); av_reduce(&dar.num, &dar.den, dw, dh, INT_MAX); vf->priv->in_pixfmt = imgfmt2pixfmt(fmt); vf->priv->in_imgfmt = fmt; vf->priv->in_w = w; vf->priv->in_h = h; vf->priv->in_sar = av_div_q(dar, iar); ret = avfilter_graph_config(vf->priv->graph, NULL); if (ret < 0) return 0; out = vf->priv->out->inputs[0]; vf->priv->out_w = out->w; vf->priv->out_h = out->h; vf->priv->out_pixfmt = out->format; vf->priv->out_imgfmt = pixfmt2imgfmt(out->format); vf->priv->out_sar = out->sample_aspect_ratio; if (vf->priv->out_sar.num != vf->priv->in_sar.num || vf->priv->out_sar.den != vf->priv->in_sar.den || out->w != w || out->h != h) { av_reduce(&iar.num, &iar.den, out->w, out->h, INT_MAX); dar = av_mul_q(iar, out->sample_aspect_ratio); if (av_cmp_q(dar, iar) >= 0) { dh = out->h; dw = av_rescale(dh, dar.num, dar.den); } else { dw = out->w; dh = av_rescale(dw, dar.den, dar.num); } } return vf_next_config(vf, out->w, out->h, dw, dh, flags, fmt); }
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; 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; }
int main(int argc, char **argv) { const char *outfilename = NULL; const char *infilename = NULL; FILE *outfile = NULL; FILE *infile = NULL; char *graph_string = NULL; AVFilterGraph *graph = av_mallocz(sizeof(AVFilterGraph)); char c; av_log_set_level(AV_LOG_DEBUG); while ((c = getopt(argc, argv, "hi:o:")) != -1) { switch (c) { case 'h': usage(); return 0; case 'i': infilename = optarg; break; case 'o': outfilename = optarg; break; case '?': return 1; } } if (!infilename || !strcmp(infilename, "-")) infilename = "/dev/stdin"; infile = fopen(infilename, "r"); if (!infile) { fprintf(stderr, "Impossible to open input file '%s': %s\n", infilename, strerror(errno)); return 1; } if (!outfilename || !strcmp(outfilename, "-")) outfilename = "/dev/stdout"; outfile = fopen(outfilename, "w"); if (!outfile) { fprintf(stderr, "Impossible to open output file '%s': %s\n", outfilename, strerror(errno)); return 1; } /* read from infile and put it in a buffer */ { unsigned int count = 0; struct line *line, *last_line, *first_line; char *p; last_line = first_line = av_malloc(sizeof(struct line)); while (fgets(last_line->data, sizeof(last_line->data), infile)) { struct line *new_line = av_malloc(sizeof(struct line)); count += strlen(last_line->data); last_line->next = new_line; last_line = new_line; } last_line->next = NULL; graph_string = av_malloc(count + 1); p = graph_string; for (line = first_line; line->next; line = line->next) { unsigned int l = strlen(line->data); memcpy(p, line->data, l); p += l; } *p = '\0'; } avfilter_register_all(); if (avfilter_graph_parse(graph, graph_string, NULL, NULL, NULL) < 0) { fprintf(stderr, "Impossible to parse the graph description\n"); return 1; } if (avfilter_graph_config(graph, NULL) < 0) return 1; print_digraph(outfile, graph); fflush(outfile); return 0; }
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; }
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 init_filter_graph(AVFilterGraph **graph, AVFilterContext **src, AVFilterContext **sink) { AVFilterGraph *filter_graph; AVFilterContext *abuffer_ctx; AVFilter *abuffer; AVFilterContext *volume_ctx; AVFilter *volume; AVFilterContext *aformat_ctx; AVFilter *aformat; AVFilterContext *abuffersink_ctx; AVFilter *abuffersink; AVDictionary *options_dict = NULL; uint8_t options_str[1024]; uint8_t ch_layout[64]; int err; /* Create a new filtergraph, which will contain all the filters. */ filter_graph = avfilter_graph_alloc(); if (!filter_graph) { fprintf(stderr, "Unable to create filter graph.\n"); return AVERROR(ENOMEM); } /* Create the abuffer filter; * it will be used for feeding the data into the graph. */ abuffer = avfilter_get_by_name("abuffer"); if (!abuffer) { fprintf(stderr, "Could not find the abuffer filter.\n"); return AVERROR_FILTER_NOT_FOUND; } abuffer_ctx = avfilter_graph_alloc_filter(filter_graph, abuffer, "src"); if (!abuffer_ctx) { fprintf(stderr, "Could not allocate the abuffer instance.\n"); return AVERROR(ENOMEM); } /* Set the filter options through the AVOptions API. */ av_get_channel_layout_string(ch_layout, sizeof(ch_layout), 0, INPUT_CHANNEL_LAYOUT); av_opt_set (abuffer_ctx, "channel_layout", ch_layout, AV_OPT_SEARCH_CHILDREN); av_opt_set (abuffer_ctx, "sample_fmt", av_get_sample_fmt_name(INPUT_FORMAT), AV_OPT_SEARCH_CHILDREN); av_opt_set_q (abuffer_ctx, "time_base", (AVRational){ 1, INPUT_SAMPLERATE }, AV_OPT_SEARCH_CHILDREN); av_opt_set_int(abuffer_ctx, "sample_rate", INPUT_SAMPLERATE, AV_OPT_SEARCH_CHILDREN); /* Now initialize the filter; we pass NULL options, since we have already * set all the options above. */ err = avfilter_init_str(abuffer_ctx, NULL); if (err < 0) { fprintf(stderr, "Could not initialize the abuffer filter.\n"); return err; } /* Create volume filter. */ volume = avfilter_get_by_name("volume"); if (!volume) { fprintf(stderr, "Could not find the volume filter.\n"); return AVERROR_FILTER_NOT_FOUND; } volume_ctx = avfilter_graph_alloc_filter(filter_graph, volume, "volume"); if (!volume_ctx) { fprintf(stderr, "Could not allocate the volume instance.\n"); return AVERROR(ENOMEM); } /* A different way of passing the options is as key/value pairs in a * dictionary. */ av_dict_set(&options_dict, "volume", AV_STRINGIFY(VOLUME_VAL), 0); err = avfilter_init_dict(volume_ctx, &options_dict); av_dict_free(&options_dict); if (err < 0) { fprintf(stderr, "Could not initialize the volume filter.\n"); return err; } /* Create the aformat filter; * it ensures that the output is of the format we want. */ aformat = avfilter_get_by_name("aformat"); if (!aformat) { fprintf(stderr, "Could not find the aformat filter.\n"); return AVERROR_FILTER_NOT_FOUND; } aformat_ctx = avfilter_graph_alloc_filter(filter_graph, aformat, "aformat"); if (!aformat_ctx) { fprintf(stderr, "Could not allocate the aformat instance.\n"); return AVERROR(ENOMEM); } /* A third way of passing the options is in a string of the form * key1=value1:key2=value2.... */ snprintf(options_str, sizeof(options_str), "sample_fmts=%s:sample_rates=%d:channel_layouts=0x%"PRIx64, av_get_sample_fmt_name(AV_SAMPLE_FMT_S16), 44100, (uint64_t)AV_CH_LAYOUT_STEREO); err = avfilter_init_str(aformat_ctx, options_str); if (err < 0) { av_log(NULL, AV_LOG_ERROR, "Could not initialize the aformat filter.\n"); return err; } /* Finally create the abuffersink filter; * it will be used to get the filtered data out of the graph. */ abuffersink = avfilter_get_by_name("abuffersink"); if (!abuffersink) { fprintf(stderr, "Could not find the abuffersink filter.\n"); return AVERROR_FILTER_NOT_FOUND; } abuffersink_ctx = avfilter_graph_alloc_filter(filter_graph, abuffersink, "sink"); if (!abuffersink_ctx) { fprintf(stderr, "Could not allocate the abuffersink instance.\n"); return AVERROR(ENOMEM); } /* This filter takes no options. */ err = avfilter_init_str(abuffersink_ctx, NULL); if (err < 0) { fprintf(stderr, "Could not initialize the abuffersink instance.\n"); return err; } /* Connect the filters; * in this simple case the filters just form a linear chain. */ err = avfilter_link(abuffer_ctx, 0, volume_ctx, 0); if (err >= 0) err = avfilter_link(volume_ctx, 0, aformat_ctx, 0); if (err >= 0) err = avfilter_link(aformat_ctx, 0, abuffersink_ctx, 0); if (err < 0) { fprintf(stderr, "Error connecting filters\n"); return err; } /* Configure the graph. */ err = avfilter_graph_config(filter_graph, NULL); if (err < 0) { av_log(NULL, AV_LOG_ERROR, "Error configuring the filter graph\n"); return err; } *graph = filter_graph; *src = abuffer_ctx; *sink = abuffersink_ctx; 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"); }
/* 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; }
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 {
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; 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 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; }
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; }
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; }
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; }
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; }