android生成预处理文件,FFmpeg:Android利用Filter进行音频数据预处理
前言
這篇文件簡單介紹下移動端Android系統(tǒng)下利用FFmpeg的Filter進(jìn)行音頻數(shù)據(jù)預(yù)處理的方法。
按照慣例先上一份源碼 AndroidFFmpegFilter。
項(xiàng)目實(shí)現(xiàn)了:
FFmepg編譯須知
由于需要用到Filter模塊,
所以在FFmpeg編譯腳本中需要開啟相關(guān)編譯選項(xiàng)。
否則會出現(xiàn) avfilter_get_by_name(filter_name) 找不到對應(yīng)的處理器。
--enable-filters
#or
--enable-filter=name #name 指定需要使用到的filter name
如果不想自己編譯,可以使用項(xiàng)目編譯好的 動態(tài)庫。
使用FFmpeg相關(guān)動態(tài)庫
接下來要將ffmpeg的動態(tài)庫鏈接到我們的工程上面。
Filter相關(guān)只需要使用到libavfilter.so、libavformat.so、libavutil.so這三個動態(tài)庫。
參考代碼如下(提供CMake實(shí)現(xiàn),Android.mk請自己轉(zhuǎn)換):
set(LIB_DIR ${PROJECT_SOURCE_DIR}/libs)
#設(shè)置ffmpeg的頭文件目錄位置
include_directories(${LIB_DIR}/include/ffmpeg)
#導(dǎo)入avfilter動態(tài)庫
add_library( avfilter
SHARED
IMPORTED )
set_target_properties( avfilter
PROPERTIES
IMPORTED_LOCATION
${LIB_DIR}/${ANDROID_ABI}/libavfilter-6.so )
#導(dǎo)入avformat動態(tài)庫
add_library( avformat
SHARED
IMPORTED )
set_target_properties( avformat
PROPERTIES
IMPORTED_LOCATION
${LIB_DIR}/${ANDROID_ABI}/libavformat-57.so )
#導(dǎo)入avutil動態(tài)庫
add_library( avutil
SHARED
IMPORTED )
set_target_properties( avutil
PROPERTIES
IMPORTED_LOCATION
${LIB_DIR}/${ANDROID_ABI}/libavutil-55.so )
#連接動態(tài)庫
target_link_libraries(
your-lib
avfilter
avutil
avformat
)
FFmpeg Filter初始化流程
導(dǎo)入頭文件
extern "C" {
#include
#include
#include
};
注冊相關(guān)filter
avfilter_register_all();
獲取一個AVFilterGraph
利用這個Graph可以對后續(xù)的AVFilter進(jìn)行管理。
AVFilterGraph *graph = avfilter_graph_alloc();
對于AVFilter的處理
一般步驟都是:
1、通過filter_name獲取到需要使用的AVFilter。
AVFilter filter = avfilter_get_by_name(filter_name);
2、利用AVFilter從AVFilterGraph獲取到相應(yīng)的上下文環(huán)境。
AVFilterContext filter_ctx = avfilter_graph_alloc_filter(graph, filter, NULL);
3、構(gòu)造初始化參數(shù)配置(多種方式)
方式一
char options_str[1024];
snprintf(options_str, sizeof(options_str),
"sample_fmt=%s:sample_rate=%d:channel_layout=0x%" PRIx64 ,
av_get_sample_fmt_name(sample_format),
sample_rate,
sample_channel);
avfilter_init_str(filter_ctx, options_str);
方式二
char ch_layout[64];
av_get_channel_layout_string(ch_layout, sizeof(ch_layout), 0, sample_channel);
av_opt_set(filter_ctx, "channel_layout", ch_layout, AV_OPT_SEARCH_CHILDREN);
av_opt_set(filter_ctx, "sample_fmt", av_get_sample_fmt_name(sample_format), AV_OPT_SEARCH_CHILDREN);
av_opt_set_int(filter_ctx, "sample_rate", sample_rate, AV_OPT_SEARCH_CHILDREN);
avfilter_init_str(filter_ctx, NULL);
方式三
AVDictionary *options_dict = NULL;
char ch_layout[64];
av_get_channel_layout_string(ch_layout, sizeof(ch_layout), 0, sample_channel);
av_dict_set(&options_dict, "channel_layout", ch_layout, AV_OPT_SEARCH_CHILDREN);
av_dict_set(&options_dict, "sample_fmt", av_get_sample_fmt_name(sample_format), AV_OPT_SEARCH_CHILDREN);
av_dict_set(&options_dict, "sample_rate", sample_rate, AV_OPT_SEARCH_CHILDREN);
avfilter_init_dict(volume_ctx, &options_dict);
PS:以上三種方式的實(shí)現(xiàn)效果是一致的。
對各個Filter進(jìn)行鏈接
連接情況一(例如音量調(diào)節(jié)):
//abuffersrc_ctx -> volume_ctx -> abuffersink_ctx
avfilter_link(abuffersrc_ctx, 0, volume_ctx, 0);
avfilter_link(volume_ctx, 0, abuffersink_ctx, 0);
連接情況二 (例如混音):
//abuffersrc1_ctx
// -> amix_ctx -> abuffersink_ctx
//abuffersrc2_ctx
avfilter_link(abuffersrc1_ctx, 0, amix_ctx, 0);
avfilter_link(abuffersrc2_ctx, 0, amix_ctx, 1);
avfilter_link(amix_ctx, 0, abuffersink_ctx, 0);
初始化整個filters鏈
avfilter_graph_config(graph, NULL);
以上的流程就是整個FFmpeg Filter的初始化過程。
FFmpeg Filter使用流程
源音頻數(shù)據(jù)輸入
1、構(gòu)造一個AVFrame:
//獲取一個AVFrame實(shí)例
AVFrame *avframe = av_frame_alloc();
//配置輸入音頻的格式、采樣率、聲道和采樣數(shù)
avframe->sample_rate = sample_rate;
avframe->format = sample_format;
avframe->channel_layout = sample_channel;
avframe->nb_samples = nb_sample;
//根據(jù)上面設(shè)置的情況,申請音頻數(shù)據(jù)緩沖區(qū)
av_frame_get_buffer(avframe, 1);
2、將源音頻輸入送入Filter鏈中:
av_buffersrc_add_frame(abuffersrc_ctx, avframe);
3、銷毀AVFrame相關(guān)資源
av_frame_free(&avframe);
處理后音頻數(shù)據(jù)輸出
1、申請一個AVFrame實(shí)例,值得提醒的是我們不需要對這個AVFrame做任何配置
AVFrame *avframe = av_frame_alloc();
2、從Filters鏈中獲取處理后的數(shù)據(jù)包
av_buffersink_get_frame(abuffersink_ctx, avframe);
3、提取完畢AVFrame的數(shù)據(jù)后,我們需要將其銷毀
av_frame_free(&avframe);
最后說幾句
對于FFmpeg Filter的使用,基本都是遵循上述流程。
注冊Filters
獲取一個AVFilterGraph
獲取多個AVFilter和AVFilterContext并進(jìn)行參數(shù)配置
連接各個AVFilterContext
初始化整個Filters鏈
將源數(shù)據(jù)AVFrame輸入Filters鏈接收端
從Filters鏈輸出端獲取處理后數(shù)據(jù)AVFrame
對于音量調(diào)節(jié),我們需要獲取如下幾個filter:
abuffer:提供了音頻數(shù)據(jù)的輸入端。
volume:提供了音頻數(shù)據(jù)音量調(diào)節(jié)的模塊。
aformat:提供了轉(zhuǎn)換成我們期望輸出格式的模塊,是因?yàn)镚raph會在abuffer和volume之間自動做了格式轉(zhuǎn)換。
abuffersink:提供了音頻數(shù)據(jù)的輸出端。
對于混音,我們需要獲取如下幾個filter:
abuffer:提供了音頻數(shù)據(jù)的輸入端,我們需要獲取兩個,因?yàn)橛袃陕份斎搿?/p>
amix:提供了多路音頻數(shù)據(jù)混合的模塊。
aformat:提供了轉(zhuǎn)換成我們期望輸出格式的模塊,是因?yàn)镚raph會在abuffer和amix之間自動做了格式轉(zhuǎn)換。
abuffersink:提供了音頻數(shù)據(jù)的輸出端。
播放PCM文件可以利用Audacity這個工具可以導(dǎo)入pcm原始文件,并且提供了波形圖查看和播放功能。
本文同步發(fā)布于簡書、CSDN。
End!
總結(jié)
以上是生活随笔為你收集整理的android生成预处理文件,FFmpeg:Android利用Filter进行音频数据预处理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 华为鸿蒙测试结果,华为鸿蒙OS系统测试结
- 下一篇: android中变量作用域,在 Andr