diff options
Diffstat (limited to 'media/libstagefright/QCUtilityClass.cpp')
-rw-r--r-- | media/libstagefright/QCUtilityClass.cpp | 356 |
1 files changed, 356 insertions, 0 deletions
diff --git a/media/libstagefright/QCUtilityClass.cpp b/media/libstagefright/QCUtilityClass.cpp new file mode 100644 index 0000000..1efc040 --- /dev/null +++ b/media/libstagefright/QCUtilityClass.cpp @@ -0,0 +1,356 @@ +/*Copyright (c) 2013, 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 "QCUtilClass" +#include <utils/Log.h> + +#include <include/QCUtilityClass.h> +#include "include/ExtendedExtractor.h" +#include <media/stagefright/MetaData.h> + +#include <media/stagefright/foundation/ADebug.h> +#include <media/stagefright/MediaDefs.h> +#include <media/stagefright/OMXCodec.h> + +namespace android { + +//-- START :: HFR Related Changes ----- + +status_t QCUtilityClass::helper_StageFrightRecoder_hfr(sp<MetaData> &meta, sp<MetaData> &enc_meta, + int64_t &maxFileDurationUs, int32_t frameRate, + video_encoder videoEncoder) { + status_t retVal = OK; + int32_t hfr = 0; + + if (!meta->findInt32(kKeyHFR, &hfr)) { + ALOGW("hfr not found, default to 0"); + } + + if (hfr && frameRate) { + maxFileDurationUs = maxFileDurationUs * (hfr/frameRate); + } + + enc_meta->setInt32(kKeyHFR, hfr); + int32_t width = 0, height = 0; + + CHECK(meta->findInt32(kKeyWidth, &width)); + CHECK(meta->findInt32(kKeyHeight, &height)); + + char mDeviceName[100]; + property_get("ro.board.platform",mDeviceName,"0"); + if (!strncmp(mDeviceName, "msm7627a", 8)) { + if (hfr && (width * height > 432*240)) { + ALOGE("HFR mode is supported only upto WQVGA resolution"); + return INVALID_OPERATION; + } + } else { + if(hfr && ((videoEncoder != VIDEO_ENCODER_H264) || (width * height > 800*480))) { + ALOGE("HFR mode is supported only upto WVGA and H264 codec."); + return INVALID_OPERATION; + } + } + return retVal; +} + +void QCUtilityClass::helper_CameraSource_hfr(const CameraParameters& params, + sp<MetaData> &meta) { + const char *hfr_str = params.get("video-hfr"); + int32_t hfr = -1; + + if (hfr_str != NULL) { + hfr = atoi(hfr_str); + } + if (hfr < 0) { + ALOGW("Invalid hfr value(%d) set from app. Disabling HFR.", hfr); + hfr = 0; + } + meta->setInt32(kKeyHFR, hfr); +} + +void QCUtilityClass::helper_MPEG4Writer_hfr(sp<MetaData> &meta, + int64_t ×tampUs) { + int32_t frameRate = 0, hfr = 0, multiple = 0; + + if (!(meta->findInt32(kKeyFrameRate, &frameRate))) { + return; + } + + if (!(meta->findInt32(kKeyHFR, &hfr))) { + return; + } + + multiple = hfr ? (hfr/frameRate) : 1; + timestampUs = multiple * timestampUs; +} + +void QCUtilityClass::helper_OMXCodec_hfr(const sp<MetaData> &meta, + int32_t &frameRate, + int32_t &bitRate, + int32_t &newFrameRate) { + int32_t hfr = 0, hfrRatio = 0; + if (!(meta->findInt32(kKeyHFR, &hfr))) { + return; + } + + hfrRatio = hfr ? hfr/frameRate : 1; + frameRate = hfr?hfr:frameRate; + bitRate = hfr ? (hfrRatio*bitRate) : bitRate; + newFrameRate = frameRate / hfrRatio; +} + +void QCUtilityClass::helper_OMXCodec_hfr(const sp<MetaData> &inputFormat, + sp<MetaData> &outputFormat) { + int32_t frameRate = 0, hfr = 0; + inputFormat->findInt32(kKeyHFR, &hfr); + inputFormat->findInt32(kKeyFrameRate, &frameRate); + outputFormat->setInt32(kKeyHFR, hfr); + outputFormat->setInt32(kKeyFrameRate, frameRate); +} + +//-- END :: HFR related changes ----- + + +//-- START :: AUDIO disable and change in profile base on property ----- + +bool QCUtilityClass::helper_Awesomeplayer_checkIfAudioDisable() { + bool retVal = false; + char disableAudio[PROPERTY_VALUE_MAX]; + property_get("persist.debug.sf.noaudio", disableAudio, "0"); + if (atoi(disableAudio) == 1) { + retVal = true; + } + return retVal; +} + +bool QCUtilityClass::helper_StagefrightRecoder_checkIfAudioDisable() { + bool retVal = false; + char disableAudio[PROPERTY_VALUE_MAX]; + property_get("camcorder.debug.disableaudio", disableAudio, "0"); + if (atoi(disableAudio) == 1) { + retVal = true; + } + return retVal; +} + +void QCUtilityClass::helper_StagefrightRecoder_setUserprofile(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; + } +} + +void QCUtilityClass::helper_OMXCodec_setBFrames(OMX_VIDEO_PARAM_MPEG4TYPE &mpeg4type, + bool &numBFrames) { + if (mpeg4type.eProfile > OMX_VIDEO_MPEG4ProfileSimple) { + mpeg4type.nAllowedPictureTypes |= OMX_VIDEO_PictureTypeB; + mpeg4type.nBFrames = 1; + mpeg4type.nPFrames /= (mpeg4type.nBFrames + 1); + numBFrames = mpeg4type.nBFrames; + } + return; +} + +void QCUtilityClass::helper_OMXCodec_setBFrames(OMX_VIDEO_PARAM_AVCTYPE &h264type, + bool &numBFrames, + int32_t iFramesInterval, + int32_t frameRate) { + 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); + numBFrames = h264type.nBFrames; + } + return; +} +//-- END :: AUDIO disable and change in profile base on property ----- +void QCUtilityClass::helper_addMediaCodec(Vector<MediaCodecList::CodecInfo> &mCodecInfos, + KeyedVector<AString, size_t> &mTypes, + bool encoder, const char *name, + const char *type, uint32_t quirks) { + mCodecInfos.push(); + MediaCodecList::CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1); + info->mName = name; + info->mIsEncoder = encoder; + ssize_t index = mTypes.indexOfKey(type); + uint32_t bit = mTypes.valueAt(index); + info->mTypes |= 1ul << bit; + info->mQuirks = quirks; +} + +uint32_t QCUtilityClass::helper_getCodecSpecificQuirks(KeyedVector<AString, size_t> &mCodecQuirks, + Vector<AString> quirks) { + size_t i = 0, numQuirks = quirks.size(); + uint32_t bit = 0, value = 0; + for (i = 0; i < numQuirks; i++) + { + ssize_t index = mCodecQuirks.indexOfKey(quirks.itemAt(i)); + bit = mCodecQuirks.valueAt(index); + value |= 1ul << bit; + } + return value; +} + +//- 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 that defaultExt will be deleted in this function if the new parser is taken +sp<MediaExtractor> QCUtilityClass::helper_MediaExtractor_CreateIfNeeded(sp<MediaExtractor> defaultExt, + const sp<DataSource> &source, + const char *mime) { + bool bCheckExtendedExtractor = false; + bool videoOnly = true; + bool amrwbAudio = false; + if (defaultExt != NULL) { + for (size_t i = 0; i < defaultExt->countTracks(); ++i) { + sp<MetaData> meta = defaultExt->getTrackMetaData(i); + const char *_mime; + CHECK(meta->findCString(kKeyMIMEType, &_mime)); + + String8 mime = String8(_mime); + + if (!strncasecmp(mime.string(), "audio/", 6)) { + videoOnly = false; + + amrwbAudio = !strncasecmp(mime.string(), + MEDIA_MIMETYPE_AUDIO_AMR_WB, + strlen(MEDIA_MIMETYPE_AUDIO_AMR_WB)); + if (amrwbAudio) break; + } + } + bCheckExtendedExtractor = videoOnly || amrwbAudio; + } else { + bCheckExtendedExtractor = true; + } + + if (!bCheckExtendedExtractor) { + ALOGD("extended extractor not needed, return default"); + return defaultExt; + } + + sp<MediaExtractor> retextParser; + + //Create Extended Extractor only if default extractor are not selected + ALOGD("Try creating ExtendedExtractor"); + retextParser = ExtendedExtractor::CreateExtractor(source, mime); + + if (retextParser == NULL) { + ALOGD("Couldn't create the extended extractor, return default one"); + return defaultExt; + } + + if (defaultExt == NULL) { + ALOGD("default one is NULL, return extended extractor"); + return retextParser; + } + + //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 i = 0; (i < retextParser->countTracks()); ++i) { + sp<MetaData> meta = retextParser->getTrackMetaData(i); + const char *mime; + bool success = meta->findCString(kKeyMIMEType, &mime); + if ((success == true) && !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS)) { + ALOGD("Discarding default extractor and using the extended one"); + bUseDefaultExtractor = false; + break; + } + } + + if (bUseDefaultExtractor) { + ALOGD("using default extractor inspite of having a new extractor"); + retextParser.clear(); + return defaultExt; + } else { + defaultExt.clear(); + return retextParser; + } +} + +} |