diff options
Diffstat (limited to 'media/libstagefright/OMXCodec.cpp')
-rwxr-xr-x | media/libstagefright/OMXCodec.cpp | 4582 |
1 files changed, 0 insertions, 4582 deletions
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp deleted file mode 100755 index 9769f21..0000000 --- a/media/libstagefright/OMXCodec.cpp +++ /dev/null @@ -1,4582 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "OMXCodec" -#include <utils/Log.h> - -#include "include/AACEncoder.h" -#include "include/AVCEncoder.h" -#include "include/M4vH263Encoder.h" - -#include "include/ESDS.h" - -#include <binder/IServiceManager.h> -#include <binder/MemoryDealer.h> -#include <binder/ProcessState.h> -#include <HardwareAPI.h> -#include <media/stagefright/foundation/ADebug.h> -#include <media/IMediaPlayerService.h> -#include <media/stagefright/MediaBuffer.h> -#include <media/stagefright/MediaBufferGroup.h> -#include <media/stagefright/MediaDefs.h> -#include <media/stagefright/MediaCodecList.h> -#include <media/stagefright/MediaExtractor.h> -#include <media/stagefright/MetaData.h> -#include <media/stagefright/OMXCodec.h> -#include <media/stagefright/Utils.h> -#include <media/stagefright/SkipCutBuffer.h> -#include <utils/Vector.h> - -#include <OMX_Audio.h> -#include <OMX_Component.h> - -#include "include/avc_utils.h" - -namespace android { - -// Treat time out as an error if we have not received any output -// buffers after 3 seconds. -const static int64_t kBufferFilledEventTimeOutNs = 3000000000LL; - -// OMX Spec defines less than 50 color formats. If the query for -// color format is executed for more than kMaxColorFormatSupported, -// the query will fail to avoid looping forever. -// 1000 is more than enough for us to tell whether the omx -// component in question is buggy or not. -const static uint32_t kMaxColorFormatSupported = 1000; - -#define FACTORY_CREATE_ENCODER(name) \ -static sp<MediaSource> Make##name(const sp<MediaSource> &source, const sp<MetaData> &meta) { \ - return new name(source, meta); \ -} - -#define FACTORY_REF(name) { #name, Make##name }, - -FACTORY_CREATE_ENCODER(AACEncoder) -FACTORY_CREATE_ENCODER(AVCEncoder) -FACTORY_CREATE_ENCODER(M4vH263Encoder) - -static sp<MediaSource> InstantiateSoftwareEncoder( - const char *name, const sp<MediaSource> &source, - const sp<MetaData> &meta) { - struct FactoryInfo { - const char *name; - sp<MediaSource> (*CreateFunc)(const sp<MediaSource> &, const sp<MetaData> &); - }; - - static const FactoryInfo kFactoryInfo[] = { - FACTORY_REF(AACEncoder) - FACTORY_REF(AVCEncoder) - FACTORY_REF(M4vH263Encoder) - }; - for (size_t i = 0; - i < sizeof(kFactoryInfo) / sizeof(kFactoryInfo[0]); ++i) { - if (!strcmp(name, kFactoryInfo[i].name)) { - return (*kFactoryInfo[i].CreateFunc)(source, meta); - } - } - - return NULL; -} - -#undef FACTORY_CREATE_ENCODER -#undef FACTORY_REF - -#define CODEC_LOGI(x, ...) ALOGI("[%s] "x, mComponentName, ##__VA_ARGS__) -#define CODEC_LOGV(x, ...) ALOGV("[%s] "x, mComponentName, ##__VA_ARGS__) -#define CODEC_LOGE(x, ...) ALOGE("[%s] "x, mComponentName, ##__VA_ARGS__) - -struct OMXCodecObserver : public BnOMXObserver { - OMXCodecObserver() { - } - - void setCodec(const sp<OMXCodec> &target) { - mTarget = target; - } - - // from IOMXObserver - virtual void onMessage(const omx_message &msg) { - sp<OMXCodec> codec = mTarget.promote(); - - if (codec.get() != NULL) { - Mutex::Autolock autoLock(codec->mLock); - codec->on_message(msg); - codec.clear(); - } - } - -protected: - virtual ~OMXCodecObserver() {} - -private: - wp<OMXCodec> mTarget; - - OMXCodecObserver(const OMXCodecObserver &); - OMXCodecObserver &operator=(const OMXCodecObserver &); -}; - -template<class T> -static void InitOMXParams(T *params) { - params->nSize = sizeof(T); - params->nVersion.s.nVersionMajor = 1; - params->nVersion.s.nVersionMinor = 0; - params->nVersion.s.nRevision = 0; - params->nVersion.s.nStep = 0; -} - -static bool IsSoftwareCodec(const char *componentName) { - if (!strncmp("OMX.google.", componentName, 11)) { - return true; - } - - if (!strncmp("OMX.", componentName, 4)) { - return false; - } - - return true; -} - -// A sort order in which OMX software codecs are first, followed -// by other (non-OMX) software codecs, followed by everything else. -static int CompareSoftwareCodecsFirst( - const String8 *elem1, const String8 *elem2) { - bool isOMX1 = !strncmp(elem1->string(), "OMX.", 4); - bool isOMX2 = !strncmp(elem2->string(), "OMX.", 4); - - bool isSoftwareCodec1 = IsSoftwareCodec(elem1->string()); - bool isSoftwareCodec2 = IsSoftwareCodec(elem2->string()); - - if (isSoftwareCodec1) { - if (!isSoftwareCodec2) { return -1; } - - if (isOMX1) { - if (isOMX2) { return 0; } - - return -1; - } else { - if (isOMX2) { return 0; } - - return 1; - } - - return -1; - } - - if (isSoftwareCodec2) { - return 1; - } - - return 0; -} - -// static -void OMXCodec::findMatchingCodecs( - const char *mime, - bool createEncoder, const char *matchComponentName, - uint32_t flags, - Vector<String8> *matchingCodecs, - Vector<uint32_t> *matchingCodecQuirks) { - matchingCodecs->clear(); - - if (matchingCodecQuirks) { - matchingCodecQuirks->clear(); - } - - const MediaCodecList *list = MediaCodecList::getInstance(); - if (list == NULL) { - return; - } - - size_t index = 0; - for (;;) { - ssize_t matchIndex = - list->findCodecByType(mime, createEncoder, index); - - if (matchIndex < 0) { - break; - } - - index = matchIndex + 1; - - const char *componentName = list->getCodecName(matchIndex); - - // If a specific codec is requested, skip the non-matching ones. - if (matchComponentName && strcmp(componentName, matchComponentName)) { - continue; - } - - // When requesting software-only codecs, only push software codecs - // When requesting hardware-only codecs, only push hardware codecs - // When there is request neither for software-only nor for - // hardware-only codecs, push all codecs - if (((flags & kSoftwareCodecsOnly) && IsSoftwareCodec(componentName)) || - ((flags & kHardwareCodecsOnly) && !IsSoftwareCodec(componentName)) || - (!(flags & (kSoftwareCodecsOnly | kHardwareCodecsOnly)))) { - - matchingCodecs->push(String8(componentName)); - - if (matchingCodecQuirks) { - matchingCodecQuirks->push(getComponentQuirks(list, matchIndex)); - } - } - } - - if (flags & kPreferSoftwareCodecs) { - matchingCodecs->sort(CompareSoftwareCodecsFirst); - } -} - -// static -uint32_t OMXCodec::getComponentQuirks( - const MediaCodecList *list, size_t index) { - uint32_t quirks = 0; - if (list->codecHasQuirk( - index, "requires-allocate-on-input-ports")) { - quirks |= kRequiresAllocateBufferOnInputPorts; - } - if (list->codecHasQuirk( - index, "requires-allocate-on-output-ports")) { - quirks |= kRequiresAllocateBufferOnOutputPorts; - } - if (list->codecHasQuirk( - index, "output-buffers-are-unreadable")) { - quirks |= kOutputBuffersAreUnreadable; - } - - return quirks; -} - -// static -bool OMXCodec::findCodecQuirks(const char *componentName, uint32_t *quirks) { - const MediaCodecList *list = MediaCodecList::getInstance(); - - if (list == NULL) { - return false; - } - - ssize_t index = list->findCodecByName(componentName); - - if (index < 0) { - return false; - } - - *quirks = getComponentQuirks(list, index); - - return true; -} - -// static -sp<MediaSource> OMXCodec::Create( - const sp<IOMX> &omx, - const sp<MetaData> &meta, bool createEncoder, - const sp<MediaSource> &source, - const char *matchComponentName, - uint32_t flags, - const sp<ANativeWindow> &nativeWindow) { - int32_t requiresSecureBuffers; - if (source->getFormat()->findInt32( - kKeyRequiresSecureBuffers, - &requiresSecureBuffers) - && requiresSecureBuffers) { - flags |= kIgnoreCodecSpecificData; - flags |= kUseSecureInputBuffers; - } - - const char *mime; - bool success = meta->findCString(kKeyMIMEType, &mime); - CHECK(success); - - Vector<String8> matchingCodecs; - Vector<uint32_t> matchingCodecQuirks; - findMatchingCodecs( - mime, createEncoder, matchComponentName, flags, - &matchingCodecs, &matchingCodecQuirks); - - if (matchingCodecs.isEmpty()) { - return NULL; - } - - sp<OMXCodecObserver> observer = new OMXCodecObserver; - IOMX::node_id node = 0; - - for (size_t i = 0; i < matchingCodecs.size(); ++i) { - const char *componentNameBase = matchingCodecs[i].string(); - uint32_t quirks = matchingCodecQuirks[i]; - const char *componentName = componentNameBase; - - AString tmp; - if (flags & kUseSecureInputBuffers) { - tmp = componentNameBase; - tmp.append(".secure"); - - componentName = tmp.c_str(); - } - - if (createEncoder) { - sp<MediaSource> softwareCodec = - InstantiateSoftwareEncoder(componentName, source, meta); - - if (softwareCodec != NULL) { - ALOGV("Successfully allocated software codec '%s'", componentName); - - return softwareCodec; - } - } - - ALOGV("Attempting to allocate OMX node '%s'", componentName); - - if (!createEncoder - && (quirks & kOutputBuffersAreUnreadable) - && (flags & kClientNeedsFramebuffer)) { - if (strncmp(componentName, "OMX.SEC.", 8)) { - // For OMX.SEC.* decoders we can enable a special mode that - // gives the client access to the framebuffer contents. - - ALOGW("Component '%s' does not give the client access to " - "the framebuffer contents. Skipping.", - componentName); - - continue; - } - } - - status_t err = omx->allocateNode(componentName, observer, &node); - if (err == OK) { - ALOGV("Successfully allocated OMX node '%s'", componentName); - - sp<OMXCodec> codec = new OMXCodec( - omx, node, quirks, flags, - createEncoder, mime, componentName, - source, nativeWindow); - - observer->setCodec(codec); - - err = codec->configureCodec(meta); - - if (err == OK) { - if (!strcmp("OMX.Nvidia.mpeg2v.decode", componentName)) { - codec->mFlags |= kOnlySubmitOneInputBufferAtOneTime; - } - - return codec; - } - - ALOGV("Failed to configure codec '%s'", componentName); - } - } - - return NULL; -} - -status_t OMXCodec::parseAVCCodecSpecificData( - const void *data, size_t size, - unsigned *profile, unsigned *level) { - const uint8_t *ptr = (const uint8_t *)data; - - // verify minimum size and configurationVersion == 1. - if (size < 7 || ptr[0] != 1) { - return ERROR_MALFORMED; - } - - *profile = ptr[1]; - *level = ptr[3]; - - // There is decodable content out there that fails the following - // assertion, let's be lenient for now... - // CHECK((ptr[4] >> 2) == 0x3f); // reserved - - size_t lengthSize = 1 + (ptr[4] & 3); - - // commented out check below as H264_QVGA_500_NO_AUDIO.3gp - // violates it... - // CHECK((ptr[5] >> 5) == 7); // reserved - - size_t numSeqParameterSets = ptr[5] & 31; - - ptr += 6; - size -= 6; - - for (size_t i = 0; i < numSeqParameterSets; ++i) { - if (size < 2) { - return ERROR_MALFORMED; - } - - size_t length = U16_AT(ptr); - - ptr += 2; - size -= 2; - - if (size < length) { - return ERROR_MALFORMED; - } - - addCodecSpecificData(ptr, length); - - ptr += length; - size -= length; - } - - if (size < 1) { - return ERROR_MALFORMED; - } - - size_t numPictureParameterSets = *ptr; - ++ptr; - --size; - - for (size_t i = 0; i < numPictureParameterSets; ++i) { - if (size < 2) { - return ERROR_MALFORMED; - } - - size_t length = U16_AT(ptr); - - ptr += 2; - size -= 2; - - if (size < length) { - return ERROR_MALFORMED; - } - - addCodecSpecificData(ptr, length); - - ptr += length; - size -= length; - } - - return OK; -} - -status_t OMXCodec::configureCodec(const sp<MetaData> &meta) { - ALOGV("configureCodec protected=%d", - (mFlags & kEnableGrallocUsageProtected) ? 1 : 0); - - if (!(mFlags & kIgnoreCodecSpecificData)) { - uint32_t type; - const void *data; - size_t size; - if (meta->findData(kKeyESDS, &type, &data, &size)) { - ESDS esds((const char *)data, size); - CHECK_EQ(esds.InitCheck(), (status_t)OK); - - const void *codec_specific_data; - size_t codec_specific_data_size; - esds.getCodecSpecificInfo( - &codec_specific_data, &codec_specific_data_size); - - addCodecSpecificData( - codec_specific_data, codec_specific_data_size); - } else if (meta->findData(kKeyAVCC, &type, &data, &size)) { - // Parse the AVCDecoderConfigurationRecord - - unsigned profile, level; - status_t err; - if ((err = parseAVCCodecSpecificData( - data, size, &profile, &level)) != OK) { - ALOGE("Malformed AVC codec specific data."); - return err; - } - - CODEC_LOGI( - "AVC profile = %u (%s), level = %u", - profile, AVCProfileToString(profile), level); - } else if (meta->findData(kKeyVorbisInfo, &type, &data, &size)) { - addCodecSpecificData(data, size); - - CHECK(meta->findData(kKeyVorbisBooks, &type, &data, &size)); - addCodecSpecificData(data, size); - } - } - - int32_t bitRate = 0; - if (mIsEncoder) { - CHECK(meta->findInt32(kKeyBitRate, &bitRate)); - } - if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mMIME)) { - setAMRFormat(false /* isWAMR */, bitRate); - } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mMIME)) { - setAMRFormat(true /* isWAMR */, bitRate); - } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mMIME)) { - int32_t numChannels, sampleRate; - CHECK(meta->findInt32(kKeyChannelCount, &numChannels)); - CHECK(meta->findInt32(kKeySampleRate, &sampleRate)); - - int32_t isADTS; - if (!meta->findInt32(kKeyIsADTS, &isADTS)) { - isADTS = false; - } - - status_t err = setAACFormat(numChannels, sampleRate, bitRate, isADTS); - if (err != OK) { - CODEC_LOGE("setAACFormat() failed (err = %d)", err); - return err; - } - } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_G711_ALAW, mMIME) - || !strcasecmp(MEDIA_MIMETYPE_AUDIO_G711_MLAW, mMIME)) { - // These are PCM-like formats with a fixed sample rate but - // a variable number of channels. - - int32_t numChannels; - CHECK(meta->findInt32(kKeyChannelCount, &numChannels)); - - setG711Format(numChannels); - } - - if (!strncasecmp(mMIME, "video/", 6)) { - - if (mIsEncoder) { - setVideoInputFormat(mMIME, meta); - } else { - int32_t width, height; - bool success = meta->findInt32(kKeyWidth, &width); - success = success && meta->findInt32(kKeyHeight, &height); - CHECK(success); - status_t err = setVideoOutputFormat( - mMIME, width, height); - - if (err != OK) { - return err; - } - } - } - - int32_t maxInputSize; - if (meta->findInt32(kKeyMaxInputSize, &maxInputSize)) { - setMinBufferSize(kPortIndexInput, (OMX_U32)maxInputSize); - } - - initOutputFormat(meta); - - if ((mFlags & kClientNeedsFramebuffer) - && !strncmp(mComponentName, "OMX.SEC.", 8)) { - OMX_INDEXTYPE index; - - status_t err = - mOMX->getExtensionIndex( - mNode, - "OMX.SEC.index.ThumbnailMode", - &index); - - if (err != OK) { - return err; - } - - OMX_BOOL enable = OMX_TRUE; - err = mOMX->setConfig(mNode, index, &enable, sizeof(enable)); - - if (err != OK) { - CODEC_LOGE("setConfig('OMX.SEC.index.ThumbnailMode') " - "returned error 0x%08x", err); - - return err; - } - - mQuirks &= ~kOutputBuffersAreUnreadable; - } - - if (mNativeWindow != NULL - && !mIsEncoder - && !strncasecmp(mMIME, "video/", 6) - && !strncmp(mComponentName, "OMX.", 4)) { - status_t err = initNativeWindow(); - if (err != OK) { - return err; - } - } - - return OK; -} - -void OMXCodec::setMinBufferSize(OMX_U32 portIndex, OMX_U32 size) { - OMX_PARAM_PORTDEFINITIONTYPE def; - InitOMXParams(&def); - def.nPortIndex = portIndex; - - status_t err = mOMX->getParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - CHECK_EQ(err, (status_t)OK); - - if ((portIndex == kPortIndexInput && (mQuirks & kInputBufferSizesAreBogus)) - || (def.nBufferSize < size)) { - def.nBufferSize = size; - } - - err = mOMX->setParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - CHECK_EQ(err, (status_t)OK); - - err = mOMX->getParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - CHECK_EQ(err, (status_t)OK); - - // Make sure the setting actually stuck. - if (portIndex == kPortIndexInput - && (mQuirks & kInputBufferSizesAreBogus)) { - CHECK_EQ(def.nBufferSize, size); - } else { - CHECK(def.nBufferSize >= size); - } -} - -status_t OMXCodec::setVideoPortFormatType( - OMX_U32 portIndex, - OMX_VIDEO_CODINGTYPE compressionFormat, - OMX_COLOR_FORMATTYPE colorFormat) { - OMX_VIDEO_PARAM_PORTFORMATTYPE format; - InitOMXParams(&format); - format.nPortIndex = portIndex; - format.nIndex = 0; - bool found = false; - - OMX_U32 index = 0; - for (;;) { - format.nIndex = index; - status_t err = mOMX->getParameter( - mNode, OMX_IndexParamVideoPortFormat, - &format, sizeof(format)); - - if (err != OK) { - return err; - } - - // The following assertion is violated by TI's video decoder. - // CHECK_EQ(format.nIndex, index); - -#if 1 - CODEC_LOGV("portIndex: %ld, index: %ld, eCompressionFormat=%d eColorFormat=%d", - portIndex, - index, format.eCompressionFormat, format.eColorFormat); -#endif - - if (format.eCompressionFormat == compressionFormat - && format.eColorFormat == colorFormat) { - found = true; - break; - } - - ++index; - if (index >= kMaxColorFormatSupported) { - CODEC_LOGE("color format %d or compression format %d is not supported", - colorFormat, compressionFormat); - return UNKNOWN_ERROR; - } - } - - if (!found) { - return UNKNOWN_ERROR; - } - - CODEC_LOGV("found a match."); - status_t err = mOMX->setParameter( - mNode, OMX_IndexParamVideoPortFormat, - &format, sizeof(format)); - - return err; -} - -static size_t getFrameSize( - OMX_COLOR_FORMATTYPE colorFormat, int32_t width, int32_t height) { - switch (colorFormat) { - case OMX_COLOR_FormatYCbYCr: - case OMX_COLOR_FormatCbYCrY: - return width * height * 2; - - case OMX_COLOR_FormatYUV420Planar: - case OMX_COLOR_FormatYUV420SemiPlanar: - case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar: - /* - * FIXME: For the Opaque color format, the frame size does not - * need to be (w*h*3)/2. It just needs to - * be larger than certain minimum buffer size. However, - * currently, this opaque foramt has been tested only on - * YUV420 formats. If that is changed, then we need to revisit - * this part in the future - */ - case OMX_COLOR_FormatAndroidOpaque: - return (width * height * 3) / 2; - - default: - CHECK(!"Should not be here. Unsupported color format."); - break; - } -} - -status_t OMXCodec::findTargetColorFormat( - const sp<MetaData>& meta, OMX_COLOR_FORMATTYPE *colorFormat) { - ALOGV("findTargetColorFormat"); - CHECK(mIsEncoder); - - *colorFormat = OMX_COLOR_FormatYUV420SemiPlanar; - int32_t targetColorFormat; - if (meta->findInt32(kKeyColorFormat, &targetColorFormat)) { - *colorFormat = (OMX_COLOR_FORMATTYPE) targetColorFormat; - } - - // Check whether the target color format is supported. - return isColorFormatSupported(*colorFormat, kPortIndexInput); -} - -status_t OMXCodec::isColorFormatSupported( - OMX_COLOR_FORMATTYPE colorFormat, int portIndex) { - ALOGV("isColorFormatSupported: %d", static_cast<int>(colorFormat)); - - // Enumerate all the color formats supported by - // the omx component to see whether the given - // color format is supported. - OMX_VIDEO_PARAM_PORTFORMATTYPE portFormat; - InitOMXParams(&portFormat); - portFormat.nPortIndex = portIndex; - OMX_U32 index = 0; - portFormat.nIndex = index; - while (true) { - if (OMX_ErrorNone != mOMX->getParameter( - mNode, OMX_IndexParamVideoPortFormat, - &portFormat, sizeof(portFormat))) { - break; - } - // Make sure that omx component does not overwrite - // the incremented index (bug 2897413). - CHECK_EQ(index, portFormat.nIndex); - if (portFormat.eColorFormat == colorFormat) { - CODEC_LOGV("Found supported color format: %d", portFormat.eColorFormat); - return OK; // colorFormat is supported! - } - ++index; - portFormat.nIndex = index; - - if (index >= kMaxColorFormatSupported) { - CODEC_LOGE("More than %ld color formats are supported???", index); - break; - } - } - - CODEC_LOGE("color format %d is not supported", colorFormat); - return UNKNOWN_ERROR; -} - -void OMXCodec::setVideoInputFormat( - const char *mime, const sp<MetaData>& meta) { - - int32_t width, height, frameRate, bitRate, stride, sliceHeight; - bool success = meta->findInt32(kKeyWidth, &width); - success = success && meta->findInt32(kKeyHeight, &height); - success = success && meta->findInt32(kKeyFrameRate, &frameRate); - success = success && meta->findInt32(kKeyBitRate, &bitRate); - success = success && meta->findInt32(kKeyStride, &stride); - success = success && meta->findInt32(kKeySliceHeight, &sliceHeight); - CHECK(success); - CHECK(stride != 0); - - OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused; - if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { - compressionFormat = OMX_VIDEO_CodingAVC; - } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { - compressionFormat = OMX_VIDEO_CodingMPEG4; - } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { - compressionFormat = OMX_VIDEO_CodingH263; - } else { - ALOGE("Not a supported video mime type: %s", mime); - CHECK(!"Should not be here. Not a supported video mime type."); - } - - OMX_COLOR_FORMATTYPE colorFormat; - CHECK_EQ((status_t)OK, findTargetColorFormat(meta, &colorFormat)); - - status_t err; - OMX_PARAM_PORTDEFINITIONTYPE def; - OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video; - - //////////////////////// Input port ///////////////////////// - CHECK_EQ(setVideoPortFormatType( - kPortIndexInput, OMX_VIDEO_CodingUnused, - colorFormat), (status_t)OK); - - InitOMXParams(&def); - def.nPortIndex = kPortIndexInput; - - err = mOMX->getParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - CHECK_EQ(err, (status_t)OK); - - def.nBufferSize = getFrameSize(colorFormat, - stride > 0? stride: -stride, sliceHeight); - - CHECK_EQ((int)def.eDomain, (int)OMX_PortDomainVideo); - - video_def->nFrameWidth = width; - video_def->nFrameHeight = height; - video_def->nStride = stride; - video_def->nSliceHeight = sliceHeight; - video_def->xFramerate = (frameRate << 16); // Q16 format - video_def->eCompressionFormat = OMX_VIDEO_CodingUnused; - video_def->eColorFormat = colorFormat; - - err = mOMX->setParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - CHECK_EQ(err, (status_t)OK); - - //////////////////////// Output port ///////////////////////// - CHECK_EQ(setVideoPortFormatType( - kPortIndexOutput, compressionFormat, OMX_COLOR_FormatUnused), - (status_t)OK); - InitOMXParams(&def); - def.nPortIndex = kPortIndexOutput; - - err = mOMX->getParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - - CHECK_EQ(err, (status_t)OK); - CHECK_EQ((int)def.eDomain, (int)OMX_PortDomainVideo); - - video_def->nFrameWidth = width; - video_def->nFrameHeight = height; - video_def->xFramerate = 0; // No need for output port - video_def->nBitrate = bitRate; // Q16 format - video_def->eCompressionFormat = compressionFormat; - video_def->eColorFormat = OMX_COLOR_FormatUnused; - if (mQuirks & kRequiresLargerEncoderOutputBuffer) { - // Increases the output buffer size - def.nBufferSize = ((def.nBufferSize * 3) >> 1); - } - - err = mOMX->setParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - CHECK_EQ(err, (status_t)OK); - - /////////////////// Codec-specific //////////////////////// - switch (compressionFormat) { - case OMX_VIDEO_CodingMPEG4: - { - CHECK_EQ(setupMPEG4EncoderParameters(meta), (status_t)OK); - break; - } - - case OMX_VIDEO_CodingH263: - CHECK_EQ(setupH263EncoderParameters(meta), (status_t)OK); - break; - - case OMX_VIDEO_CodingAVC: - { - CHECK_EQ(setupAVCEncoderParameters(meta), (status_t)OK); - break; - } - - default: - CHECK(!"Support for this compressionFormat to be implemented."); - break; - } -} - -static OMX_U32 setPFramesSpacing(int32_t iFramesInterval, int32_t frameRate) { - if (iFramesInterval < 0) { - return 0xFFFFFFFF; - } else if (iFramesInterval == 0) { - return 0; - } - OMX_U32 ret = frameRate * iFramesInterval; - CHECK(ret > 1); - return ret; -} - -status_t OMXCodec::setupErrorCorrectionParameters() { - OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE errorCorrectionType; - InitOMXParams(&errorCorrectionType); - errorCorrectionType.nPortIndex = kPortIndexOutput; - - status_t err = mOMX->getParameter( - mNode, OMX_IndexParamVideoErrorCorrection, - &errorCorrectionType, sizeof(errorCorrectionType)); - if (err != OK) { - ALOGW("Error correction param query is not supported"); - return OK; // Optional feature. Ignore this failure - } - - errorCorrectionType.bEnableHEC = OMX_FALSE; - errorCorrectionType.bEnableResync = OMX_TRUE; - errorCorrectionType.nResynchMarkerSpacing = 256; - errorCorrectionType.bEnableDataPartitioning = OMX_FALSE; - errorCorrectionType.bEnableRVLC = OMX_FALSE; - - err = mOMX->setParameter( - mNode, OMX_IndexParamVideoErrorCorrection, - &errorCorrectionType, sizeof(errorCorrectionType)); - if (err != OK) { - ALOGW("Error correction param configuration is not supported"); - } - - // Optional feature. Ignore the failure. - return OK; -} - -status_t OMXCodec::setupBitRate(int32_t bitRate) { - OMX_VIDEO_PARAM_BITRATETYPE bitrateType; - InitOMXParams(&bitrateType); - bitrateType.nPortIndex = kPortIndexOutput; - - status_t err = mOMX->getParameter( - mNode, OMX_IndexParamVideoBitrate, - &bitrateType, sizeof(bitrateType)); - CHECK_EQ(err, (status_t)OK); - - bitrateType.eControlRate = OMX_Video_ControlRateVariable; - bitrateType.nTargetBitrate = bitRate; - - err = mOMX->setParameter( - mNode, OMX_IndexParamVideoBitrate, - &bitrateType, sizeof(bitrateType)); - CHECK_EQ(err, (status_t)OK); - return OK; -} - -status_t OMXCodec::getVideoProfileLevel( - const sp<MetaData>& meta, - const CodecProfileLevel& defaultProfileLevel, - CodecProfileLevel &profileLevel) { - CODEC_LOGV("Default profile: %ld, level %ld", - defaultProfileLevel.mProfile, defaultProfileLevel.mLevel); - - // Are the default profile and level overwriten? - int32_t profile, level; - if (!meta->findInt32(kKeyVideoProfile, &profile)) { - profile = defaultProfileLevel.mProfile; - } - if (!meta->findInt32(kKeyVideoLevel, &level)) { - level = defaultProfileLevel.mLevel; - } - CODEC_LOGV("Target profile: %d, level: %d", profile, level); - - // Are the target profile and level supported by the encoder? - OMX_VIDEO_PARAM_PROFILELEVELTYPE param; - InitOMXParams(¶m); - param.nPortIndex = kPortIndexOutput; - for (param.nProfileIndex = 0;; ++param.nProfileIndex) { - status_t err = mOMX->getParameter( - mNode, OMX_IndexParamVideoProfileLevelQuerySupported, - ¶m, sizeof(param)); - - if (err != OK) break; - - int32_t supportedProfile = static_cast<int32_t>(param.eProfile); - int32_t supportedLevel = static_cast<int32_t>(param.eLevel); - CODEC_LOGV("Supported profile: %d, level %d", - supportedProfile, supportedLevel); - - if (profile == supportedProfile && - level <= supportedLevel) { - // We can further check whether the level is a valid - // value; but we will leave that to the omx encoder component - // via OMX_SetParameter call. - profileLevel.mProfile = profile; - profileLevel.mLevel = level; - return OK; - } - } - - CODEC_LOGE("Target profile (%d) and level (%d) is not supported", - profile, level); - return BAD_VALUE; -} - -status_t OMXCodec::setupH263EncoderParameters(const sp<MetaData>& meta) { - int32_t iFramesInterval, frameRate, bitRate; - bool success = meta->findInt32(kKeyBitRate, &bitRate); - success = success && meta->findInt32(kKeyFrameRate, &frameRate); - success = success && meta->findInt32(kKeyIFramesInterval, &iFramesInterval); - CHECK(success); - OMX_VIDEO_PARAM_H263TYPE h263type; - InitOMXParams(&h263type); - h263type.nPortIndex = kPortIndexOutput; - - status_t err = mOMX->getParameter( - mNode, OMX_IndexParamVideoH263, &h263type, sizeof(h263type)); - CHECK_EQ(err, (status_t)OK); - - h263type.nAllowedPictureTypes = - OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP; - - h263type.nPFrames = setPFramesSpacing(iFramesInterval, frameRate); - if (h263type.nPFrames == 0) { - h263type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI; - } - h263type.nBFrames = 0; - - // Check profile and level parameters - CodecProfileLevel defaultProfileLevel, profileLevel; - defaultProfileLevel.mProfile = h263type.eProfile; - defaultProfileLevel.mLevel = h263type.eLevel; - err = getVideoProfileLevel(meta, defaultProfileLevel, profileLevel); - if (err != OK) return err; - h263type.eProfile = static_cast<OMX_VIDEO_H263PROFILETYPE>(profileLevel.mProfile); - h263type.eLevel = static_cast<OMX_VIDEO_H263LEVELTYPE>(profileLevel.mLevel); - - h263type.bPLUSPTYPEAllowed = OMX_FALSE; - h263type.bForceRoundingTypeToZero = OMX_FALSE; - h263type.nPictureHeaderRepetition = 0; - h263type.nGOBHeaderInterval = 0; - - err = mOMX->setParameter( - mNode, OMX_IndexParamVideoH263, &h263type, sizeof(h263type)); - CHECK_EQ(err, (status_t)OK); - - CHECK_EQ(setupBitRate(bitRate), (status_t)OK); - CHECK_EQ(setupErrorCorrectionParameters(), (status_t)OK); - - return OK; -} - -status_t OMXCodec::setupMPEG4EncoderParameters(const sp<MetaData>& meta) { - int32_t iFramesInterval, frameRate, bitRate; - bool success = meta->findInt32(kKeyBitRate, &bitRate); - success = success && meta->findInt32(kKeyFrameRate, &frameRate); - success = success && meta->findInt32(kKeyIFramesInterval, &iFramesInterval); - CHECK(success); - OMX_VIDEO_PARAM_MPEG4TYPE mpeg4type; - InitOMXParams(&mpeg4type); - mpeg4type.nPortIndex = kPortIndexOutput; - - status_t err = mOMX->getParameter( - mNode, OMX_IndexParamVideoMpeg4, &mpeg4type, sizeof(mpeg4type)); - CHECK_EQ(err, (status_t)OK); - - mpeg4type.nSliceHeaderSpacing = 0; - mpeg4type.bSVH = OMX_FALSE; - mpeg4type.bGov = OMX_FALSE; - - mpeg4type.nAllowedPictureTypes = - OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP; - - mpeg4type.nPFrames = setPFramesSpacing(iFramesInterval, frameRate); - if (mpeg4type.nPFrames == 0) { - mpeg4type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI; - } - mpeg4type.nBFrames = 0; - mpeg4type.nIDCVLCThreshold = 0; - mpeg4type.bACPred = OMX_TRUE; - mpeg4type.nMaxPacketSize = 256; - mpeg4type.nTimeIncRes = 1000; - mpeg4type.nHeaderExtension = 0; - mpeg4type.bReversibleVLC = OMX_FALSE; - - // Check profile and level parameters - CodecProfileLevel defaultProfileLevel, profileLevel; - defaultProfileLevel.mProfile = mpeg4type.eProfile; - defaultProfileLevel.mLevel = mpeg4type.eLevel; - err = getVideoProfileLevel(meta, defaultProfileLevel, profileLevel); - if (err != OK) return err; - mpeg4type.eProfile = static_cast<OMX_VIDEO_MPEG4PROFILETYPE>(profileLevel.mProfile); - mpeg4type.eLevel = static_cast<OMX_VIDEO_MPEG4LEVELTYPE>(profileLevel.mLevel); - - err = mOMX->setParameter( - mNode, OMX_IndexParamVideoMpeg4, &mpeg4type, sizeof(mpeg4type)); - CHECK_EQ(err, (status_t)OK); - - CHECK_EQ(setupBitRate(bitRate), (status_t)OK); - CHECK_EQ(setupErrorCorrectionParameters(), (status_t)OK); - - return OK; -} - -status_t OMXCodec::setupAVCEncoderParameters(const sp<MetaData>& meta) { - int32_t iFramesInterval, frameRate, bitRate; - bool success = meta->findInt32(kKeyBitRate, &bitRate); - success = success && meta->findInt32(kKeyFrameRate, &frameRate); - success = success && meta->findInt32(kKeyIFramesInterval, &iFramesInterval); - CHECK(success); - - OMX_VIDEO_PARAM_AVCTYPE h264type; - InitOMXParams(&h264type); - h264type.nPortIndex = kPortIndexOutput; - - status_t err = mOMX->getParameter( - mNode, OMX_IndexParamVideoAvc, &h264type, sizeof(h264type)); - CHECK_EQ(err, (status_t)OK); - - h264type.nAllowedPictureTypes = - OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP; - - // Check profile and level parameters - CodecProfileLevel defaultProfileLevel, profileLevel; - defaultProfileLevel.mProfile = h264type.eProfile; - defaultProfileLevel.mLevel = h264type.eLevel; - err = getVideoProfileLevel(meta, defaultProfileLevel, profileLevel); - if (err != OK) return err; - h264type.eProfile = static_cast<OMX_VIDEO_AVCPROFILETYPE>(profileLevel.mProfile); - h264type.eLevel = static_cast<OMX_VIDEO_AVCLEVELTYPE>(profileLevel.mLevel); - - // FIXME: - // Remove the workaround after the work in done. - if (!strncmp(mComponentName, "OMX.TI.DUCATI1", 14)) { - h264type.eProfile = OMX_VIDEO_AVCProfileBaseline; - } - - if (h264type.eProfile == OMX_VIDEO_AVCProfileBaseline) { - h264type.nSliceHeaderSpacing = 0; - h264type.bUseHadamard = OMX_TRUE; - h264type.nRefFrames = 1; - h264type.nBFrames = 0; - h264type.nPFrames = setPFramesSpacing(iFramesInterval, frameRate); - if (h264type.nPFrames == 0) { - h264type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI; - } - h264type.nRefIdx10ActiveMinus1 = 0; - h264type.nRefIdx11ActiveMinus1 = 0; - h264type.bEntropyCodingCABAC = OMX_FALSE; - h264type.bWeightedPPrediction = OMX_FALSE; - h264type.bconstIpred = OMX_FALSE; - h264type.bDirect8x8Inference = OMX_FALSE; - h264type.bDirectSpatialTemporal = OMX_FALSE; - h264type.nCabacInitIdc = 0; - } - - if (h264type.nBFrames != 0) { - h264type.nAllowedPictureTypes |= OMX_VIDEO_PictureTypeB; - } - - h264type.bEnableUEP = OMX_FALSE; - h264type.bEnableFMO = OMX_FALSE; - h264type.bEnableASO = OMX_FALSE; - h264type.bEnableRS = OMX_FALSE; - h264type.bFrameMBsOnly = OMX_TRUE; - h264type.bMBAFF = OMX_FALSE; - h264type.eLoopFilterMode = OMX_VIDEO_AVCLoopFilterEnable; - - if (!strcasecmp("OMX.Nvidia.h264.encoder", mComponentName)) { - h264type.eLevel = OMX_VIDEO_AVCLevelMax; - } - - err = mOMX->setParameter( - mNode, OMX_IndexParamVideoAvc, &h264type, sizeof(h264type)); - CHECK_EQ(err, (status_t)OK); - - CHECK_EQ(setupBitRate(bitRate), (status_t)OK); - - return OK; -} - -status_t OMXCodec::setVideoOutputFormat( - const char *mime, OMX_U32 width, OMX_U32 height) { - CODEC_LOGV("setVideoOutputFormat width=%ld, height=%ld", width, height); - - OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused; - if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { - compressionFormat = OMX_VIDEO_CodingAVC; - } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { - compressionFormat = OMX_VIDEO_CodingMPEG4; - } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { - compressionFormat = OMX_VIDEO_CodingH263; - } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_VPX, mime)) { - compressionFormat = OMX_VIDEO_CodingVPX; - } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG2, mime)) { - compressionFormat = OMX_VIDEO_CodingMPEG2; - } else { - ALOGE("Not a supported video mime type: %s", mime); - CHECK(!"Should not be here. Not a supported video mime type."); - } - - status_t err = setVideoPortFormatType( - kPortIndexInput, compressionFormat, OMX_COLOR_FormatUnused); - - if (err != OK) { - return err; - } - -#if 1 - { - OMX_VIDEO_PARAM_PORTFORMATTYPE format; - InitOMXParams(&format); - format.nPortIndex = kPortIndexOutput; - format.nIndex = 0; - - status_t err = mOMX->getParameter( - mNode, OMX_IndexParamVideoPortFormat, - &format, sizeof(format)); - CHECK_EQ(err, (status_t)OK); - CHECK_EQ((int)format.eCompressionFormat, (int)OMX_VIDEO_CodingUnused); - - CHECK(format.eColorFormat == OMX_COLOR_FormatYUV420Planar - || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar - || format.eColorFormat == OMX_COLOR_FormatCbYCrY - || format.eColorFormat == OMX_TI_COLOR_FormatYUV420PackedSemiPlanar - || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar); - - err = mOMX->setParameter( - mNode, OMX_IndexParamVideoPortFormat, - &format, sizeof(format)); - - if (err != OK) { - return err; - } - } -#endif - - OMX_PARAM_PORTDEFINITIONTYPE def; - InitOMXParams(&def); - def.nPortIndex = kPortIndexInput; - - OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video; - - err = mOMX->getParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - - CHECK_EQ(err, (status_t)OK); - -#if 1 - // XXX Need a (much) better heuristic to compute input buffer sizes. - const size_t X = 64 * 1024; - if (def.nBufferSize < X) { - def.nBufferSize = X; - } -#endif - - CHECK_EQ((int)def.eDomain, (int)OMX_PortDomainVideo); - - video_def->nFrameWidth = width; - video_def->nFrameHeight = height; - - video_def->eCompressionFormat = compressionFormat; - video_def->eColorFormat = OMX_COLOR_FormatUnused; - - err = mOMX->setParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - - if (err != OK) { - return err; - } - - //////////////////////////////////////////////////////////////////////////// - - InitOMXParams(&def); - def.nPortIndex = kPortIndexOutput; - - err = mOMX->getParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - CHECK_EQ(err, (status_t)OK); - CHECK_EQ((int)def.eDomain, (int)OMX_PortDomainVideo); - -#if 0 - def.nBufferSize = - (((width + 15) & -16) * ((height + 15) & -16) * 3) / 2; // YUV420 -#endif - - video_def->nFrameWidth = width; - video_def->nFrameHeight = height; - - err = mOMX->setParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - - return err; -} - -OMXCodec::OMXCodec( - const sp<IOMX> &omx, IOMX::node_id node, - uint32_t quirks, uint32_t flags, - bool isEncoder, - const char *mime, - const char *componentName, - const sp<MediaSource> &source, - const sp<ANativeWindow> &nativeWindow) - : mOMX(omx), - mOMXLivesLocally(omx->livesLocally(node, getpid())), - mNode(node), - mQuirks(quirks), - mFlags(flags), - mIsEncoder(isEncoder), - mIsVideo(!strncasecmp("video/", mime, 6)), - mMIME(strdup(mime)), - mComponentName(strdup(componentName)), - mSource(source), - mCodecSpecificDataIndex(0), - mState(LOADED), - mInitialBufferSubmit(true), - mSignalledEOS(false), - mNoMoreOutputData(false), - mOutputPortSettingsHaveChanged(false), - mSeekTimeUs(-1), - mSeekMode(ReadOptions::SEEK_CLOSEST_SYNC), - mTargetTimeUs(-1), - mOutputPortSettingsChangedPending(false), - mSkipCutBuffer(NULL), - mLeftOverBuffer(NULL), - mPaused(false), - mNativeWindow( - (!strncmp(componentName, "OMX.google.", 11) - || !strcmp(componentName, "OMX.Nvidia.mpeg2v.decode")) - ? NULL : nativeWindow) { - mPortStatus[kPortIndexInput] = ENABLED; - mPortStatus[kPortIndexOutput] = ENABLED; - - setComponentRole(); -} - -// static -void OMXCodec::setComponentRole( - const sp<IOMX> &omx, IOMX::node_id node, bool isEncoder, - const char *mime) { - struct MimeToRole { - const char *mime; - const char *decoderRole; - const char *encoderRole; - }; - - static const MimeToRole kMimeToRole[] = { - { MEDIA_MIMETYPE_AUDIO_MPEG, - "audio_decoder.mp3", "audio_encoder.mp3" }, - { MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I, - "audio_decoder.mp1", "audio_encoder.mp1" }, - { MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II, - "audio_decoder.mp2", "audio_encoder.mp2" }, - { MEDIA_MIMETYPE_AUDIO_AMR_NB, - "audio_decoder.amrnb", "audio_encoder.amrnb" }, - { MEDIA_MIMETYPE_AUDIO_AMR_WB, - "audio_decoder.amrwb", "audio_encoder.amrwb" }, - { MEDIA_MIMETYPE_AUDIO_AAC, - "audio_decoder.aac", "audio_encoder.aac" }, - { MEDIA_MIMETYPE_AUDIO_VORBIS, - "audio_decoder.vorbis", "audio_encoder.vorbis" }, - { MEDIA_MIMETYPE_AUDIO_G711_MLAW, - "audio_decoder.g711mlaw", "audio_encoder.g711mlaw" }, - { MEDIA_MIMETYPE_AUDIO_G711_ALAW, - "audio_decoder.g711alaw", "audio_encoder.g711alaw" }, - { MEDIA_MIMETYPE_VIDEO_AVC, - "video_decoder.avc", "video_encoder.avc" }, - { MEDIA_MIMETYPE_VIDEO_MPEG4, - "video_decoder.mpeg4", "video_encoder.mpeg4" }, - { MEDIA_MIMETYPE_VIDEO_H263, - "video_decoder.h263", "video_encoder.h263" }, - { MEDIA_MIMETYPE_VIDEO_VPX, - "video_decoder.vpx", "video_encoder.vpx" }, - }; - - static const size_t kNumMimeToRole = - sizeof(kMimeToRole) / sizeof(kMimeToRole[0]); - - size_t i; - for (i = 0; i < kNumMimeToRole; ++i) { - if (!strcasecmp(mime, kMimeToRole[i].mime)) { - break; - } - } - - if (i == kNumMimeToRole) { - return; - } - - const char *role = - isEncoder ? kMimeToRole[i].encoderRole - : kMimeToRole[i].decoderRole; - - if (role != NULL) { - OMX_PARAM_COMPONENTROLETYPE roleParams; - InitOMXParams(&roleParams); - - strncpy((char *)roleParams.cRole, - role, OMX_MAX_STRINGNAME_SIZE - 1); - - roleParams.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0'; - - status_t err = omx->setParameter( - node, OMX_IndexParamStandardComponentRole, - &roleParams, sizeof(roleParams)); - - if (err != OK) { - ALOGW("Failed to set standard component role '%s'.", role); - } - } -} - -void OMXCodec::setComponentRole() { - setComponentRole(mOMX, mNode, mIsEncoder, mMIME); -} - -OMXCodec::~OMXCodec() { - mSource.clear(); - - CHECK(mState == LOADED || mState == ERROR || mState == LOADED_TO_IDLE); - - status_t err = mOMX->freeNode(mNode); - CHECK_EQ(err, (status_t)OK); - - mNode = NULL; - setState(DEAD); - - clearCodecSpecificData(); - - free(mComponentName); - mComponentName = NULL; - - free(mMIME); - mMIME = NULL; - - delete mSkipCutBuffer; - mSkipCutBuffer = NULL; -} - -status_t OMXCodec::init() { - // mLock is held. - - CHECK_EQ((int)mState, (int)LOADED); - - status_t err; - if (!(mQuirks & kRequiresLoadedToIdleAfterAllocation)) { - err = mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle); - CHECK_EQ(err, (status_t)OK); - setState(LOADED_TO_IDLE); - } - - err = allocateBuffers(); - if (err != (status_t)OK) { - return err; - } - - if (mQuirks & kRequiresLoadedToIdleAfterAllocation) { - err = mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle); - CHECK_EQ(err, (status_t)OK); - - setState(LOADED_TO_IDLE); - } - - while (mState != EXECUTING && mState != ERROR) { - mAsyncCompletion.wait(mLock); - } - - return mState == ERROR ? UNKNOWN_ERROR : OK; -} - -// static -bool OMXCodec::isIntermediateState(State state) { - return state == LOADED_TO_IDLE - || state == IDLE_TO_EXECUTING - || state == EXECUTING_TO_IDLE - || state == IDLE_TO_LOADED - || state == RECONFIGURING; -} - -status_t OMXCodec::allocateBuffers() { - status_t err = allocateBuffersOnPort(kPortIndexInput); - - if (err != OK) { - return err; - } - - return allocateBuffersOnPort(kPortIndexOutput); -} - -status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) { - if (mNativeWindow != NULL && portIndex == kPortIndexOutput) { - return allocateOutputBuffersFromNativeWindow(); - } - - if ((mFlags & kEnableGrallocUsageProtected) && portIndex == kPortIndexOutput) { - ALOGE("protected output buffers must be stent to an ANativeWindow"); - return PERMISSION_DENIED; - } - - status_t err = OK; - if ((mFlags & kStoreMetaDataInVideoBuffers) - && portIndex == kPortIndexInput) { - err = mOMX->storeMetaDataInBuffers(mNode, kPortIndexInput, OMX_TRUE); - if (err != OK) { - ALOGE("Storing meta data in video buffers is not supported"); - return err; - } - } - - OMX_PARAM_PORTDEFINITIONTYPE def; - InitOMXParams(&def); - def.nPortIndex = portIndex; - - err = mOMX->getParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - - if (err != OK) { - return err; - } - - CODEC_LOGV("allocating %lu buffers of size %lu on %s port", - def.nBufferCountActual, def.nBufferSize, - portIndex == kPortIndexInput ? "input" : "output"); - - size_t totalSize = def.nBufferCountActual * def.nBufferSize; - mDealer[portIndex] = new MemoryDealer(totalSize, "OMXCodec"); - - for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) { - sp<IMemory> mem = mDealer[portIndex]->allocate(def.nBufferSize); - CHECK(mem.get() != NULL); - - BufferInfo info; - info.mData = NULL; - info.mSize = def.nBufferSize; - - IOMX::buffer_id buffer; - if (portIndex == kPortIndexInput - && ((mQuirks & kRequiresAllocateBufferOnInputPorts) - || (mFlags & kUseSecureInputBuffers))) { - if (mOMXLivesLocally) { - mem.clear(); - - err = mOMX->allocateBuffer( - mNode, portIndex, def.nBufferSize, &buffer, - &info.mData); - } else { - err = mOMX->allocateBufferWithBackup( - mNode, portIndex, mem, &buffer); - } - } else if (portIndex == kPortIndexOutput - && (mQuirks & kRequiresAllocateBufferOnOutputPorts)) { - if (mOMXLivesLocally) { - mem.clear(); - - err = mOMX->allocateBuffer( - mNode, portIndex, def.nBufferSize, &buffer, - &info.mData); - } else { - err = mOMX->allocateBufferWithBackup( - mNode, portIndex, mem, &buffer); - } - } else { - err = mOMX->useBuffer(mNode, portIndex, mem, &buffer); - } - - if (err != OK) { - ALOGE("allocate_buffer_with_backup failed"); - return err; - } - - if (mem != NULL) { - info.mData = mem->pointer(); - } - - info.mBuffer = buffer; - info.mStatus = OWNED_BY_US; - info.mMem = mem; - info.mMediaBuffer = NULL; - - if (portIndex == kPortIndexOutput) { - if (!(mOMXLivesLocally - && (mQuirks & kRequiresAllocateBufferOnOutputPorts) - && (mQuirks & kDefersOutputBufferAllocation))) { - // If the node does not fill in the buffer ptr at this time, - // we will defer creating the MediaBuffer until receiving - // the first FILL_BUFFER_DONE notification instead. - info.mMediaBuffer = new MediaBuffer(info.mData, info.mSize); - info.mMediaBuffer->setObserver(this); - } - } - - mPortBuffers[portIndex].push(info); - - CODEC_LOGV("allocated buffer %p on %s port", buffer, - portIndex == kPortIndexInput ? "input" : "output"); - } - - if (portIndex == kPortIndexOutput) { - - sp<MetaData> meta = mSource->getFormat(); - int32_t delay = 0; - if (!meta->findInt32(kKeyEncoderDelay, &delay)) { - delay = 0; - } - int32_t padding = 0; - if (!meta->findInt32(kKeyEncoderPadding, &padding)) { - padding = 0; - } - int32_t numchannels = 0; - if (delay + padding) { - if (meta->findInt32(kKeyChannelCount, &numchannels)) { - size_t frameSize = numchannels * sizeof(int16_t); - if (mSkipCutBuffer) { - size_t prevbuffersize = mSkipCutBuffer->size(); - if (prevbuffersize != 0) { - ALOGW("Replacing SkipCutBuffer holding %d bytes", prevbuffersize); - } - delete mSkipCutBuffer; - } - mSkipCutBuffer = new SkipCutBuffer(delay * frameSize, padding * frameSize, - def.nBufferSize); - } - } - } - - // dumpPortStatus(portIndex); - - if (portIndex == kPortIndexInput && (mFlags & kUseSecureInputBuffers)) { - Vector<MediaBuffer *> buffers; - for (size_t i = 0; i < def.nBufferCountActual; ++i) { - const BufferInfo &info = mPortBuffers[kPortIndexInput].itemAt(i); - - MediaBuffer *mbuf = new MediaBuffer(info.mData, info.mSize); - buffers.push(mbuf); - } - - status_t err = mSource->setBuffers(buffers); - - if (err != OK) { - for (size_t i = 0; i < def.nBufferCountActual; ++i) { - buffers.editItemAt(i)->release(); - } - buffers.clear(); - - CODEC_LOGE( - "Codec requested to use secure input buffers but " - "upstream source didn't support that."); - - return err; - } - } - - return OK; -} - -status_t OMXCodec::applyRotation() { - sp<MetaData> meta = mSource->getFormat(); - - int32_t rotationDegrees; - if (!meta->findInt32(kKeyRotation, &rotationDegrees)) { - rotationDegrees = 0; - } - - uint32_t transform; - switch (rotationDegrees) { - case 0: transform = 0; break; - case 90: transform = HAL_TRANSFORM_ROT_90; break; - case 180: transform = HAL_TRANSFORM_ROT_180; break; - case 270: transform = HAL_TRANSFORM_ROT_270; break; - default: transform = 0; break; - } - - status_t err = OK; - - if (transform) { - err = native_window_set_buffers_transform( - mNativeWindow.get(), transform); - } - - return err; -} - -status_t OMXCodec::allocateOutputBuffersFromNativeWindow() { - // Get the number of buffers needed. - OMX_PARAM_PORTDEFINITIONTYPE def; - InitOMXParams(&def); - def.nPortIndex = kPortIndexOutput; - - status_t err = mOMX->getParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - if (err != OK) { - return err; - } - - err = native_window_set_scaling_mode(mNativeWindow.get(), - NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); - - if (err != OK) { - return err; - } - - err = native_window_set_buffers_geometry( - mNativeWindow.get(), - def.format.video.nFrameWidth, - def.format.video.nFrameHeight, - def.format.video.eColorFormat); - - if (err != 0) { - ALOGE("native_window_set_buffers_geometry failed: %s (%d)", - strerror(-err), -err); - return err; - } - - err = applyRotation(); - if (err != OK) { - return err; - } - - // Set up the native window. - OMX_U32 usage = 0; - err = mOMX->getGraphicBufferUsage(mNode, kPortIndexOutput, &usage); - if (err != 0) { - ALOGW("querying usage flags from OMX IL component failed: %d", err); - // XXX: Currently this error is logged, but not fatal. - usage = 0; - } - if (mFlags & kEnableGrallocUsageProtected) { - usage |= GRALLOC_USAGE_PROTECTED; - } - - // Make sure to check whether either Stagefright or the video decoder - // requested protected buffers. - if (usage & GRALLOC_USAGE_PROTECTED) { - // Verify that the ANativeWindow sends images directly to - // SurfaceFlinger. - int queuesToNativeWindow = 0; - err = mNativeWindow->query( - mNativeWindow.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, - &queuesToNativeWindow); - if (err != 0) { - ALOGE("error authenticating native window: %d", err); - return err; - } - if (queuesToNativeWindow != 1) { - ALOGE("native window could not be authenticated"); - return PERMISSION_DENIED; - } - } - - ALOGV("native_window_set_usage usage=0x%lx", usage); - err = native_window_set_usage( - mNativeWindow.get(), usage | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP); - if (err != 0) { - ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), -err); - return err; - } - - int minUndequeuedBufs = 0; - err = mNativeWindow->query(mNativeWindow.get(), - NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBufs); - if (err != 0) { - ALOGE("NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d)", - strerror(-err), -err); - return err; - } - - // XXX: Is this the right logic to use? It's not clear to me what the OMX - // buffer counts refer to - how do they account for the renderer holding on - // to buffers? - if (def.nBufferCountActual < def.nBufferCountMin + minUndequeuedBufs) { - OMX_U32 newBufferCount = def.nBufferCountMin + minUndequeuedBufs; - def.nBufferCountActual = newBufferCount; - err = mOMX->setParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - if (err != OK) { - CODEC_LOGE("setting nBufferCountActual to %lu failed: %d", - newBufferCount, err); - return err; - } - } - - err = native_window_set_buffer_count( - mNativeWindow.get(), def.nBufferCountActual); - if (err != 0) { - ALOGE("native_window_set_buffer_count failed: %s (%d)", strerror(-err), - -err); - return err; - } - - CODEC_LOGV("allocating %lu buffers from a native window of size %lu on " - "output port", def.nBufferCountActual, def.nBufferSize); - - // Dequeue buffers and send them to OMX - for (OMX_U32 i = 0; i < def.nBufferCountActual; i++) { - ANativeWindowBuffer* buf; - err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf); - if (err != 0) { - ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), -err); - break; - } - - sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(buf, false)); - BufferInfo info; - info.mData = NULL; - info.mSize = def.nBufferSize; - info.mStatus = OWNED_BY_US; - info.mMem = NULL; - info.mMediaBuffer = new MediaBuffer(graphicBuffer); - info.mMediaBuffer->setObserver(this); - mPortBuffers[kPortIndexOutput].push(info); - - IOMX::buffer_id bufferId; - err = mOMX->useGraphicBuffer(mNode, kPortIndexOutput, graphicBuffer, - &bufferId); - if (err != 0) { - CODEC_LOGE("registering GraphicBuffer with OMX IL component " - "failed: %d", err); - break; - } - - mPortBuffers[kPortIndexOutput].editItemAt(i).mBuffer = bufferId; - - CODEC_LOGV("registered graphic buffer with ID %p (pointer = %p)", - bufferId, graphicBuffer.get()); - } - - OMX_U32 cancelStart; - OMX_U32 cancelEnd; - if (err != 0) { - // If an error occurred while dequeuing we need to cancel any buffers - // that were dequeued. - cancelStart = 0; - cancelEnd = mPortBuffers[kPortIndexOutput].size(); - } else { - // Return the last two buffers to the native window. - cancelStart = def.nBufferCountActual - minUndequeuedBufs; - cancelEnd = def.nBufferCountActual; - } - - for (OMX_U32 i = cancelStart; i < cancelEnd; i++) { - BufferInfo *info = &mPortBuffers[kPortIndexOutput].editItemAt(i); - cancelBufferToNativeWindow(info); - } - - return err; -} - -status_t OMXCodec::cancelBufferToNativeWindow(BufferInfo *info) { - CHECK_EQ((int)info->mStatus, (int)OWNED_BY_US); - CODEC_LOGV("Calling cancelBuffer on buffer %p", info->mBuffer); - int err = mNativeWindow->cancelBuffer( - mNativeWindow.get(), info->mMediaBuffer->graphicBuffer().get()); - if (err != 0) { - CODEC_LOGE("cancelBuffer failed w/ error 0x%08x", err); - - setState(ERROR); - return err; - } - info->mStatus = OWNED_BY_NATIVE_WINDOW; - return OK; -} - -OMXCodec::BufferInfo* OMXCodec::dequeueBufferFromNativeWindow() { - // Dequeue the next buffer from the native window. - ANativeWindowBuffer* buf; - int err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf); - if (err != 0) { - CODEC_LOGE("dequeueBuffer failed w/ error 0x%08x", err); - - setState(ERROR); - return 0; - } - - // Determine which buffer we just dequeued. - Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput]; - BufferInfo *bufInfo = 0; - for (size_t i = 0; i < buffers->size(); i++) { - sp<GraphicBuffer> graphicBuffer = buffers->itemAt(i). - mMediaBuffer->graphicBuffer(); - if (graphicBuffer->handle == buf->handle) { - bufInfo = &buffers->editItemAt(i); - break; - } - } - - if (bufInfo == 0) { - CODEC_LOGE("dequeued unrecognized buffer: %p", buf); - - setState(ERROR); - return 0; - } - - // The native window no longer owns the buffer. - CHECK_EQ((int)bufInfo->mStatus, (int)OWNED_BY_NATIVE_WINDOW); - bufInfo->mStatus = OWNED_BY_US; - - return bufInfo; -} - -status_t OMXCodec::pushBlankBuffersToNativeWindow() { - status_t err = NO_ERROR; - ANativeWindowBuffer* anb = NULL; - int numBufs = 0; - int minUndequeuedBufs = 0; - - // We need to reconnect to the ANativeWindow as a CPU client to ensure that - // no frames get dropped by SurfaceFlinger assuming that these are video - // frames. - err = native_window_api_disconnect(mNativeWindow.get(), - NATIVE_WINDOW_API_MEDIA); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)", - strerror(-err), -err); - return err; - } - - err = native_window_api_connect(mNativeWindow.get(), - NATIVE_WINDOW_API_CPU); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: api_connect failed: %s (%d)", - strerror(-err), -err); - return err; - } - - err = native_window_set_scaling_mode(mNativeWindow.get(), - NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: set_buffers_geometry failed: %s (%d)", - strerror(-err), -err); - goto error; - } - - err = native_window_set_buffers_geometry(mNativeWindow.get(), 1, 1, - HAL_PIXEL_FORMAT_RGBX_8888); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: set_buffers_geometry failed: %s (%d)", - strerror(-err), -err); - goto error; - } - - err = native_window_set_usage(mNativeWindow.get(), - GRALLOC_USAGE_SW_WRITE_OFTEN); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: set_usage failed: %s (%d)", - strerror(-err), -err); - goto error; - } - - err = mNativeWindow->query(mNativeWindow.get(), - NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBufs); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: MIN_UNDEQUEUED_BUFFERS query " - "failed: %s (%d)", strerror(-err), -err); - goto error; - } - - numBufs = minUndequeuedBufs + 1; - err = native_window_set_buffer_count(mNativeWindow.get(), numBufs); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: set_buffer_count failed: %s (%d)", - strerror(-err), -err); - goto error; - } - - // We push numBufs + 1 buffers to ensure that we've drawn into the same - // buffer twice. This should guarantee that the buffer has been displayed - // on the screen and then been replaced, so an previous video frames are - // guaranteed NOT to be currently displayed. - for (int i = 0; i < numBufs + 1; i++) { - err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &anb); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: dequeueBuffer failed: %s (%d)", - strerror(-err), -err); - goto error; - } - - sp<GraphicBuffer> buf(new GraphicBuffer(anb, false)); - err = mNativeWindow->lockBuffer(mNativeWindow.get(), - buf->getNativeBuffer()); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: lockBuffer failed: %s (%d)", - strerror(-err), -err); - goto error; - } - - // Fill the buffer with the a 1x1 checkerboard pattern ;) - uint32_t* img = NULL; - err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: lock failed: %s (%d)", - strerror(-err), -err); - goto error; - } - - *img = 0; - - err = buf->unlock(); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: unlock failed: %s (%d)", - strerror(-err), -err); - goto error; - } - - err = mNativeWindow->queueBuffer(mNativeWindow.get(), - buf->getNativeBuffer()); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: queueBuffer failed: %s (%d)", - strerror(-err), -err); - goto error; - } - - anb = NULL; - } - -error: - - if (err != NO_ERROR) { - // Clean up after an error. - if (anb != NULL) { - mNativeWindow->cancelBuffer(mNativeWindow.get(), anb); - } - - native_window_api_disconnect(mNativeWindow.get(), - NATIVE_WINDOW_API_CPU); - native_window_api_connect(mNativeWindow.get(), - NATIVE_WINDOW_API_MEDIA); - - return err; - } else { - // Clean up after success. - err = native_window_api_disconnect(mNativeWindow.get(), - NATIVE_WINDOW_API_CPU); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)", - strerror(-err), -err); - return err; - } - - err = native_window_api_connect(mNativeWindow.get(), - NATIVE_WINDOW_API_MEDIA); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: api_connect failed: %s (%d)", - strerror(-err), -err); - return err; - } - - return NO_ERROR; - } -} - -int64_t OMXCodec::getDecodingTimeUs() { - CHECK(mIsEncoder && mIsVideo); - - if (mDecodingTimeList.empty()) { - CHECK(mSignalledEOS || mNoMoreOutputData); - // No corresponding input frame available. - // This could happen when EOS is reached. - return 0; - } - - List<int64_t>::iterator it = mDecodingTimeList.begin(); - int64_t timeUs = *it; - mDecodingTimeList.erase(it); - return timeUs; -} - -void OMXCodec::on_message(const omx_message &msg) { - if (mState == ERROR) { - ALOGW("Dropping OMX message - we're in ERROR state."); - return; - } - - switch (msg.type) { - case omx_message::EVENT: - { - onEvent( - msg.u.event_data.event, msg.u.event_data.data1, - msg.u.event_data.data2); - - break; - } - - case omx_message::EMPTY_BUFFER_DONE: - { - IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer; - - CODEC_LOGV("EMPTY_BUFFER_DONE(buffer: %p)", buffer); - - Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput]; - size_t i = 0; - while (i < buffers->size() && (*buffers)[i].mBuffer != buffer) { - ++i; - } - - CHECK(i < buffers->size()); - if ((*buffers)[i].mStatus != OWNED_BY_COMPONENT) { - ALOGW("We already own input buffer %p, yet received " - "an EMPTY_BUFFER_DONE.", buffer); - } - - BufferInfo* info = &buffers->editItemAt(i); - info->mStatus = OWNED_BY_US; - - // Buffer could not be released until empty buffer done is called. - if (info->mMediaBuffer != NULL) { - if (mIsEncoder && - (mQuirks & kAvoidMemcopyInputRecordingFrames)) { - // If zero-copy mode is enabled this will send the - // input buffer back to the upstream source. - restorePatchedDataPointer(info); - } - - info->mMediaBuffer->release(); - info->mMediaBuffer = NULL; - } - - if (mPortStatus[kPortIndexInput] == DISABLING) { - CODEC_LOGV("Port is disabled, freeing buffer %p", buffer); - - status_t err = freeBuffer(kPortIndexInput, i); - CHECK_EQ(err, (status_t)OK); - } else if (mState != ERROR - && mPortStatus[kPortIndexInput] != SHUTTING_DOWN) { - CHECK_EQ((int)mPortStatus[kPortIndexInput], (int)ENABLED); - - if (mFlags & kUseSecureInputBuffers) { - drainAnyInputBuffer(); - } else { - drainInputBuffer(&buffers->editItemAt(i)); - } - } - break; - } - - case omx_message::FILL_BUFFER_DONE: - { - IOMX::buffer_id buffer = msg.u.extended_buffer_data.buffer; - OMX_U32 flags = msg.u.extended_buffer_data.flags; - - CODEC_LOGV("FILL_BUFFER_DONE(buffer: %p, size: %ld, flags: 0x%08lx, timestamp: %lld us (%.2f secs))", - buffer, - msg.u.extended_buffer_data.range_length, - flags, - msg.u.extended_buffer_data.timestamp, - msg.u.extended_buffer_data.timestamp / 1E6); - - Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput]; - size_t i = 0; - while (i < buffers->size() && (*buffers)[i].mBuffer != buffer) { - ++i; - } - - CHECK(i < buffers->size()); - BufferInfo *info = &buffers->editItemAt(i); - - if (info->mStatus != OWNED_BY_COMPONENT) { - ALOGW("We already own output buffer %p, yet received " - "a FILL_BUFFER_DONE.", buffer); - } - - info->mStatus = OWNED_BY_US; - - if (mPortStatus[kPortIndexOutput] == DISABLING) { - CODEC_LOGV("Port is disabled, freeing buffer %p", buffer); - - status_t err = freeBuffer(kPortIndexOutput, i); - CHECK_EQ(err, (status_t)OK); - -#if 0 - } else if (mPortStatus[kPortIndexOutput] == ENABLED - && (flags & OMX_BUFFERFLAG_EOS)) { - CODEC_LOGV("No more output data."); - mNoMoreOutputData = true; - mBufferFilled.signal(); -#endif - } else if (mPortStatus[kPortIndexOutput] != SHUTTING_DOWN) { - CHECK_EQ((int)mPortStatus[kPortIndexOutput], (int)ENABLED); - - if (info->mMediaBuffer == NULL) { - CHECK(mOMXLivesLocally); - CHECK(mQuirks & kRequiresAllocateBufferOnOutputPorts); - CHECK(mQuirks & kDefersOutputBufferAllocation); - - // The qcom video decoders on Nexus don't actually allocate - // output buffer memory on a call to OMX_AllocateBuffer - // the "pBuffer" member of the OMX_BUFFERHEADERTYPE - // structure is only filled in later. - - info->mMediaBuffer = new MediaBuffer( - msg.u.extended_buffer_data.data_ptr, - info->mSize); - info->mMediaBuffer->setObserver(this); - } - - MediaBuffer *buffer = info->mMediaBuffer; - bool isGraphicBuffer = buffer->graphicBuffer() != NULL; - - if (!isGraphicBuffer - && msg.u.extended_buffer_data.range_offset - + msg.u.extended_buffer_data.range_length - > buffer->size()) { - CODEC_LOGE( - "Codec lied about its buffer size requirements, " - "sending a buffer larger than the originally " - "advertised size in FILL_BUFFER_DONE!"); - } - buffer->set_range( - msg.u.extended_buffer_data.range_offset, - msg.u.extended_buffer_data.range_length); - - buffer->meta_data()->clear(); - - buffer->meta_data()->setInt64( - kKeyTime, msg.u.extended_buffer_data.timestamp); - - if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_SYNCFRAME) { - buffer->meta_data()->setInt32(kKeyIsSyncFrame, true); - } - bool isCodecSpecific = false; - if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_CODECCONFIG) { - buffer->meta_data()->setInt32(kKeyIsCodecConfig, true); - isCodecSpecific = true; - } - - if (isGraphicBuffer || mQuirks & kOutputBuffersAreUnreadable) { - buffer->meta_data()->setInt32(kKeyIsUnreadable, true); - } - - buffer->meta_data()->setPointer( - kKeyPlatformPrivate, - msg.u.extended_buffer_data.platform_private); - - buffer->meta_data()->setPointer( - kKeyBufferID, - msg.u.extended_buffer_data.buffer); - - if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_EOS) { - CODEC_LOGV("No more output data."); - mNoMoreOutputData = true; - } - - if (mIsEncoder && mIsVideo) { - int64_t decodingTimeUs = isCodecSpecific? 0: getDecodingTimeUs(); - buffer->meta_data()->setInt64(kKeyDecodingTime, decodingTimeUs); - } - - if (mTargetTimeUs >= 0) { - CHECK(msg.u.extended_buffer_data.timestamp <= mTargetTimeUs); - - if (msg.u.extended_buffer_data.timestamp < mTargetTimeUs) { - CODEC_LOGV( - "skipping output buffer at timestamp %lld us", - msg.u.extended_buffer_data.timestamp); - - fillOutputBuffer(info); - break; - } - - CODEC_LOGV( - "returning output buffer at target timestamp " - "%lld us", - msg.u.extended_buffer_data.timestamp); - - mTargetTimeUs = -1; - } - - mFilledBuffers.push_back(i); - mBufferFilled.signal(); - if (mIsEncoder) { - sched_yield(); - } - } - - break; - } - - default: - { - CHECK(!"should not be here."); - break; - } - } -} - -// Has the format changed in any way that the client would have to be aware of? -static bool formatHasNotablyChanged( - const sp<MetaData> &from, const sp<MetaData> &to) { - if (from.get() == NULL && to.get() == NULL) { - return false; - } - - if ((from.get() == NULL && to.get() != NULL) - || (from.get() != NULL && to.get() == NULL)) { - return true; - } - - const char *mime_from, *mime_to; - CHECK(from->findCString(kKeyMIMEType, &mime_from)); - CHECK(to->findCString(kKeyMIMEType, &mime_to)); - - if (strcasecmp(mime_from, mime_to)) { - return true; - } - - if (!strcasecmp(mime_from, MEDIA_MIMETYPE_VIDEO_RAW)) { - int32_t colorFormat_from, colorFormat_to; - CHECK(from->findInt32(kKeyColorFormat, &colorFormat_from)); - CHECK(to->findInt32(kKeyColorFormat, &colorFormat_to)); - - if (colorFormat_from != colorFormat_to) { - return true; - } - - int32_t width_from, width_to; - CHECK(from->findInt32(kKeyWidth, &width_from)); - CHECK(to->findInt32(kKeyWidth, &width_to)); - - if (width_from != width_to) { - return true; - } - - int32_t height_from, height_to; - CHECK(from->findInt32(kKeyHeight, &height_from)); - CHECK(to->findInt32(kKeyHeight, &height_to)); - - if (height_from != height_to) { - return true; - } - - int32_t left_from, top_from, right_from, bottom_from; - CHECK(from->findRect( - kKeyCropRect, - &left_from, &top_from, &right_from, &bottom_from)); - - int32_t left_to, top_to, right_to, bottom_to; - CHECK(to->findRect( - kKeyCropRect, - &left_to, &top_to, &right_to, &bottom_to)); - - if (left_to != left_from || top_to != top_from - || right_to != right_from || bottom_to != bottom_from) { - return true; - } - } else if (!strcasecmp(mime_from, MEDIA_MIMETYPE_AUDIO_RAW)) { - int32_t numChannels_from, numChannels_to; - CHECK(from->findInt32(kKeyChannelCount, &numChannels_from)); - CHECK(to->findInt32(kKeyChannelCount, &numChannels_to)); - - if (numChannels_from != numChannels_to) { - return true; - } - - int32_t sampleRate_from, sampleRate_to; - CHECK(from->findInt32(kKeySampleRate, &sampleRate_from)); - CHECK(to->findInt32(kKeySampleRate, &sampleRate_to)); - - if (sampleRate_from != sampleRate_to) { - return true; - } - } - - return false; -} - -void OMXCodec::onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) { - switch (event) { - case OMX_EventCmdComplete: - { - onCmdComplete((OMX_COMMANDTYPE)data1, data2); - break; - } - - case OMX_EventError: - { - CODEC_LOGE("ERROR(0x%08lx, %ld)", data1, data2); - - setState(ERROR); - break; - } - - case OMX_EventPortSettingsChanged: - { - CODEC_LOGV("OMX_EventPortSettingsChanged(port=%ld, data2=0x%08lx)", - data1, data2); - - if (data2 == 0 || data2 == OMX_IndexParamPortDefinition) { - // There is no need to check whether mFilledBuffers is empty or not - // when the OMX_EventPortSettingsChanged is not meant for reallocating - // the output buffers. - if (data1 == kPortIndexOutput) { - CHECK(mFilledBuffers.empty()); - } - onPortSettingsChanged(data1); - } else if (data1 == kPortIndexOutput && - (data2 == OMX_IndexConfigCommonOutputCrop || - data2 == OMX_IndexConfigCommonScale)) { - - sp<MetaData> oldOutputFormat = mOutputFormat; - initOutputFormat(mSource->getFormat()); - - if (data2 == OMX_IndexConfigCommonOutputCrop && - formatHasNotablyChanged(oldOutputFormat, mOutputFormat)) { - mOutputPortSettingsHaveChanged = true; - - } else if (data2 == OMX_IndexConfigCommonScale) { - OMX_CONFIG_SCALEFACTORTYPE scale; - InitOMXParams(&scale); - scale.nPortIndex = kPortIndexOutput; - - // Change display dimension only when necessary. - if (OK == mOMX->getConfig( - mNode, - OMX_IndexConfigCommonScale, - &scale, sizeof(scale))) { - int32_t left, top, right, bottom; - CHECK(mOutputFormat->findRect(kKeyCropRect, - &left, &top, - &right, &bottom)); - - // The scale is in 16.16 format. - // scale 1.0 = 0x010000. When there is no - // need to change the display, skip it. - ALOGV("Get OMX_IndexConfigScale: 0x%lx/0x%lx", - scale.xWidth, scale.xHeight); - - if (scale.xWidth != 0x010000) { - mOutputFormat->setInt32(kKeyDisplayWidth, - ((right - left + 1) * scale.xWidth) >> 16); - mOutputPortSettingsHaveChanged = true; - } - - if (scale.xHeight != 0x010000) { - mOutputFormat->setInt32(kKeyDisplayHeight, - ((bottom - top + 1) * scale.xHeight) >> 16); - mOutputPortSettingsHaveChanged = true; - } - } - } - } - break; - } - -#if 0 - case OMX_EventBufferFlag: - { - CODEC_LOGV("EVENT_BUFFER_FLAG(%ld)", data1); - - if (data1 == kPortIndexOutput) { - mNoMoreOutputData = true; - } - break; - } -#endif - - default: - { - CODEC_LOGV("EVENT(%d, %ld, %ld)", event, data1, data2); - break; - } - } -} - -void OMXCodec::onCmdComplete(OMX_COMMANDTYPE cmd, OMX_U32 data) { - switch (cmd) { - case OMX_CommandStateSet: - { - onStateChange((OMX_STATETYPE)data); - break; - } - - case OMX_CommandPortDisable: - { - OMX_U32 portIndex = data; - CODEC_LOGV("PORT_DISABLED(%ld)", portIndex); - - CHECK(mState == EXECUTING || mState == RECONFIGURING); - CHECK_EQ((int)mPortStatus[portIndex], (int)DISABLING); - CHECK_EQ(mPortBuffers[portIndex].size(), 0u); - - mPortStatus[portIndex] = DISABLED; - - if (mState == RECONFIGURING) { - CHECK_EQ(portIndex, (OMX_U32)kPortIndexOutput); - - sp<MetaData> oldOutputFormat = mOutputFormat; - initOutputFormat(mSource->getFormat()); - - // Don't notify clients if the output port settings change - // wasn't of importance to them, i.e. it may be that just the - // number of buffers has changed and nothing else. - bool formatChanged = formatHasNotablyChanged(oldOutputFormat, mOutputFormat); - if (!mOutputPortSettingsHaveChanged) { - mOutputPortSettingsHaveChanged = formatChanged; - } - - status_t err = enablePortAsync(portIndex); - if (err != OK) { - CODEC_LOGE("enablePortAsync(%ld) failed (err = %d)", portIndex, err); - setState(ERROR); - } else { - err = allocateBuffersOnPort(portIndex); - if (err != OK) { - CODEC_LOGE("allocateBuffersOnPort failed (err = %d)", err); - setState(ERROR); - } - } - } - break; - } - - case OMX_CommandPortEnable: - { - OMX_U32 portIndex = data; - CODEC_LOGV("PORT_ENABLED(%ld)", portIndex); - - CHECK(mState == EXECUTING || mState == RECONFIGURING); - CHECK_EQ((int)mPortStatus[portIndex], (int)ENABLING); - - mPortStatus[portIndex] = ENABLED; - - if (mState == RECONFIGURING) { - CHECK_EQ(portIndex, (OMX_U32)kPortIndexOutput); - - setState(EXECUTING); - - fillOutputBuffers(); - } - break; - } - - case OMX_CommandFlush: - { - OMX_U32 portIndex = data; - - CODEC_LOGV("FLUSH_DONE(%ld)", portIndex); - - CHECK_EQ((int)mPortStatus[portIndex], (int)SHUTTING_DOWN); - mPortStatus[portIndex] = ENABLED; - - CHECK_EQ(countBuffersWeOwn(mPortBuffers[portIndex]), - mPortBuffers[portIndex].size()); - - if (mSkipCutBuffer && mPortStatus[kPortIndexOutput] == ENABLED) { - mSkipCutBuffer->clear(); - } - - if (mState == RECONFIGURING) { - CHECK_EQ(portIndex, (OMX_U32)kPortIndexOutput); - - disablePortAsync(portIndex); - } else if (mState == EXECUTING_TO_IDLE) { - if (mPortStatus[kPortIndexInput] == ENABLED - && mPortStatus[kPortIndexOutput] == ENABLED) { - CODEC_LOGV("Finished flushing both ports, now completing " - "transition from EXECUTING to IDLE."); - - mPortStatus[kPortIndexInput] = SHUTTING_DOWN; - mPortStatus[kPortIndexOutput] = SHUTTING_DOWN; - - status_t err = - mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle); - CHECK_EQ(err, (status_t)OK); - } - } else { - // We're flushing both ports in preparation for seeking. - - if (mPortStatus[kPortIndexInput] == ENABLED - && mPortStatus[kPortIndexOutput] == ENABLED) { - CODEC_LOGV("Finished flushing both ports, now continuing from" - " seek-time."); - - // We implicitly resume pulling on our upstream source. - mPaused = false; - - drainInputBuffers(); - fillOutputBuffers(); - } - - if (mOutputPortSettingsChangedPending) { - CODEC_LOGV( - "Honoring deferred output port settings change."); - - mOutputPortSettingsChangedPending = false; - onPortSettingsChanged(kPortIndexOutput); - } - } - - break; - } - - default: - { - CODEC_LOGV("CMD_COMPLETE(%d, %ld)", cmd, data); - break; - } - } -} - -void OMXCodec::onStateChange(OMX_STATETYPE newState) { - CODEC_LOGV("onStateChange %d", newState); - - switch (newState) { - case OMX_StateIdle: - { - CODEC_LOGV("Now Idle."); - if (mState == LOADED_TO_IDLE) { - status_t err = mOMX->sendCommand( - mNode, OMX_CommandStateSet, OMX_StateExecuting); - - CHECK_EQ(err, (status_t)OK); - - setState(IDLE_TO_EXECUTING); - } else { - CHECK_EQ((int)mState, (int)EXECUTING_TO_IDLE); - - CHECK_EQ( - countBuffersWeOwn(mPortBuffers[kPortIndexInput]), - mPortBuffers[kPortIndexInput].size()); - - CHECK_EQ( - countBuffersWeOwn(mPortBuffers[kPortIndexOutput]), - mPortBuffers[kPortIndexOutput].size()); - - status_t err = mOMX->sendCommand( - mNode, OMX_CommandStateSet, OMX_StateLoaded); - - CHECK_EQ(err, (status_t)OK); - - err = freeBuffersOnPort(kPortIndexInput); - CHECK_EQ(err, (status_t)OK); - - err = freeBuffersOnPort(kPortIndexOutput); - CHECK_EQ(err, (status_t)OK); - - mPortStatus[kPortIndexInput] = ENABLED; - mPortStatus[kPortIndexOutput] = ENABLED; - - if ((mFlags & kEnableGrallocUsageProtected) && - mNativeWindow != NULL) { - // We push enough 1x1 blank buffers to ensure that one of - // them has made it to the display. This allows the OMX - // component teardown to zero out any protected buffers - // without the risk of scanning out one of those buffers. - pushBlankBuffersToNativeWindow(); - } - - setState(IDLE_TO_LOADED); - } - break; - } - - case OMX_StateExecuting: - { - CHECK_EQ((int)mState, (int)IDLE_TO_EXECUTING); - - CODEC_LOGV("Now Executing."); - - mOutputPortSettingsChangedPending = false; - - setState(EXECUTING); - - // Buffers will be submitted to the component in the first - // call to OMXCodec::read as mInitialBufferSubmit is true at - // this point. This ensures that this on_message call returns, - // releases the lock and ::init can notice the state change and - // itself return. - break; - } - - case OMX_StateLoaded: - { - CHECK_EQ((int)mState, (int)IDLE_TO_LOADED); - - CODEC_LOGV("Now Loaded."); - - setState(LOADED); - break; - } - - case OMX_StateInvalid: - { - setState(ERROR); - break; - } - - default: - { - CHECK(!"should not be here."); - break; - } - } -} - -// static -size_t OMXCodec::countBuffersWeOwn(const Vector<BufferInfo> &buffers) { - size_t n = 0; - for (size_t i = 0; i < buffers.size(); ++i) { - if (buffers[i].mStatus != OWNED_BY_COMPONENT) { - ++n; - } - } - - return n; -} - -status_t OMXCodec::freeBuffersOnPort( - OMX_U32 portIndex, bool onlyThoseWeOwn) { - Vector<BufferInfo> *buffers = &mPortBuffers[portIndex]; - - status_t stickyErr = OK; - - for (size_t i = buffers->size(); i-- > 0;) { - BufferInfo *info = &buffers->editItemAt(i); - - if (onlyThoseWeOwn && info->mStatus == OWNED_BY_COMPONENT) { - continue; - } - - CHECK(info->mStatus == OWNED_BY_US - || info->mStatus == OWNED_BY_NATIVE_WINDOW); - - CODEC_LOGV("freeing buffer %p on port %ld", info->mBuffer, portIndex); - - status_t err = freeBuffer(portIndex, i); - - if (err != OK) { - stickyErr = err; - } - - } - - CHECK(onlyThoseWeOwn || buffers->isEmpty()); - - return stickyErr; -} - -status_t OMXCodec::freeBuffer(OMX_U32 portIndex, size_t bufIndex) { - Vector<BufferInfo> *buffers = &mPortBuffers[portIndex]; - - BufferInfo *info = &buffers->editItemAt(bufIndex); - - status_t err = mOMX->freeBuffer(mNode, portIndex, info->mBuffer); - - if (err == OK && info->mMediaBuffer != NULL) { - CHECK_EQ(portIndex, (OMX_U32)kPortIndexOutput); - info->mMediaBuffer->setObserver(NULL); - - // Make sure nobody but us owns this buffer at this point. - CHECK_EQ(info->mMediaBuffer->refcount(), 0); - - // Cancel the buffer if it belongs to an ANativeWindow. - sp<GraphicBuffer> graphicBuffer = info->mMediaBuffer->graphicBuffer(); - if (info->mStatus == OWNED_BY_US && graphicBuffer != 0) { - err = cancelBufferToNativeWindow(info); - } - - info->mMediaBuffer->release(); - info->mMediaBuffer = NULL; - } - - if (err == OK) { - buffers->removeAt(bufIndex); - } - - return err; -} - -void OMXCodec::onPortSettingsChanged(OMX_U32 portIndex) { - CODEC_LOGV("PORT_SETTINGS_CHANGED(%ld)", portIndex); - - CHECK_EQ((int)mState, (int)EXECUTING); - CHECK_EQ(portIndex, (OMX_U32)kPortIndexOutput); - CHECK(!mOutputPortSettingsChangedPending); - - if (mPortStatus[kPortIndexOutput] != ENABLED) { - CODEC_LOGV("Deferring output port settings change."); - mOutputPortSettingsChangedPending = true; - return; - } - - setState(RECONFIGURING); - - if (mQuirks & kNeedsFlushBeforeDisable) { - if (!flushPortAsync(portIndex)) { - onCmdComplete(OMX_CommandFlush, portIndex); - } - } else { - disablePortAsync(portIndex); - } -} - -bool OMXCodec::flushPortAsync(OMX_U32 portIndex) { - CHECK(mState == EXECUTING || mState == RECONFIGURING - || mState == EXECUTING_TO_IDLE); - - CODEC_LOGV("flushPortAsync(%ld): we own %d out of %d buffers already.", - portIndex, countBuffersWeOwn(mPortBuffers[portIndex]), - mPortBuffers[portIndex].size()); - - CHECK_EQ((int)mPortStatus[portIndex], (int)ENABLED); - mPortStatus[portIndex] = SHUTTING_DOWN; - - if ((mQuirks & kRequiresFlushCompleteEmulation) - && countBuffersWeOwn(mPortBuffers[portIndex]) - == mPortBuffers[portIndex].size()) { - // No flush is necessary and this component fails to send a - // flush-complete event in this case. - - return false; - } - - status_t err = - mOMX->sendCommand(mNode, OMX_CommandFlush, portIndex); - CHECK_EQ(err, (status_t)OK); - - return true; -} - -void OMXCodec::disablePortAsync(OMX_U32 portIndex) { - CHECK(mState == EXECUTING || mState == RECONFIGURING); - - CHECK_EQ((int)mPortStatus[portIndex], (int)ENABLED); - mPortStatus[portIndex] = DISABLING; - - CODEC_LOGV("sending OMX_CommandPortDisable(%ld)", portIndex); - status_t err = - mOMX->sendCommand(mNode, OMX_CommandPortDisable, portIndex); - CHECK_EQ(err, (status_t)OK); - - freeBuffersOnPort(portIndex, true); -} - -status_t OMXCodec::enablePortAsync(OMX_U32 portIndex) { - CHECK(mState == EXECUTING || mState == RECONFIGURING); - - CHECK_EQ((int)mPortStatus[portIndex], (int)DISABLED); - mPortStatus[portIndex] = ENABLING; - - CODEC_LOGV("sending OMX_CommandPortEnable(%ld)", portIndex); - return mOMX->sendCommand(mNode, OMX_CommandPortEnable, portIndex); -} - -void OMXCodec::fillOutputBuffers() { - CHECK_EQ((int)mState, (int)EXECUTING); - - // This is a workaround for some decoders not properly reporting - // end-of-output-stream. If we own all input buffers and also own - // all output buffers and we already signalled end-of-input-stream, - // the end-of-output-stream is implied. - if (mSignalledEOS - && countBuffersWeOwn(mPortBuffers[kPortIndexInput]) - == mPortBuffers[kPortIndexInput].size() - && countBuffersWeOwn(mPortBuffers[kPortIndexOutput]) - == mPortBuffers[kPortIndexOutput].size()) { - mNoMoreOutputData = true; - mBufferFilled.signal(); - - return; - } - - Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput]; - for (size_t i = 0; i < buffers->size(); ++i) { - BufferInfo *info = &buffers->editItemAt(i); - if (info->mStatus == OWNED_BY_US) { - fillOutputBuffer(&buffers->editItemAt(i)); - } - } -} - -void OMXCodec::drainInputBuffers() { - CHECK(mState == EXECUTING || mState == RECONFIGURING); - - if (mFlags & kUseSecureInputBuffers) { - Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput]; - for (size_t i = 0; i < buffers->size(); ++i) { - if (!drainAnyInputBuffer() - || (mFlags & kOnlySubmitOneInputBufferAtOneTime)) { - break; - } - } - } else { - Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput]; - for (size_t i = 0; i < buffers->size(); ++i) { - BufferInfo *info = &buffers->editItemAt(i); - - if (info->mStatus != OWNED_BY_US) { - continue; - } - - if (!drainInputBuffer(info)) { - break; - } - - if (mFlags & kOnlySubmitOneInputBufferAtOneTime) { - break; - } - } - } -} - -bool OMXCodec::drainAnyInputBuffer() { - return drainInputBuffer((BufferInfo *)NULL); -} - -OMXCodec::BufferInfo *OMXCodec::findInputBufferByDataPointer(void *ptr) { - Vector<BufferInfo> *infos = &mPortBuffers[kPortIndexInput]; - for (size_t i = 0; i < infos->size(); ++i) { - BufferInfo *info = &infos->editItemAt(i); - - if (info->mData == ptr) { - CODEC_LOGV( - "input buffer data ptr = %p, buffer_id = %p", - ptr, - info->mBuffer); - - return info; - } - } - - TRESPASS(); -} - -OMXCodec::BufferInfo *OMXCodec::findEmptyInputBuffer() { - Vector<BufferInfo> *infos = &mPortBuffers[kPortIndexInput]; - for (size_t i = 0; i < infos->size(); ++i) { - BufferInfo *info = &infos->editItemAt(i); - - if (info->mStatus == OWNED_BY_US) { - return info; - } - } - - TRESPASS(); -} - -bool OMXCodec::drainInputBuffer(BufferInfo *info) { - if (info != NULL) { - CHECK_EQ((int)info->mStatus, (int)OWNED_BY_US); - } - - if (mSignalledEOS) { - return false; - } - - if (mCodecSpecificDataIndex < mCodecSpecificData.size()) { - CHECK(!(mFlags & kUseSecureInputBuffers)); - - const CodecSpecificData *specific = - mCodecSpecificData[mCodecSpecificDataIndex]; - - size_t size = specific->mSize; - - if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mMIME) - && !(mQuirks & kWantsNALFragments)) { - static const uint8_t kNALStartCode[4] = - { 0x00, 0x00, 0x00, 0x01 }; - - CHECK(info->mSize >= specific->mSize + 4); - - size += 4; - - memcpy(info->mData, kNALStartCode, 4); - memcpy((uint8_t *)info->mData + 4, - specific->mData, specific->mSize); - } else { - CHECK(info->mSize >= specific->mSize); - memcpy(info->mData, specific->mData, specific->mSize); - } - - mNoMoreOutputData = false; - - CODEC_LOGV("calling emptyBuffer with codec specific data"); - - status_t err = mOMX->emptyBuffer( - mNode, info->mBuffer, 0, size, - OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_CODECCONFIG, - 0); - CHECK_EQ(err, (status_t)OK); - - info->mStatus = OWNED_BY_COMPONENT; - - ++mCodecSpecificDataIndex; - return true; - } - - if (mPaused) { - return false; - } - - status_t err; - - bool signalEOS = false; - int64_t timestampUs = 0; - - size_t offset = 0; - int32_t n = 0; - - - for (;;) { - MediaBuffer *srcBuffer; - if (mSeekTimeUs >= 0) { - if (mLeftOverBuffer) { - mLeftOverBuffer->release(); - mLeftOverBuffer = NULL; - } - - MediaSource::ReadOptions options; - options.setSeekTo(mSeekTimeUs, mSeekMode); - - mSeekTimeUs = -1; - mSeekMode = ReadOptions::SEEK_CLOSEST_SYNC; - mBufferFilled.signal(); - - err = mSource->read(&srcBuffer, &options); - - if (err == OK) { - int64_t targetTimeUs; - if (srcBuffer->meta_data()->findInt64( - kKeyTargetTime, &targetTimeUs) - && targetTimeUs >= 0) { - CODEC_LOGV("targetTimeUs = %lld us", targetTimeUs); - mTargetTimeUs = targetTimeUs; - } else { - mTargetTimeUs = -1; - } - } - } else if (mLeftOverBuffer) { - srcBuffer = mLeftOverBuffer; - mLeftOverBuffer = NULL; - - err = OK; - } else { - err = mSource->read(&srcBuffer); - } - - if (err != OK) { - signalEOS = true; - mFinalStatus = err; - mSignalledEOS = true; - mBufferFilled.signal(); - break; - } - - if (mFlags & kUseSecureInputBuffers) { - info = findInputBufferByDataPointer(srcBuffer->data()); - CHECK(info != NULL); - } - - size_t remainingBytes = info->mSize - offset; - - if (srcBuffer->range_length() > remainingBytes) { - if (offset == 0) { - CODEC_LOGE( - "Codec's input buffers are too small to accomodate " - "buffer read from source (info->mSize = %d, srcLength = %d)", - info->mSize, srcBuffer->range_length()); - - srcBuffer->release(); - srcBuffer = NULL; - - setState(ERROR); - return false; - } - - mLeftOverBuffer = srcBuffer; - break; - } - - bool releaseBuffer = true; - if (mIsEncoder && (mQuirks & kAvoidMemcopyInputRecordingFrames)) { - CHECK(mOMXLivesLocally && offset == 0); - - OMX_BUFFERHEADERTYPE *header = - (OMX_BUFFERHEADERTYPE *)info->mBuffer; - - CHECK(header->pBuffer == info->mData); - - header->pBuffer = - (OMX_U8 *)srcBuffer->data() + srcBuffer->range_offset(); - - releaseBuffer = false; - info->mMediaBuffer = srcBuffer; - } else { - if (mFlags & kStoreMetaDataInVideoBuffers) { - releaseBuffer = false; - info->mMediaBuffer = srcBuffer; - } - - if (mFlags & kUseSecureInputBuffers) { - // Data in "info" is already provided at this time. - - releaseBuffer = false; - - CHECK(info->mMediaBuffer == NULL); - info->mMediaBuffer = srcBuffer; - } else { - CHECK(srcBuffer->data() != NULL) ; - memcpy((uint8_t *)info->mData + offset, - (const uint8_t *)srcBuffer->data() - + srcBuffer->range_offset(), - srcBuffer->range_length()); - } - } - - int64_t lastBufferTimeUs; - CHECK(srcBuffer->meta_data()->findInt64(kKeyTime, &lastBufferTimeUs)); - CHECK(lastBufferTimeUs >= 0); - if (mIsEncoder && mIsVideo) { - mDecodingTimeList.push_back(lastBufferTimeUs); - } - - if (offset == 0) { - timestampUs = lastBufferTimeUs; - } - - offset += srcBuffer->range_length(); - - if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_VORBIS, mMIME)) { - CHECK(!(mQuirks & kSupportsMultipleFramesPerInputBuffer)); - CHECK_GE(info->mSize, offset + sizeof(int32_t)); - - int32_t numPageSamples; - if (!srcBuffer->meta_data()->findInt32( - kKeyValidSamples, &numPageSamples)) { - numPageSamples = -1; - } - - memcpy((uint8_t *)info->mData + offset, - &numPageSamples, - sizeof(numPageSamples)); - - offset += sizeof(numPageSamples); - } - - if (releaseBuffer) { - srcBuffer->release(); - srcBuffer = NULL; - } - - ++n; - - if (!(mQuirks & kSupportsMultipleFramesPerInputBuffer)) { - break; - } - - int64_t coalescedDurationUs = lastBufferTimeUs - timestampUs; - - if (coalescedDurationUs > 250000ll) { - // Don't coalesce more than 250ms worth of encoded data at once. - break; - } - } - - if (n > 1) { - ALOGV("coalesced %d frames into one input buffer", n); - } - - OMX_U32 flags = OMX_BUFFERFLAG_ENDOFFRAME; - - if (signalEOS) { - flags |= OMX_BUFFERFLAG_EOS; - } else { - mNoMoreOutputData = false; - } - - CODEC_LOGV("Calling emptyBuffer on buffer %p (length %d), " - "timestamp %lld us (%.2f secs)", - info->mBuffer, offset, - timestampUs, timestampUs / 1E6); - - if (info == NULL) { - CHECK(mFlags & kUseSecureInputBuffers); - CHECK(signalEOS); - - // This is fishy, there's still a MediaBuffer corresponding to this - // info available to the source at this point even though we're going - // to use it to signal EOS to the codec. - info = findEmptyInputBuffer(); - } - - err = mOMX->emptyBuffer( - mNode, info->mBuffer, 0, offset, - flags, timestampUs); - - if (err != OK) { - setState(ERROR); - return false; - } - - info->mStatus = OWNED_BY_COMPONENT; - - return true; -} - -void OMXCodec::fillOutputBuffer(BufferInfo *info) { - CHECK_EQ((int)info->mStatus, (int)OWNED_BY_US); - - if (mNoMoreOutputData) { - CODEC_LOGV("There is no more output data available, not " - "calling fillOutputBuffer"); - return; - } - - if (info->mMediaBuffer != NULL) { - sp<GraphicBuffer> graphicBuffer = info->mMediaBuffer->graphicBuffer(); - if (graphicBuffer != 0) { - // When using a native buffer we need to lock the buffer before - // giving it to OMX. - CODEC_LOGV("Calling lockBuffer on %p", info->mBuffer); - int err = mNativeWindow->lockBuffer(mNativeWindow.get(), - graphicBuffer.get()); - if (err != 0) { - CODEC_LOGE("lockBuffer failed w/ error 0x%08x", err); - - setState(ERROR); - return; - } - } - } - - CODEC_LOGV("Calling fillBuffer on buffer %p", info->mBuffer); - status_t err = mOMX->fillBuffer(mNode, info->mBuffer); - - if (err != OK) { - CODEC_LOGE("fillBuffer failed w/ error 0x%08x", err); - - setState(ERROR); - return; - } - - info->mStatus = OWNED_BY_COMPONENT; -} - -bool OMXCodec::drainInputBuffer(IOMX::buffer_id buffer) { - Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput]; - for (size_t i = 0; i < buffers->size(); ++i) { - if ((*buffers)[i].mBuffer == buffer) { - return drainInputBuffer(&buffers->editItemAt(i)); - } - } - - CHECK(!"should not be here."); - - return false; -} - -void OMXCodec::fillOutputBuffer(IOMX::buffer_id buffer) { - Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput]; - for (size_t i = 0; i < buffers->size(); ++i) { - if ((*buffers)[i].mBuffer == buffer) { - fillOutputBuffer(&buffers->editItemAt(i)); - return; - } - } - - CHECK(!"should not be here."); -} - -void OMXCodec::setState(State newState) { - mState = newState; - mAsyncCompletion.signal(); - - // This may cause some spurious wakeups but is necessary to - // unblock the reader if we enter ERROR state. - mBufferFilled.signal(); -} - -status_t OMXCodec::waitForBufferFilled_l() { - - if (mIsEncoder) { - // For timelapse video recording, the timelapse video recording may - // not send an input frame for a _long_ time. Do not use timeout - // for video encoding. - return mBufferFilled.wait(mLock); - } - status_t err = mBufferFilled.waitRelative(mLock, kBufferFilledEventTimeOutNs); - if (err != OK) { - CODEC_LOGE("Timed out waiting for output buffers: %d/%d", - countBuffersWeOwn(mPortBuffers[kPortIndexInput]), - countBuffersWeOwn(mPortBuffers[kPortIndexOutput])); - } - return err; -} - -void OMXCodec::setRawAudioFormat( - OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels) { - - // port definition - OMX_PARAM_PORTDEFINITIONTYPE def; - InitOMXParams(&def); - def.nPortIndex = portIndex; - status_t err = mOMX->getParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - CHECK_EQ(err, (status_t)OK); - def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; - CHECK_EQ(mOMX->setParameter(mNode, OMX_IndexParamPortDefinition, - &def, sizeof(def)), (status_t)OK); - - // pcm param - OMX_AUDIO_PARAM_PCMMODETYPE pcmParams; - InitOMXParams(&pcmParams); - pcmParams.nPortIndex = portIndex; - - err = mOMX->getParameter( - mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams)); - - CHECK_EQ(err, (status_t)OK); - - pcmParams.nChannels = numChannels; - pcmParams.eNumData = OMX_NumericalDataSigned; - pcmParams.bInterleaved = OMX_TRUE; - pcmParams.nBitPerSample = 16; - pcmParams.nSamplingRate = sampleRate; - pcmParams.ePCMMode = OMX_AUDIO_PCMModeLinear; - - if (numChannels == 1) { - pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelCF; - } else { - CHECK_EQ(numChannels, 2); - - pcmParams.eChannelMapping[0] = OMX_AUDIO_ChannelLF; - pcmParams.eChannelMapping[1] = OMX_AUDIO_ChannelRF; - } - - err = mOMX->setParameter( - mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams)); - - CHECK_EQ(err, (status_t)OK); -} - -static OMX_AUDIO_AMRBANDMODETYPE pickModeFromBitRate(bool isAMRWB, int32_t bps) { - if (isAMRWB) { - if (bps <= 6600) { - return OMX_AUDIO_AMRBandModeWB0; - } else if (bps <= 8850) { - return OMX_AUDIO_AMRBandModeWB1; - } else if (bps <= 12650) { - return OMX_AUDIO_AMRBandModeWB2; - } else if (bps <= 14250) { - return OMX_AUDIO_AMRBandModeWB3; - } else if (bps <= 15850) { - return OMX_AUDIO_AMRBandModeWB4; - } else if (bps <= 18250) { - return OMX_AUDIO_AMRBandModeWB5; - } else if (bps <= 19850) { - return OMX_AUDIO_AMRBandModeWB6; - } else if (bps <= 23050) { - return OMX_AUDIO_AMRBandModeWB7; - } - - // 23850 bps - return OMX_AUDIO_AMRBandModeWB8; - } else { // AMRNB - if (bps <= 4750) { - return OMX_AUDIO_AMRBandModeNB0; - } else if (bps <= 5150) { - return OMX_AUDIO_AMRBandModeNB1; - } else if (bps <= 5900) { - return OMX_AUDIO_AMRBandModeNB2; - } else if (bps <= 6700) { - return OMX_AUDIO_AMRBandModeNB3; - } else if (bps <= 7400) { - return OMX_AUDIO_AMRBandModeNB4; - } else if (bps <= 7950) { - return OMX_AUDIO_AMRBandModeNB5; - } else if (bps <= 10200) { - return OMX_AUDIO_AMRBandModeNB6; - } - - // 12200 bps - return OMX_AUDIO_AMRBandModeNB7; - } -} - -void OMXCodec::setAMRFormat(bool isWAMR, int32_t bitRate) { - OMX_U32 portIndex = mIsEncoder ? kPortIndexOutput : kPortIndexInput; - - OMX_AUDIO_PARAM_AMRTYPE def; - InitOMXParams(&def); - def.nPortIndex = portIndex; - - status_t err = - mOMX->getParameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def)); - - CHECK_EQ(err, (status_t)OK); - - def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF; - - def.eAMRBandMode = pickModeFromBitRate(isWAMR, bitRate); - err = mOMX->setParameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def)); - CHECK_EQ(err, (status_t)OK); - - //////////////////////// - - if (mIsEncoder) { - sp<MetaData> format = mSource->getFormat(); - int32_t sampleRate; - int32_t numChannels; - CHECK(format->findInt32(kKeySampleRate, &sampleRate)); - CHECK(format->findInt32(kKeyChannelCount, &numChannels)); - - setRawAudioFormat(kPortIndexInput, sampleRate, numChannels); - } -} - -status_t OMXCodec::setAACFormat( - int32_t numChannels, int32_t sampleRate, int32_t bitRate, bool isADTS) { - if (numChannels > 2) { - ALOGW("Number of channels: (%d) \n", numChannels); - } - - if (mIsEncoder) { - if (isADTS) { - return -EINVAL; - } - - //////////////// input port //////////////////// - setRawAudioFormat(kPortIndexInput, sampleRate, numChannels); - - //////////////// output port //////////////////// - // format - OMX_AUDIO_PARAM_PORTFORMATTYPE format; - InitOMXParams(&format); - format.nPortIndex = kPortIndexOutput; - format.nIndex = 0; - status_t err = OMX_ErrorNone; - while (OMX_ErrorNone == err) { - CHECK_EQ(mOMX->getParameter(mNode, OMX_IndexParamAudioPortFormat, - &format, sizeof(format)), (status_t)OK); - if (format.eEncoding == OMX_AUDIO_CodingAAC) { - break; - } - format.nIndex++; - } - CHECK_EQ((status_t)OK, err); - CHECK_EQ(mOMX->setParameter(mNode, OMX_IndexParamAudioPortFormat, - &format, sizeof(format)), (status_t)OK); - - // port definition - OMX_PARAM_PORTDEFINITIONTYPE def; - InitOMXParams(&def); - def.nPortIndex = kPortIndexOutput; - CHECK_EQ(mOMX->getParameter(mNode, OMX_IndexParamPortDefinition, - &def, sizeof(def)), (status_t)OK); - def.format.audio.bFlagErrorConcealment = OMX_TRUE; - def.format.audio.eEncoding = OMX_AUDIO_CodingAAC; - CHECK_EQ(mOMX->setParameter(mNode, OMX_IndexParamPortDefinition, - &def, sizeof(def)), (status_t)OK); - - // profile - OMX_AUDIO_PARAM_AACPROFILETYPE profile; - InitOMXParams(&profile); - profile.nPortIndex = kPortIndexOutput; - CHECK_EQ(mOMX->getParameter(mNode, OMX_IndexParamAudioAac, - &profile, sizeof(profile)), (status_t)OK); - profile.nChannels = numChannels; - profile.eChannelMode = (numChannels == 1? - OMX_AUDIO_ChannelModeMono: OMX_AUDIO_ChannelModeStereo); - profile.nSampleRate = sampleRate; - profile.nBitRate = bitRate; - profile.nAudioBandWidth = 0; - profile.nFrameLength = 0; - profile.nAACtools = OMX_AUDIO_AACToolAll; - profile.nAACERtools = OMX_AUDIO_AACERNone; - profile.eAACProfile = OMX_AUDIO_AACObjectLC; - profile.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4FF; - err = mOMX->setParameter(mNode, OMX_IndexParamAudioAac, - &profile, sizeof(profile)); - - if (err != OK) { - CODEC_LOGE("setParameter('OMX_IndexParamAudioAac') failed " - "(err = %d)", - err); - return err; - } - } else { - OMX_AUDIO_PARAM_AACPROFILETYPE profile; - InitOMXParams(&profile); - profile.nPortIndex = kPortIndexInput; - - status_t err = mOMX->getParameter( - mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile)); - CHECK_EQ(err, (status_t)OK); - - profile.nChannels = numChannels; - profile.nSampleRate = sampleRate; - - profile.eAACStreamFormat = - isADTS - ? OMX_AUDIO_AACStreamFormatMP4ADTS - : OMX_AUDIO_AACStreamFormatMP4FF; - - err = mOMX->setParameter( - mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile)); - - if (err != OK) { - CODEC_LOGE("setParameter('OMX_IndexParamAudioAac') failed " - "(err = %d)", - err); - return err; - } - } - - return OK; -} - -void OMXCodec::setG711Format(int32_t numChannels) { - CHECK(!mIsEncoder); - setRawAudioFormat(kPortIndexInput, 8000, numChannels); -} - -void OMXCodec::setImageOutputFormat( - OMX_COLOR_FORMATTYPE format, OMX_U32 width, OMX_U32 height) { - CODEC_LOGV("setImageOutputFormat(%ld, %ld)", width, height); - -#if 0 - OMX_INDEXTYPE index; - status_t err = mOMX->get_extension_index( - mNode, "OMX.TI.JPEG.decode.Config.OutputColorFormat", &index); - CHECK_EQ(err, (status_t)OK); - - err = mOMX->set_config(mNode, index, &format, sizeof(format)); - CHECK_EQ(err, (status_t)OK); -#endif - - OMX_PARAM_PORTDEFINITIONTYPE def; - InitOMXParams(&def); - def.nPortIndex = kPortIndexOutput; - - status_t err = mOMX->getParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - CHECK_EQ(err, (status_t)OK); - - CHECK_EQ((int)def.eDomain, (int)OMX_PortDomainImage); - - OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image; - - CHECK_EQ((int)imageDef->eCompressionFormat, (int)OMX_IMAGE_CodingUnused); - imageDef->eColorFormat = format; - imageDef->nFrameWidth = width; - imageDef->nFrameHeight = height; - - switch (format) { - case OMX_COLOR_FormatYUV420PackedPlanar: - case OMX_COLOR_FormatYUV411Planar: - { - def.nBufferSize = (width * height * 3) / 2; - break; - } - - case OMX_COLOR_FormatCbYCrY: - { - def.nBufferSize = width * height * 2; - break; - } - - case OMX_COLOR_Format32bitARGB8888: - { - def.nBufferSize = width * height * 4; - break; - } - - case OMX_COLOR_Format16bitARGB4444: - case OMX_COLOR_Format16bitARGB1555: - case OMX_COLOR_Format16bitRGB565: - case OMX_COLOR_Format16bitBGR565: - { - def.nBufferSize = width * height * 2; - break; - } - - default: - CHECK(!"Should not be here. Unknown color format."); - break; - } - - def.nBufferCountActual = def.nBufferCountMin; - - err = mOMX->setParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - CHECK_EQ(err, (status_t)OK); -} - -void OMXCodec::setJPEGInputFormat( - OMX_U32 width, OMX_U32 height, OMX_U32 compressedSize) { - OMX_PARAM_PORTDEFINITIONTYPE def; - InitOMXParams(&def); - def.nPortIndex = kPortIndexInput; - - status_t err = mOMX->getParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - CHECK_EQ(err, (status_t)OK); - - CHECK_EQ((int)def.eDomain, (int)OMX_PortDomainImage); - OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image; - - CHECK_EQ((int)imageDef->eCompressionFormat, (int)OMX_IMAGE_CodingJPEG); - imageDef->nFrameWidth = width; - imageDef->nFrameHeight = height; - - def.nBufferSize = compressedSize; - def.nBufferCountActual = def.nBufferCountMin; - - err = mOMX->setParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - CHECK_EQ(err, (status_t)OK); -} - -void OMXCodec::addCodecSpecificData(const void *data, size_t size) { - CodecSpecificData *specific = - (CodecSpecificData *)malloc(sizeof(CodecSpecificData) + size - 1); - - specific->mSize = size; - memcpy(specific->mData, data, size); - - mCodecSpecificData.push(specific); -} - -void OMXCodec::clearCodecSpecificData() { - for (size_t i = 0; i < mCodecSpecificData.size(); ++i) { - free(mCodecSpecificData.editItemAt(i)); - } - mCodecSpecificData.clear(); - mCodecSpecificDataIndex = 0; -} - -status_t OMXCodec::start(MetaData *meta) { - Mutex::Autolock autoLock(mLock); - - if (mState != LOADED) { - return UNKNOWN_ERROR; - } - - sp<MetaData> params = new MetaData; - if (mQuirks & kWantsNALFragments) { - params->setInt32(kKeyWantsNALFragments, true); - } - if (meta) { - int64_t startTimeUs = 0; - int64_t timeUs; - if (meta->findInt64(kKeyTime, &timeUs)) { - startTimeUs = timeUs; - } - params->setInt64(kKeyTime, startTimeUs); - } - status_t err = mSource->start(params.get()); - - if (err != OK) { - return err; - } - - mCodecSpecificDataIndex = 0; - mInitialBufferSubmit = true; - mSignalledEOS = false; - mNoMoreOutputData = false; - mOutputPortSettingsHaveChanged = false; - mSeekTimeUs = -1; - mSeekMode = ReadOptions::SEEK_CLOSEST_SYNC; - mTargetTimeUs = -1; - mFilledBuffers.clear(); - mPaused = false; - - return init(); -} - -status_t OMXCodec::stop() { - CODEC_LOGV("stop mState=%d", mState); - - Mutex::Autolock autoLock(mLock); - - while (isIntermediateState(mState)) { - mAsyncCompletion.wait(mLock); - } - - bool isError = false; - switch (mState) { - case LOADED: - break; - - case ERROR: - { - OMX_STATETYPE state = OMX_StateInvalid; - status_t err = mOMX->getState(mNode, &state); - CHECK_EQ(err, (status_t)OK); - - if (state != OMX_StateExecuting) { - break; - } - // else fall through to the idling code - isError = true; - } - - case EXECUTING: - { - setState(EXECUTING_TO_IDLE); - - if (mQuirks & kRequiresFlushBeforeShutdown) { - CODEC_LOGV("This component requires a flush before transitioning " - "from EXECUTING to IDLE..."); - - bool emulateInputFlushCompletion = - !flushPortAsync(kPortIndexInput); - - bool emulateOutputFlushCompletion = - !flushPortAsync(kPortIndexOutput); - - if (emulateInputFlushCompletion) { - onCmdComplete(OMX_CommandFlush, kPortIndexInput); - } - - if (emulateOutputFlushCompletion) { - onCmdComplete(OMX_CommandFlush, kPortIndexOutput); - } - } else { - mPortStatus[kPortIndexInput] = SHUTTING_DOWN; - mPortStatus[kPortIndexOutput] = SHUTTING_DOWN; - - status_t err = - mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle); - CHECK_EQ(err, (status_t)OK); - } - - while (mState != LOADED && mState != ERROR) { - mAsyncCompletion.wait(mLock); - } - - if (isError) { - // We were in the ERROR state coming in, so restore that now - // that we've idled the OMX component. - setState(ERROR); - } - - break; - } - - default: - { - CHECK(!"should not be here."); - break; - } - } - - if (mLeftOverBuffer) { - mLeftOverBuffer->release(); - mLeftOverBuffer = NULL; - } - - mSource->stop(); - - CODEC_LOGV("stopped in state %d", mState); - - return OK; -} - -sp<MetaData> OMXCodec::getFormat() { - Mutex::Autolock autoLock(mLock); - - return mOutputFormat; -} - -status_t OMXCodec::read( - MediaBuffer **buffer, const ReadOptions *options) { - status_t err = OK; - *buffer = NULL; - - Mutex::Autolock autoLock(mLock); - - if (mState != EXECUTING && mState != RECONFIGURING) { - return UNKNOWN_ERROR; - } - - bool seeking = false; - int64_t seekTimeUs; - ReadOptions::SeekMode seekMode; - if (options && options->getSeekTo(&seekTimeUs, &seekMode)) { - seeking = true; - } - - if (mInitialBufferSubmit) { - mInitialBufferSubmit = false; - - if (seeking) { - CHECK(seekTimeUs >= 0); - mSeekTimeUs = seekTimeUs; - mSeekMode = seekMode; - - // There's no reason to trigger the code below, there's - // nothing to flush yet. - seeking = false; - mPaused = false; - } - - drainInputBuffers(); - - if (mState == EXECUTING) { - // Otherwise mState == RECONFIGURING and this code will trigger - // after the output port is reenabled. - fillOutputBuffers(); - } - } - - if (seeking) { - while (mState == RECONFIGURING) { - if ((err = waitForBufferFilled_l()) != OK) { - return err; - } - } - - if (mState != EXECUTING) { - return UNKNOWN_ERROR; - } - - CODEC_LOGV("seeking to %lld us (%.2f secs)", seekTimeUs, seekTimeUs / 1E6); - - mSignalledEOS = false; - - CHECK(seekTimeUs >= 0); - mSeekTimeUs = seekTimeUs; - mSeekMode = seekMode; - - mFilledBuffers.clear(); - - CHECK_EQ((int)mState, (int)EXECUTING); - - bool emulateInputFlushCompletion = !flushPortAsync(kPortIndexInput); - bool emulateOutputFlushCompletion = !flushPortAsync(kPortIndexOutput); - - if (emulateInputFlushCompletion) { - onCmdComplete(OMX_CommandFlush, kPortIndexInput); - } - - if (emulateOutputFlushCompletion) { - onCmdComplete(OMX_CommandFlush, kPortIndexOutput); - } - - while (mSeekTimeUs >= 0) { - if ((err = waitForBufferFilled_l()) != OK) { - return err; - } - } - } - - while (mState != ERROR && !mNoMoreOutputData && mFilledBuffers.empty()) { - if ((err = waitForBufferFilled_l()) != OK) { - return err; - } - } - - if (mState == ERROR) { - return UNKNOWN_ERROR; - } - - if (mFilledBuffers.empty()) { - return mSignalledEOS ? mFinalStatus : ERROR_END_OF_STREAM; - } - - if (mOutputPortSettingsHaveChanged) { - mOutputPortSettingsHaveChanged = false; - - return INFO_FORMAT_CHANGED; - } - - size_t index = *mFilledBuffers.begin(); - mFilledBuffers.erase(mFilledBuffers.begin()); - - BufferInfo *info = &mPortBuffers[kPortIndexOutput].editItemAt(index); - CHECK_EQ((int)info->mStatus, (int)OWNED_BY_US); - info->mStatus = OWNED_BY_CLIENT; - - info->mMediaBuffer->add_ref(); - if (mSkipCutBuffer) { - mSkipCutBuffer->submit(info->mMediaBuffer); - } - *buffer = info->mMediaBuffer; - - return OK; -} - -void OMXCodec::signalBufferReturned(MediaBuffer *buffer) { - Mutex::Autolock autoLock(mLock); - - Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput]; - for (size_t i = 0; i < buffers->size(); ++i) { - BufferInfo *info = &buffers->editItemAt(i); - - if (info->mMediaBuffer == buffer) { - CHECK_EQ((int)mPortStatus[kPortIndexOutput], (int)ENABLED); - CHECK_EQ((int)info->mStatus, (int)OWNED_BY_CLIENT); - - info->mStatus = OWNED_BY_US; - - if (buffer->graphicBuffer() == 0) { - fillOutputBuffer(info); - } else { - sp<MetaData> metaData = info->mMediaBuffer->meta_data(); - int32_t rendered = 0; - if (!metaData->findInt32(kKeyRendered, &rendered)) { - rendered = 0; - } - if (!rendered) { - status_t err = cancelBufferToNativeWindow(info); - if (err < 0) { - return; - } - } - - info->mStatus = OWNED_BY_NATIVE_WINDOW; - - // Dequeue the next buffer from the native window. - BufferInfo *nextBufInfo = dequeueBufferFromNativeWindow(); - if (nextBufInfo == 0) { - return; - } - - // Give the buffer to the OMX node to fill. - fillOutputBuffer(nextBufInfo); - } - return; - } - } - - CHECK(!"should not be here."); -} - -static const char *imageCompressionFormatString(OMX_IMAGE_CODINGTYPE type) { - static const char *kNames[] = { - "OMX_IMAGE_CodingUnused", - "OMX_IMAGE_CodingAutoDetect", - "OMX_IMAGE_CodingJPEG", - "OMX_IMAGE_CodingJPEG2K", - "OMX_IMAGE_CodingEXIF", - "OMX_IMAGE_CodingTIFF", - "OMX_IMAGE_CodingGIF", - "OMX_IMAGE_CodingPNG", - "OMX_IMAGE_CodingLZW", - "OMX_IMAGE_CodingBMP", - }; - - size_t numNames = sizeof(kNames) / sizeof(kNames[0]); - - if (type < 0 || (size_t)type >= numNames) { - return "UNKNOWN"; - } else { - return kNames[type]; - } -} - -static const char *colorFormatString(OMX_COLOR_FORMATTYPE type) { - static const char *kNames[] = { - "OMX_COLOR_FormatUnused", - "OMX_COLOR_FormatMonochrome", - "OMX_COLOR_Format8bitRGB332", - "OMX_COLOR_Format12bitRGB444", - "OMX_COLOR_Format16bitARGB4444", - "OMX_COLOR_Format16bitARGB1555", - "OMX_COLOR_Format16bitRGB565", - "OMX_COLOR_Format16bitBGR565", - "OMX_COLOR_Format18bitRGB666", - "OMX_COLOR_Format18bitARGB1665", - "OMX_COLOR_Format19bitARGB1666", - "OMX_COLOR_Format24bitRGB888", - "OMX_COLOR_Format24bitBGR888", - "OMX_COLOR_Format24bitARGB1887", - "OMX_COLOR_Format25bitARGB1888", - "OMX_COLOR_Format32bitBGRA8888", - "OMX_COLOR_Format32bitARGB8888", - "OMX_COLOR_FormatYUV411Planar", - "OMX_COLOR_FormatYUV411PackedPlanar", - "OMX_COLOR_FormatYUV420Planar", - "OMX_COLOR_FormatYUV420PackedPlanar", - "OMX_COLOR_FormatYUV420SemiPlanar", - "OMX_COLOR_FormatYUV422Planar", - "OMX_COLOR_FormatYUV422PackedPlanar", - "OMX_COLOR_FormatYUV422SemiPlanar", - "OMX_COLOR_FormatYCbYCr", - "OMX_COLOR_FormatYCrYCb", - "OMX_COLOR_FormatCbYCrY", - "OMX_COLOR_FormatCrYCbY", - "OMX_COLOR_FormatYUV444Interleaved", - "OMX_COLOR_FormatRawBayer8bit", - "OMX_COLOR_FormatRawBayer10bit", - "OMX_COLOR_FormatRawBayer8bitcompressed", - "OMX_COLOR_FormatL2", - "OMX_COLOR_FormatL4", - "OMX_COLOR_FormatL8", - "OMX_COLOR_FormatL16", - "OMX_COLOR_FormatL24", - "OMX_COLOR_FormatL32", - "OMX_COLOR_FormatYUV420PackedSemiPlanar", - "OMX_COLOR_FormatYUV422PackedSemiPlanar", - "OMX_COLOR_Format18BitBGR666", - "OMX_COLOR_Format24BitARGB6666", - "OMX_COLOR_Format24BitABGR6666", - }; - - size_t numNames = sizeof(kNames) / sizeof(kNames[0]); - - if (type == OMX_TI_COLOR_FormatYUV420PackedSemiPlanar) { - return "OMX_TI_COLOR_FormatYUV420PackedSemiPlanar"; - } else if (type == OMX_QCOM_COLOR_FormatYVU420SemiPlanar) { - return "OMX_QCOM_COLOR_FormatYVU420SemiPlanar"; - } else if (type < 0 || (size_t)type >= numNames) { - return "UNKNOWN"; - } else { - return kNames[type]; - } -} - -static const char *videoCompressionFormatString(OMX_VIDEO_CODINGTYPE type) { - static const char *kNames[] = { - "OMX_VIDEO_CodingUnused", - "OMX_VIDEO_CodingAutoDetect", - "OMX_VIDEO_CodingMPEG2", - "OMX_VIDEO_CodingH263", - "OMX_VIDEO_CodingMPEG4", - "OMX_VIDEO_CodingWMV", - "OMX_VIDEO_CodingRV", - "OMX_VIDEO_CodingAVC", - "OMX_VIDEO_CodingMJPEG", - }; - - size_t numNames = sizeof(kNames) / sizeof(kNames[0]); - - if (type < 0 || (size_t)type >= numNames) { - return "UNKNOWN"; - } else { - return kNames[type]; - } -} - -static const char *audioCodingTypeString(OMX_AUDIO_CODINGTYPE type) { - static const char *kNames[] = { - "OMX_AUDIO_CodingUnused", - "OMX_AUDIO_CodingAutoDetect", - "OMX_AUDIO_CodingPCM", - "OMX_AUDIO_CodingADPCM", - "OMX_AUDIO_CodingAMR", - "OMX_AUDIO_CodingGSMFR", - "OMX_AUDIO_CodingGSMEFR", - "OMX_AUDIO_CodingGSMHR", - "OMX_AUDIO_CodingPDCFR", - "OMX_AUDIO_CodingPDCEFR", - "OMX_AUDIO_CodingPDCHR", - "OMX_AUDIO_CodingTDMAFR", - "OMX_AUDIO_CodingTDMAEFR", - "OMX_AUDIO_CodingQCELP8", - "OMX_AUDIO_CodingQCELP13", - "OMX_AUDIO_CodingEVRC", - "OMX_AUDIO_CodingSMV", - "OMX_AUDIO_CodingG711", - "OMX_AUDIO_CodingG723", - "OMX_AUDIO_CodingG726", - "OMX_AUDIO_CodingG729", - "OMX_AUDIO_CodingAAC", - "OMX_AUDIO_CodingMP3", - "OMX_AUDIO_CodingSBC", - "OMX_AUDIO_CodingVORBIS", - "OMX_AUDIO_CodingWMA", - "OMX_AUDIO_CodingRA", - "OMX_AUDIO_CodingMIDI", - }; - - size_t numNames = sizeof(kNames) / sizeof(kNames[0]); - - if (type < 0 || (size_t)type >= numNames) { - return "UNKNOWN"; - } else { - return kNames[type]; - } -} - -static const char *audioPCMModeString(OMX_AUDIO_PCMMODETYPE type) { - static const char *kNames[] = { - "OMX_AUDIO_PCMModeLinear", - "OMX_AUDIO_PCMModeALaw", - "OMX_AUDIO_PCMModeMULaw", - }; - - size_t numNames = sizeof(kNames) / sizeof(kNames[0]); - - if (type < 0 || (size_t)type >= numNames) { - return "UNKNOWN"; - } else { - return kNames[type]; - } -} - -static const char *amrBandModeString(OMX_AUDIO_AMRBANDMODETYPE type) { - static const char *kNames[] = { - "OMX_AUDIO_AMRBandModeUnused", - "OMX_AUDIO_AMRBandModeNB0", - "OMX_AUDIO_AMRBandModeNB1", - "OMX_AUDIO_AMRBandModeNB2", - "OMX_AUDIO_AMRBandModeNB3", - "OMX_AUDIO_AMRBandModeNB4", - "OMX_AUDIO_AMRBandModeNB5", - "OMX_AUDIO_AMRBandModeNB6", - "OMX_AUDIO_AMRBandModeNB7", - "OMX_AUDIO_AMRBandModeWB0", - "OMX_AUDIO_AMRBandModeWB1", - "OMX_AUDIO_AMRBandModeWB2", - "OMX_AUDIO_AMRBandModeWB3", - "OMX_AUDIO_AMRBandModeWB4", - "OMX_AUDIO_AMRBandModeWB5", - "OMX_AUDIO_AMRBandModeWB6", - "OMX_AUDIO_AMRBandModeWB7", - "OMX_AUDIO_AMRBandModeWB8", - }; - - size_t numNames = sizeof(kNames) / sizeof(kNames[0]); - - if (type < 0 || (size_t)type >= numNames) { - return "UNKNOWN"; - } else { - return kNames[type]; - } -} - -static const char *amrFrameFormatString(OMX_AUDIO_AMRFRAMEFORMATTYPE type) { - static const char *kNames[] = { - "OMX_AUDIO_AMRFrameFormatConformance", - "OMX_AUDIO_AMRFrameFormatIF1", - "OMX_AUDIO_AMRFrameFormatIF2", - "OMX_AUDIO_AMRFrameFormatFSF", - "OMX_AUDIO_AMRFrameFormatRTPPayload", - "OMX_AUDIO_AMRFrameFormatITU", - }; - - size_t numNames = sizeof(kNames) / sizeof(kNames[0]); - - if (type < 0 || (size_t)type >= numNames) { - return "UNKNOWN"; - } else { - return kNames[type]; - } -} - -void OMXCodec::dumpPortStatus(OMX_U32 portIndex) { - OMX_PARAM_PORTDEFINITIONTYPE def; - InitOMXParams(&def); - def.nPortIndex = portIndex; - - status_t err = mOMX->getParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - CHECK_EQ(err, (status_t)OK); - - printf("%s Port = {\n", portIndex == kPortIndexInput ? "Input" : "Output"); - - CHECK((portIndex == kPortIndexInput && def.eDir == OMX_DirInput) - || (portIndex == kPortIndexOutput && def.eDir == OMX_DirOutput)); - - printf(" nBufferCountActual = %ld\n", def.nBufferCountActual); - printf(" nBufferCountMin = %ld\n", def.nBufferCountMin); - printf(" nBufferSize = %ld\n", def.nBufferSize); - - switch (def.eDomain) { - case OMX_PortDomainImage: - { - const OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image; - - printf("\n"); - printf(" // Image\n"); - printf(" nFrameWidth = %ld\n", imageDef->nFrameWidth); - printf(" nFrameHeight = %ld\n", imageDef->nFrameHeight); - printf(" nStride = %ld\n", imageDef->nStride); - - printf(" eCompressionFormat = %s\n", - imageCompressionFormatString(imageDef->eCompressionFormat)); - - printf(" eColorFormat = %s\n", - colorFormatString(imageDef->eColorFormat)); - - break; - } - - case OMX_PortDomainVideo: - { - OMX_VIDEO_PORTDEFINITIONTYPE *videoDef = &def.format.video; - - printf("\n"); - printf(" // Video\n"); - printf(" nFrameWidth = %ld\n", videoDef->nFrameWidth); - printf(" nFrameHeight = %ld\n", videoDef->nFrameHeight); - printf(" nStride = %ld\n", videoDef->nStride); - - printf(" eCompressionFormat = %s\n", - videoCompressionFormatString(videoDef->eCompressionFormat)); - - printf(" eColorFormat = %s\n", - colorFormatString(videoDef->eColorFormat)); - - break; - } - - case OMX_PortDomainAudio: - { - OMX_AUDIO_PORTDEFINITIONTYPE *audioDef = &def.format.audio; - - printf("\n"); - printf(" // Audio\n"); - printf(" eEncoding = %s\n", - audioCodingTypeString(audioDef->eEncoding)); - - if (audioDef->eEncoding == OMX_AUDIO_CodingPCM) { - OMX_AUDIO_PARAM_PCMMODETYPE params; - InitOMXParams(¶ms); - params.nPortIndex = portIndex; - - err = mOMX->getParameter( - mNode, OMX_IndexParamAudioPcm, ¶ms, sizeof(params)); - CHECK_EQ(err, (status_t)OK); - - printf(" nSamplingRate = %ld\n", params.nSamplingRate); - printf(" nChannels = %ld\n", params.nChannels); - printf(" bInterleaved = %d\n", params.bInterleaved); - printf(" nBitPerSample = %ld\n", params.nBitPerSample); - - printf(" eNumData = %s\n", - params.eNumData == OMX_NumericalDataSigned - ? "signed" : "unsigned"); - - printf(" ePCMMode = %s\n", audioPCMModeString(params.ePCMMode)); - } else if (audioDef->eEncoding == OMX_AUDIO_CodingAMR) { - OMX_AUDIO_PARAM_AMRTYPE amr; - InitOMXParams(&amr); - amr.nPortIndex = portIndex; - - err = mOMX->getParameter( - mNode, OMX_IndexParamAudioAmr, &amr, sizeof(amr)); - CHECK_EQ(err, (status_t)OK); - - printf(" nChannels = %ld\n", amr.nChannels); - printf(" eAMRBandMode = %s\n", - amrBandModeString(amr.eAMRBandMode)); - printf(" eAMRFrameFormat = %s\n", - amrFrameFormatString(amr.eAMRFrameFormat)); - } - - break; - } - - default: - { - printf(" // Unknown\n"); - break; - } - } - - printf("}\n"); -} - -status_t OMXCodec::initNativeWindow() { - // Enable use of a GraphicBuffer as the output for this node. This must - // happen before getting the IndexParamPortDefinition parameter because it - // will affect the pixel format that the node reports. - status_t err = mOMX->enableGraphicBuffers(mNode, kPortIndexOutput, OMX_TRUE); - if (err != 0) { - return err; - } - - return OK; -} - -void OMXCodec::initNativeWindowCrop() { - int32_t left, top, right, bottom; - - CHECK(mOutputFormat->findRect( - kKeyCropRect, - &left, &top, &right, &bottom)); - - android_native_rect_t crop; - crop.left = left; - crop.top = top; - crop.right = right + 1; - crop.bottom = bottom + 1; - - // We'll ignore any errors here, if the surface is - // already invalid, we'll know soon enough. - native_window_set_crop(mNativeWindow.get(), &crop); -} - -void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) { - mOutputFormat = new MetaData; - mOutputFormat->setCString(kKeyDecoderComponent, mComponentName); - if (mIsEncoder) { - int32_t timeScale; - if (inputFormat->findInt32(kKeyTimeScale, &timeScale)) { - mOutputFormat->setInt32(kKeyTimeScale, timeScale); - } - } - - OMX_PARAM_PORTDEFINITIONTYPE def; - InitOMXParams(&def); - def.nPortIndex = kPortIndexOutput; - - status_t err = mOMX->getParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - CHECK_EQ(err, (status_t)OK); - - switch (def.eDomain) { - case OMX_PortDomainImage: - { - OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image; - CHECK_EQ((int)imageDef->eCompressionFormat, - (int)OMX_IMAGE_CodingUnused); - - mOutputFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW); - mOutputFormat->setInt32(kKeyColorFormat, imageDef->eColorFormat); - mOutputFormat->setInt32(kKeyWidth, imageDef->nFrameWidth); - mOutputFormat->setInt32(kKeyHeight, imageDef->nFrameHeight); - break; - } - - case OMX_PortDomainAudio: - { - OMX_AUDIO_PORTDEFINITIONTYPE *audio_def = &def.format.audio; - - if (audio_def->eEncoding == OMX_AUDIO_CodingPCM) { - OMX_AUDIO_PARAM_PCMMODETYPE params; - InitOMXParams(¶ms); - params.nPortIndex = kPortIndexOutput; - - err = mOMX->getParameter( - mNode, OMX_IndexParamAudioPcm, ¶ms, sizeof(params)); - CHECK_EQ(err, (status_t)OK); - - CHECK_EQ((int)params.eNumData, (int)OMX_NumericalDataSigned); - CHECK_EQ(params.nBitPerSample, 16u); - CHECK_EQ((int)params.ePCMMode, (int)OMX_AUDIO_PCMModeLinear); - - int32_t numChannels, sampleRate; - inputFormat->findInt32(kKeyChannelCount, &numChannels); - inputFormat->findInt32(kKeySampleRate, &sampleRate); - - if ((OMX_U32)numChannels != params.nChannels) { - ALOGV("Codec outputs a different number of channels than " - "the input stream contains (contains %d channels, " - "codec outputs %ld channels).", - numChannels, params.nChannels); - } - - if (sampleRate != (int32_t)params.nSamplingRate) { - ALOGV("Codec outputs at different sampling rate than " - "what the input stream contains (contains data at " - "%d Hz, codec outputs %lu Hz)", - sampleRate, params.nSamplingRate); - } - - mOutputFormat->setCString( - kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW); - - // Use the codec-advertised number of channels, as some - // codecs appear to output stereo even if the input data is - // mono. If we know the codec lies about this information, - // use the actual number of channels instead. - mOutputFormat->setInt32( - kKeyChannelCount, - (mQuirks & kDecoderLiesAboutNumberOfChannels) - ? numChannels : params.nChannels); - - mOutputFormat->setInt32(kKeySampleRate, params.nSamplingRate); - } else if (audio_def->eEncoding == OMX_AUDIO_CodingAMR) { - OMX_AUDIO_PARAM_AMRTYPE amr; - InitOMXParams(&amr); - amr.nPortIndex = kPortIndexOutput; - - err = mOMX->getParameter( - mNode, OMX_IndexParamAudioAmr, &amr, sizeof(amr)); - CHECK_EQ(err, (status_t)OK); - - CHECK_EQ(amr.nChannels, 1u); - mOutputFormat->setInt32(kKeyChannelCount, 1); - - if (amr.eAMRBandMode >= OMX_AUDIO_AMRBandModeNB0 - && amr.eAMRBandMode <= OMX_AUDIO_AMRBandModeNB7) { - mOutputFormat->setCString( - kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_NB); - mOutputFormat->setInt32(kKeySampleRate, 8000); - } else if (amr.eAMRBandMode >= OMX_AUDIO_AMRBandModeWB0 - && amr.eAMRBandMode <= OMX_AUDIO_AMRBandModeWB8) { - mOutputFormat->setCString( - kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_WB); - mOutputFormat->setInt32(kKeySampleRate, 16000); - } else { - CHECK(!"Unknown AMR band mode."); - } - } else if (audio_def->eEncoding == OMX_AUDIO_CodingAAC) { - mOutputFormat->setCString( - kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC); - int32_t numChannels, sampleRate, bitRate; - inputFormat->findInt32(kKeyChannelCount, &numChannels); - inputFormat->findInt32(kKeySampleRate, &sampleRate); - inputFormat->findInt32(kKeyBitRate, &bitRate); - mOutputFormat->setInt32(kKeyChannelCount, numChannels); - mOutputFormat->setInt32(kKeySampleRate, sampleRate); - mOutputFormat->setInt32(kKeyBitRate, bitRate); - } else { - CHECK(!"Should not be here. Unknown audio encoding."); - } - break; - } - - case OMX_PortDomainVideo: - { - OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video; - - if (video_def->eCompressionFormat == OMX_VIDEO_CodingUnused) { - mOutputFormat->setCString( - kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW); - } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingMPEG4) { - mOutputFormat->setCString( - kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4); - } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingH263) { - mOutputFormat->setCString( - kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263); - } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingAVC) { - mOutputFormat->setCString( - kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC); - } else { - CHECK(!"Unknown compression format."); - } - - mOutputFormat->setInt32(kKeyWidth, video_def->nFrameWidth); - mOutputFormat->setInt32(kKeyHeight, video_def->nFrameHeight); - mOutputFormat->setInt32(kKeyColorFormat, video_def->eColorFormat); - - if (!mIsEncoder) { - OMX_CONFIG_RECTTYPE rect; - InitOMXParams(&rect); - rect.nPortIndex = kPortIndexOutput; - status_t err = - mOMX->getConfig( - mNode, OMX_IndexConfigCommonOutputCrop, - &rect, sizeof(rect)); - - CODEC_LOGI( - "video dimensions are %ld x %ld", - video_def->nFrameWidth, video_def->nFrameHeight); - - if (err == OK) { - CHECK_GE(rect.nLeft, 0); - CHECK_GE(rect.nTop, 0); - CHECK_GE(rect.nWidth, 0u); - CHECK_GE(rect.nHeight, 0u); - CHECK_LE(rect.nLeft + rect.nWidth - 1, video_def->nFrameWidth); - CHECK_LE(rect.nTop + rect.nHeight - 1, video_def->nFrameHeight); - - mOutputFormat->setRect( - kKeyCropRect, - rect.nLeft, - rect.nTop, - rect.nLeft + rect.nWidth - 1, - rect.nTop + rect.nHeight - 1); - - CODEC_LOGI( - "Crop rect is %ld x %ld @ (%ld, %ld)", - rect.nWidth, rect.nHeight, rect.nLeft, rect.nTop); - } else { - mOutputFormat->setRect( - kKeyCropRect, - 0, 0, - video_def->nFrameWidth - 1, - video_def->nFrameHeight - 1); - } - - if (mNativeWindow != NULL) { - initNativeWindowCrop(); - } - } - break; - } - - default: - { - CHECK(!"should not be here, neither audio nor video."); - break; - } - } - - // If the input format contains rotation information, flag the output - // format accordingly. - - int32_t rotationDegrees; - if (mSource->getFormat()->findInt32(kKeyRotation, &rotationDegrees)) { - mOutputFormat->setInt32(kKeyRotation, rotationDegrees); - } -} - -status_t OMXCodec::pause() { - Mutex::Autolock autoLock(mLock); - - mPaused = true; - - return OK; -} - -//////////////////////////////////////////////////////////////////////////////// - -status_t QueryCodecs( - const sp<IOMX> &omx, - const char *mime, bool queryDecoders, bool hwCodecOnly, - Vector<CodecCapabilities> *results) { - Vector<String8> matchingCodecs; - results->clear(); - - OMXCodec::findMatchingCodecs(mime, - !queryDecoders /*createEncoder*/, - NULL /*matchComponentName*/, - hwCodecOnly ? OMXCodec::kHardwareCodecsOnly : 0 /*flags*/, - &matchingCodecs); - - for (size_t c = 0; c < matchingCodecs.size(); c++) { - const char *componentName = matchingCodecs.itemAt(c).string(); - - if (strncmp(componentName, "OMX.", 4)) { - // Not an OpenMax component but a software codec. - - results->push(); - CodecCapabilities *caps = &results->editItemAt(results->size() - 1); - caps->mComponentName = componentName; - continue; - } - - sp<OMXCodecObserver> observer = new OMXCodecObserver; - IOMX::node_id node; - status_t err = omx->allocateNode(componentName, observer, &node); - - if (err != OK) { - continue; - } - - OMXCodec::setComponentRole(omx, node, !queryDecoders, mime); - - results->push(); - CodecCapabilities *caps = &results->editItemAt(results->size() - 1); - caps->mComponentName = componentName; - - OMX_VIDEO_PARAM_PROFILELEVELTYPE param; - InitOMXParams(¶m); - - param.nPortIndex = queryDecoders ? 0 : 1; - - for (param.nProfileIndex = 0;; ++param.nProfileIndex) { - err = omx->getParameter( - node, OMX_IndexParamVideoProfileLevelQuerySupported, - ¶m, sizeof(param)); - - if (err != OK) { - break; - } - - CodecProfileLevel profileLevel; - profileLevel.mProfile = param.eProfile; - profileLevel.mLevel = param.eLevel; - - caps->mProfileLevels.push(profileLevel); - } - - // Color format query - OMX_VIDEO_PARAM_PORTFORMATTYPE portFormat; - InitOMXParams(&portFormat); - portFormat.nPortIndex = queryDecoders ? 1 : 0; - for (portFormat.nIndex = 0;; ++portFormat.nIndex) { - err = omx->getParameter( - node, OMX_IndexParamVideoPortFormat, - &portFormat, sizeof(portFormat)); - if (err != OK) { - break; - } - caps->mColorFormats.push(portFormat.eColorFormat); - } - - CHECK_EQ(omx->freeNode(node), (status_t)OK); - } - - return OK; -} - -status_t QueryCodecs( - const sp<IOMX> &omx, - const char *mimeType, bool queryDecoders, - Vector<CodecCapabilities> *results) { - return QueryCodecs(omx, mimeType, queryDecoders, false /*hwCodecOnly*/, results); -} - -void OMXCodec::restorePatchedDataPointer(BufferInfo *info) { - CHECK(mIsEncoder && (mQuirks & kAvoidMemcopyInputRecordingFrames)); - CHECK(mOMXLivesLocally); - - OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)info->mBuffer; - header->pBuffer = (OMX_U8 *)info->mData; -} - -} // namespace android |