Смешивание AVPackets в mp4 файл - вновь - PullRequest
1 голос
/ 09 мая 2019

Я ссылаюсь на эту тему здесь: Смешивание AVPackets в mp4-файл

Вопрос в основном такой же, как у меня, и первый ответ выглядит очень многообещающе.Исходный код (somkind of pseudo), который предоставляет пользователь pogorskiy , похоже, делает именно то, что мне нужно:

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);

Данные pkt , которые я получаю отсторонний API от моей камеры connectctec.Нет файла для открытия, для чтения входных данных, и нет потока RTSP, который будет получен с камеры.Это просто вызов API, который дает мне указатель на кодированный кадр H264, который является именно необработанными данными для AVPacket.

В любом случае, я пытаюсь использовать этот код в качестве основы для моего приложения, но первыйВозникающая проблема заключается в том, что я получаю ошибку времени выполнения:

Could not find tag for codec none in stream #0, codec not currently supported in container

Поэтому я начал добавлять дополнительную информацию в кодек, как погорский предложил:

outStrm->codec->codec_id = AV_CODEC_ID_H264;
outStrm->codec->width = 1920;
outStrm->codec->height = 1080;

Теперь, когда я предоставил codec_id, я надеялся, что сообщение во время выполнения изменится, по крайней мере, на что-то другое, но оно по-прежнему будет таким же:

Could not find tag for codec none in stream #0, codec not currently supported in container

Любая идея о том, как я могу настроить структуры,чтобы я мог открыть файл mp4 для записи своих пакетов в?

1 Ответ

1 голос
/ 10 мая 2019

Хорошо, у меня все получилось. По крайней мере, я могу открыть файл mp4 и записать в него мои закодированные H264 пакеты. Файл даже открывается в VLC и показывает самый первый кадр ... Ничего более, но это начало.

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

char outputFileName[] = "camera.mp4";

av_log_set_level(AV_LOG_DEBUG);

AVOutputFormat * outFmt = av_guess_format("mp4", NULL, NULL);
AVFormatContext *outFmtCtx = NULL;
avformat_alloc_output_context2(&outFmtCtx, outFmt, NULL, NULL);
AVStream * outStrm = avformat_new_stream(outFmtCtx, NULL);
outStrm->id = 0;
outStrm->time_base = {1, 30};
outStrm->avg_frame_rate = {1, 30};

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

outFmtCtx->video_codec_id = AV_CODEC_ID_H264;

///....
/// 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->codecpar->codec_id = AV_CODEC_ID_H264;
outStrm->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
/// outStrm->codec->time_base
/// outStrm->codec->extradata 
/// outStrm->codec->extradata_size
/// outStrm->codec->pix_fmt
outStrm->codecpar->width = 1920;
outStrm->codecpar->height = 1080;
/// outStrm->codec->sample_aspect_ratio
/// see ffmpeg.c for details  

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

avformat_write_header(outFmtCtx, NULL); 

*** Camera access loop via GenICam API starts here ***
n++;
av_init_packet(&avPacket);
avPacket.data = static_cast<uint8_t*>(pPtr); // raw data from the Camera with H264 encoded frame
avPacket.size = datasize; // datasize received from the GenICam API along with pPtr (the raw data)
avPacket.pts = (1/30) * n; // stupid try to set pts and dts somehow... Working on this...
avPacket.dts = (1/30) * (n-1);
avPacket.pos = n;
avPacket.stream_index = outStrm->index;

av_write_frame(outFmtCtx, &avPacket);

**** Camera access loop ends here ****

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

Как я уже сказал, полученный файл mp4 показывает самый первый кадр в течение доли секунды, и после этого он прекращает воспроизведение. Я думаю, что отображается первый кадр, потому что я уверен, что это I-кадр, содержащий полное изображение.

Я не знаю, нужно ли мне предоставлять некоторые дополнительные данные мультиплексору, чтобы получить работающий файл mp4. Я все еще работаю над этим.

Любые комментарии и идеи приветствуются!

Спасибо, Maik

...