diff options
Diffstat (limited to 'media')
31 files changed, 1399 insertions, 159 deletions
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 2725b5b..087a567 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -1,7 +1,7 @@ /* ** ** Copyright 2008, The Android Open Source Project -** Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. +** Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -136,6 +136,7 @@ status_t AudioRecord::set( ALOGV("set(): sampleRate %d, channelMask %#x, frameCount %d",sampleRate, channelMask, frameCount); AutoMutex lock(mLock); + status_t status; if (mAudioRecord != 0) { return INVALID_OPERATION; @@ -185,12 +186,61 @@ status_t AudioRecord::set( return BAD_VALUE; } +#ifdef QCOM_HARDWARE + size_t inputBuffSizeInBytes = -1; + if (AudioSystem::getInputBufferSize(sampleRate, format, channelCount, &inputBuffSizeInBytes) + != NO_ERROR) { + ALOGE("AudioSystem could not query the input buffer size."); + return NO_INIT; + } + ALOGV("AudioRecord::set() inputBuffSizeInBytes = %d", inputBuffSizeInBytes ); + + if (inputBuffSizeInBytes == 0) { + ALOGE("Recording parameters are not supported: sampleRate %d, channelCount %d, format %d", + sampleRate, channelCount, format); + return BAD_VALUE; + } + + // Change for Codec type + int frameSizeInBytes = 0; + if(inputSource == AUDIO_SOURCE_VOICE_COMMUNICATION) { + if (audio_is_linear_pcm(format)) { + frameSizeInBytes = channelCount * (format == AUDIO_FORMAT_PCM_16_BIT ? sizeof(int16_t) +: sizeof(int8_t)); + } else { + frameSizeInBytes = channelCount *sizeof(int16_t); + } + } else { + if (format ==AUDIO_FORMAT_AMR_NB) { + frameSizeInBytes = channelCount * 32; // Full rate framesize + } else if (format ==AUDIO_FORMAT_EVRC) { + frameSizeInBytes = channelCount * 23; // Full rate framesize + } else if (format ==AUDIO_FORMAT_QCELP) { + frameSizeInBytes = channelCount * 35; // Full rate framesize + } else if (format ==AUDIO_FORMAT_AAC) { + frameSizeInBytes = 2048; + } else if ((format ==AUDIO_FORMAT_PCM_16_BIT) || (format ==AUDIO_FORMAT_PCM_8_BIT)) { + if (audio_is_linear_pcm(format)) { + frameSizeInBytes = channelCount * (format == AUDIO_FORMAT_PCM_16_BIT ? sizeof(int16_t) : sizeof(int8_t)); + } else { + frameSizeInBytes = sizeof(int8_t); + } + } else if(format == AUDIO_FORMAT_AMR_WB) { + frameSizeInBytes = channelCount * 61; + + } + } + // We use 2* size of input buffer for ping pong use of record buffer. + int minFrameCount = 2 * inputBuffSizeInBytes / frameSizeInBytes; +#else // validate framecount int minFrameCount = 0; - status_t status = getMinFrameCount(&minFrameCount, sampleRate, format, channelMask); + status = getMinFrameCount(&minFrameCount, sampleRate, format, channelMask); if (status != NO_ERROR) { return status; } +#endif + ALOGV("AudioRecord::set() minFrameCount = %d", minFrameCount); if (frameCount == 0) { @@ -203,6 +253,10 @@ status_t AudioRecord::set( notificationFrames = frameCount/2; } +#ifdef QCOM_HARDWARE + //update mInputSource before openRecord_l + mInputSource = inputSource; +#endif // create the IAudioRecord status = openRecord_l(sampleRate, format, channelMask, frameCount, input); @@ -233,7 +287,9 @@ status_t AudioRecord::set( mMarkerReached = false; mNewPosition = 0; mUpdatePeriod = 0; +#ifndef QCOM_HARDWARE mInputSource = inputSource; +#endif mInput = input; AudioSystem::acquireAudioSessionId(mSessionId); @@ -269,11 +325,36 @@ uint32_t AudioRecord::frameCount() const size_t AudioRecord::frameSize() const { - if (audio_is_linear_pcm(mFormat)) { - return channelCount()*audio_bytes_per_sample(mFormat); +#ifdef QCOM_HARDWARE + if(inputSource() == AUDIO_SOURCE_VOICE_COMMUNICATION) { + if (audio_is_linear_pcm(mFormat)) { + return channelCount()*audio_bytes_per_sample(mFormat); + } else { + return channelCount()*sizeof(int16_t); + } } else { - return sizeof(uint8_t); + if (format() ==AUDIO_FORMAT_AMR_NB) { + return channelCount() * 32; // Full rate framesize + } else if (format() == AUDIO_FORMAT_EVRC) { + return channelCount() * 23; // Full rate framesize + } else if (format() == AUDIO_FORMAT_QCELP) { + return channelCount() * 35; // Full rate framesize + } else if (format() == AUDIO_FORMAT_AAC) { + // Not actual framsize but for variable frame rate AAC encoding, + // buffer size is treated as a frame size + return 2048; + } else if(format() == AUDIO_FORMAT_AMR_WB) { + return channelCount() * 61; + } +#endif + if (audio_is_linear_pcm(mFormat)) { + return channelCount()*audio_bytes_per_sample(mFormat); + } else { + return sizeof(uint8_t); + } +#ifdef QCOM_HARDWARE } +#endif } audio_source_t AudioRecord::inputSource() const @@ -453,7 +534,7 @@ status_t AudioRecord::openRecord_l( sampleRate, format, channelMask, frameCount, - IAudioFlinger::TRACK_DEFAULT, + (int16_t)inputSource(), tid, &mSessionId, &status); diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index a2f4348..1025799 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -69,25 +69,31 @@ status_t AudioTrack::getMinFrameCount( // audio_format_t format // audio_channel_mask_t channelMask // audio_output_flags_t flags - int afSampleRate; + int afSampleRate = 0; if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) { return NO_INIT; } - int afFrameCount; + int afFrameCount = 0; if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) { return NO_INIT; } - uint32_t afLatency; + uint32_t afLatency = 0; if (AudioSystem::getOutputLatency(&afLatency, streamType) != NO_ERROR) { return NO_INIT; } + if(!afSampleRate || !afFrameCount) { + ALOGW("samplerate or framecount 0"); + return NO_INIT; + } + // Ensure that buffer depth covers at least audio hardware latency uint32_t minBufCount = afLatency / ((1000 * afFrameCount) / afSampleRate); if (minBufCount < 2) minBufCount = 2; *frameCount = (sampleRate == 0) ? afFrameCount * minBufCount : - afFrameCount * minBufCount * sampleRate / afSampleRate; + afFrameCount * minBufCount * sampleRate / afSampleRate; + ALOGV("getMinFrameCount=%d: afFrameCount=%d, minBufCount=%d, afSampleRate=%d, afLatency=%d", *frameCount, afFrameCount, minBufCount, afSampleRate, afLatency); return NO_ERROR; @@ -455,11 +461,23 @@ uint32_t AudioTrack::frameCount() const size_t AudioTrack::frameSize() const { - if (audio_is_linear_pcm(mFormat)) { - return channelCount()*audio_bytes_per_sample(mFormat); +#ifdef QCOM_HARDWARE + if ((audio_stream_type_t)mStreamType == AUDIO_STREAM_VOICE_CALL) { + if (audio_is_linear_pcm(mFormat)) { + return channelCount()*audio_bytes_per_sample(mFormat); + } else { + return channelCount()*sizeof(int16_t); + } } else { - return sizeof(uint8_t); +#endif + if (audio_is_linear_pcm(mFormat)) { + return channelCount()*audio_bytes_per_sample(mFormat); + } else { + return sizeof(uint8_t); + } +#ifdef QCOM_HARDWARE } +#endif } sp<IMemory>& AudioTrack::sharedBuffer() @@ -980,20 +998,26 @@ status_t AudioTrack::createTrack_l( } else if (!(flags & AUDIO_OUTPUT_FLAG_FAST)) { // FIXME move these calculations and associated checks to server - int afSampleRate; + int afSampleRate = 0; if (AudioSystem::getSamplingRate(output, streamType, &afSampleRate) != NO_ERROR) { return NO_INIT; } - int afFrameCount; + int afFrameCount = 0; if (AudioSystem::getFrameCount(output, streamType, &afFrameCount) != NO_ERROR) { return NO_INIT; } + if(!afSampleRate && !afFrameCount) { + ALOGW("samplerate or framecount zero"); + return NO_INIT; + } + // Ensure that buffer depth covers at least audio hardware latency uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate); if (minBufCount < 2) minBufCount = 2; - int minFrameCount = (afFrameCount*sampleRate*minBufCount)/afSampleRate; + uint32_t minFrameCount = (afFrameCount*sampleRate*minBufCount)/afSampleRate; + ALOGV("minFrameCount: %d, afFrameCount=%d, minBufCount=%d, sampleRate=%d, afSampleRate=%d" ", afLatency=%d", minFrameCount, afFrameCount, minBufCount, sampleRate, afSampleRate, afLatency); @@ -1088,7 +1112,10 @@ status_t AudioTrack::createTrack_l( mCblk->waitTimeMs = 0; mRemainingFrames = mNotificationFramesAct; // FIXME don't believe this lie - mLatency = afLatency + (1000*mCblk->frameCount) / sampleRate; + if(sampleRate) + mLatency = afLatency + (1000*mCblk->frameCount) / sampleRate; + else + mLatency = afLatency; // If IAudioTrack is re-created, don't let the requested frameCount // decrease. This can confuse clients that cache frameCount(). if (mCblk->frameCount > mFrameCount) { diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp index fa536a6..e1299c2 100644..100755 --- a/media/libmedia/MediaProfiles.cpp +++ b/media/libmedia/MediaProfiles.cpp @@ -87,31 +87,35 @@ const MediaProfiles::NameToTagMap MediaProfiles::sCamcorderQualityNameMap[] = { {"timelapse720p", CAMCORDER_QUALITY_TIME_LAPSE_720P}, {"timelapse1080p", CAMCORDER_QUALITY_TIME_LAPSE_1080P}, {"timelapseqvga", CAMCORDER_QUALITY_TIME_LAPSE_QVGA}, + {"timelapsevga", CAMCORDER_QUALITY_TIME_LAPSE_VGA}, + {"timelapsewvga", CAMCORDER_QUALITY_TIME_LAPSE_WVGA}, + {"timelapsefwvga", CAMCORDER_QUALITY_TIME_LAPSE_FWVGA}, + {"timelapsewqvga", CAMCORDER_QUALITY_TIME_LAPSE_WQVGA}, }; /*static*/ void MediaProfiles::logVideoCodec(const MediaProfiles::VideoCodec& codec) { - ALOGV("video codec:"); - ALOGV("codec = %d", codec.mCodec); - ALOGV("bit rate: %d", codec.mBitRate); - ALOGV("frame width: %d", codec.mFrameWidth); - ALOGV("frame height: %d", codec.mFrameHeight); - ALOGV("frame rate: %d", codec.mFrameRate); +ALOGV("video codec:"); +ALOGV("codec = %d", codec.mCodec); +ALOGV("bit rate: %d", codec.mBitRate); +ALOGV("frame width: %d", codec.mFrameWidth); +ALOGV("frame height: %d", codec.mFrameHeight); +ALOGV("frame rate: %d", codec.mFrameRate); } /*static*/ void MediaProfiles::logAudioCodec(const MediaProfiles::AudioCodec& codec) { - ALOGV("audio codec:"); - ALOGV("codec = %d", codec.mCodec); - ALOGV("bit rate: %d", codec.mBitRate); - ALOGV("sample rate: %d", codec.mSampleRate); - ALOGV("number of channels: %d", codec.mChannels); +ALOGV("audio codec:"); +ALOGV("codec = %d", codec.mCodec); +ALOGV("bit rate: %d", codec.mBitRate); +ALOGV("sample rate: %d", codec.mSampleRate); +ALOGV("number of channels: %d", codec.mChannels); } /*static*/ void -MediaProfiles::logVideoEncoderCap(const MediaProfiles::VideoEncoderCap& cap) + MediaProfiles::logVideoEncoderCap(const MediaProfiles::VideoEncoderCap& cap) { ALOGV("video encoder cap:"); ALOGV("codec = %d", cap.mCodec); diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk index 1cc21d6..d978e90 100644 --- a/media/libmediaplayerservice/Android.mk +++ b/media/libmediaplayerservice/Android.mk @@ -41,10 +41,12 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_STATIC_LIBRARIES := \ libstagefright_nuplayer \ libstagefright_rtsp \ + libmedia_helper \ LOCAL_C_INCLUDES := \ $(call include-path-for, graphics corecg) \ $(TOP)/frameworks/av/media/libstagefright/include \ + $(TOP)/frameworks/av/include/media \ $(TOP)/frameworks/av/media/libstagefright/rtsp \ $(TOP)/frameworks/av/media/libstagefright/wifi-display \ $(TOP)/frameworks/native/include/media/openmax \ diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h index 972de37..d41c3b5 100644 --- a/media/libmediaplayerservice/MediaPlayerService.h +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -1,9 +1,9 @@ /* ** -** Copyright 2008, The Android Open Source Project ** Copyright (c) 2013, The Linux Foundation. All rights reserved. -** Not a Contribution, Apache license notifications and license are retained -** for attribution purposes only. +** Not a Contribution. +** +** Copyright (C) 2008 The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index 5e8d435..4d25277 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -21,7 +21,7 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "StagefrightRecorder" #include <utils/Log.h> - +#include <media/AudioParameter.h> #include "StagefrightRecorder.h" #include <binder/IPCThreadState.h> @@ -33,13 +33,6 @@ #include <media/stagefright/AudioSource.h> #include <media/stagefright/AMRWriter.h> #include <media/stagefright/AACWriter.h> -#ifdef QCOM_HARDWARE -#include <media/stagefright/ExtendedWriter.h> -#include <media/stagefright/WAVEWriter.h> -#endif -#ifdef QCOM_FM_ENABLED -#include <media/stagefright/FMA2DPWriter.h> -#endif #include <media/stagefright/CameraSource.h> #include <media/stagefright/CameraSourceTimeLapse.h> #include <media/stagefright/MPEG2TSWriter.h> @@ -53,18 +46,26 @@ #include <camera/ICamera.h> #include <camera/CameraParameters.h> #include <gui/Surface.h> +#include <utils/String8.h> #include <utils/Errors.h> #include <sys/types.h> #include <ctype.h> #include <unistd.h> -#include <system/audio.h> #ifdef QCOM_HARDWARE +#include <media/stagefright/ExtendedWriter.h> +#include <media/stagefright/WAVEWriter.h> #include <QCMediaDefs.h> #include <cutils/properties.h> +#include <QCUtilityClass.h> +#endif +#ifdef QCOM_FM_ENABLED +#include <media/stagefright/FMA2DPWriter.h> #endif +#include <system/audio.h> + #include "ARTPWriter.h" namespace android { @@ -117,6 +118,12 @@ status_t StagefrightRecorder::setAudioSource(audio_source_t as) { return BAD_VALUE; } +#ifdef QCOM_HARDWARE + if(QCUtilityClass::helper_StagefrightRecoder_checkIfAudioDisable()) { + return OK; + } +#endif + if (as == AUDIO_SOURCE_DEFAULT) { mAudioSource = AUDIO_SOURCE_MIC; } else { @@ -168,6 +175,12 @@ status_t StagefrightRecorder::setAudioEncoder(audio_encoder ae) { return BAD_VALUE; } +#ifdef QCOM_HARDWARE + if(QCUtilityClass::helper_StagefrightRecoder_checkIfAudioDisable()) { + return OK; + } +#endif + if (ae == AUDIO_ENCODER_DEFAULT) { mAudioEncoder = AUDIO_ENCODER_AMR_NB; } else { @@ -187,7 +200,7 @@ status_t StagefrightRecorder::setAudioEncoder(audio_encoder ae) { } else if(mAudioEncoder == AUDIO_ENCODER_AMR_WB) { mSampleRate = 16000; mAudioChannels = 1; - mAudioBitRate = 23850; + mAudioBitRate = mAudioBitRate ? mAudioBitRate : 23850; } else { mSampleRate = mSampleRate ? mSampleRate : 8000; mAudioChannels = mAudioChannels ? mAudioChannels : 1; @@ -856,6 +869,47 @@ status_t StagefrightRecorder::start() { } sp<MediaSource> StagefrightRecorder::createAudioSource() { +#ifdef QCOM_ENHANCED_AUDIO + bool tunneledSource = false; + const char *tunnelMime; + { + AudioParameter param; + String8 key("tunneled-input-formats"); + param.add( key, String8("get") ); + String8 valueStr = AudioSystem::getParameters( 0, param.toString()); + AudioParameter result(valueStr); + int value; + if ( mAudioEncoder == AUDIO_ENCODER_AMR_NB && + result.getInt(String8("AMR"),value) == NO_ERROR ) { + tunneledSource = true; + tunnelMime = MEDIA_MIMETYPE_AUDIO_AMR_NB; + } + else if ( mAudioEncoder == AUDIO_ENCODER_QCELP && + result.getInt(String8("QCELP"),value) == NO_ERROR ) { + tunneledSource = true; + tunnelMime = MEDIA_MIMETYPE_AUDIO_QCELP; + } + else if ( mAudioEncoder == AUDIO_ENCODER_EVRC && + result.getInt(String8("EVRC"),value) == NO_ERROR ) { + tunneledSource = true; + tunnelMime = MEDIA_MIMETYPE_AUDIO_EVRC; + } + } + + if ( tunneledSource ) { + sp<AudioSource> audioSource = NULL; + sp<MetaData> meta = new MetaData; + meta->setInt32(kKeyChannelCount, mAudioChannels); + meta->setInt32(kKeySampleRate, mSampleRate); + meta->setInt32(kKeyBitRate, mAudioBitRate); + if (mAudioTimeScale > 0) { + meta->setInt32(kKeyTimeScale, mAudioTimeScale); + } + meta->setCString( kKeyMIMEType, tunnelMime ); + audioSource = new AudioSource( mAudioSource, meta); + return audioSource->initCheck( ) == OK ? audioSource : NULL; + } +#endif sp<AudioSource> audioSource = new AudioSource( mAudioSource, @@ -1550,6 +1604,19 @@ status_t StagefrightRecorder::setupVideoEncoder( if (mVideoTimeScale > 0) { enc_meta->setInt32(kKeyTimeScale, mVideoTimeScale); } + +#ifdef QCOM_HARDWARE + status_t retVal = + QCUtilityClass::helper_StageFrightRecoder_hfr(meta,enc_meta, mMaxFileDurationUs, + mFrameRate, mVideoEncoder); + if(retVal != OK) { + return retVal; + } + + QCUtilityClass::helper_StagefrightRecoder_setUserprofile(mVideoEncoder, + mVideoEncoderProfile); +#endif + if (mVideoEncoderProfile != -1) { enc_meta->setInt32(kKeyVideoProfile, mVideoEncoderProfile); } diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index ddf95dc..a9e344d 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -32,6 +32,16 @@ #include <media/stagefright/OMXClient.h> #include <media/stagefright/OMXCodec.h> +#include <media/stagefright/MetaData.h> + +#ifdef QCOM_ENHANCED_AUDIO +#include <QCMediaDefs.h> +#include <QCMetaData.h> +#include <QOMX_AudioExtensions.h> +#include <OMX_QCOMExtns.h> +#include "include/QCUtilityClass.h" +#endif + #include <media/hardware/HardwareAPI.h> #include <OMX_Component.h> @@ -925,6 +935,100 @@ status_t ACodec::configureCodec( mIsEncoder = encoder; +#ifdef QCOM_ENHANCED_AUDIO + if (!strcasecmp(mime, "audio/x-ms-wma")) { + if (mIsEncoder) { + ALOGE("WMA encoding not supported"); + return ERROR_UNSUPPORTED; + } else { + int32_t version; + OMX_AUDIO_PARAM_WMATYPE paramWMA; + QOMX_AUDIO_PARAM_WMA10PROTYPE paramWMA10; + CHECK(msg->findInt32("WMA-Version", &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("bsps", &bitspersample)); + CHECK(msg->findInt32("fmtt", &formattag)); + CHECK(msg->findInt32("ade1",&advencopt1)); + CHECK(msg->findInt32("ade2",&advencopt2)); + CHECK(msg->findInt32("vpks",&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("brte", &bitRate)); + CHECK(msg->findInt32("eopt", &encodeOptions)); + CHECK(msg->findInt32("blka", &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 = mOMX->getParameter( + mNode,OMX_IndexParamAudioWma, ¶mWMA, sizeof(paramWMA)); + } else if(version==kTypeWMAPro || version==kTypeWMALossLess) { + mOMX->getExtensionIndex(mNode,"OMX.Qualcomm.index.audio.wma10Pro",&index); + err = mOMX->getParameter( + mNode, 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; + err = mOMX->setParameter( + mNode, OMX_IndexParamAudioWma, ¶mWMA, sizeof(paramWMA)); + } else if(version==kTypeWMAPro || version==kTypeWMALossLess) { + paramWMA10.nChannels = numChannels; + paramWMA10.nSamplingRate = sampleRate; + paramWMA10.nEncodeOptions = encodeOptions; + paramWMA10.nBitRate = bitRate; + paramWMA10.nBlockAlign = blockAlign; + paramWMA10.advancedEncodeOpt = advencopt1; + paramWMA10.advancedEncodeOpt2 = advencopt2; + paramWMA10.formatTag = formattag; + paramWMA10.validBitsPerSample = bitspersample; + paramWMA10.nVirtualPktSize = VirtualPktSize; + err = mOMX->setParameter( + mNode, index, ¶mWMA10, sizeof(paramWMA10)); + } + CHECK_EQ(err, (status_t)OK); + int32_t maxInputSize1; + if (msg->findInt32("max-input-size", &maxInputSize1)) { + setMinBufferSize(kPortIndexInput, (size_t)maxInputSize1); + } + return err; + } + } +#endif + status_t err = setComponentRole(encoder /* isEncoder */, mime); if (err != OK) { @@ -1482,7 +1586,8 @@ status_t ACodec::setSupportedOutputFormat() { || format.eColorFormat == OMX_COLOR_FormatCbYCrY || format.eColorFormat == OMX_TI_COLOR_FormatYUV420PackedSemiPlanar || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar - || format.eColorFormat == OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka); + || format.eColorFormat == OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka + || format.eColorFormat == OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar32m ); return mOMX->setParameter( mNode, OMX_IndexParamVideoPortFormat, @@ -3146,9 +3251,33 @@ bool ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) { Vector<OMXCodec::CodecNameAndQuirks> matchingCodecs; AString mime; + uint32_t quirks = 0; +#ifdef QCOM_ENHANCED_AUDIO + msg->findString("mime", &mime); + + if(!(strcmp(mime.c_str(),"audio/x-ms-wma"))){ + mCodec->mQuirks = quirks; + mCodec->mOMX = omx; + + mCodec->mPortEOS[kPortIndexInput] = + mCodec->mPortEOS[kPortIndexOutput] = false; + + mCodec->mInputEOSResult = OK; + + { + sp<AMessage> notify = mCodec->mNotify->dup(); + notify->setInt32("what", ACodec::kWhatComponentAllocated); + notify->setString("componentName", mCodec->mComponentName.c_str()); + notify->post(); + } + + mCodec->changeState(mCodec->mLoadedState); + + return true; + } +#endif AString componentName; - uint32_t quirks = 0; if (msg->findString("componentName", &componentName)) { ssize_t index = matchingCodecs.add(); OMXCodec::CodecNameAndQuirks *entry = &matchingCodecs.editItemAt(index); @@ -3173,7 +3302,6 @@ bool ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) { 0, // flags &matchingCodecs); } - sp<CodecObserver> observer = new CodecObserver; IOMX::node_id node = NULL; @@ -3327,11 +3455,93 @@ bool ACodec::LoadedState::onConfigureComponent( const sp<AMessage> &msg) { ALOGV("onConfigureComponent"); - CHECK(mCodec->mNode != NULL); - AString mime; CHECK(msg->findString("mime", &mime)); +#ifdef QCOM_ENHANCED_AUDIO + if (!strcasecmp(mime.c_str(), "audio/x-ms-wma")){ + OMXClient client; + CHECK_EQ(client.connect(), (status_t)OK); + sp<IOMX> omx = client.interface(); + Vector<OMXCodec::CodecNameAndQuirks> matchingCodecs; + AString componentName; + uint32_t quirks = 0; + int32_t version = -1; + + msg->findInt32("WMA-Version", &version); + if(kTypeWMA == version){ + componentName = "OMX.qcom.audio.decoder.wma"; + } else if(kTypeWMAPro == version){ + componentName = "OMX.qcom.audio.decoder.wma10Pro"; + } else if(kTypeWMALossLess == version){ + componentName = "OMX.qcom.audio.decoder.wmaLossLess"; + } else { + mCodec->signalError(OMX_ErrorComponentNotFound); + return false; + } + + int32_t encoder; + if (!msg->findInt32("encoder", &encoder)) { + encoder = false; + } + + OMXCodec::findMatchingCodecs( + mime.c_str(), + encoder, // createEncoder + componentName.c_str(), // matchComponentName + 0, // flags + &matchingCodecs); + + sp<CodecObserver> observer = new CodecObserver; + IOMX::node_id node = NULL; + + for (size_t matchIndex = 0; matchIndex < matchingCodecs.size(); + ++matchIndex) { + componentName = matchingCodecs.itemAt(matchIndex).mName.string(); + quirks = matchingCodecs.itemAt(matchIndex).mQuirks; + + pid_t tid = androidGetTid(); + int prevPriority = androidGetThreadPriority(tid); + androidSetThreadPriority(tid, ANDROID_PRIORITY_FOREGROUND); + status_t err = omx->allocateNode(componentName.c_str(), observer, &node); + androidSetThreadPriority(tid, prevPriority); + + if (err == OK) { + break; + } + node = NULL; + } + if (node == NULL) { + if (!mime.empty()) { + ALOGE("Unable to instantiate a decoder for type '%s'.", + mime.c_str()); + } else { + ALOGE("Unable to instantiate decoder '%s'.", componentName.c_str()); + } + + mCodec->signalError(OMX_ErrorComponentNotFound); + return false; + } + sp<AMessage> notify = new AMessage(kWhatOMXMessage, mCodec->id()); + observer->setNotificationMessage(notify); + + mCodec->mComponentName = componentName; + mCodec->mFlags = 0; + + if (componentName.endsWith(".secure")) { + mCodec->mFlags |= kFlagIsSecure; + } + + mCodec->mQuirks = quirks; + mCodec->mOMX = omx; + mCodec->mNode = node; + + mCodec->mPortEOS[kPortIndexInput] = + mCodec->mPortEOS[kPortIndexOutput] = false; + } +#endif + + CHECK(mCodec->mNode != NULL); status_t err = mCodec->configureCodec(mime.c_str(), msg); if (err != OK) { diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index 193291e..766cf5e 100755 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -92,7 +92,8 @@ LOCAL_SRC_FILES += \ QCMediaDefs.cpp \ QCOMXCodec.cpp \ WAVEWriter.cpp \ - ExtendedExtractor.cpp + ExtendedExtractor.cpp \ + QCUtilityClass.cpp LOCAL_C_INCLUDES += \ $(TOP)/hardware/qcom/media/mm-core/inc diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp index deb6b70..80b64c2 100644 --- a/media/libstagefright/AudioPlayer.cpp +++ b/media/libstagefright/AudioPlayer.cpp @@ -500,11 +500,11 @@ size_t AudioPlayer::fillBuffer(void *data, size_t size) { { Mutex::Autolock autoLock(mLock); mNumFramesPlayed += size_done / mFrameSize; - mNumFramesPlayedSysTimeUs = ALooper::GetNowUs(); if (mReachedEOS) { mPinnedTimeUs = mNumFramesPlayedSysTimeUs; } else { + mNumFramesPlayedSysTimeUs = ALooper::GetNowUs(); mPinnedTimeUs = -1ll; } } @@ -535,14 +535,21 @@ int64_t AudioPlayer::getRealTimeUsLocked() const { // compensate using system time. int64_t diffUs; if (mPinnedTimeUs >= 0ll) { - diffUs = mPinnedTimeUs; + if(mReachedEOS) + diffUs = ALooper::GetNowUs(); + else + diffUs = mPinnedTimeUs; + } else { diffUs = ALooper::GetNowUs(); } diffUs -= mNumFramesPlayedSysTimeUs; - return result + diffUs; + if(result + diffUs <= mPositionTimeRealUs) + return result + diffUs; + else + return mPositionTimeRealUs; } int64_t AudioPlayer::getMediaTimeUs() { diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp index bb2d415..2bb721c 100644 --- a/media/libstagefright/AudioSource.cpp +++ b/media/libstagefright/AudioSource.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2010 The Android Open Source Project - * Copyright (c) 2012, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,8 +29,17 @@ #include <cutils/properties.h> #include <stdlib.h> -namespace android { +#ifdef QCOM_ENHANCED_AUDIO +#define AMR_FRAMESIZE 32 +#define QCELP_FRAMESIZE 35 +#define EVRC_FRAMESIZE 23 +#define AMR_WB_FRAMESIZE 61 +#endif +namespace android { +// Treat time out as an error if we have not received any output +// buffers after 1 seconds +const static int64_t WaitLockEventTimeOutNs = 1000000000LL; static void AudioRecordCallbackFunction(int event, void *user, void *info) { AudioSource *source = (AudioSource *) user; switch (event) { @@ -55,7 +64,13 @@ AudioSource::AudioSource( mSampleRate(sampleRate), mPrevSampleTimeUs(0), mNumFramesReceived(0), - mNumClientOwnedBuffers(0) { + mNumClientOwnedBuffers(0) +#ifdef QCOM_ENHANCED_AUDIO + ,mFormat(AUDIO_FORMAT_PCM_16_BIT), + mMime(MEDIA_MIMETYPE_AUDIO_RAW) +#endif +{ + ALOGV("sampleRate: %d, channelCount: %d", sampleRate, channelCount); CHECK(channelCount == 1 || channelCount == 2 || channelCount == 6); @@ -64,10 +79,23 @@ AudioSource::AudioSource( sampleRate, AUDIO_FORMAT_PCM_16_BIT, audio_channel_in_mask_from_count(channelCount)); + +#ifdef QCOM_ENHANCED_AUDIO + if ( NO_ERROR != AudioSystem::getInputBufferSize( + sampleRate, mFormat, channelCount, (size_t*)&mMaxBufferSize) ) { + mMaxBufferSize = kMaxBufferSize; + ALOGV("mMaxBufferSize = %d", mMaxBufferSize); + } +#endif + if (status == OK) { // make sure that the AudioRecord callback never returns more than the maximum // buffer size +#ifdef QCOM_ENHANCED_AUDIO + int frameCount = mMaxBufferSize / sizeof(int16_t) / channelCount; +#else int frameCount = kMaxBufferSize / sizeof(int16_t) / channelCount; +#endif // make sure that the AudioRecord total buffer size is large enough int bufCount = 2; @@ -78,7 +106,11 @@ AudioSource::AudioSource( mRecord = new AudioRecord( inputSource, sampleRate, AUDIO_FORMAT_PCM_16_BIT, audio_channel_in_mask_from_count(channelCount), +#ifdef QCOM_ENHANCED_AUDIO + 4 * mMaxBufferSize / sizeof(int16_t), /* Enable ping-pong buffers */ +#else bufCount * frameCount, +#endif AudioRecordCallbackFunction, this, frameCount); @@ -99,6 +131,62 @@ AudioSource::AudioSource( } } +#ifdef QCOM_ENHANCED_AUDIO +AudioSource::AudioSource( audio_source_t inputSource, const sp<MetaData>& meta ) + : mStarted(false), + mPrevSampleTimeUs(0), + mNumFramesReceived(0), + mNumClientOwnedBuffers(0), + mFormat(AUDIO_FORMAT_PCM_16_BIT), + mMime(MEDIA_MIMETYPE_AUDIO_RAW) { + + const char * mime; + ALOGE("SK: in AudioSource : inputSource: %d", inputSource); + CHECK( meta->findCString( kKeyMIMEType, &mime ) ); + mMime = mime; + int32_t sampleRate = 0; //these are the only supported values + int32_t channels = 0; //for the below tunnel formats + CHECK( meta->findInt32( kKeyChannelCount, &channels ) ); + CHECK( meta->findInt32( kKeySampleRate, &sampleRate ) ); + int32_t frameSize = -1; + mSampleRate = sampleRate; + if ( !strcasecmp( mime, MEDIA_MIMETYPE_AUDIO_AMR_NB ) ) { + mFormat = AUDIO_FORMAT_AMR_NB; + frameSize = AMR_FRAMESIZE; + mMaxBufferSize = AMR_FRAMESIZE*10; + } + else if ( !strcasecmp( mime, MEDIA_MIMETYPE_AUDIO_QCELP ) ) { + mFormat = AUDIO_FORMAT_QCELP; + frameSize = QCELP_FRAMESIZE; + mMaxBufferSize = QCELP_FRAMESIZE*10; + } + else if ( !strcasecmp( mime, MEDIA_MIMETYPE_AUDIO_EVRC ) ) { + mFormat = AUDIO_FORMAT_EVRC; + frameSize = EVRC_FRAMESIZE; + mMaxBufferSize = EVRC_FRAMESIZE*10; + } + else if ( !strcasecmp( mime, MEDIA_MIMETYPE_AUDIO_AMR_WB ) ) { + mFormat = AUDIO_FORMAT_AMR_WB; + frameSize = AMR_WB_FRAMESIZE; + mMaxBufferSize = AMR_WB_FRAMESIZE*10; + } + else { + CHECK(0); + } + mAutoRampStartUs = 0; + CHECK(channels == 1 || channels == 2); + + mRecord = new AudioRecord( + inputSource, sampleRate, mFormat, + channels > 1? AUDIO_CHANNEL_IN_STEREO: + AUDIO_CHANNEL_IN_MONO, + 4*mMaxBufferSize/channels/frameSize, + AudioRecordCallbackFunction, + this); + mInitCheck = mRecord->initCheck(); +} +#endif + AudioSource::~AudioSource() { if (mStarted) { reset(); @@ -184,10 +272,17 @@ sp<MetaData> AudioSource::getFormat() { } sp<MetaData> meta = new MetaData; +#ifdef QCOM_ENHANCED_AUDIO + meta->setCString(kKeyMIMEType, mMime); + meta->setInt32(kKeySampleRate, mRecord->getSampleRate()); + meta->setInt32(kKeyChannelCount, mRecord->channelCount()); + meta->setInt32(kKeyMaxInputSize, mMaxBufferSize); +#else meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW); meta->setInt32(kKeySampleRate, mSampleRate); meta->setInt32(kKeyChannelCount, mRecord->channelCount()); meta->setInt32(kKeyMaxInputSize, kMaxBufferSize); +#endif return meta; } @@ -234,7 +329,9 @@ status_t AudioSource::read( } while (mStarted && mBuffersReceived.empty()) { - mFrameAvailableCondition.wait(mLock); + status_t err = mFrameAvailableCondition.waitRelative(mLock,WaitLockEventTimeOutNs); + if(err == -ETIMEDOUT) + return (status_t)err; } if (!mStarted) { return OK; @@ -249,24 +346,33 @@ status_t AudioSource::read( int64_t timeUs; CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs)); int64_t elapsedTimeUs = timeUs - mStartTimeUs; - if (elapsedTimeUs < mAutoRampStartUs) { - memset((uint8_t *) buffer->data(), 0, buffer->range_length()); - } else if (elapsedTimeUs < mAutoRampStartUs + kAutoRampDurationUs) { - int32_t autoRampDurationFrames = - (kAutoRampDurationUs * mSampleRate + 500000LL) / 1000000LL; - - int32_t autoRampStartFrames = - (mAutoRampStartUs * mSampleRate + 500000LL) / 1000000LL; - - int32_t nFrames = mNumFramesReceived - autoRampStartFrames; - rampVolume(nFrames, autoRampDurationFrames, - (uint8_t *) buffer->data(), buffer->range_length()); +#ifdef QCOM_ENHANCED_AUDIO + if ( mFormat == AUDIO_FORMAT_PCM_16_BIT ) { +#endif + if (elapsedTimeUs < mAutoRampStartUs) { + memset((uint8_t *) buffer->data(), 0, buffer->range_length()); + } else if (elapsedTimeUs < mAutoRampStartUs + kAutoRampDurationUs) { + int32_t autoRampDurationFrames = + (kAutoRampDurationUs * mSampleRate + 500000LL) / 1000000LL; + + int32_t autoRampStartFrames = + (mAutoRampStartUs * mSampleRate + 500000LL) / 1000000LL; + + int32_t nFrames = mNumFramesReceived - autoRampStartFrames; + rampVolume(nFrames, autoRampDurationFrames, + (uint8_t *) buffer->data(), buffer->range_length()); + } +#ifdef QCOM_ENHANCED_AUDIO } +#endif // Track the max recording signal amplitude. if (mTrackMaxAmplitude) { - trackMaxAmplitude( - (int16_t *) buffer->data(), buffer->range_length() >> 1); +#ifdef QCOM_ENHANCED_AUDIO + if (mFormat == AUDIO_FORMAT_PCM_16_BIT) +#endif + trackMaxAmplitude( + (int16_t *) buffer->data(), buffer->range_length() >> 1); } *out = buffer; @@ -321,7 +427,9 @@ status_t AudioSource::dataCallback(const AudioRecord::Buffer& audioBuffer) { } CHECK_EQ(numLostBytes & 1, 0u); +#ifndef QCOM_ENHANCED_AUDIO CHECK_EQ(audioBuffer.size & 1, 0u); +#endif if (numLostBytes > 0) { // Loss of audio frames should happen rarely; thus the LOGW should // not cause a logging spam @@ -359,19 +467,45 @@ status_t AudioSource::dataCallback(const AudioRecord::Buffer& audioBuffer) { void AudioSource::queueInputBuffer_l(MediaBuffer *buffer, int64_t timeUs) { const size_t bufferSize = buffer->range_length(); const size_t frameSize = mRecord->frameSize(); +#ifdef QCOM_ENHANCED_AUDIO + int64_t timestampUs = mPrevSampleTimeUs; + int64_t recordDurationUs = 0; + if ( mFormat == AUDIO_FORMAT_PCM_16_BIT ){ + recordDurationUs = ((1000000LL * (bufferSize / (2 * mRecord->channelCount()))) + + (mSampleRate >> 1)) / mSampleRate; + } else { + recordDurationUs = bufferDurationUs(bufferSize); + } + timestampUs += recordDurationUs; +#else const int64_t timestampUs = mPrevSampleTimeUs + ((1000000LL * (bufferSize / frameSize)) + (mSampleRate >> 1)) / mSampleRate; +#endif if (mNumFramesReceived == 0) { buffer->meta_data()->setInt64(kKeyAnchorTime, mStartTimeUs); } buffer->meta_data()->setInt64(kKeyTime, mPrevSampleTimeUs); - buffer->meta_data()->setInt64(kKeyDriftTime, timeUs - mInitialReadTimeUs); +#ifdef QCOM_ENHANCED_AUDIO + if (mFormat == AUDIO_FORMAT_PCM_16_BIT) { +#endif + buffer->meta_data()->setInt64(kKeyDriftTime, timeUs - mInitialReadTimeUs); +#ifdef QCOM_ENHANCED_AUDIO + } else { + int64_t wallClockTimeUs = timeUs - mInitialReadTimeUs; + int64_t mediaTimeUs = mStartTimeUs + mPrevSampleTimeUs; + buffer->meta_data()->setInt64(kKeyDriftTime, mediaTimeUs - wallClockTimeUs); + } +#endif mPrevSampleTimeUs = timestampUs; +#ifdef QCOM_ENHANCED_AUDIO + mNumFramesReceived += buffer->range_length() / sizeof(int16_t); +#else mNumFramesReceived += bufferSize / frameSize; +#endif mBuffersReceived.push_back(buffer); mFrameAvailableCondition.signal(); } @@ -399,4 +533,27 @@ int16_t AudioSource::getMaxAmplitude() { return value; } +#ifdef QCOM_ENHANCED_AUDIO +int64_t AudioSource::bufferDurationUs( ssize_t n ) { + + int64_t dataDurationMs = 0; + if (mFormat == AUDIO_FORMAT_AMR_NB) { + dataDurationMs = (n/AMR_FRAMESIZE) * 20; //ms + } + else if (mFormat == AUDIO_FORMAT_EVRC) { + dataDurationMs = (n/EVRC_FRAMESIZE) * 20; //ms + } + else if (mFormat == AUDIO_FORMAT_QCELP) { + dataDurationMs = (n/QCELP_FRAMESIZE) * 20; //ms + } + else if (mFormat == AUDIO_FORMAT_AMR_WB) { + dataDurationMs = (n/AMR_WB_FRAMESIZE) * 20; //ms + } + + else + CHECK(0); + + return dataDurationMs*1000LL; +} +#endif } // namespace android diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index c68b476..ad221d1 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -57,6 +57,9 @@ #include <media/stagefright/MediaSource.h> #include <media/stagefright/MetaData.h> #include <media/stagefright/OMXCodec.h> +#ifdef QCOM_HARDWARE +#include "include/QCUtilityClass.h" +#endif #include <gui/ISurfaceTexture.h> #include <gui/SurfaceTextureClient.h> @@ -255,6 +258,46 @@ AwesomePlayer::~AwesomePlayer() { mClient.disconnect(); } +void AwesomePlayer::printStats() { + char value[PROPERTY_VALUE_MAX]; + property_get("persist.debug.sf.statistics", value, "0"); + if (atoi(value) && mVideoSource != NULL) { + ALOGE("===========================\n" + " videoDimensions(%d x %d)\n" + " Total Video Frames Decoded(%lld)\n" + " Total Video Frames Rendered(%lld)\n" + " Total Playback Duration(%lld ms)\n" + " numVideoFramesDropped(%lld)\n" + " Average Frames Per Second(%.4f)\n" + " Last Seek To Time(%lld ms)\n" + " Last Paused Time(%lld ms)\n" + " First Frame Latency (%lld ms)\n" + " Number of times AV Sync Lost(%u)\n" + " Max Video Ahead Time Delta(%u)\n" + " Max Video Behind Time Delta(%u)\n" + " Max Time Sync Loss(%u)\n" + " EOS(%d)\n" + " PLAYING(%d)\n" + "===========================\n\n", + mStats.mVideoWidth, + mStats.mVideoHeight, + mStats.mNumVideoFramesDecoded, + mStats.mTotalFrames, + mStats.mTotalTimeUs/1000, + mStats.mNumVideoFramesDropped, + mStats.mTotalTimeUs > 0 ? ((double)(mStats.mTotalFrames)*1E6)/((double)mStats.mTotalTimeUs) : 0, + mStats.mLastSeekToTimeMs, + mStats.mLastPausedTimeMs, + mStats.mFirstFrameLatencyUs/1000, + mStats.mNumTimesSyncLoss, + -mStats.mMaxEarlyDelta/1000, + mStats.mMaxLateDelta/1000, + mStats.mMaxTimeSyncLoss/1000, + (mFlags & VIDEO_AT_EOS) > 0, + (mFlags & PLAYING) > 0); + } +} + void AwesomePlayer::cancelPlayerEvents(bool keepNotifications) { mQueue.cancelEvent(mVideoEvent->eventID()); mVideoEventPending = false; @@ -448,7 +491,11 @@ status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) { &mStats.mTracks.editItemAt(mStats.mVideoTrackIndex); stat->mMIME = mime.string(); } - } else if (!haveAudio && !strncasecmp(mime.string(), "audio/", 6)) { + } else if (!haveAudio && +#ifdef QCOM_HARDWARE + !QCUtilityClass::helper_Awesomeplayer_checkIfAudioDisable() && +#endif + !strncasecmp(mime.string(), "audio/", 6)) { setAudioSource(extractor->getTrack(i)); haveAudio = true; mActiveAudioTrackIndex = i; @@ -573,6 +620,8 @@ void AwesomePlayer::reset_l() { mVideoRenderer.clear(); + modifyFlags(PLAYING, CLEAR); + printStats(); if (mVideoSource != NULL) { shutdownVideoDecoder_l(); } @@ -1039,7 +1088,7 @@ status_t AwesomePlayer::play_l() { // We don't want to post an error notification at this point, // the error returned from MediaPlayer::start() will suffice. bool sendErrorNotification = false; -#ifdef IS_TUNNEL_MODE +#ifdef USE_TUNNEL_MODE if(mIsTunnelAudio) { // For tunnel Audio error has to be posted to the client sendErrorNotification = true; @@ -1080,6 +1129,7 @@ status_t AwesomePlayer::play_l() { if (mAudioSource != NULL && mVideoSource != NULL) { postVideoLagEvent_l(); } + printStats(); } if (mFlags & AT_EOS) { @@ -1296,9 +1346,10 @@ status_t AwesomePlayer::pause_l(bool at_eos) { Playback::PAUSE, 0); } - if(!(mFlags & AT_EOS)){ + if(!(mFlags & VIDEO_AT_EOS)){ Mutex::Autolock autoLock(mStatsLock); mStats.mLastPausedTimeMs = mVideoTimeUs/1000; + printStats(); } uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder; @@ -1832,6 +1883,7 @@ void AwesomePlayer::finishSeekIfNecessary(int64_t videoTimeUs) { mStats.mLastSeekToTimeMs = mSeekTimeUs/1000; logFirstFrame(); } + printStats(); } void AwesomePlayer::onVideoEvent() { diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp index 9f63ec0..f7d452b 100755 --- a/media/libstagefright/CameraSource.cpp +++ b/media/libstagefright/CameraSource.cpp @@ -30,7 +30,10 @@ #include <gui/Surface.h> #include <utils/String8.h> #include <cutils/properties.h> - +#ifdef QCOM_HARDWARE +#include "include/QCUtilityClass.h" +#include <QCMetaData.h> +#endif #ifdef USE_TI_CUSTOM_DOMX #include <OMX_TI_IVCommon.h> #endif @@ -569,6 +572,11 @@ status_t CameraSource::initWithCameraAccess( mMeta->setInt32(kKeyStride, mVideoSize.width); mMeta->setInt32(kKeySliceHeight, mVideoSize.height); mMeta->setInt32(kKeyFrameRate, mVideoFrameRate); + +#ifdef QCOM_HARDWARE + QCUtilityClass::helper_CameraSource_hfr(params, mMeta); +#endif + return OK; } diff --git a/media/libstagefright/LPAPlayerALSA.cpp b/media/libstagefright/LPAPlayerALSA.cpp index 0aa419c..e2f30ed 100644 --- a/media/libstagefright/LPAPlayerALSA.cpp +++ b/media/libstagefright/LPAPlayerALSA.cpp @@ -51,10 +51,9 @@ static const char mName[] = "LPAPlayer"; -#define MEM_PADDING 64 -#define MEM_BUFFER_SIZE (256*1024) +#define MEM_METADATA_SIZE 64 +#define MEM_BUFFER_SIZE ((256*1024) - MEM_METADATA_SIZE) #define MEM_BUFFER_COUNT 4 - #define PCM_FORMAT 2 #define NUM_FDS 2 #define LPA_BUFFER_TIME 1500000 diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index 6d1f8c6..04b508b 100755 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -40,6 +40,10 @@ #include "include/ESDS.h" +#ifdef QCOM_HARDWARE +#include "include/QCUtilityClass.h" +#endif + namespace android { static const int64_t kMinStreamableFileSizeInBytes = 5 * 1024 * 1024; @@ -2161,6 +2165,12 @@ status_t MPEG4Writer::Track::threadEntry() { meta_data->findInt32(kKeyIsSyncFrame, &isSync); CHECK(meta_data->findInt64(kKeyTime, ×tampUs)); +#ifdef QCOM_HARDWARE + if(!mIsAudio) { + QCUtilityClass::helper_MPEG4Writer_hfr(mMeta, timestampUs); + } +#endif + //////////////////////////////////////////////////////////////////////////////// if (mStszTableEntries->count() == 0) { mFirstSampleTimeRealUs = systemTime() / 1000; @@ -2190,6 +2200,10 @@ status_t MPEG4Writer::Track::threadEntry() { */ int64_t decodingTimeUs; CHECK(meta_data->findInt64(kKeyDecodingTime, &decodingTimeUs)); +#ifdef QCOM_HARDWARE + QCUtilityClass::helper_MPEG4Writer_hfr(mMeta, decodingTimeUs); +#endif + decodingTimeUs -= previousPausedDurationUs; cttsOffsetTimeUs = timestampUs + kMaxCttsOffsetTimeUs - decodingTimeUs; diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp index d24337f..f815ec9 100644 --- a/media/libstagefright/MediaCodecList.cpp +++ b/media/libstagefright/MediaCodecList.cpp @@ -28,6 +28,10 @@ #include <libexpat/expat.h> +#ifdef QCOM_HARDWARE +#include "include/QCUtilityClass.h" +#endif + namespace android { static Mutex sInitMutex; @@ -64,6 +68,14 @@ MediaCodecList::MediaCodecList() addMediaCodec( false /* encoder */, "OMX.google.raw.decoder", "audio/raw"); + +#ifdef QCOM_HARDWARE + Vector<AString> QcomAACQuirks; + QcomAACQuirks.push(AString("requires-allocate-on-input-ports")); + QcomAACQuirks.push(AString("requires-allocate-on-output-ports")); + QCUtilityClass::helper_addMediaCodec(mCodecInfos, mTypes, false, "OMX.qcom.audio.decoder.multiaac", + "audio/mp4a-latm", QCUtilityClass::helper_getCodecSpecificQuirks(mCodecQuirks, QcomAACQuirks)); +#endif } #if 0 diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp index 1eb5c19..33e526a 100644 --- a/media/libstagefright/MediaExtractor.cpp +++ b/media/libstagefright/MediaExtractor.cpp @@ -35,6 +35,7 @@ #include "include/AACExtractor.h" #ifdef QCOM_HARDWARE #include "include/ExtendedExtractor.h" +#include "include/QCUtilityClass.h" #endif #include "matroska/MatroskaExtractor.h" @@ -60,7 +61,6 @@ uint32_t MediaExtractor::flags() const { sp<MediaExtractor> MediaExtractor::Create( const sp<DataSource> &source, const char *mime) { sp<AMessage> meta; - bool bCheckExtendedExtractor = false; String8 tmp; if (mime == NULL) { @@ -107,9 +107,6 @@ sp<MediaExtractor> MediaExtractor::Create( } else { ret = new MPEG4Extractor(source); } -#ifdef QCOM_ENHANCED_AUDIO - bCheckExtendedExtractor = true; -#endif } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) { ret = new MP3Extractor(source, meta); } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB) @@ -147,49 +144,13 @@ sp<MediaExtractor> MediaExtractor::Create( } #ifdef QCOM_HARDWARE - //If default extractor created and flag is not set to check extended extractor, - // then pass default extractor. - if (ret && (!bCheckExtendedExtractor) ) { - ALOGD("returning default extractor"); - return ret; - } - - //Create Extended Extractor only if default extractor are not selected - ALOGV("Using ExtendedExtractor"); - sp<MediaExtractor> retextParser = ExtendedExtractor::CreateExtractor(source, mime); - //if we came here, it means we do not have to use the default extractor, if created above. - bool bUseDefaultExtractor = false; - - if(bCheckExtendedExtractor) { - ALOGV("bCheckExtendedExtractor is true"); - //bCheckExtendedExtractor is true which means default extractor was found - // but we want to give preference to extended extractor based on certain - // codec type.Set bUseDefaultExtractor to true if extended extractor - //does not return specific codec type that we are looking for. - bUseDefaultExtractor = true; - ALOGV(" bCheckExtendedExtractor is true..checking extended extractor"); - for (size_t i = 0; (retextParser!=NULL) && (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)) { - ALOGV("Discarding default extractor and using the extended one"); - //We found what we were looking for, set bUseDefaultExtractor to false; - bUseDefaultExtractor = false; - if(ret) { - //delete the default extractor as we will be using extended extractor.. - delete ret; - } - break; - } - } - } - if( (retextParser != NULL) && (!bUseDefaultExtractor) ) { - ALOGV("returning retextParser"); - return retextParser; - } -#endif + //ret will get deleted within if replaced + return QCUtilityClass::helper_MediaExtractor_CreateIfNeeded(ret, + source, + mime); +#else return ret; +#endif } } // namespace android diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index b8b3ec4..26cae65 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -52,7 +52,9 @@ #include <QCMetaData.h> #include <QOMX_AudioExtensions.h> #include <OMX_QCOMExtns.h> +#include "include/QCUtilityClass.h" #endif + #include "include/avc_utils.h" #ifdef USE_SAMSUNG_COLORFORMAT @@ -415,7 +417,14 @@ sp<MediaSource> OMXCodec::Create( CHECK(success); Vector<CodecNameAndQuirks> matchingCodecs; - findMatchingCodecs( + +#ifdef QCOM_HARDWARE + if (QCOMXCodec::useHWAACDecoder(mime)) { + findMatchingCodecs(mime, createEncoder, + "OMX.qcom.audio.decoder.multiaac", flags, &matchingCodecs); + } else +#endif + findMatchingCodecs( mime, createEncoder, matchComponentName, flags, &matchingCodecs); if (matchingCodecs.isEmpty()) { @@ -1054,6 +1063,11 @@ void OMXCodec::setVideoInputFormat( CHECK(success); CHECK(stride != 0); +#ifdef QCOM_HARDWARE + int32_t newFrameRate = frameRate; + QCUtilityClass::helper_OMXCodec_hfr(meta, frameRate, bitRate, newFrameRate); +#endif + OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused; if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { compressionFormat = OMX_VIDEO_CodingAVC; @@ -1288,7 +1302,11 @@ status_t OMXCodec::setupH263EncoderParameters(const sp<MetaData>& meta) { h263type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP; - h263type.nPFrames = setPFramesSpacing(iFramesInterval, frameRate); + int32_t newFrameRate = frameRate; +#ifdef QCOM_HARDWARE + QCUtilityClass::helper_OMXCodec_hfr(meta, frameRate, bitRate, newFrameRate); +#endif + h263type.nPFrames = setPFramesSpacing(iFramesInterval, newFrameRate); if (h263type.nPFrames == 0) { h263type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI; } @@ -1339,7 +1357,11 @@ status_t OMXCodec::setupMPEG4EncoderParameters(const sp<MetaData>& meta) { mpeg4type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP; - mpeg4type.nPFrames = setPFramesSpacing(iFramesInterval, frameRate); + int32_t newFrameRate = frameRate; +#ifdef QCOM_HARDWARE + QCUtilityClass::helper_OMXCodec_hfr(meta, frameRate, bitRate, newFrameRate); +#endif + mpeg4type.nPFrames = setPFramesSpacing(iFramesInterval, newFrameRate); if (mpeg4type.nPFrames == 0) { mpeg4type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI; } @@ -1360,6 +1382,9 @@ status_t OMXCodec::setupMPEG4EncoderParameters(const sp<MetaData>& meta) { mpeg4type.eProfile = static_cast<OMX_VIDEO_MPEG4PROFILETYPE>(profileLevel.mProfile); mpeg4type.eLevel = static_cast<OMX_VIDEO_MPEG4LEVELTYPE>(profileLevel.mLevel); +#ifdef QCOM_HARDWARE + QCUtilityClass::helper_OMXCodec_setBFrames(mpeg4type, mNumBFrames); +#endif err = mOMX->setParameter( mNode, OMX_IndexParamVideoMpeg4, &mpeg4type, sizeof(mpeg4type)); CHECK_EQ(err, (status_t)OK); @@ -1397,7 +1422,12 @@ status_t OMXCodec::setupAVCEncoderParameters(const sp<MetaData>& meta) { h264type.eProfile = static_cast<OMX_VIDEO_AVCPROFILETYPE>(profileLevel.mProfile); h264type.eLevel = static_cast<OMX_VIDEO_AVCLEVELTYPE>(profileLevel.mLevel); - // XXX + int32_t newFrameRate = frameRate; +#ifdef QCOM_HARDWARE + QCUtilityClass::helper_OMXCodec_hfr(meta, frameRate, bitRate, newFrameRate); +#endif + +#ifndef QCOM_HARDWARE #ifdef USE_TI_DUCATI_H264_PROFILE if ((strncmp(mComponentName, "OMX.TI.DUCATI1", 14) != 0) && (h264type.eProfile != OMX_VIDEO_AVCProfileBaseline)) { @@ -1405,19 +1435,22 @@ status_t OMXCodec::setupAVCEncoderParameters(const sp<MetaData>& meta) { if (h264type.eProfile != OMX_VIDEO_AVCProfileBaseline) { #endif ALOGW("Use baseline profile instead of %d for AVC recording", - h264type.eProfile); + h264type.eProfile); h264type.eProfile = OMX_VIDEO_AVCProfileBaseline; } +#endif if (h264type.eProfile == OMX_VIDEO_AVCProfileBaseline) { h264type.nSliceHeaderSpacing = 0; h264type.bUseHadamard = OMX_TRUE; h264type.nRefFrames = 1; h264type.nBFrames = 0; +#ifndef QCOM_HARDWARE h264type.nPFrames = setPFramesSpacing(iFramesInterval, frameRate); if (h264type.nPFrames == 0) { h264type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI; } +#endif h264type.nRefIdx10ActiveMinus1 = 0; h264type.nRefIdx11ActiveMinus1 = 0; h264type.bEntropyCodingCABAC = OMX_FALSE; @@ -1428,6 +1461,12 @@ status_t OMXCodec::setupAVCEncoderParameters(const sp<MetaData>& meta) { h264type.nCabacInitIdc = 0; } +#ifdef QCOM_HARDWARE + QCUtilityClass::helper_OMXCodec_setBFrames(h264type, + mNumBFrames, + iFramesInterval, + newFrameRate); +#endif if (h264type.nBFrames != 0) { h264type.nAllowedPictureTypes |= OMX_VIDEO_PictureTypeB; } @@ -1509,6 +1548,7 @@ status_t OMXCodec::setVideoOutputFormat( || format.eColorFormat == OMX_TI_COLOR_FormatYUV420PackedSemiPlanar || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar || format.eColorFormat == OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka + || format.eColorFormat == OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar32m #ifdef USE_SAMSUNG_COLORFORMAT || format.eColorFormat == OMX_SEC_COLOR_FormatNV12TPhysicalAddress || format.eColorFormat == OMX_SEC_COLOR_FormatNV12Tiled @@ -1653,7 +1693,11 @@ OMXCodec::OMXCodec( mNativeWindow( (!strncmp(componentName, "OMX.google.", 11) || !strcmp(componentName, "OMX.Nvidia.mpeg2v.decode")) - ? NULL : nativeWindow) { + ? NULL : nativeWindow) +#ifdef QCOM_HARDWARE + ,mNumBFrames(0) +#endif +{ mPortStatus[kPortIndexInput] = ENABLED; mPortStatus[kPortIndexOutput] = ENABLED; @@ -2152,6 +2196,15 @@ status_t OMXCodec::allocateOutputBuffersFromNativeWindow() { return err; } +#ifdef QCOM_BSP + err = mNativeWindow.get()->perform(mNativeWindow.get(), + NATIVE_WINDOW_SET_BUFFERS_SIZE, def.nBufferSize); + if (err != 0) { + ALOGE("native_window_set_buffers_size failed: %s (%d)", strerror(-err), + -err); + return err; + } +#endif CODEC_LOGV("allocating %lu buffers from a native window of size %lu on " "output port", def.nBufferCountActual, def.nBufferSize); @@ -3028,13 +3081,30 @@ void OMXCodec::onStateChange(OMX_STATETYPE newState) { mPortStatus[kPortIndexInput] = ENABLED; mPortStatus[kPortIndexOutput] = ENABLED; - if ((mFlags & kEnableGrallocUsageProtected) && - mNativeWindow != NULL) { - // We push enough 1x1 blank buffers to ensure that one of - // them has made it to the display. This allows the OMX - // component teardown to zero out any protected buffers - // without the risk of scanning out one of those buffers. - pushBlankBuffersToNativeWindow(); + if (mNativeWindow != NULL) { +#ifdef QCOM_BSP + /* + * reset buffer size field with SurfaceTexture + * back to 0. This will ensure proper size + * buffers are allocated if the same SurfaceTexture + * is re-used in a different decode session + */ + int err = + mNativeWindow.get()->perform(mNativeWindow.get(), + NATIVE_WINDOW_SET_BUFFERS_SIZE, + 0); + if (err != 0) { + ALOGE("set_buffers_size failed: %s (%d)", strerror(-err), + -err); + } +#endif + if (mFlags & kEnableGrallocUsageProtected) { + // We push enough 1x1 blank buffers to ensure that one of + // them has made it to the display. This allows the OMX + // component teardown to zero out any protected buffers + // without the risk of scanning out one of those buffers. + pushBlankBuffersToNativeWindow(); + } } setState(IDLE_TO_LOADED); @@ -3305,7 +3375,10 @@ void OMXCodec::drainInputBuffers() { } if (mFlags & kOnlySubmitOneInputBufferAtOneTime) { - break; +#ifdef QCOM_HARDWARE + if (i == mNumBFrames) +#endif + break; } } } @@ -3757,6 +3830,9 @@ void OMXCodec::setRawAudioFormat( OMX_PARAM_PORTDEFINITIONTYPE def; InitOMXParams(&def); def.nPortIndex = portIndex; +#ifdef QCOM_ENHANCED_AUDIO + def.format.audio.cMIMEType = NULL; +#endif status_t err = mOMX->getParameter( mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); CHECK_EQ(err, (status_t)OK); @@ -5235,6 +5311,10 @@ void OMXCodec::initOutputFormat(const sp<MetaData> &inputFormat) { if (mNativeWindow != NULL) { initNativeWindowCrop(); } +#ifdef QCOM_HARDWARE + } else { + QCUtilityClass::helper_OMXCodec_hfr(inputFormat, mOutputFormat); +#endif } break; } diff --git a/media/libstagefright/QCOMXCodec.cpp b/media/libstagefright/QCOMXCodec.cpp index fcc57f2..a2f3b35 100644 --- a/media/libstagefright/QCOMXCodec.cpp +++ b/media/libstagefright/QCOMXCodec.cpp @@ -30,6 +30,7 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "QCOMXCodec" #include <utils/Log.h> +#include <cutils/properties.h> #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/MediaDefs.h> @@ -593,7 +594,7 @@ void QCOMXCodec::setQCSpecificVideoFormat(const sp<MetaData> &meta, sp<IOMX> OMX void QCOMXCodec::checkIfInterlaced(const uint8_t *ptr, const sp<MetaData> &meta) { uint16_t spsSize = (((uint16_t)ptr[6]) << 8) + (uint16_t)(ptr[7]); - int32_t width = 0, height = 0, isInterlaced = 0; + int32_t width = 0, height = 0, isInterlaced = 1; const uint8_t *spsStart = &ptr[8]; sp<ABuffer> seqParamSet = new ABuffer(spsSize); @@ -607,4 +608,14 @@ void QCOMXCodec::checkIfInterlaced(const uint8_t *ptr, const sp<MetaData> &meta) return; } +bool QCOMXCodec::useHWAACDecoder(const char *mime) { + char value[PROPERTY_VALUE_MAX]; + int aaccodectype = property_get("media.aaccodectype", value, NULL); + if (!strcmp("0", value) && aaccodectype && !strcmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { + ALOGI("Using Hardware AAC Decoder"); + return true; + } + return false; +} + } 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; + } +} + +} diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp index d9858d7..4a42a70 100644 --- a/media/libstagefright/SampleTable.cpp +++ b/media/libstagefright/SampleTable.cpp @@ -360,8 +360,9 @@ status_t SampleTable::setCompositionTimeToSampleParams( return ERROR_IO; } - if (U32_AT(header) != 0) { - // Expected version = 0, flags = 0. + if (U32_AT(header) != 0 && + U32_AT(header) != 0x01000000) { + // Expected version = 0/1, flags = 0. return ERROR_MALFORMED; } diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp index 74e9222..7bd2032 100644 --- a/media/libstagefright/Utils.cpp +++ b/media/libstagefright/Utils.cpp @@ -28,6 +28,17 @@ #include <media/stagefright/MetaData.h> #include <media/stagefright/Utils.h> +#ifdef QCOM_ENHANCED_AUDIO +#include <QCMediaDefs.h> +#include <QCMetaData.h> +#include <QOMX_AudioExtensions.h> +#include <OMX_QCOMExtns.h> +#include "include/avc_utils.h" + +#include "include/QCUtilityClass.h" +#endif + + namespace android { uint16_t U16_AT(const uint8_t *ptr) { @@ -111,6 +122,46 @@ status_t convertMetaDataToMessage( if (meta->findInt32(kKeyIsADTS, &isADTS)) { msg->setInt32("is-adts", true); } +#ifdef QCOM_ENHANCED_AUDIO + int32_t keyWMAVersion; + if (meta->findInt32(kKeyWMAVersion, &keyWMAVersion)) { + msg->setInt32("WMA-Version", keyWMAVersion); + } + int32_t bitRate; + int32_t encodeOptions; + int32_t blockAlign; + int32_t bitspersample; + int32_t formattag; + int32_t advencopt1; + int32_t advencopt2; + int32_t VirtualPktSize; + + if (meta->findInt32(kKeyWMABitspersample, &bitspersample)) { + msg->setInt32("bsps", bitspersample); + } + if (meta->findInt32(kKeyWMAFormatTag, &formattag)) { + msg->setInt32("fmtt", formattag); + } + if (meta->findInt32(kKeyWMAAdvEncOpt1, &advencopt1)) { + msg->setInt32("ade1", advencopt1); + } + + if (meta->findInt32(kKeyWMAAdvEncOpt2, &advencopt2)) { + msg->setInt32("ade2", advencopt2); + } + if (meta->findInt32(kKeyWMAVirPktSize, &VirtualPktSize)) { + msg->setInt32("vpks", VirtualPktSize); + } + if (meta->findInt32(kKeyBitRate, &bitRate)) { + msg->setInt32("brte", bitRate); + } + if (meta->findInt32(kKeyWMAEncodeOpt, &encodeOptions)) { + msg->setInt32("eopt", encodeOptions); + } + if (meta->findInt32(kKeyWMABlockAlign, &blockAlign)) { + msg->setInt32("blka", blockAlign); + } +#endif } int32_t maxInputSize; diff --git a/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp index a38400b..2640319 100644 --- a/media/libstagefright/WAVExtractor.cpp +++ b/media/libstagefright/WAVExtractor.cpp @@ -192,8 +192,8 @@ status_t WAVExtractor::init() { mNumChannels = U16_LE_AT(&formatSpec[2]); if (mWaveFormat != WAVE_FORMAT_EXTENSIBLE) { - if (mNumChannels != 1 && mNumChannels != 2) { - ALOGW("More than 2 channels (%d) in non-WAVE_EXT, unknown channel mask", + if (mNumChannels != 1 && mNumChannels != 2 && mNumChannels != 4) { + ALOGW("More than 4 channels (%d) in non-WAVE_EXT, unknown channel mask", mNumChannels); } } else { @@ -271,6 +271,10 @@ status_t WAVExtractor::init() { if (mValidFormat) { mDataOffset = offset; mDataSize = chunkSize; + off64_t dataSourceSize = 0; + + if (OK == mDataSource->getSize(&dataSourceSize) && mDataSize > (dataSourceSize - offset)) + mDataSize = dataSourceSize - offset; mTrackMeta = new MetaData; diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp index fbe98f1..7bfa375 100644 --- a/media/libstagefright/avc_utils.cpp +++ b/media/libstagefright/avc_utils.cpp @@ -60,7 +60,11 @@ void FindAVCDimensions( parseUE(&br); // bit_depth_luma_minus8 parseUE(&br); // bit_depth_chroma_minus8 br.skipBits(1); // qpprime_y_zero_transform_bypass_flag - CHECK_EQ(br.getBits(1), 0u); // seq_scaling_matrix_present_flag + bool seq_scaling_matrix_present = (br.getBits(1) != 0u); + if (isInterlaced != NULL && seq_scaling_matrix_present) { + return; + } + CHECK_EQ(seq_scaling_matrix_present, false); // seq_scaling_matrix_present_flag } parseUE(&br); // log2_max_frame_num_minus4 @@ -128,11 +132,11 @@ void FindAVCDimensions( (frame_crop_left_offset + frame_crop_right_offset) * cropUnitX; *height -= (frame_crop_top_offset + frame_crop_bottom_offset) * cropUnitY; - - if (isInterlaced != NULL) { - *isInterlaced = !frame_mbs_only_flag; - } } + if (isInterlaced != NULL) { + *isInterlaced = !frame_mbs_only_flag; + } + } status_t getNextNALUnit( diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp index d88813e..606a43d 100644 --- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp +++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp @@ -358,9 +358,13 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { inInfo->mOwnedByUs = false; notifyEmptyBufferDone(inHeader); - if (!mIsFirst) { + if (!mIsFirst || mInputBufferCount) { // flush out the decoder's delayed data by calling DecodeFrame // one more time, with the AACDEC_FLUSH flag set + + // for the use case where the first frame in the buffer is EOS, + // decode the header to update the sample rate and channel mode + // and flush out the buffer. INT_PCM *outBuffer = reinterpret_cast<INT_PCM *>( outHeader->pBuffer + outHeader->nOffset); @@ -392,6 +396,9 @@ void SoftAAC2::onQueueFilled(OMX_U32 portIndex) { } outHeader->nFlags = OMX_BUFFERFLAG_EOS; + outHeader->nTimeStamp = + mAnchorTimeUs + + (mNumSamplesOutput * 1000000ll) / mStreamInfo->sampleRate; outQueue.erase(outQueue.begin()); outInfo->mOwnedByUs = false; diff --git a/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp index 07f8b4f..27dea92 100644 --- a/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp +++ b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp @@ -71,7 +71,7 @@ void SoftAMRNBEncoder::initPorts() { def.eDir = OMX_DirInput; def.nBufferCountMin = kNumBuffers; def.nBufferCountActual = def.nBufferCountMin; - def.nBufferSize = kNumSamplesPerFrame * sizeof(int16_t); + def.nBufferSize = kNumSamplesPerFrame * sizeof(int16_t) * 4; def.bEnabled = OMX_TRUE; def.bPopulated = OMX_FALSE; def.eDomain = OMX_PortDomainAudio; diff --git a/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp index 9ccb49c..afd2b32 100644 --- a/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp +++ b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp @@ -78,7 +78,7 @@ void SoftAMRWBEncoder::initPorts() { def.eDir = OMX_DirInput; def.nBufferCountMin = kNumBuffers; def.nBufferCountActual = def.nBufferCountMin; - def.nBufferSize = kNumSamplesPerFrame * sizeof(int16_t); + def.nBufferSize = kNumSamplesPerFrame * sizeof(int16_t) * 4; def.bEnabled = OMX_TRUE; def.bPopulated = OMX_FALSE; def.eDomain = OMX_PortDomainAudio; diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp index fb1135c..aade29c 100644 --- a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp +++ b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp @@ -110,7 +110,7 @@ void SoftMP3::initPorts() { void SoftMP3::initDecoder() { mConfig->equalizerType = flat; mConfig->crcEnabled = false; - + mConfig->samplingRate = mSamplingRate; uint32_t memRequirements = pvmp3_decoderMemRequirements(); mDecoderBuf = malloc(memRequirements); @@ -237,10 +237,13 @@ void SoftMP3::onQueueFilled(OMX_U32 portIndex) { if (decoderErr != NO_ENOUGH_MAIN_DATA_ERROR && decoderErr != SIDE_INFO_ERROR) { ALOGE("mp3 decoder returned error %d", decoderErr); - - notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); - mSignalledError = true; - return; + if(decoderErr == SYNCH_LOST_ERROR) { + mConfig->outputFrameSize = kOutputBufferSize / sizeof(int16_t); + } else { + notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL); + mSignalledError = true; + return; + } } if (mConfig->outputFrameSize == 0) { diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h index 8bda7f8..b77cc86 100644 --- a/media/libstagefright/include/AwesomePlayer.h +++ b/media/libstagefright/include/AwesomePlayer.h @@ -308,6 +308,7 @@ private: void logCatchUp(int64_t ts, int64_t clock, int64_t delta); void logLate(int64_t ts, int64_t clock, int64_t delta); void logOnTime(int64_t ts, int64_t clock, int64_t delta); + void printStats(); int64_t getTimeOfDayUs(); #ifdef QCOM_HARDWARE void checkTunnelExceptions(); diff --git a/media/libstagefright/include/QCUtilityClass.h b/media/libstagefright/include/QCUtilityClass.h new file mode 100644 index 0000000..91b184f --- /dev/null +++ b/media/libstagefright/include/QCUtilityClass.h @@ -0,0 +1,111 @@ +/*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. + */ + +#ifndef QC_UTIL_CLASS_H_ +#define QC_UTIL_CLASS_H_ + +#include <QCMetaData.h> +#include <cutils/properties.h> +#include <QCMediaDefs.h> + +#include <media/Metadata.h> +#include <media/stagefright/MediaSource.h> +#include <media/stagefright/foundation/AString.h> +#include <media/stagefright/MediaCodecList.h> + +#include <utils/Errors.h> +#include <sys/types.h> +#include <ctype.h> +#include <unistd.h> +#include <utils/StrongPointer.h> + +#include <media/MediaRecorderBase.h> +#include <camera/CameraParameters.h> + +#include <OMX_Video.h> +#include <media/stagefright/MediaExtractor.h> +#include <media/stagefright/MetaData.h> +#include <media/stagefright/MediaDebug.h> +#include <media/stagefright/MediaDefs.h> + +namespace android { + +struct QCUtilityClass +{ + // helper function to enable Stagefright Recoder to recalculate fileduration + // when hfr property is set + static status_t helper_StageFrightRecoder_hfr(sp<MetaData> &meta, sp<MetaData> &enc_meta, + int64_t &maxFileDurationUs, int32_t frameRate, + video_encoder videoEncoder); + + // helper function to enable camera source to set kKeyHFR when video-hfr is enabled + static void helper_CameraSource_hfr(const CameraParameters& params, sp<MetaData> &meta); + + // helper function to enable MPEG4Writer to compute timestamp when hfr is enable + static void helper_MPEG4Writer_hfr(sp<MetaData> &meta, int64_t ×tampUs); + + // helper function to enable OMXCodec to recalculate frameRate, bitrate when hfr is enable + static void helper_OMXCodec_hfr(const sp<MetaData> &meta, int32_t &frameRate, + int32_t &bitRate, int32_t &newFrameRate); + + // helper function to enable OMXCodec to set HFR and FrameRate on output format when + // present on input format + static void helper_OMXCodec_hfr(const sp<MetaData> &inputFormat, sp<MetaData> &outputFormat); + + // helper function to disable audio when decode audio disable prop is set + static bool helper_Awesomeplayer_checkIfAudioDisable(); + + // helper function to disable audio when encode audio disable prop is set + static bool helper_StagefrightRecoder_checkIfAudioDisable(); + + //helper function to set encoding profiles + static void helper_StagefrightRecoder_setUserprofile(video_encoder &videoEncoder, + int32_t &videoEncoderProfile); + //helper function to setBframe related info for MPEG4type + static void helper_OMXCodec_setBFrames(OMX_VIDEO_PARAM_MPEG4TYPE &mpeg4type, bool &numBFrames); + + //helper function to setBframe related info for H264 type + static void helper_OMXCodec_setBFrames(OMX_VIDEO_PARAM_AVCTYPE &h264type, bool &numBFrames, + int32_t iFramesInterval, int32_t frameRate); + + //helper function to add media codecs with specific quirks + static void helper_addMediaCodec(Vector<MediaCodecList::CodecInfo> &mCodecInfos, + KeyedVector<AString, size_t> &mTypes, + bool encoder, const char *name, + const char *type, uint32_t quirks); + + //helper function to calculate the value of quirks from strings + static uint32_t helper_getCodecSpecificQuirks(KeyedVector<AString, size_t> &mCodecQuirks, + Vector<AString> quirks); + static sp<MediaExtractor> helper_MediaExtractor_CreateIfNeeded(sp<MediaExtractor> defaultExt, + const sp<DataSource> &source, + const char *mime); +}; + +} +#endif //QC_UTIL_CLASS diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp index bff3def..e41b342 100644 --- a/media/libstagefright/omx/OMXNodeInstance.cpp +++ b/media/libstagefright/omx/OMXNodeInstance.cpp @@ -599,15 +599,20 @@ status_t OMXNodeInstance::freeBuffer( OMX_U32 portIndex, OMX::buffer_id buffer) { Mutex::Autolock autoLock(mLock); - removeActiveBuffer(portIndex, buffer); - OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer; BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate); OMX_ERRORTYPE err = OMX_FreeBuffer(mHandle, portIndex, header); - delete buffer_meta; - buffer_meta = NULL; + if (err != OMX_ErrorNone) { + ALOGW("OMX_FreeBuffer failed w/ err %x, do not remove from active buffer list", err); + } else { + ALOGI("OMX_FreeBuffer for buffer header %p successful", header); + removeActiveBuffer(portIndex, buffer); + + delete buffer_meta; + buffer_meta = NULL; + } return StatusFromOMXError(err); } diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk index 1ff87c8..3dde663 100644 --- a/media/mediaserver/Android.mk +++ b/media/mediaserver/Android.mk @@ -16,6 +16,10 @@ ifeq ($(BOARD_USE_SECTVOUT),true) LOCAL_SHARED_LIBRARIES += libTVOut endif +ifeq ($(TARGET_QCOM_AUDIO_VARIANT),caf) + LOCAL_CFLAGS += -DQCOM_ENHANCED_AUDIO +endif + # FIXME The duplicate audioflinger is temporary LOCAL_C_INCLUDES := \ frameworks/av/media/libmediaplayerservice \ |