FFmpeg時間戳

FFmpeg內部有多種時間戳,基於不一樣的時間基準。理解這些時間概念,有助於經過FFmpeg進行音視頻開發。ide

在我看來,FFmpeg有兩個時間基準:AV_TIME_BASE和AVStream->time_base。函數

內部時間基準:AV_TIME_BASE

AV_TIME_BASE表示1S對應多長時間,AV_TIME_BASE_Q則是對應的分數形式,以下所示:ui

/** * Internal time base represented as integer * */
#define AV_TIME_BASE 1000000

/** * Internal time base represented as fractional value */
#define AV_TIME_BASE_Q (AVRational){1, AV_TIME_BASE}
複製代碼

AVFormatContext中的參數可能是基於AV_TIME_BASE的,以下所示:spa

/** * Position of the first frame of the component, in * AV_TIME_BASE fractional seconds. * 第一幀的開始時間戳 */
int64_t start_time;
/** * Duration of the stream, in AV_TIME_BASE fractional * seconds. * 時長 */
int64_t duration;
複製代碼

好比:經過AVFormatContext計算出音視頻文件的時長:code

/** * Convert an AVRational to a `double`. */
static inline double av_q2d(AVRational a){
    return a.num / (double) a.den;
}

// 單位秒
AVFormatContext->duration * av_q2d(AV_TIME_BASE_Q) 複製代碼

因此,基於內部時間基準的時間戳轉換很簡單:component

// 時間戳轉換到秒
time_in_seconds = timestamp * av_q2d(AV_TIME_BASE_Q)
// 秒轉換到時間戳
timestamp = time_in_seconds * AV_TIME_BASE
複製代碼

流時間基準:AVStream->time_base

AVStream表示AVFormatContext中一條具體的流結構,好比:音頻流、視頻流和字幕流等。AVStream->time_base也是分數結構AVRational,只不過再也不是固定值,而是依賴於具體流。 AVStreamAVPacketAVFrame中的時間戳可能是基於對應的流時間基準。orm

例如:AVStream中的幀開始時間戳和流時長:視頻

/** * This is the fundamental unit of time (in seconds) in terms * of which frame timestamps are represented. * 表示一秒對應多長時間 */
AVRational time_base;
/** * Decoding: pts of the first frame of the stream in presentation order, in stream time base. */
int64_t start_time;
/** * Decoding: duration of the stream, in stream time base. */
int64_t duration;
複製代碼

要計算出流時長信息(秒),以下所示:開發

//計算出AVStream多少秒
duration(秒) = AVStream->duration * av_q2d(AVStream->time_base);
複製代碼

好比:某視頻流的time_base是1/90000,即:90000表示1秒。那麼2700000實際表示30秒。get

再看一下AVFrame中的時間戳:

/** * frame timestamp estimated using various heuristics, in stream time base * */
int64_t best_effort_timestamp;
/** * Presentation timestamp in time_base units (time when frame should be shown to user). */
int64_t pts;
複製代碼

通常狀況下,二者均可以表示PTS時間戳,且都是基於流時間基準。

// 用秒錶示PTS
timestamp(秒) = av_frame_get_best_effort_timestamp(AVFrame) * av_q2d(AVStream->time_base);
複製代碼

不一樣時間基準之間的轉換

爲了在不一樣時間基準間進行轉換,FFmpeg提供了av_rescale_q函數進行轉換

/** * Rescale a 64-bit integer by 2 rational numbers. * The operation is mathematically equivalent to `a * bq / cq`. * a表示要原始值,bq表示原來的時間基準;cq表示要轉換到的時間基準 */
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq) av_const;
複製代碼

例如:把流時間戳轉換到內部時間戳:

// 把某個視頻幀的pts轉換成內部時間基準
av_rescale_q(AVFrame->pts, AVStream->time_base, AV_TIME_BASE_Q)
複製代碼

ffmpeg中進行seek時(av_seek_frame),時間戳必須基於流時間基準,好比:seek到第5秒。

// 首先計算出基於視頻流時間基準的時間戳
int64_t timestamp_in_stream_time_base = av_rescale_q(5 * AV_TIME_BASE, AV_TIME_BASE_Q, video_stream_->time_base);
// 而後seek
av_seek_frame(av_format_context, video_stream_index, timestamp_in_stream_time_base, AVSEEK_FLAG_BACKWARD);
複製代碼
相關文章
相關標籤/搜索