文章目錄
I . FFMPEG AVFrame 圖像數據幀處理 前置操作
II . FFMPEG 解碼 AVPacket 數據到 AVFrame 流程
III. FFMPEG 解碼前后的圖像格式
IV . FFMPEG 獲取 SwsContext
V . FFMPEG 初始化圖像數據存儲內存
VI . FFMPEG 初圖像格式轉換
VII . FFMPEG AVFrame 圖像格式轉換 YUV -> RGBA 代碼示例
I . FFMPEG AVFrame 圖像數據幀處理 前置操作
FFMPEG 解碼 AVPacket 數據到 AVFrame 數據前置操作 :
① FFMPEG 初始化 : 參考博客 【Android FFMPEG 開發】FFMPEG 初始化 ( 網絡初始化 | 打開音視頻 | 查找音視頻流 )
② FFMPEG 獲取 AVStream 音視頻流 : 參考博客 【Android FFMPEG 開發】FFMPEG 獲取 AVStream 音視頻流 ( AVFormatContext 結構體 | 獲取音視頻流信息 | 獲取音視頻流個數 | 獲取音視頻流 )
③ FFMPEG 獲取 AVCodec 編解碼器 : 參考博客 【Android FFMPEG 開發】FFMPEG 獲取編解碼器 ( 獲取編解碼參數 | 查找編解碼器 | 獲取編解碼器上下文 | 設置上下文參數 | 打開編解碼器 )
④ FFMPEG 讀取音視頻流中的數據到 AVPacket : 參考博客 【Android FFMPEG 開發】FFMPEG 讀取音視頻流中的數據到 AVPacket ( 初始化 AVPacket 數據 | 讀取 AVPacket )
⑤ FFMPEG 解碼 AVPacket 數據到 AVFrame : 參考博客 【Android FFMPEG 開發】FFMPEG 解碼 AVPacket 數據到 AVFrame ( AVPacket->解碼器 | 初始化 AVFrame | 解碼為 AVFrame 數據 )
II . FFMPEG 解碼 AVPacket 數據到 AVFrame 流程
FFMPEG 解碼 AVPacket 數據到 AVFrame 流程 :
〇 前置操作 : FFMPEG 環境初始化 , 獲取 AVStream 音視頻流 , 獲取 AVCodec 編解碼器 , 讀取音視頻流中的數據到 AVPacket , 解碼 AVPacket 數據到 AVFrame , 然后才能進行下面的操作 ;
① 獲取 SwsContext : sws_getContext ( )
SwsContext *swsContext = sws_getContext(
//源圖像的 寬 , 高 , 圖像像素格式
avCodecContext->width, avCodecContext->height, avCodecContext->pix_fmt,
//目標圖像 大小不變 , 不進行縮放操作 , 只將像素格式設置成 RGBA 格式的
avCodecContext->width, avCodecContext->height, AV_PIX_FMT_RGBA,
//使用的轉換算法 , FFMPEG 提供了許多轉換算法 , 有快速的 , 有高質量的 , 需要自己測試
SWS_BILINEAR,
//源圖像濾鏡 , 這里傳 NULL 即可
0,
//目標圖像濾鏡 , 這里傳 NULL 即可
0,
//額外參數 , 這里傳 NULL 即可
0
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
② 初始化圖像數據存儲空間 : av_image_alloc ( )
av_image_alloc(dst_data, dst_linesize,
avCodecContext->width, avCodecContext->height, AV_PIX_FMT_RGBA,
1);
1
2
3
③ 轉換圖像格式 : sws_scale ( )
sws_scale(
//SwsContext *swsContext 轉換上下文
swsContext,
//要轉換的數據內容
avFrame->data,
//數據中每行的字節長度
avFrame->linesize,
0,
avFrame->height,
//轉換后目標圖像數據存放在這里
dst_data,
//轉換后的目標圖像行數
dst_linesize
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
III. FFMPEG 解碼前后的圖像格式
AVPacket 數據解碼后的數據存儲在 AVFrame 結構體中 , 如果是視頻數據 , 那么存儲的是一幀圖像 , 圖像的像素格式是 YUV 格式的 , 一般 Android 中繪制需要使用 ARGB 的像素格式 , 這里需要將圖像的存儲格式由 YUV 格式轉為 ARGB 格式 ;
IV . FFMPEG 獲取 SwsContext
1 . SwsContext 結構體 : 轉換圖像格式 , 首先要獲取 SwsContext 結構體指針 , 在該 SwsContext 結構體中封裝了圖像轉換相關的參數信息 , 如 源圖像 目標圖像的寬高 , 像素格式信息等 ; 調用 sws_getContext ( ) 方法可以獲取 SwsContext * 結構體指針 ;
2 . SwsContext ( ) 函數原型 : 為 SwsContext 結構體分配內存 , 並返回其結構體指針 ;
① int srcW 參數 : 源圖像的寬度 ;
② int srcH 參數 : 源圖像的高度 ;
③ enum AVPixelFormat srcFormat 參數 : 源圖像的像素格式 ;
④ int dstW 參數 : 目標圖像的寬度 ;
⑤ int dstH 參數 : 目標圖像的高度 ;
⑥ enum AVPixelFormat dstFormat 參數 : 目標圖像的像素格式 ;
⑦ int flags 參數 : 使用的轉換算法 , 可以選擇高速度 , 或者高質量等參數 ;
⑧ SwsFilter *srcFilter 參數 : 源圖像濾鏡 ;
⑨ SwsFilter *dstFilter 參數 : 目標圖像濾鏡 ;
⑩ const double *param 參數 : 額外參數 ;
/**
* Allocate and return an SwsContext. You need it to perform
* scaling/conversion operations using sws_scale().
*
* @param srcW the width of the source image
* @param srcH the height of the source image
* @param srcFormat the source image format
* @param dstW the width of the destination image
* @param dstH the height of the destination image
* @param dstFormat the destination image format
* @param flags specify which algorithm and options to use for rescaling
* @param param extra parameters to tune the used scaler
* For SWS_BICUBIC param[0] and [1] tune the shape of the basis
* function, param[0] tunes f(1) and param[1] f´(1)
* For SWS_GAUSS param[0] tunes the exponent and thus cutoff
* frequency
* For SWS_LANCZOS param[0] tunes the width of the window function
* @return a pointer to an allocated context, or NULL in case of error
* @note this function is to be removed after a saner alternative is
* written
*/
struct SwsContext *sws_getContext(int srcW, int srcH, enum AVPixelFormat srcFormat,
int dstW, int dstH, enum AVPixelFormat dstFormat,
int flags, SwsFilter *srcFilter,
SwsFilter *dstFilter, const double *param);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
3 . 獲取 SwsContext 代碼示例 :
SwsContext *swsContext = sws_getContext(
//源圖像的 寬 , 高 , 圖像像素格式
avCodecContext->width, avCodecContext->height, avCodecContext->pix_fmt,
//目標圖像 大小不變 , 不進行縮放操作 , 只將像素格式設置成 RGBA 格式的
avCodecContext->width, avCodecContext->height, AV_PIX_FMT_RGBA,
//使用的轉換算法 , FFMPEG 提供了許多轉換算法 , 有快速的 , 有高質量的 , 需要自己測試
SWS_BILINEAR,
//源圖像濾鏡 , 這里傳 NULL 即可
0,
//目標圖像濾鏡 , 這里傳 NULL 即可
0,
//額外參數 , 這里傳 NULL 即可
0
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
V . FFMPEG 初始化圖像數據存儲內存
1 . 圖像數據保存 : 需要兩個變量來進行存儲 , 一個是指針 , 指向一塊內存 , 該內存中存儲實際的圖像數據 , 一個是 int 數值 , 存儲該內存中存儲了多少數據 ;
① 指針 : 將圖像數據保存到 uint8_t *dst_data[4] 指針數組中的指針元素指向的內存中 ;
② 行數 : int dst_linesize[4] 中存儲其行數 , 代表了上面指針指向的內存每行存儲了多少數據 ;
2 . 圖像數據指針的操作 :
① 初始化 : 這個內存需要用專門的函數 av_image_alloc ( ) 進行初始化 ;
② 釋放 : 這個指針需要使用專門的函數 void av_freep(void *ptr) 進行釋放 ;
3 . av_image_alloc ( ) 函數原型 : 根據圖像的寬高 , 像素格式 , 為 相應的 指向圖像數據的指針 和 行數 進行初始化 ;
① uint8_t *pointers[4] 參數 : 指向圖像數據的指針 , 這是四個指針 , 這里只是用了一個 , 也就是第一個 ;
② int linesizes[4] 參數 : 存儲每個圖像數據存儲的數據行數 ;
③ int w 參數 : 圖像的寬度 ;
④ int h 參數 : 圖像的高度 ;
⑤ enum AVPixelFormat pix_fmt : 圖像的像素格式 , ARGB 格式的 ;
⑥ int align 參數 : 設置 1 即可 ;
/**
* Allocate an image with size w and h and pixel format pix_fmt, and
* fill pointers and linesizes accordingly.
* The allocated image buffer has to be freed by using
* av_freep(&pointers[0]).
*
* @param align the value to use for buffer size alignment
* @return the size in bytes required for the image buffer, a negative
* error code in case of failure
*/
int av_image_alloc(uint8_t *pointers[4], int linesizes[4],
int w, int h, enum AVPixelFormat pix_fmt, int align);
1
2
3
4
5
6
7
8
9
10
11
12
4 . av_image_alloc ( ) 代碼示例 :
//指針數組 , 數組中存放的是指針
uint8_t *dst_data[4];
//普通的 int 數組
int dst_linesize[4];
//初始化 dst_data 和 dst_linesize , 為其申請內存 , 注意使用完畢后需要釋放內存
av_image_alloc(dst_data, dst_linesize,
avCodecContext->width, avCodecContext->height, AV_PIX_FMT_RGBA,
1);
1
2
3
4
5
6
7
8
9
10
VI . FFMPEG 初圖像格式轉換
1 . 准備工作完畢 : 轉換使用的上下文 SwsContext , 轉換后的數據存儲 指針 和 行數 , 准備就緒后 , 可以開始轉換 AVFrame 中的 YUV 像素格式的圖像為 RGBA 像素格式 ;
2 . 轉換使用方法 : 調用 sws_scale ( ) 方法 , 執行轉換操作 ;
3 . sws_scale ( ) 函數原型 : 轉換圖像像素格式 ;
① struct SwsContext *c 參數 : 轉換上下文 ;
② const uint8_t *const srcSlice[] 參數 : 源圖像數據指針 ;
③ const int srcStride[] 參數 : 源圖像每行有多少個數據 ;
④ int srcSliceY 參數 : 源圖像數據數組處理的索引值 , 從 0 開始計數 , 一般是 0 ;
⑤ int srcSliceH 參數 : 源圖像的高度 , 即有多少行數據 ;
⑥ uint8_t *const dst[] 參數 : 圖像數組指針數組 ;
⑦ const int dstStride[] 參數 : 圖像數據每行的數據個數 ;
/**
* Scale the image slice in srcSlice and put the resulting scaled
* slice in the image in dst. A slice is a sequence of consecutive
* rows in an image.
*
* Slices have to be provided in sequential order, either in
* top-bottom or bottom-top order. If slices are provided in
* non-sequential order the behavior of the function is undefined.
*
* @param c the scaling context previously created with
* sws_getContext()
* @param srcSlice the array containing the pointers to the planes of
* the source slice
* @param srcStride the array containing the strides for each plane of
* the source image
* @param srcSliceY the position in the source image of the slice to
* process, that is the number (counted starting from
* zero) in the image of the first row of the slice
* @param srcSliceH the height of the source slice, that is the number
* of rows in the slice
* @param dst the array containing the pointers to the planes of
* the destination image
* @param dstStride the array containing the strides for each plane of
* the destination image
* @return the height of the output slice
*/
int sws_scale(struct SwsContext *c, const uint8_t *const srcSlice[],
const int srcStride[], int srcSliceY, int srcSliceH,
uint8_t *const dst[], const int dstStride[]);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
4 . sws_scale ( ) 使用示例 :
sws_scale(
//SwsContext *swsContext 轉換上下文
swsContext,
//要轉換的數據內容
avFrame->data,
//數據中每行的字節長度
avFrame->linesize,
0,
avFrame->height,
//轉換后目標圖像數據存放在這里
dst_data,
//轉換后的目標圖像行數
dst_linesize
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
VII . FFMPEG AVFrame 圖像格式轉換 YUV -> RGBA 代碼示例
//1 . 獲取轉換上下文
SwsContext *swsContext = sws_getContext(
//源圖像的 寬 , 高 , 圖像像素格式
avCodecContext->width, avCodecContext->height, avCodecContext->pix_fmt,
//目標圖像 大小不變 , 不進行縮放操作 , 只將像素格式設置成 RGBA 格式的
avCodecContext->width, avCodecContext->height, AV_PIX_FMT_RGBA,
//使用的轉換算法 , FFMPEG 提供了許多轉換算法 , 有快速的 , 有高質量的 , 需要自己測試
SWS_BILINEAR,
//源圖像濾鏡 , 這里傳 NULL 即可
0,
//目標圖像濾鏡 , 這里傳 NULL 即可
0,
//額外參數 , 這里傳 NULL 即可
0
);
//2 . 初始化圖像存儲內存
//指針數組 , 數組中存放的是指針
uint8_t *dst_data[4];
//普通的 int 數組
int dst_linesize[4];
//初始化 dst_data 和 dst_linesize , 為其申請內存 , 注意使用完畢后需要釋放內存
av_image_alloc(dst_data, dst_linesize,
avCodecContext->width, avCodecContext->height, AV_PIX_FMT_RGBA,
1);
//3 . 格式轉換
sws_scale(
//SwsContext *swsContext 轉換上下文
swsContext,
//要轉換的數據內容
avFrame->data,
//數據中每行的字節長度
avFrame->linesize,
0,
avFrame->height,
//轉換后目標圖像數據存放在這里
dst_data,
//轉換后的目標圖像行數
dst_linesize
);
from:https://blog.csdn.net/shulianghan/article/details/104772549