如何确定编解码器/容器组合是否与 FFmpeg 兼容?

How can I determine if a codec / container combination is compatible with FFmpeg?

我正在考虑重新混合一些保存音频和视频的容器,以便我提取最好的第一个音频流,并将其存储在一个新的容器中,例如只有 音频流存在。

FFmpeg 的输出上下文是这样创建的:

AVFormatContext* output_context = NULL;
avformat_alloc_output_context2( &output_context, NULL, "mp4", NULL );

我有一份可接受输出的候选清单,例如MP4、M4A 等……基本上是 Apple 音频文件服务可读的那些:

kAudioFileAIFFType              = 'AIFF',
kAudioFileAIFCType              = 'AIFC',
kAudioFileWAVEType              = 'WAVE',
kAudioFileSoundDesigner2Type    = 'Sd2f',
kAudioFileNextType              = 'NeXT',
kAudioFileMP3Type               = 'MPG3',   // mpeg layer 3
kAudioFileMP2Type               = 'MPG2',   // mpeg layer 2
kAudioFileMP1Type               = 'MPG1',   // mpeg layer 1
kAudioFileAC3Type               = 'ac-3',
kAudioFileAAC_ADTSType          = 'adts',
kAudioFileMPEG4Type             = 'mp4f',
kAudioFileM4AType               = 'm4af',
kAudioFileM4BType               = 'm4bf',
kAudioFileCAFType               = 'caff',
kAudioFile3GPType               = '3gpp',
kAudioFile3GP2Type              = '3gp2',
kAudioFileAMRType               = 'amrf'

我的问题是:在 FFmpeg 中是否有一个简单的 API 可以用来在给定音频流所在的编解码器的情况下选择兼容的输出容器?

对于每个单独的 muxer,通常有一个编解码器标签编写 function.That 函数将检查另一个源文件中的列表或通过相同的 switch 语句工作。没有中央名册或容器匹配实用程序功能。最好的办法是在 libavcodec/allcodecs.c 中识别编解码器 ID,然后在 libavformat/ 中为该 ID 进行 grep,特别是在以 enc 为后缀的文件中,例如matroskaenc.c.

这个问题有一个动态的方法。这枚举了每个容器的编解码器,但您也会得到相反的结果:

// enumerate all codecs and put into list
std::vector<AVCodec*> encoderList;
AVCodec * codec = nullptr;
while (codec = av_codec_next(codec))
{
    // try to get an encoder from the system
    auto encoder = avcodec_find_encoder(codec->id);
    if (encoder)
    {
        encoderList.push_back(encoder);
    }
}
// enumerate all containers
AVOutputFormat * outputFormat = nullptr;
while (outputFormat = av_oformat_next(outputFormat))
{
    for (auto codec : encoderList)
    {
        // only add the codec if it can be used with this container
        if (avformat_query_codec(outputFormat, codec->id, FF_COMPLIANCE_STRICT) == 1)
        {
            // add codec for container
        }
    }
}

如果您只需要特定的容器或编解码器,您可以将白名单与它们的 nameid 字段一起使用,并在枚举时使用它。