Как я могу определить, совместима ли комбинация кодек / контейнер с FFmpeg?

Я смотрю на повторное мультиплексирование некоторых контейнеров, содержащих аудио и видео, так что я извлекаю лучший, первый аудио поток и сохраняю его в новом контейнере, где, например, присутствует только аудио поток.

Выходной контекст для FFmpeg создается так:

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

У меня есть список допустимых выходных данных, например, MP4, M4A и т. Д., В основном те, которые читаются сервисами Apple Audio File Services:

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, который можно использовать для выбора совместимого выходного контейнера с учетом кодека, в котором находится аудиопоток?

3 ответа

Решение

Для каждого отдельного мультиплексора обычно есть функция записи тега кодека. Эта функция будет проверять список в другом исходном файле или работать через switch утверждение в том же. Там нет центрального реестра или функции соответствия контейнера. Лучше всего идентифицировать кодек в libavcodec/allcodecs.c а затем grep в libavformat/ для этого идентификатора, особенно в файлах с суффиксом 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
        }
    }
}

Если вам нужны конкретные контейнеры или кодеки, вы можете использовать белый список с их name или же id поля и использовать это при перечислении.

API ffmpeg с тех пор изменился, теперь можно выполнить перечисление всех контейнеров и кодеков, например

      void enumerate() {
    // enumerate all codecs and put into list
    std::vector<const AVCodec*> encoderList;

    void* codecState = nullptr; //start with null
    const AVCodec* codec = av_codec_iterate(&codecState);
    while (codec) {
        encoderList.push_back(codec);
        codec = av_codec_iterate(&codecState);
    }

    // enumerate all containers available for muxing
    void* muxerState = nullptr;
    const AVOutputFormat* ofmt = av_muxer_iterate(&muxerState);
    while (ofmt) {
        std::set<std::string> codecNames;
        for (auto codec : encoderList) {
            // check if codec can be used in this container
            if (avformat_query_codec(ofmt, codec->id, FF_COMPLIANCE_NORMAL) == 1) {
                // check for audio codecs here
                if (avcodec_get_type(codec->id) == AVMEDIA_TYPE_AUDIO) {
                    codecNames.insert(avcodec_get_name(codec->id));
                }
            }
        }
        // print unique format and codec names
        for (auto& codecName : codecNames) {
            std::printf("format '%s' codec '%s'\n", ofmt->name, codecName.c_str());
        }
        // get next format
        ofmt = av_muxer_iterate(&muxerState);
    }
}
Другие вопросы по тегам