• 学习改造源码


    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

     

  • 相关阅读:
    浏览器渲染页面
    递归求1-100之和
    border属性
    ES6 Class
    数组去重
    get、post请求
    对象冒充继承
    原型链继承
    实现JS数据拷贝
    【转】centos升级curl版本
  • 原文地址:https://www.cnblogs.com/hdu-2010/p/6226252.html
Copyright © 2020-2023  润新知