版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領
文檔簡介
【移動應用開發(fā)技術】怎么在android中使用FFmpeg實現(xiàn)音頻混合
怎么在android中使用FFmpeg實現(xiàn)音頻混合?針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。采用androidstudio進行開發(fā),配置build.gradle文件:defaultConfig
{
externalNativeBuild
{
cmake
{
cppFlags
""
}
}
ndk
{
abiFilters
"armeabi-v7a"
}
}另外指定cmake文件路徑:externalNativeBuild
{
cmake
{
path
"CMakeLists.txt"
}
}
sourceSets
{
main
{
jniLibs.srcDirs
=
['libs']
jni.srcDirs
=
[]
}
}從FFmpeg官網(wǎng)下載源碼,編譯成ffmpeg.so動態(tài)庫,并且導入相關源文件與頭文件:然后配置cMakeLists文件:add_library(
#
Sets
the
name
of
the
library.
audio-handle
#
Sets
the
library
as
a
shared
library.
SHARED
#
Provides
a
relative
path
to
your
source
file(s).
src/main/cpp/ffmpeg_cmd.c
src/main/cpp/cmdutils.c
src/main/cpp/ffmpeg.c
src/main/cpp/ffmpeg_filter.c
src/main/cpp/ffmpeg_opt.c)
add_library(
ffmpeg
SHARED
IMPORTED
)
set_target_properties(
ffmpeg
PROPERTIES
IMPORTED_LOCATION
../../../../libs/armeabi-v7a/libffmpeg.so
)
include_directories(src/main/cpp/include)
find_library(
log-lib
log
)
target_link_libraries(
audio-handle
ffmpeg
${log-lib}
)
調(diào)用FFmpeg命令行進行音頻處理:
/**
*
調(diào)用ffmpeg處理音頻
*
@param
handleType
handleType
*/
private
void
doHandleAudio(int
handleType){
String[]
commandLine
=
null;
switch
(handleType){
case
0://轉碼
String
transformFile
=
PATH
+
File.separator
+
"transform.aac";
commandLine
=
FFmpegUtil.transformAudio(srcFile,
transformFile);
break;
case
1://剪切
String
cutFile
=
PATH
+
File.separator
+
"cut.mp3";
commandLine
=
FFmpegUtil.cutAudio(srcFile,
10,
15,
cutFile);
break;
case
2://合并
String
concatFile
=
PATH
+
File.separator
+
"concat.mp3";
commandLine
=
FFmpegUtil.concatAudio(srcFile,
appendFile,
concatFile);
break;
case
3://混合
String
mixFile
=
PATH
+
File.separator
+
"mix.aac";
commandLine
=
FFmpegUtil.mixAudio(srcFile,
appendFile,
mixFile);
break;
default:
break;
}
executeFFmpegCmd(commandLine);
}其中,音頻混音、合并、剪切和轉碼的FFmpeg命令行的拼接如下:/**
*
使用ffmpeg命令行進行音頻轉碼
*
@param
srcFile
源文件
*
@param
targetFile
目標文件(后綴指定轉碼格式)
*
@return
轉碼后的文件
*/
public
static
String[]
transformAudio(String
srcFile,
String
targetFile){
String
transformAudioCmd
=
"ffmpeg
-i
%s
%s";
transformAudioCmd
=
String.format(transformAudioCmd,
srcFile,
targetFile);
return
transformAudioCmd.split("
");//以空格分割為字符串數(shù)組
}
/**
*
使用ffmpeg命令行進行音頻剪切
*
@param
srcFile
源文件
*
@param
startTime
剪切的開始時間(單位為秒)
*
@param
duration
剪切時長(單位為秒)
*
@param
targetFile
目標文件
*
@return
剪切后的文件
*/
@SuppressLint("DefaultLocale")
public
static
String[]
cutAudio(String
srcFile,
int
startTime,
int
duration,
String
targetFile){
String
cutAudioCmd
=
"ffmpeg
-i
%s
-ss
%d
-t
%d
%s";
cutAudioCmd
=
String.format(cutAudioCmd,
srcFile,
startTime,
duration,
targetFile);
return
cutAudioCmd.split("
");//以空格分割為字符串數(shù)組
}
/**
*
使用ffmpeg命令行進行音頻合并
*
@param
srcFile
源文件
*
@param
appendFile
待追加的文件
*
@param
targetFile
目標文件
*
@return
合并后的文件
*/
public
static
String[]
concatAudio(String
srcFile,
String
appendFile,
String
targetFile){
String
concatAudioCmd
=
"ffmpeg
-i
concat:%s|%s
-acodec
copy
%s";
concatAudioCmd
=
String.format(concatAudioCmd,
srcFile,
appendFile,
targetFile);
return
concatAudioCmd.split("
");//以空格分割為字符串數(shù)組
}
/**
*
使用ffmpeg命令行進行音頻混合
*
@param
srcFile
源文件
*
@param
mixFile
待混合文件
*
@param
targetFile
目標文件
*
@return
混合后的文件
*/
public
static
String[]
mixAudio(String
srcFile,
String
mixFile,
String
targetFile){
String
mixAudioCmd
=
"ffmpeg
-i
%s
-i
%s
-filter_complex
amix=inputs=2:duration=first
-strict
-2
%s";
mixAudioCmd
=
String.format(mixAudioCmd,
srcFile,
mixFile,
targetFile);
return
mixAudioCmd.split("
");//以空格分割為字符串數(shù)組
}FFmpeg處理混音的公式如下,其中sample1為源文件采樣率、sample2為待混合文件采樣率:混音公式:value=sample1+sample2-(sample1*sample2/(pow(2,16-1)-1))開啟子線程,調(diào)用native方法進行音頻處理:public
static
void
execute(final
String[]
commands,
final
OnHandleListener
onHandleListener){
new
Thread(new
Runnable()
{
@Override
public
void
run()
{
if(onHandleListener
!=
null){
onHandleListener.onBegin();
}
//調(diào)用ffmpeg進行處理
int
result
=
handle(commands);
if(onHandleListener
!=
null){
onHandleListener.onEnd(result);
}
}
}).start();
}
private
native
static
int
handle(String[]
commands);關鍵的native方法,是把java傳入的字符串數(shù)組轉成二級指針數(shù)組,然后調(diào)用FFmpeg源碼中的run方法:JNIEXPORT
jint
JNICALL
Java_com_frank_ffmpeg_FFmpegCmd_handle
(JNIEnv
*env,
jclass
obj,
jobjectArray
commands){
int
argc
=
(*env)->GetArrayLength(env,
commands);
char
**argv
=
(char**)malloc(argc
*
sizeof(char*));
int
i;
int
result;
for
(i
=
0;
i
<
argc;
i++)
{
jstring
jstr
=
(jstring)
(*env)->GetObjectArrayElement(env,
commands,
i);
char*
temp
=
(char*)
(*env)->GetStringUTFChars(env,
jstr,
0);
argv[i]
=
malloc(1024);
strcpy(argv[i],
temp);
(*env)->ReleaseStringUTFChars(env,
jstr,
temp);
}
//執(zhí)行ffmpeg命令
result
=
run(argc,
argv);
//釋放內(nèi)存
for
(i
=
0;
i
<
argc;
i++)
{
free(argv[i]);
}
free(argv);
return
result;
}關于FFmpeg的run方法的源碼如下,中間有部分省略:int
run(int
argc,
char
**argv)
{
/****************省略********************/
//注冊各個模塊
avcodec_register_all();
#if
CONFIG_AVDEVICE
avdevice_register_all();
#endif
avfilter_register_all();
av_register_all();
avformat_network_init();
show_banner(argc,
argv,
options);
term_init();
/****************省略********************/
//解析命令選項與打開輸入輸出文件
int
ret
=
ffmpeg_parse_options(argc,
argv);
if
(ret
<
0)
exit_program(1);
/****************省略********************/
//文件轉換
if
(transcode()
<
0)
exit_program(1);
/****************省略********************/
//退出程序操作:關閉文件、釋放內(nèi)存
exit_program(received_nb_signals
?
255
:
main_return_code);
ffmpeg_cleanup(0);
}其中,最關鍵的是文件轉換部分,源碼如下:static
int
transcode(void)
{
int
ret,
i;
AVFormatContext
*os;
OutputStream
*ost;
InputStream
*ist;
int64_t
timer_start;
int64_t
total_packets_written
=
0;
//轉碼方法初始化
ret
=
transcode_init();
if
(ret
<
0)
goto
fail;
if
(stdin_interaction)
{
av_log(NULL,
AV_LOG_INFO,
"Press
[q]
to
stop,
[?]
for
help\n");
}
timer_start
=
av_gettime_relative();
#if
HAVE_PTHREADS
if
((ret
=
init_input_threads())
<
0)
goto
fail;
#endif
//transcode循環(huán)處理
while
(!received_sigterm)
{
int64_t
cur_time=
av_gettime_relative();
//如果遇到"q"命令,則退出循環(huán)
if
(stdin_interaction)
if
(check_keyboard_interaction(cur_time)
<
0)
break;
//判斷是否還有輸出流
if
(!need_output())
{
av_log(NULL,
AV_LOG_VERBOSE,
"No
more
output
streams
to
write
to,
finishing.\n");
break;
}
ret
=
transcode_step();
if
(ret
<
0
&&
ret
!=
AVERROR_EOF)
{
char
errbuf[128];
av_strerror(ret,
errbuf,
sizeof(errbuf));
av_log(NULL,
AV_LOG_ERROR,
"Error
while
filtering:
%s\n",
errbuf);
break;
}
//打印音視頻流信息
print_report(0,
timer_start,
cur_time);
}
#if
HAVE_PTHREADS
free_input_threads();
#endif
//文件末尾最后一個stream,刷新解碼器buffer
for
(i
=
0;
i
<
nb_input_streams;
i++)
{
ist
=
input_streams[i];
if
(!input_files[ist->file_index]->eof_reached
&&
ist->decoding_needed)
{
process_input_packet(ist,
NULL,
0);
}
}
flush_encoders();
term_exit();
//寫文件尾,關閉文件
for
(i
=
0;
i
<
nb_output_files;
i++)
{
os
=
output_files[i]->ctx;
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024銅門智能鎖具配套銷售合同3篇
- 二零二五年醫(yī)療機構健康體檢服務合同4篇
- 影視作品2025年度融資保理合同3篇
- 2025年度個人醫(yī)療貸款合同電子服務4篇
- 2025年度陶瓷行業(yè)市場調(diào)研代理合同3篇
- 2025年度物流運輸合同貨物安全與損壞賠償擔保協(xié)議范本4篇
- 二零二五年社區(qū)食堂承包與便民服務合同樣本3篇
- 2025年度個人購房稅費繳納協(xié)議書4篇
- 荒山荒地二零二五年度農(nóng)業(yè)觀光旅游承包合同樣本3篇
- 二零二五版新能源電站承包經(jīng)營開發(fā)協(xié)議3篇
- PEP小學六年級英語上冊選詞填空專題訓練
- 古建筑修繕項目施工規(guī)程(試行)
- GA 844-2018防砸透明材料
- 化學元素周期表記憶與讀音 元素周期表口訣順口溜
- 非人力資源經(jīng)理的人力資源管理培訓(新版)課件
- MSDS物質(zhì)安全技術資料-201膠水
- 鉬氧化物還原過程中的物相轉變規(guī)律及其動力學機理研究
- (完整word)2019注冊消防工程師繼續(xù)教育三科試習題及答案
- 《調(diào)試件現(xiàn)場管理制度》
- 社區(qū)治理現(xiàn)代化課件
- 代持房屋協(xié)議書
評論
0/150
提交評論