stagefright框架下的awesomeplayer播放准备阶段

来源:互联网 发布:楼体亮化设计软件 编辑:程序博客网 时间:2024/05/17 23:08

前文分析了AwesomePlayer的setDataSource阶段,对于已经分离好的音视频数据,下一步就是为其设置解码器,这一阶段称为 prepare。

直接从AwesomePlayer::prepareAsync()开始,

status_t AwesomePlayer::prepareAsync() {    return prepareAsync_l();}status_t AwesomePlayer::prepareAsync_l() {     if (!mQueueStarted) {        mQueue.start();        mQueueStarted = true;    }    modifyFlags(PREPARING, SET);    mAsyncPrepareEvent = new AwesomeEvent(            this, &AwesomePlayer::onPrepareAsyncEvent);    mQueue.postEvent(mAsyncPrepareEvent);}

播放器准备阶段主要由prepareAsync_l实施,_l代表lock。首先检查下时间队列是否正常工作,然后将mFlags设置为PREPARING。并将事件mAsyncPrepareEvent送到消息队列,于是onPrepareAsyncEvent将会执行。

void AwesomePlayer::onPrepareAsyncEvent() {    Mutex::Autolock autoLock(mLock);    beginPrepareAsync_l();}void AwesomePlayer::beginPrepareAsync_l() {    if (mUri.size() > 0) {        status_t err = finishSetDataSource_l();        if (err != OK) {            abortPrepare(err);            return;        }    }    if (mVideoTrack != NULL && mVideoSource == NULL) {        status_t err = initVideoDecoder();    }    if (mAudioTrack != NULL && mAudioSource == NULL) {        status_t err = initAudioDecoder();    }    modifyFlags(PREPARING_CONNECTED, SET);    if (isStreamingHTTP()) {        postBufferingEvent_l();    } else {        finishAsyncPrepare_l();    }}

beginPrepareAsync_l中会对http源做特殊处理,对于本地aaa.mp3则会初始化视频和音频解码器。

status_t AwesomePlayer::initVideoDecoder(uint32_t flags) { mVideoSource = OMXCodec::Create(            mClient.interface(), mVideoTrack->getFormat(),            false, // createEncoder            mVideoTrack,            NULL, flags, USE_SURFACE_ALLOC ? mNativeWindow : NULL);#define USE_SURFACE_ALLOC 1

这里就大名鼎鼎的OpenMax编码解码框架,对于参数:
const sp &omx 为mClient.interface()
const sp &meta 为mVideoTrack->getFormat()
bool createEncoder 为false
const sp &source 为mVideoTrack
const char *matchComponentName 为NULL
uint32_t flags 为flags
const sp &nativeWindow 为mNativeWindow

将创建一个带解码的视频源mVideoSource,其实质是一个OMXCodec类型的codec。

   Vector<CodecNameAndQuirks> matchingCodecs;   findMatchingCodecs(mime, createEncoder, matchComponentName, flags, &matchingCodecs);            sp<OMXCodec> codec = new OMXCodec(                    omx, node, quirks, flags,                    createEncoder, mime, componentName,                    source, nativeWindow);            observer->setCodec(codec);            return codec;enum CreationFlags {        kPreferSoftwareCodecs    = 1,        // Request for software or hardware codecs. If request        // can not be fullfilled, Create() returns NULL.        kSoftwareCodecsOnly      = 8,        kHardwareCodecsOnly      = 16,        // Store meta data in video buffers        kStoreMetaDataInVideoBuffers = 32,        // Secure decoding mode        kUseSecureInputBuffers = 256,    };

在创建omx之前还会涉及到软解和硬解,先用一个matchingCodecs来装载匹配的解码器,根据解码内容和解码标志判断是需要硬解还是软解IsSoftwareCodec。如没指明用软解还是硬解,则将所有解码器装入matchingCodecs。

视频解码器设置完毕后,再设置音频解码器,

status_t AwesomePlayer::initAudioDecoder() {    sp<MetaData> meta = mAudioTrack->getFormat();    CHECK(meta->findCString(kKeyMIMEType, &mime));    mOffloadAudio = canOffloadStream(meta, (mVideoSource != NULL),isStreamingHTTP(), streamType);    if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {        ALOGV("createAudioPlayer: bypass OMX (raw)");        mAudioSource = mAudioTrack;    } else {        // If offloading we still create a OMX decoder as a fall-back        // but we don't start it        mOmxSource = OMXCodec::Create(                mClient.interface(), mAudioTrack->getFormat(),                false, // createEncoder                mAudioTrack);        if (mOffloadAudio) {            ALOGV("createAudioPlayer: bypass OMX (offload)");            mAudioSource = mAudioTrack;        } else {            mAudioSource = mOmxSource;        }    }

音频解码器初始化首先检查是否为硬解码的音频流,如果是则不再对其解码,以免重复解码。然后检查下是否为已经解码过的音频流。如果音频流不为原始音频流MEDIA_MIMETYPE_AUDIO_RAW,则需要创建解码器,如果是正着解码的音频流,也需要创建解码器,但不启动它。
音频解码器和视频解码器的创建差不多,这块比较复杂,到OMX时再分析。

解码器创建好之后,修改播放标志位modifyFlags(PREPARING_CONNECTED, SET);并进入finishAsyncPrepare_l();

void AwesomePlayer::finishAsyncPrepare_l() {    if (mIsAsyncPrepare) {        if (mVideoSource == NULL) {            notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);        } else {            notifyVideoSize_l();        }        notifyListener_l(MEDIA_PREPARED);    }    mPrepareResult = OK;    modifyFlags((PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED), CLEAR);    modifyFlags(PREPARED, SET);    mAsyncPrepareEvent = NULL;    mPreparedCondition.broadcast();}

这里notifyVideoSize_l()开始准备视频播放时画面尺寸。主要参数有:
displayWidth、displayHeight、usableWidth、usableHeight、rotationDegrees。

然后发送通知播放器准备就绪,notifyListener_l(MEDIA_PREPARED);是时候播放媒体文件了。

0 0
原创粉丝点击