[源码] Eoxplayer主框架流程
作者:互联网
Eoxplayer主框架流程
核心流程
主要流程:
- 采用1个线程Loop实现音/视频的解码渲染。(通常做法是把音视频各用1个线程去解码渲染,各不影响,刚看到还是挺意外的)
- message queue处理控制命令,上报的消息。
主要类:
- ExoPlayerImplInternal:管理source,render和播放流程。
- Mediasource MediaPeriod:url数据下载,extractor,解复用。
- MediaCodecRenderer: 包括了解码和渲染。
playing流程
Loop:
ExoPlayerImplInternal::doSomeWork {
updatePeriods(); //Period 准备
for (Renderer renderer : enabledRenderers) { //audio video render
MediaCodecRenderer::render()
while () {
drainOutputBuffer() //从解码器取帧,然后渲染
codec.queueOutputBuffer()
processOutputBuffer() //渲染
}
while () {
feedInputBuffer() //送入解码器
codec.queueInputBuffer()
BaseRenderer::readSource() //从mediasource读frame
ProgressiveMediaPeriod::readData()
}
}
}
- loop的代码流程如上,每次loop依次去调用render
- render中会去mediaPeriod read解复用的帧,放入解码器。每次调用不一定会渲染,可能会解码还没完成,或者等同步sleep。
- 主要的2个线程:ExoPlayerImp的loop, mediaSource下数据解复用放到sampleQueue
AudioTrack调用
单Loop刚开始会有疑问:怎么解决audiotrack write接口block的问题(sdk < 21),接口block会影响到视频的渲染。
if (Util.SDK_INT < 21) { // isInputPcm == true
// Work out how many bytes we can write without the risk of blocking.
int bytesToWrite = audioTrackPositionTracker.getAvailableBufferSize(writtenPcmBytes);
if (bytesToWrite > 0) {
bytesToWrite = Math.min(bytesRemaining, bytesToWrite);
bytesWritten = audioTrack.write(preV21OutputBuffer, preV21OutputBufferOffset, bytesToWrite);
if (bytesWritten > 0) {
preV21OutputBufferOffset += bytesWritten;
buffer.position(buffer.position() + bytesWritten);
}
}
}
相关类: DefaultAudioSink.writeBuffer
对于sdk < 21,audio track write会block,通过估计audiotrack的buffer来避免block:
- 计算audiotrack的bufferSize
- 记录写进audiotrack的bytes,writtenPcmBytes
- 通过AudioTrack::getPlaybackHeadPosition,获取当前播到的frames,推算出getAvailableBufferSize
- 根据AvailableBuffer决定是否送进去,实现低api也不会block
标签:Eoxplayer,渲染,audiotrack,流程,bytesWritten,源码,bytesToWrite,block 来源: https://blog.csdn.net/neilooo/article/details/114187926