Здравствуйте.
Уже неделю мучаю ffmpeg. На данный момент осилено декодирование видео в несжатый вариант (raw). Теперь нужно реализовать кодирование в тот формат, который мне нужен. И вроде бы даже что-то там у меня кодируется, но на выходе получается нечитаемый файл.
Судя по всему, я просто пишу корявый заголовок и поэтому понять, удалось ли что-то там кодировать — невозможно, т.к. файл-то не проиграть.
Пробую пока тупо расжать и сжать обратно mp4-файл.
Вот функция, которая открывает выходной файл и пишет заголовок. По сути, слегка переделанный код из примера transcoding.c, идущего вместе с исходниками ffmpeg.
int open_output_file(const char *filename)
{
int result;
avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, filename);
if (!ofmt_ctx)
{
printf("can't create output context\n");
return -1;
}
ostream = avformat_new_stream(ofmt_ctx, NULL);
if (!ostream)
{
printf("can't create new stream\n");
return -1;
}
ostream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
ostream->codecpar->codec_id = AV_CODEC_ID_H264;
ostream->codecpar->height = decoder_ctx->height;
ostream->codecpar->width = decoder_ctx->width;
encoder_ctx = ostream->codec;
encoder = avcodec_find_encoder(decoder_ctx->codec_id);
if (!encoder)
{
printf("can't find encoder\n");
return -1;
}
encoder_ctx->codec_type = AVMEDIA_TYPE_VIDEO;
encoder_ctx->codec_id = AV_CODEC_ID_H264;
encoder_ctx->height = decoder_ctx->height;
encoder_ctx->width = decoder_ctx->width;
encoder_ctx->qmin = 10;
encoder_ctx->qmax = 51;
encoder_ctx->max_qdiff = 4;
encoder_ctx->sample_aspect_ratio = decoder_ctx->sample_aspect_ratio;
encoder_ctx->time_base = decoder_ctx->time_base;
ostream->time_base = decoder_ctx->time_base;
if (encoder->pix_fmts)
{
encoder_ctx->pix_fmt = encoder->pix_fmts[0];
}
else
{
encoder_ctx->pix_fmt = decoder_ctx->pix_fmt;
}
result = avcodec_open2(encoder_ctx, encoder, NULL)
if (result < 0)
{
printf("can't open encoder for video stream \n");
return -1;
}
if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
encoder_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
av_dump_format(ofmt_ctx, 0, filename, 1);
result = avio_open(&ofmt_ctx->pb, filename, AVIO_FLAG_WRITE);
if (result < 0)
{
printf("can't open output file %s\n", filename);
return -1;
}
result = avformat_write_header(ofmt_ctx, NULL);
if (result < 0)
{
printf("can't write header\n");
return -1;
}
return 0;
}
В результате работы функции получается файл размером 48 байт, с вот таким содержимым:
$ head -1 out.mp4
ftypisomisomiso2avc1mp4freemdat
Если выполнить ffprobe на этот файл, в ответ получаем ругань:
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x3530bc0] moov atom not found
out.mp4: Invalid data found when processing input
Если посмотреть корректный mp4-файл, то там в начале вот так (те же первые 48 байт):
▒ftypmp42isommp42�KmoovlmvhdМ�"М�"X�
Если отрезать эти самые 48 байт от корректного mp4-файла и скормить их ffprobe, то он хотя бы не матерится:
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'test.mp4':
Metadata:
major_brand : mp42
minor_version : 0
compatible_brands: isommp42
creation_time : 2014-11-27 16:04:50
Duration: N/A, bitrate: N/A
Предположительно, что-то не так в параметре ofmt_ctx
функции avformat_write_header
. Посмотрел в дебагере значения некоторых полей структуры ofmt_ctx->oformat
и с точки зрения человека, не разбирающегося в кодировании видео, все выглядит нормально:
136 if (avformat_write_header(ofmt_ctx, NULL) < 0)
(gdb) print ofmt_ctx->oformat->name
$1 = 0xfb258c "mp4"
(gdb) print ofmt_ctx->oformat->mime_type
$2 = 0xf858cd "video/mp4"
(gdb) print ofmt_ctx->oformat->video_codec
$3 = AV_CODEC_ID_H264
В общем, как говорится, куда рыть, что еще смотреть?
Скорее всего, у меня еще будут возникать вопросы, с которыми самостоятельно разобраться не получится. Лучше писать их в продолжение созданных мною прошлых тем или же на каждый вопрос заводить отдельную?