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;
}
