diff --git a/NOTICE b/NOTICE index 152be205957..cdfcb862328 100644 --- a/NOTICE +++ b/NOTICE @@ -322,3 +322,32 @@ Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in these Data Files or Software without prior written authorization of the copyright holder. + + +Copyright (c) 2012 - 2014, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/include/media/stagefright/ExtendedCodec.h b/include/media/stagefright/ExtendedCodec.h new file mode 100644 index 00000000000..f0b1c91ad81 --- /dev/null +++ b/include/media/stagefright/ExtendedCodec.h @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2013 - 2014, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef EXTENDED_CODEC_H_ +#define EXTENDED_CODEC_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace android { + +struct MediaCodecList; +struct OMXCodec; + +enum{ + kRequiresWMAProComponent = 0x40000000, +}; + + +struct ExtendedCodec { + + enum { + kPortIndexInput = 0, + kPortIndexOutput = 1 + }; + static status_t convertMetaDataToMessage( + const sp &meta, sp *format); + + static uint32_t getComponentQuirks ( + const MediaCodecList *list, size_t index); + + static status_t setAudioFormat( + const sp &meta, const char* mime, + sp OMXhandle,IOMX::node_id nodeID, + bool isEncoder); + + static status_t setAudioFormat( + const sp &msg, const char* mime, + sp OMXhandle,IOMX::node_id nodeID, + bool isEncoder); + + static status_t setVideoInputFormat( + const char *mime, + OMX_VIDEO_CODINGTYPE *compressionFormat); + + static status_t setVideoOutputFormat( + const char *mime, + OMX_VIDEO_CODINGTYPE *compressionFormat); + + static status_t getSupportedAudioFormatInfo( + const AString* mime, + sp OMXhandle, + IOMX::node_id nodeID, + int portIndex, + int* channelCount); + + static status_t handleSupportedAudioFormats( + int format, AString* mime); + + static const char* overrideComponentName( + uint32_t quirks, const sp &meta); + + static void overrideComponentName( + uint32_t quirks, const sp &msg, + AString* componentName); + + static void getRawCodecSpecificData( + const sp &meta, + const void* &data, + size_t& size); + + static sp getRawCodecSpecificData( + const sp &msg); + + static void getAacCodecSpecificData( + const sp &meta, + const void* &data, + size_t& size); + + static sp getAacCodecSpecificData( + const sp &msg); + + static status_t setSupportedRole( + const sp &omx, IOMX::node_id node, + bool isEncoder, const char *mime); + + static void configureFramePackingFormat( + const sp &msg, sp OMXhandle, + IOMX::node_id nodeID, const char* componentName); + + static void configureFramePackingFormat( + const sp &meta, sp OMXhandle, + IOMX::node_id nodeID, const char* componentName); + + static void configureVideoDecoder( + const sp &meta, const char* mime, + sp OMXhandle, const uint32_t flags, + IOMX::node_id nodeID, const char* componentName); + + static void configureVideoDecoder( + const sp &msg, const char* mime, + sp OMXhandle, const uint32_t flags, + IOMX::node_id nodeID, const char* componentName); + + static void enableSmoothStreaming( + const sp &omx, IOMX::node_id nodeID, bool* isEnabled, + const char* componentName); + + static bool useHWAACDecoder(const char *mime); + +private: + static const char* getMsgKey(int key ); + + static status_t setWMAFormat( + const sp &meta, sp OMXhandle, + IOMX::node_id nodeID, bool isEncoder ); + + static status_t setWMAFormat( + const sp &msg, sp OMXhandle, + IOMX::node_id nodeID, bool isEncoder ); + + static void setEVRCFormat( + int32_t numChannels, int32_t sampleRate, + sp OMXhandle, IOMX::node_id nodeID, + bool isEncoder ); + + static void setQCELPFormat( + int32_t numChannels, int32_t sampleRate, + sp OMXhandle, IOMX::node_id nodeID, + bool isEncoder ); + + static void setAC3Format( + int32_t numChannels, int32_t sampleRate, + sp OMXhandle, IOMX::node_id nodeID); + + static status_t setDIVXFormat( + const sp &msg, const char* mime, + sp OMXhandle,IOMX::node_id nodeID, int port_index); + + static status_t setAMRWBPLUSFormat( + int32_t numChannels, int32_t sampleRate, + sp OMXhandle, IOMX::node_id nodeID); + +}; + +} +#endif /*EXTENDED_CODEC_H_ */ + diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h index e3411602d9f..14339182798 100644 --- a/include/media/stagefright/OMXCodec.h +++ b/include/media/stagefright/OMXCodec.h @@ -363,6 +363,8 @@ struct OMXCodec : public MediaSource, OMXCodec(const OMXCodec &); OMXCodec &operator=(const OMXCodec &); + + int32_t mNumBFrames; }; struct CodecCapabilities { diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index cadd69199da..f61ca24bc13 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -52,6 +52,8 @@ #include #include +#include "ExtendedUtils.h" + #include #include "ARTPWriter.h" @@ -116,6 +118,10 @@ status_t StagefrightRecorder::setAudioSource(audio_source_t as) { return BAD_VALUE; } + if (ExtendedUtils::ShellProp::isAudioDisabled(true)) { + return OK; + } + if (as == AUDIO_SOURCE_DEFAULT) { mAudioSource = AUDIO_SOURCE_MIC; } else { @@ -167,6 +173,10 @@ status_t StagefrightRecorder::setAudioEncoder(audio_encoder ae) { return BAD_VALUE; } + if (ExtendedUtils::ShellProp::isAudioDisabled(true)) { + return OK; + } + if (ae == AUDIO_ENCODER_DEFAULT) { mAudioEncoder = AUDIO_ENCODER_AMR_NB; } else { @@ -1514,6 +1524,9 @@ status_t StagefrightRecorder::setupVideoEncoder( if (mVideoTimeScale > 0) { format->setInt32("time-scale", mVideoTimeScale); } + + ExtendedUtils::ShellProp::setEncoderProfile(mVideoEncoder, mVideoEncoderProfile); + if (mVideoEncoderProfile != -1) { format->setInt32("profile", mVideoEncoderProfile); } diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp old mode 100644 new mode 100755 index 2f2f9cfaa38..c347d9f7204 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include @@ -1119,7 +1120,7 @@ status_t ACodec::setComponentRole( } if (i == kNumMimeToRole) { - return ERROR_UNSUPPORTED; + return ExtendedCodec::setSupportedRole(mOMX, mNode, isEncoder, mime); } const char *role = @@ -1369,6 +1370,10 @@ status_t ACodec::configureCodec( } else { err = setupVideoDecoder(mime, msg); } + if (err == OK) { + const char* componentName = mComponentName.c_str(); + ExtendedCodec::configureVideoDecoder(msg, mime, mOMX, 0, mNode, componentName); + } } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) { int32_t numChannels, sampleRate; if (!msg->findInt32("channel-count", &numChannels) @@ -1498,6 +1503,19 @@ status_t ACodec::configureCodec( } else { err = setupAC3Codec(encoder, numChannels, sampleRate); } + } else { + if (encoder) { + int32_t numChannels, sampleRate; + if (msg->findInt32("channel-count", &numChannels) + && msg->findInt32("sample-rate", &sampleRate)) { + setupRawAudioFormat(kPortIndexInput, sampleRate, numChannels); + } + } + err = ExtendedCodec::setAudioFormat( + msg, mime, mOMX, mNode, mIsEncoder); + if(err != OK) { + return err; + } } if (err != OK) { @@ -2102,7 +2120,9 @@ status_t ACodec::setupVideoDecoder( status_t err = GetVideoCodingTypeFromMime(mime, &compressionFormat); if (err != OK) { - return err; + if (ExtendedCodec::setVideoOutputFormat(mime, &compressionFormat) != OK) { + return err; + } } err = setVideoPortFormatType( @@ -2239,7 +2259,11 @@ status_t ACodec::setupVideoEncoder(const char *mime, const sp &msg) { err = GetVideoCodingTypeFromMime(mime, &compressionFormat); if (err != OK) { - return err; + err = ExtendedCodec::setVideoInputFormat(mime, &compressionFormat); + if (err != OK) { + ALOGE("Not a supported video mime type: %s", mime); + return err; + } } err = setVideoPortFormatType( @@ -3497,8 +3521,25 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp ¬ify) { } default: + { + AString mimeType; + status_t err = ExtendedCodec::handleSupportedAudioFormats( + audioDef->eEncoding, &mimeType); + if (err == OK) { + int channelCount; + err = ExtendedCodec::getSupportedAudioFormatInfo( + &mimeType, + mOMX, + mNode, + kPortIndexOutput, + &channelCount); + notify->setString("mime", mimeType.c_str()); + notify->setInt32("channel-count", channelCount); + break; + } ALOGE("UNKNOWN AUDIO CODING: %d\n", audioDef->eEncoding); TRESPASS(); + } } break; } @@ -4552,6 +4593,7 @@ bool ACodec::UninitializedState::onAllocateComponent(const sp &msg) { ++matchIndex) { componentName = matchingCodecs.itemAt(matchIndex).mName.string(); quirks = matchingCodecs.itemAt(matchIndex).mQuirks; + ExtendedCodec::overrideComponentName(quirks, msg, &componentName); pid_t tid = androidGetTid(); int prevPriority = androidGetThreadPriority(tid); diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index 193f8a76967..14ac53eed35 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -44,6 +44,7 @@ LOCAL_SRC_FILES:= \ NuMediaExtractor.cpp \ OMXClient.cpp \ OMXCodec.cpp \ + ExtendedCodec.cpp \ OggExtractor.cpp \ SampleIterator.cpp \ SampleTable.cpp \ @@ -60,6 +61,8 @@ LOCAL_SRC_FILES:= \ WVMExtractor.cpp \ XINGSeeker.cpp \ avc_utils.cpp \ + ExtendedExtractor.cpp \ + ExtendedUtils.cpp \ LOCAL_C_INCLUDES:= \ $(TOP)/frameworks/av/include/media/ \ @@ -112,6 +115,12 @@ LOCAL_STATIC_LIBRARIES := \ libFLAC \ libmedia_helper +ifeq ($(TARGET_ENABLE_QC_AV_ENHANCEMENTS),true) + LOCAL_CFLAGS += -DENABLE_AV_ENHANCEMENTS + LOCAL_C_INCLUDES += $(TOP)/hardware/qcom/media/mm-core/inc + LOCAL_SRC_FILES += ExtendedMediaDefs.cpp +endif #TARGET_ENABLE_AV_ENHANCEMENTS + LOCAL_SHARED_LIBRARIES += \ libstagefright_enc_common \ libstagefright_avc_common \ diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index ab8ac79b676..ffc62a5253e 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -55,6 +55,7 @@ #include #include #include +#include "include/ExtendedUtils.h" #include #include @@ -465,7 +466,8 @@ status_t AwesomePlayer::setDataSource_l(const sp &extractor) { &mStats.mTracks.editItemAt(mStats.mVideoTrackIndex); stat->mMIME = mime.string(); } - } else if (!haveAudio && !strncasecmp(mime.string(), "audio/", 6)) { + } else if (!haveAudio && !strncasecmp(mime.string(), "audio/", 6) && + !ExtendedUtils::ShellProp::isAudioDisabled(false)) { setAudioSource(extractor->getTrack(i)); haveAudio = true; mActiveAudioTrackIndex = i; diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp old mode 100644 new mode 100755 index c99db84c822..20a20318505 --- a/media/libstagefright/DataSource.cpp +++ b/media/libstagefright/DataSource.cpp @@ -30,6 +30,7 @@ #include "include/OggExtractor.h" #include "include/WAVExtractor.h" #include "include/WVMExtractor.h" +#include "include/ExtendedExtractor.h" #include "matroska/MatroskaExtractor.h" @@ -172,6 +173,7 @@ void DataSource::RegisterDefaultSniffers() { RegisterSniffer_l(SniffAAC); RegisterSniffer_l(SniffMPEG2PS); RegisterSniffer_l(SniffWVM); + RegisterSniffer_l(ExtendedExtractor::Sniff); char value[PROPERTY_VALUE_MAX]; if (property_get("drm.service.enabled", value, NULL) diff --git a/media/libstagefright/ExtendedCodec.cpp b/media/libstagefright/ExtendedCodec.cpp new file mode 100644 index 00000000000..41051477301 --- /dev/null +++ b/media/libstagefright/ExtendedCodec.cpp @@ -0,0 +1,1283 @@ +/* + * Copyright (c) 2013 - 2014, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "ExtendedCodec" +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#define ARG_TOUCH(x) (void)x + +#ifdef ENABLE_AV_ENHANCEMENTS + +#include +#include +#include +#include +#include +#include "include/ExtendedUtils.h" + +namespace android { +enum MetaKeyType{ + INT32, INT64, STRING, DATA, CSD +}; + +struct MetaKeyEntry{ + int MetaKey; + const char* MsgKey; + MetaKeyType KeyType; +}; + +static const MetaKeyEntry MetaKeyTable[] { + {kKeyBitRate , "bitrate" , INT32}, + {kKeyAacCodecSpecificData , "aac-codec-specific-data", CSD}, + {kKeyRawCodecSpecificData , "raw-codec-specific-data", CSD}, + {kKeyDivXVersion , "divx-version" , INT32}, // int32_t + {kKeyDivXDrm , "divx-drm" , DATA}, // void * + {kKeyWMAEncodeOpt , "wma-encode-opt" , INT32}, // int32_t + {kKeyWMABlockAlign , "wma-block-align" , INT32}, // int32_t + {kKeyWMAVersion , "wma-version" , INT32}, // int32_t + {kKeyWMAAdvEncOpt1 , "wma-adv-enc-opt1" , INT32}, // int16_t + {kKeyWMAAdvEncOpt2 , "wma-adv-enc-opt2" , INT32}, // int32_t + {kKeyWMAFormatTag , "wma-format-tag" , INT32}, // int32_t + {kKeyWMABitspersample , "wma-bits-per-sample" , INT32}, // int32_t + {kKeyWMAVirPktSize , "wma-vir-pkt-size" , INT32}, // int32_t + {kKeyWMAChannelMask , "wma-channel-mask" , INT32}, // int32_t + + {kKeyFileFormat , "file-format" , STRING}, // cstring + + {kkeyAacFormatAdif , "aac-format-adif" , INT32}, // bool (int32_t) + {kkeyAacFormatLtp , "aac-format-ltp" , INT32}, + + //DTS subtype + {kKeyDTSSubtype , "dts-subtype" , INT32}, //int32_t + + //Extractor sets this + {kKeyUseArbitraryMode , "use-arbitrary-mode" , INT32}, //bool (int32_t) + {kKeySmoothStreaming , "smooth-streaming" , INT32}, //bool (int32_t) + {kKeyHFR , "hfr" , INT32}, // int32_t + + {kKeySampleRate , "sample-rate" , INT32}, + {kKeyChannelCount , "channel-count" , INT32}, +}; + +const char* ExtendedCodec::getMsgKey(int key) { + static const size_t numMetaKeys = + sizeof(MetaKeyTable) / sizeof(MetaKeyTable[0]); + size_t i; + for (i = 0; i < numMetaKeys; ++i) { + if (key == MetaKeyTable[i].MetaKey) { + return MetaKeyTable[i].MsgKey; + } + } + return "unknown"; +} + +status_t ExtendedCodec::convertMetaDataToMessage( + const sp &meta, sp *format) { + const char * str_val; + int32_t int32_val; + int64_t int64_val; + uint32_t data_type; + const void * data; + size_t size; + static const size_t numMetaKeys = + sizeof(MetaKeyTable) / sizeof(MetaKeyTable[0]); + size_t i; + for (i = 0; i < numMetaKeys; ++i) { + if (MetaKeyTable[i].KeyType == INT32 && + meta->findInt32(MetaKeyTable[i].MetaKey, &int32_val)) { + ALOGV("found metakey %s of type int32", MetaKeyTable[i].MsgKey); + format->get()->setInt32(MetaKeyTable[i].MsgKey, int32_val); + } else if (MetaKeyTable[i].KeyType == INT64 && + meta->findInt64(MetaKeyTable[i].MetaKey, &int64_val)) { + ALOGV("found metakey %s of type int64", MetaKeyTable[i].MsgKey); + format->get()->setInt64(MetaKeyTable[i].MsgKey, int64_val); + } else if (MetaKeyTable[i].KeyType == STRING && + meta->findCString(MetaKeyTable[i].MetaKey, &str_val)) { + ALOGV("found metakey %s of type string", MetaKeyTable[i].MsgKey); + format->get()->setString(MetaKeyTable[i].MsgKey, str_val); + } else if ( (MetaKeyTable[i].KeyType == DATA || + MetaKeyTable[i].KeyType == CSD) && + meta->findData(MetaKeyTable[i].MetaKey, &data_type, &data, &size)) { + ALOGV("found metakey %s of type data", MetaKeyTable[i].MsgKey); + if (MetaKeyTable[i].KeyType == CSD) { + const char *mime; + CHECK(meta->findCString(kKeyMIMEType, &mime)); + if (strcasecmp( mime, MEDIA_MIMETYPE_VIDEO_AVC)) { + sp buffer = new ABuffer(size); + memcpy(buffer->data(), data, size); + buffer->meta()->setInt32("csd", true); + buffer->meta()->setInt64("timeUs", 0); + format->get()->setBuffer("csd-0", buffer); + } else { + const uint8_t *ptr = (const uint8_t *)data; + CHECK(size >= 8); + int seqLength = 0, picLength = 0; + for(size_t i=4; i buffer = new ABuffer(seqLength); + memcpy(buffer->data(), data, seqLength); + buffer->meta()->setInt32("csd", true); + buffer->meta()->setInt64("timeUs", 0); + format->get()->setBuffer("csd-0", buffer); + picLength=size-seqLength; + sp buffer1 = new ABuffer(picLength); + memcpy(buffer1->data(), (char *)data+seqLength, picLength); + buffer1->meta()->setInt32("csd", true); + buffer1->meta()->setInt64("timeUs", 0); + format->get()->setBuffer("csd-1", buffer1); + } + } else { + sp buffer = new ABuffer(size); + memcpy(buffer->data(), data, size); + format->get()->setBuffer(MetaKeyTable[i].MsgKey, buffer); + } + } + } + return OK; +} + +uint32_t ExtendedCodec::getComponentQuirks( + const MediaCodecList *list, size_t index) { + uint32_t quirks = 0; + + if (list->codecHasQuirk( + index, "requires-wma-pro-component")) { + quirks |= kRequiresWMAProComponent; + } + return quirks; +} + +const char* ExtendedCodec::overrideComponentName( + uint32_t quirks, const sp &meta) { + const char* componentName = NULL; + if (quirks & kRequiresWMAProComponent) + { + int32_t version = 0; + if ((meta->findInt32(kKeyWMAVersion, &version))) { + if (version==kTypeWMA) { + componentName = "OMX.qcom.audio.decoder.wma"; + } else if (version==kTypeWMAPro) { + componentName = "OMX.qcom.audio.decoder.wma10Pro"; + } else if (version==kTypeWMALossLess) { + componentName = "OMX.qcom.audio.decoder.wmaLossLess"; + } + } + } + return componentName; +} + +void ExtendedCodec::overrideComponentName( + uint32_t quirks, const sp &msg, AString* componentName) { + if (quirks & kRequiresWMAProComponent) + { + int32_t version = 0; + if ((msg->findInt32(getMsgKey(kKeyWMAVersion), &version))) { + if (version==kTypeWMA) { + componentName->setTo("OMX.qcom.audio.decoder.wma"); + } else if (version==kTypeWMAPro) { + componentName->setTo("OMX.qcom.audio.decoder.wma10Pro"); + } else if (version==kTypeWMALossLess) { + componentName->setTo("OMX.qcom.audio.decoder.wmaLossLess"); + } + } + } +} + +template +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; +} + +status_t ExtendedCodec::setDIVXFormat( + const sp &msg, const char* mime, sp OMXhandle, + IOMX::node_id nodeID, int port_index) { + status_t err = OK; + + if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX, mime) || + !strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX4, mime) || + !strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX311, mime)) { + ALOGV("Setting the QOMX_VIDEO_PARAM_DIVXTYPE params "); + QOMX_VIDEO_PARAM_DIVXTYPE paramDivX; + InitOMXParams(¶mDivX); + paramDivX.nPortIndex = port_index; + int32_t DivxVersion = 0; + CHECK(msg->findInt32(getMsgKey(kKeyDivXVersion),&DivxVersion)); + ALOGV("Divx Version Type %d\n",DivxVersion); + + if (DivxVersion == kTypeDivXVer_4) { + paramDivX.eFormat = QOMX_VIDEO_DIVXFormat4; + } else if (DivxVersion == kTypeDivXVer_5) { + paramDivX.eFormat = QOMX_VIDEO_DIVXFormat5; + } else if (DivxVersion == kTypeDivXVer_6) { + paramDivX.eFormat = QOMX_VIDEO_DIVXFormat6; + } else if (DivxVersion == kTypeDivXVer_3_11 ) { + paramDivX.eFormat = QOMX_VIDEO_DIVXFormat311; + } else { + paramDivX.eFormat = QOMX_VIDEO_DIVXFormatUnused; + } + paramDivX.eProfile = (QOMX_VIDEO_DIVXPROFILETYPE)0; //Not used for now. + + err = OMXhandle->setParameter(nodeID, + (OMX_INDEXTYPE)OMX_QcomIndexParamVideoDivx, + ¶mDivX, sizeof(paramDivX)); + } + + return err; +} + +void ExtendedCodec::getRawCodecSpecificData( + const sp &meta, const void* &data, size_t &size) { + uint32_t type = 0; + size = 0; + if (meta->findData(kKeyRawCodecSpecificData, &type, &data, &size)) { + ALOGV("OMXCodec::configureCodec found kKeyRawCodecSpecificData of size %d\n", size); + } +} + +sp ExtendedCodec::getRawCodecSpecificData( + const sp &msg) { + sp buffer; + if (msg->findBuffer(getMsgKey(kKeyRawCodecSpecificData), &buffer)) { + ALOGV("ACodec found kKeyRawCodecSpecificData of size %d\n", buffer->size()); + return buffer; + } + return NULL; +} + +void ExtendedCodec::getAacCodecSpecificData( + const sp &meta, const void* &data, size_t &size) { + uint32_t type = 0; + size = 0; + if (meta->findData(kKeyAacCodecSpecificData, &type, &data, &size)) { + ALOGV("OMXCodec::configureCodec found kKeyAacCodecSpecificData of size %d\n", size); + } +} + +sp ExtendedCodec::getAacCodecSpecificData( + const sp &msg) { + sp buffer; + if (msg->findBuffer(getMsgKey(kKeyAacCodecSpecificData), &buffer)) { + ALOGV("ACodec found kKeyAacCodecSpecificData of size %d\n", buffer->size()); + return buffer; + } + return NULL; +} + +status_t ExtendedCodec::setAudioFormat( + const sp &meta, const char* mime, sp OMXhandle, + IOMX::node_id nodeID, bool isEncoder ) { + sp msg = new AMessage(); + msg->clear(); + convertMetaDataToMessage(meta, &msg); + return setAudioFormat(msg, mime, OMXhandle, nodeID, isEncoder); +} + +status_t ExtendedCodec::setAudioFormat( + const sp &msg, const char* mime, sp OMXhandle, + IOMX::node_id nodeID, bool isEncoder ) { + ALOGV("setAudioFormat called"); + status_t err = OK; + + if ((!strcasecmp(MEDIA_MIMETYPE_AUDIO_AC3, mime)) || + (!strcasecmp(MEDIA_MIMETYPE_AUDIO_EAC3, mime))) { + int32_t numChannels, sampleRate; + CHECK(msg->findInt32("channel-count", &numChannels)); + CHECK(msg->findInt32("sample-rate", &sampleRate)); + /* Commenting following call as AC3 soft decoder does not + need it and it causes issue with playback*/ + //setAC3Format(numChannels, sampleRate, OMXhandle, nodeID); + } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_EVRC, mime)) { + int32_t numChannels, sampleRate; + CHECK(msg->findInt32("channel-count", &numChannels)); + CHECK(msg->findInt32("sample-rate", &sampleRate)); + setEVRCFormat(numChannels, sampleRate, OMXhandle, nodeID, isEncoder ); + } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_QCELP, mime)) { + int32_t numChannels, sampleRate; + CHECK(msg->findInt32("channel-count", &numChannels)); + CHECK(msg->findInt32("sample-rate", &sampleRate)); + setQCELPFormat(numChannels, sampleRate, OMXhandle, nodeID, isEncoder); + } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_WMA, mime)) { + err = setWMAFormat(msg, OMXhandle, nodeID, isEncoder); + } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS, mime)) { + int32_t numChannels, sampleRate; + CHECK(msg->findInt32("channel-count", &numChannels)); + CHECK(msg->findInt32("sample-rate", &sampleRate)); + err = setAMRWBPLUSFormat(numChannels, sampleRate, OMXhandle, nodeID); + } + return err; +} + +status_t ExtendedCodec::setVideoInputFormat( + const char *mime, OMX_VIDEO_CODINGTYPE *compressionFormat) { + status_t retVal = OK; + if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX, mime)) { + *compressionFormat= (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingDivx; + } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX4, mime)) { + *compressionFormat= (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingDivx; + } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX311, mime)) { + *compressionFormat= (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingDivx; + } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_WMV, mime)) { + *compressionFormat = OMX_VIDEO_CodingWMV; + } else if (!strcasecmp(MEDIA_MIMETYPE_CONTAINER_MPEG2, mime)) { + *compressionFormat = OMX_VIDEO_CodingMPEG2; + } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) { + *compressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingHevc; + } else { + retVal = BAD_VALUE; + } + + return retVal; +} + +status_t ExtendedCodec::setVideoOutputFormat( + const char *mime, OMX_VIDEO_CODINGTYPE *compressionFormat) { + status_t retVal = OK; + if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX, mime)) { + *compressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingDivx; + } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX311, mime)) { + *compressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingDivx; + } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX4, mime)) { + *compressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingDivx; + } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_WMV, mime)) { + *compressionFormat = OMX_VIDEO_CodingWMV; + } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) { + *compressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingHevc; + } else { + retVal = BAD_VALUE; + } + return retVal; +} + +status_t ExtendedCodec::setSupportedRole( + const sp &omx, IOMX::node_id node, + bool isEncoder, const char *mime) { + ALOGV("setSupportedRole Called %s", mime); + struct MimeToRole { + const char *mime; + const char *decoderRole; + const char *encoderRole; + }; + + static const MimeToRole kQCMimeToRole[] = { + { MEDIA_MIMETYPE_AUDIO_EVRC, + "audio_decoder.evrchw", "audio_encoder.evrc" }, + { MEDIA_MIMETYPE_AUDIO_QCELP, + "audio_decoder,qcelp13Hw", "audio_encoder.qcelp13" }, + { MEDIA_MIMETYPE_VIDEO_DIVX, + "video_decoder.divx", NULL }, + { MEDIA_MIMETYPE_VIDEO_DIVX4, + "video_decoder.divx", NULL }, + { MEDIA_MIMETYPE_VIDEO_DIVX311, + "video_decoder.divx", NULL }, + { MEDIA_MIMETYPE_VIDEO_WMV, + "video_decoder.vc1", NULL }, + { MEDIA_MIMETYPE_AUDIO_AC3, + "audio_decoder.ac3", NULL }, + { MEDIA_MIMETYPE_AUDIO_WMA, + "audio_decoder.wma" , NULL }, + { MEDIA_MIMETYPE_VIDEO_HEVC, + "video_decoder.hevc" , NULL }, + + }; + + static const size_t kNumMimeToRole = + sizeof(kQCMimeToRole) / sizeof(kQCMimeToRole[0]); + + size_t i; + for (i = 0; i < kNumMimeToRole; ++i) { + if (!strcasecmp(mime, kQCMimeToRole[i].mime)) { + break; + } + } + + if (i == kNumMimeToRole) { + return ERROR_UNSUPPORTED; + } + + const char *role = + isEncoder ? kQCMimeToRole[i].encoderRole + : kQCMimeToRole[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); + return err; + } + } + return OK; +} + +status_t ExtendedCodec::getSupportedAudioFormatInfo( + const AString* mime, + sp OMXhandle, + IOMX::node_id nodeID, + int portIndex, + int* channelCount) { + status_t retVal = OK; + if (!strncmp(mime->c_str(), MEDIA_MIMETYPE_AUDIO_QCELP, strlen(MEDIA_MIMETYPE_AUDIO_QCELP))) { + OMX_AUDIO_PARAM_QCELP13TYPE params; + InitOMXParams(¶ms); + params.nPortIndex = portIndex; + CHECK_EQ(OMXhandle->getParameter( + nodeID, OMX_IndexParamAudioQcelp13, ¶ms, sizeof(params)), (status_t)OK); + *channelCount = params.nChannels; + } else if (!strncmp(mime->c_str(), MEDIA_MIMETYPE_AUDIO_EVRC, strlen(MEDIA_MIMETYPE_AUDIO_EVRC))) { + OMX_AUDIO_PARAM_EVRCTYPE params; + InitOMXParams(¶ms); + params.nPortIndex = portIndex; + CHECK_EQ(OMXhandle->getParameter( + nodeID, OMX_IndexParamAudioEvrc, ¶ms, sizeof(params)), (status_t)OK); + *channelCount = params.nChannels; + } else { + retVal = BAD_VALUE; + } + return retVal; +} + +status_t ExtendedCodec::handleSupportedAudioFormats(int format, AString* mime) { + ALOGV("checkQCFormats called"); + status_t retVal = OK; + if (format == OMX_AUDIO_CodingQCELP13 ) { + *mime = MEDIA_MIMETYPE_AUDIO_QCELP; + } else if (format == OMX_AUDIO_CodingEVRC ) { + *mime = MEDIA_MIMETYPE_AUDIO_EVRC; + } else { + retVal = BAD_VALUE; + } + return retVal; +} + +void ExtendedCodec::configureFramePackingFormat( + const sp &msg, sp OMXhandle, IOMX::node_id nodeID, + const char* componentName) { + //ignore non QC components + if (strncmp(componentName, "OMX.qcom.", 9)) { + return; + } + + int32_t mode = 0; + OMX_QCOM_PARAM_PORTDEFINITIONTYPE portFmt; + portFmt.nPortIndex = kPortIndexInput; + + if (msg->findInt32(getMsgKey(kKeyUseArbitraryMode), &mode) && mode) { + ALOGI("Decoder will be in arbitrary mode"); + portFmt.nFramePackingFormat = OMX_QCOM_FramePacking_Arbitrary; + } else { + ALOGI("Decoder will be in frame by frame mode"); + portFmt.nFramePackingFormat = OMX_QCOM_FramePacking_OnlyOneCompleteFrame; + } + status_t err = OMXhandle->setParameter( + nodeID, (OMX_INDEXTYPE)OMX_QcomIndexPortDefn, + (void *)&portFmt, sizeof(portFmt)); + if (err != OK) { + ALOGW("Failed to set frame packing format on component"); + } +} + +void ExtendedCodec::configureFramePackingFormat( + const sp &meta, sp OMXhandle, IOMX::node_id nodeID, + const char* componentName) { + sp msg = new AMessage(); + msg->clear(); + convertMetaDataToMessage(meta, &msg); + configureFramePackingFormat(msg, OMXhandle, nodeID, componentName); +} + +void ExtendedCodec::configureVideoDecoder( + const sp &msg, const char* mime, sp OMXhandle, + const uint32_t flags, IOMX::node_id nodeID, const char* componentName ) { + if (strncmp(componentName, "OMX.qcom.", 9)) { + //do nothing for non QC component + return; + } + + configureFramePackingFormat(msg, OMXhandle, nodeID, componentName); + + setDIVXFormat(msg, mime, OMXhandle, nodeID, kPortIndexOutput); + AString fileFormat; + const char *fileFormatCStr = NULL; + bool success = msg->findString(getMsgKey(kKeyFileFormat), &fileFormat); + if (success) { + fileFormatCStr = fileFormat.c_str(); + } + + // Enable timestamp reordering for AVI file type, mpeg4 and vc1 codec types + const char* roleVC1 = "OMX.qcom.video.decoder.vc1"; + const char* roleMPEG4 = "OMX.qcom.video.decoder.mpeg4"; + if (!strncmp(componentName, roleVC1, strlen(roleVC1)) || + !strncmp(componentName, roleMPEG4, strlen(roleMPEG4)) || + (fileFormatCStr!= NULL && !strncmp(fileFormatCStr, "video/avi", 9))) { + ALOGI("Enabling timestamp reordering"); + QOMX_INDEXTIMESTAMPREORDER reorder; + InitOMXParams(&reorder); + reorder.nPortIndex = kPortIndexOutput; + reorder.bEnable = OMX_TRUE; + status_t err = OMXhandle->setParameter(nodeID, + (OMX_INDEXTYPE)OMX_QcomIndexParamEnableTimeStampReorder, + (void *)&reorder, sizeof(reorder)); + + if (err != OK) { + ALOGW("Failed to enable timestamp reordering"); + } + } + + // Enable Sync-frame decode mode for thumbnails + if (flags & OMXCodec::kClientNeedsFramebuffer) { + ALOGV("Enabling thumbnail mode."); + QOMX_ENABLETYPE enableType; + OMX_INDEXTYPE indexType; + + status_t err = OMXhandle->getExtensionIndex( + nodeID, OMX_QCOM_INDEX_PARAM_VIDEO_SYNCFRAMEDECODINGMODE, + &indexType); + if (err != OK) { + ALOGW("Failed to get extension for SYNCFRAMEDECODINGMODE"); + return; + } + + enableType.bEnable = OMX_TRUE; + err = OMXhandle->setParameter(nodeID,indexType, + (void *)&enableType, sizeof(enableType)); + if (err != OK) { + ALOGW("Failed to get extension for SYNCFRAMEDECODINGMODE"); + return; + } + ALOGI("Thumbnail mode enabled."); + } + +} + +void ExtendedCodec::configureVideoDecoder( + const sp &meta, const char* mime, sp OMXhandle, + const uint32_t flags, IOMX::node_id nodeID, const char* componentName ) { + sp msg = new AMessage(); + msg->clear(); + convertMetaDataToMessage(meta, &msg); + configureVideoDecoder(msg, mime, OMXhandle, flags, nodeID, componentName); +} + +void ExtendedCodec::enableSmoothStreaming( + const sp &omx, IOMX::node_id nodeID, bool* isEnabled, + const char* componentName) { + *isEnabled = false; + + if (!ExtendedUtils::ShellProp::isSmoothStreamingEnabled()) { + return; + } + + //ignore non QC components + if (strncmp(componentName, "OMX.qcom.", 9)) { + return; + } + if (strstr(componentName, ".secure")) { + char prop[PROPERTY_VALUE_MAX] = {0}; + property_get("mm.disable.sec_smoothstreaming", prop, "0"); + if (!strncmp(prop, "true", 4) || atoi(prop)) { + ALOGI("Smoothstreaming not enabled for secure Sessions"); + return; + } + } + status_t err = omx->setParameter( + nodeID, + (OMX_INDEXTYPE)OMX_QcomIndexParamEnableSmoothStreaming, + &err, sizeof(status_t)); + if (err != OK) { + ALOGE("Failed to enable Smoothstreaming!"); + return; + } + *isEnabled = true; + ALOGI("Smoothstreaming Enabled"); + return; +} + +//private methods +void ExtendedCodec::setEVRCFormat( + int32_t numChannels, int32_t sampleRate, sp OMXhandle, + IOMX::node_id nodeID, bool isEncoder ) { + ALOGV("setEVRCFormat called"); + + ARG_TOUCH(sampleRate); + if (isEncoder) { + CHECK(numChannels == 1); + //////////////// input port //////////////////// + //handle->setRawAudioFormat(kPortIndexInput, sampleRate, numChannels); + //////////////// output port //////////////////// + // format + OMX_AUDIO_PARAM_PORTFORMATTYPE format; + format.nPortIndex = kPortIndexOutput; + format.nIndex = 0; + status_t err = OMX_ErrorNone; + while (OMX_ErrorNone == err) { + CHECK_EQ(OMXhandle->getParameter(nodeID, OMX_IndexParamAudioPortFormat, + &format, sizeof(format)), (status_t)OK); + if (format.eEncoding == OMX_AUDIO_CodingEVRC) { + break; + } + format.nIndex++; + } + CHECK_EQ((status_t)OK, err); + CHECK_EQ(OMXhandle->setParameter(nodeID, OMX_IndexParamAudioPortFormat, + &format, sizeof(format)), (status_t)OK); + + // port definition + OMX_PARAM_PORTDEFINITIONTYPE def; + InitOMXParams(&def); + def.nPortIndex = kPortIndexOutput; + def.format.audio.cMIMEType = NULL; + CHECK_EQ(OMXhandle->getParameter(nodeID, OMX_IndexParamPortDefinition, + &def, sizeof(def)), (status_t)OK); + def.format.audio.bFlagErrorConcealment = OMX_TRUE; + def.format.audio.eEncoding = OMX_AUDIO_CodingEVRC; + CHECK_EQ(OMXhandle->setParameter(nodeID, OMX_IndexParamPortDefinition, + &def, sizeof(def)), (status_t)OK); + + // profile + OMX_AUDIO_PARAM_EVRCTYPE profile; + InitOMXParams(&profile); + profile.nPortIndex = kPortIndexOutput; + CHECK_EQ(OMXhandle->getParameter(nodeID, OMX_IndexParamAudioEvrc, + &profile, sizeof(profile)), (status_t)OK); + profile.nChannels = numChannels; + CHECK_EQ(OMXhandle->setParameter(nodeID, OMX_IndexParamAudioEvrc, + &profile, sizeof(profile)), (status_t)OK); + } else { + ALOGI("EVRC decoder \n"); + } +} + +void ExtendedCodec::setQCELPFormat( + int32_t numChannels, int32_t sampleRate, sp OMXhandle, + IOMX::node_id nodeID, bool isEncoder ) { + + ARG_TOUCH(sampleRate); + if (isEncoder) { + CHECK(numChannels == 1); + //////////////// input port //////////////////// + //handle->setRawAudioFormat(kPortIndexInput, sampleRate, numChannels); + //////////////// output port //////////////////// + // format + OMX_AUDIO_PARAM_PORTFORMATTYPE format; + format.nPortIndex = kPortIndexOutput; + format.nIndex = 0; + status_t err = OMX_ErrorNone; + while (OMX_ErrorNone == err) { + CHECK_EQ(OMXhandle->getParameter(nodeID, OMX_IndexParamAudioPortFormat, + &format, sizeof(format)), (status_t)OK); + if (format.eEncoding == OMX_AUDIO_CodingQCELP13) { + break; + } + format.nIndex++; + } + CHECK_EQ((status_t)OK, err); + CHECK_EQ(OMXhandle->setParameter(nodeID, OMX_IndexParamAudioPortFormat, + &format, sizeof(format)), (status_t)OK); + + // port definition + OMX_PARAM_PORTDEFINITIONTYPE def; + InitOMXParams(&def); + def.nPortIndex = kPortIndexOutput; + def.format.audio.cMIMEType = NULL; + CHECK_EQ(OMXhandle->getParameter(nodeID, OMX_IndexParamPortDefinition, + &def, sizeof(def)), (status_t)OK); + def.format.audio.bFlagErrorConcealment = OMX_TRUE; + def.format.audio.eEncoding = OMX_AUDIO_CodingQCELP13; + CHECK_EQ(OMXhandle->setParameter(nodeID, OMX_IndexParamPortDefinition, + &def, sizeof(def)), (status_t)OK); + + // profile + OMX_AUDIO_PARAM_QCELP13TYPE profile; + InitOMXParams(&profile); + profile.nPortIndex = kPortIndexOutput; + CHECK_EQ(OMXhandle->getParameter(nodeID, OMX_IndexParamAudioQcelp13, + &profile, sizeof(profile)), (status_t)OK); + profile.nChannels = numChannels; + CHECK_EQ(OMXhandle->setParameter(nodeID, OMX_IndexParamAudioQcelp13, + &profile, sizeof(profile)), (status_t)OK); + } + else { + ALOGI("QCELP decoder \n"); + } +} + +status_t ExtendedCodec::setWMAFormat( + const sp &meta, sp OMXhandle, + IOMX::node_id nodeID, bool isEncoder ) { + sp msg = new AMessage(); + msg->clear(); + convertMetaDataToMessage(meta, &msg); + return setWMAFormat(msg, OMXhandle, nodeID, isEncoder); +} + +status_t ExtendedCodec::setWMAFormat( + const sp &msg, sp OMXhandle, + IOMX::node_id nodeID, bool isEncoder ) { + ALOGV("setWMAFormat Called"); + + if (isEncoder) { + ALOGE("WMA encoding not supported"); + return OK; + } else { + int32_t version; + OMX_AUDIO_PARAM_WMATYPE paramWMA; + QOMX_AUDIO_PARAM_WMA10PROTYPE paramWMA10; + CHECK(msg->findInt32(getMsgKey(kKeyWMAVersion), &version)); + int32_t numChannels; + int32_t bitRate; + int32_t sampleRate; + int32_t encodeOptions; + int32_t blockAlign; + int32_t bitspersample; + int32_t formattag; + int32_t advencopt1; + int32_t advencopt2; + int32_t VirtualPktSize; + if (version==kTypeWMAPro || version==kTypeWMALossLess) { + CHECK(msg->findInt32(getMsgKey(kKeyWMABitspersample), &bitspersample)); + CHECK(msg->findInt32(getMsgKey(kKeyWMAFormatTag), &formattag)); + CHECK(msg->findInt32(getMsgKey(kKeyWMAAdvEncOpt1), &advencopt1)); + CHECK(msg->findInt32(getMsgKey(kKeyWMAAdvEncOpt2), &advencopt2)); + CHECK(msg->findInt32(getMsgKey(kKeyWMAVirPktSize), &VirtualPktSize)); + } + if (version==kTypeWMA) { + InitOMXParams(¶mWMA); + paramWMA.nPortIndex = kPortIndexInput; + } else if (version==kTypeWMAPro || version==kTypeWMALossLess) { + InitOMXParams(¶mWMA10); + paramWMA10.nPortIndex = kPortIndexInput; + } + CHECK(msg->findInt32("channel-count", &numChannels)); + CHECK(msg->findInt32("sample-rate", &sampleRate)); + CHECK(msg->findInt32(getMsgKey(kKeyBitRate), &bitRate)); + CHECK(msg->findInt32(getMsgKey(kKeyWMAEncodeOpt), &encodeOptions)); + CHECK(msg->findInt32(getMsgKey(kKeyWMABlockAlign), &blockAlign)); + ALOGV("Channels: %d, SampleRate: %d, BitRate; %d" + "EncodeOptions: %d, blockAlign: %d", numChannels, + sampleRate, bitRate, encodeOptions, blockAlign); + if (sampleRate>48000 || numChannels>2) + { + ALOGE("Unsupported samplerate/channels"); + return ERROR_UNSUPPORTED; + } + if (version==kTypeWMAPro || version==kTypeWMALossLess) + { + ALOGV("Bitspersample: %d, wmaformattag: %d," + "advencopt1: %d, advencopt2: %d VirtualPktSize %d", bitspersample, + formattag, advencopt1, advencopt2, VirtualPktSize); + } + status_t err = OK; + OMX_INDEXTYPE index; + if (version==kTypeWMA) { + err = OMXhandle->getParameter( + nodeID, OMX_IndexParamAudioWma, ¶mWMA, sizeof(paramWMA)); + } else if (version==kTypeWMAPro || version==kTypeWMALossLess) { + OMXhandle->getExtensionIndex(nodeID,"OMX.Qualcomm.index.audio.wma10Pro",&index); + err = OMXhandle->getParameter( + nodeID, index, ¶mWMA10, sizeof(paramWMA10)); + } + CHECK_EQ(err, (status_t)OK); + if (version==kTypeWMA) { + paramWMA.nChannels = numChannels; + paramWMA.nSamplingRate = sampleRate; + paramWMA.nEncodeOptions = encodeOptions; + paramWMA.nBitRate = bitRate; + paramWMA.nBlockAlign = blockAlign; + } else if (version==kTypeWMAPro || version==kTypeWMALossLess) { + paramWMA10.nChannels = numChannels; + paramWMA10.nSamplingRate = sampleRate; + paramWMA10.nEncodeOptions = encodeOptions; + paramWMA10.nBitRate = bitRate; + paramWMA10.nBlockAlign = blockAlign; + } + if (version==kTypeWMAPro || version==kTypeWMALossLess) { + paramWMA10.advancedEncodeOpt = advencopt1; + paramWMA10.advancedEncodeOpt2 = advencopt2; + paramWMA10.formatTag = formattag; + paramWMA10.validBitsPerSample = bitspersample; + paramWMA10.nVirtualPktSize = VirtualPktSize; + } + if (version==kTypeWMA) { + err = OMXhandle->setParameter( + nodeID, OMX_IndexParamAudioWma, ¶mWMA, sizeof(paramWMA)); + } else if (version==kTypeWMAPro || version==kTypeWMALossLess) { + err = OMXhandle->setParameter( + nodeID, index, ¶mWMA10, sizeof(paramWMA10)); + } + return err; + } + return OK; +} + +void ExtendedCodec::setAC3Format( + int32_t numChannels, int32_t sampleRate, sp OMXhandle, + IOMX::node_id nodeID) { + QOMX_AUDIO_PARAM_AC3TYPE profileAC3; + QOMX_AUDIO_PARAM_AC3PP profileAC3PP; + OMX_INDEXTYPE indexTypeAC3; + OMX_INDEXTYPE indexTypeAC3PP; + OMX_PARAM_PORTDEFINITIONTYPE portParam; + + //configure input port + ALOGV("setAC3Format samplerate %d, numChannels %d", sampleRate, numChannels); + InitOMXParams(&portParam); + portParam.nPortIndex = 0; + status_t err = OMXhandle->getParameter( + nodeID, OMX_IndexParamPortDefinition, &portParam, sizeof(portParam)); + CHECK_EQ(err, (status_t)OK); + err = OMXhandle->setParameter( + nodeID, OMX_IndexParamPortDefinition, &portParam, sizeof(portParam)); + CHECK_EQ(err, (status_t)OK); + + //configure output port + portParam.nPortIndex = 1; + err = OMXhandle->getParameter( + nodeID, OMX_IndexParamPortDefinition, &portParam, sizeof(portParam)); + CHECK_EQ(err, (status_t)OK); + err = OMXhandle->setParameter( + nodeID, OMX_IndexParamPortDefinition, &portParam, sizeof(portParam)); + CHECK_EQ(err, (status_t)OK); + + err = OMXhandle->getExtensionIndex(nodeID, OMX_QCOM_INDEX_PARAM_AC3TYPE, &indexTypeAC3); + + InitOMXParams(&profileAC3); + profileAC3.nPortIndex = kPortIndexInput; + err = OMXhandle->getParameter(nodeID, indexTypeAC3, &profileAC3, sizeof(profileAC3)); + CHECK_EQ(err,(status_t)OK); + + profileAC3.nSamplingRate = sampleRate; + profileAC3.nChannels = 2; + profileAC3.eChannelConfig = OMX_AUDIO_AC3_CHANNEL_CONFIG_2_0; + + ALOGV("numChannels = %d, profileAC3.nChannels = %d", numChannels, profileAC3.nChannels); + + err = OMXhandle->setParameter(nodeID, indexTypeAC3, &profileAC3, sizeof(profileAC3)); + CHECK_EQ(err,(status_t)OK); + + //for output port + OMX_AUDIO_PARAM_PCMMODETYPE profilePcm; + InitOMXParams(&profilePcm); + profilePcm.nPortIndex = kPortIndexOutput; + err = OMXhandle->getParameter( + nodeID, OMX_IndexParamAudioPcm, &profilePcm, sizeof(profilePcm)); + CHECK_EQ(err, (status_t)OK); + + profilePcm.nSamplingRate = sampleRate; + err = OMXhandle->setParameter( + nodeID, OMX_IndexParamAudioPcm, &profilePcm, sizeof(profilePcm)); + CHECK_EQ(err, (status_t)OK); + OMXhandle->getExtensionIndex(nodeID, OMX_QCOM_INDEX_PARAM_AC3PP, &indexTypeAC3PP); + + InitOMXParams(&profileAC3PP); + profileAC3PP.nPortIndex = kPortIndexInput; + err = OMXhandle->getParameter( + nodeID, indexTypeAC3PP, &profileAC3PP, sizeof(profileAC3PP)); + CHECK_EQ(err, (status_t)OK); + + int i; + int channel_routing[6] = {0}; + + for (i=0; i<6; i++) { + channel_routing[i] = -1; + } + for (i=0; i<6; i++) { + profileAC3PP.eChannelRouting[i] = (OMX_AUDIO_AC3_CHANNEL_ROUTING)channel_routing[i]; + } + + profileAC3PP.eChannelRouting[0] = OMX_AUDIO_AC3_CHANNEL_LEFT; + profileAC3PP.eChannelRouting[1] = OMX_AUDIO_AC3_CHANNEL_RIGHT; + err = OMXhandle->setParameter(nodeID, indexTypeAC3PP, &profileAC3PP, sizeof(profileAC3PP)); + CHECK_EQ(err, (status_t)OK); +} + +status_t ExtendedCodec::setAMRWBPLUSFormat( + int32_t numChannels, int32_t sampleRate, sp OMXhandle, + IOMX::node_id nodeID) { + + QOMX_AUDIO_PARAM_AMRWBPLUSTYPE profileAMRWBPlus; + OMX_INDEXTYPE indexTypeAMRWBPlus; + OMX_PARAM_PORTDEFINITIONTYPE portParam; + + ALOGV("AMRWB+ setformat sampleRate:%d numChannels:%d",sampleRate,numChannels); + + //configure input port + InitOMXParams(&portParam); + portParam.nPortIndex = kPortIndexInput; + status_t err = OMXhandle->getParameter( + nodeID, OMX_IndexParamPortDefinition, &portParam, sizeof(portParam)); + CHECK_EQ(err, (status_t)OK); + err = OMXhandle->setParameter( + nodeID, OMX_IndexParamPortDefinition, &portParam, sizeof(portParam)); + CHECK_EQ(err, (status_t)OK); + + //configure output port + portParam.nPortIndex = kPortIndexOutput; + err = OMXhandle->getParameter( + nodeID, OMX_IndexParamPortDefinition, &portParam, sizeof(portParam)); + CHECK_EQ(err, (status_t)OK); + err = OMXhandle->setParameter( + nodeID, OMX_IndexParamPortDefinition, &portParam, sizeof(portParam)); + CHECK_EQ(err, (status_t)OK); + + err = OMXhandle->getExtensionIndex(nodeID, OMX_QCOM_INDEX_PARAM_AMRWBPLUS, &indexTypeAMRWBPlus); + + //for input port + InitOMXParams(&profileAMRWBPlus); + profileAMRWBPlus.nPortIndex = kPortIndexInput; + err = OMXhandle->getParameter(nodeID, indexTypeAMRWBPlus, &profileAMRWBPlus, sizeof(profileAMRWBPlus)); + CHECK_EQ(err,(status_t)OK); + + profileAMRWBPlus.nSampleRate = sampleRate; + profileAMRWBPlus.nChannels = numChannels; + err = OMXhandle->setParameter(nodeID, indexTypeAMRWBPlus, &profileAMRWBPlus, sizeof(profileAMRWBPlus)); + CHECK_EQ(err,(status_t)OK); + + //for output port + OMX_AUDIO_PARAM_PCMMODETYPE profilePcm; + InitOMXParams(&profilePcm); + profilePcm.nPortIndex = kPortIndexOutput; + err = OMXhandle->getParameter( + nodeID, OMX_IndexParamAudioPcm, &profilePcm, sizeof(profilePcm)); + CHECK_EQ(err, (status_t)OK); + + profilePcm.nSamplingRate = sampleRate; + profilePcm.nChannels = numChannels; + err = OMXhandle->setParameter( + nodeID, OMX_IndexParamAudioPcm, &profilePcm, sizeof(profilePcm)); + CHECK_EQ(err, (status_t)OK); + + return err; +} + +bool ExtendedCodec::useHWAACDecoder(const char *mime) { + char value[PROPERTY_VALUE_MAX] = {0}; + int aaccodectype = 0; + aaccodectype = property_get("media.aaccodectype", value, NULL); + if (aaccodectype && !strncmp("0", value, 1) && + !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { + ALOGI("Using Hardware AAC Decoder"); + return true; + } + return false; +} + +} //namespace android + +#else //ENABLE_AV_ENHANCEMENTS + +namespace android { + status_t ExtendedCodec::convertMetaDataToMessage( + const sp &meta, sp *format) { + ARG_TOUCH(meta); + ARG_TOUCH(format); + return OK; + } + + uint32_t ExtendedCodec::getComponentQuirks ( + const MediaCodecList *list, size_t index) { + ARG_TOUCH(list); + ARG_TOUCH(index); + return 0; + } + + status_t ExtendedCodec::setDIVXFormat( + const sp &msg, const char* mime, + sp OMXhandle, IOMX::node_id nodeID, int port_index) { + ARG_TOUCH(msg); + ARG_TOUCH(mime); + ARG_TOUCH(OMXhandle); + ARG_TOUCH(nodeID); + ARG_TOUCH(port_index); + return OK; + } + + status_t ExtendedCodec::setAudioFormat( + const sp &meta, const char* mime, + sp OMXhandle,IOMX::node_id nodeID, + bool isEncoder) { + ARG_TOUCH(meta); + ARG_TOUCH(mime); + ARG_TOUCH(OMXhandle); + ARG_TOUCH(nodeID); + ARG_TOUCH(isEncoder); + return OK; + } + + status_t ExtendedCodec::setAudioFormat( + const sp &msg, const char* mime, + sp OMXhandle,IOMX::node_id nodeID, + bool isEncoder) { + ARG_TOUCH(msg); + ARG_TOUCH(mime); + ARG_TOUCH(OMXhandle); + ARG_TOUCH(nodeID); + ARG_TOUCH(isEncoder); + return OK; + } + + status_t ExtendedCodec::setVideoInputFormat( + const char *mime, + OMX_VIDEO_CODINGTYPE *compressionFormat) { + ARG_TOUCH(mime); + ARG_TOUCH(compressionFormat); + return OK; + } + + status_t ExtendedCodec::setVideoOutputFormat( + const char *mime, + OMX_VIDEO_CODINGTYPE *compressionFormat) { + ARG_TOUCH(mime); + ARG_TOUCH(compressionFormat); + return OK; + } + + status_t ExtendedCodec::getSupportedAudioFormatInfo( + const AString* mime, + sp OMXhandle, + IOMX::node_id nodeID, + int portIndex, + int* channelCount) { + ARG_TOUCH(mime); + ARG_TOUCH(OMXhandle); + ARG_TOUCH(nodeID); + ARG_TOUCH(portIndex); + ARG_TOUCH(channelCount); + return OK; + } + + status_t ExtendedCodec::handleSupportedAudioFormats( + int format, AString* meta) { + ARG_TOUCH(format); + ARG_TOUCH(meta); + return UNKNOWN_ERROR; + } + + const char* ExtendedCodec::overrideComponentName ( + uint32_t quirks, const sp &meta) { + ARG_TOUCH(quirks); + ARG_TOUCH(meta); + return NULL; + } + + void ExtendedCodec::overrideComponentName( + uint32_t quirks, const sp &msg, + AString* componentName) { + ARG_TOUCH(quirks); + ARG_TOUCH(msg); + ARG_TOUCH(componentName); + } + + void ExtendedCodec::getRawCodecSpecificData( + const sp &meta, const void* &data, size_t &size) { + ARG_TOUCH(meta); + ARG_TOUCH(data); + size = 0; + } + + sp ExtendedCodec::getRawCodecSpecificData( + const sp &msg) { + ARG_TOUCH(msg); + return NULL; + } + + void ExtendedCodec::getAacCodecSpecificData( + const sp &meta, + const void* &data, + size_t& size) { + ARG_TOUCH(meta); + ARG_TOUCH(data); + size = 0; + return; + } + + sp ExtendedCodec::getAacCodecSpecificData( + const sp &msg) { + ARG_TOUCH(msg); + return NULL; + } + + + status_t ExtendedCodec::setSupportedRole( + const sp &omx, IOMX::node_id node, + bool isEncoder, const char *mime) { + ARG_TOUCH(omx); + ARG_TOUCH(node); + ARG_TOUCH(isEncoder); + ARG_TOUCH(mime); + return OK; + } + + status_t ExtendedCodec::setWMAFormat( + const sp &meta, sp OMXhandle, + IOMX::node_id nodeID, bool isEncoder) { + ARG_TOUCH(meta); + ARG_TOUCH(OMXhandle); + ARG_TOUCH(nodeID); + ARG_TOUCH(isEncoder); + return OK; + } + + status_t ExtendedCodec::setWMAFormat( + const sp &msg, sp OMXhandle, + IOMX::node_id nodeID, bool isEncoder) { + ARG_TOUCH(msg); + ARG_TOUCH(OMXhandle); + ARG_TOUCH(nodeID); + ARG_TOUCH(isEncoder); + return OK; + } + + void ExtendedCodec::setEVRCFormat( + int32_t numChannels, int32_t sampleRate, + sp OMXhandle, IOMX::node_id nodeID, + bool isEncoder) { + ARG_TOUCH(numChannels); + ARG_TOUCH(sampleRate); + ARG_TOUCH(OMXhandle); + ARG_TOUCH(nodeID); + ARG_TOUCH(isEncoder); + } + + void ExtendedCodec::setQCELPFormat( + int32_t numChannels, int32_t sampleRate, + sp OMXhandle, IOMX::node_id nodeID, + bool isEncoder) { + ARG_TOUCH(numChannels); + ARG_TOUCH(sampleRate); + ARG_TOUCH(OMXhandle); + ARG_TOUCH(nodeID); + ARG_TOUCH(isEncoder); + } + + void ExtendedCodec::setAC3Format( + int32_t numChannels, int32_t sampleRate, + sp OMXhandle, IOMX::node_id nodeID) { + ARG_TOUCH(numChannels); + ARG_TOUCH(sampleRate); + ARG_TOUCH(OMXhandle); + ARG_TOUCH(nodeID); + } + + status_t ExtendedCodec::setAMRWBPLUSFormat( + int32_t numChannels, int32_t sampleRate, + sp OMXhandle, IOMX::node_id nodeID) { + ARG_TOUCH(numChannels); + ARG_TOUCH(sampleRate); + ARG_TOUCH(OMXhandle); + ARG_TOUCH(nodeID); + return OK; + } + + void ExtendedCodec::configureFramePackingFormat( + const sp &msg, sp OMXhandle, + IOMX::node_id nodeID, const char* componentName) { + ARG_TOUCH(msg); + ARG_TOUCH(OMXhandle); + ARG_TOUCH(nodeID); + ARG_TOUCH(componentName); + } + + void ExtendedCodec::configureFramePackingFormat( + const sp &meta, sp OMXhandle, + IOMX::node_id nodeID, const char* componentName) { + ARG_TOUCH(meta); + ARG_TOUCH(OMXhandle); + ARG_TOUCH(nodeID); + ARG_TOUCH(componentName); + } + + void ExtendedCodec::configureVideoDecoder( + const sp &meta, const char* mime, sp OMXhandle, + const uint32_t flags, IOMX::node_id nodeID, const char* componentName) { + ARG_TOUCH(meta); + ARG_TOUCH(mime); + ARG_TOUCH(OMXhandle); + ARG_TOUCH(flags); + ARG_TOUCH(nodeID); + ARG_TOUCH(componentName); + } + + void ExtendedCodec::configureVideoDecoder( + const sp &msg, const char* mime, sp OMXhandle, + const uint32_t flags, IOMX::node_id nodeID, const char* componentName) { + ARG_TOUCH(msg); + ARG_TOUCH(mime); + ARG_TOUCH(OMXhandle); + ARG_TOUCH(flags); + ARG_TOUCH(nodeID); + ARG_TOUCH(componentName); + } + + bool ExtendedCodec::useHWAACDecoder(const char *mime) { + ARG_TOUCH(mime); + return false; + } + + void ExtendedCodec::enableSmoothStreaming( + const sp &omx, IOMX::node_id nodeID, bool* isEnabled, + const char* componentName) { + ARG_TOUCH(omx); + ARG_TOUCH(nodeID); + ARG_TOUCH(componentName); + *isEnabled = false; + return; + } + +} //namespace android + +#endif //ENABLE_AV_ENHANCEMENTS diff --git a/media/libstagefright/ExtendedExtractor.cpp b/media/libstagefright/ExtendedExtractor.cpp new file mode 100644 index 00000000000..305563d0ac8 --- /dev/null +++ b/media/libstagefright/ExtendedExtractor.cpp @@ -0,0 +1,151 @@ +/*Copyright (c) 2012 - 2014, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "ExtendedExtractor" +#include +#include // for dlopen/dlclose +#include "include/ExtendedExtractor.h" + +#define ARG_TOUCH(x) (void)x + +#ifdef ENABLE_AV_ENHANCEMENTS + +namespace android { + +static const char* EXTENDED_EXTRACTOR_LIB = "libExtendedExtractor.so"; +static const char* EXTENDED_EXTRACTOR_CREATE = "CreateExtractor"; +static const char* EXTENDED_EXTRACTOR_SNIFF = "SniffExtendedExtractor"; + +typedef MediaExtractor* (*ExtendedExtractorCreate) + (const sp &source, const char* mime); + +typedef bool (*ExtendedExtractorSniff) + (const sp &source, String8 *mimeType, + float *confidence,sp *meta); + +static void* loadExtendedExtractorLib() { + static void* extendedExtractorLib = NULL; + static bool alreadyTriedToLoadLib = false; + + if(!alreadyTriedToLoadLib) { + alreadyTriedToLoadLib = true; + + extendedExtractorLib = ::dlopen(EXTENDED_EXTRACTOR_LIB, RTLD_LAZY); + + if(extendedExtractorLib == NULL) { + ALOGV("Failed to load %s, dlerror = %s \n", + EXTENDED_EXTRACTOR_LIB, dlerror()); + } + } + + return extendedExtractorLib; +} + +MediaExtractor* ExtendedExtractor::Create ( + const sp &source, const char *mime) { + static ExtendedExtractorCreate create = NULL; + static bool alreadyTriedToFindCreateFunction = false; + MediaExtractor* extractor = NULL; + + if (!alreadyTriedToFindCreateFunction) { + void *extendedExtractorLib = loadExtendedExtractorLib(); + + if (extendedExtractorLib != NULL) { + create = (ExtendedExtractorCreate) dlsym ( + extendedExtractorLib, EXTENDED_EXTRACTOR_CREATE); + alreadyTriedToFindCreateFunction = true; + } + } + + if (create == NULL) { + ALOGE ("Failed to find symbol : %s, dlerror = %s", + EXTENDED_EXTRACTOR_CREATE, dlerror()); + return NULL; + } + + extractor = create (source, mime); + if (extractor == NULL) { + ALOGE("Failed to instantiate extractor \n"); + } + + return extractor; +} + +bool ExtendedExtractor::Sniff ( + const sp &source, String8 *mimeType, + float *confidence,sp *meta) { + void *extendedExtractorLib = loadExtendedExtractorLib(); + bool retVal = false; + + if (extendedExtractorLib != NULL) { + ExtendedExtractorSniff sniff = (ExtendedExtractorSniff) dlsym ( + extendedExtractorLib, EXTENDED_EXTRACTOR_SNIFF); + + if (sniff == NULL) { + ALOGE ("Failed to find symbol : %s, dlerror = %s", + EXTENDED_EXTRACTOR_SNIFF, dlerror()); + return retVal; + } + + retVal = sniff (source, mimeType, confidence, meta); + + if(!retVal) { + ALOGV("Sniff Failed"); + } + } + return retVal; +} + +} // namespace android + +#else //ENABLE_AV_ENHANCEMENTS + +namespace android { + +MediaExtractor* ExtendedExtractor::Create ( + const sp &source, const char *mime) { + ARG_TOUCH(source); + ARG_TOUCH(mime); + return NULL; +} +bool ExtendedExtractor::Sniff ( + const sp &source, String8 *mimeType, + float *confidence, sp *meta) { + ARG_TOUCH(source); + ARG_TOUCH(mimeType); + ARG_TOUCH(confidence); + ARG_TOUCH(meta); + *confidence = 0.0; + return false; +} + +} // namespace android + +#endif //ENABLE_AV_ENHANCEMENTS + diff --git a/media/libstagefright/ExtendedMediaDefs.cpp b/media/libstagefright/ExtendedMediaDefs.cpp new file mode 100644 index 00000000000..c15de3fe466 --- /dev/null +++ b/media/libstagefright/ExtendedMediaDefs.cpp @@ -0,0 +1,65 @@ +/*Copyright (c) 2012 - 2014, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +namespace android { + +const char *MEDIA_MIMETYPE_AUDIO_EVRC = "audio/evrc"; + +const char *MEDIA_MIMETYPE_VIDEO_WMV = "video/x-ms-wmv"; +const char *MEDIA_MIMETYPE_AUDIO_WMA = "audio/x-ms-wma"; +const char *MEDIA_MIMETYPE_CONTAINER_ASF = "video/x-ms-asf"; +const char *MEDIA_MIMETYPE_VIDEO_DIVX = "video/divx"; +const char *MEDIA_MIMETYPE_CONTAINER_AAC = "audio/aac"; +const char *MEDIA_MIMETYPE_CONTAINER_QCP = "audio/vnd.qcelp"; +const char *MEDIA_MIMETYPE_VIDEO_DIVX311 = "video/divx311"; +const char *MEDIA_MIMETYPE_VIDEO_DIVX4 = "video/divx4"; + +const char *MEDIA_MIMETYPE_CONTAINER_MPEG2 = "video/mp2"; + +const char *MEDIA_MIMETYPE_CONTAINER_3G2 = "video/3g2"; +const char *MEDIA_MIMETYPE_AUDIO_DTS = "audio/dts"; + +const char *MEDIA_MIMETYPE_AUDIO_DTS_LBR = "audio/dts-lbr"; +const char *MEDIA_MIMETYPE_AUDIO_EAC3 = "audio/eac3"; +const char *MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS = "audio/amr-wb-plus"; +const char *MEDIA_MIMETYPE_CONTAINER_QCAMR_NB = "audio/qc-amr"; +const char *MEDIA_MIMETYPE_CONTAINER_QCAMR_WB = "audio/qc-amr-wb"; +const char *MEDIA_MIMETYPE_CONTAINER_QCMPEG = "audio/qc-mpeg"; +const char *MEDIA_MIMETYPE_CONTAINER_QCWAV = "audio/qc-wav"; +const char *MEDIA_MIMETYPE_CONTAINER_QCMPEG2TS = "video/qc-mp2ts"; +const char *MEDIA_MIMETYPE_CONTAINER_QCMPEG2PS = "video/qc-mp2ps"; +const char *MEDIA_MIMETYPE_CONTAINER_QCMPEG4 = "video/qc-mp4"; +const char *MEDIA_MIMETYPE_CONTAINER_QCMATROSKA = "video/qc-matroska"; +const char *MEDIA_MIMETYPE_CONTAINER_QCOGG = "video/qc-ogg"; +const char *MEDIA_MIMETYPE_CONTAINER_QCFLV = "video/qc-flv"; +const char *MEDIA_MIMETYPE_VIDEO_VPX = "video/x-vnd.on2.vp8"; //backward compatibility +const char *MEDIA_MIMETYPE_CONTAINER_QTIFLAC = "audio/qti-flac"; + +} // namespace android diff --git a/media/libstagefright/ExtendedUtils.cpp b/media/libstagefright/ExtendedUtils.cpp new file mode 100644 index 00000000000..d295af37869 --- /dev/null +++ b/media/libstagefright/ExtendedUtils.cpp @@ -0,0 +1,483 @@ +/*Copyright (c) 2013 - 2014, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "ExtendedUtils" +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "include/ExtendedUtils.h" + +static const int64_t kDefaultAVSyncLateMargin = 40000; +static const int64_t kMaxAVSyncLateMargin = 250000; + +#define ARG_TOUCH(x) (void)x + +#ifdef ENABLE_AV_ENHANCEMENTS + +#include +#include + +#include "include/ExtendedExtractor.h" +#include "include/avc_utils.h" + +namespace android { + +bool ExtendedUtils::ShellProp::isAudioDisabled(bool isEncoder) { + bool retVal = false; + char disableAudio[PROPERTY_VALUE_MAX]; + property_get("persist.debug.sf.noaudio", disableAudio, "0"); + if (isEncoder && (atoi(disableAudio) & 0x02)) { + retVal = true; + } else if (atoi(disableAudio) & 0x01) { + retVal = true; + } + return retVal; +} + +void ExtendedUtils::ShellProp::setEncoderProfile( + video_encoder &videoEncoder, int32_t &videoEncoderProfile) { + char value[PROPERTY_VALUE_MAX]; + bool customProfile = false; + if (!property_get("encoder.video.profile", value, NULL) > 0) { + return; + } + + switch (videoEncoder) { + case VIDEO_ENCODER_H264: + if (strncmp("base", value, 4) == 0) { + videoEncoderProfile = OMX_VIDEO_AVCProfileBaseline; + ALOGI("H264 Baseline Profile"); + } else if (strncmp("main", value, 4) == 0) { + videoEncoderProfile = OMX_VIDEO_AVCProfileMain; + ALOGI("H264 Main Profile"); + } else if (strncmp("high", value, 4) == 0) { + videoEncoderProfile = OMX_VIDEO_AVCProfileHigh; + ALOGI("H264 High Profile"); + } else { + ALOGW("Unsupported H264 Profile"); + } + break; + case VIDEO_ENCODER_MPEG_4_SP: + if (strncmp("simple", value, 5) == 0 ) { + videoEncoderProfile = OMX_VIDEO_MPEG4ProfileSimple; + ALOGI("MPEG4 Simple profile"); + } else if (strncmp("asp", value, 3) == 0 ) { + videoEncoderProfile = OMX_VIDEO_MPEG4ProfileAdvancedSimple; + ALOGI("MPEG4 Advanced Simple Profile"); + } else { + ALOGW("Unsupported MPEG4 Profile"); + } + break; + default: + ALOGW("No custom profile support for other codecs"); + break; + } +} + +int64_t ExtendedUtils::ShellProp::getMaxAVSyncLateMargin() { + char lateMarginMs[PROPERTY_VALUE_MAX] = {0}; + property_get("media.sf.set.late.margin", lateMarginMs, "0"); + int64_t newLateMarginUs = atoi(lateMarginMs)*1000; + int64_t maxLateMarginUs = newLateMarginUs; + + if (newLateMarginUs > kDefaultAVSyncLateMargin + || newLateMarginUs < kDefaultAVSyncLateMargin) { + maxLateMarginUs = kDefaultAVSyncLateMargin; + } + + ALOGI("AV Sync late margin : Intended=%lldms Using=%lldms", + maxLateMarginUs/1000, newLateMarginUs/1000); + return maxLateMarginUs; +} + +bool ExtendedUtils::ShellProp::isSmoothStreamingEnabled() { + char prop[PROPERTY_VALUE_MAX] = {0}; + property_get("mm.enable.smoothstreaming", prop, "0"); + if (!strncmp(prop, "true", 4) || atoi(prop)) { + return true; + } + return false; +} + +void ExtendedUtils::setBFrames( + OMX_VIDEO_PARAM_MPEG4TYPE &mpeg4type, int32_t &numBFrames, + const char* componentName) { + //ignore non QC components + if (strncmp(componentName, "OMX.qcom.", 9)) { + return; + } + if (mpeg4type.eProfile > OMX_VIDEO_MPEG4ProfileSimple) { + mpeg4type.nAllowedPictureTypes |= OMX_VIDEO_PictureTypeB; + mpeg4type.nBFrames = 1; + mpeg4type.nPFrames /= (mpeg4type.nBFrames + 1); + numBFrames = mpeg4type.nBFrames; + } + return; +} + +void ExtendedUtils::setBFrames( + OMX_VIDEO_PARAM_AVCTYPE &h264type, int32_t &numBFrames, + int32_t iFramesInterval, int32_t frameRate, const char* componentName) { + //ignore non QC components + if (strncmp(componentName, "OMX.qcom.", 9)) { + return; + } + OMX_U32 val = 0; + if (iFramesInterval < 0) { + val = 0xFFFFFFFF; + } else if (iFramesInterval == 0) { + val = 0; + } else { + val = frameRate * iFramesInterval - 1; + CHECK(val > 1); + } + + h264type.nPFrames = val; + + if (h264type.nPFrames == 0) { + h264type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI; + } + + if (h264type.eProfile > OMX_VIDEO_AVCProfileBaseline) { + h264type.nAllowedPictureTypes |= OMX_VIDEO_PictureTypeB; + h264type.nBFrames = 1; + h264type.nPFrames /= (h264type.nBFrames + 1); + //enable CABAC as default entropy mode for Hihg/Main profiles + h264type.bEntropyCodingCABAC = OMX_TRUE; + h264type.nCabacInitIdc = 0; + numBFrames = h264type.nBFrames; + } + return; +} + +/* +QCOM HW AAC encoder allowed bitrates +------------------------------------------------------------------------------------------------------------------ +Bitrate limit |AAC-LC(Mono) | AAC-LC(Stereo) |AAC+(Mono) | AAC+(Stereo) | eAAC+ | +Minimum |Min(24000,0.5 * f_s) |Min(24000,f_s) | 24000 |24000 | 24000 | +Maximum |Min(192000,6 * f_s) |Min(192000,12 * f_s) | Min(192000,6 * f_s) | Min(192000,12 * f_s) | Min(192000,12 * f_s) | +------------------------------------------------------------------------------------------------------------------ +*/ +bool ExtendedUtils::UseQCHWAACEncoder(audio_encoder Encoder,int32_t Channel,int32_t BitRate,int32_t SampleRate) +{ + bool ret = false; + int minBiteRate = -1; + int maxBiteRate = -1; + char propValue[PROPERTY_VALUE_MAX] = {0}; + + ARG_TOUCH(BitRate); + property_get("qcom.hw.aac.encoder",propValue,NULL); + if (!strncmp(propValue,"true",sizeof("true"))) { + //check for QCOM's HW AAC encoder only when qcom.aac.encoder = true; + ALOGV("qcom.aac.encoder enabled, check AAC encoder(%d) allowed bitrates",Encoder); + switch (Encoder) { + case AUDIO_ENCODER_AAC:// for AAC-LC format + if (Channel == 1) {//mono + minBiteRate = MIN_BITERATE_AAC<(SampleRate/2)?MIN_BITERATE_AAC:(SampleRate/2); + maxBiteRate = MAX_BITERATE_AAC<(SampleRate*6)?MAX_BITERATE_AAC:(SampleRate*6); + } else if (Channel == 2) {//stereo + minBiteRate = MIN_BITERATE_AAC= minBiteRate && BitRate <= maxBiteRate) { + ret = true; + } + } + + return ret; +} + + +//- returns NULL if we dont really need a new extractor (or cannot), +// valid extractor is returned otherwise +//- caller needs to check for NULL +// ---------------------------------------- +// defaultExt - the existing extractor +// source - file source +// mime - container mime +// ---------------------------------------- +// Note: defaultExt will be deleted in this function if the new parser is selected + +sp ExtendedUtils::MediaExtractor_CreateIfNeeded(sp defaultExt, + const sp &source, + const char *mime) { + bool bCheckExtendedExtractor = false; + bool videoTrackFound = false; + bool audioTrackFound = false; + bool amrwbAudio = false; + int numOfTrack = 0; + + if (defaultExt != NULL) { + for (size_t trackItt = 0; trackItt < defaultExt->countTracks(); ++trackItt) { + ++numOfTrack; + sp meta = defaultExt->getTrackMetaData(trackItt); + const char *_mime; + CHECK(meta->findCString(kKeyMIMEType, &_mime)); + + String8 mime = String8(_mime); + + if (!strncasecmp(mime.string(), "audio/", 6)) { + audioTrackFound = true; + + amrwbAudio = !strncasecmp(mime.string(), + MEDIA_MIMETYPE_AUDIO_AMR_WB, + strlen(MEDIA_MIMETYPE_AUDIO_AMR_WB)); + if (amrwbAudio) { + break; + } + } else if (!strncasecmp(mime.string(), "video/", 6)) { + videoTrackFound = true; + } + } + + if (amrwbAudio) { + bCheckExtendedExtractor = true; + } else if (numOfTrack == 0) { + bCheckExtendedExtractor = true; + } else if (numOfTrack == 1) { + if ((videoTrackFound) || + (!videoTrackFound && !audioTrackFound)) { + bCheckExtendedExtractor = true; + } + } else if (numOfTrack >= 2) { + if (videoTrackFound && audioTrackFound) { + if (amrwbAudio) { + bCheckExtendedExtractor = true; + } + } else { + bCheckExtendedExtractor = true; + } + } + } else { + bCheckExtendedExtractor = true; + } + + if (!bCheckExtendedExtractor) { + ALOGD("extended extractor not needed, return default"); + return defaultExt; + } + + //Create Extended Extractor only if default extractor is not selected + ALOGD("Try creating ExtendedExtractor"); + sp retExtExtractor = ExtendedExtractor::Create(source, mime); + + if (retExtExtractor == NULL) { + ALOGD("Couldn't create the extended extractor, return default one"); + return defaultExt; + } + + if (defaultExt == NULL) { + ALOGD("default extractor is NULL, return extended extractor"); + return retExtExtractor; + } + + //bCheckExtendedExtractor is true which means default extractor was found + //but we want to give preference to extended extractor based on certain + //conditions. + + //needed to prevent a leak in case both extractors are valid + //but we still dont want to use the extended one. we need + //to delete the new one + bool bUseDefaultExtractor = true; + + for (size_t trackItt = 0; (trackItt < retExtExtractor->countTracks()); ++trackItt) { + sp meta = retExtExtractor->getTrackMetaData(trackItt); + const char *mime; + bool success = meta->findCString(kKeyMIMEType, &mime); + if ((success == true) && + (!strncasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS, + strlen(MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS)) || + !strncasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC, + strlen(MEDIA_MIMETYPE_VIDEO_HEVC)) )) { + + ALOGD("Discarding default extractor and using the extended one"); + bUseDefaultExtractor = false; + break; + } + } + + if (bUseDefaultExtractor) { + ALOGD("using default extractor inspite of having a new extractor"); + retExtExtractor.clear(); + return defaultExt; + } else { + defaultExt.clear(); + return retExtExtractor; + } + +} + +bool ExtendedUtils::isAVCProfileSupported(int32_t profile) { + if (profile == OMX_VIDEO_AVCProfileMain || + profile == OMX_VIDEO_AVCProfileHigh || + profile == OMX_VIDEO_AVCProfileBaseline) { + return true; + } else { + return false; + } +} + +void ExtendedUtils::updateNativeWindowBufferGeometry(ANativeWindow* anw, + OMX_U32 width, OMX_U32 height, OMX_COLOR_FORMATTYPE colorFormat) { + ARG_TOUCH(anw); + ARG_TOUCH(width); + ARG_TOUCH(height); + ARG_TOUCH(colorFormat); + +#if UPDATE_BUFFER_GEOMETRY_AVAILABLE + if (anw != NULL) { + ALOGI("Calling native window update buffer geometry [%lu x %lu]", + width, height); + status_t err = anw->perform( + anw, NATIVE_WINDOW_UPDATE_BUFFERS_GEOMETRY, + width, height, colorFormat); + if (err != OK) { + ALOGE("UPDATE_BUFFER_GEOMETRY failed %d", err); + } + } +#endif +} + +bool ExtendedUtils::checkIsThumbNailMode(const uint32_t flags, char* componentName) { + bool isInThumbnailMode = false; + if ((flags & OMXCodec::kClientNeedsFramebuffer) && !strncmp(componentName, "OMX.qcom.", 9)) { + isInThumbnailMode = true; + } + return isInThumbnailMode; +} + +} +#else //ENABLE_AV_ENHANCEMENTS + +namespace android { + +bool ExtendedUtils::ShellProp::isAudioDisabled(bool isEncoder) { + return false; +} + +void ExtendedUtils::ShellProp::setEncoderProfile( + video_encoder &videoEncoder, int32_t &videoEncoderProfile) { + ARG_TOUCH(videoEncoder); + ARG_TOUCH(videoEncoderProfile); +} + +int64_t ExtendedUtils::ShellProp::getMaxAVSyncLateMargin() { + return kDefaultAVSyncLateMargin; +} + +bool ExtendedUtils::ShellProp::isSmoothStreamingEnabled() { + return false; +} + +void ExtendedUtils::setBFrames( + OMX_VIDEO_PARAM_MPEG4TYPE &mpeg4type, int32_t &numBFrames, + const char* componentName) { + ARG_TOUCH(mpeg4type); + ARG_TOUCH(numBFrames); + ARG_TOUCH(componentName); +} + +void ExtendedUtils::setBFrames( + OMX_VIDEO_PARAM_AVCTYPE &h264type, int32_t &numBFrames, + int32_t iFramesInterval, int32_t frameRate, + const char* componentName) { + ARG_TOUCH(h264type); + ARG_TOUCH(numBFrames); + ARG_TOUCH(iFramesInterval); + ARG_TOUCH(frameRate); + ARG_TOUCH(componentName); +} + +bool ExtendedUtils::UseQCHWAACEncoder(audio_encoder Encoder,int32_t Channel, + int32_t BitRate,int32_t SampleRate) { + ARG_TOUCH(Encoder); + ARG_TOUCH(Channel); + ARG_TOUCH(BitRate); + ARG_TOUCH(SampleRate); + return false; +} + +sp ExtendedUtils::MediaExtractor_CreateIfNeeded( + sp defaultExt, + const sp &source, + const char *mime) { + ARG_TOUCH(defaultExt); + ARG_TOUCH(source); + ARG_TOUCH(mime); + return defaultExt; +} + +bool ExtendedUtils::isAVCProfileSupported(int32_t profile) { + ARG_TOUCH(profile); + return false; +} + +void ExtendedUtils::updateNativeWindowBufferGeometry(ANativeWindow* anw, + OMX_U32 width, OMX_U32 height, OMX_COLOR_FORMATTYPE colorFormat) { + ARG_TOUCH(anw); + ARG_TOUCH(width); + ARG_TOUCH(height); + ARG_TOUCH(colorFormat); +} + +bool ExtendedUtils::checkIsThumbNailMode(const uint32_t flags, char* componentName) { + ARG_TOUCH(flags); + ARG_TOUCH(componentName); + return false; +} + +} +#endif //ENABLE_AV_ENHANCEMENTS diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp old mode 100644 new mode 100755 index df47bd56767..437d82223ca --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -1697,6 +1698,18 @@ void MediaCodec::extractCSD(const sp &format) { ++i; } + sp extendedCSD = ExtendedCodec::getRawCodecSpecificData(format); + if (extendedCSD != NULL) { + ALOGV("pushing extended CSD of size %d", extendedCSD->size()); + mCSD.push_back(extendedCSD); + } + + sp aacCSD = ExtendedCodec::getAacCodecSpecificData(format); + if (aacCSD != NULL) { + ALOGV("pushing AAC CSD of size %d", aacCSD->size()); + mCSD.push_back(aacCSD); + } + ALOGV("Found %zu pieces of codec specific data.", mCSD.size()); } diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp old mode 100644 new mode 100755 index 9ab66119995..7c66429daf4 --- a/media/libstagefright/MediaExtractor.cpp +++ b/media/libstagefright/MediaExtractor.cpp @@ -39,6 +39,8 @@ #include #include +#include "include/ExtendedUtils.h" + namespace android { sp MediaExtractor::getMetaData() { @@ -126,7 +128,7 @@ sp MediaExtractor::Create( } } - return ret; + return ExtendedUtils::MediaExtractor_CreateIfNeeded(ret, source, mime); } } // namespace android diff --git a/media/libstagefright/NOTICE b/media/libstagefright/NOTICE index c5b1efa7aac..42cdaab58b2 100644 --- a/media/libstagefright/NOTICE +++ b/media/libstagefright/NOTICE @@ -188,3 +188,31 @@ END OF TERMS AND CONDITIONS +Copyright (c) 2012 - 2014, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index a8806c8e5b4..6d021e04332 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -52,6 +52,8 @@ #include #include +#include +#include "include/ExtendedUtils.h" #include "include/avc_utils.h" namespace android { @@ -260,6 +262,8 @@ uint32_t OMXCodec::getComponentQuirks( quirks |= kOutputBuffersAreUnreadable; } + quirks |= ExtendedCodec::getComponentQuirks(list,index); + return quirks; } @@ -342,6 +346,11 @@ sp OMXCodec::Create( } } + const char* ext_componentName = ExtendedCodec::overrideComponentName(quirks, meta); + if(ext_componentName != NULL) { + componentName = ext_componentName; + } + ALOGV("Attempting to allocate OMX node '%s'", componentName); if (!createEncoder @@ -571,6 +580,11 @@ status_t OMXCodec::configureCodec(const sp &meta) { addCodecSpecificData(data, size); CHECK(meta->findData(kKeyOpusSeekPreRoll, &type, &data, &size)); addCodecSpecificData(data, size); + } else { + ExtendedCodec::getRawCodecSpecificData(meta, data, size); + if (size) { + addCodecSpecificData(data, size); + } } } @@ -640,6 +654,18 @@ status_t OMXCodec::configureCodec(const sp &meta) { CHECK(meta->findInt32(kKeySampleRate, &sampleRate)); setRawAudioFormat(kPortIndexInput, sampleRate, numChannels); + } else { + if (mIsEncoder && !mIsVideo) { + int32_t numChannels, sampleRate; + CHECK(meta->findInt32(kKeyChannelCount, &numChannels)); + CHECK(meta->findInt32(kKeySampleRate, &sampleRate)); + setRawAudioFormat(kPortIndexInput, sampleRate, numChannels); + } + status_t err = ExtendedCodec::setAudioFormat( + meta, mMIME, mOMX, mNode, mIsEncoder); + if(OK != err) { + return err; + } } if (!strncasecmp(mMIME, "video/", 6)) { @@ -647,6 +673,9 @@ status_t OMXCodec::configureCodec(const sp &meta) { if (mIsEncoder) { setVideoInputFormat(mMIME, meta); } else { + ExtendedCodec::configureVideoDecoder( + meta, mMIME, mOMX, mFlags, mNode, mComponentName); + status_t err = setVideoOutputFormat( mMIME, meta); @@ -895,8 +924,11 @@ void OMXCodec::setVideoInputFormat( } 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."); + status_t err = ExtendedCodec::setVideoInputFormat(mime, &compressionFormat); + if (err != OK) { + ALOGE("Not a supported video mime type: %s", mime); + CHECK(!"Should not be here. Not a supported video mime type."); + } } OMX_COLOR_FORMATTYPE colorFormat; @@ -1185,6 +1217,7 @@ status_t OMXCodec::setupMPEG4EncoderParameters(const sp& meta) { mpeg4type.eProfile = static_cast(profileLevel.mProfile); mpeg4type.eLevel = static_cast(profileLevel.mLevel); + ExtendedUtils::setBFrames(mpeg4type, mNumBFrames, mComponentName); err = mOMX->setParameter( mNode, OMX_IndexParamVideoMpeg4, &mpeg4type, sizeof(mpeg4type)); CHECK_EQ(err, (status_t)OK); @@ -1223,7 +1256,9 @@ status_t OMXCodec::setupAVCEncoderParameters(const sp& meta) { h264type.eLevel = static_cast(profileLevel.mLevel); // XXX - if (h264type.eProfile != OMX_VIDEO_AVCProfileBaseline) { + if (ExtendedUtils::isAVCProfileSupported(h264type.eProfile)){ + ALOGI("Profile type is %d ",h264type.eProfile); + } else if (h264type.eProfile != OMX_VIDEO_AVCProfileBaseline) { ALOGW("Use baseline profile instead of %d for AVC recording", h264type.eProfile); h264type.eProfile = OMX_VIDEO_AVCProfileBaseline; @@ -1248,6 +1283,8 @@ status_t OMXCodec::setupAVCEncoderParameters(const sp& meta) { h264type.nCabacInitIdc = 0; } + ExtendedUtils::setBFrames( + h264type, mNumBFrames, iFramesInterval, frameRate, mComponentName); if (h264type.nBFrames != 0) { h264type.nAllowedPictureTypes |= OMX_VIDEO_PictureTypeB; } @@ -1295,9 +1332,13 @@ status_t OMXCodec::setVideoOutputFormat( } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG2, mime)) { compressionFormat = OMX_VIDEO_CodingMPEG2; } else { + status_t err = ExtendedCodec::setVideoOutputFormat(mime,&compressionFormat); + + if(err != OK) { 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); @@ -1440,7 +1481,8 @@ OMXCodec::OMXCodec( mPaused(false), mNativeWindow( (!strncmp(componentName, "OMX.google.", 11)) - ? NULL : nativeWindow) { + ? NULL : nativeWindow), + mNumBFrames(0) { mPortStatus[kPortIndexInput] = ENABLED; mPortStatus[kPortIndexOutput] = ENABLED; @@ -1513,6 +1555,7 @@ void OMXCodec::setComponentRole( } if (i == kNumMimeToRole) { + ExtendedCodec::setSupportedRole(omx, node, isEncoder, mime); return; } diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp index 4449d576103..3e01a0908d3 100644 --- a/media/libstagefright/StagefrightMediaScanner.cpp +++ b/media/libstagefright/StagefrightMediaScanner.cpp @@ -44,6 +44,9 @@ static bool FileHasAcceptableExtension(const char *extension) { ".wav", ".amr", ".midi", ".xmf", ".rtttl", ".rtx", ".ota", ".mkv", ".mka", ".webm", ".ts", ".fl", ".flac", ".mxmf", ".avi", ".mpeg", ".mpg", ".awb", ".mpga" +#ifdef ENABLE_AV_ENHANCEMENTS + ,".qcp", ".ac3", ".dts", ".wmv", ".ec3", ".mov" +#endif }; static const size_t kNumValidExtensions = sizeof(kValidExtensions) / sizeof(kValidExtensions[0]); diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp old mode 100644 new mode 100755 index 25afc5b70c6..96009106c53 --- a/media/libstagefright/Utils.cpp +++ b/media/libstagefright/Utils.cpp @@ -34,6 +34,7 @@ #include #include #include +#include namespace android { @@ -346,6 +347,7 @@ status_t convertMetaDataToMessage( msg->setBuffer("csd-0", buffer); } + ExtendedCodec::convertMetaDataToMessage(meta, &msg); *format = msg; return OK; diff --git a/media/libstagefright/include/ExtendedExtractor.h b/media/libstagefright/include/ExtendedExtractor.h new file mode 100644 index 00000000000..590674deadf --- /dev/null +++ b/media/libstagefright/include/ExtendedExtractor.h @@ -0,0 +1,49 @@ +/*Copyright (c) 2012 - 2014, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef EXTENDED_EXTRACTOR_ +#define EXTENDED_EXTRACTOR_ + +#include + +namespace android { + +class MediaExtractor; +class ExtendedExtractor +{ +public: + static MediaExtractor* Create ( + const sp &source, const char *mime); + static bool Sniff ( + const sp &source, String8 *mimeType, + float *confidence,sp *meta); +}; + +} // namespace android + +#endif //EXTENDED_EXTRACTOR_ diff --git a/media/libstagefright/include/ExtendedUtils.h b/media/libstagefright/include/ExtendedUtils.h new file mode 100644 index 00000000000..04f260b7981 --- /dev/null +++ b/media/libstagefright/include/ExtendedUtils.h @@ -0,0 +1,97 @@ +/* Copyright (c) 2013 - 2014, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EXTENDED_UTILS_H_ +#define EXTENDED_UTILS_H_ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define MIN_BITERATE_AAC 24000 +#define MAX_BITERATE_AAC 192000 + +namespace android { + +/* + * This class is a placeholder for utility methods for + * QC specific changes + */ +struct ExtendedUtils { + + /* + * This class is a placeholder for methods to override + * default heaviour based on shell properties set + */ + struct ShellProp { + // check if shell property to disable audio is set + static bool isAudioDisabled(bool isEncoder); + + //helper function to set encoding profiles + static void setEncoderProfile(video_encoder &videoEncoder, + int32_t &videoEncoderProfile); + + static bool isSmoothStreamingEnabled(); + + static int64_t getMaxAVSyncLateMargin(); + }; + + //set B frames for MPEG4 + static void setBFrames(OMX_VIDEO_PARAM_MPEG4TYPE &mpeg4type, int32_t &numBFrames, + const char* componentName); + + //set B frames for H264 + static void setBFrames(OMX_VIDEO_PARAM_AVCTYPE &h264type, int32_t &numBFrames, + int32_t iFramesInterval, int32_t frameRate, const char* componentName); + + static bool UseQCHWAACEncoder(audio_encoder Encoder, int32_t Channel, + int32_t BitRate, int32_t SampleRate); + + static sp MediaExtractor_CreateIfNeeded( + sp defaultExt, const sp &source, + const char *mime); + + static bool isAVCProfileSupported(int32_t profile); + + //notify stride change to ANW + static void updateNativeWindowBufferGeometry(ANativeWindow* anw, + OMX_U32 width, OMX_U32 height, OMX_COLOR_FORMATTYPE colorFormat); + + static bool checkIsThumbNailMode(const uint32_t flags, char* componentName); + +}; + +} +#endif //EXTENDED_UTILS_H_