阅读MovieDecoder::initializeFilterGraph的代码,发现ffmpeg的filter用起来是和Gstreamer的plugin是一样的概念,通过avfilter_link,将各个创建好的filter按自己想要的次序链接到一起,然后avfilter_graph_config之后,就可以使用了。
下面是initializeFilterGraph的代码:
void MovieDecoder::initializeFilterGraph(const AVRational& timeBase, const std::string& size, bool maintainAspectRatio)
{
static const AVPixelFormat pixelFormats[] = { AV_PIX_FMT_RGB24, AV_PIX_FMT_NONE };
auto del = [] (AVBufferSinkParams* p) { av_freep(p); };
std::unique_ptr buffersinkParams(av_buffersink_params_alloc(), del);
avfilter_register_all();
m_pFilterGraph = avfilter_graph_alloc();
assert(m_pFilterGraph);
std::stringstream ss;
ss << "video_size=" << m_pVideoCodecContext->width << "x" << m_pVideoCodecContext->height
<< ":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=rgb24", nullptr, m_pFilterGraph),
"Failed to create format filter");
AVFilterContext* rotateFilter = nullptr;
auto rotation = getStreamRotation();
if (rotation == 3)
{
checkRc(avfilter_graph_create_filter(&rotateFilter, avfilter_get_by_name("rotate"), "thumb_rotate", "PI", nullptr, m_pFilterGraph),
"Failed to create rotate filter");
}
else if (rotation != -1)
{
checkRc(avfilter_graph_create_filter(&rotateFilter, avfilter_get_by_name("transpose"), "thumb_transpose", std::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");
}
这里面的filter有:
filtersource
filtersink
scaleFilter
yadifFilter
formatFilter
rotateFilter
link的次序为:
m_pFilterSource->yadifFilter->scaleFilter->formatFilter->rotateFilter->iltersink
如果yadifFilter,rotateFilter创建失败,实际上就只有scaleFilter和formatFilter
m_pFilterSource->scaleFilter->formatFilter->iltersink
所以,如果只要yuv到rgb转换,可以去掉其他的filter,还是保留了de-interlace的yadif filter实现如下:
void MovieDecoder::initializeFilterGraph(const AVRational& timeBase, const std::string& size, bool maintainAspectRatio)
{
static const AVPixelFormat pixelFormats[] = { AV_PIX_FMT_RGB24, AV_PIX_FMT_NONE };
auto del = [] (AVBufferSinkParams* p) { av_freep(p); };
std::unique_ptr buffersinkParams(av_buffersink_params_alloc(), del);
avfilter_register_all();
m_pFilterGraph = avfilter_graph_alloc();
assert(m_pFilterGraph);
std::stringstream ss;
ss << "video_size=" << m_pVideoCodecContext->width << "x" << m_pVideoCodecContext->height
<< ":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* formatFilter = nullptr;
checkRc(avfilter_graph_create_filter(&formatFilter, avfilter_get_by_name("format"), "thumb_format", "pix_fmts=rgb24", nullptr, m_pFilterGraph),
"Failed to create format filter");
checkRc(avfilter_link(formatFilter, 0, m_pFilterSink, 0), "Failed to link fomart filtersink");
if (yadifFilter)
{
checkRc(avfilter_link(yadifFilter, 0, formatFilter, 0), "Failed to link yadif & format filter");
checkRc(avfilter_link(m_pFilterSource, 0, yadifFilter, 0), "Failed to link filtersrc yadif filter");
}
else
{
checkRc(avfilter_link(m_pFilterSource, 0, formatFilter, 0), "Failed to link filtersrc format filter");
}
checkRc(avfilter_graph_config(m_pFilterGraph, nullptr), "Failed to configure filter graph");
}