iOS基于ffmpeg做出的视频直播 (一)

现在非常流行直播,相信很多人都跟我一样十分好奇这个技术是如何实现的,正好最近在做一个ffmpeg的项目,发现这个工具很容易就可以做直播,下面来给大家分享下技术要点:

首先你得编译出ffmpeg运行所需的静态库,这个百度一下有很多内容,这里我就不多说了,建议可以用Github上的一个开源脚本来编译,简单粗暴有效率。

地址:GitHub - kewlbear/FFmpeg-iOS-build-script: Shell scripts to build FFmpeg for iOS and tvOS

下载后直接用终端运行build-ffmpeg.sh脚本就行了,大概半个小时就全部编译好了…反正我觉得速度还行吧(PS:当初编译Android源码那叫一个慢啊…),若是报错就再来一遍,直到提示成功。

视频直播怎么直播呢?大概流程图如下:

1.直播人设备端:从摄像头获取视频流,然后使用rtmp服务提交到服务器

2.服务器端:接收直播人提交的rtmp视频流,并为观看者提供rtmp源

3.观看者:用播放器播放rtmp源的视频.

PS:RTMP是Real Time Messaging Protocol(实时消息传输协议)的首字母缩写。该协议基于TCP,是一个协议族,包括RTMP基本协议及RTMPT/RTMPS/RTMPE等多种变种。

前期准备:

新建一个项目,将所有需要引入的ffmpeg的静态库及其他相关库引入到工程中,配置头文件搜索路径,这一步网上有很多教程就不重复叙述了。

我是用上面脚本编译的最新版,为了后期使用,需要将这些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);

直播端:用ffmpeg库抓取直播人设备的摄像头信息,生成裸数据流stream,注意!!!这里是裸流,裸流意味着什么呢?就是不包含PTS(Presentation Time Stamp。PTS主要用于度量解码后的视频帧什么时候被显示出来)、DTS(Decode Time Stamp。DTS主要是标识读入内存中的bit流在什么时候开始送入解码器中进行解码)等信息的数据流,播放器拿到这种流是无法进行播放的.将这个客户端只需要将这个数据流以RTMP协议传到服务器即可。

如何获取摄像头信息:

使用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上传视频流:

使用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(argc,argv);

//线程已杀死,下方的代码不会执行

ffmpeg -re -itemp.h264 -vcodec copy -f flvrtmp://xxx/xxx/livestream

这行代码就是

-re参数是按照帧率发送,否则ffmpeg会按最高速率发送,那么视频会忽快忽慢,

-itemp.h264是需要上传的裸h264流

-vcoder copy 这段是复制一份不改变源

-f flvrtmp://xxx/xxx/livestream是指定格式为flv发送到这个url

这里看到输入是裸流或者是文件,但是我们从摄像头获取到的是直接内存流,这怎么解决呢?

当然是有办法的啦

1.将这串参数中temp.h264参数变为null

2.初始化自定义的AVIOContext,指定自定义的回调函数。示例代码如下:

//AVIOContext中的缓存

unsignedchar*aviobuffer=(unsignedchar*)av_malloc(32768);

AVIOContext*avio=avio_alloc_context(aviobuffer,32768,0,NULL,read_buffer,NULL,NULL);

pFormatCtx->pb=avio;

if(avformat_open_input(&pFormatCtx,NULL,NULL,NULL)!=0){

printf("Couldn‘t open inputstream.(无法打开输入流)\n");

return-1;

}

3. 自己写回调函数,从输入源中取数据。示例代码如下:

//Callback

intread_buffer(void*opaque, uint8_t *buf,intbuf_size){

//休眠,否则会一次性全部发送完

if(pkt.stream_index==videoindex){

AVRational time_base=ifmt_ctx->streams[videoindex]->time_base;

AVRational time_base_q={1,AV_TIME_BASE};

int64_t pts_time = av_rescale_q(pkt.dts, time_base, time_base_q);

int64_t now_time = av_gettime() - start_time;

if(pts_time > now_time)

av_usleep(pts_time - now_time);

}

//fp_open替换为摄像头输入流

if(!feof(fp_open)){

inttrue_size=fread(buf,1,buf_size,fp_open);

returntrue_size;

}else{

return-1;

}

}

服务端:原谅我一个移动开发不懂服务器端,大概应该是获取直播端上传的视频流再进行广播.所以就略过吧.

播放端:播放端实际上就是一个播放器,可以有很多解决方案,这里提供一种最简单的,因为很多直播软件播放端和客户端都是同一个软件,所以这里直接使用项目中已经有的ffmpeg进行播放简单粗暴又省事.

在Github上有个基于ffmpeg的第三方播放器kxmovie,直接用这个就好.

地址:GitHub - kolyvan/kxmovie: movie player for iOS using ffmpeg

当你把kxmovie的播放器部分添加到之前做好的上传部分,你会发现报错了......

查找的结果是kxmovie所使用的avpicture_deinterlace方法不存在,我第一个想法就是想办法屏蔽到这个方法,让程序能正常使用,结果......当然不能正常播放视频了,一百度才发现这个方法居然是去交错,虽然我视频只是不够丰富,但是也知道这个方法肯定是不能少的.

没事,只有改源码了.从ffmpeg官方源码库中可以找到这个方法.

地址:ffmpeg.org/doxygen/1.0/imgconvert_8c-source.html#l00940

发现这个方法在之前的实现中是在avcodec.h中声明是AVPicture的方法,然后在avpicture.c中再调用libavcodec/imgconvert.c这个文件中,也就是说这个方法本身就是属于imgconvert.c的,avpicture.c只是间接调用,查找ffmpeg3.0的imgconvert.c文件,居然没这个方法,但是官方代码库中是有这个方法的,难道是已经移除了?移除不移除关我毛事,我只想能用,所以简单点直接改avpicture.c

首先添加这几个宏定义

#define deinterlace_line_inplace deinterlace_line_inplace_c

#define deinterlace_line         deinterlace_line_c

#define ff_cropTbl ((uint8_t *)NULL)

然后从网页上复制这几个方法到avpicture.c文件中

static void deinterlace_line_c

static void deinterlace_line_inplace_c

static void deinterlace_bottom_field

static void deinterlace_bottom_field_inplace

int avpicture_deinterlace

再在avcodec.h头文件中,avpicture_alloc方法下面添加声明:

attribute_deprecated

intavpicture_deinterlace(AVPicture*dst,constAVPicture*src,

enumAVPixelFormatpix_fmt,intwidth,intheight);

保存后再用终端执行build-ffmpeg.sh脚本编译一次就行了…再次导入项目中kxmovie就不会报错了,播放视频的代码如下:

KxMovieViewController*vc = [KxMovieViewControllermovieViewControllerWithContentPath:pathparameters:nil];

[selfpresentViewController:vcanimated:YEScompletion:nil];

注:其中path可以是以http/rtmp/trsp开始的url

摘自:这里

时间: 2024-08-06 16:00:56

iOS基于ffmpeg做出的视频直播 (一)的相关文章

iOS开发之集成ijkplayer视频直播

ijkplayer 是一款做视频直播的框架, 基于ffmpeg, 支持 Android 和 iOS, 网上也有很多集成说明, 但是个人觉得还是不够详细, 在这里详细的讲一下在 iOS 中如何集成ijkplayer, 即便以前从没有接触过, 按着下面做也可以集成成功! 编辑:Bison 投稿: jianshu_wl 一. 下载ijkplayer ijkplayer下载地址 下载完成后解压, 解压后文件夹内部目录如下图: 二. 编译 ijkplayer 说是编译 ijkplayer, 其实是编译 f

iOS基于FFmpeg之配置FFmpeg框架(二)

本文出自:这里 摘自http://blog.sina.com.cn/s/blog_47522f7f0102vbwp.html,按步骤实践可行.感谢! 1. FFMPEG层次结构的简单理解 要使用FFMPEG,首先需要理解FFMPEG的代码结构.根据志哥的提示,ffmpeg的代码是包括两部分的,一部分是library,一部分是tool.api都是在library里面,如果直接调api来操作视频的话,就需要写c或者c++了.另一部分是tool,使用的是命令行,则不需要自己去编码来实现视频操作的流程.

iOS基于Ffmpeg资料(四)

一.编译针对iOS平台的ffmpeg库(kxmovie) 近期有一个项目,需要播放各种格式的音频.视频以及网络摄像头实时监控的视频流数据,经过多种折腾之后,最后选择了kxmovie,kxmovie项目已经整合了ffmpeg和简单的播放器,具体可以参考kxmovie主页:https://github.com/kolyvan/kxmovie 编译kxmovie很简单,已经支持iOS 6.1 和 armv7s,一次成功,编译过程没出现什么问题: git clone git://github.com/k

iOS平台基于ffmpeg的视频直播技术揭秘

现在非常流行直播,相信很多人都跟我一样十分好奇这个技术是如何实现的,正好最近在做一个ffmpeg的项目,发现这个工具很容易就可以做直播,下面来给大家分享下技术要点: 首先你得编译出ffmpeg运行所需的静态库,这个百度一下有很多内容,这里我就不多说了,建议可以用Github上的一个开源脚本来编译,简单粗暴有效率. 地址:GitHub - kewlbear/FFmpeg-iOS-build-script: Shell scripts to build FFmpeg for iOS and tvOS

最简单的基于FFmpeg的移动端例子:IOS 视频解码器

本文记录IOS平台下基于FFmpeg的视频解码器.该示例C语言的源代码来自于<最简单的基于FFMPEG+SDL的视频播放器>.相关的概念就不再重复记录了. 源代码 项目的目录结构如图所示. C代码位于ViewController.m文件中,内容如下所示. /** * 最简单的基于FFmpeg的视频解码器-IOS * Simplest FFmpeg IOS Decoder * * 雷霄骅 Lei Xiaohua * [email protected] * 中国传媒大学/数字电视技术 * Comm

最简单的基于FFmpeg的移动端样例:IOS 视频转码器

===================================================== 最简单的基于FFmpeg的移动端样例系列文章列表: 最简单的基于FFmpeg的移动端样例:Android HelloWorld 最简单的基于FFmpeg的移动端样例:Android 视频解码器 最简单的基于FFmpeg的移动端样例:Android 视频解码器-单个库版 最简单的基于FFmpeg的移动端样例:Android 推流器 最简单的基于FFmpeg的移动端样例:Android 视频转

最简单的基于FFmpeg的移动端样例:IOS 视频解码器

===================================================== 最简单的基于FFmpeg的移动端样例系列文章列表: 最简单的基于FFmpeg的移动端样例:Android HelloWorld 最简单的基于FFmpeg的移动端样例:Android 视频解码器 最简单的基于FFmpeg的移动端样例:Android 视频解码器-单个库版 最简单的基于FFmpeg的移动端样例:Android 推流器 最简单的基于FFmpeg的移动端样例:Android 视频转

最简单的基于FFmpeg的移动端例子:IOS 视频转码器

本文记录iOS平台下基于FFmpeg的视频转码器.该转码器实际上移植自ffmpeg工程中的ffmpeg.c源代码.有关ffmpeg.c的源代码可以参考文章<ffmpeg.c函数结构简单分析(画图)>,在这里就不重复记录了. 源代码 项目的目录结构如图所示. 下列C语言文件拷贝自FFmpeg源代码: cmdutils.ccmdutils.hcmdutils_common_opts.hconfig.hffmpeg.hffmpeg_filter.cffmpeg_opt.c 此外在编译ffmpeg.c

IOS 视频直播/智能家居(一行行敲代码,从零开始)lesson:1整体架构

前段时间由于工作需要做了一个视频直播/智能家居类的应用.算是对iOS音视频专栏中流媒体处理做了一次小结.这里想把整个开发流程纪录下来,一方面是和大家共同探讨学习,另一方面也可以方便自己以后查漏补缺. 整个开发没有借助任何第三方框架,所有流媒体协议都是一行行敲上去的,为什么呢?呵呵 授之以鱼不如授之以渔! 下面开始先了解下整个软件的架构. 前端我们在IOS audio&video 专栏中已经介绍的非常详细了,包括摄像头.音视频的各种处理都做了详细的分析.后端我们也在IOS audio&vid