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,
,
&texture);
由于上面取到的是ios相机视频流,用上面一种方法更好。
YUV:
glTexImage2D(GL_TEXTURE_2D,
,
GL_LUMINANCE,
widths[i],
heights[i],
,
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,
, 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为空停止。
FFmpeg for ios架构:中级的更多相关文章
- IOS架构师之路:我对IOS架构的点点认识(大纲)
1.今天我鼓起了勇气,想纪录自己对IOS架构学习成长的点点滴滴. 从事IOS开发也有几年的时间,从刚開始最主要的语言.界面.逻辑,再到后面复杂点的线程.数据处理.网络请求.动画,最后到最复杂的底层音视 ...
- iOS 架构模式--解密 MVC,MVP,MVVM以及VIPER架构
本文由CocoaChina译者lynulzy(社区ID)翻译 作者:Bohdan Orlov 原文:iOS Architecture Patterns 在 iOS 中使用 MVC 架构感觉很奇怪? 迁 ...
- iOS 架构模式-MVVM
iOS 架构模式-MVVM MVVM Model-View-ViewModelMVVM 其实是MVC的进化版,他将业务逻辑从VC中解耦到ViewModel,实现VC的瘦身. 做一个简单的登录判断: 创 ...
- ffmpeg for iOS
链接: ios ffmpeg 实时视频压缩(主要是H264) 最简单的基于FFmpeg的移动端例子:IOS 视频转码器 iOS下使用FFMPEG的一些总结 iOS配置FFmpeg框架 iOS上使用高大 ...
- 李洪强iOS开发之基于彻底解耦合的实验性iOS架构
基于彻底解耦合的实验性iOS架构 这周我决定做一个关于彻底解耦合的应用架构的实验.我想探究的主题是: “如果所有的应用内通讯都通过一个事件流来完成会怎么样?” 我构造了一个待办事项应用,因为这是我 ...
- iOS - 架构的认识过程,悬崖勒马。
16年的时候写过一篇代码讲解的,依旧是这三种架构,现在20年将近了,看到好的文章,是否增加新的认识. 16年链接 iOS - 架构模式 - 解密 MVC.MVP.MVVM.VIPER架构 新项目选择架 ...
- iOS架构师之路:控制器(View Controller)瘦身设计
前言 古老的MVC架构是容易被iOS开发者理解和接受的设计模式,但是由于iOS开发的项目功能越来越负责庞大,项目代码也随之不断壮大,MVC的模糊定义导致我们的业务开发工程师很容易把大量的代码写到视图控 ...
- 对于iOS架构的认识过程
MVC 经典就是经典,没有之一.iOS中MVC架构,看懂斯坦福大学白胡子老头这张图基本上就可以了. 斯坦福大学MVC架构.png 简单理解,就是Controller对象拥有View和Model对象 ...
- 百度在职 iOS 架构师的成长笔记,送给还在迷茫的你!
前言 我们经常在网上会看到这样的文章,你的同龄人正在如何如何.......这是典型的贩卖焦虑的文章.的确,现阶段,刚毕业几年的年轻人,面临车,房子等,有时候压力挺大的. 但你过度焦虑的话,每天生活在恐 ...
随机推荐
- Codeforces Round #470 (rated, Div. 2, based on VK Cup 2018 Round 1)
A. Protect Sheep time limit per test 1 second memory limit per test 256 megabytes input standard inp ...
- Spring 依赖注入(一、注入方式)
首先装配一个实体类People package com.maya.model; public class People { private int id; private String name; p ...
- 设计模式(一)单例模式:1-饿汉模式(Eager)
思想: 饿汉模式是最常提及的2种单例模式之一,其核心思想,是类持有一个自身的 instance 属性,并且在申明的同时立即初始化. 同时,类将自身的构造器权限设为 private,防止外部代码创建对象 ...
- 使用runtime关联对象将视图添加到视图的类目里
//get方法 - (RJCircularLoaderView*)rj_circularLoaderView { RJCircularLoaderView *loaderView = objc_get ...
- 【Luogu】P1419寻找段落(单调队列)
题目链接 不知为何状态突然奇差无比,按说这题本来应该是水题的,但不仅不会做,还比着题解爆零五次 二分平均值(想到了),单调队列维护最大区间和(想到了但是不会,???为什么我不会???) #includ ...
- kb-07专题--线段树-01-单点修改,区间查和
给定区间长度,然后给两个操作,单点增加值和单点减值,询问一个区间的人数和:(水) 代码如下: /* 写的第一个线段树,丑: */ #include<iostream> #include&l ...
- ACM程序设计选修课——1044: (ds:队列)打印队列(queue模拟)
问题 A: (ds:队列)打印队列 时间限制: 1 Sec 内存限制: 128 MB 提交: 25 解决: 4 [提交][状态][讨论版] 题目描述 网络工程实验室只有一台打印机,它承担了非常繁重 ...
- [转] Makefile 基础 (6) —— Makefile 使用条件判断
该篇文章为转载,是对原作者系列文章的总汇加上标注. 支持原创,请移步陈浩大神博客:(最原始版本) http://blog.csdn.net/haoel/article/details/2886 我转自 ...
- 防止点击asp.net的button按钮刷新页面(保留button的外观)
原文发布时间为:2008-08-06 -- 来源于本人的百度文章 [由搬家工具导入] Button btn=new Button(); 1、如果用 btn.Enabled=false;是可以防止刷新的 ...
- 转 C语言编译过程简介
C语言编译过程简介 C语言编译过程简介 刚开始接触编程的时候,只知道照书敲敲代码,一直都不知道为什么在windows平台下代码经过鼠标那样点击几下,程序的结果就会在那个黑色的屏幕上.现在找了个机会将C ...