学习改造源码

0 背景介绍

 

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可以非常容易合并左右声道的音频为立体声比如

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常住内存,并转换我们的待合并文件。

1 ffmpeg源码

ffmpeg-3.1.2的源码解压后的目录结构如图所示

 ffmpeg.c中main函数如下,当输入命令行的时候,下面的main函数开始执行诸如,初始化,参数解析,合并转换,内存释放等步骤。本文的重点就是改造下面的main函数。

 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'
", 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
");
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
");
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
", ti / 1000000.0);
62     }
63     av_log(NULL, AV_LOG_DEBUG, "%"PRIu64" frames successfully decoded, %"PRIu64" decoding errors
",
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 }
ffmpeg_main

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 测试

为了常驻内存

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
", 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

 

原文地址:https://www.cnblogs.com/hdu-2010/p/6226252.html