FFmpeg for ios架构:中级

FFmpeg这部分想了非常久,也没找到比較好的解说方式。本来想像其他博客一样。对着代码一行行的分析。但后来感觉不太现实,FFmpeg应用在IOS上怎么说代码最少也有个5、6k行(包含音视频、业务逻辑),再加上由于小弟也要上班养家。所以没这么多时间写的非常具体,仅仅能做一个随笔。简而化之的就整个架构描写叙述描写叙述。只是全部这些提到的地方都是使用的核心难点。不清楚地方还请大家多多包涵,请勿拍砖。呵呵

另外除了这篇还准备写一篇FFmpeg for ios架构:高级篇。请大家多多关注。

整个代码 分为四个部分:

(1)    音频播放模块(audio unit控制)

(2)    视频贴图模块 opengl

(3)    音视频解码模块 ffmpeg

(4)    业务逻辑  音视频同步  循环解码 模块oc swift

1 视频贴图模块

这部分依旧採用的是OpenGL纹理贴图模块。这样的方法使用起来和之前的录像以及视频播放界面展示的原理是一样的,这里就不再细表(能够參考博客中其他篇)。可是有一点要介绍一下,怎样使用OpenGL现实RGB与YUV。

这里介绍两种方法:RGB

CVReturn err =
CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault,

videoTextureCache,

pixelBuffer,

NULL,

GL_TEXTURE_2D,

GL_RGBA,

frameWidth,

frameHeight,

GL_BGRA,

GL_UNSIGNED_BYTE,

0,

&texture);

由于上面取到的是ios相机视频流,用上面一种方法更好。

YUV:

glTexImage2D(GL_TEXTURE_2D,

0,

GL_LUMINANCE,

widths[i],

heights[i],

0,

GL_LUMINANCE,

GL_UNSIGNED_BYTE,

pixels[i]);

除了YUV我们还能显示各种參数:

/* PixelFormat */

#define GL_DEPTH_COMPONENT                              
0x1902

#define GL_ALPHA                                        
0x1906

#define GL_RGB                                           0x1907

#define GL_RGBA                                         
0x1908

#define GL_LUMINANCE                                    
0x1909

#define GL_LUMINANCE_ALPHA                              
0x190A

再来看看音频播放模块:

2 Audio Unit 音频播放模块(參见专栏中Aduio Unit博客)

2.1 对audio Session的各种属性进行监听进行监听

经常使用的监听:

中断监听、音频输出源监听(插拔耳机)、音量监听

经常使用的属性设置:

播放录音模式属性、音频硬件处理採样周期设置

举两个样例:

插拔耳机监听设置:

AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange,

sessionPropertyListener,

(__bridge
void *)(self)

音频模式设置:

UInt32 sessionCategory =
kAudioSessionCategory_MediaPlayback;

AudioSessionSetProperty(kAudioSessionProperty_AudioCategory,

sizeof(sessionCategory),

&sessionCategory),

"Couldn‘tset audio category")

2.2 设置Audio Unit各种属性(參见专栏中Aduio Unit博客)

回调方法中,主要是须要逻辑层,控制通过ffmpeg解码之后的数据一段段的装载到audio unit中。

这部分逻辑比較复杂,在ffmpeg逻辑层介绍。

另外Audiounit拿到数据之后,还要推断下量化类型,是整形还是浮点。假设是16位整形。这里是要转化位浮点数来进行处理的。

3 FFmpeg解码

重点的部分来了,这个重点是怎样进行解码。

3.0 注冊全部的解码器
av_register_all();

3.1 视频源类型:拿到本地视频文件路径或者网络rtsp流媒体我么须要对视频源类型进行推断。假设是网络视频。那么我们须要初始化avformat_network_init();初始化网络解码的相关方法。

3.2 打开文件获取文件的相关属性

ffmpeg的基本结构体的类型描写叙述。參见还有一篇博客:

这里对每一个变量或者结构体就不做详解了。

初始化AVFormatContext

avformat_alloc_context();

打开文件

avformat_open_input

查找视频文件的流信息

avformat_find_stream_info(formatCtx,
NULL)

获取音视频流文件各种信息:

av_dump_format(formatCtx,
0, path, false);

以下就開始对音视频分别进行处理了

3.3视频流处理

依据AVMEDIA_TYPE_VIDEO
遍历stream,找到视频流轨道序号。比方这里视频轨道是0

依据视频流序号,我们能够获取解码器的上下文:

AVCodecContext *codecCtx =
_formatCtx->streams[videoStream]->codec;

依据解码器的上下文寻找响应的解码器

avcodec_find_decoder(codecCtx->codec_id);

为视频帧分配空间

avcodec_alloc_frame();

不管是播放本地视频还是网络的rtsp流都有这个步骤的。

3.4音频流处理

依据AVMEDIA_TYPE_AUDIO
遍历stream。找到视频流轨道序号,比方这里视频轨道是1

依据视频流序号,我们能够获取解码器的上下文:

AVCodecContext *codecCtx =
_formatCtx->streams[audioStream]->codec;

查找音频解码器

AVCodec *codec =
avcodec_find_decoder(codecCtx->codec_id);

这里比视频多一步:假设当前设备的音频硬件不支持我们解码的这样的数据类型须要调用以下这种方法转化一下:

swr_alloc_set_opts

为音频帧分配空间

AVStream *st =
_formatCtx->streams[_audioStream];

3.5 ffmpeg解码逻辑

前期准备完毕之后,点击播放button,业务逻辑层就開始调用ffmpeg方法,開始解码。

首先開始读取音视频包

av_read_frame(_formatCtx, &packet)

假设是音频数据调用音频解码模块,视频数据调用视频解码模块:

解码视频:

int len =
avcodec_decode_video2(_videoCodecCtx,

_videoFrame,

&gotframe,

&packet);

解码音频:

int len =
avcodec_decode_audio4(_audioCodecCtx,

_audioFrame,

&gotframe,

&packet);

假设数据buffer超出最低门限,或者packetsize剩余大小为零,那么当前解码循环都停止。

由于每次读取的包的大小,可能不仅仅包括一张图片或者一帧音频。所以每次解码之后packetsize的大小都减小了。视频解码之后能够转化为YUV,也能够使用YUV转RGB。这里ffmpeg解码之后原生的就是YUV,不须要再转化为RGB了。

当然转化为RGB之后处理图片特效等更方便。

3.6 快进快退拖动

和文件的操作类似,都是seek移动就可以。

avformat_seek_file(_formatCtx,
_videoStream, ts, ts, ts,
AVSEEK_FLAG_FRAME);

avcodec_flush_buffers(_videoCodecCtx);

4 业务逻辑部分

4.1 音频播放数据装载逻辑

4.1.1 首先清空audio io中buffer空间。比方这里每次处理512个点,双通道,16位量化位数,那么每次处理4096个字节。

4.1.2  读取音频帧中数据。拿到数据之后每次处理4096点,假设当前数据为处理完。那么等待下次audio io中buffer有空间时继续装载,直至当前音频帧中全部音频数据都处理完位置。

4.1.3 假设当前音频帧已经处理完。那么继续从音频帧中读取下一帧音频数据。反复3.1.2的步骤。

由于音频控制逻辑在Audio Unit已经设置完毕,所以这里我们仅仅须要将数据即使的装载进去就可以。

4.2 视频播放同步逻辑、解码逻辑

4.2.1 第一次解码之后要延迟一段时间,等待100ms左右,等待音视频将buffer最小门限装满然后在開始播放。

4.2.2 播放採用递归调用,每次视频帧展示时间,须要调用视频帧时间戳校验。通过当前系统时间戳与当前播放时间戳对照。决定当前显示帧的显示时间,能够尽可能的将每帧图片的显示时间平均。

4.2.3 同一时候每次显示一帧图片,那么进行一次音视频解码,看看是否音视频缓存buffer是否已经低于最低门限了,假设低于那么開始解码。

4.3 音视频同步逻辑

音视频在播放的时候有时候会出现音频过快或者过慢的情况,这时就须要对音视频播放时间进行调整。

通过3.1的音频装载逻辑我们已经知道音频的数据填充过程。

所以:

4.3.1 音频过快:

从音频帧中取出数据之后,我们并没有吧当前音频数据从音频帧中移除,而是将全部的Audio IO buffer内容填充0,类似静音效果,这样就能够实现类似音频帧等待的效果。

4.3.2 音频过慢:

而音频过慢时。我们直接将当前处理音频帧从音频帧队列中移除,不做不论什么audio io buffer 操作,进行读取下一帧音频帧。假设下一帧音频帧还非常慢,继续移除,读取第三帧音频帧。

知道音频帧速度适中为止或者音频buffer为空停止。

时间: 2024-08-04 14:23:38

FFmpeg for ios架构:中级的相关文章

IOS架构师之路:我对IOS架构的点点认识(大纲)

1.今天我鼓起了勇气,想纪录自己对IOS架构学习成长的点点滴滴. 从事IOS开发也有几年的时间,从刚開始最主要的语言.界面.逻辑,再到后面复杂点的线程.数据处理.网络请求.动画,最后到最复杂的底层音视频.图像算法.自己定义各种效果.网络底层处理.甚至是最后的性能:neon.asm优化. 感觉自己在IOS的开发中,每次都是雾里看花,明明非常接近真理却总是触摸不到.对IOS缺乏一种全局把控的感觉.所以我下定决定想看看IOS的一些官方文档,看看IOS的各个模块的层次结构究竟是怎么回事. 大约从一年前開

iOS 架构模式

iOS 架构模式-MVVM MVVM Model-View-ViewModelMVVM 其实是MVC的进化版,他将业务逻辑从VC中解耦到ViewModel,实现VC的瘦身. 做一个简单的登录判断: 创建LoginViewModel(逻辑处理),LoginModel(只放数据),LoginViewController. 这里不用LoginView是为了能更好的把精力集中在用ViewModel解耦上. 在LoginModel中加入方法 //.h - (instancetype)initWithUse

iOS架构组件化

前言 本文简书地址:http://www.jianshu.com/p/2d89f55fc2c4 当一个App只有几个人开发的时候,很容易就会在一个单项目中开发.但当App开发人数越来越多,甚至几百人,十几个不同BU都在协调开发同一个App的时候,就必须对架构进行组件化,才能方便开发.本文主要基于手机淘宝的一次架构探索:手机淘宝客户端架构探索实践,基于此文进行的一些学习和探索,写一篇文章给自己梳理一下. 组件化的目的 首先,第一个问题,为何需要组件化? 如果依旧是单工程项目,或者是多工程引入同一个

ffmpeg for iOS

链接: ios ffmpeg 实时视频压缩(主要是H264) 最简单的基于FFmpeg的移动端例子:IOS 视频转码器 iOS下使用FFMPEG的一些总结

iOS架构模式--解密 MVC,MVP,MVVM以及VIPER架构

在 iOS 中使用 MVC 架构感觉很奇怪? 迁移到MVVM架构又怀有疑虑?听说过 VIPER 又不确定是否真的值得切换? 相信你会找到以上问题的答案,如果没找到请在评论中指出. 你将要整理出你在 iOS 环境下所有关于架构模式的知识.我们将带领大家简要的回顾一些流行的架构,并且在理论和实践上对它们进行比较,通过一些小的例子深化你的认知.如果对文中提到的一些关键词有兴趣,可以点击连接去查看更详细的内容. 掌控设计模式可能会使人上瘾,所以要当心,你可能会对一些问题清晰明了,不再像阅读之前那样迷惑,

iOS架构师之路:控制器(View Controller)瘦身设计

前言 古老的MVC架构是容易被iOS开发者理解和接受的设计模式,但是由于iOS开发的项目功能越来越负责庞大,项目代码也随之不断壮大,MVC的模糊定义导致我们的业务开发工程师很容易把大量的代码写到视图控制器中,行业中对这种控制器有个专业词汇Massive ViewControler(臃肿的视图控制器).代码臃肿导致可读性可维护性差,而且这种不清晰的设计还有许多的副作用,比如代码重用性差.作为架构师需要关注项目的代码质量.指导业务开发工程师写出高质量,高健壮性,高可用的代码也是很重要的工作.因此需要

iOS - 架构模式 - 解密 MVC、MVP、MVVM、VIPER架构

在 iOS 中使用 MVC 架构感觉很奇怪? 迁移到MVVM架构又怀有疑虑?听说过 VIPER 又不确定是否真的值得切换? 相信你会找到以上问题的答案,如果没找到请在评论中指出. 你将要整理出你在 iOS 环境下所有关于架构模式的知识.我们将带领大家简要的回顾一些流行的架构,并且在理论和实践上对它们进行比较,通过一些小的例子深化你的认知.如果对文中提到的一些关键词有兴趣,可以点击连接去查看更详细的内容. 掌控设计模式可能会使人上瘾,所以要当心,你可能会对一些问题清晰明了,不再像阅读之前那样迷惑,

iOS 架构模式--解密 MVC,MVP,MVVM以及VIPER架构

在 iOS 中使用 MVC 架构感觉很奇怪? 迁移到MVVM架构又怀有疑虑?听说过 VIPER 又不确定是否真的值得切换? 相信你会找到以上问题的答案,如果没找到请在评论中指出. 你将要整理出你在 iOS 环境下所有关于架构模式的知识.我们将带领大家简要的回顾一些流行的架构,并且在理论和实践上对它们进行比较,通过一些小的例子深化你的认知.如果对文中提到的一些关键词有兴趣,可以点击连接去查看更详细的内容. 掌控设计模式可能会使人上瘾,所以要当心,你可能会对一些问题清晰明了,不再像阅读之前那样迷惑,

8年iOS架构师告诉你,为什么iOS现在不行了!

前言: 在近一段时间里,笔者会经常听到在职iOS开发人员的各种吐槽,各种无奈,各种对于iOS市场唱衰,更是在某度搜索引擎上随便一点iOS就是各种负面新闻,事实上,经过笔者的一番了解,断定其实你们看到的一定是个假iOS! 如果你的工作只是为了赚钱, 不管换什么工作,只要过个一两年到了瓶颈期,你都会有类似的感觉,请不要随意怀疑一个行业的高峰或者低潮期,请正视自己,正视一个行业. 做为一个开发者,有一个学习的氛围跟一个交流圈子特别重要这是一个我的iOS交流群:638302184,不管你是小白还是大牛欢