FFmpeg(7)-av_read_frame()讀取幀數據AVPacket和av_seek_frame()改變播放進度


一.av_read_frame()

該函數用於讀取具體的音/視頻幀數據

int av_read_frame(AVFormatContext *s, AVPacket *pkt);

參數說明:

AVFormatContext *s   // 文件格式上下文

AVPacket *pkt      // 這個值不能傳NULL,必須是一個空間,

            // 返回值:return 0 is OK, <0 on error or end of file

 

二.AVPacket

2.1 結構體常見參數說明

AVBufferRef buf;     // 指向一個buf空間,該空間是用來存儲引用計數的。有可能多個AVPacket指向的都是這個buf的空間。因此要在每次拷貝的時候對其進行+1,刪除的時候對其進行-1.

int64_t pts        // 顯示時間。是一個long long 的類型。

int64_t des     // 解碼時間。與上面一致,單位也是long long 類型。

uint8_t *data; int size // 指向的是AVBufferRef里面再分配的空間。該空間無法手動刪除,因為是在動態庫中創建的,需要調用FFmpeg提供的接口來刪除。

 

2.2 相關函數說明

AVPacket *av_packet_alloc(void)         // AVPacket空間的創建和初始化。創建一個AVPacket對象,它會在堆上面申請空間,因此還需要去手動釋放。

AVPacket *av_packet_clone(const AVPacket *src); // AVPacket空間的復制。創建並應用引用計數, 同時分配空間並增加引用計數。

int av_packet_ref(AVPacket *dst, const AVPacket *src); // 手動對AVPacket的引用計數+1

int av_packet_unref(AVPacket *pkt);  // 手動對AVPacket的引用計數-1

void av_packet_free(AVPacket **pkt); // 清空對象並減引用計數

void av_init_packet(AVPacket *pkt); // 初始化的一個接口,如果只是在棧中或者是new了一個對象,可以利用此函數進行初始化。

int av_packet_from_data(AVPacket *pkt, uint8_t *data, int size); // 分配空間的函數。如果創建了一個AVPacket,但還需要分配空間的話,可以調用該函數來分配空間。

int av_copy_packet(AVPacket *dst, const AVPacket *src); // 早期函數,已過期。不推薦使用。

 

 

三.av_seek_frame()

該函數可以將音/視頻seek到指定的位置。

參數說明:

AVFormatContext *s // 封裝格式上下文

int streamIndex    // 流的索引。默認值為-1,因為媒體文件中可能既包含視頻又包含音頻,可以通過streamIndex來指定究竟是以視頻還是音頻來移。

int64_t timestamp. // 時間戳。你要移動到哪個時間位置。

int flag       // 標識位。表示我們移動的策略(究竟是向前移,還是向后移)。

 

PS:av_seek_frame flag

#define AVSEEK_FLAG_BACKGROUND 1              ///<<Seek Background 往后移,

#define AVSEEK_FALG_BYTE         ///<<<seeking based on position in bytes 時間
變成一個byte, 按照文件的大小位置跳到那個位置

#define AVSEEK_FLAG_ANY         ///<<<seek to any frame, even non-keyframes // 移動到任意幀的位置前面關鍵幀,

#define AVSEEK_FLAG_FRAME        ///<<<seeking based on frame number // 找關鍵幀,一般與AVSEEK_FLAG_BACKGROUND一起使用

 

 

四.代碼示例

// 讀取一幀數據
    AVPacket *packet = av_packet_alloc();
    for (;;) {
        int ret = av_read_frame(ic, packet);
        if (ret != 0) {
            LOGI("讀取到結尾處");
            int pos = 20 * r2d(ic->streams[videoStream]->time_base);
            // 改變播放進度
            av_seek_frame(ic, videoStream, pos, AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_FRAME);
            continue;
        }
        LOGI("streamIndex=%d, size=%d, pts=%lld, flag=%d",
             packet->stream_index,
             packet->size,
             packet->pts,
             packet->flags
        );
        av_packet_unref(packet);
    }

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM