FFmpeg:AVPacket結構體分析

AVPacket

文檔地址:傳送門

在AVPacket結構體的說明部分:有這麼一段描述,足夠說明它的作用和重要性。

該結構存儲壓縮數據。 它通常由解複用器導出,然後作爲輸入傳遞給解碼器,或作爲編碼器的輸出接收,然後傳遞給複用器。

對於視頻而言,它通常應包含一個壓縮幀。 對於音頻,它可能包含幾個壓縮幀。 允許編碼器輸出空包,沒有壓縮數據,只包含不重要的附加信息數據。例如在編碼結束時更新一些流參數。

AVPacket是FFmpeg中爲數不多的結構之一,其大小是公共ABI的一部分。 因此,它可以在棧上分配,並且不會添加新的字段,除非libavcodec和libavformat有大的改動。

雖然前面引用部分已經說了AVPacket的作用時機,但這裏還是單獨強調和總結一下:

  • 解碼時:媒體源數據解封裝(解複用)後,解碼前。
  • 編碼時:YUV數據編碼後,封裝前。

AVPacket主要保存一些媒體流的基本信息,例如PTS、DTS時間。最重要的當然就是媒體數據的buffer地址了。

比較重要的有:

  • pts:控制顯示的pts時間
  • dts:控制解碼的dts時間
  • *data:媒體數據buffer的指針
  • duration:AVStream-> time_base單位中此數據包的持續時間,如果未知則爲0。 在演示順序中等於next_pts - this_pts。

初始化與清理

AVPacket* avPacket = av_packet_alloc(); // 初始化
av_packet_unref(avPacket); // 清理

沒什麼稀奇,都是調用特定的函數來處理。這裏需要提一下,雖然在第一小節提到,AVPacket是可以在棧內存上分配,也就是這樣:AVPacket avPacket,但如非必要,我還是不建議這麼做,畢竟有現成的API,就別給自己挖坑了。

還有一個函數:

int av_packet_ref (AVPacket *dst, const AVPacket *src)

它的作用是:

設置對給定數據包描述的數據的新引用。

如果src的data指針不爲空,則將指針地址作爲dst中data指針的值。 否則在dst中分配一個新緩衝區並將數據從src複製到其中。

所有其他字段都是從src複製的。

這個函數和av_packet_unref函數的作用剛好相反。我們詳細瞭解一下這背後的故事:

我們在一開始有提到AVPacket保存了數據buffer的地址,所以,它實際上並沒有包含數據內存本身,只是在它的字段中,用了一個uint8_t *data;來保存數據buffer的地址。

av_packet_ref函數的作用,就是從已有的AVPacket中複製一份出來。關於data部分,如果src的數據是引用計數的,直接把地址拷貝一份,然後把對應buffer的引用計數+1。如果不是,需要新分配一份保存數據的內存空間,並把src中的數據拷貝過來。

av_packet_unref函數,則會看buffer的引用計數器,如果不爲0就-1,爲零的話則會清楚掉buffer,AVPacket的其它數據也會回到初始狀態。

結構定義及成員解讀

typedef struct AVPacket {
    AVBufferRef *buf; // data的buffer引用指針計數結構體
    int64_t pts; // 控制顯示的pts時間
    int64_t dts; // 控制解碼的dts時間
    uint8_t *data; // 媒體數據buffer的指針
    int   size; // 數據大小
    int   stream_index; // 流index
    int   flags; // AV_PKT_FLAG值的組合
    AVPacketSideData *side_data; // 容器可以提供的附加數據包數據。 數據包可以包含幾種類型的輔助信息。
		// AVStream-> time_base單位中此數據包的持續時間,如果未知則爲0。 在演示順序中等於next_pts  -  this_pts。
    int64_t duration;
    int64_t pos; // 流中的字節位置,如果未知則爲-1
} AVPacket;

來擴展一下用來計數的結構體:

typedef struct AVBufferRef {
    AVBuffer *buffer;
    // 當且僅當這是對緩衝區的唯一引用時才被認爲是可寫的,在這種情況下av_buffer_is_writable()返回1。
    uint8_t *data;
    int      size; // 數據大小(以字節爲單位)
} AVBufferRef;

這個結構體,保存了對數據緩衝區的引用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章