【Android FFMPEG 开发】FFMPEG 读取音视频流中的数据到 AVPacket ( 初始化 AVPacket 数据 | 读取 AVPacket )
文章目錄
- I . FFMPEG 獲取 AVPacket 數據前置操作
- II . FFMPEG 獲取 AVPacket 數據流程
- III . FFMPEG AVPacket 結構體
- IV . AVPacket 數據讀取流程
- V . FFMPEG 初始化 AVPacket 數據包 av_packet_alloc ( )
- VI . FFMPEG 讀取 AVPacket 數據 av_read_frame ( )
- VII . FFMPEG 獲取 AVPacket 數據流程 代碼示例
I . FFMPEG 獲取 AVPacket 數據前置操作
FFMPEG 獲取 AVPacket 數據前置操作 :
① FFMPEG 初始化 : 參考博客 【Android FFMPEG 開發】FFMPEG 初始化 ( 網絡初始化 | 打開音視頻 | 查找音視頻流 )
② FFMPEG 獲取 AVStream 音視頻流 : 參考博客 【Android FFMPEG 開發】FFMPEG 獲取 AVStream 音視頻流 ( AVFormatContext 結構體 | 獲取音視頻流信息 | 獲取音視頻流個數 | 獲取音視頻流 )
③ FFMPEG 獲取 AVCodec 編解碼器 : 參考博客 【Android FFMPEG 開發】FFMPEG 獲取編解碼器 ( 獲取編解碼參數 | 查找編解碼器 | 獲取編解碼器上下文 | 設置上下文參數 | 打開編解碼器 )
II . FFMPEG 獲取 AVPacket 數據流程
FFMPEG 獲取 AVPacket 數據流程 :
〇 前置操作 : FFMPEG 環境初始化 , 獲取 AVStream 音視頻流 , 獲取 AVCodec 編解碼器 , 然后才能進行下面的操作 ;
① 初始化 AVPacket 空數據包 : av_packet_alloc ( )
AVPacket *avPacket = av_packet_alloc();② 讀取 AVPacket 數據 : av_read_frame ( AVFormatContext *s , AVPacket *pkt )
int read_frame_result = av_read_frame(formatContext, avPacket);III . FFMPEG AVPacket 結構體
1 . AVPacket 結構體 : 該結構體用于封裝被編碼壓縮的數據 , 不能直接使用 , 需要解碼后才能進行音頻視頻播放 ;
typedef struct AVPacket {... } AVPacket;2 . AVPacket 存儲數據 : AVPacket 存放編碼后的音視頻數據的 , 獲取該數據包后 , 需要對該數據進行解碼 , 解碼后將數據存放在 AVFrame 中 ;
3 . 編碼前后數據存放 : AVPacket 是編碼后的數據 , AVFrame 是編碼前的數據 ;
IV . AVPacket 數據讀取流程
1 . 讀取音視頻流數據到 AVPacket 中 : 首先要在外部聲明 AVPacket * 結構體指針 , 并為其初始化 , 然后調用 av_read_frame ( ) 方法 , 將已經初始化好內存的 AVPacket * 結構體指針 傳給上述方法 , FFMPEG 將在 av_read_frame ( ) 方法中讀取數據 , 并存儲到堆內存中的 AVPacket 結構體中 ;
2 . AVPacket 的內存初始化和釋放 :
① AVPacket 初始化 : 調用 av_packet_alloc ( ) 方法初始化內存 ;
② AVPacket 釋放 : 調用 av_packet_free ( ) 釋放內存 ;
V . FFMPEG 初始化 AVPacket 數據包 av_packet_alloc ( )
1 . av_packet_alloc ( ) 函數原型 : 在堆內存中為 AVPacket 分配內存 , 并為 AVPacket 結構體各個字段設置默認值 ;
① 返回值 : 返回一個 AVPacket * 結構體指針 , 如果內存分配失敗 , 就會返回 NULL ;
/*** Allocate an AVPacket and set its fields to default values. The resulting* struct must be freed using av_packet_free().** @return An AVPacket filled with default values or NULL on failure.** @note this only allocates the AVPacket itself, not the data buffers. Those* must be allocated through other means such as av_new_packet.** @see av_new_packet*/ AVPacket *av_packet_alloc(void);2 . 代碼示例 :
//讀取數據包 // AVPacket 存放編碼后的音視頻數據的 , 獲取該數據包后 , 需要對該數據進行解碼 , 解碼后將數據存放在 AVFrame 中 // AVPacket 是編碼后的數據 , AVFrame 是編碼前的數據 //創建 AVPacket 空數據包 AVPacket *avPacket = av_packet_alloc();VI . FFMPEG 讀取 AVPacket 數據 av_read_frame ( )
1 . av_read_frame ( ) 函數原型 : 獲取音視頻流的下一幀數據 ;
① AVFormatContext *s 參數 : 該參數中存儲了音視頻流格式相關信息 , 該參數是在之前使用 avformat_find_stream_info ( ) 方法獲取的 ;
② AVPacket *pkt 參數 : 傳入該結構體指針 , 在方法中會按照 AVFormatContext *s 信息讀取一幀音視頻數據 , 并將該數據存儲到 AVPacket 結構體中 ;
③ int 返回值 : 返回 0 代表讀取一幀數據 ( 音頻 / 視頻 ) 成功 , < 0 說明獲取數據失敗 ;
/*** Return the next frame of a stream.* This function returns what is stored in the file, and does not validate* that what is there are valid frames for the decoder. It will split what is* stored in the file into frames and return one for each call. It will not* omit invalid data between valid frames so as to give the decoder the maximum* information possible for decoding.** If pkt->buf is NULL, then the packet is valid until the next* av_read_frame() or until avformat_close_input(). Otherwise the packet* is valid indefinitely. In both cases the packet must be freed with* av_packet_unref when it is no longer needed. For video, the packet contains* exactly one frame. For audio, it contains an integer number of frames if each* frame has a known fixed size (e.g. PCM or ADPCM data). If the audio frames* have a variable size (e.g. MPEG audio), then it contains one frame.** pkt->pts, pkt->dts and pkt->duration are always set to correct* values in AVStream.time_base units (and guessed if the format cannot* provide them). pkt->pts can be AV_NOPTS_VALUE if the video format* has B-frames, so it is better to rely on pkt->dts if you do not* decompress the payload.** @return 0 if OK, < 0 on error or end of file*/ int av_read_frame(AVFormatContext *s, AVPacket *pkt);2 . FFMPEG 讀取 AVPacket 數據 代碼示例 :
/*讀取數據包 , 并存儲到 AVPacket 數據包中參數分析 : 一維指針 與 二維指針 參數分析① 注意 : 第二個參數是 AVPacket * 類型的 , 那么傳入 AVPacket *avPacket 變量不能修改 avPacket 指針的指向 , 即該指針指向的結構體不能改變只能修改 avPacket 指向的結構體中的元素的值因此 , 傳入的 avPacket 結構體指針必須先進行初始化 , 然后再傳入av_read_frame 函數內 , 沒有修改 AVPacket *avPacket 的值 , 但是修改了結構體中元素的值② 與此相對應的是 avformat_open_input 方法 , 傳入 AVFormatContext ** 二維指針傳入的的 AVFormatContext ** 是沒有經過初始化的 , 連內存都沒有分配在 avformat_open_input 方法中創建并初始化 AVFormatContext * 結構體指針然后將該指針地址賦值給 AVFormatContext **avformat_open_input 函數內修改了 AVFormatContext ** 參數的值返回值 0 說明讀取成功 , 小于 0 說明讀取失敗 , 或者 讀取完畢*/ int read_frame_result = av_read_frame(formatContext, avPacket);VII . FFMPEG 獲取 AVPacket 數據流程 代碼示例
//讀取數據包 // AVPacket 存放編碼后的音視頻數據的 , 獲取該數據包后 , 需要對該數據進行解碼 , 解碼后將數據存放在 AVFrame 中 // AVPacket 是編碼后的數據 , AVFrame 是編碼前的數據 //創建 AVPacket 空數據包 AVPacket *avPacket = av_packet_alloc(); /*讀取數據包 , 并存儲到 AVPacket 數據包中參數分析 : 一維指針 與 二維指針 參數分析① 注意 : 第二個參數是 AVPacket * 類型的 , 那么傳入 AVPacket *avPacket 變量不能修改 avPacket 指針的指向 , 即該指針指向的結構體不能改變只能修改 avPacket 指向的結構體中的元素的值因此 , 傳入的 avPacket 結構體指針必須先進行初始化 , 然后再傳入av_read_frame 函數內 , 沒有修改 AVPacket *avPacket 的值 , 但是修改了結構體中元素的值② 與此相對應的是 avformat_open_input 方法 , 傳入 AVFormatContext ** 二維指針傳入的的 AVFormatContext ** 是沒有經過初始化的 , 連內存都沒有分配在 avformat_open_input 方法中創建并初始化 AVFormatContext * 結構體指針然后將該指針地址賦值給 AVFormatContext **avformat_open_input 函數內修改了 AVFormatContext ** 參數的值返回值 0 說明讀取成功 , 小于 0 說明讀取失敗 , 或者 讀取完畢*/ int read_frame_result = av_read_frame(formatContext, avPacket);
總結
以上是生活随笔為你收集整理的【Android FFMPEG 开发】FFMPEG 读取音视频流中的数据到 AVPacket ( 初始化 AVPacket 数据 | 读取 AVPacket )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【C++】函数 指针类型参数 与 引用类
- 下一篇: 【Android 应用开发】Canvas