当前位置:网站首页>【学习】从零开始的音视频开发(9)——NuPlayer
【学习】从零开始的音视频开发(9)——NuPlayer
2022-04-23 07:16:00 【Panic Lin】
NuPlayer基于StagefrightPlayer的基础类构建,利用了底层的ALooper/AHandler机制来进行异步解码播放,Alooper轮循队列中的消息,把消息推送到AHandler处理,最后通过handleMessage函数回调,做相应的逻辑处理
NuPlayer整体结构
MediaPlayerFactory通过工厂模式创建NuPlayerFactory,然后通过NuPlayerFactory创建NuPlayerDriver,接着通过NuPlayerDriver构建一个NuPlayer,NuPlayer作为播放器,其中设计数据解析、解码、渲染等过程


NuPlayer的构建过程
在上层调用setDataSource函数后,开始到达MediaPlayerService的setDataSource函数,通过getPlayerType函数获取播放器类型

播放器类型枚举如下

这时再回到MediaPlayerFactory中看看getPlayerType函数

接下来进入一个宏函数,宏的主要作用是替换,提高代码的执行效率,因为其省去了分配和释放栈帧、传参、传返回值等一系列工作

这个宏函数的标示遍历map中存放的播放器工厂类,调用scoreFactory可以得到播放器的播放能力,如果是NuPlayer,默认有一个0.8的值,返回的ret就是NuPlayerFactory对象,如果得到的值为0.0,就进入getDefaultPlayerType函数

默认也是NuPlayerFactory
针对NuPlayerFactory不会直接创建NuPlayer,而是在NuPlayerDriver的构造函数中创建一个NuPlayerDriver

在NuPlayerDriver的构造函数中,创建了一个NuPlayer,NuPlayerDriver是对NuPlayer的封装,继承MediaPlayerInterface接口。通过NuPlayer可以实现播放功能,主要用于通知上面的流程
NuPlayer继承自AHandler,并且引入了AMessage,通过ALooper来处理消息,比如它的prepareAsync函数

实际就是发送一个kWhatPrepare消息。在onMessageReceived函数中,收到消息并进行处理(该函数太长,仅摘取kWhatPrepare部分分析)

NuPlayer的数据解析模块
解析的模块主要是NuPlayerSource以及继承它的几个类,如HTTPLiveSource、RTSPSource、GenericSource等
在NuPlayer中调用setDataSourceAsync函数后

这里会根据不同协议选择不同的Source对象,有了这个Source对象后,发送kWhatSetDataSource消息(下图同样只是该函数部分截图)

通过具体的Source解析完数据,再把Source强制转换成mSource给Decoder使用,这时里面就包含了数据相关信息,其中的一个HTTPLiveSource,主要用于解析HLS协议

当调用HTTPLiveSource的prepareAsync函数时

内部主要构建了一个LiveSession对象,通过LiveSession内部的connectAsync函数,创建一个会话


查看onConnect函数

网络请求,开始取播放列表,在取到播放列表后进行回调(下图是回调函数)

上面的代码主要是根据URL返回的M3U文件,获取对应的BandwidthItem,如果熟悉M3U文件,可以知道M3U文件有一级索引和二级索引,下图是一些举例

其主要作用是动态码率适应,BANDWIDTH越大,分辨率越高。BINDWIDTH实际上就是带宽
若想获得某个Track的信息,得到视频、音频、字幕相关信息,可以通过LiveSession的getTrackInfo函数

到此数据解析模块完成,视频源的主要作用都是得到音视频数据信息,最终通过mSource变量传递给解码器
NuPlayer的解码模块
它引入了NuPlayerDecoderBase,这是一个基类,真正的解码器逻辑在NuPlayerDecoder.cpp中,它继承了这个基类,下面先查看实例化解码器

上面的代码构造了Decoder对象,且进行了初始化和构建解码器
由于NuPlayerDecoder继承自NuPlayerDecoderBase类,所以Configure函数会执行NuPlayerDecoder的Configure函数,最终回调onConfigure函数,其位于NuPlayerDecoder.cpp中

从onConfigure函数可以看到,NuPlayerDecoder引入了MediaCodec作为解码器。通过CreateByType/CreateByComponentName创建了Codec对象。
NuPlayer的渲染模块
主要功能
1.将音视频原始数据缓存到队列
2.音频数据消耗播放
3.视频数据消耗显示
4.音视频同步
5.播放器控制
将音视频原始数据缓存到队列,在NuPlayerRenderer.h中,存在一个QueueEntry结构体和两个队列


数据在onQueueBuffer函数中进行添加

而音频的播放在NuPlayerRenderer中,会先调用openAudioSink函数

发送一个kWhatOpenAudioSink消息,收到消息后进行如下处理

调用onOpenAudioSink函数

这里打开了AudioSink(音频后端)。当将音频数据放入音频队列时,会接着调用postDrainAudioQueue_l函数

上图代码发送了一个kWhatDrainAudioQueue

主要是有一个进行判断的onDrainAudioQueue函数,判断是否需要重新向AudioSink写入数据

到这里,这个音频播放流程如下:先打开音频后端,然后当向音频队列中发送数据,音频队列同时向音频后端写入数据,以供播放音频
视频显示的话,同样是在视频原始数据进入视频队列后,开始执行postDrainVideoQueue函数

这里先发送一个kWhatDrainVideoQueue的消息,然后进行音视频同步,发送消息后会出发调用onDrainVideoQueue

NuPlayer::Renderer使用的是以视频为基准的同步机制,解码后的音频数据时间戳如果大于视频数据时间戳,直接丢弃音频包,然后直接渲染视频。同步机制主要位于视频缓冲区处理部分的onDrainVideoQueue和音频缓冲区处理部分的onDrainVideoQueue中。音视频的渲染都采用类似定时器的机制,只不过视频显示需要依赖于实际解码器,音频播放需要依赖于AudioSink接口
版权声明
本文为[Panic Lin]所创,转载请带上原文链接,感谢
https://blog.csdn.net/PanicLin/article/details/124356518
边栏推荐
猜你喜欢

How does feign integrate hystrix

数据安全问题已成隐患,看vivo如何让“用户数据”重新披甲
![[appium] encountered the problem of switching the H5 page embedded in the mobile phone during the test](/img/4a/c741ec4f9aa724e150a5ae24d0f9e9.png)
[appium] encountered the problem of switching the H5 page embedded in the mobile phone during the test

每周leetcode - 06 数组专题 7~739~50~offer 62~26~189~9
![[programming practice / embedded competition] learning record of embedded competition (II): picture streaming based on TCP](/img/6c/7408180d0c24560b4a68982635520e.jpg)
[programming practice / embedded competition] learning record of embedded competition (II): picture streaming based on TCP

The third divisor of leetcode simple question

LeetCode簡單題之計算字符串的數字和

2022.4.11-4.17 AI行业周刊(第93期):AI行业的困局

Principle of sentinel integrating Nacos to update data dynamically

vivo,硬件安全的爱与雷霆
随机推荐
剑指offer day24 数学(中等)
扎心了!一女子发朋友圈羡慕别人按时发工资被开除,连点赞的同事也一同被开除了...
LeetCode中等题之旋转函数
ASAN 极简原理
[go]常见的并发模型[泛型版]
Anti shake and throttling
Implementation of promise all
2022.4.11-4.17 AI industry weekly (issue 93): the dilemma of AI industry
js将树形结构数据转为一维数组数据
The simple problem of leetcode is to calculate the numerical sum of strings
Solidity IDE Remix中文版使用手册
mysql查询字符串类型的字段使用数字类型查询时问题
Samsung, March to the west again
3C装配中的机械臂运动规划
分布式服务治理Nacos
redis主从服务器问题
LeetCode15. Sum of three
Rotation function of leetcode medium problem
干货!以点为形:可微分的泊松求解器
2022.4.11-4.17 AI行业周刊(第93期):AI行业的困局