Need help, recently, I am using ffmpeg libavcodec to decode a video file then encode to H264 and write to an mp4 media container, finally, the media file's duration is zero, the following is my code's workflow:
AVFormatContext* input_format_context = NULL;
AVFormatContext* output_format_context = NULL;
AVIOContext* output_io_context = NULL;
AVCodecContext* input_codec_context = NULL;
AVCodecContext* output_codec_context = NULL;
AVCodec* codec = NULL;
AVStream* input_stream = NULL;
AVStream* output_stream = NULL;
AVFrame* frame = NULL;
int convert_init(const char* input_filename, const char* output_filename)
{
/** Allocate a new encode context */
avformat_open_input(&input_format_context,
input_filename, NULL, NULL);
/** Get information on the input file (number of streams etc.). */
avformat_find_stream_info(input_format_context, NULL);
/** Open the output file to write to it. */
avio_open(&output_io_context, output_filename,
AVIO_FLAG_WRITE);
/** Create a new format context for the output container format. */
output_format_context = avformat_alloc_context();
/** Associate the output file (pointer) with the container format context. */
output_format_context->pb = output_io_context;
/** Guess the desired container format based on the file extension. */
output_format_context->oformat = av_guess_format(NULL,
output_filename, NULL);
av_strlcpy((output_format_context)->filename, output_filename,
sizeof(output_format_context->filename));
/** stream0 is the video stream */
AVStream* input_stream = input_format_context->streams[0];
/**
* Init the input_codec_context
*/
/** Find a decoder for the audio stream. */
codec = avcodec_find_decoder(input_stream->codecpar->codec_id);
/** Allocate a new decode context */
input_codec_context = avcodec_alloc_context3(codec);
/** Initialize the stream parameters with demuxer information */
avcodec_parameters_to_context(input_codec_context,
input_stream->codecpar);
/** Open the decoder for the stream. */
avcodec_open2(input_codec_context, codec, NULL);
/**
* Create an output stream for writing encoded data
*
* AM I MISSING SOMETHING ?
*
*/
output_stream = avformat_new_stream(output_format_context, NULL);
/**
* Init the output_codec_context
*/
/** Find a encoder for the output video stream, using H264. */
codec = avcodec_find_encoder(AV_CODEC_ID_H264);
/** Allocate an encode context. */
output_codec_context = avcodec_alloc_context3(codec);
/**
* Setup encode context parameters.
*
* AM I MISSING SOMETHING ?
*
* */
output_codec_context->bit_rate = input_codec_context->bit_rate;
output_codec_context->width = input_codec_context->width;
output_codec_context->height = input_codec_context->height;
output_codec_context->time_base = (AVRational){1, 25};
output_codec_context->framerate = (AVRational){25, 1};
output_codec_context->gop_size = 10;
output_codec_context->max_b_frames = 1;
output_codec_context->pix_fmt = AV_PIX_FMT_YUV420P;
output_codec_context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
/** Setup output_stream codecpar. */
avcodec_parameters_from_context(output_stream->codecpar,
codec_context);
/** Alloc an av frame */
frame = av_frame_alloc();
}
void convert_it()
{
AVPacket input_packet;
AVPacket output_packet;
/** Write the media file container header */
avformat_write_header(output_format_context, NULL);
/**
* decode frames and encode to H264
* */
while (1) {
av_init_packet(&input_packet);
input_packet.data = NULL;
input_packet.size = 0;
av_init_packet(&output_packet);
output_packet.data = NULL;
output_packet.size = 0;
/** Read a frame to decode */
av_read_frame(input_format_context, &input_packet);
if (av_read_frame is end of file) {
break;
}
...
...
/** Decoding... */
avcodec_send_packet(input_codec_context, &input_packet);
...
...
/** Get a decoded frame */
avcodec_receive_frame(input_codec_context, frame);
...
...
/** Make the frame writable, is it necessary ?? */
av_frame_make_writable(frame);
/** Encode to H264 */
avcodec_send_frame(output_codec_context, frame);
...
...
/** Get a encoded packet */
avcodec_receive_packet(output_codec_context, &output_packet);
/**
* Write the packet to output.
* Here is the point! should I configure the parameters
* in packet such as 'pts', 'dts', 'duration', etc, if so,
* hwo? or I just directly write the packet into output?
*/
av_interleaved_write_frame(output_format_context, &packet);
}
/** Write the media file container trailer */
av_write_trailer(output_format_context);
}
int main() {
convert_init("./sample.avi", "./output.mp4");
convert_it();
}
using VLC or QuickTime to playback the output.mp4 file, it failed, cause the file duration is zero, when dragging the time progress bar, I can see the picture frame clearly, it seems that the encoding packet buffer data is correct, but the timestamp is error, am I missing something when configure the output_stream or packet? The following is message from ffprobe.
ffprobe output.mp4
ffprobe version 3.3.3 Copyright (c) 2007-2017 the FFmpeg developers
built with Apple LLVM version 8.1.0 (clang-802.0.42)
configuration: --enable-shared --enable-libmp3lame
libavutil 55. 58.100 / 55. 58.100
libavcodec 57. 89.100 / 57. 89.100
libavformat 57. 71.100 / 57. 71.100
libavdevice 57. 6.100 / 57. 6.100
libavfilter 6. 82.100 / 6. 82.100
libswscale 4. 6.100 / 4. 6.100
libswresample 2. 7.100 / 2. 7.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'output.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
encoder : Lavf57.71.100
Duration: 00:00:00.06, start: 0.000000, bitrate: 6902181 kb/s
Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 720x408 [SAR 1:1 DAR 30:17], 13929056 kb/s, 90k fps, 90k tbr, 90k tbn, 50 tbc (default)
Metadata:
handler_name : VideoHandler