在iOS中使用FFmpeg命令及编码

    • 摘要:简介FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案,包括了领先的音、视频编码库libavcodec等。ffmpeg.logo以下是各个模块功能简要说明:libavformat:用于各种音视频封装格式的生成和解析;libavcodec:用于各种类型声音、图像编解码;libavutil:包含一些公共的工具函数;libswscale:用于视频场景比例缩放、色彩映射转换; 

    • 简介 

      FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案,包括了领先的音、视频编码库libavcodec等。


      在iOS中使用FFmpeg命令_IOS 
      ffmpeg.logo 

      以下是各个模块功能简要说明:


      libavformat:用于各种音视频封装格式的生成和解析;
      libavcodec:用于各种类型声音、图像编解码;
      libavutil:包含一些公共的工具函数;
      libswscale:用于视频场景比例缩放、色彩映射转换;
      libpostproc:用于后期效果处理;
      ffmpeg:该项目提供的一个工具,可用于格式转换、解码或电视卡即时编码等;
      ffsever:一个 HTTP 多媒体即时广播串流服务器;
      ffplay:是一个简单的播放器,使用ffmpeg 库解析和解码,通过SDL显示;


      实现功能 

      代码地址 https://github.com/QinminiOS/FFmpeg/


      图片、声音合成视频。 
      视频编码转换。 
      视频加水印。 
      视频滤镜。 
      库文件编译 
      1、编译编解码库文件 

      由于FFmpeg库文件编译的难度比较大,因此我这里主要使用了github开源的脚本文件去编译。脚本地址: FFmpeg-iOS-build-script 这个脚本更新很及时,已经支持3.0以上的版本了。这里我使用的是FFmpeg3.0的版本。因此修改了shell脚本的ffmpeg版本:


      SOURCE="ffmpeg-3.0" 

      修改好后执行命令:


      sh build-ffmpeg.sh 

      脚本则会自动从github中把ffmpeg源码下到本地并开始编译,编译好后在当前目录生成了FFmpeg-iOS文件夹。


      注意:


      在scratch目录每个架构都有一个配置文件 config.h 这个文件比较重要。它表示当前编译的库文件的配置参数。比如:开启了哪些解码器、编码器。


      在iOS中使用FFmpeg命令_IOS 
      配置文件 
      2、编译命令行支持库文件 

      当库文件编译好后,我们可以看到在当前目录生成了FFmpeg-iOS文件夹,这个文件夹就是编译生成的通用库。


      在iOS中使用FFmpeg命令_IOS 
      库文件 

      由于我们在编译的时候使用了--disable-programs编译选项,如下所示:


      CONFIGURE_FLAGS="--enable-cross-compile --disable-debug --disable-programs --disable-doc --enable-pic" 

      因此并不会编译命令行相关的工具。因此,我们需要自己编译相关文件来支持FFmpeg命令行的解析。


      在编译命令解析相关的库文件的时候,我们主要用到了一下几个源文件


      ffmpeg_videotoolbox.c
      cmdutils.c
      ffmpeg_filter.c
      ffmpeg_opt.c
      ffmpeg.c
      ffprobe.c 

      在编译的时候我们需要修改ffmpeg.c的main函数,因为一个程序不能有两个main函数,在这里我们改成ffmpeg_main,如下所示:


      int ffmpeg_main(int argc, char **argv)
      {
      int ret;
      int64_t ti;
      register_exit(ffmpeg_cleanup);
      setvbuf(stderr,NULL,_IONBF,0); /* win32 runtime needs this */
      av_log_set_flags(AV_LOG_SKIP_REPEATED);
      parse_loglevel(argc, argv, options);
      if(argc>1 &;&; !strcmp(argv[1], "-d")){
      run_as_daemon=1;
      av_log_set_callback(log_callback_null);
      argc--;
      argv++;
      }
      //以下是省略内容
      ...

      我们还需要修改cmdutils.c中的exit_program函数,删掉函数中原来的内容, 添加 return ret;并修改函数的返回类型为int。如果不修改,在FFmpeg命令执行完成后,程序会退出。


      int exit_program(int ret);
      int exit_program(int ret)
      {
      //if (program_exit)
      // program_exit(ret);
      //exit(ret);
      return ret;

      修改完成后,我们用Xcode新建一个静态库工程,然后将上面的源文件拖入项目中。在这里需要配置头文件搜索路径,我们主要是在FFmpeg-iOS文件夹中搜索($(SRCROOT)/../FFmpeg-iOS/include)以及ffmpeg-3.0目录中搜索($(SRCROOT)/../ffmpeg-3.0)也就是源文件中搜索。之所以要在源文件中搜索,是因为编译出来的FFmpeg-iOS文件夹中并没有拷贝所有头文件,只有必要的头文件。在这里我们不需要链接之前编译的库文件,因为静态库本来就只是编译(clang -c)和打包(ar -r)的产物,并不需要链接。


      在iOS中使用FFmpeg命令_IOS 
      静态库工程 

      编译好后我们通过lipo -create 命令生成模拟器和真机架构的通用库。


      lipo -create /Users/qinmin/Library/Developer/Xcode/DerivedData/FFmpeg-cvfzxtnwpwznsfclqrttxwgczhjv/Build/Products/Debug-iphonesimulator/libFFmpeg.a /Users/qinmin/Library/Developer/Xcode/DerivedData/FFmpeg-cvfzxtnwpwznsfclqrttxwgczhjv/Build/Products/Debug-iphoneos/libFFmpeg.a -output /Users/qinmin/Desktop/libFFmpeg.a 
      使用库文件 

      1、视频切分为图片。


      extern int ffmpeg_main(int argc, char * argv[]);
      - (IBAction)sliceBtnClick:(UIButton *)sender
      {
      dispatch_async(dispatch_get_global_queue(0, 0), ^{
      char *movie = (char *)[BundlePath(@"1.mp4") UTF8String];
      char *outPic = (char *)[DocumentPath(@"%05d.jpg") UTF8String];
      char* a[] = {
      "ffmpeg",
      "-i",
      movie,
      "-r",
      "10",
      outPic
      };
      ffmpeg_main(sizeof(a)/sizeof(*a), a);
      });

      2、图片、声音合成视频。


      extern int ffmpeg_main(int argc, char * argv[]);
      - (IBAction)composeBtnClick:(UIButton *)sender
      {
      dispatch_async(dispatch_get_global_queue(0, 0), ^{
      char *outPic = (char *)[DocumentPath(@"%05d.jpg") UTF8String];
      char *movie = (char *)[DocumentPath(@"1.mp4") UTF8String];
      char* a[] = {
      "ffmpeg",
      "-i",
      outPic,
      "-vcodec",
      "mpeg4",
      movie
      };
      ffmpeg_main(sizeof(a)/sizeof(*a), a);
      });

      3、视频编码转换。


      extern int ffmpeg_main(int argc, char * argv[]);
      - (IBAction)transBtnClick:(UIButton *)sender
      {
      dispatch_async(dispatch_get_global_queue(0, 0), ^{
      char *outPic = (char *)[DocumentPath(@"out.avi") UTF8String];
      char *movie = (char *)[BundlePath(@"1.mp4") UTF8String];
      char* a[] = {
      "ffmpeg",
      "-i",
      movie,
      "-vcodec",
      "mpeg4",
      outPic
      };
      ffmpeg_main(sizeof(a)/sizeof(*a), a);
      });

      4、视频加水印


      extern int ffmpeg_main(int argc, char * argv[]);
      - (IBAction)logoBtnClick:(UIButton *)sender
      {
      dispatch_async(dispatch_get_global_queue(0, 0), ^{
      char *outPic = (char *)[DocumentPath(@"logo.mp4") UTF8String];
      char *movie = (char *)[BundlePath(@"1.mp4") UTF8String];
      char logo[1024];
      // 左上
      sprintf(logo, "movie=%s [logo]; [in][logo] overlay=30:10 [out]", [BundlePath(@"ff.jpg") UTF8String]);
      // 左下
      //sprintf(logo, "movie=%s [logo]; [in][logo] overlay=30:main_h-overlay_h-10 [out]", [BundlePath(@"ff.jpg") UTF8String]);
      // 右下
      //sprintf(logo, "movie=%s [logo]; [in][logo] overlay=main_w-overlay_w-10:main_h-overlay_h-10 [out]", [BundlePath(@"ff.jpg") UTF8String]);
      // 右上
      //sprintf(logo, "movie=%s [logo]; [in][logo] overlay=main_w-overlay_w-10:10 [out]", [BundlePath(@"ff.jpg") UTF8String]);
      char* a[] = {
      "ffmpeg",
      "-i",
      movie,
      "-vf",
      logo,
      outPic
      };
      ffmpeg_main(sizeof(a)/sizeof(*a), a);
      });

      5、视频滤镜


      extern int ffmpeg_main(int argc, char * argv[]);
      - (IBAction)filterBtnClick:(id)sender
      {
      dispatch_async(dispatch_get_global_queue(0, 0), ^{
      char *outPic = (char *)[DocumentPath(@"filter.mp4") UTF8String];
      char *movie = (char *)[BundlePath(@"1.mp4") UTF8String];
      // 画格子
      //char *filter = "drawgrid=w=iw/3:h=ih/3:t=2:aliyunzixun@xxx.com";
      // 画矩形
      char *filter = "drawbox=x=10:y=20:w=200:h=60:aliyunzixun@xxx.com";
      // 裁剪
      //char *filter = "crop=in_w/2:in_h/2:(in_w-out_w)/2+((in_w-out_w)/2)*sin(n/10):(in_h-out_h)/2 +((in_h-out_h)/2)*sin(n/7)";
      char* a[] = {
      "ffmpeg",
      "-i",
      movie,
      "-vf",
      filter,
      outPic
      };
      ffmpeg_main(sizeof(a)/sizeof(*a), a);
      });

      效果展示 
      在iOS中使用FFmpeg命令_IOS 
      切分图片.png 

      在iOS中使用FFmpeg命令_IOS 
      加水印.png 

      在iOS中使用FFmpeg命令_IOS 
      滤镜.png 
      总结 

      在移动设备上使用FFmpeg编解码、添加滤镜等操作的时候还是很费CPU的。因此,在使用的时候需要综合考虑。


      参考 

      https://ffmpeg.org/ffmpeg-filters.html#crop


      FFmpeg-iOS-build-script




    • 以上是

在iOS中使用FFmpeg命令

      的内容,更多 

命令 使用 ffmpeg iOS 

      的内容,请您使用右上方搜索功能获取相关信息。
posted @ 2018-04-10 11:14  sundaysios  阅读(1284)  评论(0)    收藏  举报