0 背景介紹html
FFmpeg is a name of a free software project for the multimedia handling licensed under GNU General Public License. The most popular part of the project is ffmpeg command line tool for video and audio encoding/decoding and its main features are the high speed, quality of output and small file sizes. "FF" from FFmpeg means Fast Forward - a control button on media players, and "mpeg" is an abbreviation of the Moving Pictures Experts Group. The FFmpeg logo contains a zig-zag pattern, that is characteristic for the entropy coding scheme illustrated with 8x8 block in the picture.
調用ffmpeg能夠很是容易合併左右聲道的音頻爲立體聲好比java
ffmpeg -i 1.wav -i 2.wav -filter_complex "amovie=1.wav [l]; amovie=2.wav [r]; [l] [r] amerge" 1_2.mp3
具體細節請參考博文http://www.cnblogs.com/hdu-2010/p/5791097.html。可是每次調用命令都會頻繁切換進程,涉及OS的調度。在數據量很大,且實時性要求很高的時候,不免會浪費沒必要要的時間。因此下面介紹怎麼改造ffmpeg的源碼,使得ffmpeg常住內存,並轉換咱們的待合併文件。linux
1 ffmpeg源碼windows
ffmpeg-3.1.2的源碼解壓後的目錄結構如圖所示服務器
ffmpeg.c中main函數以下,當輸入命令行的時候,下面的main函數開始執行諸如,初始化,參數解析,合併轉換,內存釋放等步驟。本文的重點就是改造下面的main函數。ide
1 int main(int argc, char **argv) //main 2 { 3 int ret; 4 int64_t ti; 5 6 init_dynload(); 7 8 register_exit(ffmpeg_cleanup); 9 10 setvbuf(stderr,NULL,_IONBF,0); /* win32 runtime needs this */ 11 12 av_log_set_flags(AV_LOG_SKIP_REPEATED); 13 parse_loglevel(argc, argv, options); 14 15 if(argc>1 && !strcmp(argv[1], "-d")){ 16 run_as_daemon=1; 17 av_log_set_callback(log_callback_null); 18 argc--; 19 argv++; 20 } 21 22 avcodec_register_all(); 23 #if CONFIG_AVDEVICE 24 avdevice_register_all(); 25 #endif 26 avfilter_register_all(); 27 av_register_all(); 28 avformat_network_init(); 29 30 show_banner(argc, argv, options); 31 32 term_init(); 33 34 /* parse options and open all input/output files */ 35 ret = ffmpeg_parse_options(argc, argv); 36 if (ret < 0) 37 exit_program(1); 38 39 if (nb_output_files <= 0 && nb_input_files == 0) { 40 show_usage(); 41 av_log(NULL, AV_LOG_WARNING, "Use -h to get full help or, even better, run 'man %s'\n", program_name); 42 exit_program(1); 43 } 44 45 /* file converter / grab */ 46 if (nb_output_files <= 0) { 47 av_log(NULL, AV_LOG_FATAL, "At least one output file must be specified\n"); 48 exit_program(1); 49 } 50 51 // if (nb_input_files == 0) { 52 // av_log(NULL, AV_LOG_FATAL, "At least one input file must be specified\n"); 53 // exit_program(1); 54 // } 55 56 current_time = ti = getutime(); 57 if (transcode() < 0) 58 exit_program(1); 59 ti = getutime() - ti; 60 if (do_benchmark) { 61 av_log(NULL, AV_LOG_INFO, "bench: utime=%0.3fs\n", ti / 1000000.0); 62 } 63 av_log(NULL, AV_LOG_DEBUG, "%"PRIu64" frames successfully decoded, %"PRIu64" decoding errors\n", 64 decode_error_stat[0], decode_error_stat[1]); 65 if ((decode_error_stat[0] + decode_error_stat[1]) * max_error_rate < decode_error_stat[1]) 66 exit_program(69); 67 68 exit_program(received_nb_signals ? 255 : main_return_code); 69 return main_return_code; 70 }
2 編譯函數
爲了快速調試代碼,須要有以下幾點的準備工做。下面的工做是在LINUX Red Hat Enterprise Linux Server release 5.4 (Tikanga) 版本中測試的。學習
1 在Linux上安裝ffmpeg,具體安裝步驟可參看篇首提供的博文。 2 在安裝ffmpeg源碼包中,複製在執行./configure時生成的config.h文件,還有(cmdutils.h ,ffmpeg.h) 2個。
3 複製在編譯階段生成的.o 文件。主要是(ffmpeg_opt.o cmdutils.o ffmpeg_filter.o)3個。
4 新建工程目錄new_ffmpeg, 把上述複製的文件放入其中,外加ffmpeg.c。此時,一共有7個文件,可是在編譯以前須要對ffmpeg.c作些改變,不然編譯通不過。
5 編譯
6 連接
7 測試
若是須要在windows下面測試,可參考已故音頻專家雷霄驊的博客,裏面有許多有價值的可debug的工程文件。測試
3 測試this
爲了常駐內存
1 就須要對main函數中的exit_program函數改造,該函數 在register_exit(ffmpeg_cleanup)步驟, 這裏是調用了ffmpeg_cleanup函數。刪除exit_program,用ffmpeg_cleanup函數代替。 2 改造ffmpeg.c中的全局變量,防止轉換出錯。
4 靜態編譯和動態編譯
1 //hello.h 2 3 #ifndef __TEST_LIB__ 4 #define __TEST_LIB__ 5 6 void hello(const char *name); 7 #endif 8 9 //hello.c 10 11 #include <stdio.h> 12 13 void hello(const char *name) 14 { 15 printf("hello %s\n", name); 16 } 17 18 //main.c 19 20 #include "hello.h" 21 22 int main() 23 { 24 hello("everyone"); 25 return 0; 26 }
4.1 靜態編譯
0 原始文件 hello.c hello.h main.c
1 $ gcc -c hello.c #生成.o文件 2 $ ar cr libmyhello.a hello.o #生成靜態文件libmyhello.a,注意庫文件的命名方式 3 $ gcc -o hello main.c -L. -lmyhello #鏈接庫文件,生成可執行的靜態文件 hello 4 $ ./hello #測試 hello everyone
4.2 動態編譯
0 原始文件 hello.c hello.h main.c 1 $gcc -c -fPIC hello.c #生成共享的.o文件 2 $gcc -shared -fPIC -o libmyhello.so hello.o #生成動態庫libmyhello.so 3 $gcc -o hello main.c -L. -lmyhello #連接動態庫 4 $./hello #測試 ./hello: error while loading shared libraries: libmyhello.so: cannot open shared object file: No such file or directory 只需把當前目錄動態庫libmyhello.so放入 /usr/local/lib下便可。 或者在第3步指定連接器的路徑,即 3 $gcc -o hello main.c -L. -lmyhello -Wl,-rpath=. #指定連接目錄 4 $./hello #測試 hello everyone
參考資料
1 ffmpeg下載 http://ffmpeg.org/releases/ffmpeg-3.1.2.tar.bz2
2 雷霄驊(leixiaohua1020)的專欄 ffmpeg.c函數結構簡單分析(畫圖) http://blog.csdn.net/leixiaohua1020/article/details/39760711
3 [總結]FFMPEG視音頻編解碼零基礎學習方法 http://blog.csdn.net/leixiaohua1020/article/details/15811977/
4 linux動態編譯和靜態編譯 http://blog.csdn.net/l_yangliu/article/details/6951005
5 java amr格式轉mp3格式(完美解決Linux下轉換0K問題)
6 ffmpeg+ffserver多媒體服務器開發入門 http://blog.csdn.net/rootusers/article/details/49822499