008-iOS编译FFmpeg、kxmovie实现视频播放
一、需要工具
1.gas-preprocessor(我们需要编译的ffmpeg所需的脚本文件,下载地址:https://github.com/libav/gas-preprocessor)
2.Yasm
3.FFmpeg-iOS-build-script(下载地址:https://github.com/kewlbear/FFmpeg-iOS-build-script)
4.kxmovie(第三方播放库,下载地址:https://github.com/applexiaohao/kxmovie)
二、编译过程
1.下载gas-preprocessor
1)下载好的gas-preprocessor解压后文件内容为:

2)将gas-preprocessor.pl文件复制粘贴到 /usr/sbin/ 目录下,若是根本就不能将这个文件复制到这个路径,我们需要换一个路径,/usr/local/bin/ 目录下
a.如果我们没有在桌面上显示硬盘,我们需要去Finder中勾选硬盘复选框

b.然后,我们还需要在终端中输入指令,显示隐藏文件夹
// 显示隐藏文件夹 defaults write com.apple.finder AppleShowAllFiles Yes && killall Finder // 不显示隐藏文件夹 defaults write com.apple.finder AppleShowAllFiles No && killall Finder
c.打开目标目录

3)然后为文件开启可执行权限,打开终端输入以下命令行:
chmod 777 /usr/sbin/gas-preprocessor.pl
或者
chmod 777 /usr/local/bin/gas-preprocessor.pl
2.下载yasm
1)在下载yasm之前,我们必须先下载Homebrew(Mac平台的一个包管理工具,提供了许多Mac下没有的Linux工具等)。打开终端,输入一下命令行:
brew
终端显示一下结果,表示已经安装Homebrew:

如果不是以上结果,则需要安装Homebrew。在终端中输入一下命令下载安装:
ruby -e “$(curl -fsSL [https://raw.githubusercontent.com/Homebrew/install/master/install](https://raw.githubusercontent.com/Homebrew/install/master/install))”
如需卸载Homebrew,打开终端输入:
brew cleanup
2)下载安装yasm
yasm是一个完全重写的 NASM 汇编。目前,它支持x86和AMD64指令集,接受NASM和气体汇编语法,产出二进制,ELF32 , ELF64 , COFF , Mach - O的( 32和64 ),RDOFF2 ,的Win32和Win64对象的格式,并生成STABS 调试信息的来源,DWARF 2 ,CodeView 8格式。
a.下载yasm
brew install yasm
如果结果显示一下情况,表示安装成功

如果已经安装,会出现一下情况:

但是也可能比较麻烦,已经安装,但是没有关联:

如果出现没有关联这个问题,那么我们不防先卸载yasm,终端输入:
brew remove yasm
结果显示如下,表示卸载成功:

然后再重新安装,终端输入:
brew install yasm
结果显示:

按照以上结果提示,终端输入:
brew link yasm
结果显示:

说明目录下/usr/local/include不是可写的,这就注意啦,我们发现,其实在当前目录下,根本就不存在include文件夹,所以必须先去创建该文件夹,终端输入:
sudo mkdir include
需要输入电脑密码,输密码时时不可见的,输完直接回车即可
然后就是需要将用户设为管理者,终端输入:
sudo chown -R $USER:admin /usr/local/include/
需要输入电脑密码,输密码时时不可见的,输完直接回车即可
再就是需要修改用户权限,终端输入:
chmod 777 /usr/local/include/
终端输入:
brew link --overwrite yasm
结果显示:

同样的问题,路径/usr/local/lib不能写,终端输入:
sudo mkdir /usr/local/lib/
终端输入:
sudo chown -R $USER:admin /usr/local/lib/
终端输入:
brew link --overwrite yasm
到这里我们的yasm关联才做好啦...
b.检测是否安装yasm,终端输入:
brew search yasm
已安装结果显示:

未安装结果显示:

3.编译FFmpeg-iOS-build-script,得到我们需要的iOS能够用的ffmpeg库
1)下载解压FFmpeg-iOS-build-script,如下文件夹内容:

2)编译脚本
a.打开脚本文件所在文件路径
cd FFmpeg-iOS-build-script文件夹路径
举个例子,我的放在桌面:
cd /Users/mac02/Desktop/FFmpeg-iOS-build-script-master
b.编译命令
./build-ffmpeg.sh
结果显示:

这个时间可能要等得比较久,等编译完成后,我们发现编译后的文件夹内容有:

4.添加FFmpeg-iOS、下载kxmovie文件到工程
1)新键一个工程

2)将FFmpeg-iOS拖到项目中
3)下载kxmovie,并且将kxmovie文件夹添加到工程中,添加完毕后的项目结构

除了这些,还需要添加一些类库:
框架:MediaPlayer、CoreAudio、 AudioToolbox、Accelerate、QuartzCore、OpenGLES
系统库:libiconv.tbd、libbz2.tbd、libz.tbd
三、总结编译中的错误
1.错误信息:'libavformat/avformat.h' file not found

方法:
错误是由于文件路径不对,需要在Build Settings -> Header Search Paths 添加文件路径:
$(PROJECT_DIR)/RTSP/FFmpeg-iOS/include
2.错误信息:

方法:
这是因为缺少VideoToolbox.framework库,添加这个库即可
3.错误信息:

方法:
此处直接按照它的提示,将 'PIX_FMT_RGB24'改变成'AV_PIX_FMT_RGB24'即可
4.错误信息:
在KxMovieDecoder.h 与KxMovieDecoder.m文件中:

方法:
由于KxMovieDecoder.h缺少头文件#import <UIKit/UIKit.h>,添加上去就好
5.因为是FFmpeg 3.0版本,所以还会出现一些其他问题:


方法:
大概的意思是说在KxMovieDecoder文件里面,有一个方法“decodeFrames: ”,在这个方法里面的"_avpicture_deinterlace"这个方法不能用,armv7结构里面没有这种方法。因此需要找到这个方法直接注释掉即可

6.错误信息:

方法:
添加系统库libbz2.1.0.tbd
7.错误信息:
关于Xcode7的一个问题:
does not contain bitcode. You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target. for architecture arm64
方法:

关于kxmovie的其他问题可以去它的论坛:kxmovie论坛
四、添加代码
#import "KxMovieViewController.h" // 导入头文件 - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; NSString *path = @"http://192.168.2.13/test/1avi.avi"; NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; // increase buffering for .wmv, it solves problem with delaying audio frames if ([path.pathExtension isEqualToString:@"wmv"]) parameters[KxMovieParameterMinBufferedDuration] = @(5.0); // disable deinterlacing for iPhone, because it's complex operation can cause stuttering if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) parameters[KxMovieParameterDisableDeinterlacing] = @(YES); KxMovieViewController *vc = [KxMovieViewController movieViewControllerWithContentPath:path parameters:parameters]; [self presentViewController:vc animated:YES completion:nil]; }
五、具体使用请参考kxmovie工程中:KxMovieExample
1.在这里我先贴出我需要使用的控制器代码
1 // ViewController.m文件 2 #import "ViewController.h" 3 #import "KxMovieViewController.h" // 导入头文件 4 5 @interface ViewController () 6 7 @end 8 9 @implementation ViewController 10 11 - (void)viewDidLoad 12 { 13 [super viewDidLoad]; 14 15 self.view.backgroundColor = [UIColor whiteColor]; 16 17 // 创建一个按钮 18 UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem]; 19 btn.frame = CGRectMake(40, 100, self.view.bounds.size.width - 40 * 2, 50); 20 [btn setTitle:@"跳转播放器" forState:UIControlStateNormal]; 21 btn.titleLabel.font = [UIFont boldSystemFontOfSize:20]; 22 btn.backgroundColor = [UIColor blackColor]; 23 btn.tintColor = [UIColor whiteColor]; 24 [btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside]; 25 [self.view addSubview:btn]; 26 } 27 28 #pragma mark - 点击事件 29 - (void)btnClick:(UIButton *)btn 30 { 31 NSString *path = @"rtsp://admin:rIPC2015@192.168.1.64/vga1"; 32 NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; 33 parameters[KxMovieParameterMinBufferedDuration] = @(5.0); 34 35 if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) 36 parameters[KxMovieParameterDisableDeinterlacing] = @(YES); 37 38 KxMovieViewController *vc = [KxMovieViewController movieViewControllerWithContentPath:path parameters:parameters]; 39 vc.view.backgroundColor = [UIColor yellowColor]; 40 [self presentViewController:vc animated:YES completion:nil]; 41 } 42 43 @end
2.遇到的问题
在播放网络摄像头实时监控视频时出现以下错误:
UDP timeout, retrying with TCP
Nonmatching transport in server reply
Could not find codec parameters for stream 0 (Video: h264): unspecified size
Consider increasing the value for the 'analyzeduration' and 'probesize' options
Couldn't find stream information
最终我们只需要将kxmovie中文件KxMovieDecoder.m中以下方法做一下修改
1 - (kxMovieError)openInput:(NSString *)path 2 { 3 AVFormatContext *formatCtx = NULL; 4 if (_interruptCallback) { 5 formatCtx = avformat_alloc_context(); 6 7 if (!formatCtx) 8 return kxMovieErrorOpenFile; 9 10 AVIOInterruptCB cb = {interrupt_callback, (__bridge void *)(self)}; 11 formatCtx->interrupt_callback = cb; 12 } 13 14 // ********** 修改的代码 ********** 15 AVDictionary* options = NULL; 16 av_dict_set(&options, "rtsp_transport", "tcp", 0); 17 if (avformat_open_input(&formatCtx, [path cStringUsingEncoding: NSASCIIStringEncoding], NULL, &options) != 0) { 18 if (formatCtx) 19 avformat_free_context(formatCtx); 20 return kxMovieErrorOpenFile; 21 } 22 // ********** 修改的代码 ********** 23 24 if (avformat_find_stream_info(formatCtx, NULL) < 0) { 25 26 avformat_close_input(&formatCtx); 27 return kxMovieErrorStreamInfoNotFound; 28 } 29 30 av_dump_format(formatCtx, 0, [path.lastPathComponent cStringUsingEncoding: NSUTF8StringEncoding], false); 31 32 _formatCtx = formatCtx; 33 return kxMovieErrorNone; 34 }

浙公网安备 33010602011771号