使用ffmpeg libavcodec将视频流编码为H264,为啥持续时间为零
Posted
技术标签:
【中文标题】使用ffmpeg libavcodec将视频流编码为H264,为啥持续时间为零【英文标题】:using ffmpeg libavcodec encode video stream to H264, why duration is zero使用ffmpeg libavcodec将视频流编码为H264,为什么持续时间为零 【发布时间】:2018-02-10 08:14:14 【问题描述】:需要帮助,最近我正在使用ffmpeg libavcodec解码视频文件然后编码为H264并写入mp4媒体容器,最后媒体文件的持续时间为零,以下是我的代码工作流程:
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();
使用VLC或QuickTime播放output.mp4文件失败,导致文件时长为零,拖动时间进度条时,我可以清楚地看到画框,看来编码包缓冲区数据是正确的,但时间戳是错误的,我在配置 output_stream 或数据包时是否遗漏了什么?以下是来自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
【问题讨论】:
请提供输入输出文件。 【参考方案1】:您的问题可能是在复用过程中帧的时基错误。 取决于格式,the muxer can change the stream timebase。
流时基应设置为调用者希望用于此流的时基(注意,复用器实际使用的时基可能不同,稍后将介绍)。 [...] 请注意,发送到复用器的数据包的时间信息必须在相应的 AVStream 的时基中。该时基由复用器设置(在 avformat_write_header() 步骤中),并且可能与调用者请求的时基不同。
因此,在编写帧之前,您必须将其时基从创建 FormatContext 时设置的理论时基转换为流实际使用的时基。为此,您可以使用 av_packet_rescale_ts 函数。
例如:av_packet_rescale_ts(
packet,
codec_contex->time_base, // your theoric timebase
format_context->streams[packet->stream_index]->time_base); // the actual timebase
【讨论】:
以上是关于使用ffmpeg libavcodec将视频流编码为H264,为啥持续时间为零的主要内容,如果未能解决你的问题,请参考以下文章
基于 FFMPEG 的视频编码(libavcodec ,致敬雷霄骅)
基于 FFMPEG 的视频编码(libavcodec ,致敬雷霄骅)
基于 FFMPEG 的视频编码 源码(libavcodec,C++ Qt)
基于 FFMPEG 的视频编码 源码(libavcodec,C++ Qt)