Я использую библиотеки ffmpeg для создания файла AVI и следую muxing.c ffmpeg
пример как ниже
avformat_alloc_output_context2
Добавить видео потоки, используя AV_CODEC_ID_H264
кодек с набором параметров ниже:
int AddVideoStream(AVStream *&video_st, AVFormatContext *&oc, AVCodec **codec, enum AVCodecID codec_id){
AVCodecContext *c;
/* find the encoder */
*codec = avcodec_find_encoder(codec_id); //codec id = AV_CODEC_ID_H264
if (!(*codec)) {
sprintf(strError , "Could not find encoder for '%s' line %d\n", avcodec_get_name(codec_id), __LINE__);
commonGlobal->WriteRuntimeBackupLogs(strError);
return RS_NOT_OK;
}
video_st = avformat_new_stream(oc, *codec);
if (!video_st) {
sprintf(strError , "Could not allocate stream line %d\n", __LINE__);
commonGlobal->WriteRuntimeBackupLogs(strError);
return RS_NOT_OK;
}
video_st->id = oc->nb_streams-1;
c = video_st->codec;
avcodec_get_context_defaults3(c, *codec);
c->codec_id = codec_id;
c->bit_rate = 500*1000;
/* Resolution must be a multiple of two. */
c->width = 1280;
c->height = 720;
/* timebase: This is the fundamental unit of time (in seconds) in terms
* of which frame timestamps are represented. For fixed-fps content,
* timebase should be 1/framerate and timestamp increments should be
* identical to 1. */
c->time_base.den = 25*1000;
c->time_base.num = 1000;
c->gop_size = 12;//(int)(av_q2d(c->time_base) / 2); // GOP size is framerate/2
c->pix_fmt = STREAM_PIX_FMT;
/* Some formats want stream headers to be separate. */
if (oc->oformat->flags & AVFMT_GLOBALHEADER)
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
return RS_OK;
}
Открыть видео поток: open_video
int open_video( AVFormatContext *oc, AVCodec *codec, AVStream *st ){
int ret;
AVCodecContext *c = st->codec;
char strError[STR_LENGTH_256];
/* open the codec */
ret = avcodec_open2(c, codec, NULL);
if (ret < 0) {
sprintf(strError , "Could not open video codec line %d", __LINE__);
commonGlobal->WriteRuntimeBackupLogs(strError);
return RS_NOT_OK;
}
/* allocate and init a re-usable frame */
frame = avcodec_alloc_frame();
if (!frame) {
sprintf(strError , "Could not allocate video frame line %d", __LINE__);
commonGlobal->WriteRuntimeBackupLogs(strError);
return RS_NOT_OK;
}
/* Allocate the encoded raw picture. */
ret = avpicture_alloc(&dst_picture, c->pix_fmt, c->width, c->height);
if (ret < 0) {
sprintf(strError , "Could not allocate picture line %d", __LINE__);
commonGlobal->WriteRuntimeBackupLogs(strError);
return RS_NOT_OK;
}
/* If the output format is not YUV420P, then a temporary YUV420P
* picture is needed too. It is then converted to the required
* output format. */
if (c->pix_fmt != AV_PIX_FMT_YUV420P) {
ret = avpicture_alloc(&src_picture, AV_PIX_FMT_YUV420P, c->width, c->height);
if (ret < 0) {
sprintf(strError , "Could not allocate temporary picture line %d", __LINE__);
commonGlobal->WriteRuntimeBackupLogs(strError);
return RS_NOT_OK;
}
}
/* copy data and linesize picture pointers to frame */
*((AVPicture *)frame) = dst_picture;
return RS_OK;
}
Напишите заголовок потока AVI: avformat_write_header
Кодировать видеокадр:avcodec_encode_video2
Случай а: входные данные здесь BRG frames
поэтому я кодирую их в H264 и перехожу к следующему шагу.
Случай б: входные данные здесь H264 compressed frames (these frames captured from H264 RTP stream)
поэтому я оставляю этот шаг, а затем перехожу к следующему шагу.
Напишите Interleave Video frame: av_interleaved_write_frame(oc, &pkt)
Случай а: запись пакетных данных, закодированных с шага 5, без ошибок.
Случай б: я всегда получаю ошибку от av_interleaved_write_frame
со значением -22. Это может быть неверный аргумент EINVAL. Так что кто-то может сказать мне, что не так? или некоторые параметры, которые я пропустил здесь.
int WriteVideoFrame(AVFormatContext *&oc, AVStream *&st,
uint8_t *imageData `/*BRG data input*/`,
int width,
int height,
bool isStart,
bool isData,
bool isCompressed,
AVPacket* packet `/*H264 data input*/`)
{
if (isCompressed == false)// For BRG data
{
static struct SwsContext *sws_ctx;
AVCodecContext *c = st->codec;
if (isData)
{
if (!frame) {
//fprintf(stderr, "Could not allocate video frame\n");
return RS_NOT_OK;
}
if (isStart == true)
frame->pts = 0;
/* Allocate the encoded raw picture. */
if (width != c->width || height != c->height)
{
if (!sws_ctx)
{
sws_ctx = sws_getContext(width, height,
AV_PIX_FMT_BGR24, c->width, c->height,
AV_PIX_FMT_YUV420P, SWS_FAST_BILINEAR, 0, 0, 0);
if (!sws_ctx)
{
sprintf(strError, "Could not initialize the conversion context line %d\n", __LINE__);
commonGlobal->WriteRuntimeBackupLogs(strError);
return RS_NOT_OK;
}
}
uint8_t * inData[1] = { imageData }; // RGB24 have one plane
int inLinesize[1] = { 3 * width }; // RGB stride
sws_scale(sws_ctx, inData, inLinesize, 0, height, dst_picture.data, dst_picture.linesize);
}
else
BRG24ToYUV420p(dst_picture.data, imageData, width, height); //Phong Le changed this
}
if (oc->oformat->flags & AVFMT_RAWPICTURE)
{
/* Raw video case - directly store the picture in the packet */
AVPacket pkt;
av_init_packet(&pkt);
pkt.flags |= AV_PKT_FLAG_KEY;
pkt.stream_index = st->index;
pkt.data = dst_picture.data[0];
pkt.size = sizeof(AVPicture);
ret = av_interleaved_write_frame(oc, &pkt);
av_free_packet(&pkt);
}
else
{
/* encode the image */
AVPacket pkt;
int got_output;
av_init_packet(&pkt);
pkt.data = NULL; // packet data will be allocated by the encoder
pkt.size = 0;
ret = avcodec_encode_video2(c, &pkt, frame, &got_output);
if (ret < 0) {
sprintf(strError, "Error encoding video frame line %d\n", __LINE__);
commonGlobal->WriteRuntimeBackupLogs(strError);
av_free_packet(&pkt);
return RS_NOT_OK;
}
/* If size is zero, it means the image was buffered. */
if (got_output) {
if (c->coded_frame->key_frame)
pkt.flags |= AV_PKT_FLAG_KEY;
pkt.stream_index = st->index;
/* Write the compressed frame to the media file. */
ret = av_interleaved_write_frame(oc, &pkt);
}
else
{
ret = 0;
}
av_free_packet(&pkt);
}
if (ret != 0)
{
sprintf(strError, "Error while writing video frame line %d\n", __LINE__);
commonGlobal->WriteRuntimeBackupLogs(strError);
return RS_NOT_OK;
}
frame->pts += av_rescale_q(1, st->codec->time_base, st->time_base);
return RS_OK;
}
еще /Данные H264/
{
if (isStart == true)
packet->pts = 0;
else
packet->pts += av_rescale_q(1, st->codec->time_base, st->time_base);
ret = av_interleaved_write_frame(oc, packet);
if (ret < 0)
{
sprintf(strError, "Error while writing video frame line %d\n", __LINE__);
commonGlobal->WriteRuntimeBackupLogs(strError);
return RS_NOT_OK;
}
return RS_OK;
}
}
-> Случай a: Создание файла AVI прошло успешно.
-> Дело Б: Неудача.
Спасибо
Тянь Во
Задача ещё не решена.