FFmpeg时间戳详解 (3)

可以发现,对于同一个视频帧,它们时间基(tbn)不同因此时间戳(pkt_pts)也不同,但是计算出来的时刻值(pkt_pts_time)是相同的。
看第一帧的时间戳,计算关系:80×{1,1000} == 7200×{1,90000} == 0.080000

3.7 转码过程中的时间基转换

编解码器中的时间基(AVCodecContext.time_base,3.2节中的tbc)定义如下:

typedef struct AVCodecContext { ...... /** * 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 * identically 1. * This often, but not always is the inverse of the frame rate or field rate * for video. 1/time_base is not the average frame rate if the frame rate is not * constant. * * Like containers, elementary streams also can store timestamps, 1/time_base * is the unit in which these timestamps are specified. * As example of such codec time base see ISO/IEC 14496-2:2001(E) * vop_time_increment_resolution and fixed_vop_rate * (fixed_vop_rate == 0 implies that it is different from the framerate) * * - encoding: MUST be set by user. * - decoding: the use of this field for decoding is deprecated. * Use framerate instead. */ AVRational time_base; ...... }

上述注释指出,AVCodecContext.time_base是帧率(视频帧)的倒数,每帧时间戳递增1,那么tbc就等于帧率。编码过程中,应由用户设置好此参数。解码过程中,此参数已过时,建议直接使用帧率倒数用作时间基。
这里有一个问题:按照此处注释说明,帧率为25的视频流,tbc理应为25,但实际值却为50,不知作何解释?是否tbc已经过时,不具参考意义?

根据注释中的建议,实际使用时,在视频解码过程中,我们不使用AVCodecContext.time_base,而用帧率倒数作时间基,在视频编码过程中,我们将AVCodecContext.time_base设置为帧率的倒数。

3.7.1 视频流

视频按帧播放,所以解码后的原始视频帧时间基为 1/framerate。
视频解码过程中的时间基转换处理:

AVFormatContext *ifmt_ctx; AVStream *in_stream; AVCodecContext *dec_ctx; AVPacket packet; AVFrame *frame; // 从输入文件中读取编码帧 av_read_frame(ifmt_ctx, &packet); // 时间基转换 int raw_video_time_base = av_inv_q(dec_ctx->framerate); av_packet_rescale_ts(packet, in_stream->time_base, raw_video_time_base); // 解码 avcodec_send_packet(dec_ctx, packet) avcodec_receive_frame(dec_ctx, frame);

视频编码过程中的时间基转换处理:

AVFormatContext *ofmt_ctx; AVStream *out_stream; AVCodecContext *dec_ctx; AVCodecContext *enc_ctx; AVPacket packet; AVFrame *frame; // 编码 avcodec_send_frame(enc_ctx, frame); avcodec_receive_packet(enc_ctx, packet); // 时间基转换 packet.stream_index = out_stream_idx; enc_ctx->time_base = av_inv_q(dec_ctx->framerate); av_packet_rescale_ts(&opacket, enc_ctx->time_base, out_stream->time_base); // 将编码帧写入输出媒体文件 av_interleaved_write_frame(o_fmt_ctx, &packet); 3.7.2 音频流

音频按采样点播放,所以解码后的原始音频帧时间基为 1/sample_rate
音频解码过程中的时间基转换处理:

AVFormatContext *ifmt_ctx; AVStream *in_stream; AVCodecContext *dec_ctx; AVPacket packet; AVFrame *frame; // 从输入文件中读取编码帧 av_read_frame(ifmt_ctx, &packet); // 时间基转换 int raw_audio_time_base = av_inv_q(dec_ctx->sample_rate); av_packet_rescale_ts(packet, in_stream->time_base, raw_audio_time_base); // 解码 avcodec_send_packet(dec_ctx, packet) avcodec_receive_frame(dec_ctx, frame);

音频编码过程中的时间基转换处理:

AVFormatContext *ofmt_ctx; AVStream *out_stream; AVCodecContext *dec_ctx; AVCodecContext *enc_ctx; AVPacket packet; AVFrame *frame; // 编码 avcodec_send_frame(enc_ctx, frame); avcodec_receive_packet(enc_ctx, packet); // 时间基转换 packet.stream_index = out_stream_idx; enc_ctx->time_base = av_inv_q(dec_ctx->sample_rate); av_packet_rescale_ts(&opacket, enc_ctx->time_base, out_stream->time_base); // 将编码帧写入输出媒体文件 av_interleaved_write_frame(o_fmt_ctx, &packet); 4. 参考资料

[1]. What does the output of ffmpeg mean? tbr tbn tbc etc?
[2]. 视频编解码基础概念, https://www.cnblogs.com/leisure_chn/p/10285829.html
[3]. 对ffmpeg的时间戳的理解笔记, https://blog.csdn.net/topsluo/article/details/76239136
[4]. ffmpeg中的时间戳与时间基,
[5]. ffmpeg编解码中涉及到的pts详解,
[6]. 音视频录入的pts和dts问题, https://blog.csdn.net/zhouyongku/article/details/38510747

5. 修改记录

2019-03-16 V1.0 初稿
2019-03-23 V1.1 增加3.7节

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyyspz.html