一.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); }