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

前文分析了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);是时候播放媒体文件了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值