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