打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
转:NuPlayer处理机制

ICS4.0.3中增加一个单独的播放器叫做NuPlayer播放器,目前的HTTP和RTSP都使用的是NuPlayer,其他的使用的是StageFrightPlayer,如代码所示:

播放器应用层通过调用MediaPlayer->setDataSource设置了播放器的类型,如下所示:

player_type getPlayerType(const char* url)
{
if (TestPlayerStub::canBeUsed(url)) {
return TEST_PLAYER;
}

if (!strncasecmp("http://", url, 7)
|| !strncasecmp("https://", url, 8)) {
size_t len = strlen(url);
if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) {
return NU_PLAYER;
}

if (strstr(url,"m3u8")) {
return NU_PLAYER;
}
}

if (!strncasecmp("rtsp://", url, 7)) {
return NU_PLAYER;
}

return getDefaultPlayerType();
}

可以看到对于HTTP和RTSP流媒体使用的播放器框架是NuPlayer,以下分析一下创建NuPlayer的处理流程。

1.创建Nulayer所做的处理

创建的时候不是创建NuPlayer而是创建NuPlayerDriver,在NuPlayerDriver::NuPlayerDriver()构造函数中:
1.1 创建了ALooper对象mLooper,并调用了 mLooper->start函数,优先级为PRIORITY_AUDIO。
在ALooper::start函数中循环执行ALooper::loop()函数,在loop函数中调用gLooperRoster.deliverMessage函数,
然后在ALooperRoster::deliverMessag函数中调用handler->onMessageReceived函数,最终执行了AHandler的子struct中的onMessageReceived函数,
处理具体消息;例如MyHandler的onMessageReceived函数,用于处理rtsp的消息。
1.2 创建了NuPlayer对象mPlayer,并调用 mLooper->registerHandler,把mPlayer注册到全局变量gLooperRoster的mHandlers成员vector中。
所有的AHandler对象都需要注册到全局变量gLooperRoster的mHandlers成员中。

2. NuPlayer::start处理的流程为以下顺序
2.1 MediaPlayer::start() -> MediaPlayerService::Client::start() ->
2.2 NuPlayerDriver::start()
在NuPlayerDriver::setDataSource中mState被设置为STOPPED状态,所以在start函数中执行了mPlayer->start(),调用到NuPlayer::start()函数
2.3 NuPlayer::start()
发送kWhatStart消息
2.4 NuPlayer::onMessageReceived对kWhatStart消息的处理
2.4.1 接收到kWhatStart消息后,先对一些变量赋初始值,并调用mSource->start()函数,对于rtsp流来说,即调用NuPlayer::RTSPSource::start()函数;对于http流来说,即调用NuPlayer::HTTPSource::start()函数。
2.4.1.1 NuPlayer::RTSPSource::start()
(1)创建了ALooper对象mLooper,并调用了mLooper->setName("rtsp")和mLooper->start()函数。
(2)创建了AHandlerReflector<RTSPSource>对象mReflector,并通过调用 mLooper->registerHandler,把mReflector注册到全局变量gLooperRoster的mHandlers成员中
AHandlerReflector的作用暂时还不清楚,貌似是指定RTSPSource接收消息
(3)创建消息kWhatNotify,并做为MyHandler的参数,在NuPlayer::RTSPSource::onMessageReceived函数中处理了kWhatNotify消息
(4)创建MyHandler对象mHandler,并注册到gLooperRoster的mHandlers成员中
(5)执行mHandler->connect(),链接到服务器,并把mState设置为CONNECTING状态
调用ARTSPConnection的connect函数,进行链接服务器的处理。
2.4.2 新建Renderer对象mRenderer,并发送kWhatRendererNotify消息,把mRenderer注册到全局变量gLooperRoster的mHandlers成员中
Renderer构造函数只是简单的对变量赋默认值,并没有做其他处理
2.4.3 调用postScanSources()函数,进行初始化audio/video的解码器decoder
(1)NuPlayer::postScanSources()函数中发送了kWhatScanSources消息

2.5 NuPlayer::onMessageReceived对kWhatScanSources消息的处理
2.5.1 调用instantiateDecoder函数执行初始化video和audio解码器
  1. instantiateDecoder(false, &mVideoDecoder);
  2. if (mAudioSink != NULL) {
  3. instantiateDecoder(true, &mAudioDecoder);
  4. }
2.5.2 NuPlayer::instantiateDecoder
(1)当初始化audio解码器时,发送kWhatAudioNotify消息
当初始化video解码器时,发送kWhatVideoNotify消息
(2)初始解码器Decoder对象decoder,并注册到全局变量gLooperRoster的mHandlers成员中
  1. *decoder = audio ? new Decoder(notify) :
  2. new Decoder(notify, mNativeWindow); // video时,设置NativeWindowWrapper参数
  3. looper()->registerHandler(*decoder);
  4. (*decoder)->configure(meta); // 调用decoder的configure方法,初始化ACodec解码器
2.5.3 NuPlayer::Decoder::configure
(1)创建消息kWhatCodecNotify,用于ACodec对象mCodec的通知消息
(2)调用makeFormat函数,根据meta类型,创建对应的message format
(3)创建ACodec对象mCodec,
(4)video解码时,创建ALooper对象mCodecLooper,用于释放主消息event队列,并注册到全局变量gLooperRoster的mHandlers成员中
mCodecLooper的name设置为"NuPlayerDecoder"

2.6 NuPlayer::onMessageReceived
case kWhatVideoNotify:
case kWhatAudioNotify:

取得AMessage消息"codec-request"对应的"what"值,分别对以下情况处理
2.6.1 ACodec::kWhatFillThisBuffer
执行feedDecoderInputData函数,取得一个有效的buffer

2.6.2 ACodec::kWhatEOS
向render发送EOS消息
mRenderer->queueEOS(audio, err);

2.6.3 ACodec::kWhatFlushCompleted
(1)把mFlushingAudio或mFlushingVideo设置为FLUSHED或者SHUTTING_DOWN_DECODER状态
(2)调用finishFlushIfPossible()函数,执行一些flush后的操作,例如:
mRenderer->signalTimeDiscontinuity();
mAudioDecoder->signalResume();
mVideoDecoder->signalResume();
finishReset();
如果mAudioDecoder == NULL || mVideoDecoder == NULL,则会执行postScanSources()函数,进行初始化audio/video的解码器decoder

2.6.4 ACodec::kWhatOutputFormatChanged

2.6.5 ACodec::kWhatShutdownCompleted

2.6.6 ACodec::kWhatError

2.6.7 ACodec::kWhatDrainThisBuffer // 在ACodec::BaseState::onOMXFillBufferDone中发送的
调用renderBuffer(audio, codecRequest), 把需要解码的数据放入render队列

2.7 NuPlayer::renderBuffer
先做一些检查,丢弃需要跳过的数据
调用mRenderer->queueBuffer(audio, buffer, reply);,把真正需要解码的数据放入renderer队列

2.8 NuPlayer::Renderer::queueBuffer
发送kWhatQueueBuffer消息
  1. sp<AMessage> msg = new AMessage(kWhatQueueBuffer, id());
  2. msg->setInt32("audio", static_cast<int32_t>(audio));
  3. msg->setObject("buffer", buffer);
  4. msg->setMessage("notifyConsumed", notifyConsumed);
  5. msg->post();
2.9 NuPlayer::Renderer::onMessageReceived
case kWhatQueueBuffer:
--->
NuPlayer::Renderer::onQueueBuffer
在video时,调用postDrainVideoQueue函数
--->
NuPlayer::Renderer::postDrainVideoQueue()
发送kWhatDrainVideoQueue消息,消息延迟时间为delayUs。

+++++++++++++++变量注解+++++++++++++++
  1. mAnchorTimeMediaUs表示audio的媒体时间mediaTimeUs,初始值为-1
  2. mAnchorTimeMediaUs = mediaTimeUs;
  3. int64_t realTimeOffsetUs =
  4. (mAudioSink->latency() / 2 /* XXX */
  5. + numFramesPendingPlayout
  6. * mAudioSink->msecsPerFrame()) * 1000ll;
  7. // LOGI("realTimeOffsetUs = %lld us", realTimeOffsetUs);
  8. mAnchorTimeRealUs =
  9. ALooper::GetNowUs() + realTimeOffsetUs;
  10. mAnchorTimeRealUs表示audio的已经处理完(包括已经播放和正要播放)的数据的时间。如果没有audio,则为当前系统时间
  11. mAnchorTimeRealUs = ALooper::GetNowUs();
++++++++++++++++++++++++++++++
--->
NuPlayer::Renderer::onMessageReceived
case kWhatDrainVideoQueue:
调用onDrainVideoQueue()处理
继续调用postDrainVideoQueue函数,循环处理下一个buffer
--->
  1. NuPlayer::Renderer::onDrainVideoQueue()
  2. // 发送消息表示此buffer已经处理
  3. entry->mNotifyConsumed->setInt32("render", !tooLate);
  4. entry->mNotifyConsumed->post();
  5. mVideoQueue.erase(mVideoQueue.begin());
  6. entry = NULL;
  7. notifyPosition();
--------------------------------------------------------------------------------------------------
**************** 发送kWhatDrainThisBuffer消息的处理流程 Start ****************

NuPlayer::instantiateDecoder
创建Decoder对象,然后调用
(*decoder)->configure(meta);
--->
NuPlayer::Decoder::configure
调用mCodec->initiateSetup(format);
--->
ACodec::initiateSetup
发送kWhatSetup消息
--->
ACodec::UninitializedState::onMessageReceived
case ACodec::kWhatSetup:
调用onSetup(msg);
--->
  1. ACodec::UninitializedState::onSetup
  2. status_t err = omx->allocateNode(componentName.c_str(), observer, &node);
--->
OMX::allocateNode
创建了OMXNodeInstance对象,并注册了OMXNodeInstance::kCallbacks回调
--->
  1. // static
  2. OMX_CALLBACKTYPE OMXNodeInstance::kCallbacks = {
  3. &OnEvent, &OnEmptyBufferDone, &OnFillBufferDone // 注册了回调函数OnFillBufferDone
  4. };
--->
  1. OMX_ERRORTYPE OMXNodeInstance::OnFillBufferDone(
  2. OMX_IN OMX_HANDLETYPE hComponent,
  3. OMX_IN OMX_PTR pAppData,
  4. OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
  5. OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
  6. if (instance->mDying) {
  7. return OMX_ErrorNone;
  8. }
  9. return instance->owner()->OnFillBufferDone(instance->nodeID(), pBuffer); // OMXNodeInstance含有OMX成员变量OMX *mOwner;
  10. }
--->
OMX::OnFillBufferDone
设置msg.type = omx_message::FILL_BUFFER_DONE;并发送
--->
  1. ACodec::BaseState::onOMXMessage
  2. case omx_message::FILL_BUFFER_DONE:
  3. return onOMXFillBufferDone(
  4. bufferID,
  5. (size_t)rangeOffset, (size_t)rangeLength,
  6. (OMX_U32)flags,
  7. timeUs,
  8. platformPrivate,
  9. dataPtr);
--->
  1. ACodec::BaseState::onOMXFillBufferDone
  2. PortMode mode = getPortMode(kPortIndexOutput);
  3. switch (mode) {
  4. case KEEP_BUFFERS:
  5. break;
  6. case RESUBMIT_BUFFERS:
  7. 设置发送消息notify->setInt32("what", ACodec::kWhatDrainThisBuffer);
**************** 发送kWhatDrainThisBuffer消息的处理流程 End ****************
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
Android 9.0 multimedia框架解析(四)start过程
Android中基于NuPlayer的RTSP框架学习
Android Http Live streaming
开发人员选项那点事儿
【探索公作式】明天发布会 你真正了解 MIUI8 的开发者选项吗
手把手搭建RTSP流媒体服务器
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服