iOS 运用 ffmpeg 实现视频直播 (DZB item)
iOS 如何运用 ffmpeg 实现直播技术.
说明,本文主要介绍如何运用 ffmpeg
视频直播的大概流程:
1.直播设备端(推流):从摄像头获取视频流,然后使用 rtmp 服务提交到服务器.
2.服务器端:接收直播人提交的 rtmp 视频流,并为观看者提供 rtmp 源.
3.观看者(拉流):用播放器播放 rtmp 的视频源.
ps:RTMP(Real Time Messaging Protocol) 实时消息传输协议.该协议基于 TCP, 是一个协议族
前期准备:
新建一个项目,将所有需要引入的 ffmpeg 的静态库以及其他相关库引入到工程中,配置头文件搜索路径. ffmpeg 最新版本的应该是2.1的,历史版本详见http://www.ffmpeg.org/releases/,在这个网站上我们可以下到所有历史版本的库. ffmpeg 是一个跨平台的用 C 语言写成的库,包含了编码,解码,色彩空间装换等库.编译需要用到命令行,对于我们这些没搞过后台或者 Linux 开发的脚本知识欠缺的人来说的确是一个挑战.大家就各种百度 Google, 可以看下这个脚本, https://gist.github.com/m1entus/6983547 是一个老外写的,运行这个脚本需要依赖一个库 Perl 写的脚本,搜了一下网上目前编译 FFmpeg 库的帖子基本都会提到这个脚本,地址如下:https://github.com/mansr/gas-preprocessor
下载完这两个脚本后,编译 ffmpeg 库的准备工作就基本完成了,接着依次执行下面几步:
1.拷贝gas-preprocessor.pl文件到 /usr/bin目录下。(不能拷贝的把权限打开)
2.修改gas-preprocessor.pl文件的权限 要有读写的操作
3.切换build-ffmpeg.sh脚本的目录下,使用命令
sh build-ffmpeg.sh 运行该脚本即可。
注意: 1) build-ffmpeg.sh脚本的父目录的名字不能包括空格,否则可能导致构建失败。
2) build-ffmpeg.sh脚本中可以配置编译的FFMpeg版本,以及使用iOS SDK的版本
该脚本中默认采用的FFmpeg是2.0版本的.使用 iOS7.0的 SDK 编译, C语言编译器采用clang, 应用中可以根据时间项目需要选中不同的 FFmpeg 和 iOS SDK 版本
根据上面的步骤来看,编译工作也没有什么复杂的.
编译完成后,为了后期的使用,需要将这些 C 文件添加到项目:
cmdutils_common_opts.h
cmdutils.h及cmdutils.c
config.h在scratch目录下取个对应平台的
ffmpeg_filter.c
ffmpeg_opt.c
ffmpeg_videotoolbox.c
ffmpeg.h及ffmpeg.c
除了config.h文件外,别的文件均在ffmpeg-3.0源码目录中
注意:1.此时编译的话会报错,因为 ffmpeg.c 文件中包含 main 函数,将该函数重民命为 ffmpeg_main 并在 ffmpeg.h 中添加 ffmpeg_main 函数的声明
2.ffmpeg 任务完成后会结束进程,而 iOS 设备都是单进程多线程任务,所以需要将 cmdutils.c 文件中的 exit_program 方法中的 exit(ret).改为结束线程,需要引入#include pthread_exit(null)
直播端:用 FFmepg 库抓取直播人设备的摄像头信息
使用 libavdevice 库可以代开获取摄像头的输入流,在 ffmpeg 中获取摄像头的输入流跟打开文件输入流很类似,示例代码如下:
//打开一个文件夹
AVFormatContext*pFormatCtx =avformat_alloc_context();
avformat_open_input(&pFormatCtx,"test.h264",NULL,NULL);
//获取摄像头输入
AVFormatContext*pFormatCtx =avformat_alloc_context();
//查找输入设备
AVInputFormat*ifmt=av_find_input_format("vfwcap");
//选取 vfwcap类型的第一个输入设备作为输入流
avformat_open_input(&pFormatCtx,0, ifmt,NULL);
如何使用 RTMP 上传视频流
使用 ffmpeg.c 中的 ffmpeg_main 方法直接运行该指令即可,示例代码: NSString*command =@"ffmpeg -re -i temp.h264 -vcodec copy -f flv rtmp://xxx/xxx/livestream";
//根据空格将指令分割为指令数组
NSArray*argv_array=[command_strcomponentsSeparatedByString:(@" ")];
//将 OC 对象转换为对应的 C 对象
intargc=(int)argv_array.count;
char** argv=(char**)malloc(sizeof(char*)*argc);
for(inti=0;i
{
argv[i]=(char*)malloc(sizeof(char)*1024);
strcpy(argv[i],[[argv_arrayobjectAtIndex:i]UTF8String]);
}
//传入指令数及指令数组
ffmpeg_main
//线程杀死,下面的代码不会执行
ffmpeg -re -itemp.h264 -vcodec copy -f flvrtmp://xxx/xxx/livestream 这行代码 -re 参数是按照帧率发送,否则ffmpeg会按最高速率发送,那么视频速率会忽快忽慢 -itemp.h264是需要上传的裸 h264流
服务端:这个需要后台的技术,原谅我前台不懂,大概就是采集视频后进行编码,再返回到服务器.
播放端:播放端实际上就是一个播放器,很多直播软件播放端和客户端都是同一个软件,所以使用项目中的 ffmpeg 进行播放简单粗暴又省事.
在 Github 上有个基于 ffmpeg 的第三方播放器Kxmovie,直接用就好. 地址:GitHub - kolyvan/kxmovie: movie player for iOS using ffmpeg.用法看它的 Readme.