转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52560012

前言:上篇文中最后介绍了数据解码放到Buffer过程,今天分析的是stagefright框架中音视频输出过程:

先看下今天的Agenda:

  • 一张图回顾数据处理过程
  • 视频渲染器构建过程
  • 音频数据到Buffer过程
  • AudioPlayer在AwesomePlayer运行过程
  • 音视频同步
  • 音视频输出
  • 一张图看音视频输出

一张图回顾数据处理过程

视频渲染器构建过程

在构造时,new AweSomeEvent时,就开始把AwesomePlayer把onVideoEvent注入进去。









以上代码最会调用initRenderer_l函数

从上面代码来看:AwesomeRemoteRenderer的本质由OMX::createRenderer会先建立一个hardware renderer就是:mVideoRenderer =

new AwesomeNativeWindowRenderer(mNativeWindow, rotationDegrees);若失败,则建立new AwesomeLocalRenderer(mNativeWindow, format);

接下来看下:



而另一个AwesomeLocalRenderer在构造时new SoftwareRenderer(nativeWindow)

AwesomeLocalRender的本质上是由OMX:createRenderer,createRenderer会建立一个渲染器。如果video decoder是software component,则建立一个AwesomeLocalRenderer作为mVideoRenderer

AwesomeLocalRenderer的constructor会呼叫本身的init函数,其所做的事和OMX::createRenderer一模一样。可以理解为把read的数据显示在渲染器中。

渲染器渲染出画面后,我们可能会想,MediaExtractor把音视频进行分开,那音频呢?谁来让他们保持同步的呢?

音频数据到Buffer过程

无论是音频也好,还是视频,都是bufferdata,音频或视频总有一个来维持时间线的流。举个例子:我们看过双簧,一个人说话,一个人演示动作,动作快了不行,话说快,动作跟不上也不行。中间在联系台词时,自然有一些停顿或暗号。在OpenCore中,设置了一个主clock,而audio和video就分别以此作为输出的依据。而在Stagefright中,audio的输出是透过callback函式来驱动,video则根据audio的timestamp来做同步。在这之前,我们得了解下音频相关playback过程:

Stagefright框架中,audio的部分是交由AudioPlayer来处理,它是在AwesomePlayer::play_l中被建立的。贴一段以前分析过的代码:只不过当时没有向AudioPlayer方向向下看



创建AudioPlayer

再接着看下startAudioPlayer_l函数,

接下来看下音频mAudioPlayer->start(true)的操作,上面的过程都是在AwesomePlayer中,接下来变到AudioPlayer.cpp类中:



这里首先要介绍一下mAudioSink ,当mAudioSink不为NULL的时候,AudioPlayer会将其传入构造函数。

而且AudioPlayer中的播放操作都会依考mAudioSink来完成。

此处mAudioSink是从MediaPlayerService注册而来的AudioOut对象。具体代码在MediaPlayerservice中

间接地调用到stagefrightplayer->setAudioSink,最终到awesomeplayer中,如下:

而构造AudioPlayer时用到的就是mAudioSink成员,因此后面分析传入的mAudioSink的操作时,记住实际的对象为AudioOut对象,在MediaPlayerService定义。

本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52560012

AudioPlayer在AwesomePlayer运行过程

下面看AudioPlayer构造函数

主要是进行初始化,并将传入的mAudioSink存在成员mAudioSink中

再回到上面的start函数中

总结如下:

  • 调用mSource->read 启动解码,解码第一帧相当于启动了解码循环
  • 获取音频参数:采样率、声道数、以及量化位数(这里只支持PCM_16_BIT)
  • 启动输出:这里若mAudioSink非空,则启动mAudioSink进行输出,否则构造一个AudioTrack进行音频输出,这里AudioTrack是比较底层的接口 AudioOut是AudioTrack的封装。
  • 在start方法中主要是调用mAudioSink进行工作,主要代码如下:

刚介绍过mAudioSink是AudioOut对象,看下实际的实现(代码在mediaplayerservice.cpp中)

首先mAudioSink->open 需要注意的是传入的参数中有个函数指针 AudioPlayer::AudioSinkCallback ,其主要作用就是audioout播放pcm的时候会定期调用此回调函数填充数据,具体实现如下

以上代码总结为:

  • 1、处理传入的参数,回调函数保存在mCallback中, cookie代表的是AudioPlayer对象指针类型,接下来是根据采样率声道数等计算 frameCount。
  • 2、构造AudioTrack对象,并且赋值给t
  • 3、将audiotrack对象存储在mTrack成员中

    当以上过程完成后,继续分析AudioPlayer.start函数时,最后都会实例化一个AudioTrack对象,然后获取帧大小,比特等信息,然后调用mAudioTrack.start,最后到达mediaplayerservice音频输出start函数。

调用mTrack->start,audiotrack启动后就会周期性的调用 回调函数从解码器获取数据.

本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52560012

音视频同步

回到我们前面的问题:音视频如何同步?通过fillBuffer,不断填充buffer。

代码如下:

以上代码总结为:当callback函数回调AudioPlayer读取解码后的数据时,AudioPlayer会取得两个时间戳:mPositionTimeMediaUs和mPositionTimeRealUs,mPositionTimeMediaUs是数据里面所持有的时间戳(timestamp);mPositionTimeRealUs则是播放此数据的实际时间(依据frame number及sample rate得出)。

以上代码总结为:

  • 在构造audioplayer的时候会执行mTimeSource = mAudioPlayer,

    即将AudioPlayer作为参考时钟,
  • 上述代码中成员变量mSeekTimeUs是由如下语句获得:CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
  • realTimeOffset = getRealTimeUsLocked() - mPositionTimeRealUs; 当显示画面是第一帧时,表示当前的audio的播放时间与第一帧video的时间差值
  • 其中变量是通过mAudioPlayer->getMediaTimeMapping( int64_t *realtime_us, int64_t *mediatime_us) {

    Mutex::Autolock autoLock(mLock)得到

二者的差值表示这一包pcm数据已经播放了多少。Stagefright中的video便依据从AudioPlayer得出来之两个时间戳的差值,作为播放的依据

音视频输出

最后回到本文开头的onVideoEvent方法中,

这样最终音视频数据通过渲染器就到Surface显示画面,就可看到视频和听到声音了。

本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52560012

一张图看音视频输出

第一时间获得博客更新提醒,以及更多android干货,源码分析,欢迎关注我的微信公众号,扫一扫下方二维码或者长按识别二维码,即可关注。

如果你觉得好,随手点赞,也是对笔者的肯定,也可以分享此公众号给你更多的人,原创不易

Android Multimedia框架总结(十)Stagefright框架之音视频输出过程的更多相关文章

  1. Android多媒体框架总结(1) - 利用MediaMuxer合成音视频数据流程分析

    场景介绍: 设备端通过服务器传向客户端(Android手机)实时发送视频数据(H.264)和音频数据(g711a或g711u), 需要在客户端将音视频数据保存为MP4文件存放在本地,用户可以通过APP ...

  2. Android IOS WebRTC 音视频开发总结(七十)-- 移动端音视频技术优化的七个方向

    最近直播很火,很多朋友对背后的技术比较感兴趣,所以今天我们整理一篇关于移动端视频优化的文章,这篇文章是我朋友在一个技术大会上分享过的,更多内容请关注我们的微信公众号:rtcblacker 视频直播为什 ...

  3. 转:Android IOS WebRTC 音视频开发总结 (系列文章集合)

    随笔分类 - webrtc   Android IOS WebRTC 音视频开发总结(七八)-- 为什么WebRTC端到端监控很关键? 摘要: 本文主要介绍WebRTC端到端监控(我们翻译和整理的,译 ...

  4. 堪称教科书级别的Android音视频入门进阶学习手册,开源分享!

    概述 随着整个互联网的崛起,数据传递的形式也在不断升级变化,总的流行趋势如下: 纯文本的短信,QQ -> 空间,微博,朋友圈的图片文字结合 -> 微信语音 -> 各大直播软件 -&g ...

  5. Android Multimedia框架总结(十五)Camera框架之Camera2补充

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52751055 前言:监于5.0之 ...

  6. Android Multimedia框架总结(九)Stagefright框架之数据处理及到OMXCodec过程

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼:http://blog.csdn.net/hejjunlin/article/details/52532085 不知不觉到第九篇了,感觉还有 ...

  7. Android Multimedia框架总结(八)Stagefright框架之AwesomePlayer及数据解析器

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼:http://blog.csdn.net/hejjunlin/article/details/52503057 前言:前面一篇分析了medi ...

  8. Android Multimedia框架总结(二十四)MediaMuxer实现手机屏幕录制成gif图

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/53866405 前言:上篇中,介绍 ...

  9. Android Multimedia框架总结(十一)CodeC部分之AwesomePlayer到OMX服务

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52623882 前言:上篇文< ...

随机推荐

  1. 机器学习技法:12 Neural Network

    Roadmap Motivation Neural Network Hypothesis Neural Network Learning Optimization and Regularization ...

  2. [HNOI 2014]米特运输

    Description 米特是D星球上一种非常神秘的物质,蕴含着巨大的能量.在以米特为主要能源的D星上,这种米特能源的运输和储 存一直是一个大问题.D星上有N个城市,我们将其顺序编号为1到N,1号城市 ...

  3. [USACO 12DEC]Running Away From the Barn

    Description It's milking time at Farmer John's farm, but the cows have all run away! Farmer John nee ...

  4. 2015 多校联赛 ——HDU5334(构造)

    Virtual Participation Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Ot ...

  5. [bzoj5015][Snoi2017]礼物

    来自FallDream的博客,未经允许,请勿转载,谢谢. 热情好客的请森林中的朋友们吃饭,他的朋友被编号为 1-N,每个到来的朋友都会带给他一些礼物:.其中,第一个朋友会带给他 1 个,之后,每一个朋 ...

  6. 51Nod 1753 相似子串

    题目大意: 两个字符串相似定义为: 1.两个字符串长度相等 2.两个字符串对应位置上有且仅有至多一个位置所对应的字符不相同 给定一个字符串,每次询问两个子串在给定的规则下是否相似.给定的规则指每次给出 ...

  7. VMware下安装Linux(CentOs6.3)操作系统

    VMware 10.0.2 CentOs 6.3 VMware的安装以及CentOs的下载比较简单,这里不再描述 1.创建新的虚拟机 2.选择典型 3.选择稍后安装操作系统 4.选择如图所示 5.虚拟 ...

  8. 笔记9 AOP练习3(通过注解引入新功能 )

    切面可以为Spring bean添加新方法. 在Spring中,切面只是实现了它们所包装bean相同接口的 代理.如果除了实现这些接口,代理也能暴露新接口的话,会怎么样 呢?那样的话,切面所通知的be ...

  9. Python中模块之hashlib&hmac的讲解

    hashlib & hmac的讲解 两个模块主要用于加密相关的操作. 1. hashlib模块 md5 具体代码如下 import hashlib ha_m5 = hashlib.md5()# ...

  10. 记一次sql优化——left join不走索引问题

    sql一执行就卡住,然后就...杀进程了 看了一下表的大小 第一反应就是加索引,然后explain看了一下走什么索引了,结果很尴尬,三个表,只走了一个索引...一群人在那纠结为毛走不了索引. 无意间发 ...