diff options
Diffstat (limited to 'media/libstagefright/ACodec.cpp')
-rw-r--r-- | media/libstagefright/ACodec.cpp | 410 |
1 files changed, 354 insertions, 56 deletions
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index cd2408b..581bfba 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -44,6 +44,9 @@ #include <media/stagefright/OMXCodec.h> #include <media/stagefright/PersistentSurface.h> #include <media/stagefright/SurfaceUtils.h> +#include <media/stagefright/FFMPEGSoftCodec.h> +#include <media/stagefright/Utils.h> + #include <media/hardware/HardwareAPI.h> #include <OMX_AudioExt.h> @@ -52,8 +55,14 @@ #include <OMX_IndexExt.h> #include <OMX_AsString.h> +#ifdef USE_SAMSUNG_COLORFORMAT +#include <sec_format.h> +#endif + #include "include/avc_utils.h" +#include <stagefright/AVExtensions.h> + namespace android { // OMX errors are directly mapped into status_t range if @@ -497,6 +506,8 @@ ACodec::ACodec() mSentFormat(false), mIsVideo(false), mIsEncoder(false), + mEncoderComponent(false), + mComponentAllocByName(false), mFatalError(false), mShutdownInProgress(false), mExplicitShutdown(false), @@ -539,6 +550,10 @@ ACodec::ACodec() ACodec::~ACodec() { } +status_t ACodec::setupCustomCodec(status_t err, const char * /*mime*/, const sp<AMessage> &/*msg*/) { + return err; +} + void ACodec::setNotificationMessage(const sp<AMessage> &msg) { mNotify = msg; } @@ -613,8 +628,8 @@ void ACodec::initiateShutdown(bool keepComponentAllocated) { msg->setInt32("keepComponentAllocated", keepComponentAllocated); msg->post(); if (!keepComponentAllocated) { - // ensure shutdown completes in 3 seconds - (new AMessage(kWhatReleaseCodecInstance, this))->post(3000000); + // ensure shutdown completes in 30 seconds + (new AMessage(kWhatReleaseCodecInstance, this))->post(30000000); } } @@ -716,7 +731,7 @@ status_t ACodec::handleSetSurface(const sp<Surface> &surface) { if (storingMetadataInDecodedBuffers() && !mLegacyAdaptiveExperiment && info.mStatus == BufferInfo::OWNED_BY_NATIVE_WINDOW) { - ALOGV("skipping buffer %p", info.mGraphicBuffer->getNativeBuffer()); + ALOGV("skipping buffer %p", info.mGraphicBuffer.get() ? info.mGraphicBuffer->getNativeBuffer() : 0x0); continue; } ALOGV("attaching buffer %p", info.mGraphicBuffer->getNativeBuffer()); @@ -752,7 +767,8 @@ status_t ACodec::handleSetSurface(const sp<Surface> &surface) { } // push blank buffers to previous window if requested - if (mFlags & kFlagPushBlankBuffersToNativeWindowOnShutdown) { + if (mFlags & kFlagPushBlankBuffersToNativeWindowOnShutdown || + mFlags & kFlagPushBlankBuffersToNativeWindowOnSwitch) { pushBlankBuffersToNativeWindow(mNativeWindow.get()); } @@ -828,15 +844,11 @@ status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) { : OMXCodec::kRequiresAllocateBufferOnOutputPorts; if ((portIndex == kPortIndexInput && (mFlags & kFlagIsSecure)) - || (portIndex == kPortIndexOutput && usingMetadataOnEncoderOutput())) { + || (portIndex == kPortIndexOutput && usingMetadataOnEncoderOutput()) + || canAllocateBuffer(portIndex)) { mem.clear(); - void *ptr; - err = mOMX->allocateBuffer( - mNode, portIndex, bufSize, &info.mBufferID, - &ptr); - - info.mData = new ABuffer(ptr, bufSize); + err = allocateBuffer(portIndex, bufSize, info); } else if (mQuirks & requiresAllocateBufferBit) { err = mOMX->allocateBufferWithBackup( mNode, portIndex, mem, &info.mBufferID, allottedSize); @@ -908,14 +920,57 @@ status_t ACodec::setupNativeWindowSizeFormatAndUsage( usage |= kVideoGrallocUsage; *finalUsage = usage; +#ifdef USE_SAMSUNG_COLORFORMAT + OMX_COLOR_FORMATTYPE eNativeColorFormat = def.format.video.eColorFormat; + setNativeWindowColorFormat(eNativeColorFormat); +#endif + ALOGV("gralloc usage: %#x(OMX) => %#x(ACodec)", omxUsage, usage); - return setNativeWindowSizeFormatAndUsage( + int32_t width = 0, height = 0; + int32_t isAdaptivePlayback = 0; + + if (mInputFormat->findInt32("adaptive-playback", &isAdaptivePlayback) + && isAdaptivePlayback + && mInputFormat->findInt32("max-width", &width) + && mInputFormat->findInt32("max-height", &height)) { + width = max(width, (int32_t)def.format.video.nFrameWidth); + height = max(height, (int32_t)def.format.video.nFrameHeight); + ALOGV("Adaptive playback width = %d, height = %d", width, height); + } else { + width = def.format.video.nFrameWidth; + height = def.format.video.nFrameHeight; + } + err = setNativeWindowSizeFormatAndUsage( nativeWindow, - def.format.video.nFrameWidth, - def.format.video.nFrameHeight, + width, + height, +#ifdef USE_SAMSUNG_COLORFORMAT + eNativeColorFormat, +#else def.format.video.eColorFormat, +#endif mRotationDegrees, usage); +#ifdef QCOM_HARDWARE + if (err == OK) { + OMX_CONFIG_RECTTYPE rect; + InitOMXParams(&rect); + rect.nPortIndex = kPortIndexOutput; + err = mOMX->getConfig( + mNode, OMX_IndexConfigCommonOutputCrop, &rect, sizeof(rect)); + if (err == OK) { + ALOGV("rect size = %d, %d, %d, %d", rect.nLeft, rect.nTop, rect.nWidth, rect.nHeight); + android_native_rect_t crop; + crop.left = rect.nLeft; + crop.top = rect.nTop; + crop.right = rect.nLeft + rect.nWidth - 1; + crop.bottom = rect.nTop + rect.nHeight - 1; + ALOGV("crop update (%d, %d), (%d, %d)", crop.left, crop.top, crop.right, crop.bottom); + err = native_window_set_crop(nativeWindow, &crop); + } + } +#endif + return err; } status_t ACodec::configureOutputBuffersFromNativeWindow( @@ -974,6 +1029,12 @@ status_t ACodec::configureOutputBuffersFromNativeWindow( // 2. try to allocate two (2) additional buffers to reduce starvation from // the consumer // plus an extra buffer to account for incorrect minUndequeuedBufs +#ifdef BOARD_CANT_REALLOCATE_OMX_BUFFERS + // Some devices don't like to set OMX_IndexParamPortDefinition at this + // point (even with an unmodified def), so skip it if possible. + // This check was present in KitKat. + if (def.nBufferCountActual < def.nBufferCountMin + *minUndequeuedBuffers) { +#endif for (OMX_U32 extraBuffers = 2 + 1; /* condition inside loop */; extraBuffers--) { OMX_U32 newBufferCount = def.nBufferCountMin + *minUndequeuedBuffers + extraBuffers; @@ -993,6 +1054,9 @@ status_t ACodec::configureOutputBuffersFromNativeWindow( return err; } } +#ifdef BOARD_CANT_REALLOCATE_OMX_BUFFERS + } +#endif err = native_window_set_buffer_count( mNativeWindow.get(), def.nBufferCountActual); @@ -1244,6 +1308,27 @@ void ACodec::dumpBuffers(OMX_U32 portIndex) { } } +#ifdef USE_SAMSUNG_COLORFORMAT +void ACodec::setNativeWindowColorFormat(OMX_COLOR_FORMATTYPE &eNativeColorFormat) +{ + // In case of Samsung decoders, we set proper native color format for the Native Window + if (!strcasecmp(mComponentName.c_str(), "OMX.SEC.AVC.Decoder") + || !strcasecmp(mComponentName.c_str(), "OMX.SEC.FP.AVC.Decoder") + || !strcasecmp(mComponentName.c_str(), "OMX.SEC.MPEG4.Decoder") + || !strcasecmp(mComponentName.c_str(), "OMX.Exynos.AVC.Decoder")) { + switch (eNativeColorFormat) { + case OMX_COLOR_FormatYUV420SemiPlanar: + eNativeColorFormat = (OMX_COLOR_FORMATTYPE)HAL_PIXEL_FORMAT_YCbCr_420_SP; + break; + case OMX_COLOR_FormatYUV420Planar: + default: + eNativeColorFormat = (OMX_COLOR_FORMATTYPE)HAL_PIXEL_FORMAT_YCbCr_420_P; + break; + } + } +} +#endif + status_t ACodec::cancelBufferToNativeWindow(BufferInfo *info) { CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_US); @@ -1327,7 +1412,8 @@ ACodec::BufferInfo *ACodec::dequeueBufferFromNativeWindow() { } bool stale = false; - for (size_t i = mBuffers[kPortIndexOutput].size(); i-- > 0;) { + for (size_t i = mBuffers[kPortIndexOutput].size(); i > 0;) { + i--; BufferInfo *info = &mBuffers[kPortIndexOutput].editItemAt(i); if (info->mGraphicBuffer != NULL && @@ -1370,7 +1456,8 @@ ACodec::BufferInfo *ACodec::dequeueBufferFromNativeWindow() { // get oldest undequeued buffer BufferInfo *oldest = NULL; - for (size_t i = mBuffers[kPortIndexOutput].size(); i-- > 0;) { + for (size_t i = mBuffers[kPortIndexOutput].size(); i > 0;) { + i--; BufferInfo *info = &mBuffers[kPortIndexOutput].editItemAt(i); if (info->mStatus == BufferInfo::OWNED_BY_NATIVE_WINDOW && @@ -1574,6 +1661,8 @@ status_t ACodec::setComponentRole( "audio_decoder.ac3", "audio_encoder.ac3" }, { MEDIA_MIMETYPE_AUDIO_EAC3, "audio_decoder.eac3", "audio_encoder.eac3" }, + { MEDIA_MIMETYPE_VIDEO_MPEG4_DP, + "video_decoder.mpeg4", NULL }, }; static const size_t kNumMimeToRole = @@ -1587,7 +1676,7 @@ status_t ACodec::setComponentRole( } if (i == kNumMimeToRole) { - return ERROR_UNSUPPORTED; + return FFMPEGSoftCodec::setSupportedRole(mOMX, mNode, isEncoder, mime); } const char *role = @@ -1639,6 +1728,8 @@ status_t ACodec::configureCodec( return err; } + enableCustomAllocationMode(msg); + int32_t bitRate = 0; // FLAC encoder doesn't need a bitrate, other encoders do if (encoder && strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC) @@ -1896,6 +1987,12 @@ status_t ACodec::configureCodec( && push != 0) { mFlags |= kFlagPushBlankBuffersToNativeWindowOnShutdown; } + + int32_t val; + if (msg->findInt32("push-blank-buffers-on-switch", &val) + && val != 0) { + mFlags |= kFlagPushBlankBuffersToNativeWindowOnSwitch; + } } int32_t rotationDegrees; @@ -1909,7 +2006,8 @@ status_t ACodec::configureCodec( if (video) { // determine need for software renderer bool usingSwRenderer = false; - if (haveNativeWindow && mComponentName.startsWith("OMX.google.")) { + if (haveNativeWindow && (mComponentName.startsWith("OMX.google.") || + mComponentName.startsWith("OMX.ffmpeg."))) { usingSwRenderer = true; haveNativeWindow = false; } @@ -1994,10 +2092,12 @@ status_t ACodec::configureCodec( // and have the decoder figure it all out. err = OK; } else { - err = setupRawAudioFormat( + int32_t bitsPerSample = 16; + msg->findInt32("bits-per-sample", &bitsPerSample); + err = setupRawAudioFormatInternal( encoder ? kPortIndexInput : kPortIndexOutput, sampleRate, - numChannels); + numChannels, bitsPerSample); } } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { int32_t numChannels, sampleRate; @@ -2009,6 +2109,7 @@ status_t ACodec::configureCodec( int32_t sbrMode; int32_t maxOutputChannelCount; int32_t pcmLimiterEnable; + int32_t bitsPerSample = 16; drcParams_t drc; if (!msg->findInt32("is-adts", &isADTS)) { isADTS = 0; @@ -2047,11 +2148,12 @@ status_t ACodec::configureCodec( // value is unknown drc.targetRefLevel = -1; } + msg->findInt32("bits-per-sample", &bitsPerSample); err = setupAACCodec( encoder, numChannels, sampleRate, bitRate, aacProfile, isADTS != 0, sbrMode, maxOutputChannelCount, drc, - pcmLimiterEnable); + pcmLimiterEnable, bitsPerSample); } } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)) { err = setupAMRCodec(encoder, false /* isWAMR */, bitRate); @@ -2072,7 +2174,7 @@ status_t ACodec::configureCodec( } err = setupG711Codec(encoder, sampleRate, numChannels); } - } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC)) { + } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC) && encoder) { int32_t numChannels = 0, sampleRate = 0, compressionLevel = -1; if (encoder && (!msg->findInt32("channel-count", &numChannels) @@ -2108,16 +2210,21 @@ status_t ACodec::configureCodec( || !msg->findInt32("sample-rate", &sampleRate)) { err = INVALID_OPERATION; } else { - err = setupRawAudioFormat(kPortIndexInput, sampleRate, numChannels); + int32_t bitsPerSample = 16; + msg->findInt32("bits-per-sample", &bitsPerSample); + err = setupRawAudioFormatInternal(kPortIndexInput, sampleRate, numChannels, bitsPerSample); } - } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AC3)) { + } else if (!strncmp(mComponentName.c_str(), "OMX.google.", 11) + && !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); + int32_t bitsPerSample = 16; + msg->findInt32("bits-per-sample", &bitsPerSample); + err = setupAC3Codec(encoder, numChannels, sampleRate, bitsPerSample); } } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_EAC3)) { int32_t numChannels; @@ -2126,7 +2233,16 @@ status_t ACodec::configureCodec( || !msg->findInt32("sample-rate", &sampleRate)) { err = INVALID_OPERATION; } else { - err = setupEAC3Codec(encoder, numChannels, sampleRate); + int32_t bitsPerSample = 16; + msg->findInt32("bits-per-sample", &bitsPerSample); + err = setupEAC3Codec(encoder, numChannels, sampleRate, bitsPerSample); + } + } else { + if (!strncmp(mComponentName.c_str(), "OMX.ffmpeg.", 11) && !mIsEncoder) { + err = FFMPEGSoftCodec::setAudioFormat( + msg, mime, mOMX, mNode); + } else { + err = setupCustomCodec(err, mime, msg); } } @@ -2297,15 +2413,16 @@ status_t ACodec::setupAACCodec( bool encoder, int32_t numChannels, int32_t sampleRate, int32_t bitRate, int32_t aacProfile, bool isADTS, int32_t sbrMode, int32_t maxOutputChannelCount, const drcParams_t& drc, - int32_t pcmLimiterEnable) { + int32_t pcmLimiterEnable, int32_t bitsPerSample) { if (encoder && isADTS) { return -EINVAL; } - status_t err = setupRawAudioFormat( + status_t err = setupRawAudioFormatInternal( encoder ? kPortIndexInput : kPortIndexOutput, sampleRate, - numChannels); + numChannels, + bitsPerSample); if (err != OK) { return err; @@ -2442,9 +2559,9 @@ status_t ACodec::setupAACCodec( } status_t ACodec::setupAC3Codec( - bool encoder, int32_t numChannels, int32_t sampleRate) { - status_t err = setupRawAudioFormat( - encoder ? kPortIndexInput : kPortIndexOutput, sampleRate, numChannels); + bool encoder, int32_t numChannels, int32_t sampleRate, int32_t bitsPerSample) { + status_t err = setupRawAudioFormatInternal( + encoder ? kPortIndexInput : kPortIndexOutput, sampleRate, numChannels, bitsPerSample); if (err != OK) { return err; @@ -2480,9 +2597,9 @@ status_t ACodec::setupAC3Codec( } status_t ACodec::setupEAC3Codec( - bool encoder, int32_t numChannels, int32_t sampleRate) { - status_t err = setupRawAudioFormat( - encoder ? kPortIndexInput : kPortIndexOutput, sampleRate, numChannels); + bool encoder, int32_t numChannels, int32_t sampleRate, int32_t bitsPerSample) { + status_t err = setupRawAudioFormatInternal( + encoder ? kPortIndexInput : kPortIndexOutput, sampleRate, numChannels, bitsPerSample); if (err != OK) { return err; @@ -2629,6 +2746,11 @@ status_t ACodec::setupFlacCodec( status_t ACodec::setupRawAudioFormat( OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels) { + return setupRawAudioFormatInternal(portIndex, sampleRate, numChannels, 16); +} + +status_t ACodec::setupRawAudioFormatInternal( + OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels, int32_t bitsPerSample) { OMX_PARAM_PORTDEFINITIONTYPE def; InitOMXParams(&def); def.nPortIndex = portIndex; @@ -2663,7 +2785,7 @@ status_t ACodec::setupRawAudioFormat( pcmParams.nChannels = numChannels; pcmParams.eNumData = OMX_NumericalDataSigned; pcmParams.bInterleaved = OMX_TRUE; - pcmParams.nBitPerSample = 16; + pcmParams.nBitPerSample = bitsPerSample; pcmParams.nSamplingRate = sampleRate; pcmParams.ePCMMode = OMX_AUDIO_PCMModeLinear; @@ -2839,13 +2961,14 @@ static const struct VideoCodingMapEntry { { MEDIA_MIMETYPE_VIDEO_AVC, OMX_VIDEO_CodingAVC }, { MEDIA_MIMETYPE_VIDEO_HEVC, OMX_VIDEO_CodingHEVC }, { MEDIA_MIMETYPE_VIDEO_MPEG4, OMX_VIDEO_CodingMPEG4 }, + { MEDIA_MIMETYPE_VIDEO_MPEG4_DP, OMX_VIDEO_CodingMPEG4 }, { MEDIA_MIMETYPE_VIDEO_H263, OMX_VIDEO_CodingH263 }, { MEDIA_MIMETYPE_VIDEO_MPEG2, OMX_VIDEO_CodingMPEG2 }, { MEDIA_MIMETYPE_VIDEO_VP8, OMX_VIDEO_CodingVP8 }, { MEDIA_MIMETYPE_VIDEO_VP9, OMX_VIDEO_CodingVP9 }, }; -static status_t GetVideoCodingTypeFromMime( +status_t ACodec::GetVideoCodingTypeFromMime( const char *mime, OMX_VIDEO_CODINGTYPE *codingType) { for (size_t i = 0; i < sizeof(kVideoCodingMapEntry) / sizeof(kVideoCodingMapEntry[0]); @@ -2888,6 +3011,9 @@ status_t ACodec::setupVideoDecoder( OMX_VIDEO_CODINGTYPE compressionFormat; status_t err = GetVideoCodingTypeFromMime(mime, &compressionFormat); + err = FFMPEGSoftCodec::setVideoFormat(err, + msg, mime, mOMX, mNode, mIsEncoder, &compressionFormat, + mComponentName.c_str()); if (err != OK) { return err; } @@ -3038,7 +3164,11 @@ status_t ACodec::setupVideoEncoder(const char *mime, const sp<AMessage> &msg) { OMX_VIDEO_CODINGTYPE compressionFormat; err = GetVideoCodingTypeFromMime(mime, &compressionFormat); + err = FFMPEGSoftCodec::setVideoFormat(err, + msg, mime, mOMX, mNode, mIsEncoder, &compressionFormat, + mComponentName.c_str()); if (err != OK) { + ALOGE("Not a supported video mime type: %s", mime); return err; } @@ -3232,6 +3362,7 @@ status_t ACodec::setupMPEG4EncoderParameters(const sp<AMessage> &msg) { mpeg4type.eLevel = static_cast<OMX_VIDEO_MPEG4LEVELTYPE>(level); } + setBFrames(&mpeg4type); err = mOMX->setParameter( mNode, OMX_IndexParamVideoMpeg4, &mpeg4type, sizeof(mpeg4type)); @@ -3429,6 +3560,8 @@ status_t ACodec::setupAVCEncoderParameters(const sp<AMessage> &msg) { err = verifySupportForProfileAndLevel(profile, level); if (err != OK) { + ALOGE("%s does not support profile %x @ level %x", + mComponentName.c_str(), profile, level); return err; } @@ -3437,11 +3570,14 @@ status_t ACodec::setupAVCEncoderParameters(const sp<AMessage> &msg) { } // XXX + // Allow higher profiles to be set since the encoder seems to support +#ifdef USE_AVC_BASELINE_PROFILE if (h264type.eProfile != OMX_VIDEO_AVCProfileBaseline) { ALOGW("Use baseline profile instead of %d for AVC recording", h264type.eProfile); h264type.eProfile = OMX_VIDEO_AVCProfileBaseline; } +#endif if (h264type.eProfile == OMX_VIDEO_AVCProfileBaseline) { h264type.nSliceHeaderSpacing = 0; @@ -3462,6 +3598,7 @@ status_t ACodec::setupAVCEncoderParameters(const sp<AMessage> &msg) { h264type.nCabacInitIdc = 0; } + setBFrames(&h264type, iFrameInterval, frameRate); if (h264type.nBFrames != 0) { h264type.nAllowedPictureTypes |= OMX_VIDEO_PictureTypeB; } @@ -3502,6 +3639,8 @@ status_t ACodec::setupHEVCEncoderParameters(const sp<AMessage> &msg) { frameRate = (float)tmp; } + AVUtils::get()->setIntraPeriod(setPFramesSpacing(iFrameInterval, frameRate), 0, mOMX, mNode); + OMX_VIDEO_PARAM_HEVCTYPE hevcType; InitOMXParams(&hevcType); hevcType.nPortIndex = kPortIndexOutput; @@ -3683,7 +3822,7 @@ status_t ACodec::setupErrorCorrectionParameters() { errorCorrectionType.bEnableHEC = OMX_FALSE; errorCorrectionType.bEnableResync = OMX_TRUE; - errorCorrectionType.nResynchMarkerSpacing = 256; + errorCorrectionType.nResynchMarkerSpacing = 0; errorCorrectionType.bEnableDataPartitioning = OMX_FALSE; errorCorrectionType.bEnableRVLC = OMX_FALSE; @@ -3842,6 +3981,7 @@ bool ACodec::describeDefaultColorFormat(DescribeColorFormatParams ¶ms) { fmt != OMX_COLOR_FormatYUV420PackedPlanar && fmt != OMX_COLOR_FormatYUV420SemiPlanar && fmt != OMX_COLOR_FormatYUV420PackedSemiPlanar && + fmt != OMX_TI_COLOR_FormatYUV420PackedSemiPlanar && fmt != HAL_PIXEL_FORMAT_YV12) { ALOGW("do not know color format 0x%x = %d", fmt, fmt); return false; @@ -3914,6 +4054,7 @@ bool ACodec::describeDefaultColorFormat(DescribeColorFormatParams ¶ms) { case OMX_COLOR_FormatYUV420SemiPlanar: // FIXME: NV21 for sw-encoder, NV12 for decoder and hw-encoder case OMX_COLOR_FormatYUV420PackedSemiPlanar: + case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar: // NV12 image.mPlane[image.U].mOffset = params.nStride * params.nSliceHeight; image.mPlane[image.U].mColInc = 2; @@ -4071,6 +4212,16 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp<AMessage> ¬ify) { rect.nWidth = videoDef->nFrameWidth; rect.nHeight = videoDef->nFrameHeight; } +#ifdef MTK_HARDWARE + if (!strncmp(mComponentName.c_str(), "OMX.MTK.", 8) && mOMX->getConfig( + mNode, (OMX_INDEXTYPE) 0x7f00001c /* OMX_IndexVendorMtkOmxVdecGetCropInfo */, + &rect, sizeof(rect)) != OK) { + rect.nLeft = 0; + rect.nTop = 0; + rect.nWidth = videoDef->nFrameWidth; + rect.nHeight = videoDef->nFrameHeight; + } +#endif if (rect.nLeft < 0 || rect.nTop < 0 || @@ -4138,6 +4289,14 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp<AMessage> ¬ify) { default: { + if (!strncmp(mComponentName.c_str(), "OMX.ffmpeg.", 11)) { + err = FFMPEGSoftCodec::getVideoPortFormat(portIndex, + (int)videoDef->eCompressionFormat, notify, mOMX, mNode); + if (err == OK) { + break; + } + } + if (mIsEncoder ^ (portIndex == kPortIndexOutput)) { // should be CodingUnused ALOGE("Raw port video compression format is %s(%d)", @@ -4183,7 +4342,10 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp<AMessage> ¬ify) { if (params.nChannels <= 0 || (params.nChannels != 1 && !params.bInterleaved) - || params.nBitPerSample != 16u + || (params.nBitPerSample != 16u + && params.nBitPerSample != 24u + && params.nBitPerSample != 32u + && params.nBitPerSample != 8u)// we support 8/16/24/32 bit s/w decoding || params.eNumData != OMX_NumericalDataSigned || params.ePCMMode != OMX_AUDIO_PCMModeLinear) { ALOGE("unsupported PCM port: %u channels%s, %u-bit, %s(%d), %s(%d) mode ", @@ -4198,6 +4360,8 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp<AMessage> ¬ify) { notify->setString("mime", MEDIA_MIMETYPE_AUDIO_RAW); notify->setInt32("channel-count", params.nChannels); notify->setInt32("sample-rate", params.nSamplingRate); + notify->setInt32("bits-per-sample", params.nBitPerSample); + notify->setInt32("pcm-format", getPCMFormat(notify)); if (mChannelMaskPresent) { notify->setInt32("channel-mask", mChannelMask); @@ -4248,6 +4412,13 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp<AMessage> ¬ify) { case OMX_AUDIO_CodingFLAC: { + if (!strncmp(mComponentName.c_str(), "OMX.ffmpeg.", 11)) { + err = FFMPEGSoftCodec::getAudioPortFormat(portIndex, + (int)audioDef->eEncoding, notify, mOMX, mNode); + if (err != OK) { + return err; + } + } else { OMX_AUDIO_PARAM_FLACTYPE params; InitOMXParams(¶ms); params.nPortIndex = portIndex; @@ -4261,6 +4432,7 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp<AMessage> ¬ify) { notify->setString("mime", MEDIA_MIMETYPE_AUDIO_FLAC); notify->setInt32("channel-count", params.nChannels); notify->setInt32("sample-rate", params.nSampleRate); + } break; } @@ -4402,6 +4574,14 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp<AMessage> ¬ify) { } default: + if (!strncmp(mComponentName.c_str(), "OMX.ffmpeg.", 11)) { + err = FFMPEGSoftCodec::getAudioPortFormat(portIndex, + (int)audioDef->eEncoding, notify, mOMX, mNode); + } + if (err == OK) { + break; + } + ALOGE("Unsupported audio coding: %s(%d)\n", asString(audioDef->eEncoding), audioDef->eEncoding); return BAD_TYPE; @@ -4440,18 +4620,17 @@ void ACodec::sendFormatChange(const sp<AMessage> &reply) { (mEncoderDelay || mEncoderPadding)) { int32_t channelCount; CHECK(notify->findInt32("channel-count", &channelCount)); - size_t frameSize = channelCount * sizeof(int16_t); if (mSkipCutBuffer != NULL) { size_t prevbufsize = mSkipCutBuffer->size(); if (prevbufsize != 0) { ALOGW("Replacing SkipCutBuffer holding %zu bytes", prevbufsize); } } - mSkipCutBuffer = new SkipCutBuffer( - mEncoderDelay * frameSize, - mEncoderPadding * frameSize); + mSkipCutBuffer = new SkipCutBuffer(mEncoderDelay, mEncoderPadding, channelCount); } + getVQZIPInfo(notify); + notify->post(); mSentFormat = true; @@ -4600,6 +4779,7 @@ bool ACodec::BaseState::onMessageReceived(const sp<AMessage> &msg) { ALOGI("[%s] forcing the release of codec", mCodec->mComponentName.c_str()); status_t err = mCodec->mOMX->freeNode(mCodec->mNode); + mCodec->changeState(mCodec->mUninitializedState); ALOGE_IF("[%s] failed to release codec instance: err=%d", mCodec->mComponentName.c_str(), err); sp<AMessage> notify = mCodec->mNotify->dup(); @@ -5184,6 +5364,7 @@ bool ACodec::BaseState::onOMXFillBufferDone( mCodec->mSkipCutBuffer->submit(info->mData); } info->mData->meta()->setInt64("timeUs", timeUs); + info->mData->meta()->setObject("graphic-buffer", info->mGraphicBuffer); sp<AMessage> notify = mCodec->mNotify->dup(); notify->setInt32("what", CodecBase::kWhatDrainThisBuffer); @@ -5193,6 +5374,8 @@ bool ACodec::BaseState::onOMXFillBufferDone( reply->setInt32("buffer-id", info->mBufferID); + (void)mCodec->setDSModeHint(reply, flags, timeUs); + notify->setMessage("reply", reply); notify->post(); @@ -5247,8 +5430,9 @@ void ACodec::BaseState::onOutputBufferDrained(const sp<AMessage> &msg) { ALOGW_IF(err != NO_ERROR, "failed to set crop: %d", err); } + bool skip = mCodec->getDSModeHint(msg); int32_t render; - if (mCodec->mNativeWindow != NULL + if (!skip && mCodec->mNativeWindow != NULL && msg->findInt32("render", &render) && render != 0 && info->mData != NULL && info->mData->size() != 0) { ATRACE_NAME("render"); @@ -5376,6 +5560,8 @@ void ACodec::UninitializedState::stateEntered() { mCodec->mOMX.clear(); mCodec->mQuirks = 0; mCodec->mFlags = 0; + mCodec->mEncoderComponent = 0; + mCodec->mComponentAllocByName = 0; mCodec->mInputMetadataType = kMetadataBufferTypeInvalid; mCodec->mOutputMetadataType = kMetadataBufferTypeInvalid; mCodec->mComponentName.clear(); @@ -5481,6 +5667,7 @@ bool ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) { ssize_t index = matchingCodecs.add(); OMXCodec::CodecNameAndQuirks *entry = &matchingCodecs.editItemAt(index); entry->mName = String8(componentName.c_str()); + mCodec->mComponentAllocByName = true; if (!OMXCodec::findCodecQuirks( componentName.c_str(), &entry->mQuirks)) { @@ -5493,6 +5680,10 @@ bool ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) { encoder = false; } + if (encoder == true) { + mCodec->mEncoderComponent = true; + } + OMXCodec::findMatchingCodecs( mime.c_str(), encoder, // createEncoder @@ -5685,6 +5876,7 @@ bool ACodec::LoadedState::onConfigureComponent( status_t err = OK; AString mime; + if (!msg->findString("mime", &mime)) { err = BAD_VALUE; } else { @@ -5694,13 +5886,80 @@ bool ACodec::LoadedState::onConfigureComponent( ALOGE("[%s] configureCodec returning error %d", mCodec->mComponentName.c_str(), err); - mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err)); - return false; + if (!mCodec->mEncoderComponent && !mCodec->mComponentAllocByName && + !strncmp(mime.c_str(), "video/", strlen("video/"))) { + Vector<OMXCodec::CodecNameAndQuirks> matchingCodecs; + + OMXCodec::findMatchingCodecs( + mime.c_str(), + false, // createEncoder + NULL, // matchComponentName + 0, // flags + &matchingCodecs); + + err = mCodec->mOMX->freeNode(mCodec->mNode); + + if (err != OK) { + ALOGE("Failed to freeNode"); + mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err)); + return false; + } + + mCodec->mNode = 0; + AString componentName; + sp<CodecObserver> observer = new CodecObserver; + + err = NAME_NOT_FOUND; + for (size_t matchIndex = 0; matchIndex < matchingCodecs.size(); + ++matchIndex) { + componentName = matchingCodecs.itemAt(matchIndex).mName.string(); + if (!strcmp(mCodec->mComponentName.c_str(), componentName.c_str())) { + continue; + } + + pid_t tid = gettid(); + int prevPriority = androidGetThreadPriority(tid); + androidSetThreadPriority(tid, ANDROID_PRIORITY_FOREGROUND); + err = mCodec->mOMX->allocateNode(componentName.c_str(), observer, &mCodec->mNode); + androidSetThreadPriority(tid, prevPriority); + + if (err == OK) { + break; + } else { + ALOGW("Allocating component '%s' failed, try next one.", componentName.c_str()); + } + + mCodec->mNode = 0; + } + + if (mCodec->mNode == 0) { + if (!mime.empty()) { + ALOGE("Unable to instantiate a decoder for type '%s'", mime.c_str()); + } else { + ALOGE("Unable to instantiate codec '%s' with err %#x.", componentName.c_str(), err); + } + + mCodec->signalError((OMX_ERRORTYPE)err, makeNoSideEffectStatus(err)); + return false; + } + + sp<AMessage> notify = new AMessage(kWhatOMXMessageList, mCodec); + observer->setNotificationMessage(notify); + mCodec->mComponentName = componentName; + + err = mCodec->configureCodec(mime.c_str(), msg); + } + + if (err != OK) { + mCodec->signalError((OMX_ERRORTYPE)err, makeNoSideEffectStatus(err)); + return false; + } } { sp<AMessage> notify = mCodec->mNotify->dup(); notify->setInt32("what", CodecBase::kWhatComponentConfigured); + notify->setString("componentName", mCodec->mComponentName.c_str()); notify->setMessage("input-format", mCodec->mInputFormat); notify->setMessage("output-format", mCodec->mOutputFormat); notify->post(); @@ -6363,6 +6622,23 @@ void ACodec::onSignalEndOfInputStream() { notify->post(); } +sp<IOMXObserver> ACodec::createObserver() { + sp<CodecObserver> observer = new CodecObserver; + sp<AMessage> notify = new AMessage(kWhatOMXMessageList, this); + observer->setNotificationMessage(notify); + return observer; +} + +status_t ACodec::allocateBuffer( + OMX_U32 portIndex, size_t bufSize, BufferInfo &info) { + void *ptr; + status_t err = mOMX->allocateBuffer( + mNode, portIndex, bufSize, &info.mBufferID, &ptr); + + info.mData = new ABuffer(ptr, bufSize); + return err; +} + bool ACodec::ExecutingState::onOMXFrameRendered(int64_t mediaTimeUs, nsecs_t systemNano) { mCodec->onFrameRendered(mediaTimeUs, systemNano); return true; @@ -6433,8 +6709,34 @@ bool ACodec::OutputPortSettingsChangedState::onMessageReceived( bool handled = false; switch (msg->what()) { - case kWhatFlush: case kWhatShutdown: + { + int32_t keepComponentAllocated; + CHECK(msg->findInt32( + "keepComponentAllocated", &keepComponentAllocated)); + + mCodec->mShutdownInProgress = true; + mCodec->mExplicitShutdown = true; + mCodec->mKeepComponentAllocated = keepComponentAllocated; + + status_t err = mCodec->mOMX->sendCommand( + mCodec->mNode, OMX_CommandStateSet, OMX_StateIdle); + if (err != OK) { + if (keepComponentAllocated) { + mCodec->signalError(OMX_ErrorUndefined, FAILED_TRANSACTION); + } + // TODO: do some recovery here. + } else { + // This is technically not correct, but appears to be + // the only way to free the component instance using + // ExectingToIdleState. + mCodec->changeState(mCodec->mExecutingToIdleState); + } + + handled = true; + break; + } + case kWhatFlush: case kWhatResume: case kWhatSetParameters: { @@ -6493,6 +6795,11 @@ bool ACodec::OutputPortSettingsChangedState::onOMXEvent( mCodec->mNode, OMX_CommandPortEnable, kPortIndexOutput); } + /* Clear the RenderQueue in which queued GraphicBuffers hold the + * actual buffer references in order to free them early. + */ + mCodec->mRenderTracker.clear(systemTime(CLOCK_MONOTONIC)); + if (err == OK) { err = mCodec->allocateBuffersOnPort(kPortIndexOutput); ALOGE_IF(err != OK, "Failed to allocate output port buffers after port " @@ -6501,15 +6808,6 @@ bool ACodec::OutputPortSettingsChangedState::onOMXEvent( if (err != OK) { mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err)); - - // This is technically not correct, but appears to be - // the only way to free the component instance. - // Controlled transitioning from excecuting->idle - // and idle->loaded seem impossible probably because - // the output port never finishes re-enabling. - mCodec->mShutdownInProgress = true; - mCodec->mKeepComponentAllocated = false; - mCodec->changeState(mCodec->mLoadedState); } return true; |