添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

时间基(time_base)是FFmpeg中作为 时间单位 的概念。不同的音视频封装格式,可以使用不同的 time_base

FFmpeg内部的时间都会基于 AV_TIME_BASE 作为时间单位,比如AVStream中的duration表示这个流的长度为duration个 AV_TIME_BASE

* Internal time base represented as integer #define AV_TIME_BASE 1000000

AVStream中的time_base的定义:

typedef struct AVStream { 
		* This is the fundamental unit of time (in seconds) in terms
		* of which frame timestamps are represented.
		* decoding: set by libavformat
		* encoding: May be set by the caller before avformat_write_header() to
		*           provide a hint to the muxer about the desired timebase. In
		*           avformat_write_header(), the muxer will overwrite this field
		*           with the timebase that will actually be used for the timestamps
		*           written into the file (which may or may not be related to the
		*           user-provided one, depending on the format).
	AVRational time_base;
     * Decoding: duration of the stream, in stream time base.
     * If a source file does not specify a duration, but does specify
     * a bitrate, this value will be estimated from bitrate and file size.
     * Encoding: May be set by the caller before avformat_write_header() to
     * provide a hint to the muxer about the estimated duration.
  int64_t duration;
	// ...

为了时间计算的精度,FFmpeg引入有理数的时间基形式 AV_TIME_BASE_Q

* Rational number (pair of numerator and denominator). typedef struct AVRational{ int num; ///< Numerator int den; ///< Denominator } AVRational; * Internal time base represented as fractional value #define AV_TIME_BASE_Q (AVRational){1, AV_TIME_BASE}

ffmpeg提供了一个把AVRatioal有理数结构转换成double的函数:

* Convert an AVRational to a `double`. * @param a AVRational to convert * @return `a` in floating-point form * @see av_d2q() static inline double av_q2d(AVRational a){ return a.num / ( double ) a.den;

时间戳换算

比如计算视频的总时长:

AVFormatContext *ifmt_ctx = NULL;
avformat_open_input(&ifmt_ctx, filename, NULL, NULL);
double totle_seconds = ifmt_ctx->duration * av_q2d(AV_TIME_BASE_Q);

根据pts计算一帧在视频中对应的秒数位置:

double sec = enc_pkt.pts * av_q2d(ofmt_ctx->streams[stream_index]->time_base);

ffmpeg内部的时间戳与标准的时间转换方法

timestamp(ffmpeg内部时间戳) = AV_TIME_BASE * time(秒)
time(秒) = AV_TIME_BASE_Q * timestamp(ffmpeg内部时间戳)

当需要把视频跳转到N秒的时候:

int64_t timestamp = N * AV_TIME_BASE; 
av_seek_frame(fmtctx, index_of_video, timestamp, AVSEEK_FLAG_BACKWARD);

时间基转换函数

另外,FFmpeg为我们提供了不同时间基之间的转换函数,把时间戳从一个时基调整到另外一个时基:

* Rescale a 64-bit integer by 2 rational numbers. * The operation is mathematically equivalent to `a * bq / cq`. * This function is equivalent to av_rescale_q_rnd() with #AV_ROUND_NEAR_INF. * @see av_rescale(), av_rescale_rnd(), av_rescale_q_rnd() int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq) av_const;

dts/pts计算

  • dts: decoding time stamp (解码时间戳)
  • pts: present time stamp (显示时间戳)
  • 转码流程中的 dts/pts 转换:

    AVPacket packet;
    av_read_frame(ifmt_ctx, &packet)
    
    AVFrame *frame = NULL;
    // 转换为解码器的时间戳
    av_packet_rescale_ts(&packet,
                                 ifmt_ctx->streams[stream_index]->time_base,
                                 ifmt_ctx->streams[stream_index]->codec->time_base);
    dec_func = (type == AVMEDIA_TYPE_VIDEO) ? avcodec_decode_video2 :
            avcodec_decode_audio4;
    ret = dec_func(ifmt_ctx->streams[stream_index]->codec, frame,
                           &got_frame, &packet);
    
    AVPacket enc_pkt;
    int (*enc_func)(AVCodecContext *, AVPacket *, const AVFrame *, int *) =
      (ifmt_ctx->streams[stream_index]->codec->codec_type ==
       AVMEDIA_TYPE_VIDEO) ? avcodec_encode_video2 : avcodec_encode_audio2;
    /* encode filtered frame */
    enc_pkt.data = NULL;
    enc_pkt.size = 0;
    av_init_packet(&enc_pkt);
    ret = enc_func(ofmt_ctx->streams[stream_index]->codec, &enc_pkt,
                    filt_frame, got_frame);
    
    // 编码后的enc_pkt的时间戳以AVCodecContext->time_base为单位
    // 编码器时间戳转为输出流AVStream时间戳
    av_packet_rescale_ts(&enc_pkt,
                           ofmt_ctx->streams[stream_index]->codec->time_base,
                           ofmt_ctx->streams[stream_index]->time_base);
    av_interleaved_write_frame(ofmt_ctx, &enc_pkt);
    
  • http://blog.csdn.net/leixiaohua1020/article/details/28114081
  • http://www.cnblogs.com/yinxiangpei/articles/3892982.html
  • http://blog.csdn.net/TopsLuo/article/details/76239136
  • https://www.jianshu.com/p/bf323cee3b8e
  • http://blog.csdn.net/leixiaohua1020/article/details/15811977

  • 本文出处:https://www.suninf.net/2018/02/ffmpeg-timestamps.html 文章版权归本人所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
    如果觉得本博客对您有帮助,欢迎 赞赏作者