Я пытаюсь закодировать сырой H264 в контейнер mp4, используя FFMPEG API в C ++. Все работает нормально, однако поле AVCC пустое и возвращает ошибку:
[iso file] Поле «avcC», размер 8 недействителен
Если я тогда использую инструмент командной строки в выходном файле:
ffmpeg -i output.mp4 -vcodec copy fixed.mp4
Выходной файл работает, и AVCC заполняется необходимой информацией. Я в недоумении, почему этот аргумент командной строки работает, но я не могу получить тот же результат, используя API.
Что я делаю в коде C ++ (также делаю вещи между вызовами функций):
outputFormat_ = av_guess_format( "mp4", NULL, NULL ); //AV_CODEC_H264
formatContext_ = avformat_alloc_context();
formatContext_->oformat = outputFormat_;
...
AVDictionary *opts = NULL;
char tmpstr[50]; sprintf(tmpstr, "%i", muxRate * KILOBYTESTOBYTES);
av_dict_set(&opts, "muxrate", tmpstr, 0);
avformat_write_header( formatContext_, &opts);
av_write_trailer(formatContext_);
Вывод это правильно, за исключением того, что отсутствует информация AVCC. Добавление этого вручную (и, соответственно, исправление длины ящиков) позволяет мне нормально воспроизводить видео. Есть идеи, почему вызовы API не генерируют информацию AVCC?
Для справки вот символы из mp4 до исправления:
.avc1 ……………………. € .8.H … H ………….. ………………………. YY …. AVCC …. СТТС
и после:
AVC1 ……………………. € .8.H … H …………… ……………………… YY …! avcC.B € (ÿá..gB € (Ú.à.- •. ..Привет<€ …. СТТС
У меня была проблема с пустыми полями AVCC с моими файлами MP4. Оказалось, я настраивался CODEC_FLAG_GLOBAL_HEADER
флаг на AVCodecContext
пример после призвание avcodec_open2
, Флаг должен быть установлен до призвание avcodec_open2
,
Решил это. Данные, которые требовались, были компонентами SPS и PPS кодека AVCC. Поскольку необработанный поток H264 был в формате приложения b, он присутствовал в начале каждого I-кадра, в блоках NAL, начиная с 0x00 0x00 0x00 0x01 0x67 и 0x00 0x00 0x00 0x01 0x68. Поэтому нужно было скопировать эту информацию в поле экстраданных кодека AVStream:
codecContext = stream->codec;
...
// videoSeqHeader contains the PPS and SPS NAL unit data
codecContext->extradata = (uint8_t*)malloc( sizeof(uint8_t) * videoSeqHeader_.size() );
for( unsigned int index = 0; index < videoSeqHeader_.size(); index++ )
{
codecContext->extradata[index] = videoSeqHeader_[index];
}
codecContext->extradata_size = (int)videoSeqHeader_.size();
Это привело к правильному заполнению поля AVCC.