NuPlayer是谷歌新研发的。 AwesomePlayer存在BUG,谷歌早已在android m 版本中弃用。
sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType) { // determine if we have the right player type sp<MediaPlayerBase> p = mPlayer; if ((p != NULL) && (p->playerType() != playerType)) { ALOGV("delete player"); p.clear(); } if (p == NULL) { p = MediaPlayerFactory::createPlayer(playerType, this, notify, mPid); } if (p != NULL) { p->setUID(mUID); } return p; }
NuPlayerDriver构造时,new NuPlayer
NuPlayerDriver::NuPlayerDriver() : mState(STATE_IDLE), mIsAsyncPrepare(false), mAsyncResult(UNKNOWN_ERROR), mSetSurfaceInProgress(false), mDurationUs(-1), mPositionUs(-1), mNumFramesTotal(0), mNumFramesDropped(0), mLooper(new ALooper), mPlayerFlags(0), mAtEOS(false), mStartupSeekTimeUs(-1) { mLooper->setName("NuPlayerDriver Looper"); mLooper->start( false, /* runOnCallingThread */ true, /* canCallJava */ PRIORITY_AUDIO); mPlayer = new NuPlayer; mLooper->registerHandler(mPlayer); mPlayer->setDriver(this); }
NuPlayer.h
struct NuPlayer : public AHandler { NuPlayer(pid_t pid); void setUID(uid_t uid); void setDriver(const wp&driver); void setDataSourceAsync(const sp&source); void setDataSourceAsync( const sp&httpService, const char *url, const KeyedVector *headers); void setDataSourceAsync(int fd, int64_t offset, int64_t length); void setDataSourceAsync(const sp&source); void prepareAsync(); void setVideoSurfaceTextureAsync( const sp&bufferProducer); void setAudioSink(const sp&sink); status_t setPlaybackSettings(const AudioPlaybackRate &rate); status_t getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */); status_t setSyncSettings(const AVSyncSettings &sync, float videoFpsHint); status_t getSyncSettings(AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */); void start(); void pause(); // Will notify the driver through "notifyResetComplete" once finished. void resetAsync(); // Will notify the driver through "notifySeekComplete" once finished // and needNotify is true. void seekToAsync(int64_t seekTimeUs, bool needNotify = false); status_t setVideoScalingMode(int32_t mode); status_t getTrackInfo(Parcel* reply) const; status_t getSelectedTrack(int32_t type, Parcel* reply) const; status_t selectTrack(size_t trackIndex, bool select, int64_t timeUs); status_t getCurrentPosition(int64_t *mediaUs); void getStats(Vector*mTrackStats); spgetFileMeta(); float getFrameRate();
当调用setDataSource时,
void NuPlayer::setDataSourceAsync(const sp&source) { spmsg = new AMessage(kWhatSetDataSource, this); spnotify = new AMessage(kWhatSourceNotify, this); msg->setObject("source", new StreamingSource(notify, source)); msg->post(); }
当发送Message时
void NuPlayer::onMessageReceived(const sp&msg) { switch (msg->what()) { case kWhatSetDataSource: { ALOGV("kWhatSetDataSource"); CHECK(mSource == NULL); status_t err = OK; spobj; CHECK(msg->findObject("source", &obj)); if (obj != NULL) { mSource = static_cast(obj.get()); } else { err = UNKNOWN_ERROR; } CHECK(mDriver != NULL); spdriver = mDriver.promote(); if (driver != NULL) { driver->notifySetDataSourceCompleted(err); } break; } }
当setDataSource好了后,上层发送start开始播放流程以后,开始创建解码器
void NuPlayer::start() { (new AMessage(kWhatStart, this))->post(); }
void NuPlayer::onMessageReceived(const sp&msg) { switch (msg->what()) { case kWhatStart: { ALOGV("kWhatStart"); if (mStarted) { // do not resume yet if the source is still buffering if (!mPausedForBuffering) { onResume(); } } else { onStart(); } mPausedByClient = false; break; } } }
接下来
void NuPlayer::onStart(int64_t startPositionUs) { if (!mSourceStarted) { mSourceStarted = true; mSource->start(); } if (startPositionUs > 0) { performSeek(startPositionUs); if (mSource->getFormat(false /* audio */) == NULL) { return; } } mOffloadAudio = false; mAudioEOS = false; mVideoEOS = false; mStarted = true; uint32_t flags = 0; if (mSource->isRealTime()) { flags |= Renderer::FLAG_REAL_TIME; } sp<MetaData> audioMeta = mSource->getFormatMeta(true /* audio */); audio_stream_type_t streamType = AUDIO_STREAM_MUSIC; if (mAudioSink != NULL) { streamType = mAudioSink->getAudioStreamType(); } sp<AMessage> videoFormat = mSource->getFormat(false /* audio */); mOffloadAudio = canOffloadStream(audioMeta, (videoFormat != NULL), mSource->isStreaming(), streamType); if (mOffloadAudio) { flags |= Renderer::FLAG_OFFLOAD_AUDIO; } sp<AMessage> notify = new AMessage(kWhatRendererNotify, this); ++mRendererGeneration; notify->setInt32("generation", mRendererGeneration); mRenderer = new Renderer(mAudioSink, notify, flags); mRendererLooper = new ALooper; mRendererLooper->setName("NuPlayerRenderer"); mRendererLooper->start(false, false, ANDROID_PRIORITY_AUDIO); mRendererLooper->registerHandler(mRenderer); status_t err = mRenderer->setPlaybackSettings(mPlaybackSettings); if (err != OK) { mSource->stop(); mSourceStarted = false; notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); return; } float rate = getFrameRate(); if (rate > 0) { mRenderer->setVideoFrameRate(rate); } if (mVideoDecoder != NULL) { mVideoDecoder->setRenderer(mRenderer); } if (mAudioDecoder != NULL) { mAudioDecoder->setRenderer(mRenderer); } postScanSources(); }
在onStart函数最后,有一个postScanSources();实现如下:
void NuPlayer::postScanSources() { if (mScanSourcesPending) { return; } sp<AMessage> msg = new AMessage(kWhatScanSources, this); msg->setInt32("generation", mScanSourcesGeneration); msg->post(); mScanSourcesPending = true; }
会发一个Message,key是kWhatScanSources:
void NuPlayer::onMessageReceived(const sp&msg) { switch (msg->what()) { case kWhatScanSources: { int32_t generation; CHECK(msg->findInt32("generation", &generation)); if (generation != mScanSourcesGeneration) { // Drop obsolete msg. break; } mScanSourcesPending = false; ALOGV("scanning sources haveAudio=%d, haveVideo=%d", mAudioDecoder != NULL, mVideoDecoder != NULL); bool mHadAnySourcesBefore = (mAudioDecoder != NULL) || (mVideoDecoder != NULL); // initialize video before audio because successful initialization of // video may change deep buffer mode of audio. if (mSurface != NULL) { instantiateDecoder(false, &mVideoDecoder); } // Don't try to re-open audio sink if there's an existing decoder. if (mAudioSink != NULL && mAudioDecoder == NULL) { instantiateDecoder(true, &mAudioDecoder); } if (!mHadAnySourcesBefore && (mAudioDecoder != NULL || mVideoDecoder != NULL)) { // This is the first time we've found anything playable. if (mSourceFlags & Source::FLAG_DYNAMIC_DURATION) { schedulePollDuration(); } } status_t err; if ((err = mSource->feedMoreTSData()) != OK) { if (mAudioDecoder == NULL && mVideoDecoder == NULL) { // We're not currently decoding anything (no audio or // video tracks found) and we just ran out of input data. if (err == ERROR_END_OF_STREAM) { notifyListener(MEDIA_PLAYBACK_COMPLETE, 0, 0); } else { notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); } } break; } if ((mAudioDecoder == NULL && mAudioSink != NULL) || (mVideoDecoder == NULL && mSurface != NULL)) { msg->post(100000ll); mScanSourcesPending = true; } break; } } }
先初始化视频解码器,再初始化音频解码器。最后都会进入到instantiateDecoder,
status_t NuPlayer::instantiateDecoder(bool audio, sp*decoder) { // The audio decoder could be cleared by tear down. If still in shut down // process, no need to create a new audio decoder. if (*decoder != NULL || (audio && mFlushingAudio == SHUT_DOWN)) { return OK; } spformat = mSource->getFormat(audio); if (format == NULL) { return -EWOULDBLOCK; } format->setInt32("priority", 0 /* realtime */); if (!audio) { AString mime; CHECK(format->findString("mime", &mime)); spccNotify = new AMessage(kWhatClosedCaptionNotify, this); if (mCCDecoder == NULL) { mCCDecoder = new CCDecoder(ccNotify); } if (mSourceFlags & Source::FLAG_SECURE) { format->setInt32("secure", true); } if (mSourceFlags & Source::FLAG_PROTECTED) { format->setInt32("protected", true); } float rate = getFrameRate(); if (rate > 0) { format->setFloat("operating-rate", rate * mPlaybackSettings.mSpeed); } } if (audio) { spnotify = new AMessage(kWhatAudioNotify, this); ++mAudioDecoderGeneration; notify->setInt32("generation", mAudioDecoderGeneration); determineAudioModeChange(); if (mOffloadAudio) { const bool hasVideo = (mSource->getFormat(false /*audio */) != NULL); format->setInt32("has-video", hasVideo); *decoder = new DecoderPassThrough(notify, mSource, mRenderer); } else { *decoder = new Decoder(notify, mSource, mPID, mRenderer); } } else { spnotify = new AMessage(kWhatVideoNotify, this); ++mVideoDecoderGeneration; notify->setInt32("generation", mVideoDecoderGeneration); *decoder = new Decoder( notify, mSource, mPID, mRenderer, mSurface, mCCDecoder); // enable FRC if high-quality AV sync is requested, even if not // directly queuing to display, as this will even improve textureview // playback. { char value[PROPERTY_VALUE_MAX]; if (property_get("persist.sys.media.avsync", value, NULL) && (!strcmp("1", value) || !strcasecmp("true", value))) { format->setInt32("auto-frc", 1); } } } (*decoder)->init(); (*decoder)->configure(format); // allocate buffers to decrypt widevine source buffers if (!audio && (mSourceFlags & Source::FLAG_SECURE)) { VectorinputBufs; CHECK_EQ((*decoder)->getInputBuffers(&inputBufs), (status_t)OK); Vector<MediaBuffer *> mediaBufs; for (size_t i = 0; i < inputBufs.size(); i++) { const sp<ABuffer> &buffer = inputBufs[i]; MediaBuffer *mbuf = new MediaBuffer(buffer->data(), buffer->size()); mediaBufs.push(mbuf); } status_t err = mSource->setBuffers(audio, mediaBufs); if (err != OK) { for (size_t i = 0; i < mediaBufs.size(); ++i) { mediaBufs[i]->release(); } mediaBufs.clear(); ALOGE("Secure source didn't support secure mediaBufs."); return err; } } return OK; }
开始*decoder = new Decoder(notify, mSource, mPID, mRenderer, mSurface, mCCDecoder); 然后(*decoder)->configure(format);这个Decoder结构体是定义在NuPlayerDecoder.h,看下对应configure实现。 在NuPlayerDecoder.cpp
void NuPlayer::Decoder::onConfigure(const sp<AMessage> &format) { CHECK(mCodec == NULL); mFormatChangePending = false; mTimeChangePending = false; ++mBufferGeneration; AString mime; CHECK(format->findString("mime", &mime)); mIsAudio = !strncasecmp("audio/", mime.c_str(), 6); mIsVideoAVC = !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime.c_str()); mComponentName = mime; mComponentName.append(" decoder"); ALOGV("[%s] onConfigure (surface=%p)", mComponentName.c_str(), mSurface.get()); mCodec = MediaCodec::CreateByType( mCodecLooper, mime.c_str(), false /* encoder */, NULL /* err */, mPid); int32_t secure = 0; if (format->findInt32("secure", &secure) && secure != 0) { if (mCodec != NULL) { mCodec->getName(&mComponentName); mComponentName.append(".secure"); mCodec->release(); ALOGI("[%s] creating", mComponentName.c_str()); mCodec = MediaCodec::CreateByComponentName( mCodecLooper, mComponentName.c_str(), NULL /* err */, mPid); } } if (mCodec == NULL) { ALOGE("Failed to create %s%s decoder", (secure ? "secure " : ""), mime.c_str()); handleError(UNKNOWN_ERROR); return; } mIsSecure = secure; mCodec->getName(&mComponentName); status_t err; if (mSurface != NULL) { // disconnect from surface as MediaCodec will reconnect err = native_window_api_disconnect( mSurface.get(), NATIVE_WINDOW_API_MEDIA); // We treat this as a warning, as this is a preparatory step. // Codec will try to connect to the surface, which is where // any error signaling will occur. ALOGW_IF(err != OK, "failed to disconnect from surface: %d", err); } err = mCodec->configure( format, mSurface, NULL /* crypto */, 0 /* flags */); if (err != OK) { ALOGE("Failed to configure %s decoder (err=%d)", mComponentName.c_str(), err); mCodec->release(); mCodec.clear(); handleError(err); return; } rememberCodecSpecificData(format); // the following should work in configured state CHECK_EQ((status_t)OK, mCodec->getOutputFormat(&mOutputFormat)); CHECK_EQ((status_t)OK, mCodec->getInputFormat(&mInputFormat)); mStats->setString("mime", mime.c_str()); mStats->setString("component-name", mComponentName.c_str()); if (!mIsAudio) { int32_t width, height; if (mOutputFormat->findInt32("width", &width) && mOutputFormat->findInt32("height", &height)) { mStats->setInt32("width", width); mStats->setInt32("height", height); } } sp<AMessage> reply = new AMessage(kWhatCodecNotify, this); mCodec->setCallback(reply); err = mCodec->start(); if (err != OK) { ALOGE("Failed to start %s decoder (err=%d)", mComponentName.c_str(), err); mCodec->release(); mCodec.clear(); handleError(err); return; } releaseAndResetMediaBuffers(); mPaused = false; mResumePending = false; }
其中通过CreateByType创建MediaCodec,,位于MediaCodec.cpp
// static spMediaCodec::CreateByType( const sp&looper, const char *mime, bool encoder, status_t *err, pid_t pid) { spcodec = new MediaCodec(looper, pid); const status_t ret = codec->init(mime, true /* nameIsType */, encoder); if (err != NULL) { *err = ret; } return ret == OK ? codec : NULL; // NULL deallocates codec. } // static spMediaCodec::CreateByComponentName( const sp&looper, const char *name, status_t *err, pid_t pid) { spcodec = new MediaCodec(looper, pid); const status_t ret = codec->init(name, false /* nameIsType */, false /* encoder */); if (err != NULL) { *err = ret; } return ret == OK ? codec : NULL; // NULL deallocates codec. }
调用init函数,位于MediaCodec.cpp
status_t MediaCodec::init(const AString &name, bool nameIsType, bool encoder) { mResourceManagerService->init(); // save init parameters for reset mInitName = name; mInitNameIsType = nameIsType; mInitIsEncoder = encoder; // Current video decoders do not return from OMX_FillThisBuffer // quickly, violating the OpenMAX specs, until that is remedied // we need to invest in an extra looper to free the main event // queue. if (nameIsType || !strncasecmp(name.c_str(), "omx.", 4)) { mCodec = new ACodec; } else if (!nameIsType && !strncasecmp(name.c_str(), "android.filter.", 15)) { mCodec = new MediaFilter; } else { return NAME_NOT_FOUND; } ... mLooper->registerHandler(this); mCodec->setNotificationMessage(new AMessage(kWhatCodecNotify, this)); spmsg = new AMessage(kWhatInit, this);
MediaCodec.cpp中onMessageReceived函数
void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { switch (msg->what()) { case kWhatInit: { sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); if (mState != UNINITIALIZED) { PostReplyWithError(replyID, INVALID_OPERATION); break; } mReplyID = replyID; setState(INITIALIZING); AString name; CHECK(msg->findString("name", &name)); int32_t nameIsType; int32_t encoder = false; CHECK(msg->findInt32("nameIsType", &nameIsType)); if (nameIsType) { CHECK(msg->findInt32("encoder", &encoder)); } sp<AMessage> format = new AMessage; if (nameIsType) { format->setString("mime", name.c_str()); format->setInt32("encoder", encoder); } else { format->setString("componentName", name.c_str()); } mCodec->initiateAllocateComponent(format); break; } } }
最后来到ACodec中,initiateAllocateComponent
void ACodec::initiateAllocateComponent(const sp<AMessage> &msg) { msg->setWhat(kWhatAllocateComponent); msg->setTarget(this); msg->post(); }
消息接收
bool ACodec::UninitializedState::onMessageReceived(const sp&msg) { bool handled = false; switch (msg->what()) { case ACodec::kWhatSetup: { onSetup(msg); handled = true; break; } case ACodec::kWhatAllocateComponent: { onAllocateComponent(msg); handled = true; break; } } }
初始化组件
bool ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) { ALOGV("onAllocateComponent"); CHECK(mCodec->mNode == 0); OMXClient client; if (client.connect() != OK) { mCodec->signalError(OMX_ErrorUndefined, NO_INIT); return false; } sp<IOMX> omx = client.interface(); sp<AMessage> notify = new AMessage(kWhatOMXDied, mCodec); mDeathNotifier = new DeathNotifier(notify); if (IInterface::asBinder(omx)->linkToDeath(mDeathNotifier) != OK) { // This was a local binder, if it dies so do we, we won't care // about any notifications in the afterlife. mDeathNotifier.clear(); } Vector<OMXCodec::CodecNameAndQuirks> matchingCodecs; AString mime; AString componentName; uint32_t quirks = 0; int32_t encoder = false; if (msg->findString("componentName", &componentName)) { ssize_t index = matchingCodecs.add(); OMXCodec::CodecNameAndQuirks *entry = &matchingCodecs.editItemAt(index); entry->mName = String8(componentName.c_str()); if (!OMXCodec::findCodecQuirks( componentName.c_str(), &entry->mQuirks)) { entry->mQuirks = 0; } } else { CHECK(msg->findString("mime", &mime)); if (!msg->findInt32("encoder", &encoder)) { encoder = false; } OMXCodec::findMatchingCodecs( mime.c_str(), encoder, // createEncoder NULL, // matchComponentName 0, // flags &matchingCodecs); } sp<CodecObserver> observer = new CodecObserver; IOMX::node_id node = 0; status_t err = NAME_NOT_FOUND; for (size_t matchIndex = 0; matchIndex < matchingCodecs.size(); ++matchIndex) { componentName = matchingCodecs.itemAt(matchIndex).mName.string(); quirks = matchingCodecs.itemAt(matchIndex).mQuirks; pid_t tid = gettid(); int prevPriority = androidGetThreadPriority(tid); androidSetThreadPriority(tid, ANDROID_PRIORITY_FOREGROUND); err = omx->allocateNode(componentName.c_str(), observer, &node); androidSetThreadPriority(tid, prevPriority); if (err == OK) { break; } else { ALOGW("Allocating component '%s' failed, try next one.", componentName.c_str()); } node = 0; } if (node == 0) { if (!mime.empty()) { ALOGE("Unable to instantiate a %scoder for type '%s' with err %#x.", encoder ? "en" : "de", mime.c_str(), err); } else { ALOGE("Unable to instantiate codec '%s' with err %#x.", componentName.c_str(), err); } mCodec->signalError((OMX_ERRORTYPE)err, makeNoSideEffectStatus(err)); return false; } notify = new AMessage(kWhatOMXMessageList, mCodec); observer->setNotificationMessage(notify); mCodec->mComponentName = componentName; mCodec->mRenderTracker.setComponentName(componentName); mCodec->mFlags = 0; if (componentName.endsWith(".secure")) { mCodec->mFlags |= kFlagIsSecure; mCodec->mFlags |= kFlagIsGrallocUsageProtected; mCodec->mFlags |= kFlagPushBlankBuffersToNativeWindowOnShutdown; } mCodec->mQuirks = quirks; mCodec->mOMX = omx; mCodec->mNode = node; { sp<AMessage> notify = mCodec->mNotify->dup(); notify->setInt32("what", CodecBase::kWhatComponentAllocated); notify->setString("componentName", mCodec->mComponentName.c_str()); notify->post(); } mCodec->changeState(mCodec->mLoadedState); return true; }