您当前的位置: 首页 >  android

暂无认证

  • 0浏览

    0关注

    92582博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Android Multimedia框架总结(二十八)NuPlayer到OMX过程

发布时间:2017-06-23 13:21:52 ,浏览量:0

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;
}
关注
打赏
1653961664
查看更多评论
立即登录/注册

微信扫码登录

0.7765s