Смешивание AVPackets в mp4 файл

Я занимаюсь разработкой инструмента, который получает прямой поток h.264 из сети (отправитель является аппаратным кодировщиком), буферизует последние x-минуты и создает видеофайл последних x-минут, если он запущен.

Мой инструмент может получать прямой эфир, а также буферизовать AVPackets с помощью boost :: serialization. Кроме того, я могу загрузить буферизованные AVPackets.

Но когда я пытаюсь создать / mux видеофайл (mp4) с загруженными AVPackets, возникает ошибка в mp4-файле или mp4-заголовке.
Я могу создать mp4-файл, а также записать пакеты в файл с помощью av_interleaved_write_frame (). Файл mp4 также имеет вероятный размер. Так что кажется, что AVPackets были записаны в файл.

Но когда я пытаюсь открыть mp4-файл с помощью проигрывателя вроде vlc, видео не воспроизводится. Плеер выдает ошибку вроде: заголовок не верен и не воспроизводит ни один кадр. Но я пишу заголовок с функцией writeHeader () в AVFormatContext.

Я предполагаю, что причина в том, что AVFormatContext не правильно инициализирован, но на примере ffmpeg / libav (muxing-examples) я не могу решить проблему.

Есть ли какое-либо решение (пример кода) или другой пример, как правильно инициализировать AVFormatContext?

Спасибо за вашу помощь.
Olgen

    avcodec_init();
avcodec_register_all();
av_register_all();
av_log_set_level(AV_LOG_DEBUG);

char *outputFilename = "/tmp/output.mp4";

// define AVOutputFormat
AVOutputFormat *outputFormat = NULL;
outputFormat = av_guess_format("mp4", NULL, NULL);
if (!outputFormat) {
fprintf(stderr, "Could not find suitable output format\n");
return 1;
}

// define AVFormatContext
AVFormatContext *formatContext = NULL;
// lallocate the output media context
std::cout << "alloc" << std::endl;
formatContext = avformat_alloc_context();
//  avformat_alloc_output_context(&formatContext, outputFormat, NULL, NULL);
if (!formatContext) {
fprintf(stderr, "Memory error\n");
return 1;
}
std::cout << "stream" << std::endl;
AVStream * video_st = av_new_stream(formatContext, 0);
AVCodec * codec = NULL;
avcodec_get_context_defaults3(video_st->codec, codec);
video_st->codec->coder_type = AVMEDIA_TYPE_VIDEO;

video_st->codec->flags = fc->streams[0]->codec->flags;
video_st->codec->sample_aspect_ratio = fc->streams[0]->codec->sample_aspect_ratio;
video_st->disposition = fc->streams[0]->disposition;
video_st->codec->codec_tag = fc->streams[0]->codec->codec_tag;
video_st->codec->bits_per_raw_sample = fc->streams[0]->codec->bits_per_raw_sample;
video_st->codec->chroma_sample_location = fc->streams[0]->codec->chroma_sample_location;
video_st->codec->codec_id = fc->streams[0]->codec->codec_id;
video_st->codec->codec_tag = fc->streams[0]->codec->codec_tag;
video_st->codec->time_base = fc->streams[0]->codec->time_base;
video_st->codec->extradata = fc->streams[0]->codec->extradata;
video_st->codec->extradata_size = fc->streams[0]->codec->extradata_size;
video_st->codec->pix_fmt = fc->streams[0]->codec->pix_fmt;
video_st->codec->width = fc->streams[0]->codec->width;
video_st->codec->height = fc->streams[0]->codec->height;
video_st->codec->sample_aspect_ratio = fc->streams[0]->codec->sample_aspect_ratio;std::cout << "file" << std::endl;
avio_open(&formatContext->pb, outputFilename, AVIO_FLAG_WRITE);
std::cout << "header" << std::endl;
avformat_write_header(formatContext, NULL);
//  av_write_header(formatContext);

// loop to write AVPackets with av_write_frame

Программа вылетает после avformat_write_header (formatContext, NULL) с ошибкой памяти. Я также попробовал avformat_alloc_output_context () вместо avformat_alloc_output_context2 (), но обе функции не работают. Поэтому я использовал avformat_alloc_context () (см. Выше)

Я думаю, что есть проблема распределения, но почему я не могу использовать avformat_alloc_output_context2 или avformat_alloc_output_context. Может кто-нибудь понять мою проблему здесь?

4

Решение

Это общая схема, показывающая, как преобразовывать видеофайл из существующих пакетов.

AVOutputFormat * outFmt = av_guess_format("mp4", NULL, NULL);
AVFormatContext *outFmtCtx = NULL;
avformat_alloc_output_context2(&outFmtCtx, outFmt, NULL, NULL);
AVStream * outStrm = av_new_stream(outFmtCtx, 0);

AVCodec * codec = NULL;
avcodec_get_context_defaults3(outStrm->codec, codec);
outStrm->codec->coder_type = AVMEDIA_TYPE_VIDEO;

///....
/// set some required value, such as
/// outStrm->codec->flags
/// outStrm->codec->sample_aspect_ratio
/// outStrm->disposition
/// outStrm->codec->codec_tag
/// outStrm->codec->bits_per_raw_sample
/// outStrm->codec->chroma_sample_location
/// outStrm->codec->codec_id
/// outStrm->codec->codec_tag
/// outStrm->codec->time_base
/// outStrm->codec->extradata
/// outStrm->codec->extradata_size
/// outStrm->codec->pix_fmt
/// outStrm->codec->width
/// outStrm->codec->height
/// outStrm->codec->sample_aspect_ratio
/// see ffmpeg.c for details

avio_open(&outFmtCtx->pb, outputFileName, AVIO_FLAG_WRITE);

avformat_write_header(outFmtCtx, NULL);

for (...)
{
av_write_frame(outFmtCtx, &pkt);
}

av_write_trailer(outFmtCtx);
avio_close(outFmtCtx->pb);
avformat_free_context(outFmtCtx);

Для устранения неполадок полезно установить подробное ведение журнала: av_log_set_level(AV_LOG_DEBUG);

2

Другие решения

Это может быть не так, но avformat_write_header Функция должна использоваться для написания заголовка вместо указателя функции в AVOutputFormat.write_header

1

По вопросам рекламы [email protected]