MediaCodec Analyse – config

Refrence: https://source.android.google.cn/devices/media

一 APK调用的核心API

Android APK使用 MediaCodec API 播放音视频的简易流程:

MediaCodec codec = MediaCodec.createDecoderByType("video/avc");
MediaFormat format = MediaFormat.createVideoFormat("video/avc", 320, 480);
codec.configure(format, surface, null, 0);
codec.start();

上一章节,MediaCodec codec = MediaCodec.createDecoderByType("video/avc");已经创建好APK层的MediaCodec对象实例了。在framework层最终在native层的ACodec中,通过omx = client.interface();err = omx->allocateNode(componentName.c_str(), observer, &omxNode);等语句,和OMX进行沟通。

接着就需要对MediaCodec对象实例进行配置了。

codec.configure(format, surface, null, 0);

在java-framework层简单处理一下mediaformat相关变量,调用jni层的 native_configure(...) 函数进行配置。

frameworks\base\media\java\android\media\MediaCodec.java

    public void configure(@Nullable MediaFormat format,@Nullable Surface surface, @Nullable MediaCrypto crypto,@ConfigureFlag int flags) {configure(format, surface, crypto, null, flags);}private void configure(@Nullable MediaFormat format, @Nullable Surface surface,@Nullable MediaCrypto crypto, @Nullable IHwBinder descramblerBinder,@ConfigureFlag int flags) {if (crypto != null && descramblerBinder != null) {throw new IllegalArgumentException("Can't use crypto and descrambler together!");}...... //处理mediaformat相关变量native_configure(keys, values, surface, crypto, descramblerBinder, flags);}private native final void native_configure(@Nullable String[] keys, @Nullable Object[] values,@Nullable Surface surface, @Nullable MediaCrypto crypto,@Nullable IHwBinder descramblerBinder, @ConfigureFlag int flags);

android_media_MediaCodec_native_configure(...)中简单处理了一下MediaFormat相关的变量,就调用JMediaCodec::configure(...),在其中也没太多操作,然后调用native层MediaCodec的config配置函数。

frameworks\base\media\jni\android_media_MediaCodec.cpp

static void android_media_MediaCodec_native_configure(JNIEnv *env,jobject thiz,jobjectArray keys, jobjectArray values,jobject jsurface,jobject jcrypto,jobject descramblerBinderObj,jint flags) {sp<JMediaCodec> codec = getMediaCodec(env, thiz);...... //相关mediaformat变量的处理err = codec->configure(format, bufferProducer, crypto, descrambler, flags);throwExceptionAsNecessary(env, err);
}status_t JMediaCodec::configure(const sp<AMessage> &format,const sp<IGraphicBufferProducer> &bufferProducer,const sp<ICrypto> &crypto,const sp<IDescrambler> &descrambler,int flags) {sp<Surface> client;if (bufferProducer != NULL) {mSurfaceTextureClient =new Surface(bufferProducer, true /* controlledByApp */);} else {mSurfaceTextureClient.clear();}constexpr int32_t CONFIGURE_FLAG_ENCODE = 1;AString mime;CHECK(format->findString("mime", &mime));mGraphicOutput = (mime.startsWithIgnoreCase("video/") || mime.startsWithIgnoreCase("image/"))&& !(flags & CONFIGURE_FLAG_ENCODE);mHasCryptoOrDescrambler = (crypto != nullptr) || (descrambler != nullptr);// 此处的mCodec是native层的MediaCodec对象实例。return mCodec->configure(format, mSurfaceTextureClient, crypto, descrambler, flags);
}

MediaCodec::configure(...)先处理了mediaformat等相关参数变量,然后发送kWhatConfigure消息。

frameworks\av\media\libstagefright\MediaCodec.cpp

status_t MediaCodec::configure(const sp<AMessage> &format,const sp<Surface> &surface,const sp<ICrypto> &crypto,const sp<IDescrambler> &descrambler,uint32_t flags) {sp<AMessage> msg = new AMessage(kWhatConfigure, this);...... //mediametrics相关处理...... //如果是video,把video相关的mediametrics进行设置处理msg->setMessage("format", format);msg->setInt32("flags", flags);msg->setObject("surface", surface);...... //crypto和descrambler的处理// save msg for resetmConfigureMsg = msg;status_t err;std::vector<MediaResourceParcel> resources;resources.push_back(MediaResource::CodecResource(mFlags & kFlagIsSecure, mIsVideo));resources.push_back(MediaResource::GraphicMemoryResource(1));for (int i = 0; i <= kMaxRetry; ++i) {if (i > 0) {// Don't try to reclaim resource for the first time.if (!mResourceManagerProxy->reclaimResource(resources)) {break;}}sp<AMessage> response;err = PostAndAwaitResponse(msg, &response);if (err != OK && err != INVALID_OPERATION) {ALOGE("configure failed with err 0x%08x, resetting...", err);reset();}if (!isResourceError(err)) {break;}}return err;
}

MediaCodec::onMessageReceived(...)case kWhatConfigure中,先处理了mediaformat等相关参数变量,然后调用mCodec->initiateConfigureComponent(format);,即ACodec的initiateConfigureComponent函数。

frameworks\av\media\libstagefright\MediaCodec.cpp

void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {switch (msg->what()) {......case kWhatConfigure:{sp<AReplyToken> replyID;CHECK(msg->senderAwaitsResponse(&replyID));...... //相关mediaformat参数变量的处理mReplyID = replyID;setState(CONFIGURING);...... //crypto和descrambler的处理extractCSD(format); // csd-0、csd-1的处理int32_t tunneled;if (format->findInt32("feature-tunneled-playback", &tunneled) && tunneled != 0) {ALOGI("Configuring TUNNELED video playback.");mTunneled = true;} else {mTunneled = false;}mCodec->initiateConfigureComponent(format);break;}......}
}

ACodec::initiateConfigureComponent(...)只是发送一条kWhatConfigureComponent消息,在ACodec::LoadedState::onMessageReceived(...)case kWhatConfigureComponent中,判断mime是否存在,然后调用mCodec->configureCodec(mime.c_str(), msg);,即ACodec的configureCodec函数。

frameworks\av\media\libstagefright\ACodec.cpp

void ACodec::initiateConfigureComponent(const sp<AMessage> &msg) {msg->setWhat(kWhatConfigureComponent);msg->setTarget(this);msg->post();
}bool ACodec::LoadedState::onMessageReceived(const sp<AMessage> &msg) {bool handled = false;switch (msg->what()) {case ACodec::kWhatConfigureComponent:{onConfigureComponent(msg);handled = true;break;}......}return handled;
}bool ACodec::LoadedState::onConfigureComponent(const sp<AMessage> &msg) {ALOGV("onConfigureComponent");CHECK(mCodec->mOMXNode != NULL);status_t err = OK;AString mime;if (!msg->findString("mime", &mime)) {err = BAD_VALUE;} else {err = mCodec->configureCodec(mime.c_str(), msg);}if (err != OK) {ALOGE("[%s] configureCodec returning error %d", mCodec->mComponentName.c_str(), err);mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err));return false;}mCodec->mCallback->onComponentConfigured(mCodec->mInputFormat, mCodec->mOutputFormat);return true;
}

ACodec::configureCodec(...)中,主要进行下面的步骤:

  • encoder相关参数处理
  • surface(即NativeWindow)的处理
  • 根据media类型进行相关处理

frameworks\av\media\libstagefright\ACodec.cpp

status_t ACodec::configureCodec(const char *mime, const sp<AMessage> &msg) {int32_t encoder;if (!msg->findInt32("encoder", &encoder)) {encoder = false;}sp<AMessage> inputFormat = new AMessage;sp<AMessage> outputFormat = new AMessage;mConfigFormat = msg;mIsEncoder = encoder;mIsVideo = !strncasecmp(mime, "video/", 6);mIsImage = !strncasecmp(mime, "image/", 6);mPortMode[kPortIndexInput] = IOMX::kPortModePresetByteBuffer;mPortMode[kPortIndexOutput] = IOMX::kPortModePresetByteBuffer;status_t err = setComponentRole(encoder /* isEncoder */, mime);if (err != OK) {return err;}OMX_VIDEO_CONTROLRATETYPE bitrateMode;int32_t bitrate = 0, quality;// FLAC encoder or video encoder in constant quality mode doesn't need a// bitrate, other encoders do.if (encoder) {if (mIsVideo || mIsImage) {if (!findVideoBitrateControlInfo(msg, &bitrateMode, &bitrate, &quality)) {return INVALID_OPERATION;}} else if (strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC) && !msg->findInt32("bitrate", &bitrate)) {return INVALID_OPERATION;}}// propagate bitrate to the output so that the muxer has itif (encoder && msg->findInt32("bitrate", &bitrate)) {// Technically ISO spec says that 'bitrate' should be 0 for VBR even though it is the// average bitrate. We've been setting both bitrate and max-bitrate to this same value.outputFormat->setInt32("bitrate", bitrate);outputFormat->setInt32("max-bitrate", bitrate);}int32_t storeMeta;if (encoder) {IOMX::PortMode mode = IOMX::kPortModePresetByteBuffer;if (msg->findInt32("android._input-metadata-buffer-type", &storeMeta) && storeMeta != kMetadataBufferTypeInvalid) {if (storeMeta == kMetadataBufferTypeNativeHandleSource) {mode = IOMX::kPortModeDynamicNativeHandle;} else if (storeMeta == kMetadataBufferTypeANWBuffer || storeMeta == kMetadataBufferTypeGrallocSource) {mode = IOMX::kPortModeDynamicANWBuffer;} else {return BAD_VALUE;}}err = setPortMode(kPortIndexInput, mode);if (err != OK) {return err;}if (mode != IOMX::kPortModePresetByteBuffer) {uint32_t usageBits;if (mOMXNode->getParameter((OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits, &usageBits, sizeof(usageBits)) == OK) {inputFormat->setInt32("using-sw-read-often", !!(usageBits & GRALLOC_USAGE_SW_READ_OFTEN));}}}int32_t lowLatency = 0;if (msg->findInt32("low-latency", &lowLatency)) {err = setLowLatency(lowLatency);if (err != OK) {return err;}}int32_t prependSPSPPS = 0;if (encoder && mIsVideo && msg->findInt32("prepend-sps-pps-to-idr-frames", &prependSPSPPS) && prependSPSPPS != 0) {OMX_INDEXTYPE index;err = mOMXNode->getExtensionIndex("OMX.google.android.index.prependSPSPPSToIDRFrames", &index);if (err == OK) {PrependSPSPPSToIDRFramesParams params;InitOMXParams(&params);params.bEnable = OMX_TRUE;err = mOMXNode->setParameter(index, &params, sizeof(params));}if (err != OK) {ALOGE("Encoder could not be configured to emit SPS/PPS before IDR frames. (err %d)", err);return err;}}// Only enable metadata mode on encoder output if encoder can prepend// sps/pps to idr frames, since in metadata mode the bitstream is in an// opaque handle, to which we don't have access.if (encoder && mIsVideo) {OMX_BOOL enable = (OMX_BOOL) (prependSPSPPS && msg->findInt32("android._store-metadata-in-buffers-output", &storeMeta) && storeMeta != 0);if (mFlags & kFlagIsSecure) {enable = OMX_TRUE;}err = setPortMode(kPortIndexOutput, enable ? IOMX::kPortModePresetSecureBuffer : IOMX::kPortModePresetByteBuffer);if (err != OK) {return err;}if (!msg->findInt64(KEY_REPEAT_PREVIOUS_FRAME_AFTER, &mRepeatFrameDelayUs)) {mRepeatFrameDelayUs = -1LL;}if (!msg->findDouble("time-lapse-fps", &mCaptureFps)) {float captureRate;if (msg->findAsFloat(KEY_CAPTURE_RATE, &captureRate)) {mCaptureFps = captureRate;} else {mCaptureFps = -1.0;}}if (!msg->findInt32(KEY_CREATE_INPUT_SURFACE_SUSPENDED, (int32_t*)&mCreateInputBuffersSuspended)) {mCreateInputBuffersSuspended = false;}}if (encoder && (mIsVideo || mIsImage)) {// only allow 32-bit value, since we pass it as U32 to OMX.if (!msg->findInt64(KEY_MAX_PTS_GAP_TO_ENCODER, &mMaxPtsGapUs)) {mMaxPtsGapUs = 0LL;} else if (mMaxPtsGapUs > INT32_MAX || mMaxPtsGapUs < INT32_MIN) {ALOGW("Unsupported value for max pts gap %lld", (long long) mMaxPtsGapUs);mMaxPtsGapUs = 0LL;}if (!msg->findFloat(KEY_MAX_FPS_TO_ENCODER, &mMaxFps)) {mMaxFps = -1;}// notify GraphicBufferSource to allow backward framesif (mMaxPtsGapUs < 0LL) {mMaxFps = -1;}}// NOTE: we only use native window for video decoderssp<RefBase> obj;bool haveNativeWindow = msg->findObject("native-window", &obj) && obj != NULL && mIsVideo && !encoder;mUsingNativeWindow = haveNativeWindow;if (mIsVideo && !encoder) {inputFormat->setInt32("adaptive-playback", false);int32_t usageProtected;if (msg->findInt32("protected", &usageProtected) && usageProtected) {if (!haveNativeWindow) {ALOGE("protected output buffers must be sent to an ANativeWindow");return PERMISSION_DENIED;}mFlags |= kFlagIsGrallocUsageProtected;mFlags |= kFlagPushBlankBuffersToNativeWindowOnShutdown;}}if (mFlags & kFlagIsSecure) {// use native_handles for secure input bufferserr = setPortMode(kPortIndexInput, IOMX::kPortModePresetSecureBuffer);if (err != OK) {ALOGI("falling back to non-native_handles");setPortMode(kPortIndexInput, IOMX::kPortModePresetByteBuffer);err = OK; // ignore error for now}OMX_INDEXTYPE index;if (mOMXNode->getExtensionIndex("OMX.google.android.index.preregisterMetadataBuffers", &index) == OK) {OMX_CONFIG_BOOLEANTYPE param;InitOMXParams(&param);param.bEnabled = OMX_FALSE;if (mOMXNode->getParameter(index, &param, sizeof(param)) == OK) {if (param.bEnabled == OMX_TRUE) {mFlags |= kFlagPreregisterMetadataBuffers;}}}}if (haveNativeWindow) {sp<ANativeWindow> nativeWindow = static_cast<ANativeWindow *>(static_cast<Surface *>(obj.get()));// START of temporary support for automatic FRC - THIS WILL BE REMOVEDint32_t autoFrc;if (msg->findInt32("auto-frc", &autoFrc)) {bool enabled = autoFrc;OMX_CONFIG_BOOLEANTYPE config;InitOMXParams(&config);config.bEnabled = (OMX_BOOL)enabled;status_t temp = mOMXNode->setConfig((OMX_INDEXTYPE)OMX_IndexConfigAutoFramerateConversion, &config, sizeof(config));if (temp == OK) {outputFormat->setInt32("auto-frc", enabled);} else if (enabled) {ALOGI("codec does not support requested auto-frc (err %d)", temp);}}// END of temporary support for automatic FRCint32_t tunneled;if (msg->findInt32("feature-tunneled-playback", &tunneled) && tunneled != 0) {ALOGI("Configuring TUNNELED video playback.");mTunneled = true;int32_t audioHwSync = 0;if (!msg->findInt32("audio-hw-sync", &audioHwSync)) {ALOGW("No Audio HW Sync provided for video tunnel");}err = configureTunneledVideoPlayback(audioHwSync, nativeWindow);if (err != OK) {ALOGE("configureTunneledVideoPlayback(%d,%p) failed!", audioHwSync, nativeWindow.get());return err;}int32_t maxWidth = 0, maxHeight = 0;if (msg->findInt32("max-width", &maxWidth) &&msg->findInt32("max-height", &maxHeight)) {err = mOMXNode->prepareForAdaptivePlayback(kPortIndexOutput, OMX_TRUE, maxWidth, maxHeight);if (err != OK) {ALOGW("[%s] prepareForAdaptivePlayback failed w/ err %d", mComponentName.c_str(), err);// allow failureerr = OK;} else {inputFormat->setInt32("max-width", maxWidth);inputFormat->setInt32("max-height", maxHeight);inputFormat->setInt32("adaptive-playback", true);}}} else {ALOGV("Configuring CPU controlled video playback.");mTunneled = false;// Explicity reset the sideband handle of the window for// non-tunneled video in case the window was previously used// for a tunneled video playback.err = native_window_set_sideband_stream(nativeWindow.get(), NULL);if (err != OK) {ALOGE("set_sideband_stream(NULL) failed! (err %d).", err);return err;}err = setPortMode(kPortIndexOutput, IOMX::kPortModeDynamicANWBuffer);if (err != OK) {// if adaptive playback has been requested, try JB fallback// NOTE: THIS FALLBACK MECHANISM WILL BE REMOVED DUE TO ITS// LARGE MEMORY REQUIREMENT// we will not do adaptive playback on software accessed// surfaces as they never had to respond to changes in the// crop window, and we don't trust that they will be able to.int usageBits = 0;bool canDoAdaptivePlayback;if (nativeWindow->query(nativeWindow.get(), NATIVE_WINDOW_CONSUMER_USAGE_BITS, &usageBits) != OK) {canDoAdaptivePlayback = false;} else {canDoAdaptivePlayback = (usageBits & (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK)) == 0;}int32_t maxWidth = 0, maxHeight = 0;if (canDoAdaptivePlayback && msg->findInt32("max-width", &maxWidth) && msg->findInt32("max-height", &maxHeight)) {ALOGV("[%s] prepareForAdaptivePlayback(%dx%d)", mComponentName.c_str(), maxWidth, maxHeight);err = mOMXNode->prepareForAdaptivePlayback(kPortIndexOutput, OMX_TRUE, maxWidth, maxHeight);ALOGW_IF(err != OK, "[%s] prepareForAdaptivePlayback failed w/ err %d", mComponentName.c_str(), err);if (err == OK) {inputFormat->setInt32("max-width", maxWidth);inputFormat->setInt32("max-height", maxHeight);inputFormat->setInt32("adaptive-playback", true);}}// allow failureerr = OK;} else {ALOGV("[%s] setPortMode on output to %s succeeded", mComponentName.c_str(), asString(IOMX::kPortModeDynamicANWBuffer));CHECK(storingMetadataInDecodedBuffers());inputFormat->setInt32("adaptive-playback", true);}int32_t push;if (msg->findInt32("push-blank-buffers-on-shutdown", &push) && push != 0) {mFlags |= kFlagPushBlankBuffersToNativeWindowOnShutdown;}}int32_t rotationDegrees;if (msg->findInt32("rotation-degrees", &rotationDegrees)) {mRotationDegrees = rotationDegrees;} else {mRotationDegrees = 0;}}AudioEncoding pcmEncoding = kAudioEncodingPcm16bit;(void)msg->findInt32("pcm-encoding", (int32_t*)&pcmEncoding);// invalid encodings will default to PCM-16bit in setupRawAudioFormat.if (mIsVideo || mIsImage) {// determine need for software rendererbool usingSwRenderer = false;if (haveNativeWindow) {bool requiresSwRenderer = false;OMX_PARAM_U32TYPE param;InitOMXParams(&param);param.nPortIndex = kPortIndexOutput;status_t err = mOMXNode->getParameter((OMX_INDEXTYPE)OMX_IndexParamVideoAndroidRequiresSwRenderer, &param, sizeof(param));if (err == OK && param.nU32 == 1) {requiresSwRenderer = true;}if (mComponentName.startsWith("OMX.google.") || requiresSwRenderer) {usingSwRenderer = true;haveNativeWindow = false;(void)setPortMode(kPortIndexOutput, IOMX::kPortModePresetByteBuffer);} else if (!storingMetadataInDecodedBuffers()) {err = setPortMode(kPortIndexOutput, IOMX::kPortModePresetANWBuffer);if (err != OK) {return err;}}}if (encoder) {err = setupVideoEncoder(mime, msg, outputFormat, inputFormat);} else {err = setupVideoDecoder(mime, msg, haveNativeWindow, usingSwRenderer, outputFormat);}if (err != OK) {return err;}if (haveNativeWindow) {mNativeWindow = static_cast<Surface *>(obj.get());// fallback for devices that do not handle flex-YUV for native buffersint32_t requestedColorFormat = OMX_COLOR_FormatUnused;if (msg->findInt32("color-format", &requestedColorFormat) && requestedColorFormat == OMX_COLOR_FormatYUV420Flexible) {status_t err = getPortFormat(kPortIndexOutput, outputFormat);if (err != OK) {return err;}int32_t colorFormat = OMX_COLOR_FormatUnused;OMX_U32 flexibleEquivalent = OMX_COLOR_FormatUnused;if (!outputFormat->findInt32("color-format", &colorFormat)) {ALOGE("ouptut port did not have a color format (wrong domain?)");return BAD_VALUE;}ALOGD("[%s] Requested output format %#x and got %#x.", mComponentName.c_str(), requestedColorFormat, colorFormat);if (!IsFlexibleColorFormat(mOMXNode, colorFormat, haveNativeWindow, &flexibleEquivalent) || flexibleEquivalent != (OMX_U32)requestedColorFormat) {// device did not handle flex-YUV request for native window, fall back// to SW rendererALOGI("[%s] Falling back to software renderer", mComponentName.c_str());mNativeWindow.clear();mNativeWindowUsageBits = 0;haveNativeWindow = false;usingSwRenderer = true;// TODO: implement adaptive-playback support for bytebuffer mode.// This is done by SW codecs, but most HW codecs don't support it.err = setPortMode(kPortIndexOutput, IOMX::kPortModePresetByteBuffer);inputFormat->setInt32("adaptive-playback", false);if (mFlags & kFlagIsGrallocUsageProtected) {// fallback is not supported for protected playbackerr = PERMISSION_DENIED;} else if (err == OK) {err = setupVideoDecoder(mime, msg, haveNativeWindow, usingSwRenderer, outputFormat);}}}}if (usingSwRenderer) {outputFormat->setInt32("using-sw-renderer", 1);}} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG) || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II)) {int32_t numChannels, sampleRate;if (!msg->findInt32("channel-count", &numChannels) || !msg->findInt32("sample-rate", &sampleRate)) {// Since we did not always check for these, leave them optional// and have the decoder figure it all out.err = OK;} else {err = setupRawAudioFormat(encoder ? kPortIndexInput : kPortIndexOutput,sampleRate,numChannels);}} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {int32_t numChannels, sampleRate;if (!msg->findInt32("channel-count", &numChannels) || !msg->findInt32("sample-rate", &sampleRate)) {err = INVALID_OPERATION;} else {int32_t isADTS, aacProfile;int32_t sbrMode;int32_t maxOutputChannelCount;int32_t pcmLimiterEnable;drcParams_t drc;if (!msg->findInt32("is-adts", &isADTS)) {isADTS = 0;}if (!msg->findInt32("aac-profile", &aacProfile)) {aacProfile = OMX_AUDIO_AACObjectNull;}if (!msg->findInt32("aac-sbr-mode", &sbrMode)) {sbrMode = -1;}if (!msg->findInt32("aac-max-output-channel_count", &maxOutputChannelCount)) {maxOutputChannelCount = -1;}if (!msg->findInt32("aac-pcm-limiter-enable", &pcmLimiterEnable)) {// value is unknownpcmLimiterEnable = -1;}if (!msg->findInt32("aac-encoded-target-level", &drc.encodedTargetLevel)) {// value is unknowndrc.encodedTargetLevel = -1;}if (!msg->findInt32("aac-drc-cut-level", &drc.drcCut)) {// value is unknowndrc.drcCut = -1;}if (!msg->findInt32("aac-drc-boost-level", &drc.drcBoost)) {// value is unknowndrc.drcBoost = -1;}if (!msg->findInt32("aac-drc-heavy-compression", &drc.heavyCompression)) {// value is unknowndrc.heavyCompression = -1;}if (!msg->findInt32("aac-target-ref-level", &drc.targetRefLevel)) {// value is unknowndrc.targetRefLevel = -2;}if (!msg->findInt32("aac-drc-effect-type", &drc.effectType)) {// value is unknowndrc.effectType = -2; // valid values are -1 and over}if (!msg->findInt32("aac-drc-album-mode", &drc.albumMode)) {// value is unknowndrc.albumMode = -1; // valid values are 0 and 1}if (!msg->findInt32("aac-drc-output-loudness", &drc.outputLoudness)) {// value is unknowndrc.outputLoudness = -1;}err = setupAACCodec(encoder, numChannels, sampleRate, bitrate, aacProfile,isADTS != 0, sbrMode, maxOutputChannelCount, drc,pcmLimiterEnable);}} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)) {err = setupAMRCodec(encoder, false /* isWAMR */, bitrate);} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {err = setupAMRCodec(encoder, true /* isWAMR */, bitrate);} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_G711_ALAW)|| !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_G711_MLAW)) {// These are PCM-like formats with a fixed sample rate but// a variable number of channels.int32_t numChannels;if (!msg->findInt32("channel-count", &numChannels)) {err = INVALID_OPERATION;} else {int32_t sampleRate;if (!msg->findInt32("sample-rate", &sampleRate)) {sampleRate = 8000;}err = setupG711Codec(encoder, sampleRate, numChannels);}} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC)) {// numChannels needs to be set to properly communicate PCM values.int32_t numChannels = 2, sampleRate = 44100, compressionLevel = -1;if (encoder && (!msg->findInt32("channel-count", &numChannels) || !msg->findInt32("sample-rate", &sampleRate))) {ALOGE("missing channel count or sample rate for FLAC encoder");err = INVALID_OPERATION;} else {if (encoder) {if (!msg->findInt32("complexity", &compressionLevel) &&!msg->findInt32("flac-compression-level", &compressionLevel)) {compressionLevel = 5; // default FLAC compression level} else if (compressionLevel < 0) {ALOGW("compression level %d outside [0..8] range, ""using 0",compressionLevel);compressionLevel = 0;} else if (compressionLevel > 8) {ALOGW("compression level %d outside [0..8] range, ""using 8",compressionLevel);compressionLevel = 8;}}err = setupFlacCodec(encoder, numChannels, sampleRate, compressionLevel, pcmEncoding);}} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {int32_t numChannels, sampleRate;if (encoder|| !msg->findInt32("channel-count", &numChannels)|| !msg->findInt32("sample-rate", &sampleRate)) {err = INVALID_OPERATION;} else {err = setupRawAudioFormat(kPortIndexInput, sampleRate, numChannels, pcmEncoding);}} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AC3)) {int32_t numChannels;int32_t sampleRate;if (!msg->findInt32("channel-count", &numChannels)|| !msg->findInt32("sample-rate", &sampleRate)) {err = INVALID_OPERATION;} else {err = setupAC3Codec(encoder, numChannels, sampleRate);}} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_EAC3)) {int32_t numChannels;int32_t sampleRate;if (!msg->findInt32("channel-count", &numChannels)|| !msg->findInt32("sample-rate", &sampleRate)) {err = INVALID_OPERATION;} else {err = setupEAC3Codec(encoder, numChannels, sampleRate);}} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AC4)) {int32_t numChannels;int32_t sampleRate;if (!msg->findInt32("channel-count", &numChannels)|| !msg->findInt32("sample-rate", &sampleRate)) {err = INVALID_OPERATION;} else {err = setupAC4Codec(encoder, numChannels, sampleRate);}}if (err != OK) {return err;}if (!msg->findInt32("encoder-delay", &mEncoderDelay)) {mEncoderDelay = 0;}if (!msg->findInt32("encoder-padding", &mEncoderPadding)) {mEncoderPadding = 0;}if (msg->findInt32("channel-mask", &mChannelMask)) {mChannelMaskPresent = true;} else {mChannelMaskPresent = false;}int32_t maxInputSize;if (msg->findInt32("max-input-size", &maxInputSize)) {err = setMinBufferSize(kPortIndexInput, (size_t)maxInputSize);err = OK; // ignore error} else if (!strcmp("OMX.Nvidia.aac.decoder", mComponentName.c_str())) {err = setMinBufferSize(kPortIndexInput, 8192);  // XXXerr = OK; // ignore error}int32_t priority;if (msg->findInt32("priority", &priority)) {err = setPriority(priority);err = OK; // ignore error}int32_t rateInt = -1;float rateFloat = -1;if (!msg->findFloat("operating-rate", &rateFloat)) {msg->findInt32("operating-rate", &rateInt);rateFloat = (float)rateInt;  // 16MHz (FLINTMAX) is OK for upper bound.}if (rateFloat > 0) {err = setOperatingRate(rateFloat, mIsVideo);err = OK; // ignore errors}if (err == OK) {err = setVendorParameters(msg);if (err != OK) {return err;}}// NOTE: both mBaseOutputFormat and mOutputFormat are outputFormat to signal first frame.mBaseOutputFormat = outputFormat;mLastOutputFormat.clear();err = getPortFormat(kPortIndexInput, inputFormat);if (err == OK) {err = getPortFormat(kPortIndexOutput, outputFormat);if (err == OK) {mInputFormat = inputFormat;mOutputFormat = outputFormat;}}// create data converters if neededif (!mIsVideo && !mIsImage && err == OK) {AudioEncoding codecPcmEncoding = kAudioEncodingPcm16bit;if (encoder) {(void)mInputFormat->findInt32("pcm-encoding", (int32_t*)&codecPcmEncoding);mConverter[kPortIndexInput] = AudioConverter::Create(pcmEncoding, codecPcmEncoding);if (mConverter[kPortIndexInput] != NULL) {ALOGD("%s: encoder %s input format pcm encoding converter from %d to %d",__func__, mComponentName.c_str(), pcmEncoding, codecPcmEncoding);mInputFormat->setInt32("pcm-encoding", pcmEncoding);}} else {(void)mOutputFormat->findInt32("pcm-encoding", (int32_t*)&codecPcmEncoding);mConverter[kPortIndexOutput] = AudioConverter::Create(codecPcmEncoding, pcmEncoding);if (mConverter[kPortIndexOutput] != NULL) {ALOGD("%s: decoder %s output format pcm encoding converter from %d to %d",__func__, mComponentName.c_str(), codecPcmEncoding, pcmEncoding);mOutputFormat->setInt32("pcm-encoding", pcmEncoding);}}}return err;
}

config完成后,通过mCodec->mCallback->onComponentConfigured(mCodec->mInputFormat, mCodec->mOutputFormat);调用MediaCodec的void CodecCallback::onComponentConfigured(...)

frameworks\av\media\libstagefright\MediaCodec.cpp

void CodecCallback::onComponentConfigured(const sp<AMessage> &inputFormat, const sp<AMessage> &outputFormat) {sp<AMessage> notify(mNotify->dup());notify->setInt32("what", kWhatComponentConfigured);notify->setMessage("input-format", inputFormat);notify->setMessage("output-format", outputFormat);notify->post();
}void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {switch (msg->what()) {case kWhatCodecNotify:{int32_t what;CHECK(msg->findInt32("what", &what));switch (what) {......case kWhatComponentConfigured:{if (mState == RELEASING || mState == UNINITIALIZED || mState == INITIALIZED) {// In case a kWhatError or kWhatRelease message came in and replied,// we log a warning and ignore.ALOGW("configure interrupted by error or release, current state %d",mState);break;}CHECK_EQ(mState, CONFIGURING);// reset input surface flagmHaveInputSurface = false;CHECK(msg->findMessage("input-format", &mInputFormat));CHECK(msg->findMessage("output-format", &mOutputFormat));// limit to confirming the opt-in behavior to minimize any behavioral changeif (mSurface != nullptr && !mAllowFrameDroppingBySurface) {// signal frame dropping mode in the input format as this may also be// meaningful and confusing for an encoder in a transcoder scenariomInputFormat->setInt32("allow-frame-drop", mAllowFrameDroppingBySurface);}sp<AMessage> interestingFormat = (mFlags & kFlagIsEncoder) ? mOutputFormat : mInputFormat;ALOGV("[%s] configured as input format: %s, output format: %s",mComponentName.c_str(),mInputFormat->debugString(4).c_str(),mOutputFormat->debugString(4).c_str());int32_t usingSwRenderer;if (mOutputFormat->findInt32("using-sw-renderer", &usingSwRenderer) && usingSwRenderer) {mFlags |= kFlagUsesSoftwareRenderer;}setState(CONFIGURED);(new AMessage)->postReply(mReplyID);// augment our media metrics info, now that we know more things// such as what the codec extracted from any CSD passed in.if (mMetricsHandle != 0) {sp<AMessage> format;if (mConfigureMsg != NULL &&mConfigureMsg->findMessage("format", &format)) {// format includes: mimeAString mime;if (format->findString("mime", &mime)) {mediametrics_setCString(mMetricsHandle, kCodecMime, mime.c_str());}}// perhaps video only?int32_t profile = 0;if (interestingFormat->findInt32("profile", &profile)) {mediametrics_setInt32(mMetricsHandle, kCodecProfile, profile);}int32_t level = 0;if (interestingFormat->findInt32("level", &level)) {mediametrics_setInt32(mMetricsHandle, kCodecLevel, level);}// bitrate and bitrate mode, encoder onlyif (mFlags & kFlagIsEncoder) {// encoder specific valuesint32_t bitrate_mode = -1;if (mOutputFormat->findInt32(KEY_BITRATE_MODE, &bitrate_mode)) {mediametrics_setCString(mMetricsHandle, kCodecBitrateMode,asString_BitrateMode(bitrate_mode));}int32_t bitrate = -1;if (mOutputFormat->findInt32(KEY_BIT_RATE, &bitrate)) {mediametrics_setInt32(mMetricsHandle, kCodecBitrate, bitrate);}} else {// decoder specific values}}break;}}...}...}
}

MediaCodec_Analyze-2-config相关推荐

  1. SpringCloud Alibaba微服务实战(四) - Nacos Config 配置中心

    说在前面 Nacos 是阿里巴巴开源的一个更易于构建云原生应用的动态服务发现.配置管理和服务管理平台.Nacos Config就是一个类似于SpringCloud Config的配置中心. 一.启动N ...

  2. Bad owner or permissions on xx/.ssh/config

    这个问题是服务器上面拉代码的时候遇到的问题 处理方法就是给config 添加权限 由于在在自己的服务器上面前面就不用添加sudo 了,直接执行:chmod 600 config 回车 添加权限之后 r ...

  3. 玩转Spring Cloud之配置中心(config server config client)

    玩转Spring Cloud之配置中心(config server &config client)  本文内容导航: 一.搭建配置服务中心(config server) 1.1.git方式 1 ...

  4. VS中C#读取app.config数据库配置字符串的三种方法(转)

    关于VS2008或VS2005中数据库配置字符串的三种取法 VS2008建立Form程序时,如果添加数据源会在配置文件 app.config中自动写入连接字符串,这个字符串将会在你利用DataSet, ...

  5. mysql配置文件没有spring_spring cloud config使用mysql存储配置文件

    spring cloud config使用mysql存储配置文件 1.结构图 2.pom.xml: 4.0.0 com.didispace config-server-db 1.0.0 jar con ...

  6. 解决微信H5获取SDK授权报错提示errMsg: “config:fail,Error: 系统错误,错误码:63002,invalid signature [20200908 22:17:17][]“

    如果常规检查都做过可以仔细看下微信开放文档 这个里面的报错原因 如果都不是那么极有可能是(恭喜你!看样子你的H5页面日活人数还蛮多[呲牙]) 获取腾讯微信平台access_token超过每日默认上限2 ...

  7. ATS上的hosting.config和volume.config文件解读

    为了更加灵活和精细地规划缓存磁盘的空间使用,我们可以更进一步地使用hosting.config和volume.config文件.   hosting.config 描述域名和分卷的对应关系: host ...

  8. ATS 5.3.0中parent.config配置文件解读

    该博文翻译自参考文献[1] parent.config parent.config文件识别用在缓存分级中的父代理,用这个文件去执行下面的配置: 搭建父分级缓存,兼容多父级缓存和父级缓存故障转移 配置指 ...

  9. ATS 5.3.0中按域名生成日志配置文件log_hosts.config解读

    应用场景 该配置文件用于ATS用作反向代理模式,访问日志被server域名分隔.比如,我想将sohu和ifeng的域名的日志分别记在两个不同的日志文件中,其它的日志统一记在默认的日志文件中. 配置 为 ...

  10. ATS 5.3.0中自定义日志格式文件logs_xml.config解读

    缘起 近来因为公司项目需要,阅读了一部分ATS logging system的源码实现,越发觉得logs_xml.config文件的配置非常重要,而我目前只是实践了一点它的皮毛.为此,根据自己的理解, ...

最新文章

  1. 给定一个数组,求如果排序之后,相邻两数的最大差值,要求时间复杂度O(N),且要求不能用非基于比较的排序。
  2. 现代软件工程系列 学生的精彩文章 (3) 如何在Bug 不断的情况下还能保持平常心...
  3. imgaug批量椒盐噪声 python_python手写给图像加椒盐噪声和高斯噪声
  4. 通过脚本设置Windows系统ip地址
  5. 解决int和Integer不能互转
  6. CSDN内核模块编译讨论(总结)
  7. 小猿圈WEB前端之HTML5+CSS3面试题(一)
  8. 城建坐标与经纬度转换工具
  9. FreePiano下载与使用
  10. ZedGraph绘图
  11. 无论计算机有多强大、攻击者多么聪明都无法破解的密码:一次一密
  12. 睿智的目标检测51——Tensorflow2搭建yolo3目标检测平台
  13. EditText属性整理
  14. 六大设计原则----依赖倒置原则
  15. 欧盟 | 地平线 2020 ENSEMBLE:D2.13 SOTIF Safety Concept(上)
  16. 使用TIBCO Rendezvous发送hello world,实现监听和发送
  17. 使用Chrome开发者工具精确定位网页元素位置
  18. 基于STM32F429动态信号测试分析系统
  19. 异贝,移动互联网技术,为中小微实体企业联盟、线上链接、线上线下自定义营销方案推送。案例42
  20. sql 语句中count()有条件的时候为什么要加上or null

热门文章

  1. 什么是真正的骨传导耳机,五款真骨传导耳机推荐
  2. Java版色情图像过滤入门示例及源码-0 1 0 (模拟绿坝过滤机制)
  3. 【CVPR 2021】DatasetGAN: Efficient Labeled Data Factory with Minimal Human Effort
  4. 汤晓丹的第四版计算机操作系统--第三章总结概述
  5. ROS control-----controller_manager简介
  6. AEC行业那些开源的软件在这里
  7. 第二十三课.扩散模型
  8. SQL四舍五入与截断 除余
  9. C# 服务端(API)连接 安卓设备 读取 IC卡(仅读取ID),RFID卡(包含ID卡),获取卡号(10进制)
  10. hdu 4997 Biconnected