播放媒體檔案找到對應解碼器元件的過程
以下程式碼流程為一個媒體檔案解碼時找到對應外掛的流程:
函式 status_t NuPlayer::instantiateDecoder(boolaudio, sp<DecoderBase> *decoder) 函式初始化建立解碼器
status_t NuPlayer::instantiateDecoder(boolaudio, sp<DecoderBase> *decoder) {
if (*decoder != NULL) {
return OK;
}
……
if (audio) {
sp<AMessage> notify = new AMessage(kWhatAudioNotify, id());
++mAudioDecoderGeneration;
notify->setInt32("generation", mAudioDecoderGeneration);
if (mOffloadAudio) {
*decoder = new DecoderPassThrough(notify, mSource, mRenderer);
} else {
*decoder = new Decoder(notify, mSource, mRenderer);
}
}else {
sp<AMessage> notify = new AMessage(kWhatVideoNotify, id());
++mVideoDecoderGeneration;
notify->setInt32("generation", mVideoDecoderGeneration);
*decoder = new Decoder(
notify, mSource, mRenderer,mNativeWindow, mCCDecoder);
// enable FRC if high-quality AV sync isrequested, even if not
// queuing to native window, 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);
}
}
}
if (mPlayerExtendedStats != NULL) {
format->setObject(MEDIA_EXTENDED_STATS, mPlayerExtendedStats);
}
(*decoder)->init();
(*decoder)->configure(format, mIsStreaming);
……
……
}
void NuPlayer::DecoderBase::configure(constsp<AMessage> &format, bool isStreaming) {
sp<AMessage> msg = new AMessage(kWhatConfigure, id());
msg->setMessage("format", format);
msg->setInt32("isStreaming", isStreaming);
sp<AMessage> response;
PostAndAwaitResponse(msg, &response);
}
voidNuPlayer::DecoderBase::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
case kWhatConfigure:
{
uint32_t replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
sp<AMessage> format;
uint32_t isStreaming;
CHECK(msg->findMessage("format", &format));
CHECK(msg->findInt32("isStreaming", (int32_t*)&isStreaming));
onConfigure(format,isStreaming);
(new AMessage)->postReply(replyID);
break;
}
voidNuPlayer::Decoder::onConfigure(const sp<AMessage> &format, boolisStreaming) {
CHECK(mCodec == NULL);
……
ExtendedCodec::overrideMimeType(format, &mime);
/* time allocateNode here */
{
if (mPlayerExtendedStats == NULL) {
format->findObject(MEDIA_EXTENDED_STATS,(sp<RefBase>*)&mPlayerExtendedStats);
}
int32_t isVideo = !strncasecmp(mime.c_str(), "video/", 6);
ExtendedStats::AutoProfile autoProfile(
STATS_PROFILE_ALLOCATE_NODE(isVideo),mPlayerExtendedStats);
mCodec = MediaCodec::CreateByType(mCodecLooper,mime.c_str(), false /* encoder */);
}
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());
}
}
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 (mNativeWindow != NULL) {
// disconnect from surface asMediaCodec will reconnect
err = native_window_api_disconnect(
surface.get(), NATIVE_WINDOW_API_MEDIA);
// We treat this as a warning, as thisis a preparatory step.
// Codec will try to connect to thesurface, which is where
// any error signaling will occur.
ALOGW_IF(err != OK, "failed todisconnect from surface: %d", err);
}
if (mPlayerExtendedStats != NULL) {
format->setObject(MEDIA_EXTENDED_STATS, mPlayerExtendedStats);
}
err =mCodec->configure(
format,surface, NULL /* crypto */, 0 /* flags */);
if (err != OK) {
ALOGE("Failed to configure %sdecoder (err=%d)", mComponentName.c_str(), err);
mCodec->release();
mCodec.clear();
handleError(err);
return;
}
rememberCodecSpecificData(format);
// the following should work in configuredstate
CHECK_EQ((status_t)OK,mCodec->getInputFormat(&mInputFormat));
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;
}
// the following should work after start
CHECK_EQ((status_t)OK,mCodec->getInputBuffers(&mInputBuffers));
releaseAndResetMediaBuffers();
CHECK_EQ((status_t)OK,mCodec->getOutputBuffers(&mOutputBuffers));
ALOGV("[%s] got %zu input and %zuoutput buffers",
mComponentName.c_str(),
mInputBuffers.size(),
mOutputBuffers.size());
if (mRenderer != NULL) {
requestCodecNotification();
}
mPaused = false;
mResumePending = false;
}
sp<MediaCodec> MediaCodec::CreateByType(
const sp<ALooper> &looper,const char *mime, bool encoder, status_t *err) {
sp<MediaCodec> codec = newMediaCodec(looper);
const status_t ret = codec->init(mime,true /* nameIsType */, encoder);
if (err != NULL) {
*err = ret;
}
return ret == OK ? codec : NULL; // NULLdeallocates codec.
}
void MediaCodec::onMessageReceived(const sp<AMessage>&msg) {
switch (msg->what()) {
case kWhatCodecNotify:
{
…
case kWhatInit:
{
uint32_t 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 = newAMessage;
if (nameIsType) {
format->setString("mime", name.c_str());
format->setInt32("encoder", encoder);
} else {
format->setString("componentName",name.c_str());
}
mCodec->initiateAllocateComponent(format);
break;
……
}
void ACodec::initiateAllocateComponent(const sp<AMessage>&msg) {
msg->setWhat(kWhatAllocateComponent);
msg->setTarget(id());
msg->post();
}
bool ACodec::UninitializedState::onAllocateComponent(constsp<AMessage> &msg) {
ALOGV("onAllocateComponent");
ATRACE_NAME("onAllocatecomponent");
……
#ifdefENABLE_AV_ENHANCEMENTS
// Call UseQCHWAACEncoder with no argumentsto get the correct state since
// MediaCodecSource does not pass theoutput format details when calling
// kInit leading to msg passed not havingenough details
if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_AUDIO_AAC)
&&ExtendedUtils::UseQCHWAACEncoder()) {
//use hw aac encoder
ALOGD("use QCOM HW AACencoder");
OMXCodec::findMatchingCodecs(
mime.c_str(),
encoder, // createEncoder
"OMX.qcom.audio.encoder.aac", // OMX.qcom.audio.encoder.aac
0, // flags
&matchingCodecs);
} else if (!strcasecmp(mime.c_str(),MEDIA_MIMETYPE_AUDIO_FLAC) && !encoder) {
//use google's raw decoder
OMXCodec::findMatchingCodecs(
MEDIA_MIMETYPE_AUDIO_RAW,
encoder, //createEncoder
"OMX.google.raw.decoder",
0, //flags
&matchingCodecs);
} else
OMXCodec::findMatchingCodecs(
mime.c_str(),
encoder, // createEncoder
NULL, // matchComponentName
0, // flags
&matchingCodecs);
#else
OMXCodec::findMatchingCodecs(
mime.c_str(),
encoder, // createEncoder
NULL, // matchComponentName
0, // flags
&matchingCodecs);
#endif
}
sp<CodecObserver> observer = newCodecObserver;
IOMX::node_id node = NULL;
for (size_t matchIndex = 0; matchIndex <matchingCodecs.size();
++matchIndex) {
componentName =matchingCodecs.itemAt(matchIndex).mName.string();
quirks =matchingCodecs.itemAt(matchIndex).mQuirks;
ExtendedCodec::overrideComponentName(quirks, msg, &componentName,&mime, encoder);
pid_t tid = androidGetTid();
int prevPriority =androidGetThreadPriority(tid);
androidSetThreadPriority(tid,ANDROID_PRIORITY_FOREGROUND);
status_t err = omx->allocateNode(componentName.c_str(), observer, &node);
androidSetThreadPriority(tid,prevPriority);
……
}
status_t OMX::allocateNode(
const char *name, constsp<IOMXObserver> &observer, node_id *node) {
Mutex::Autolock autoLock(mLock);
*node = 0;
OMXNodeInstance *instance = newOMXNodeInstance(this, observer, name);
OMX_COMPONENTTYPE *handle;
OMX_ERRORTYPE err =mMaster->makeComponentInstance(
name,&OMXNodeInstance::kCallbacks,
instance,&handle);
if (err != OMX_ErrorNone) {
ALOGE("FAILED to allocate omxcomponent '%s'", name);
instance->onGetHandleFailed();
return UNKNOWN_ERROR;
}
*node = makeNodeID(instance);
mDispatchers.add(*node, newCallbackDispatcher(instance));
instance->setHandle(*node, handle);
mLiveNodes.add(observer->asBinder(),instance);
observer->asBinder()->linkToDeath(this);
return OK;
}
OMX_ERRORTYPE OMXMaster::makeComponentInstance(
const char *name,
const OMX_CALLBACKTYPE *callbacks,
OMX_PTR appData,
OMX_COMPONENTTYPE **component) {
Mutex::Autolock autoLock(mLock);
*component = NULL;
ssize_t index = mPluginByComponentName.indexOfKey(String8(name));
if (index < 0) {
return OMX_ErrorInvalidComponentName;
}
OMXPluginBase *plugin =mPluginByComponentName.valueAt(index);
OMX_ERRORTYPE err =
plugin->makeComponentInstance(name, callbacks, appData, component);
if (err != OMX_ErrorNone) {
return err;
}
mPluginByInstance.add(*component, plugin);
return err;
}
OMX_ERRORTYPESoftOMXPlugin::makeComponentInstance(
const char *name,
const OMX_CALLBACKTYPE *callbacks,
OMX_PTR appData,
OMX_COMPONENTTYPE **component) {
ALOGV("makeComponentInstance'%s'", name);
……
CreateSoftOMXComponentFunccreateSoftOMXComponent =
(CreateSoftOMXComponentFunc)dlsym(
libHandle,
"_Z22createSoftOMXComponentPKcPK16OMX_CALLBACKTYPE"
"PvPP17OMX_COMPONENTTYPE");
if (createSoftOMXComponent == NULL) {
dlclose(libHandle);
libHandle = NULL;
return OMX_ErrorComponentNotFound;
}
sp<SoftOMXComponent> codec =
(*createSoftOMXComponent)(name, callbacks, appData, component);
if (codec == NULL) {
dlclose(libHandle);
libHandle = NULL;
returnOMX_ErrorInsufficientResources;
}
OMX_ERRORTYPE err =codec->initCheck();
if (err != OMX_ErrorNone) {
dlclose(libHandle);
……
}