From b86584daaaad622b11f91080f7b66e0b2b88033c Mon Sep 17 00:00:00 2001 From: Steve Kondik Date: Mon, 12 Oct 2015 13:00:34 -1000 Subject: [PATCH 01/73] av: Use project pathmap Change-Id: I0b26e698a9e1ef57115547ab4ff56fb16bd6d015 --- media/libavextensions/Android.mk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/media/libavextensions/Android.mk b/media/libavextensions/Android.mk index 0bc886d7fc5..7cefb754611 100644 --- a/media/libavextensions/Android.mk +++ b/media/libavextensions/Android.mk @@ -12,7 +12,7 @@ LOCAL_C_INCLUDES:= \ $(TOP)/frameworks/native/include/media/hardware \ $(TOP)/frameworks/native/include/media/openmax \ $(TOP)/external/flac/include \ - $(TOP)/hardware/qcom/media/mm-core/inc \ + $(TOP)/$(call project-path-for,qcom-media)/mm-core/inc \ $(TOP)/frameworks/av/media/libstagefright \ LOCAL_CFLAGS += -Wno-multichar -Werror @@ -40,7 +40,7 @@ LOCAL_C_INCLUDES:= \ $(TOP)/frameworks/native/include/media/hardware \ $(TOP)/frameworks/native/include/media/openmax \ $(TOP)/external/flac/include \ - $(TOP)/hardware/qcom/media/mm-core/inc + $(TOP)/$(call project-path-for,qcom-media)/mm-core/inc LOCAL_CFLAGS += -Wno-multichar -Werror @@ -73,7 +73,7 @@ LOCAL_C_INCLUDES:= \ $(TOP)/frameworks/native/include/media/hardware \ $(TOP)/frameworks/native/include/media/openmax \ $(TOP)/external/flac/include \ - $(TOP)/hardware/qcom/media/mm-core/inc + $(TOP)/$(call project-path-for,qcom-media)/mm-core/inc LOCAL_CFLAGS += -Wno-multichar -Werror From 6f6d90ecdcd99c96f8eb485feaf4a72191432da7 Mon Sep 17 00:00:00 2001 From: Konsta Date: Fri, 15 Aug 2014 21:04:15 +0300 Subject: [PATCH 02/73] camera: allow device to append camera parameters Overload using include/camera/CameraParametersExtra.h in device tree to add device specific camera parameters. Change-Id: Ie79380f4e49661348df4b2028ddf48daa67fca2d --- camera/CameraParameters.cpp | 5 ++++ include/camera/CameraParameters.h | 5 ++++ include/camera/CameraParametersExtra.h | 35 ++++++++++++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 include/camera/CameraParametersExtra.h diff --git a/camera/CameraParameters.cpp b/camera/CameraParameters.cpp index 68969cf649d..590ff4a73f0 100644 --- a/camera/CameraParameters.cpp +++ b/camera/CameraParameters.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include namespace android { @@ -173,6 +174,10 @@ const char CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE[] = "continuous-pictu const char CameraParameters::LIGHTFX_LOWLIGHT[] = "low-light"; const char CameraParameters::LIGHTFX_HDR[] = "high-dynamic-range"; +#ifdef CAMERA_PARAMETERS_EXTRA_C +CAMERA_PARAMETERS_EXTRA_C +#endif + CameraParameters::CameraParameters() : mMap() { diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h index ba33ffe63b9..74517b47bed 100644 --- a/include/camera/CameraParameters.h +++ b/include/camera/CameraParameters.h @@ -19,6 +19,7 @@ #include #include +#include namespace android { @@ -683,6 +684,10 @@ class CameraParameters // High-dynamic range mode static const char LIGHTFX_HDR[]; +#ifdef CAMERA_PARAMETERS_EXTRA_H +CAMERA_PARAMETERS_EXTRA_H +#endif + /** * Returns the the supported preview formats as an enum given in graphics.h * corrsponding to the format given in the input string or -1 if no such diff --git a/include/camera/CameraParametersExtra.h b/include/camera/CameraParametersExtra.h new file mode 100644 index 00000000000..80a67cc1877 --- /dev/null +++ b/include/camera/CameraParametersExtra.h @@ -0,0 +1,35 @@ +// Overload this file in your device specific config if you need +// to add extra camera parameters. +// A typical file would look like this: +/* + * Copyright (C) 2014 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* +#define CAMERA_PARAMETERS_EXTRA_C \ +const char CameraParameters::KEY_SUPPORTED_BURST_NUM[] = "supported-burst-num"; \ +const char CameraParameters::KEY_BURST_NUM[] = "burst-num"; \ +const char CameraParameters::KEY_SUPPORTED_HDR_MODES[] = "supported-hdr-modes"; \ +const char CameraParameters::KEY_HDR_MODE[] = "hdr-mode"; \ +const char CameraParameters::HDR_MODE_OFF[] = "hdr-mode-off"; \ +const char CameraParameters::HDR_MODE_HDR[] = "hdr-mode-hdr"; + +#define CAMERA_PARAMETERS_EXTRA_H \ + static const char KEY_SUPPORTED_BURST_NUM[]; \ + static const char KEY_BURST_NUM[]; \ + static const char KEY_SUPPORTED_HDR_MODES[]; \ + static const char KEY_HDR_MODE[]; \ + static const char HDR_MODE_OFF[]; \ + static const char HDR_MODE_HDR[]; +*/ From 7e03e11db4c357a9b8cd041cb381be70144c292f Mon Sep 17 00:00:00 2001 From: Surajit Podder Date: Fri, 25 Sep 2015 19:03:35 +0530 Subject: [PATCH 03/73] Revert "Revert "mediaplayer: make frame-accurate avsync configurable"" This reverts commit e17afa888040eb5fbd31249305efd88ee03bb5bc. Change-Id: I7afb6a055d3efb08fdbdff19f0bbad01934614e8 --- .../nuplayer/NuPlayerRenderer.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index aa993a9f4eb..9d2f134cc0c 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -83,6 +83,16 @@ const NuPlayer::Renderer::PcmInfo NuPlayer::Renderer::AUDIO_PCMINFO_INITIALIZER // static const int64_t NuPlayer::Renderer::kMinPositionUpdateDelayUs = 100000ll; +static bool sFrameAccurateAVsync = false; + +static void readProperties() { + char value[PROPERTY_VALUE_MAX]; + if (property_get("persist.sys.media.avsync", value, NULL)) { + sFrameAccurateAVsync = + !strcmp("1", value) || !strcasecmp("true", value); + } +} + NuPlayer::Renderer::Renderer( const sp &sink, const sp ¬ify, @@ -124,6 +134,7 @@ NuPlayer::Renderer::Renderer( mMediaClock = new MediaClock; mPlaybackRate = mPlaybackSettings.mSpeed; mMediaClock->setPlaybackRate(mPlaybackRate); + readProperties(); } NuPlayer::Renderer::~Renderer() { @@ -1065,6 +1076,11 @@ void NuPlayer::Renderer::postDrainVideoQueue() { ALOGW_IF(delayUs > 500000, "unusually high delayUs: %" PRId64, delayUs); // post 2 display refreshes before rendering is due + // FIXME currently this increases power consumption, so unless frame-accurate + // AV sync is requested, post closer to required render time (at 0.63 vsyncs) + if (!sFrameAccurateAVsync) { + twoVsyncsUs >>= 4; + } msg->post(delayUs > twoVsyncsUs ? delayUs - twoVsyncsUs : 0); mDrainVideoQueuePending = true; @@ -1477,6 +1493,8 @@ void NuPlayer::Renderer::onPause() { } void NuPlayer::Renderer::onResume() { + readProperties(); + if (!mPaused) { return; } From 99a7726b57ec6f2330a6376339fe43002f1fe940 Mon Sep 17 00:00:00 2001 From: Dhananjay Kumar Date: Tue, 20 Oct 2015 17:29:24 +0530 Subject: [PATCH 04/73] audio policy: move output handle to AudioOutputDescriptor base class Output handle of AudioOutputDescriptor is required by derived implementation of some AudioPolicyManager methods. These methods need to access attributes of an output which is not accessible through AudioOutputDescriptor base class unless output handle is made available here. Change-Id: I96ef9fd1c5a94874acb897245501ba2f9c9ab0c0 --- .../common/managerdefinitions/include/AudioOutputDescriptor.h | 2 +- .../common/managerdefinitions/src/AudioOutputDescriptor.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h index 50f622d47c8..e1c29991812 100644 --- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h +++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h @@ -72,6 +72,7 @@ class AudioOutputDescriptor: public AudioPortConfig sp mPort; audio_devices_t mDevice; // current device this output is routed to audio_patch_handle_t mPatchHandle; + audio_io_handle_t mIoHandle; // output handle uint32_t mRefCount[AUDIO_STREAM_CNT]; // number of streams of each type using this output nsecs_t mStopTime[AUDIO_STREAM_CNT]; float mCurVolume[AUDIO_STREAM_CNT]; // current stream volume in dB @@ -116,7 +117,6 @@ class SwAudioOutputDescriptor: public AudioOutputDescriptor virtual void toAudioPort(struct audio_port *port) const; const sp mProfile; // I/O profile this output derives from - audio_io_handle_t mIoHandle; // output handle uint32_t mLatency; // audio_output_flags_t mFlags; // AudioMix *mPolicyMix; // non NULL when used by a dynamic policy diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp index a278375ba80..5ddeaed7f23 100644 --- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp @@ -33,7 +33,7 @@ namespace android { AudioOutputDescriptor::AudioOutputDescriptor(const sp& port, AudioPolicyClientInterface *clientInterface) - : mPort(port), mDevice(AUDIO_DEVICE_NONE), + : mPort(port), mDevice(AUDIO_DEVICE_NONE), mIoHandle(0), mPatchHandle(0), mClientInterface(clientInterface), mId(0) { // clear usage count for all stream types @@ -223,7 +223,7 @@ void AudioOutputDescriptor::log(const char* indent) SwAudioOutputDescriptor::SwAudioOutputDescriptor( const sp& profile, AudioPolicyClientInterface *clientInterface) : AudioOutputDescriptor(profile, clientInterface), - mProfile(profile), mIoHandle(0), mLatency(0), + mProfile(profile), mLatency(0), mFlags((audio_output_flags_t)0), mPolicyMix(NULL), mOutput1(0), mOutput2(0), mDirectOpenCount(0), mGlobalRefCount(0) { From 91ba994751d54026381d7718efbcc849a75c20fe Mon Sep 17 00:00:00 2001 From: Amit Shekhar Date: Thu, 17 Sep 2015 15:51:35 -0700 Subject: [PATCH 05/73] nuplayer: Fix de-referencing NULL mSource InstantiateDecoderAction is executed after performing reset. By the time performReset call is over, mSource is cleared and instantiateDecoderAction is executed on a NULL mSource - causing crash. At this point of time, mSource is already reset and it is not intended to be used in future, so, we can safely return. Check for NULL to avoid crash. CRs-Fixed: 902831 Change-Id: If438da2b8c778c6db3640c0bc2e53d3ef68d286c --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 356c5191bc3..6305a02ca8b 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -1526,7 +1526,10 @@ status_t NuPlayer::instantiateDecoder(bool audio, sp *decoder) { if (*decoder != NULL || (audio && mFlushingAudio == SHUT_DOWN)) { return OK; } - + if (mSource == NULL) { + ALOGD("%s Ignore instantiate decoder after clearing source", __func__); + return INVALID_OPERATION; + } sp format = mSource->getFormat(audio); if (format == NULL) { From 95922a29f586d7dbe0356313ccc66e1bc71bd72a Mon Sep 17 00:00:00 2001 From: Praveen Chavan Date: Fri, 23 Oct 2015 15:31:52 -0700 Subject: [PATCH 06/73] AudioTrack: Fix the signature of AudioTrackGetTimestamp to invoke the customized method correctly. CRs-Fixed: 923592 Change-Id: I8a7da0a679bebaa70076920936081be4470da6d1 --- media/libavextensions/media/AVMediaExtensions.h | 4 ++-- media/libmedia/AudioTrack.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/media/libavextensions/media/AVMediaExtensions.h b/media/libavextensions/media/AVMediaExtensions.h index 6cf39f2821e..ae26143cb79 100644 --- a/media/libavextensions/media/AVMediaExtensions.h +++ b/media/libavextensions/media/AVMediaExtensions.h @@ -47,12 +47,12 @@ struct AVMediaUtils { return false; } virtual status_t AudioTrackGetPosition(AudioTrack* /*track*/, - uint32_t* /*position*/) { + uint32_t* /*position*/) { return NO_INIT; } virtual status_t AudioTrackGetTimestamp(AudioTrack* /*track*/, - AudioTimestamp /*timestamp*/) { + AudioTimestamp* /*timestamp*/) { return NO_INIT; } diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 2d9fcf711f5..8ad0d1037b8 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -2318,7 +2318,7 @@ status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp) } else { // Update the mapping between local consumed (mPosition) and server consumed (mServer) - if (AVMediaUtils::get()->AudioTrackGetTimestamp(this, timestamp) == NO_ERROR) { + if (AVMediaUtils::get()->AudioTrackGetTimestamp(this, ×tamp) == NO_ERROR) { return NO_ERROR; } From 10c638d2d22514c665746327ffae0a0026d11d52 Mon Sep 17 00:00:00 2001 From: vivek mehta Date: Fri, 16 Oct 2015 12:15:07 -0700 Subject: [PATCH 07/73] libmedia : audio: handle set playback rate when direct pcm used - In direct PCM usecase if setplayback rate is called then invalidate the common block and send empty offload structure below to use default path. CRs-Fixed: 916660 Change-Id: I6df7c10b7115c77a19564e2f9fabc511d76a2410 --- include/media/AudioTrack.h | 1 + media/libmedia/AudioTrack.cpp | 28 +++++++++++++++++++++++----- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h index 42883b513fc..42fa3befd0a 100644 --- a/include/media/AudioTrack.h +++ b/include/media/AudioTrack.h @@ -942,6 +942,7 @@ class AudioTrack : public RefBase // For Device Selection API // a value of AUDIO_PORT_HANDLE_NONE indicated default (AudioPolicyManager) routing. audio_port_handle_t mSelectedDeviceId; + bool mPlaybackRateSet; private: class DeathNotifier : public IBinder::DeathRecipient { diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 2d9fcf711f5..ff0f35a4e30 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -31,6 +31,7 @@ #include #include #include "media/AVMediaExtensions.h" +#include #define WAIT_PERIOD_MS 10 #define WAIT_STREAM_END_TIMEOUT_SEC 120 @@ -168,7 +169,8 @@ AudioTrack::AudioTrack() mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT), mPausedPosition(0), - mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE) + mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE), + mPlaybackRateSet(false) { mAttributes.content_type = AUDIO_CONTENT_TYPE_UNKNOWN; mAttributes.usage = AUDIO_USAGE_UNKNOWN; @@ -198,7 +200,8 @@ AudioTrack::AudioTrack( mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT), mPausedPosition(0), - mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE) + mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE), + mPlaybackRateSet(false) { mStatus = set(streamType, sampleRate, format, channelMask, frameCount, flags, cbf, user, notificationFrames, @@ -228,7 +231,8 @@ AudioTrack::AudioTrack( mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT), mPausedPosition(0), - mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE) + mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE), + mPlaybackRateSet(false) { mStatus = set(streamType, sampleRate, format, channelMask, 0 /*frameCount*/, flags, cbf, user, notificationFrames, @@ -844,6 +848,15 @@ status_t AudioTrack::setPlaybackRate(const AudioPlaybackRate &playbackRate) //set effective rates mProxy->setPlaybackRate(playbackRateTemp); mProxy->setSampleRate(effectiveRate); // FIXME: not quite "atomic" with setPlaybackRate + + // fallback out of Direct PCM if setPlaybackRate is called on PCM track + if (property_get_bool("audio.offload.track.enable", false) && + (mFormat == AUDIO_FORMAT_PCM_16_BIT) && (mOffloadInfo == NULL) && + (mFlags == AUDIO_OUTPUT_FLAG_NONE)) { + mPlaybackRateSet = true; + android_atomic_or(CBLK_INVALID, &mCblk->mFlags); + } + return NO_ERROR; } @@ -1135,11 +1148,16 @@ status_t AudioTrack::createTrack_l() audio_stream_type_t streamType = mStreamType; audio_attributes_t *attr = (mStreamType == AUDIO_STREAM_DEFAULT) ? &mAttributes : NULL; - status_t status; - status = AudioSystem::getOutputForAttr(attr, &output, + audio_offload_info_t tOffloadInfo = AUDIO_INFO_INITIALIZER; + if (mPlaybackRateSet == true && mOffloadInfo == NULL && mFormat == AUDIO_FORMAT_PCM_16_BIT) { + mOffloadInfo = &tOffloadInfo; + } + status_t status = AudioSystem::getOutputForAttr(attr, &output, (audio_session_t)mSessionId, &streamType, mClientUid, mSampleRate, mFormat, mChannelMask, mFlags, mSelectedDeviceId, mOffloadInfo); + //reset offload info if forced + mOffloadInfo = (mOffloadInfo == &tOffloadInfo) ? NULL : mOffloadInfo; if (status != NO_ERROR || output == AUDIO_IO_HANDLE_NONE) { ALOGE("Could not get audio output for session %d, stream type %d, usage %d, sample rate %u, format %#x," From becef43b5ee49c14fad7ef73f390ea17f4cb6700 Mon Sep 17 00:00:00 2001 From: Haynes Mathew George Date: Sun, 11 Oct 2015 15:58:18 -0700 Subject: [PATCH 08/73] Nuplayer: Ensure AudioSink is closed before clearing Renderer Close AudioSink object explicitly before clearing NuPlayerRenderer to avoid race conditions between NuPlayerRenderer and AudioSink callback thread. CRs-Fixed: 927545 Change-Id: Id6cef83bc8e4b6f581641b19b0bbd29eee3704bb --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 6305a02ca8b..4e5549fbe55 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -1168,6 +1168,9 @@ void NuPlayer::onMessageReceived(const sp &msg) { FLUSH_CMD_SHUTDOWN /* audio */, FLUSH_CMD_SHUTDOWN /* video */)); + mDeferredActions.push_back( + new SimpleAction(&NuPlayer::closeAudioSink)); + mDeferredActions.push_back( new SimpleAction(&NuPlayer::performReset)); From bbd59d7c0cf8a257867168699df50a3fcce3abbf Mon Sep 17 00:00:00 2001 From: Shalaj Jain Date: Fri, 16 Oct 2015 16:12:28 -0700 Subject: [PATCH 09/73] stagefright: Wait longer before force releasing codec Increase the timeout to 30 secs from 10 in order to give the components more time to move to idle state, otherwise freeNode during codec release will also try to move it to idle and bad things will happen. This is a temporary fix until software codecs error handling is improved. Change-Id: I89203bfbce1b81f53ed6e2a33747ec40a786507d --- media/libstagefright/ACodec.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index a132637e84f..3c80d03a380 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -619,8 +619,8 @@ void ACodec::initiateShutdown(bool keepComponentAllocated) { msg->setInt32("keepComponentAllocated", keepComponentAllocated); msg->post(); if (!keepComponentAllocated) { - // ensure shutdown completes in 10 seconds - (new AMessage(kWhatReleaseCodecInstance, this))->post(10000000); + // ensure shutdown completes in 30 seconds + (new AMessage(kWhatReleaseCodecInstance, this))->post(30000000); } } From 0fd06fb1c5c1b2f034ccd1a23dab7459e0c18250 Mon Sep 17 00:00:00 2001 From: Santhosh Behara Date: Wed, 21 Oct 2015 19:20:07 +0530 Subject: [PATCH 10/73] Revert "NuPlayer: Use ".m3u8" in substring search to determine HLS URL" This reverts commit 427d20a12115dbb35c6391f014f68e5283b3e6a2. Change-Id: I80295041a49295852701832d5af71adda862df8e --- media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 6305a02ca8b..1c9ea375f34 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -243,7 +243,7 @@ bool NuPlayer::IsHTTPLiveURL(const char *url) { return true; } - if (strstr(url,".m3u8")) { + if (strstr(url,"m3u8")) { return true; } } From eeffae051aa7d192e909f7d1cb6e3e925774d5cd Mon Sep 17 00:00:00 2001 From: Dilip Gopalakrishna Date: Thu, 8 Oct 2015 16:41:09 -0700 Subject: [PATCH 11/73] libcameraservice: Fix ALOG prints in FlashLight. Add missing __FUNCTION__ arguments into log statements. Change-Id: I0256bad626d490fb9360a73c104afaad7a012a97 --- .../camera/libcameraservice/CameraFlashlight.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/services/camera/libcameraservice/CameraFlashlight.cpp b/services/camera/libcameraservice/CameraFlashlight.cpp index 280bb9d755b..fd23ef99d63 100644 --- a/services/camera/libcameraservice/CameraFlashlight.cpp +++ b/services/camera/libcameraservice/CameraFlashlight.cpp @@ -99,7 +99,8 @@ status_t CameraFlashlight::createFlashlightControl(const String8& cameraId) { status_t CameraFlashlight::setTorchMode(const String8& cameraId, bool enabled) { if (!mFlashlightMapInitialized) { - ALOGE("%s: findFlashUnits() must be called before this method."); + ALOGE("%s: findFlashUnits() must be called before this method.", + __FUNCTION__); return NO_INIT; } @@ -200,7 +201,8 @@ bool CameraFlashlight::hasFlashUnit(const String8& cameraId) { bool CameraFlashlight::hasFlashUnitLocked(const String8& cameraId) { if (!mFlashlightMapInitialized) { - ALOGE("%s: findFlashUnits() must be called before this method."); + ALOGE("%s: findFlashUnits() must be called before this method.", + __FUNCTION__); return false; } @@ -219,7 +221,8 @@ status_t CameraFlashlight::prepareDeviceOpen(const String8& cameraId) { Mutex::Autolock l(mLock); if (!mFlashlightMapInitialized) { - ALOGE("%s: findFlashUnits() must be called before this method."); + ALOGE("%s: findFlashUnits() must be called before this method.", + __FUNCTION__); return NO_INIT; } @@ -256,7 +259,8 @@ status_t CameraFlashlight::deviceClosed(const String8& cameraId) { Mutex::Autolock l(mLock); if (!mFlashlightMapInitialized) { - ALOGE("%s: findFlashUnits() must be called before this method."); + ALOGE("%s: findFlashUnits() must be called before this method.", + __FUNCTION__); return NO_INIT; } From 788add7a8de76ff057858021741f3988ba966b71 Mon Sep 17 00:00:00 2001 From: Haynes Mathew George Date: Wed, 21 Oct 2015 16:38:43 -0700 Subject: [PATCH 12/73] NuPlayer: Decoder: Check for valid codec on resume The MediaCodec member associated with an NuPlayerDecoder is cleared if configure fails. A pending seek operation in NuPlayer can issue a ResumeDecoderAction. Add a NULL check before accessing the MediaCodec instance to handle this resume. Change-Id: Idc6c15168ec922ca1bd6d867cbe59847647c6f26 CRs-Fixed: 913215 --- media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index f83eaf6419e..baea834304f 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -364,7 +364,14 @@ void NuPlayer::Decoder::onResume(bool notifyComplete) { if (notifyComplete) { mResumePending = true; } - mCodec->start(); + + if (mCodec != NULL) { + mCodec->start(); + } else { + ALOGW("Decoder %s onResume without a valid codec object", + mComponentName.c_str()); + handleError(NO_INIT); + } } void NuPlayer::Decoder::doFlush(bool notifyComplete) { From 31d09de28b6ca2e79c2d157a6412759e3aa88804 Mon Sep 17 00:00:00 2001 From: Ashish Jain Date: Tue, 20 Oct 2015 12:30:49 +0530 Subject: [PATCH 13/73] stagefright: Enable QTI FLAC based on feature flag -QTI Flac decoder is used only if QTI_FLAC_DECODER flag is defined. -Enable QTI_FLAC_DECODER flag if respective feature flag is enabled. Change-Id: I192e30af3e53a57f13aa2be5dc92bfbe5f20d096 CRs-Fixed: 927012 --- media/libstagefright/Android.mk | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index 03e7e464c77..b2729af2ed8 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -137,6 +137,12 @@ ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT))) LOCAL_CFLAGS += -DENABLE_STAGEFRIGHT_EXPERIMENTS endif +ifeq ($(call is-vendor-board-platform,QCOM),true) +ifeq ($(strip $(AUDIO_FEATURE_ENABLED_EXTN_FLAC_DECODER)),true) + LOCAL_CFLAGS += -DQTI_FLAC_DECODER +endif +endif + LOCAL_CLANG := true LOCAL_MODULE:= libstagefright From 9be69bd990889cc942a53c22f6f8463f146fd8e7 Mon Sep 17 00:00:00 2001 From: Shivaprasad Hongal Date: Fri, 18 Sep 2015 15:17:14 -0700 Subject: [PATCH 14/73] stagefright: Remove additional deep-copy of encoder buffers MPEG4Writer makes a copy of encoded buffer to avoid holding on to the read buffer. This is not needed with MediaCodecSource, as the encoded-output buffer is already copied to a heap buffer. This saves a copy and some power. However, cloning the buffer is still needed for upstream sources that cannot afford to keep the buffers with writer up until they are released. So, pass a hint in buffer's metadata to indicate if it is OK to delay the release and not copy the buffer Change-Id: Ib59ac29ebc6ce4afd6fc272688a8260438ab1517 --- .../stagefright/AVExtensions.h | 3 +++ media/libstagefright/MPEG4Writer.cpp | 26 ++++++++++++------- media/libstagefright/MediaCodecSource.cpp | 2 ++ 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/media/libavextensions/stagefright/AVExtensions.h b/media/libavextensions/stagefright/AVExtensions.h index 9c712e45488..17ea475f751 100644 --- a/media/libavextensions/stagefright/AVExtensions.h +++ b/media/libavextensions/stagefright/AVExtensions.h @@ -161,6 +161,9 @@ struct AVUtils { virtual bool useQCHWEncoder(const sp &, AString &) { return false; } + virtual bool canDeferRelease(const sp &/*meta*/) { return false; } + virtual void setDeferRelease(sp &/*meta*/) {} + struct HEVCMuxer { virtual bool reassembleHEVCCSD(const AString &mime, sp csd0, sp &meta); diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index 94f40b4841a..cb9df293a37 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -2284,15 +2284,23 @@ status_t MPEG4Writer::Track::threadEntry() { continue; } - // Make a deep copy of the MediaBuffer and Metadata and release - // the original as soon as we can - MediaBuffer *copy = new MediaBuffer(buffer->range_length()); - memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(), - buffer->range_length()); - copy->set_range(0, buffer->range_length()); - meta_data = new MetaData(*buffer->meta_data().get()); - buffer->release(); - buffer = NULL; + MediaBuffer *copy = NULL; + // Check if the upstream source hints it is OK to hold on to the + // buffer without releasing immediately and avoid cloning the buffer + if (AVUtils::get()->canDeferRelease(buffer->meta_data())) { + copy = buffer; + meta_data = new MetaData(*buffer->meta_data().get()); + } else { + // Make a deep copy of the MediaBuffer and Metadata and release + // the original as soon as we can + copy = new MediaBuffer(buffer->range_length()); + memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(), + buffer->range_length()); + copy->set_range(0, buffer->range_length()); + meta_data = new MetaData(*buffer->meta_data().get()); + buffer->release(); + buffer = NULL; + } if (mIsAvc || mIsHEVC) StripStartcode(copy); diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp index dbd9cb035da..925be14cb4e 100644 --- a/media/libstagefright/MediaCodecSource.cpp +++ b/media/libstagefright/MediaCodecSource.cpp @@ -759,6 +759,8 @@ void MediaCodecSource::onMessageReceived(const sp &msg) { MediaBuffer *mbuf = new MediaBuffer(outbuf->size()); memcpy(mbuf->data(), outbuf->data(), outbuf->size()); + sp meta = mbuf->meta_data(); + AVUtils::get()->setDeferRelease(meta); if (!(flags & MediaCodec::BUFFER_FLAG_CODECCONFIG)) { if (mIsVideo) { From 85ad714b38516807efe40d67da406208d72b0dd0 Mon Sep 17 00:00:00 2001 From: Shalaj Jain Date: Wed, 21 Oct 2015 19:01:59 -0700 Subject: [PATCH 15/73] stagefright: Return error for wrong buffer index in MediaCodec Return error if the index passed by client is incorrect rather than returning OK with null buffer. Also add a null buffer check in MPEG4Writer as it shouldn't rely on the source returning the correct error code, just as a precaution. Change-Id: Iaefcd57a545ec3ce4ec0b8d4220bdf41377ff798 --- media/libstagefright/MPEG4Writer.cpp | 4 +++- media/libstagefright/MediaCodec.cpp | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index 94f40b4841a..c37026033db 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -2231,7 +2231,9 @@ status_t MPEG4Writer::Track::threadEntry() { MediaBuffer *buffer; const char *trackName = mIsAudio ? "Audio" : "Video"; while (!mDone && (err = mSource->read(&buffer)) == OK) { - if (buffer->range_length() == 0) { + if (buffer == NULL) { + continue; + } else if (buffer->range_length() == 0) { buffer->release(); buffer = NULL; ++nZeroLengthFrames; diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index 7f7c7fa19b2..c6ba76e195f 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -871,6 +871,8 @@ status_t MediaCodec::getBufferAndFormat( } *format = info.mFormat; } + } else { + return BAD_INDEX; } return OK; } From dcd760385776f0e4176cf763c8042d56af7e4503 Mon Sep 17 00:00:00 2001 From: Shivaprasad Hongal Date: Mon, 26 Oct 2015 19:05:35 -0700 Subject: [PATCH 16/73] Stagefright: use set buffers mode. Use set buffers mode if parser supports it. Change-Id: Ia3d12f15fa28f25e1ccb724158cc91ce26fc81ed --- include/media/stagefright/MediaExtractor.h | 4 +++- .../mediaplayerservice/AVNuExtensions.h | 2 ++ .../mediaplayerservice/AVNuUtils.cpp | 8 +++++++ .../stagefright/AVExtensions.h | 4 ++-- .../libavextensions/stagefright/AVFactory.cpp | 5 +++-- .../nuplayer/GenericSource.cpp | 22 ++++++++++++++----- .../nuplayer/GenericSource.h | 1 + .../nuplayer/NuPlayer.cpp | 3 ++- .../nuplayer/NuPlayerSource.h | 1 + media/libstagefright/MediaExtractor.cpp | 7 +++--- media/libstagefright/avc_utils.cpp | 18 +++++++++++---- 11 files changed, 56 insertions(+), 19 deletions(-) diff --git a/include/media/stagefright/MediaExtractor.h b/include/media/stagefright/MediaExtractor.h index 183933a77ee..32925ca6585 100644 --- a/include/media/stagefright/MediaExtractor.h +++ b/include/media/stagefright/MediaExtractor.h @@ -29,7 +29,8 @@ class MetaData; class MediaExtractor : public RefBase { public: static sp Create( - const sp &source, const char *mime = NULL); + const sp &source, const char *mime = NULL, + const uint32_t flags = 0); virtual size_t countTracks() = 0; virtual sp getTrack(size_t index) = 0; @@ -67,6 +68,7 @@ class MediaExtractor : public RefBase { } virtual void setUID(uid_t uid) { } + virtual void setExtraFlags(uint32_t flag) {} protected: MediaExtractor() : mIsDrm(false) {} diff --git a/media/libavextensions/mediaplayerservice/AVNuExtensions.h b/media/libavextensions/mediaplayerservice/AVNuExtensions.h index a10937dc5ef..c6aba716345 100644 --- a/media/libavextensions/mediaplayerservice/AVNuExtensions.h +++ b/media/libavextensions/mediaplayerservice/AVNuExtensions.h @@ -80,6 +80,8 @@ struct AVNuUtils { virtual void setDecodedPCMFormat(const sp &); virtual status_t convertToSinkFormatIfNeeded(const sp &, sp &, audio_format_t sinkFormat, bool isOffload); + virtual uint32_t getUseSetBuffersFlag(); + virtual bool canUseSetBuffers(const sp &Meta); virtual void printFileName(int fd); virtual void checkFormatChange(bool *formatChange, const sp &accessUnit); diff --git a/media/libavextensions/mediaplayerservice/AVNuUtils.cpp b/media/libavextensions/mediaplayerservice/AVNuUtils.cpp index aacf76a18bc..c254a70c56d 100644 --- a/media/libavextensions/mediaplayerservice/AVNuUtils.cpp +++ b/media/libavextensions/mediaplayerservice/AVNuUtils.cpp @@ -104,6 +104,14 @@ void AVNuUtils::checkFormatChange(bool * /*formatChange*/, const sp & /*accessUnit*/) { } +uint32_t AVNuUtils::getUseSetBuffersFlag() { + return 0; +} + +bool AVNuUtils::canUseSetBuffers(const sp &/*Meta*/) { + return false; +} + // ----- NO TRESSPASSING BEYOND THIS LINE ------ AVNuUtils::AVNuUtils() {} diff --git a/media/libavextensions/stagefright/AVExtensions.h b/media/libavextensions/stagefright/AVExtensions.h index 9c712e45488..b45c0513df4 100644 --- a/media/libavextensions/stagefright/AVExtensions.h +++ b/media/libavextensions/stagefright/AVExtensions.h @@ -68,10 +68,10 @@ struct AVFactory { virtual sp createACodec(); virtual MediaExtractor* createExtendedExtractor( const sp &source, const char *mime, - const sp &meta); + const sp &meta, const uint32_t flags); virtual sp updateExtractor( sp ext, const sp &source, - const char *mime, const sp &meta); + const char *mime, const sp &meta, const uint32_t flags); virtual sp createCachedSource( const sp &source, const char *cacheConfig = NULL, diff --git a/media/libavextensions/stagefright/AVFactory.cpp b/media/libavextensions/stagefright/AVFactory.cpp index 90ac7b2917b..2a3810d3fc4 100644 --- a/media/libavextensions/stagefright/AVFactory.cpp +++ b/media/libavextensions/stagefright/AVFactory.cpp @@ -57,13 +57,14 @@ sp AVFactory::createACodec() { } MediaExtractor* AVFactory::createExtendedExtractor( - const sp &, const char *, const sp &) { + const sp &, const char *, const sp &, + const uint32_t) { return NULL; } sp AVFactory::updateExtractor( sp ext, const sp &, - const char *, const sp &) { + const char *, const sp &, const uint32_t) { return ext; } diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index 6957a905a54..efdf096d678 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -37,6 +37,7 @@ #include "../../libstagefright/include/NuCachedSource2.h" #include "../../libstagefright/include/WVMExtractor.h" #include "../../libstagefright/include/HTTPBase.h" +#include "mediaplayerservice/AVNuExtensions.h" namespace android { @@ -60,6 +61,7 @@ NuPlayer::GenericSource::GenericSource( mAudioIsVorbis(false), mIsWidevine(false), mIsSecure(false), + mUseSetBuffers(false), mIsStreaming(false), mUIDValid(uidValid), mUID(uid), @@ -172,7 +174,8 @@ status_t NuPlayer::GenericSource::initFromDataSource() { extractor = mWVMExtractor; } else { extractor = MediaExtractor::Create(mDataSource, - mimeType.isEmpty() ? NULL : mimeType.string()); + mimeType.isEmpty() ? NULL : mimeType.string(), + mIsStreaming ? 0 : AVNuUtils::get()->getUseSetBuffersFlag()); } if (extractor == NULL) { @@ -202,6 +205,11 @@ status_t NuPlayer::GenericSource::initFromDataSource() { } } + if (AVNuUtils::get()->canUseSetBuffers(mFileMeta)) { + mUseSetBuffers = true; + ALOGI("setBuffers mode enabled"); + } + int32_t totalBitrate = 0; size_t numtracks = extractor->countTracks(); @@ -318,7 +326,7 @@ int64_t NuPlayer::GenericSource::getLastReadPosition() { status_t NuPlayer::GenericSource::setBuffers( bool audio, Vector &buffers) { - if (mIsSecure && !audio) { + if ((mIsSecure || mUseSetBuffers) && !audio) { return mVideoTrack.mSource->setBuffers(buffers); } return INVALID_OPERATION; @@ -428,7 +436,8 @@ void NuPlayer::GenericSource::onPrepareAsync() { | FLAG_CAN_PAUSE | FLAG_CAN_SEEK_BACKWARD | FLAG_CAN_SEEK_FORWARD - | FLAG_CAN_SEEK); + | FLAG_CAN_SEEK + | (mUseSetBuffers ? FLAG_USE_SET_BUFFERS : 0)); if (mIsSecure) { // secure decoders must be instantiated before starting widevine source @@ -1008,7 +1017,8 @@ status_t NuPlayer::GenericSource::dequeueAccessUnit( // start pulling in more buffers if we only have one (or no) buffer left // so that decoder has less chance of being starved - if (track->mPackets->getAvailableBufferCount(&finalResult) < 2) { + if ((track->mPackets->getAvailableBufferCount(&finalResult) < 2) + && !mUseSetBuffers) { postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO); } @@ -1352,7 +1362,7 @@ sp NuPlayer::GenericSource::mediaBufferToABuffer( } sp ab; - if (mIsSecure && !audio) { + if ((mIsSecure || mUseSetBuffers) && !audio) { // data is already provided in the buffer ab = new ABuffer(NULL, mb->range_length()); mb->add_ref(); @@ -1503,7 +1513,7 @@ void NuPlayer::GenericSource::readBuffer( track->mPackets->clear(); } - if (mIsWidevine) { + if (mIsWidevine || mUseSetBuffers) { options.setNonBlocking(); } diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h index 01819471e90..ebc1fdc64e1 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.h +++ b/media/libmediaplayerservice/nuplayer/GenericSource.h @@ -126,6 +126,7 @@ struct NuPlayer::GenericSource : public NuPlayer::Source { bool mAudioIsVorbis; bool mIsWidevine; bool mIsSecure; + bool mUseSetBuffers; bool mIsStreaming; bool mUIDValid; uid_t mUID; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 1186149b80c..ec1ab795d4c 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -1605,7 +1605,8 @@ status_t NuPlayer::instantiateDecoder(bool audio, sp *decoder) { (*decoder)->configure(format); // allocate buffers to decrypt widevine source buffers - if (!audio && (mSourceFlags & Source::FLAG_SECURE)) { + if (!audio && ((mSourceFlags & Source::FLAG_SECURE) || + (mSourceFlags & Source::FLAG_USE_SET_BUFFERS))) { Vector > inputBufs; CHECK_EQ((*decoder)->getInputBuffers(&inputBufs), (status_t)OK); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h index 9ee6c7b798c..b248316f979 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h @@ -39,6 +39,7 @@ struct NuPlayer::Source : public AHandler { FLAG_DYNAMIC_DURATION = 16, FLAG_SECURE = 32, FLAG_PROTECTED = 64, + FLAG_USE_SET_BUFFERS = 128, }; enum { diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp index 0f656a1b76f..bfb2a16ed85 100644 --- a/media/libstagefright/MediaExtractor.cpp +++ b/media/libstagefright/MediaExtractor.cpp @@ -54,7 +54,8 @@ uint32_t MediaExtractor::flags() const { // static sp MediaExtractor::Create( - const sp &source, const char *mime) { + const sp &source, const char *mime, + const uint32_t flags) { sp meta; String8 tmp; @@ -94,7 +95,7 @@ sp MediaExtractor::Create( } sp ret = NULL; - if ((ret = AVFactory::get()->createExtendedExtractor(source, mime, meta)) != NULL) { + if ((ret = AVFactory::get()->createExtendedExtractor(source, mime, meta, flags)) != NULL) { } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4) || !strcasecmp(mime, "audio/mp4")) { ret = new MPEG4Extractor(source); @@ -124,7 +125,7 @@ sp MediaExtractor::Create( ret = new MidiExtractor(source); } - ret = AVFactory::get()->updateExtractor(ret, source, mime, meta); + ret = AVFactory::get()->updateExtractor(ret, source, mime, meta, flags); if (ret != NULL) { if (isDrm) { ret->setDrmFlag(true); diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp index 8c371ba0130..98b5c0e48a7 100644 --- a/media/libstagefright/avc_utils.cpp +++ b/media/libstagefright/avc_utils.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -443,25 +444,34 @@ bool IsIDR(const sp &buffer) { } bool IsAVCReferenceFrame(const sp &accessUnit) { - const uint8_t *data = accessUnit->data(); + MediaBuffer *mediaBuffer = + (MediaBuffer *)(accessUnit->getMediaBufferBase()); + const uint8_t *data = + (mediaBuffer != NULL) ? (uint8_t *) mediaBuffer->data() : accessUnit->data(); size_t size = accessUnit->size(); const uint8_t *nalStart; size_t nalSize; + bool bIsReferenceFrame = true; while (getNextNALUnit(&data, &size, &nalStart, &nalSize, true) == OK) { CHECK_GT(nalSize, 0u); unsigned nalType = nalStart[0] & 0x1f; if (nalType == 5) { - return true; + bIsReferenceFrame = true; + break; } else if (nalType == 1) { unsigned nal_ref_idc = (nalStart[0] >> 5) & 3; - return nal_ref_idc != 0; + bIsReferenceFrame = (nal_ref_idc != 0); + break; } } - return true; + if (mediaBuffer != NULL) { + mediaBuffer->release(); + } + return bIsReferenceFrame; } sp MakeAACCodecSpecificData( From d4c3afbb613f7201ece31ad2230ec22289422680 Mon Sep 17 00:00:00 2001 From: Sidipotu Ashok Date: Fri, 16 Oct 2015 06:16:13 +0530 Subject: [PATCH 17/73] NuPlayer: use a generic funtion to get flags Use a generic function to get flags while creating extractor, so that there is no restriction to a particular usecase. CRs-Fixed: 911338 Change-Id: I8520d2ea9b25ab564b7eee6610744fcaa364fe87 --- media/libavextensions/mediaplayerservice/AVNuExtensions.h | 2 +- media/libavextensions/mediaplayerservice/AVNuUtils.cpp | 2 +- media/libmediaplayerservice/nuplayer/GenericSource.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/media/libavextensions/mediaplayerservice/AVNuExtensions.h b/media/libavextensions/mediaplayerservice/AVNuExtensions.h index c6aba716345..7aeb5c30d12 100644 --- a/media/libavextensions/mediaplayerservice/AVNuExtensions.h +++ b/media/libavextensions/mediaplayerservice/AVNuExtensions.h @@ -80,7 +80,7 @@ struct AVNuUtils { virtual void setDecodedPCMFormat(const sp &); virtual status_t convertToSinkFormatIfNeeded(const sp &, sp &, audio_format_t sinkFormat, bool isOffload); - virtual uint32_t getUseSetBuffersFlag(); + virtual uint32_t getFlags(); virtual bool canUseSetBuffers(const sp &Meta); virtual void printFileName(int fd); diff --git a/media/libavextensions/mediaplayerservice/AVNuUtils.cpp b/media/libavextensions/mediaplayerservice/AVNuUtils.cpp index c254a70c56d..51c4a373a9e 100644 --- a/media/libavextensions/mediaplayerservice/AVNuUtils.cpp +++ b/media/libavextensions/mediaplayerservice/AVNuUtils.cpp @@ -104,7 +104,7 @@ void AVNuUtils::checkFormatChange(bool * /*formatChange*/, const sp & /*accessUnit*/) { } -uint32_t AVNuUtils::getUseSetBuffersFlag() { +uint32_t AVNuUtils::getFlags() { return 0; } diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index efdf096d678..5c68e8166df 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -175,7 +175,7 @@ status_t NuPlayer::GenericSource::initFromDataSource() { } else { extractor = MediaExtractor::Create(mDataSource, mimeType.isEmpty() ? NULL : mimeType.string(), - mIsStreaming ? 0 : AVNuUtils::get()->getUseSetBuffersFlag()); + mIsStreaming ? 0 : AVNuUtils::get()->getFlags()); } if (extractor == NULL) { From bbb9b1da50edbbed193b342be19b62e232254f27 Mon Sep 17 00:00:00 2001 From: Praveen Chavan Date: Mon, 19 Oct 2015 14:44:52 -0700 Subject: [PATCH 18/73] GenericSource: Synchronize access to dataSource DataSource and HTTPSource can be accessed/modified by GenericSource's looper and Client's thread which can lead to race conditions when copying the sp<>. Add a Mutex lock to synchronize such accesses and avoid race conditions. CRs-Fixed: 906899 Change-Id: I2fb4b4a7079e638e151f4fe67a780007a4011652 --- .../nuplayer/GenericSource.cpp | 22 ++++++++++++++----- .../nuplayer/GenericSource.h | 1 + 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index 6957a905a54..64069715543 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -126,6 +126,7 @@ status_t NuPlayer::GenericSource::setDataSource( status_t NuPlayer::GenericSource::setDataSource(const sp& source) { resetDataSource(); + Mutex::Autolock _l(mSourceLock); mDataSource = source; return OK; } @@ -372,6 +373,7 @@ void NuPlayer::GenericSource::onPrepareAsync() { } } + Mutex::Autolock _l(mSourceLock); mDataSource = DataSource::CreateFromURI( mHTTPService, uri, &mUriHeaders, &contentType, static_cast(mHttpSource.get()), @@ -379,6 +381,7 @@ void NuPlayer::GenericSource::onPrepareAsync() { } else { mIsWidevine = false; + Mutex::Autolock _l(mSourceLock); mDataSource = new FileSource(mFd, mOffset, mLength); mFd = -1; } @@ -468,6 +471,7 @@ void NuPlayer::GenericSource::finishPrepareAsync() { void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) { if (err != OK) { + Mutex::Autolock _l(mSourceLock); mDataSource.clear(); mCachedSource.clear(); mHttpSource.clear(); @@ -523,13 +527,21 @@ void NuPlayer::GenericSource::resume() { } void NuPlayer::GenericSource::disconnect() { - if (mDataSource != NULL) { + + sp dataSource; + sp httpSource; + { + Mutex::Autolock _l(mSourceLock); + dataSource = mDataSource; + httpSource = mHttpSource; + } + if (dataSource != NULL) { // disconnect data source - if (mDataSource->flags() & DataSource::kIsCachingDataSource) { - static_cast(mDataSource.get())->disconnect(); + if (dataSource->flags() & DataSource::kIsCachingDataSource) { + static_cast(dataSource.get())->disconnect(); } - } else if (mHttpSource != NULL) { - static_cast(mHttpSource.get())->disconnect(); + } else if (httpSource != NULL) { + static_cast(httpSource.get())->disconnect(); } } diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h index 01819471e90..beaee9a4aae 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.h +++ b/media/libmediaplayerservice/nuplayer/GenericSource.h @@ -136,6 +136,7 @@ struct NuPlayer::GenericSource : public NuPlayer::Source { int64_t mOffset; int64_t mLength; + Mutex mSourceLock; sp mDataSource; sp mCachedSource; sp mHttpSource; From 1dafcd15418346edb5b0fd1a925a29ea90b5c3c2 Mon Sep 17 00:00:00 2001 From: Shivaprasad Hongal Date: Fri, 23 Oct 2015 11:43:19 -0700 Subject: [PATCH 19/73] GenericSource: Hold an additional reference to dataSource. mDataSource can be deleted by client thread while GenericSource looper is accessing dataSource in sniff functions, which can lead to race condition. Add local sp<> to hold an additional reference to dataSource. Change-Id: I9e51f75f3c2bd703e381230dd93cb4d3f6621dab CRs-Fixed: 923729 --- media/libmediaplayerservice/nuplayer/GenericSource.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index 64069715543..b9cb1ca9328 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -154,7 +154,12 @@ status_t NuPlayer::GenericSource::initFromDataSource() { return UNKNOWN_ERROR; } } else if (mIsStreaming) { - if (!mDataSource->sniff(&mimeType, &confidence, &dummy)) { + sp dataSource; + { + Mutex::Autolock _l(mSourceLock); + dataSource = mDataSource; + } + if (!dataSource->sniff(&mimeType, &confidence, &dummy)) { return UNKNOWN_ERROR; } isWidevineStreaming = !strcasecmp( From a729f437f5f46efbd366721d7d4f398186ce77cd Mon Sep 17 00:00:00 2001 From: Shalaj Jain Date: Tue, 13 Oct 2015 17:56:23 -0700 Subject: [PATCH 20/73] nuplayer: Drop frames with DATACORRUPT flag Drop frames in NuplayerDecoder if the corresponding OMX_BUFFERFLAG_DATACORRUPT is set from OMX. Add a util function to easily switch off this feature. Do not declare MediaSource explicitly. Change-Id: I97bd238d52d660e1ab61eac222cdff28334cc5cc --- include/media/stagefright/MediaCodec.h | 1 + media/libavextensions/mediaplayerservice/AVNuExtensions.h | 1 + media/libavextensions/mediaplayerservice/AVNuUtils.cpp | 2 ++ media/libavextensions/stagefright/AVExtensions.h | 1 - media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp | 8 ++++++++ media/libstagefright/MediaCodec.cpp | 6 ++++++ 6 files changed, 18 insertions(+), 1 deletion(-) diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h index b0ae83b9fef..9c489e569f3 100644 --- a/include/media/stagefright/MediaCodec.h +++ b/include/media/stagefright/MediaCodec.h @@ -52,6 +52,7 @@ struct MediaCodec : public AHandler { BUFFER_FLAG_CODECCONFIG = 2, BUFFER_FLAG_EOS = 4, BUFFER_FLAG_EXTRADATA = 0x1000, + BUFFER_FLAG_DATACORRUPT = 0x2000, }; enum { diff --git a/media/libavextensions/mediaplayerservice/AVNuExtensions.h b/media/libavextensions/mediaplayerservice/AVNuExtensions.h index 7aeb5c30d12..1d45c005ad2 100644 --- a/media/libavextensions/mediaplayerservice/AVNuExtensions.h +++ b/media/libavextensions/mediaplayerservice/AVNuExtensions.h @@ -85,6 +85,7 @@ struct AVNuUtils { virtual void printFileName(int fd); virtual void checkFormatChange(bool *formatChange, const sp &accessUnit); + virtual bool dropCorruptFrame(); // ----- NO TRESSPASSING BEYOND THIS LINE ------ DECLARE_LOADABLE_SINGLETON(AVNuUtils); diff --git a/media/libavextensions/mediaplayerservice/AVNuUtils.cpp b/media/libavextensions/mediaplayerservice/AVNuUtils.cpp index 51c4a373a9e..95f64544329 100644 --- a/media/libavextensions/mediaplayerservice/AVNuUtils.cpp +++ b/media/libavextensions/mediaplayerservice/AVNuUtils.cpp @@ -112,6 +112,8 @@ bool AVNuUtils::canUseSetBuffers(const sp &/*Meta*/) { return false; } +bool AVNuUtils::dropCorruptFrame() { return false; } + // ----- NO TRESSPASSING BEYOND THIS LINE ------ AVNuUtils::AVNuUtils() {} diff --git a/media/libavextensions/stagefright/AVExtensions.h b/media/libavextensions/stagefright/AVExtensions.h index b45c0513df4..891c7f85f69 100644 --- a/media/libavextensions/stagefright/AVExtensions.h +++ b/media/libavextensions/stagefright/AVExtensions.h @@ -47,7 +47,6 @@ struct ACodec; struct ALooper; struct IMediaHTTPConnection; struct MediaCodec; -struct MediaSource; struct MediaHTTP; struct NuCachedSource2; class CameraParameters; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index f83eaf6419e..997920b4f5d 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -590,6 +590,14 @@ bool NuPlayer::Decoder::handleAnOutputBuffer( reply->setSize("buffer-ix", index); reply->setInt32("generation", mBufferGeneration); + if ((flags & MediaCodec::BUFFER_FLAG_DATACORRUPT) && + AVNuUtils::get()->dropCorruptFrame()) { + ALOGV("[%s] dropping corrupt buffer at time %lld as requested.", + mComponentName.c_str(), (long long)timeUs); + reply->post(); + return true; + } + if (eos) { ALOGI("[%s] saw output EOS", mIsAudio ? "audio" : "video"); diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index 7f7c7fa19b2..3ae20562aa4 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -987,6 +987,9 @@ bool MediaCodec::handleDequeueOutputBuffer(const sp &replyID, bool if (omxFlags & OMX_BUFFERFLAG_EXTRADATA) { flags |= BUFFER_FLAG_EXTRADATA; } + if (omxFlags & OMX_BUFFERFLAG_DATACORRUPT) { + flags |= BUFFER_FLAG_DATACORRUPT; + } response->setInt32("flags", flags); response->postReply(replyID); @@ -2631,6 +2634,9 @@ void MediaCodec::onOutputBufferAvailable() { if (omxFlags & OMX_BUFFERFLAG_EOS) { flags |= BUFFER_FLAG_EOS; } + if (omxFlags & OMX_BUFFERFLAG_DATACORRUPT) { + flags |= BUFFER_FLAG_DATACORRUPT; + } msg->setInt32("flags", flags); From 4f33629b62ad90687973c8496d9b60f4f18e26b1 Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Fri, 4 Sep 2015 14:15:58 -0700 Subject: [PATCH 21/73] DO NOT MERGE: CameraService: Link to client binder death at end of connect If, within a binder Looper thread, a Binder object death notifier is registered, and then a nested Binder transaction is begun, that transaction may process a death notification callback for the just-registered object, if it was dead at the time of registration. This can lead to an unexpected nested call into the service, and cause deadlock. To avoid this, move the death notifier registration to the end of handling the connect transaction. Also remove one extra bit of disconnect logging. Bug: 23525545 Change-Id: If01cbaf42704f55134118afefc9a8f7bdb014e09 --- services/camera/libcameraservice/CameraService.cpp | 14 +++++++++++--- services/camera/libcameraservice/CameraService.h | 5 ----- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index 9a1101a8df2..e4f792d9478 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -935,6 +935,16 @@ void CameraService::finishConnectLocked(const sp& client, LOG_ALWAYS_FATAL("%s: Invalid state for CameraService, clients not evicted properly", __FUNCTION__); } + + // And register a death notification for the client callback. Do + // this last to avoid Binder policy where a nested Binder + // transaction might be pre-empted to service the client death + // notification if the client process dies before linkToDeath is + // invoked. + sp remoteCallback = client->getRemote(); + if (remoteCallback != nullptr) { + remoteCallback->linkToDeath(this); + } } status_t CameraService::handleEvictionsLocked(const String8& cameraId, int clientPid, @@ -1874,11 +1884,9 @@ CameraService::BasicClient::~BasicClient() { void CameraService::BasicClient::disconnect() { if (mDisconnected) { - ALOGE("%s: Disconnect called on already disconnected client for device %d", __FUNCTION__, - mCameraId); return; } - mDisconnected = true;; + mDisconnected = true; mCameraService->removeByClient(this); mCameraService->logDisconnected(String8::format("%d", mCameraId), mClientPid, diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h index b56c161e8c0..b29317ebccf 100644 --- a/services/camera/libcameraservice/CameraService.h +++ b/services/camera/libcameraservice/CameraService.h @@ -861,11 +861,6 @@ status_t CameraService::connectHelper(const sp& cameraCb, const String return ret; } - sp remoteCallback = client->getRemote(); - if (remoteCallback != nullptr) { - remoteCallback->linkToDeath(this); - } - // Update shim paremeters for legacy clients if (effectiveApiLevel == API_1) { // Assume we have always received a Client subclass for API1 From f72f7d57142cd3415bc189a8a9dee39674117167 Mon Sep 17 00:00:00 2001 From: Susmitha Gummalla Date: Thu, 8 Oct 2015 16:00:33 -0700 Subject: [PATCH 22/73] Camera: frameworks: Add NULL check for callback --Added NULL check for mRemoteCallback Change-Id: Ib88a128a52e81b8ec1052e3222b6d8b9e494afcc --- services/camera/libcameraservice/CameraService.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index 9a1101a8df2..26c8007a10e 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -2024,7 +2024,11 @@ sp CameraService::Client::getClientFromCookie(void* user) void CameraService::Client::notifyError(ICameraDeviceCallbacks::CameraErrorCode errorCode, const CaptureResultExtras& resultExtras) { - mRemoteCallback->notifyCallback(CAMERA_MSG_ERROR, CAMERA_ERROR_RELEASED, 0); + if (mRemoteCallback != NULL) { + mRemoteCallback->notifyCallback(CAMERA_MSG_ERROR, CAMERA_ERROR_RELEASED, 0); + } else { + ALOGE("mRemoteCallback is NULL!!"); + } } // NOTE: function is idempotent From 1fb6c97d6cf1ae3264605d912b4e034809e2103a Mon Sep 17 00:00:00 2001 From: Haynes Mathew George Date: Mon, 26 Oct 2015 18:22:13 -0700 Subject: [PATCH 23/73] AudioPolicyService: Synchronize access to AudioPolicyManager Synchronize access to APM when getDevicesForStream is called on APM. CRs-Fixed: 913227 Change-Id: I2ba6922341f035375270b02000ef5a7e078f6b5a --- services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp index 793c26a1d6a..58ecb111446 100644 --- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp +++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp @@ -459,6 +459,7 @@ audio_devices_t AudioPolicyService::getDevicesForStream(audio_stream_type_t stre if (mAudioPolicyManager == NULL) { return AUDIO_DEVICE_NONE; } + Mutex::Autolock _l(mLock); return mAudioPolicyManager->getDevicesForStream(stream); } From f17204ea09e5629f3f9d9eba2e66d9fb6ce72357 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Wed, 23 Sep 2015 10:25:31 -0700 Subject: [PATCH 24/73] AudioPolicyService: fix race in AudioCommandThread Fixe race condition in AudioCommandThread::threadLoop() where a command can be inserted in first position in the queue after the sleep time has been calculated causing a longer delay than expected. Also fix a failure to hold a wake lock while commands are still in the queue. Bug: 22707905. Change-Id: I813626986677bf00106acb37ee20d3dd75d5cf33 --- .../service/AudioPolicyService.cpp | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp index d6890657ca4..41dd40ce578 100644 --- a/services/audiopolicy/service/AudioPolicyService.cpp +++ b/services/audiopolicy/service/AudioPolicyService.cpp @@ -577,22 +577,28 @@ bool AudioPolicyService::AudioCommandThread::threadLoop() } } waitTime = INT64_MAX; + // release mLock before releasing strong reference on the service as + // AudioPolicyService destructor calls AudioCommandThread::exit() which + // acquires mLock. + mLock.unlock(); + svc.clear(); + mLock.lock(); } else { waitTime = mAudioCommands[0]->mTime - curTime; break; } } - // release mLock before releasing strong reference on the service as - // AudioPolicyService destructor calls AudioCommandThread::exit() which acquires mLock. - mLock.unlock(); - svc.clear(); - mLock.lock(); - if (!exitPending() && (mAudioCommands.isEmpty() || waitTime != INT64_MAX)) { - // release delayed commands wake lock + + // release delayed commands wake lock if the queue is empty + if (mAudioCommands.isEmpty()) { release_wake_lock(mName.string()); + } + + // At this stage we have either an empty command queue or the first command in the queue + // has a finite delay. So unless we are exiting it is safe to wait. + if (!exitPending()) { ALOGV("AudioCommandThread() going to sleep"); mWaitWorkCV.waitRelative(mLock, waitTime); - ALOGV("AudioCommandThread() waking up"); } } // release delayed commands wake lock before quitting @@ -1005,6 +1011,8 @@ void AudioPolicyService::AudioCommandThread::exit() requestExit(); mWaitWorkCV.signal(); } + // Note that we can call it from the thread loop if all other references have been released + // but it will safely return WOULD_BLOCK in this case requestExitAndWait(); } From 14896d6fa21cb76e50b1d6a80527f52067c3a99b Mon Sep 17 00:00:00 2001 From: Sharad Sangle Date: Thu, 8 Oct 2015 23:59:08 +0530 Subject: [PATCH 25/73] audio: use QTI flac decoder based on flag While setting up the component for flac, current design is if encoder then don't use QTI flac component otherwise use QTI flac component, so if QTI flac is not being used then this might be wrong. So enhance the design to use QTI flac component only when it is enabled, otherwise use default flac component Change-Id: I57454841611885ae7cdf75896f8297ef8132292e CRs-Fixed: 916650 --- media/libstagefright/ACodec.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 3c80d03a380..f40a3c4b845 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -2073,7 +2073,11 @@ status_t ACodec::configureCodec( } err = setupG711Codec(encoder, sampleRate, numChannels); } +#ifdef QTI_FLAC_DECODER } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC) && encoder) { +#else + } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC)) { +#endif int32_t numChannels = 0, sampleRate = 0, compressionLevel = -1; if (encoder && (!msg->findInt32("channel-count", &numChannels) From b987753ada64c5824672ea70f92fe603f849d4b6 Mon Sep 17 00:00:00 2001 From: Manoj Kumar AVM Date: Thu, 30 Apr 2015 10:24:11 -0700 Subject: [PATCH 26/73] stagefright: Add null check before passing meta data buffer Add necessary null checks to GraphicBuffer before passing it onto Metadatabuffer. Change-Id: I5cf09da4bd316e5c1733023746aa54960a36d8c9 --- media/libstagefright/SurfaceMediaSource.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp index e8abf48cabd..7da5a9f4001 100644 --- a/media/libstagefright/SurfaceMediaSource.cpp +++ b/media/libstagefright/SurfaceMediaSource.cpp @@ -360,7 +360,11 @@ status_t SurfaceMediaSource::read( mNumFramesEncoded++; // Pass the data to the MediaBuffer. Pass in only the metadata - + if (mSlots[mCurrentSlot].mGraphicBuffer == NULL) { + ALOGV("Read: SurfaceMediaSource mGraphicBuffer is null. Returning" + "ERROR_END_OF_STREAM."); + return ERROR_END_OF_STREAM; + } passMetadataBuffer(buffer, mSlots[mCurrentSlot].mGraphicBuffer->handle); (*buffer)->setObserver(this); From 262a62c19e8b09c4e6b271c9522e7eb318e0d574 Mon Sep 17 00:00:00 2001 From: Tatenda Chipeperekwa Date: Wed, 2 Jul 2014 19:09:04 -0700 Subject: [PATCH 27/73] libstagefright: Add WFD specific flags to consumer usage flags Add the GRALLOC_USAGE_PRIVATE_WFD flag to the consumer usage flags to allow the display framework to distinguish WFD from other virtual display connections. Change-Id: I7cdbac3716fb5c18d1691701accb8e66f388de86 --- media/libstagefright/Android.mk | 5 +++++ media/libstagefright/SurfaceMediaSource.cpp | 11 +++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index b2729af2ed8..9687c7d3c78 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -132,6 +132,11 @@ LOCAL_SHARED_LIBRARIES += \ LOCAL_CFLAGS += -Wno-multichar -Werror -Wno-error=deprecated-declarations -Wall +ifeq ($(TARGET_USES_QCOM_BSP), true) + LOCAL_C_INCLUDES += hardware/qcom/display/libgralloc + LOCAL_CFLAGS += -DQTI_BSP +endif + # enable experiments only in userdebug and eng builds ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT))) LOCAL_CFLAGS += -DENABLE_STAGEFRIGHT_EXPERIMENTS diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp index e8abf48cabd..a0d55f56181 100644 --- a/media/libstagefright/SurfaceMediaSource.cpp +++ b/media/libstagefright/SurfaceMediaSource.cpp @@ -35,6 +35,9 @@ #include #include +#if QTI_BSP +#include +#endif namespace android { @@ -59,8 +62,12 @@ SurfaceMediaSource::SurfaceMediaSource(uint32_t bufferWidth, uint32_t bufferHeig BufferQueue::createBufferQueue(&mProducer, &mConsumer); mConsumer->setDefaultBufferSize(bufferWidth, bufferHeight); - mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER | - GRALLOC_USAGE_HW_TEXTURE); + mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER + | GRALLOC_USAGE_HW_TEXTURE +#if QTI_BSP + | GRALLOC_USAGE_PRIVATE_WFD +#endif + ); sp composer(ComposerService::getComposerService()); From 0c32de1af285bb3680d87ac70e064e5449c5fe99 Mon Sep 17 00:00:00 2001 From: Jeff Tinker Date: Wed, 26 Aug 2015 20:22:39 -0700 Subject: [PATCH 28/73] Fix for security vulnerability in media server bug: 23540426 Change-Id: Ifb12ac3350410a49ba7d81d1bde12822c3008cd5 --- media/libmedia/ICrypto.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/media/libmedia/ICrypto.cpp b/media/libmedia/ICrypto.cpp index 8f05936c0ec..53b105d7a7e 100644 --- a/media/libmedia/ICrypto.cpp +++ b/media/libmedia/ICrypto.cpp @@ -308,7 +308,25 @@ status_t BnCrypto::onTransact( AString errorDetailMsg; ssize_t result; - if (offset + totalSize > sharedBuffer->size()) { + size_t sumSubsampleSizes = 0; + bool overflow = false; + for (int32_t i = 0; i < numSubSamples; ++i) { + CryptoPlugin::SubSample &ss = subSamples[i]; + if (sumSubsampleSizes <= SIZE_MAX - ss.mNumBytesOfEncryptedData) { + sumSubsampleSizes += ss.mNumBytesOfEncryptedData; + } else { + overflow = true; + } + if (sumSubsampleSizes <= SIZE_MAX - ss.mNumBytesOfClearData) { + sumSubsampleSizes += ss.mNumBytesOfClearData; + } else { + overflow = true; + } + } + + if (overflow || sumSubsampleSizes != totalSize) { + result = -EINVAL; + } else if (offset + totalSize > sharedBuffer->size()) { result = -EINVAL; } else { result = decrypt( From b3e77a77cbd27ba3da1e2931c29eb4af569d4e15 Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Thu, 27 Aug 2015 13:49:32 -0700 Subject: [PATCH 29/73] Fix timedtext parsing Add bounds checking and fix other bugs. Bug: 23284974 Bug: 23541506 Bug: 23542351 Bug: 23542352 Change-Id: I53551efdf109ce1833e0c361efaf4cee7a851023 --- .../timedtext/TextDescriptions.cpp | 627 +++++++++++------- .../timedtext/TextDescriptions.h | 4 +- 2 files changed, 377 insertions(+), 254 deletions(-) diff --git a/media/libstagefright/timedtext/TextDescriptions.cpp b/media/libstagefright/timedtext/TextDescriptions.cpp index f9c1fe09380..c762a74d08f 100644 --- a/media/libstagefright/timedtext/TextDescriptions.cpp +++ b/media/libstagefright/timedtext/TextDescriptions.cpp @@ -30,9 +30,9 @@ status_t TextDescriptions::getParcelOfDescriptions( if (flags & IN_BAND_TEXT_3GPP) { if (flags & GLOBAL_DESCRIPTIONS) { - return extract3GPPGlobalDescriptions(data, size, parcel, 0); + return extract3GPPGlobalDescriptions(data, size, parcel); } else if (flags & LOCAL_DESCRIPTIONS) { - return extract3GPPLocalDescriptions(data, size, timeMs, parcel, 0); + return extract3GPPLocalDescriptions(data, size, timeMs, parcel); } } else if (flags & OUT_OF_BAND_TEXT_SRT) { if (flags & LOCAL_DESCRIPTIONS) { @@ -69,314 +69,437 @@ status_t TextDescriptions::extractSRTLocalDescriptions( // styles, and 'krok' box contains karaoke timing and positions. status_t TextDescriptions::extract3GPPLocalDescriptions( const uint8_t *data, ssize_t size, - int timeMs, Parcel *parcel, int depth) { - if (depth == 0) { - parcel->writeInt32(KEY_LOCAL_SETTING); - - // write start time to display this text sample - parcel->writeInt32(KEY_START_TIME); - parcel->writeInt32(timeMs); - - ssize_t textLen = (*data) << 8 | (*(data + 1)); - - // write text sample length and text sample itself - parcel->writeInt32(KEY_STRUCT_TEXT); - parcel->writeInt32(textLen); - parcel->writeInt32(textLen); - parcel->write(data + 2, textLen); - - if (size > textLen) { - data += (textLen + 2); - size -= (textLen + 2); - } else { - return OK; - } + int timeMs, Parcel *parcel) { + + parcel->writeInt32(KEY_LOCAL_SETTING); + + // write start time to display this text sample + parcel->writeInt32(KEY_START_TIME); + parcel->writeInt32(timeMs); + + if (size < 2) { + return OK; } + ssize_t textLen = (*data) << 8 | (*(data + 1)); - const uint8_t *tmpData = data; - ssize_t chunkSize = U32_AT(tmpData); - uint32_t chunkType = U32_AT(tmpData + 4); + if (size < textLen + 2) { + return OK; + } - if (chunkSize <= 0) { + // write text sample length and text sample itself + parcel->writeInt32(KEY_STRUCT_TEXT); + parcel->writeInt32(textLen); + parcel->writeInt32(textLen); + parcel->write(data + 2, textLen); + + if (size > textLen + 2) { + data += (textLen + 2); + size -= (textLen + 2); + } else { return OK; } - tmpData += 8; + while (size >= 8) { + const uint8_t *tmpData = data; + ssize_t chunkSize = U32_AT(tmpData); // size includes size and type + uint32_t chunkType = U32_AT(tmpData + 4); - switch(chunkType) { - // 'styl' box specifies the style of the text. - case FOURCC('s', 't', 'y', 'l'): - { - uint16_t count = U16_AT(tmpData); + if (chunkSize <= 8 || chunkSize > size) { + return OK; + } - tmpData += 2; + size_t remaining = chunkSize - 8; - for (int i = 0; i < count; i++) { - parcel->writeInt32(KEY_STRUCT_STYLE_LIST); - parcel->writeInt32(KEY_START_CHAR); - parcel->writeInt32(U16_AT(tmpData)); + tmpData += 8; - parcel->writeInt32(KEY_END_CHAR); - parcel->writeInt32(U16_AT(tmpData + 2)); + switch(chunkType) { + // 'styl' box specifies the style of the text. + case FOURCC('s', 't', 'y', 'l'): + { + if (remaining < 2) { + return OK; + } + size_t dataPos = parcel->dataPosition(); + uint16_t count = U16_AT(tmpData); - parcel->writeInt32(KEY_FONT_ID); - parcel->writeInt32(U16_AT(tmpData + 4)); + tmpData += 2; + remaining -= 2; - parcel->writeInt32(KEY_STYLE_FLAGS); - parcel->writeInt32(*(tmpData + 6)); + for (int i = 0; i < count; i++) { + if (remaining < 12) { + // roll back + parcel->setDataPosition(dataPos); + return OK; + } + parcel->writeInt32(KEY_STRUCT_STYLE_LIST); + parcel->writeInt32(KEY_START_CHAR); + parcel->writeInt32(U16_AT(tmpData)); - parcel->writeInt32(KEY_FONT_SIZE); - parcel->writeInt32(*(tmpData + 7)); + parcel->writeInt32(KEY_END_CHAR); + parcel->writeInt32(U16_AT(tmpData + 2)); - parcel->writeInt32(KEY_TEXT_COLOR_RGBA); - uint32_t rgba = *(tmpData + 8) << 24 | *(tmpData + 9) << 16 - | *(tmpData + 10) << 8 | *(tmpData + 11); - parcel->writeInt32(rgba); + parcel->writeInt32(KEY_FONT_ID); + parcel->writeInt32(U16_AT(tmpData + 4)); - tmpData += 12; + parcel->writeInt32(KEY_STYLE_FLAGS); + parcel->writeInt32(*(tmpData + 6)); + + parcel->writeInt32(KEY_FONT_SIZE); + parcel->writeInt32(*(tmpData + 7)); + + parcel->writeInt32(KEY_TEXT_COLOR_RGBA); + uint32_t rgba = *(tmpData + 8) << 24 | *(tmpData + 9) << 16 + | *(tmpData + 10) << 8 | *(tmpData + 11); + parcel->writeInt32(rgba); + + tmpData += 12; + remaining -= 12; + } + + break; + } + // 'krok' box. The number of highlight events is specified, and each + // event is specified by a starting and ending char offset and an end + // time for the event. + case FOURCC('k', 'r', 'o', 'k'): + { + if (remaining < 6) { + return OK; + } + size_t dataPos = parcel->dataPosition(); + + parcel->writeInt32(KEY_STRUCT_KARAOKE_LIST); + + int startTime = U32_AT(tmpData); + uint16_t count = U16_AT(tmpData + 4); + parcel->writeInt32(count); + + tmpData += 6; + remaining -= 6; + int lastEndTime = 0; + + for (int i = 0; i < count; i++) { + if (remaining < 8) { + // roll back + parcel->setDataPosition(dataPos); + return OK; + } + parcel->writeInt32(startTime + lastEndTime); + + lastEndTime = U32_AT(tmpData); + parcel->writeInt32(lastEndTime); + + parcel->writeInt32(U16_AT(tmpData + 4)); + parcel->writeInt32(U16_AT(tmpData + 6)); + + tmpData += 8; + remaining -= 8; + } + + break; } + // 'hlit' box specifies highlighted text + case FOURCC('h', 'l', 'i', 't'): + { + if (remaining < 4) { + return OK; + } - break; - } - // 'krok' box. The number of highlight events is specified, and each - // event is specified by a starting and ending char offset and an end - // time for the event. - case FOURCC('k', 'r', 'o', 'k'): - { + parcel->writeInt32(KEY_STRUCT_HIGHLIGHT_LIST); - parcel->writeInt32(KEY_STRUCT_KARAOKE_LIST); + // the start char offset to highlight + parcel->writeInt32(U16_AT(tmpData)); + // the last char offset to highlight + parcel->writeInt32(U16_AT(tmpData + 2)); - int startTime = U32_AT(tmpData); - uint16_t count = U16_AT(tmpData + 4); - parcel->writeInt32(count); + tmpData += 4; + remaining -= 4; + break; + } + // 'hclr' box specifies the RGBA color: 8 bits each of + // red, green, blue, and an alpha(transparency) value + case FOURCC('h', 'c', 'l', 'r'): + { + if (remaining < 4) { + return OK; + } + parcel->writeInt32(KEY_HIGHLIGHT_COLOR_RGBA); + + uint32_t rgba = *(tmpData) << 24 | *(tmpData + 1) << 16 + | *(tmpData + 2) << 8 | *(tmpData + 3); + parcel->writeInt32(rgba); + + tmpData += 4; + remaining -= 4; + break; + } + // 'dlay' box specifies a delay after a scroll in and/or + // before scroll out. + case FOURCC('d', 'l', 'a', 'y'): + { + if (remaining < 4) { + return OK; + } + parcel->writeInt32(KEY_SCROLL_DELAY); + + uint32_t delay = *(tmpData) << 24 | *(tmpData + 1) << 16 + | *(tmpData + 2) << 8 | *(tmpData + 3); + parcel->writeInt32(delay); + + tmpData += 4; + remaining -= 4; + break; + } + // 'href' box for hyper text link + case FOURCC('h', 'r', 'e', 'f'): + { + if (remaining < 5) { + return OK; + } - tmpData += 6; - int lastEndTime = 0; + size_t dataPos = parcel->dataPosition(); - for (int i = 0; i < count; i++) { - parcel->writeInt32(startTime + lastEndTime); + parcel->writeInt32(KEY_STRUCT_HYPER_TEXT_LIST); - lastEndTime = U32_AT(tmpData); - parcel->writeInt32(lastEndTime); + // the start offset of the text to be linked + parcel->writeInt32(U16_AT(tmpData)); + // the end offset of the text + parcel->writeInt32(U16_AT(tmpData + 2)); + // the number of bytes in the following URL + size_t len = *(tmpData + 4); + parcel->writeInt32(len); + + remaining -= 5; + + if (remaining < len) { + parcel->setDataPosition(dataPos); + return OK; + } + // the linked-to URL + parcel->writeInt32(len); + parcel->write(tmpData + 5, len); + + tmpData += (5 + len); + remaining -= len; + + if (remaining < 1) { + parcel->setDataPosition(dataPos); + return OK; + } + + // the number of bytes in the following "alt" string + len = *tmpData; + parcel->writeInt32(len); + + tmpData += 1; + remaining -= 1; + if (remaining < len) { + parcel->setDataPosition(dataPos); + return OK; + } + + // an "alt" string for user display + parcel->writeInt32(len); + parcel->write(tmpData, len); + + tmpData += 1; + remaining -= 1; + break; + } + // 'tbox' box to indicate the position of the text with values + // of top, left, bottom and right + case FOURCC('t', 'b', 'o', 'x'): + { + if (remaining < 8) { + return OK; + } + parcel->writeInt32(KEY_STRUCT_TEXT_POS); + parcel->writeInt32(U16_AT(tmpData)); + parcel->writeInt32(U16_AT(tmpData + 2)); parcel->writeInt32(U16_AT(tmpData + 4)); parcel->writeInt32(U16_AT(tmpData + 6)); tmpData += 8; + remaining -= 8; + break; } + // 'blnk' to specify the char range to be blinked + case FOURCC('b', 'l', 'n', 'k'): + { + if (remaining < 4) { + return OK; + } - break; - } - // 'hlit' box specifies highlighted text - case FOURCC('h', 'l', 'i', 't'): - { - parcel->writeInt32(KEY_STRUCT_HIGHLIGHT_LIST); + parcel->writeInt32(KEY_STRUCT_BLINKING_TEXT_LIST); - // the start char offset to highlight - parcel->writeInt32(U16_AT(tmpData)); - // the last char offset to highlight - parcel->writeInt32(U16_AT(tmpData + 2)); + // start char offset + parcel->writeInt32(U16_AT(tmpData)); + // end char offset + parcel->writeInt32(U16_AT(tmpData + 2)); - break; + tmpData += 4; + remaining -= 4; + break; + } + // 'twrp' box specifies text wrap behavior. If the value if 0x00, + // then no wrap. If it's 0x01, then automatic 'soft' wrap is enabled. + // 0x02-0xff are reserved. + case FOURCC('t', 'w', 'r', 'p'): + { + if (remaining < 1) { + return OK; + } + parcel->writeInt32(KEY_WRAP_TEXT); + parcel->writeInt32(*tmpData); + + tmpData += 1; + remaining -= 1; + break; + } + default: + { + break; + } } - // 'hclr' box specifies the RGBA color: 8 bits each of - // red, green, blue, and an alpha(transparency) value - case FOURCC('h', 'c', 'l', 'r'): - { - parcel->writeInt32(KEY_HIGHLIGHT_COLOR_RGBA); - uint32_t rgba = *(tmpData) << 24 | *(tmpData + 1) << 16 - | *(tmpData + 2) << 8 | *(tmpData + 3); - parcel->writeInt32(rgba); + data += chunkSize; + size -= chunkSize; + } + + return OK; +} - break; - } - // 'dlay' box specifies a delay after a scroll in and/or - // before scroll out. - case FOURCC('d', 'l', 'a', 'y'): - { - parcel->writeInt32(KEY_SCROLL_DELAY); +// To extract box 'tx3g' defined in 3GPP TS 26.245, and store it in a Parcel +status_t TextDescriptions::extract3GPPGlobalDescriptions( + const uint8_t *data, ssize_t size, Parcel *parcel) { + + parcel->writeInt32(KEY_GLOBAL_SETTING); - uint32_t delay = *(tmpData) << 24 | *(tmpData + 1) << 16 - | *(tmpData + 2) << 8 | *(tmpData + 3); - parcel->writeInt32(delay); + while (size >= 8) { + ssize_t chunkSize = U32_AT(data); + uint32_t chunkType = U32_AT(data + 4); + const uint8_t *tmpData = data; + tmpData += 8; + size_t remaining = size - 8; - break; + if (size < chunkSize) { + return OK; } - // 'href' box for hyper text link - case FOURCC('h', 'r', 'e', 'f'): - { - parcel->writeInt32(KEY_STRUCT_HYPER_TEXT_LIST); + switch(chunkType) { + case FOURCC('t', 'x', '3', 'g'): + { + if (remaining < 18) { // 8 just below, and another 10 a little further down + return OK; + } + tmpData += 8; // skip the first 8 bytes + remaining -=8; + parcel->writeInt32(KEY_DISPLAY_FLAGS); + parcel->writeInt32(U32_AT(tmpData)); + + parcel->writeInt32(KEY_STRUCT_JUSTIFICATION); + parcel->writeInt32(tmpData[4]); + parcel->writeInt32(tmpData[5]); + + parcel->writeInt32(KEY_BACKGROUND_COLOR_RGBA); + uint32_t rgba = *(tmpData + 6) << 24 | *(tmpData + 7) << 16 + | *(tmpData + 8) << 8 | *(tmpData + 9); + parcel->writeInt32(rgba); - // the start offset of the text to be linked - parcel->writeInt32(U16_AT(tmpData)); - // the end offset of the text - parcel->writeInt32(U16_AT(tmpData + 2)); + tmpData += 10; + remaining -= 10; - // the number of bytes in the following URL - int len = *(tmpData + 4); - parcel->writeInt32(len); + if (remaining < 8) { + return OK; + } + parcel->writeInt32(KEY_STRUCT_TEXT_POS); + parcel->writeInt32(U16_AT(tmpData)); + parcel->writeInt32(U16_AT(tmpData + 2)); + parcel->writeInt32(U16_AT(tmpData + 4)); + parcel->writeInt32(U16_AT(tmpData + 6)); - // the linked-to URL - parcel->writeInt32(len); - parcel->write(tmpData + 5, len); + tmpData += 8; + remaining -= 8; - tmpData += (5 + len); + if (remaining < 12) { + return OK; + } + parcel->writeInt32(KEY_STRUCT_STYLE_LIST); + parcel->writeInt32(KEY_START_CHAR); + parcel->writeInt32(U16_AT(tmpData)); - // the number of bytes in the following "alt" string - len = *tmpData; - parcel->writeInt32(len); + parcel->writeInt32(KEY_END_CHAR); + parcel->writeInt32(U16_AT(tmpData + 2)); - // an "alt" string for user display - parcel->writeInt32(len); - parcel->write(tmpData + 1, len); + parcel->writeInt32(KEY_FONT_ID); + parcel->writeInt32(U16_AT(tmpData + 4)); - break; - } - // 'tbox' box to indicate the position of the text with values - // of top, left, bottom and right - case FOURCC('t', 'b', 'o', 'x'): - { - parcel->writeInt32(KEY_STRUCT_TEXT_POS); - parcel->writeInt32(U16_AT(tmpData)); - parcel->writeInt32(U16_AT(tmpData + 2)); - parcel->writeInt32(U16_AT(tmpData + 4)); - parcel->writeInt32(U16_AT(tmpData + 6)); - - break; - } - // 'blnk' to specify the char range to be blinked - case FOURCC('b', 'l', 'n', 'k'): - { - parcel->writeInt32(KEY_STRUCT_BLINKING_TEXT_LIST); + parcel->writeInt32(KEY_STYLE_FLAGS); + parcel->writeInt32(*(tmpData + 6)); - // start char offset - parcel->writeInt32(U16_AT(tmpData)); - // end char offset - parcel->writeInt32(U16_AT(tmpData + 2)); + parcel->writeInt32(KEY_FONT_SIZE); + parcel->writeInt32(*(tmpData + 7)); - break; - } - // 'twrp' box specifies text wrap behavior. If the value if 0x00, - // then no wrap. If it's 0x01, then automatic 'soft' wrap is enabled. - // 0x02-0xff are reserved. - case FOURCC('t', 'w', 'r', 'p'): - { - parcel->writeInt32(KEY_WRAP_TEXT); - parcel->writeInt32(*tmpData); - - break; - } - default: - { - break; - } - } + parcel->writeInt32(KEY_TEXT_COLOR_RGBA); + rgba = *(tmpData + 8) << 24 | *(tmpData + 9) << 16 + | *(tmpData + 10) << 8 | *(tmpData + 11); + parcel->writeInt32(rgba); - if (size > chunkSize) { - data += chunkSize; - size -= chunkSize; - // continue to parse next box - return extract3GPPLocalDescriptions(data, size, 0, parcel, 1); - } + tmpData += 12; + remaining -= 12; - return OK; -} + if (remaining < 2) { + return OK; + } -// To extract box 'tx3g' defined in 3GPP TS 26.245, and store it in a Parcel -status_t TextDescriptions::extract3GPPGlobalDescriptions( - const uint8_t *data, ssize_t size, Parcel *parcel, int depth) { + size_t dataPos = parcel->dataPosition(); - ssize_t chunkSize = U32_AT(data); - uint32_t chunkType = U32_AT(data + 4); - const uint8_t *tmpData = data; - tmpData += 8; + parcel->writeInt32(KEY_STRUCT_FONT_LIST); + uint16_t count = U16_AT(tmpData); + parcel->writeInt32(count); - if (size < chunkSize) { - return OK; - } + tmpData += 2; + remaining -= 2; - if (depth == 0) { - parcel->writeInt32(KEY_GLOBAL_SETTING); - } - switch(chunkType) { - case FOURCC('t', 'x', '3', 'g'): - { - tmpData += 8; // skip the first 8 bytes - parcel->writeInt32(KEY_DISPLAY_FLAGS); - parcel->writeInt32(U32_AT(tmpData)); - - parcel->writeInt32(KEY_STRUCT_JUSTIFICATION); - parcel->writeInt32(tmpData[4]); - parcel->writeInt32(tmpData[5]); - - parcel->writeInt32(KEY_BACKGROUND_COLOR_RGBA); - uint32_t rgba = *(tmpData + 6) << 24 | *(tmpData + 7) << 16 - | *(tmpData + 8) << 8 | *(tmpData + 9); - parcel->writeInt32(rgba); - - tmpData += 10; - parcel->writeInt32(KEY_STRUCT_TEXT_POS); - parcel->writeInt32(U16_AT(tmpData)); - parcel->writeInt32(U16_AT(tmpData + 2)); - parcel->writeInt32(U16_AT(tmpData + 4)); - parcel->writeInt32(U16_AT(tmpData + 6)); - - tmpData += 8; - parcel->writeInt32(KEY_STRUCT_STYLE_LIST); - parcel->writeInt32(KEY_START_CHAR); - parcel->writeInt32(U16_AT(tmpData)); - - parcel->writeInt32(KEY_END_CHAR); - parcel->writeInt32(U16_AT(tmpData + 2)); - - parcel->writeInt32(KEY_FONT_ID); - parcel->writeInt32(U16_AT(tmpData + 4)); - - parcel->writeInt32(KEY_STYLE_FLAGS); - parcel->writeInt32(*(tmpData + 6)); - - parcel->writeInt32(KEY_FONT_SIZE); - parcel->writeInt32(*(tmpData + 7)); - - parcel->writeInt32(KEY_TEXT_COLOR_RGBA); - rgba = *(tmpData + 8) << 24 | *(tmpData + 9) << 16 - | *(tmpData + 10) << 8 | *(tmpData + 11); - parcel->writeInt32(rgba); - - tmpData += 12; - parcel->writeInt32(KEY_STRUCT_FONT_LIST); - uint16_t count = U16_AT(tmpData); - parcel->writeInt32(count); - - tmpData += 2; - for (int i = 0; i < count; i++) { - // font ID - parcel->writeInt32(U16_AT(tmpData)); + for (int i = 0; i < count; i++) { + if (remaining < 3) { + // roll back + parcel->setDataPosition(dataPos); + return OK; + } + // font ID + parcel->writeInt32(U16_AT(tmpData)); - // font name length - parcel->writeInt32(*(tmpData + 2)); + // font name length + parcel->writeInt32(*(tmpData + 2)); - int len = *(tmpData + 2); + size_t len = *(tmpData + 2); - parcel->write(tmpData + 3, len); - tmpData += 3 + len; - } + tmpData += 3; + remaining -= 3; - break; - } - default: - { - break; - } - } + if (remaining < len) { + // roll back + parcel->setDataPosition(dataPos); + return OK; + } - data += chunkSize; - size -= chunkSize; + parcel->write(tmpData, len); + tmpData += len; + remaining -= len; + } - if (size > 0) { - // continue to extract next 'tx3g' - return extract3GPPGlobalDescriptions(data, size, parcel, 1); + // there is a "DisparityBox" after this according to the spec, but we ignore it + break; + } + default: + { + break; + } + } + + data += chunkSize; + size -= chunkSize; } return OK; diff --git a/media/libstagefright/timedtext/TextDescriptions.h b/media/libstagefright/timedtext/TextDescriptions.h index 0144917505e..bf67f3f8634 100644 --- a/media/libstagefright/timedtext/TextDescriptions.h +++ b/media/libstagefright/timedtext/TextDescriptions.h @@ -72,10 +72,10 @@ class TextDescriptions { int timeMs, Parcel *parcel); static status_t extract3GPPGlobalDescriptions( const uint8_t *data, ssize_t size, - Parcel *parcel, int depth); + Parcel *parcel); static status_t extract3GPPLocalDescriptions( const uint8_t *data, ssize_t size, - int timeMs, Parcel *parcel, int depth); + int timeMs, Parcel *parcel); DISALLOW_EVIL_CONSTRUCTORS(TextDescriptions); }; From eff79d10f9bd995d646e61002ef5ccf6ef5b7768 Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Tue, 1 Sep 2015 11:14:18 -0700 Subject: [PATCH 30/73] libstagefright: sanity check size before dereferencing pointer in Utils.cpp Also remove some CHECK's. Bug: 23680780 Change-Id: I62d0941e203e40209fa6fbe3f923f3efdc5a6c23 --- media/libstagefright/Utils.cpp | 36 ++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp index e7d36dc35af..436aaf8189f 100644 --- a/media/libstagefright/Utils.cpp +++ b/media/libstagefright/Utils.cpp @@ -213,8 +213,10 @@ status_t convertMetaDataToMessage( const uint8_t *ptr = (const uint8_t *)data; - CHECK(size >= 7); - CHECK_EQ((unsigned)ptr[0], 1u); // configurationVersion == 1 + if (size < 7 || ptr[0] != 1) { // configurationVersion == 1 + ALOGE("b/23680780"); + return BAD_VALUE; + } uint8_t profile __unused = ptr[1]; uint8_t level __unused = ptr[3]; @@ -240,7 +242,10 @@ status_t convertMetaDataToMessage( buffer->setRange(0, 0); for (size_t i = 0; i < numSeqParameterSets; ++i) { - CHECK(size >= 2); + if (size < 2) { + ALOGE("b/23680780"); + return BAD_VALUE; + } size_t length = U16_AT(ptr); ptr += 2; @@ -269,13 +274,19 @@ status_t convertMetaDataToMessage( } buffer->setRange(0, 0); - CHECK(size >= 1); + if (size < 1) { + ALOGE("b/23680780"); + return BAD_VALUE; + } size_t numPictureParameterSets = *ptr; ++ptr; --size; for (size_t i = 0; i < numPictureParameterSets; ++i) { - CHECK(size >= 2); + if (size < 2) { + ALOGE("b/23680780"); + return BAD_VALUE; + } size_t length = U16_AT(ptr); ptr += 2; @@ -299,8 +310,10 @@ status_t convertMetaDataToMessage( } else if (meta->findData(kKeyHVCC, &type, &data, &size)) { const uint8_t *ptr = (const uint8_t *)data; - CHECK(size >= 7); - CHECK_EQ((unsigned)ptr[0], 1u); // configurationVersion == 1 + if (size < 23 || ptr[0] != 1) { // configurationVersion == 1 + ALOGE("b/23680780"); + return BAD_VALUE; + } uint8_t profile __unused = ptr[1] & 31; uint8_t level __unused = ptr[12]; ptr += 22; @@ -319,6 +332,10 @@ status_t convertMetaDataToMessage( buffer->setRange(0, 0); for (i = 0; i < numofArrays; i++) { + if (size < 3) { + ALOGE("b/23680780"); + return BAD_VALUE; + } ptr += 1; size -= 1; @@ -329,7 +346,10 @@ status_t convertMetaDataToMessage( size -= 2; for (j = 0; j < numofNals; j++) { - CHECK(size >= 2); + if (size < 2) { + ALOGE("b/23680780"); + return BAD_VALUE; + } size_t length = U16_AT(ptr); ptr += 2; From d0af906789b8ec5355d5f7f91631a9dc5776c4d7 Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Tue, 1 Sep 2015 20:07:56 +0000 Subject: [PATCH 31/73] Make IEffect command more robust (second try) Bug: 23540907 Change-Id: If30cfa535ad51521053706fc40fc98d893db5bc7 (cherry picked from commit 10e6660cc5da65b027c90489ba7ac55d1504e012) --- media/libmedia/IEffect.cpp | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/media/libmedia/IEffect.cpp b/media/libmedia/IEffect.cpp index 761b243f167..faf57950984 100644 --- a/media/libmedia/IEffect.cpp +++ b/media/libmedia/IEffect.cpp @@ -85,13 +85,15 @@ class BpEffect: public BpInterface data.writeInt32(size); status_t status = remote()->transact(COMMAND, data, &reply); + if (status == NO_ERROR) { + status = reply.readInt32(); + } if (status != NO_ERROR) { if (pReplySize != NULL) *pReplySize = 0; return status; } - status = reply.readInt32(); size = reply.readInt32(); if (size != 0 && pReplyData != NULL && pReplySize != NULL) { reply.read(pReplyData, size); @@ -155,6 +157,10 @@ status_t BnEffect::onTransact( char *cmd = NULL; if (cmdSize) { cmd = (char *)calloc(cmdSize, 1); + if (cmd == NULL) { + reply->writeInt32(NO_MEMORY); + return NO_ERROR; + } data.read(cmd, cmdSize); } uint32_t replySize = data.readInt32(); @@ -162,15 +168,22 @@ status_t BnEffect::onTransact( char *resp = NULL; if (replySize) { resp = (char *)calloc(replySize, 1); + if (resp == NULL) { + free(cmd); + reply->writeInt32(NO_MEMORY); + return NO_ERROR; + } } status_t status = command(cmdCode, cmdSize, cmd, &replySz, resp); reply->writeInt32(status); - if (replySz < replySize) { - replySize = replySz; - } - reply->writeInt32(replySize); - if (replySize) { - reply->write(resp, replySize); + if (status == NO_ERROR) { + if (replySz < replySize) { + replySize = replySz; + } + reply->writeInt32(replySize); + if (replySize) { + reply->write(resp, replySize); + } } if (cmd) { free(cmd); From f54d3e044a3ff886e38be3c1aaea469de7cd724c Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Wed, 2 Sep 2015 16:46:59 -0700 Subject: [PATCH 32/73] Zero out return values in media binder calls More specifically when handling: * GET_STREAM_VOLUME in IAudioPolicyService, and * GET_CURRENT_POSITION and GET_DURATION in IMediaPlayer This prevents leaking uninitialized values across binder in error cases. Bug: 23756261 Change-Id: I0ffd900ab12b685b0611259ade4a3efb1ec5defe --- media/libmedia/IAudioPolicyService.cpp | 2 +- media/libmedia/IMediaPlayer.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp index 334844169a8..baa5c7dc182 100644 --- a/media/libmedia/IAudioPolicyService.cpp +++ b/media/libmedia/IAudioPolicyService.cpp @@ -994,7 +994,7 @@ status_t BnAudioPolicyService::onTransact( audio_stream_type_t stream = static_cast (data.readInt32()); audio_devices_t device = static_cast (data.readInt32()); - int index; + int index = 0; status_t status = getStreamVolumeIndex(stream, &index, device); reply->writeInt32(index); reply->writeInt32(static_cast (status)); diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp index 7387a79183b..942aec3f44a 100644 --- a/media/libmedia/IMediaPlayer.cpp +++ b/media/libmedia/IMediaPlayer.cpp @@ -566,7 +566,7 @@ status_t BnMediaPlayer::onTransact( } break; case GET_CURRENT_POSITION: { CHECK_INTERFACE(IMediaPlayer, data, reply); - int msec; + int msec = 0; status_t ret = getCurrentPosition(&msec); reply->writeInt32(msec); reply->writeInt32(ret); @@ -574,7 +574,7 @@ status_t BnMediaPlayer::onTransact( } break; case GET_DURATION: { CHECK_INTERFACE(IMediaPlayer, data, reply); - int msec; + int msec = 0; status_t ret = getDuration(&msec); reply->writeInt32(msec); reply->writeInt32(ret); From 03052ac6740c392301d356de9b9574b1dcca7b18 Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Wed, 2 Sep 2015 16:46:59 -0700 Subject: [PATCH 33/73] Zero out return values in audio binder calls More specifically when handling GET_OUTPUT_FOR_ATTR in IAudioPolicyService. This prevents leaking a uninitialized `output` across binder if getOutputForAttr were to encounter errors. Bug: 23756261 Change-Id: Ibff8a1249a4e8a3c89a33a540dda428b10d6ca82 --- media/libmedia/IAudioPolicyService.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp index baa5c7dc182..7e6b9fca7e0 100644 --- a/media/libmedia/IAudioPolicyService.cpp +++ b/media/libmedia/IAudioPolicyService.cpp @@ -877,7 +877,7 @@ status_t BnAudioPolicyService::onTransact( if (hasOffloadInfo) { data.read(&offloadInfo, sizeof(audio_offload_info_t)); } - audio_io_handle_t output; + audio_io_handle_t output = 0; status_t status = getOutputForAttr(hasAttributes ? &attr : NULL, &output, session, &stream, uid, samplingRate, format, channelMask, From a9fffcd22769cb87531cf5b62de482bafe91483f Mon Sep 17 00:00:00 2001 From: Wonsik Kim Date: Wed, 2 Sep 2015 16:02:19 +0900 Subject: [PATCH 34/73] Ogg: avoid size_t overflow in base64 decoding Bug: 23707088 Change-Id: I8d32841fee3213c721cdcc57788807ea64d19d74 --- media/libstagefright/OggExtractor.cpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp index c438d3ced3d..d5c929e26a8 100644 --- a/media/libstagefright/OggExtractor.cpp +++ b/media/libstagefright/OggExtractor.cpp @@ -1220,12 +1220,14 @@ static uint8_t *DecodeBase64(const char *s, size_t size, size_t *outSize) { } } - size_t outLen = 3 * size / 4 - padding; - - *outSize = outLen; + // We divide first to avoid overflow. It's OK to do this because we + // already made sure that size % 4 == 0. + size_t outLen = (size / 4) * 3 - padding; void *buffer = malloc(outLen); - CHECK(buffer != NULL); + if (buffer == NULL) { + return NULL; + } uint8_t *out = (uint8_t *)buffer; size_t j = 0; @@ -1244,10 +1246,10 @@ static uint8_t *DecodeBase64(const char *s, size_t size, size_t *outSize) { } else if (c == '/') { value = 63; } else if (c != '=') { - return NULL; + break; } else { if (i < n - padding) { - return NULL; + break; } value = 0; @@ -1265,6 +1267,13 @@ static uint8_t *DecodeBase64(const char *s, size_t size, size_t *outSize) { } } + // Check if we exited the loop early. + if (j < outLen) { + free(buffer); + return NULL; + } + + *outSize = outLen; return (uint8_t *)buffer; } From 5fbcb3828f0f96b53baae66028708810bc4a16ac Mon Sep 17 00:00:00 2001 From: Robert Shih Date: Wed, 2 Sep 2015 14:02:47 -0700 Subject: [PATCH 35/73] Protect data source access with mutex during disconnect Bug: 23658148 Change-Id: Ic37cac7b5d166143e0b77e9919b0aaef486e4fdd --- .../nuplayer/GenericSource.cpp | 31 ++++++++++++++----- .../nuplayer/GenericSource.h | 1 + 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index 6957a905a54..21befd3883a 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -468,9 +468,17 @@ void NuPlayer::GenericSource::finishPrepareAsync() { void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) { if (err != OK) { - mDataSource.clear(); - mCachedSource.clear(); - mHttpSource.clear(); + { + sp dataSource = mDataSource; + sp cachedSource = mCachedSource; + sp httpSource = mHttpSource; + { + Mutex::Autolock _l(mDisconnectLock); + mDataSource.clear(); + mCachedSource.clear(); + mHttpSource.clear(); + } + } mBitrate = -1; cancelPollBuffering(); @@ -523,13 +531,20 @@ void NuPlayer::GenericSource::resume() { } void NuPlayer::GenericSource::disconnect() { - if (mDataSource != NULL) { + sp dataSource, httpSource; + { + Mutex::Autolock _l(mDisconnectLock); + dataSource = mDataSource; + httpSource = mHttpSource; + } + + if (dataSource != NULL) { // disconnect data source - if (mDataSource->flags() & DataSource::kIsCachingDataSource) { - static_cast(mDataSource.get())->disconnect(); + if (dataSource->flags() & DataSource::kIsCachingDataSource) { + static_cast(dataSource.get())->disconnect(); } - } else if (mHttpSource != NULL) { - static_cast(mHttpSource.get())->disconnect(); + } else if (httpSource != NULL) { + static_cast(httpSource.get())->disconnect(); } } diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h index 01819471e90..d7467c2933c 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.h +++ b/media/libmediaplayerservice/nuplayer/GenericSource.h @@ -153,6 +153,7 @@ struct NuPlayer::GenericSource : public NuPlayer::Source { int32_t mPrevBufferPercentage; mutable Mutex mReadBufferLock; + mutable Mutex mDisconnectLock; sp mLooper; From faa9ec79c2adb8fc0328afaa7af2422baa186147 Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Wed, 9 Sep 2015 09:48:34 -0700 Subject: [PATCH 36/73] IAudioFlinger: clear config before reading it from parcel. Bug: 23905951 Bug: 23912202 Change-Id: Id13a9d3cae2c09e7381b841e67ddfb188274d74c --- media/libmedia/IAudioFlinger.cpp | 30 +++++++++++++++++--------- media/libmedia/IAudioPolicyService.cpp | 14 +++++++----- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index a3f014b8835..18a933ffb4f 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -1104,8 +1104,10 @@ status_t BnAudioFlinger::onTransact( case OPEN_OUTPUT: { CHECK_INTERFACE(IAudioFlinger, data, reply); audio_module_handle_t module = (audio_module_handle_t)data.readInt32(); - audio_config_t config; - data.read(&config, sizeof(audio_config_t)); + audio_config_t config = {}; + if (data.read(&config, sizeof(audio_config_t)) != NO_ERROR) { + ALOGE("b/23905951"); + } audio_devices_t devices = (audio_devices_t)data.readInt32(); String8 address(data.readString8()); audio_output_flags_t flags = (audio_output_flags_t) data.readInt32(); @@ -1149,8 +1151,10 @@ status_t BnAudioFlinger::onTransact( CHECK_INTERFACE(IAudioFlinger, data, reply); audio_module_handle_t module = (audio_module_handle_t)data.readInt32(); audio_io_handle_t input = (audio_io_handle_t)data.readInt32(); - audio_config_t config; - data.read(&config, sizeof(audio_config_t)); + audio_config_t config = {}; + if (data.read(&config, sizeof(audio_config_t)) != NO_ERROR) { + ALOGE("b/23905951"); + } audio_devices_t device = (audio_devices_t)data.readInt32(); String8 address(data.readString8()); audio_source_t source = (audio_source_t)data.readInt32(); @@ -1255,8 +1259,10 @@ status_t BnAudioFlinger::onTransact( } case CREATE_EFFECT: { CHECK_INTERFACE(IAudioFlinger, data, reply); - effect_descriptor_t desc; - data.read(&desc, sizeof(effect_descriptor_t)); + effect_descriptor_t desc = {}; + if (data.read(&desc, sizeof(effect_descriptor_t)) != NO_ERROR) { + ALOGE("b/23905951"); + } sp client = interface_cast(data.readStrongBinder()); int32_t priority = data.readInt32(); audio_io_handle_t output = (audio_io_handle_t) data.readInt32(); @@ -1333,8 +1339,10 @@ status_t BnAudioFlinger::onTransact( } break; case GET_AUDIO_PORT: { CHECK_INTERFACE(IAudioFlinger, data, reply); - struct audio_port port; - data.read(&port, sizeof(struct audio_port)); + struct audio_port port = {}; + if (data.read(&port, sizeof(struct audio_port)) != NO_ERROR) { + ALOGE("b/23905951"); + } status_t status = getAudioPort(&port); reply->writeInt32(status); if (status == NO_ERROR) { @@ -1346,8 +1354,10 @@ status_t BnAudioFlinger::onTransact( CHECK_INTERFACE(IAudioFlinger, data, reply); struct audio_patch patch; data.read(&patch, sizeof(struct audio_patch)); - audio_patch_handle_t handle; - data.read(&handle, sizeof(audio_patch_handle_t)); + audio_patch_handle_t handle = {}; + if (data.read(&handle, sizeof(audio_patch_handle_t)) != NO_ERROR) { + ALOGE("b/23905951"); + } status_t status = createAudioPatch(&patch, &handle); reply->writeInt32(status); if (status == NO_ERROR) { diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp index 7e6b9fca7e0..0cc954fe6a9 100644 --- a/media/libmedia/IAudioPolicyService.cpp +++ b/media/libmedia/IAudioPolicyService.cpp @@ -1148,8 +1148,10 @@ status_t BnAudioPolicyService::onTransact( case GET_AUDIO_PORT: { CHECK_INTERFACE(IAudioPolicyService, data, reply); - struct audio_port port; - data.read(&port, sizeof(struct audio_port)); + struct audio_port port = {}; + if (data.read(&port, sizeof(struct audio_port)) != NO_ERROR) { + ALOGE("b/23912202"); + } status_t status = getAudioPort(&port); reply->writeInt32(status); if (status == NO_ERROR) { @@ -1162,8 +1164,10 @@ status_t BnAudioPolicyService::onTransact( CHECK_INTERFACE(IAudioPolicyService, data, reply); struct audio_patch patch; data.read(&patch, sizeof(struct audio_patch)); - audio_patch_handle_t handle; - data.read(&handle, sizeof(audio_patch_handle_t)); + audio_patch_handle_t handle = {}; + if (data.read(&handle, sizeof(audio_patch_handle_t)) != NO_ERROR) { + ALOGE("b/23912202"); + } status_t status = createAudioPatch(&patch, &handle); reply->writeInt32(status); if (status == NO_ERROR) { @@ -1292,7 +1296,7 @@ status_t BnAudioPolicyService::onTransact( data.read(&source, sizeof(struct audio_port_config)); audio_attributes_t attributes; data.read(&attributes, sizeof(audio_attributes_t)); - audio_io_handle_t handle; + audio_io_handle_t handle = {}; status_t status = startAudioSource(&source, &attributes, &handle); reply->writeInt32(status); reply->writeInt32(handle); From 2c039d6bbe168dafc8d7e653db0b4376ff496bd7 Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Thu, 10 Sep 2015 09:47:29 -0700 Subject: [PATCH 37/73] IAudioFlinger: always initialize variables to ensure no info leak when writing them to Parcel. Bug: 23953967 Change-Id: Ibbe841da149038675e9e8daea76c77558bc8564b --- media/libmedia/IAudioFlinger.cpp | 22 +++++++++++----------- media/libmedia/IAudioPolicyService.cpp | 8 ++++---- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index 18a933ffb4f..47ed359be08 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -937,7 +937,7 @@ status_t BnAudioFlinger::onTransact( pid_t tid = (pid_t) data.readInt32(); int sessionId = data.readInt32(); int clientUid = data.readInt32(); - status_t status; + status_t status = NO_ERROR; sp track; if ((haveSharedBuffer && (buffer == 0)) || ((buffer != 0) && (buffer->pointer() == NULL))) { @@ -972,7 +972,7 @@ status_t BnAudioFlinger::onTransact( size_t notificationFrames = data.readInt64(); sp cblk; sp buffers; - status_t status; + status_t status = NO_ERROR; sp record = openRecord(input, sampleRate, format, channelMask, opPackageName, &frameCount, &flags, tid, clientUid, &sessionId, ¬ificationFrames, cblk, buffers, &status); @@ -1111,7 +1111,7 @@ status_t BnAudioFlinger::onTransact( audio_devices_t devices = (audio_devices_t)data.readInt32(); String8 address(data.readString8()); audio_output_flags_t flags = (audio_output_flags_t) data.readInt32(); - uint32_t latencyMs; + uint32_t latencyMs = 0; audio_io_handle_t output; status_t status = openOutput(module, &output, &config, &devices, address, &latencyMs, flags); @@ -1190,8 +1190,8 @@ status_t BnAudioFlinger::onTransact( case GET_RENDER_POSITION: { CHECK_INTERFACE(IAudioFlinger, data, reply); audio_io_handle_t output = (audio_io_handle_t) data.readInt32(); - uint32_t halFrames; - uint32_t dspFrames; + uint32_t halFrames = 0; + uint32_t dspFrames = 0; status_t status = getRenderPosition(&halFrames, &dspFrames, output); reply->writeInt32(status); if (status == NO_ERROR) { @@ -1227,7 +1227,7 @@ status_t BnAudioFlinger::onTransact( } break; case QUERY_NUM_EFFECTS: { CHECK_INTERFACE(IAudioFlinger, data, reply); - uint32_t numEffects; + uint32_t numEffects = 0; status_t status = queryNumberEffects(&numEffects); reply->writeInt32(status); if (status == NO_ERROR) { @@ -1237,7 +1237,7 @@ status_t BnAudioFlinger::onTransact( } case QUERY_EFFECT: { CHECK_INTERFACE(IAudioFlinger, data, reply); - effect_descriptor_t desc; + effect_descriptor_t desc = {}; status_t status = queryEffect(data.readInt32(), &desc); reply->writeInt32(status); if (status == NO_ERROR) { @@ -1249,7 +1249,7 @@ status_t BnAudioFlinger::onTransact( CHECK_INTERFACE(IAudioFlinger, data, reply); effect_uuid_t uuid; data.read(&uuid, sizeof(effect_uuid_t)); - effect_descriptor_t desc; + effect_descriptor_t desc = {}; status_t status = getEffectDescriptor(&uuid, &desc); reply->writeInt32(status); if (status == NO_ERROR) { @@ -1268,9 +1268,9 @@ status_t BnAudioFlinger::onTransact( audio_io_handle_t output = (audio_io_handle_t) data.readInt32(); int sessionId = data.readInt32(); const String16 opPackageName = data.readString16(); - status_t status; - int id; - int enabled; + status_t status = NO_ERROR; + int id = 0; + int enabled = 0; sp effect = createEffect(&desc, client, priority, output, sessionId, opPackageName, &status, &id, &enabled); diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp index 0cc954fe6a9..76b5924fad3 100644 --- a/media/libmedia/IAudioPolicyService.cpp +++ b/media/libmedia/IAudioPolicyService.cpp @@ -932,7 +932,7 @@ status_t BnAudioPolicyService::onTransact( audio_channel_mask_t channelMask = data.readInt32(); audio_input_flags_t flags = (audio_input_flags_t) data.readInt32(); audio_port_handle_t selectedDeviceId = (audio_port_handle_t) data.readInt32(); - audio_io_handle_t input; + audio_io_handle_t input = {}; status_t status = getInputForAttr(&attr, &input, session, uid, samplingRate, format, channelMask, flags, selectedDeviceId); @@ -1242,9 +1242,9 @@ status_t BnAudioPolicyService::onTransact( CHECK_INTERFACE(IAudioPolicyService, data, reply); sp client = interface_cast( data.readStrongBinder()); - audio_session_t session; - audio_io_handle_t ioHandle; - audio_devices_t device; + audio_session_t session = {}; + audio_io_handle_t ioHandle = {}; + audio_devices_t device = {}; status_t status = acquireSoundTriggerSession(&session, &ioHandle, &device); reply->writeInt32(status); if (status == NO_ERROR) { From f838f1beaf6f8478020256d42dcec3b8d370605b Mon Sep 17 00:00:00 2001 From: Jeff Tinker Date: Mon, 14 Sep 2015 13:55:23 -0700 Subject: [PATCH 38/73] Fix heap data leak vulnerability bug: 23600291 Change-Id: I7979e9e25ada01c13775be8580d433a8b4ce4ffe --- drm/common/IDrmManagerService.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drm/common/IDrmManagerService.cpp b/drm/common/IDrmManagerService.cpp index b90da1b74c6..f2e14b6f55b 100644 --- a/drm/common/IDrmManagerService.cpp +++ b/drm/common/IDrmManagerService.cpp @@ -742,9 +742,11 @@ status_t BpDrmManagerService::decrypt( const status_t status = reply.readInt32(); ALOGV("Return value of decrypt() is %d", status); - const int size = reply.readInt32(); - (*decBuffer)->length = size; - reply.read((void *)(*decBuffer)->data, size); + if (status == NO_ERROR) { + const int size = reply.readInt32(); + (*decBuffer)->length = size; + reply.read((void *)(*decBuffer)->data, size); + } return status; } @@ -1470,9 +1472,11 @@ status_t BnDrmManagerService::onTransact( reply->writeInt32(status); - const int size = decBuffer->length; - reply->writeInt32(size); - reply->write(decBuffer->data, size); + if (status == NO_ERROR) { + const int size = decBuffer->length; + reply->writeInt32(size); + reply->write(decBuffer->data, size); + } clearDecryptHandle(&handle); delete encBuffer; encBuffer = NULL; From 17dd9441843d547a92c2632e9d084e405645cb6b Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Wed, 16 Sep 2015 15:01:16 -0700 Subject: [PATCH 39/73] IAudioFlinger: fix the missing initialization of variable to ensure no info leak when writing them to Parcel. Bug: 23953967 Change-Id: I3a1d0144ba3832649e322c197ff0f03305ee7829 --- media/libmedia/IAudioFlinger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index 47ed359be08..0bf503a7ad4 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -1112,7 +1112,7 @@ status_t BnAudioFlinger::onTransact( String8 address(data.readString8()); audio_output_flags_t flags = (audio_output_flags_t) data.readInt32(); uint32_t latencyMs = 0; - audio_io_handle_t output; + audio_io_handle_t output = AUDIO_IO_HANDLE_NONE; status_t status = openOutput(module, &output, &config, &devices, address, &latencyMs, flags); ALOGV("OPEN_OUTPUT output, %d", output); From 547fa15459937b02f3c3913067d3fff2bb3eb6cd Mon Sep 17 00:00:00 2001 From: Wonsik Kim Date: Mon, 7 Sep 2015 15:52:27 +0900 Subject: [PATCH 40/73] DO NOT MERGE Avoid size_t overflow in base64 decoding once again Switch to foundation base64 function in OggExtractor and fix the issue there. Bug: 23707088 Change-Id: If8ba3347c213fe7a36668c943ed264f2871ad468 --- media/libstagefright/OggExtractor.cpp | 102 +++------------------ media/libstagefright/foundation/base64.cpp | 11 ++- 2 files changed, 20 insertions(+), 93 deletions(-) diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp index d5c929e26a8..578171f9e6f 100644 --- a/media/libstagefright/OggExtractor.cpp +++ b/media/libstagefright/OggExtractor.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -1202,93 +1203,18 @@ void parseVorbisComment( } -// The returned buffer should be free()d. -static uint8_t *DecodeBase64(const char *s, size_t size, size_t *outSize) { - *outSize = 0; - - if ((size % 4) != 0) { - return NULL; - } - - size_t n = size; - size_t padding = 0; - if (n >= 1 && s[n - 1] == '=') { - padding = 1; - - if (n >= 2 && s[n - 2] == '=') { - padding = 2; - } - } - - // We divide first to avoid overflow. It's OK to do this because we - // already made sure that size % 4 == 0. - size_t outLen = (size / 4) * 3 - padding; - - void *buffer = malloc(outLen); - if (buffer == NULL) { - return NULL; - } - - uint8_t *out = (uint8_t *)buffer; - size_t j = 0; - uint32_t accum = 0; - for (size_t i = 0; i < n; ++i) { - char c = s[i]; - unsigned value; - if (c >= 'A' && c <= 'Z') { - value = c - 'A'; - } else if (c >= 'a' && c <= 'z') { - value = 26 + c - 'a'; - } else if (c >= '0' && c <= '9') { - value = 52 + c - '0'; - } else if (c == '+') { - value = 62; - } else if (c == '/') { - value = 63; - } else if (c != '=') { - break; - } else { - if (i < n - padding) { - break; - } - - value = 0; - } - - accum = (accum << 6) | value; - - if (((i + 1) % 4) == 0) { - out[j++] = (accum >> 16); - - if (j < outLen) { out[j++] = (accum >> 8) & 0xff; } - if (j < outLen) { out[j++] = accum & 0xff; } - - accum = 0; - } - } - - // Check if we exited the loop early. - if (j < outLen) { - free(buffer); - return NULL; - } - - *outSize = outLen; - return (uint8_t *)buffer; -} - static void extractAlbumArt( const sp &fileMeta, const void *data, size_t size) { ALOGV("extractAlbumArt from '%s'", (const char *)data); - size_t flacSize; - uint8_t *flac = DecodeBase64((const char *)data, size, &flacSize); - - if (flac == NULL) { + sp flacBuffer = decodeBase64(AString((const char *)data, size)); + if (flacBuffer == NULL) { ALOGE("malformed base64 encoded data."); return; } + size_t flacSize = flacBuffer->size(); + uint8_t *flac = flacBuffer->data(); ALOGV("got flac of size %zu", flacSize); uint32_t picType; @@ -1298,24 +1224,24 @@ static void extractAlbumArt( char type[128]; if (flacSize < 8) { - goto exit; + return; } picType = U32_AT(flac); if (picType != 3) { // This is not a front cover. - goto exit; + return; } typeLen = U32_AT(&flac[4]); if (typeLen > sizeof(type) - 1) { - goto exit; + return; } // we've already checked above that flacSize >= 8 if (flacSize - 8 < typeLen) { - goto exit; + return; } memcpy(type, &flac[8], typeLen); @@ -1325,7 +1251,7 @@ static void extractAlbumArt( if (!strcmp(type, "-->")) { // This is not inline cover art, but an external url instead. - goto exit; + return; } descLen = U32_AT(&flac[8 + typeLen]); @@ -1333,7 +1259,7 @@ static void extractAlbumArt( if (flacSize < 32 || flacSize - 32 < typeLen || flacSize - 32 - typeLen < descLen) { - goto exit; + return; } dataLen = U32_AT(&flac[8 + typeLen + 4 + descLen + 16]); @@ -1341,7 +1267,7 @@ static void extractAlbumArt( // we've already checked above that (flacSize - 32 - typeLen - descLen) >= 0 if (flacSize - 32 - typeLen - descLen < dataLen) { - goto exit; + return; } ALOGV("got image data, %zu trailing bytes", @@ -1351,10 +1277,6 @@ static void extractAlbumArt( kKeyAlbumArt, 0, &flac[8 + typeLen + 4 + descLen + 20], dataLen); fileMeta->setCString(kKeyAlbumArtMIME, type); - -exit: - free(flac); - flac = NULL; } //////////////////////////////////////////////////////////////////////////////// diff --git a/media/libstagefright/foundation/base64.cpp b/media/libstagefright/foundation/base64.cpp index dcf5bef3aea..7da7db9411f 100644 --- a/media/libstagefright/foundation/base64.cpp +++ b/media/libstagefright/foundation/base64.cpp @@ -22,11 +22,11 @@ namespace android { sp decodeBase64(const AString &s) { - if ((s.size() % 4) != 0) { + size_t n = s.size(); + if ((n % 4) != 0) { return NULL; } - size_t n = s.size(); size_t padding = 0; if (n >= 1 && s.c_str()[n - 1] == '=') { padding = 1; @@ -40,11 +40,16 @@ sp decodeBase64(const AString &s) { } } - size_t outLen = 3 * s.size() / 4 - padding; + // We divide first to avoid overflow. It's OK to do this because we + // already made sure that n % 4 == 0. + size_t outLen = (n / 4) * 3 - padding; sp buffer = new ABuffer(outLen); uint8_t *out = buffer->data(); + if (out == NULL || buffer->size() < outLen) { + return NULL; + } size_t j = 0; uint32_t accum = 0; for (size_t i = 0; i < n; ++i) { From 11c6c57f4a984bd8dd5fe3d65ef2322409c01383 Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Fri, 18 Sep 2015 10:04:09 -0700 Subject: [PATCH 41/73] StagefrightMetadataRetriever: handle error returned from convertMetaDataToMessage(). Bug: 23680780 Change-Id: I09dbbf95b2c874b9760938646e48a7ed543f1577 --- media/libstagefright/StagefrightMetadataRetriever.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp index 6c795ac2e08..5a8f6a58d0b 100644 --- a/media/libstagefright/StagefrightMetadataRetriever.cpp +++ b/media/libstagefright/StagefrightMetadataRetriever.cpp @@ -156,7 +156,10 @@ static VideoFrame *extractVideoFrame( sp format = source->getFormat(); sp videoFormat; - convertMetaDataToMessage(trackMeta, &videoFormat); + if (convertMetaDataToMessage(trackMeta, &videoFormat) != OK) { + ALOGW("Failed to convert meta data to message"); + return NULL; + } // TODO: Use Flexible color instead videoFormat->setInt32("color-format", OMX_COLOR_FormatYUV420Planar); From 5918d3601f5711671a6fb5ccc2f65a931aae33eb Mon Sep 17 00:00:00 2001 From: Haynes Mathew George Date: Fri, 30 Oct 2015 18:41:06 -0700 Subject: [PATCH 42/73] libstagefright: omx: Prevent assertion due to state mismatches Instead handle them a bit better. Since the assertions dealt with in this patchset can only happen if the OMX IL client died while de-init'ing the component, it is impossible to deal with all possible cases gracefully. Hence take an aggressive approach by moving state of the component to OMX_StateInvalid. This looks okay as per the spec, but might not be the best approach. Change-Id: I3f23f5e3853523fe1a7fb3aaf38b46595fa91732 --- .../include/SimpleSoftOMXComponent.h | 1 + .../omx/SimpleSoftOMXComponent.cpp | 44 +++++++++++++++++-- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/media/libstagefright/include/SimpleSoftOMXComponent.h b/media/libstagefright/include/SimpleSoftOMXComponent.h index 591b38e1114..6a0a9585aa4 100644 --- a/media/libstagefright/include/SimpleSoftOMXComponent.h +++ b/media/libstagefright/include/SimpleSoftOMXComponent.h @@ -140,6 +140,7 @@ struct SimpleSoftOMXComponent : public SoftOMXComponent { void onPortFlush(OMX_U32 portIndex, bool sendFlushComplete); void checkTransitions(); + void onTransitionError(); DISALLOW_EVIL_CONSTRUCTORS(SimpleSoftOMXComponent); }; diff --git a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp index e6a0c497268..1fd0641c274 100644 --- a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp +++ b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp @@ -417,16 +417,43 @@ void SimpleSoftOMXComponent::onSendCommand( } } +void SimpleSoftOMXComponent::onTransitionError() { + mState = OMX_StateInvalid; + mTargetState = OMX_StateInvalid; + notify(OMX_EventError, OMX_CommandStateSet, OMX_StateInvalid, 0); +} + void SimpleSoftOMXComponent::onChangeState(OMX_STATETYPE state) { + bool skipTransitions = false; + // We shouldn't be in a state transition already. - CHECK_EQ((int)mState, (int)mTargetState); + if (mState != mTargetState) { + // Workaround to prevent assertion + // XXX CHECK_EQ((int)mState, (int)mTargetState); + ALOGW("mState %d != mTargetState %d", mState, mTargetState); + skipTransitions = true; + onTransitionError(); + } switch (mState) { case OMX_StateLoaded: - CHECK_EQ((int)state, (int)OMX_StateIdle); + if (state != OMX_StateIdle) { + // Workaround to prevent assertion + // XXX CHECK_EQ((int)state, (int)OMX_StateIdle); + ALOGW("In OMX_StateLoaded, state %d != OMX_StateIdle", state); + skipTransitions = true; + onTransitionError(); + } break; case OMX_StateIdle: - CHECK(state == OMX_StateLoaded || state == OMX_StateExecuting); + if (!(state == OMX_StateLoaded || state == OMX_StateExecuting)) { + // Workaround to prevent assertion + // XXX CHECK(state == OMX_StateLoaded || state == OMX_StateExecuting); + ALOGW("In OMX_StateIdle, state %d != OMX_StateLoaded||OMX_StateExecuting", + state); + skipTransitions = true; + onTransitionError(); + } break; case OMX_StateExecuting: { @@ -440,11 +467,20 @@ void SimpleSoftOMXComponent::onChangeState(OMX_STATETYPE state) { notify(OMX_EventCmdComplete, OMX_CommandStateSet, state, NULL); break; } - + case OMX_StateInvalid: { + ALOGW("In OMX_StateInvalid, ignore state transition to %d", state); + skipTransitions = true; + onTransitionError(); + break; + } default: TRESPASS(); } + if (skipTransitions) { + return; + } + mTargetState = state; checkTransitions(); From 614ee35203329c5a617d0c5cfca9cd08446c3af5 Mon Sep 17 00:00:00 2001 From: Haynes Mathew George Date: Fri, 30 Oct 2015 15:29:47 -0700 Subject: [PATCH 43/73] audiopolicy: Add synchronization to EffectDescriptorCollection Synchronize public APIs of EffectDescriptorCollection CRs-Fixed: 920103 Change-Id: I04ccac526c6f99e61e43288776653d6b7ff325c4 --- .../common/managerdefinitions/include/EffectDescriptor.h | 3 +++ .../common/managerdefinitions/src/EffectDescriptor.cpp | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h index c9783a13471..396541be77b 100644 --- a/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h +++ b/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h @@ -21,6 +21,7 @@ #include #include #include +#include namespace android { @@ -66,6 +67,8 @@ class EffectDescriptorCollection : public KeyedVector * Maximum memory allocated to audio effects in KB */ static const uint32_t MAX_EFFECTS_MEMORY = 512; + + Mutex mLock; }; }; // namespace android diff --git a/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp index 33d838da6f1..6a0d079a913 100644 --- a/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp @@ -56,6 +56,7 @@ status_t EffectDescriptorCollection::registerEffect(const effect_descriptor_t *d int session, int id) { + Mutex::Autolock _l(mLock); if (mTotalEffectsMemory + desc->memoryUsage > getMaxEffectsMemory()) { ALOGW("registerEffect() memory limit exceeded for Fx %s, Memory %d KB", desc->name, desc->memoryUsage); @@ -80,6 +81,7 @@ status_t EffectDescriptorCollection::registerEffect(const effect_descriptor_t *d status_t EffectDescriptorCollection::unregisterEffect(int id) { + Mutex::Autolock _l(mLock); ssize_t index = indexOfKey(id); if (index < 0) { ALOGW("unregisterEffect() unknown effect ID %d", id); @@ -106,6 +108,7 @@ status_t EffectDescriptorCollection::unregisterEffect(int id) status_t EffectDescriptorCollection::setEffectEnabled(int id, bool enabled) { + Mutex::Autolock _l(mLock); ssize_t index = indexOfKey(id); if (index < 0) { ALOGW("unregisterEffect() unknown effect ID %d", id); @@ -148,6 +151,7 @@ status_t EffectDescriptorCollection::setEffectEnabled(const sp bool EffectDescriptorCollection::isNonOffloadableEffectEnabled() { + Mutex::Autolock _l(mLock); for (size_t i = 0; i < size(); i++) { sp effectDesc = valueAt(i); if (effectDesc->mEnabled && (effectDesc->mStrategy == STRATEGY_MEDIA) && @@ -172,6 +176,7 @@ uint32_t EffectDescriptorCollection::getMaxEffectsMemory() const status_t EffectDescriptorCollection::dump(int fd) { + Mutex::Autolock _l(mLock); const size_t SIZE = 256; char buffer[SIZE]; From 4ba4e7608c7589be877fd0b23595d6764bd234f4 Mon Sep 17 00:00:00 2001 From: Steve Kondik Date: Wed, 1 May 2013 02:58:11 -0700 Subject: [PATCH 44/73] camera: Don't segfault if we get a NULL parameter * Values end up NULL on some drivers, don't crash. Change-Id: Ic897dbd4629cf3af98c85f93be202c382dde806b --- camera/CameraParameters.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/camera/CameraParameters.cpp b/camera/CameraParameters.cpp index 590ff4a73f0..11f2fd17613 100644 --- a/camera/CameraParameters.cpp +++ b/camera/CameraParameters.cpp @@ -242,6 +242,9 @@ void CameraParameters::unflatten(const String8 ¶ms) void CameraParameters::set(const char *key, const char *value) { + if (key == NULL || value == NULL) + return; + // XXX i think i can do this with strspn() if (strchr(key, '=') || strchr(key, ';')) { //XXX ALOGE("Key \"%s\"contains invalid character (= or ;)", key); From a5f199e52bb2d63d53c7478b3725e46a2df693ee Mon Sep 17 00:00:00 2001 From: Peng Zhu Date: Wed, 20 Nov 2013 16:11:24 -0800 Subject: [PATCH 45/73] Camera: Add support for manual 3A. Add manual white balance mode. user can set the specific cct to lock the white balance.Just as other white balance mode, it will lock the white balance once it's set, the only difference it that the cct value is set from app. Add manual focus mode allow app to set the focus distance with DAC value or actuator step value. Once the value is set, the focus distance is locked unless app switch it back to automatically mode Change-Id: I0c08ad0cea27284645e9e710c26844ca24a5c477 --- camera/CameraParameters.cpp | 2 ++ include/camera/CameraParameters.h | 3 +++ 2 files changed, 5 insertions(+) diff --git a/camera/CameraParameters.cpp b/camera/CameraParameters.cpp index 11f2fd17613..d35519d3089 100644 --- a/camera/CameraParameters.cpp +++ b/camera/CameraParameters.cpp @@ -107,6 +107,7 @@ const char CameraParameters::WHITE_BALANCE_DAYLIGHT[] = "daylight"; const char CameraParameters::WHITE_BALANCE_CLOUDY_DAYLIGHT[] = "cloudy-daylight"; const char CameraParameters::WHITE_BALANCE_TWILIGHT[] = "twilight"; const char CameraParameters::WHITE_BALANCE_SHADE[] = "shade"; +const char CameraParameters::WHITE_BALANCE_MANUAL_CCT[] = "manual-cct"; // Values for effect settings. const char CameraParameters::EFFECT_NONE[] = "none"; @@ -169,6 +170,7 @@ const char CameraParameters::FOCUS_MODE_FIXED[] = "fixed"; const char CameraParameters::FOCUS_MODE_EDOF[] = "edof"; const char CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO[] = "continuous-video"; const char CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE[] = "continuous-picture"; +const char CameraParameters::FOCUS_MODE_MANUAL_POSITION[] = "manual"; // Values for light fx settings const char CameraParameters::LIGHTFX_LOWLIGHT[] = "low-light"; diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h index 74517b47bed..d85050d6084 100644 --- a/include/camera/CameraParameters.h +++ b/include/camera/CameraParameters.h @@ -555,6 +555,7 @@ class CameraParameters static const char WHITE_BALANCE_CLOUDY_DAYLIGHT[]; static const char WHITE_BALANCE_TWILIGHT[]; static const char WHITE_BALANCE_SHADE[]; + static const char WHITE_BALANCE_MANUAL_CCT[]; // Values for effect settings. static const char EFFECT_NONE[]; @@ -678,6 +679,8 @@ class CameraParameters // other modes. static const char FOCUS_MODE_CONTINUOUS_PICTURE[]; + static const char FOCUS_MODE_MANUAL_POSITION[]; + // Values for light special effects // Low-light enhancement mode static const char LIGHTFX_LOWLIGHT[]; From 778b658e56505ce0ef5a7570a135606f56ffa994 Mon Sep 17 00:00:00 2001 From: Arulselvan M Date: Mon, 3 Dec 2012 15:58:44 +0530 Subject: [PATCH 46/73] Can't play AAC file with ID3 tag. When the file is scanned, the ID3 tag is found to have a footer at the end of audio data. And getAdtsFrameLength return zero after reading the footer. As a result, the duration and mInitCheck are not set. The current change considers the data till footer and sets the duration based on no. of frames read till the footer/corrupt frame. Change-Id: Ie8f898435f0d4ca31fdd355146c4db7b37c0b988 Signed-off-by: Arulselvan M Signed-off-by: Jin Wei --- media/libstagefright/AACExtractor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/media/libstagefright/AACExtractor.cpp b/media/libstagefright/AACExtractor.cpp index 45e8a300b1d..f6434b44dfe 100644 --- a/media/libstagefright/AACExtractor.cpp +++ b/media/libstagefright/AACExtractor.cpp @@ -174,7 +174,7 @@ AACExtractor::AACExtractor( if (mDataSource->getSize(&streamSize) == OK) { while (offset < streamSize) { if ((frameSize = getAdtsFrameLength(source, offset, NULL)) == 0) { - return; + break; } mOffsetVector.push(offset); From b74729263fbece23924ec692f2862a9086d6c6b1 Mon Sep 17 00:00:00 2001 From: Pawit Pornkitprasan Date: Fri, 13 Jan 2012 16:16:27 +0700 Subject: [PATCH 47/73] stagefright: Fix playback for mkv files with lacing Most mkv files having 'lacing' in their audio section to save space. Android did not handle this properly, sending all frames in the block with the same time code, which causes stuttery playback. Change-Id: I4dc76e7c2a53126c7fbdd3628fe7d339d2e3364e --- .../matroska/MatroskaExtractor.cpp | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp index ecc2573bb08..e6ed9008474 100644 --- a/media/libstagefright/matroska/MatroskaExtractor.cpp +++ b/media/libstagefright/matroska/MatroskaExtractor.cpp @@ -521,8 +521,9 @@ status_t MatroskaSource::readBlock() { const mkvparser::Block *block = mBlockIter.block(); int64_t timeUs = mBlockIter.blockTimeUs(); + int frameCount = block->GetFrameCount(); - for (int i = 0; i < block->GetFrameCount(); ++i) { + for (int i = 0; i < frameCount; ++i) { const mkvparser::Block::Frame &frame = block->GetFrame(i); MediaBuffer *mbuf = new MediaBuffer(frame.len); @@ -542,6 +543,27 @@ status_t MatroskaSource::readBlock() { mBlockIter.advance(); + if (!mBlockIter.eos() && frameCount > 1) { + // For files with lacing enabled, we need to amend they kKeyTime of + // each frame so that their kKeyTime are advanced accordingly (instead + // of being set to the same value). To do this, we need to find out + // the duration of the block using the start time of the next block. + int64_t duration = mBlockIter.blockTimeUs() - timeUs; + int64_t durationPerFrame = duration / frameCount; + int64_t durationRemainder = duration % frameCount; + + // We split duration to each of the frame, distributing the remainder (if any) + // to the later frames. The later frames are processed first due to the + // use of the iterator for the doubly linked list + List::iterator it = mPendingFrames.end(); + for (int i = frameCount - 1; i >= 0; --i) { + --it; + int64_t frameRemainder = durationRemainder >= frameCount - i ? 1 : 0; + int64_t frameTimeUs = timeUs + durationPerFrame * i + frameRemainder; + (*it)->meta_data()->setInt64(kKeyTime, frameTimeUs); + } + } + return OK; } From bb2219571a16a2f29118cdfa5d36a6a3c4594cd2 Mon Sep 17 00:00:00 2001 From: Gurudatta Bhakte Date: Fri, 27 Jul 2012 19:21:34 +0530 Subject: [PATCH 48/73] FLAC coded file does not play (single metadata block files) FLAC files which has the last metadata block flag set in STREAMINFO were not playing. Sniff of FLAC is modified to accomodate this set flag. Change-Id: I76f216cc2cde6e10958324afbc704fc3e5a0e2bf Author: Gurudatta Bhakte Signed-off-by: Gurudatta Bhakte Signed-off-by: Shuo Gao Signed-off-by: Bruce Beare Signed-off-by: Jack Ren Author-tracking-BZ: 32421 --- media/libstagefright/FLACExtractor.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/media/libstagefright/FLACExtractor.cpp b/media/libstagefright/FLACExtractor.cpp index 89a91f7e250..c79180bc4e1 100644 --- a/media/libstagefright/FLACExtractor.cpp +++ b/media/libstagefright/FLACExtractor.cpp @@ -845,12 +845,14 @@ bool SniffFLAC( { // first 4 is the signature word // second 4 is the sizeof STREAMINFO + // 1st bit of 2nd 4 bytes represent whether last block of metadata or not // 042 is the mandatory STREAMINFO // no need to read rest of the header, as a premature EOF will be caught later uint8_t header[4+4]; if (source->readAt(0, header, sizeof(header)) != sizeof(header) - || memcmp("fLaC\0\0\0\042", header, 4+4)) - { + || memcmp("fLaC", header, 4) + || !(header[4] == 0x80 || header[4] == 0x00) + || memcmp("\0\0\042", header + 5, 3)) { return false; } From 1413e17cd7ffccb8eccf0b0a8fd83e5fe34c6ed7 Mon Sep 17 00:00:00 2001 From: Sergii Doroshenko Date: Fri, 20 Jul 2012 16:46:23 -0500 Subject: [PATCH 49/73] AACExtractor: Added support for APE tag To support aac audio with APE tag we need parse this tag. Otherwise AACExtractor stops reading of audio file. DR: OMAPS00267689 Change-Id: Ic697b90dbc9f2b93aeb227411359c36c113cb71e Signed-off-by: Daniel Levin --- media/libstagefright/AACExtractor.cpp | 25 +++- media/libstagefright/APE.cpp | 125 ++++++++++++++++++++ media/libstagefright/Android.mk | 1 + media/libstagefright/include/AACExtractor.h | 4 + media/libstagefright/include/APE.h | 43 +++++++ 5 files changed, 192 insertions(+), 6 deletions(-) create mode 100644 media/libstagefright/APE.cpp create mode 100644 media/libstagefright/include/APE.h diff --git a/media/libstagefright/AACExtractor.cpp b/media/libstagefright/AACExtractor.cpp index f6434b44dfe..1353e3f8b64 100644 --- a/media/libstagefright/AACExtractor.cpp +++ b/media/libstagefright/AACExtractor.cpp @@ -136,7 +136,8 @@ AACExtractor::AACExtractor( const sp &source, const sp &_meta) : mDataSource(source), mInitCheck(NO_INIT), - mFrameDurationUs(0) { + mFrameDurationUs(0), + mApeMeta(new MetaData) { sp meta = _meta; if (meta == NULL) { @@ -170,9 +171,23 @@ AACExtractor::AACExtractor( off64_t streamSize, numFrames = 0; size_t frameSize = 0; int64_t duration = 0; + uint8_t apeTag[8]; if (mDataSource->getSize(&streamSize) == OK) { while (offset < streamSize) { + mDataSource->readAt(offset, &apeTag, 8); + if (ape.isAPE(apeTag)) { + size_t apeSize = 0; + mDataSource->readAt(offset + 8 + 4, &apeSize, 1); + + if (ape.parseAPE(source, offset, mApeMeta) == false) { + break; + } + + mOffsetVector.push(offset); + offset += apeSize; + continue; + } if ((frameSize = getAdtsFrameLength(source, offset, NULL)) == 0) { break; } @@ -196,15 +211,13 @@ AACExtractor::~AACExtractor() { } sp AACExtractor::getMetaData() { - sp meta = new MetaData; if (mInitCheck != OK) { - return meta; + return mApeMeta; } + mApeMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC_ADTS); - meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC_ADTS); - - return meta; + return mApeMeta; } size_t AACExtractor::countTracks() { diff --git a/media/libstagefright/APE.cpp b/media/libstagefright/APE.cpp new file mode 100644 index 00000000000..74ca7dc4bfd --- /dev/null +++ b/media/libstagefright/APE.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "APE_TAG" +#include + +#include "include/APE.h" + +namespace android { + +APE::APE(){ + +} + +APE::~APE(){ + +} + +bool APE::isAPE(uint8_t *apeTag) const { + if(apeTag[0] == 'A' && apeTag[1] == 'P' && apeTag[2] == 'E' && + apeTag[3] == 'T' && apeTag[4] == 'A' && apeTag[5] == 'G' && + apeTag[6] == 'E' && apeTag[7] == 'X'){ + return true; + } + return false; +} + +size_t sizeItemKey(const sp &source, off64_t offset){ + off64_t ItemKeyOffset = offset; + uint8_t keyTerminator = 0; + size_t keySize = 0; + while (keyTerminator != 0){ + source->readAt(ItemKeyOffset, &keyTerminator, 1); + ItemKeyOffset++; + keySize++; + } + return keySize - 1; +} + +bool APE::parseAPE(const sp &source, off64_t offset, + sp &meta){ + + struct Map { + int key; + const char *tag; + } const kMap[] = { + { kKeyAlbum, "Album" }, + { kKeyArtist, "Artist" }, + { kKeyAlbumArtist, "Album" }, + { kKeyComposer, "Composer" }, + { kKeyGenre, "Genre" }, + { kKeyTitle, "Title" }, + { kKeyYear, "Year" }, + { kKeyCDTrackNumber, "Track" }, + { kKeyDate, "Record Date"}, + }; + + static const size_t kNumMapEntries = sizeof(kMap) / sizeof(kMap[0]); + + off64_t headerOffset = offset; + headerOffset += 16; + itemNumber = 0; + if (source->readAt(headerOffset, &itemNumber, 1) == 0) + return false; + + headerOffset += 16; + + for(uint32_t it = 0; it < itemNumber; it++){ + lenValue = 0; + if (source->readAt(headerOffset, &lenValue, 1) == 0) + return false; + + headerOffset += 4; + + itemFlags = 0; + if (source->readAt(headerOffset, &itemFlags, 1) == 0) + return false; + + headerOffset += 4; + + size_t sizeKey = sizeItemKey(source, headerOffset); + + char *key = new char[sizeKey]; + + if (source->readAt(headerOffset, key, sizeKey) == 0) + return false; + + key[sizeKey] = '\0'; + headerOffset += sizeKey + 1; + + char *val = new char[lenValue + 1]; + + if (source->readAt(headerOffset, val, lenValue) == 0) + return false; + + val[lenValue] = '\0'; + + for (size_t i = 0; i < kNumMapEntries; i++){ + if (!strcmp(key, kMap[i].tag)){ + if (itemFlags == 0) + meta->setCString(kMap[i].key, (const char *)val); + break; + } + } + headerOffset += lenValue; + delete[] key; + delete[] val; + } + + return true; +} +} //namespace android diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index 03e7e464c77..36b1cf4daf1 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -69,6 +69,7 @@ LOCAL_SRC_FILES:= \ WVMExtractor.cpp \ XINGSeeker.cpp \ avc_utils.cpp \ + APE.cpp \ LOCAL_C_INCLUDES:= \ $(TOP)/frameworks/av/include/media/ \ diff --git a/media/libstagefright/include/AACExtractor.h b/media/libstagefright/include/AACExtractor.h index e98ca82c9d2..9a0ba2f23f9 100644 --- a/media/libstagefright/include/AACExtractor.h +++ b/media/libstagefright/include/AACExtractor.h @@ -21,6 +21,7 @@ #include #include +#include "include/APE.h" namespace android { @@ -48,6 +49,9 @@ class AACExtractor : public MediaExtractor { Vector mOffsetVector; int64_t mFrameDurationUs; + APE ape; + sp mApeMeta; + AACExtractor(const AACExtractor &); AACExtractor &operator=(const AACExtractor &); }; diff --git a/media/libstagefright/include/APE.h b/media/libstagefright/include/APE.h new file mode 100644 index 00000000000..db49bb05c05 --- /dev/null +++ b/media/libstagefright/include/APE.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) Texas Instruments - http://www.ti.com/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef APE_TAG_H_ + +#define APE_TAG_H_ + +#include +#include +#include + +namespace android { + +class APE{ +public: + APE(); + ~APE(); + bool isAPE(uint8_t *apeTag) const; + bool parseAPE(const sp &source, off64_t offset, + sp &meta); + +private: + uint32_t itemNumber; + uint32_t itemFlags; + size_t lenValue; +}; + +} //namespace android + +#endif //APE_TAG_H_ From 4e47d28c53d1d126f317f85f9206607a46f07d46 Mon Sep 17 00:00:00 2001 From: Suresh Choudhary Date: Tue, 18 Mar 2014 17:24:15 +0530 Subject: [PATCH 50/73] libstagefright: Handle unsupported codec metaData Modification done in StagefrightMetadataRetriver to handle NULL return for meta data if codec is unsupported by extractor. Change-Id: I905cec5ee91b098d99e1935437b562d2d9206381 --- media/libstagefright/StagefrightMetadataRetriever.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp index 5a8f6a58d0b..c3adac4732a 100644 --- a/media/libstagefright/StagefrightMetadataRetriever.cpp +++ b/media/libstagefright/StagefrightMetadataRetriever.cpp @@ -458,6 +458,10 @@ VideoFrame *StagefrightMetadataRetriever::getFrameAtTime( for (i = 0; i < n; ++i) { sp meta = mExtractor->getTrackMetaData(i); + if (meta == NULL) { + continue; + } + const char *mime; CHECK(meta->findCString(kKeyMIMEType, &mime)); @@ -628,6 +632,10 @@ void StagefrightMetadataRetriever::parseMetaData() { size_t numTracks = mExtractor->countTracks(); + if (numTracks == 0) { //If no tracks available, corrupt or not valid stream + return; + } + char tmp[32]; sprintf(tmp, "%zu", numTracks); @@ -651,6 +659,9 @@ void StagefrightMetadataRetriever::parseMetaData() { String8 timedTextLang; for (size_t i = 0; i < numTracks; ++i) { sp trackMeta = mExtractor->getTrackMetaData(i); + if (trackMeta == NULL) { + continue; + } int64_t durationUs; if (trackMeta->findInt64(kKeyDuration, &durationUs)) { From a68e7529fbd233f42429707c9e0b23043cf58e34 Mon Sep 17 00:00:00 2001 From: Steve Kondik Date: Fri, 28 Nov 2014 13:18:08 -0800 Subject: [PATCH 51/73] stagefright: Pass AAC profile from MatroskaExtractor * Needed by framework to determine audio apth Change-Id: I8d928852fb4a24e3d575d70fbf366bae1a178b31 --- media/libstagefright/matroska/MatroskaExtractor.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp index e6ed9008474..0ecbf5839d5 100644 --- a/media/libstagefright/matroska/MatroskaExtractor.cpp +++ b/media/libstagefright/matroska/MatroskaExtractor.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include @@ -841,6 +842,17 @@ static void addESDSFromCodecPrivate( const sp &meta, bool isAudio, const void *priv, size_t privSize) { + if(isAudio) { + ABitReader br((const uint8_t *)priv, privSize); + uint32_t objectType = br.getBits(5); + + if (objectType == 31) { // AAC-ELD => additional 6 bits + objectType = 32 + br.getBits(6); + } + + meta->setInt32(kKeyAACAOT, objectType); + } + int privSizeBytesRequired = bytesForSize(privSize); int esdsSize2 = 14 + privSizeBytesRequired + privSize; int esdsSize2BytesRequired = bytesForSize(esdsSize2); From d195849ebd84b0789e0392b15bb330a907e6ae23 Mon Sep 17 00:00:00 2001 From: Steve Kondik Date: Wed, 8 Jul 2015 09:56:01 -0700 Subject: [PATCH 52/73] stagefright: Add support for loading a custom OMXPlugin * To facilitate moving the stagefright-plugins glue out of the framework, support is added to OMXMaster to load multiple external plugins besides internal/vendor versions. * This is currently limited to one plugin, defined by the "mm.sf.omx-plugin" system property. The code will allow any number of libraries to be loaded, though. * Should also be useful for nonstandard vendor implementations too. Change-Id: I27d7e16ad56baa17754d8ea47a8c608a0d73d6f1 --- media/libstagefright/omx/OMXMaster.cpp | 67 ++++++++++++++-------- media/libstagefright/omx/OMXMaster.h | 7 +-- media/libstagefright/omx/SoftOMXPlugin.cpp | 6 +- 3 files changed, 50 insertions(+), 30 deletions(-) diff --git a/media/libstagefright/omx/OMXMaster.cpp b/media/libstagefright/omx/OMXMaster.cpp index ae3cb33c09c..f7bb733b84b 100644 --- a/media/libstagefright/omx/OMXMaster.cpp +++ b/media/libstagefright/omx/OMXMaster.cpp @@ -25,52 +25,58 @@ #include #include +#include namespace android { -OMXMaster::OMXMaster() - : mVendorLibHandle(NULL) { +OMXMaster::OMXMaster() { addVendorPlugin(); addPlugin(new SoftOMXPlugin); + addUserPlugin(); } OMXMaster::~OMXMaster() { clearPlugins(); - - if (mVendorLibHandle != NULL) { - dlclose(mVendorLibHandle); - mVendorLibHandle = NULL; - } } void OMXMaster::addVendorPlugin() { addPlugin("libstagefrighthw.so"); } +void OMXMaster::addUserPlugin() { + char plugin[PROPERTY_VALUE_MAX]; + if (property_get("media.sf.omx-plugin", plugin, NULL)) { + addPlugin(plugin); + } +} + void OMXMaster::addPlugin(const char *libname) { - mVendorLibHandle = dlopen(libname, RTLD_NOW); + void* handle = dlopen(libname, RTLD_NOW); - if (mVendorLibHandle == NULL) { + if (handle == NULL) { return; } typedef OMXPluginBase *(*CreateOMXPluginFunc)(); CreateOMXPluginFunc createOMXPlugin = (CreateOMXPluginFunc)dlsym( - mVendorLibHandle, "createOMXPlugin"); + handle, "createOMXPlugin"); if (!createOMXPlugin) createOMXPlugin = (CreateOMXPluginFunc)dlsym( - mVendorLibHandle, "_ZN7android15createOMXPluginEv"); + handle, "_ZN7android15createOMXPluginEv"); if (createOMXPlugin) { - addPlugin((*createOMXPlugin)()); + addPlugin((*createOMXPlugin)(), handle); } } -void OMXMaster::addPlugin(OMXPluginBase *plugin) { +void OMXMaster::addPlugin(OMXPluginBase *plugin, void *handle) { + if (plugin == 0) { + return; + } Mutex::Autolock autoLock(mLock); - mPlugins.push_back(plugin); + mPlugins.add(plugin, handle); OMX_U32 index = 0; @@ -100,21 +106,32 @@ void OMXMaster::clearPlugins() { Mutex::Autolock autoLock(mLock); typedef void (*DestroyOMXPluginFunc)(OMXPluginBase*); - DestroyOMXPluginFunc destroyOMXPlugin = - (DestroyOMXPluginFunc)dlsym( - mVendorLibHandle, "destroyOMXPlugin"); - mPluginByComponentName.clear(); + for (unsigned int i = 0; i < mPlugins.size(); i++) { + OMXPluginBase *plugin = mPlugins.keyAt(i); + if (plugin != NULL) { + void *handle = mPlugins.valueAt(i); + + if (handle != NULL) { + DestroyOMXPluginFunc destroyOMXPlugin = + (DestroyOMXPluginFunc)dlsym( + handle, "destroyOMXPlugin"); + + if (destroyOMXPlugin) + destroyOMXPlugin(plugin); + else + delete plugin; - for (List::iterator it = mPlugins.begin(); - it != mPlugins.end(); ++it) { - if (destroyOMXPlugin) - destroyOMXPlugin(*it); - else - delete *it; - *it = NULL; + dlclose(handle); + } else { + delete plugin; + } + + plugin = NULL; + } } + mPluginByComponentName.clear(); mPlugins.clear(); } diff --git a/media/libstagefright/omx/OMXMaster.h b/media/libstagefright/omx/OMXMaster.h index 6069741742b..c07fed374fe 100644 --- a/media/libstagefright/omx/OMXMaster.h +++ b/media/libstagefright/omx/OMXMaster.h @@ -51,15 +51,14 @@ struct OMXMaster : public OMXPluginBase { private: Mutex mLock; - List mPlugins; + KeyedVector mPlugins; KeyedVector mPluginByComponentName; KeyedVector mPluginByInstance; - void *mVendorLibHandle; - void addVendorPlugin(); + void addUserPlugin(); void addPlugin(const char *libname); - void addPlugin(OMXPluginBase *plugin); + void addPlugin(OMXPluginBase *plugin, void *handle = NULL); void clearPlugins(); OMXMaster(const OMXMaster &); diff --git a/media/libstagefright/omx/SoftOMXPlugin.cpp b/media/libstagefright/omx/SoftOMXPlugin.cpp index 9389f677908..4afd5d5b059 100755 --- a/media/libstagefright/omx/SoftOMXPlugin.cpp +++ b/media/libstagefright/omx/SoftOMXPlugin.cpp @@ -77,6 +77,7 @@ OMX_ERRORTYPE SoftOMXPlugin::makeComponentInstance( OMX_COMPONENTTYPE **component) { ALOGV("makeComponentInstance '%s'", name); + dlerror(); // clear any existing error for (size_t i = 0; i < kNumComponents; ++i) { if (strcmp(name, kComponents[i].mName)) { continue; @@ -94,6 +95,8 @@ OMX_ERRORTYPE SoftOMXPlugin::makeComponentInstance( return OMX_ErrorComponentNotFound; } + ALOGV("load component %s for %s", libName.c_str(), name); + typedef SoftOMXComponent *(*CreateSoftOMXComponentFunc)( const char *, const OMX_CALLBACKTYPE *, OMX_PTR, OMX_COMPONENTTYPE **); @@ -104,7 +107,8 @@ OMX_ERRORTYPE SoftOMXPlugin::makeComponentInstance( "_Z22createSoftOMXComponentPKcPK16OMX_CALLBACKTYPE" "PvPP17OMX_COMPONENTTYPE"); - if (createSoftOMXComponent == NULL) { + if (const char *error = dlerror()) { + ALOGE("unable to dlsym %s: %s", libName.c_str(), error); dlclose(libHandle); libHandle = NULL; From 9fecdca8e258060dec698278e68cd46c9dd72eac Mon Sep 17 00:00:00 2001 From: Steve Kondik Date: Fri, 28 Nov 2014 23:26:30 -0800 Subject: [PATCH 53/73] stagefright: Improve FLAC and WAV support for 24-bit * Forward-port changes from CM11 * Remove truncation support as AudioFlinger handles rebuffering in case it can't go to the hardware. Change-Id: Iad30d04ee051050e444c3d665fa8bb7a1cfef348 --- media/libstagefright/FLACExtractor.cpp | 182 ++++++++----------------- media/libstagefright/WAVExtractor.cpp | 56 ++++---- 2 files changed, 88 insertions(+), 150 deletions(-) diff --git a/media/libstagefright/FLACExtractor.cpp b/media/libstagefright/FLACExtractor.cpp index c79180bc4e1..87345e15ee5 100644 --- a/media/libstagefright/FLACExtractor.cpp +++ b/media/libstagefright/FLACExtractor.cpp @@ -32,6 +32,13 @@ #include #include +#ifdef ENABLE_AV_ENHANCEMENTS +#include "QCMediaDefs.h" +#include "QCMetaData.h" +#endif + +#include + namespace android { class FLACParser; @@ -72,6 +79,8 @@ class FLACSource : public MediaSource { class FLACParser : public RefBase { +friend class FLACSource; + public: FLACParser( const sp &dataSource, @@ -103,6 +112,8 @@ class FLACParser : public RefBase { // media buffers void allocateBuffers(); void releaseBuffers(); + void copyBuffer(short *dst, const int *const *src, unsigned nSamples); + MediaBuffer *readBuffer() { return readBuffer(false, 0LL); } @@ -113,6 +124,7 @@ class FLACParser : public RefBase { protected: virtual ~FLACParser(); + private: sp mDataSource; sp mFileMetadata; @@ -122,7 +134,6 @@ class FLACParser : public RefBase { // media buffers size_t mMaxBufferSize; MediaBufferGroup *mGroup; - void (*mCopy)(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels); // handle to underlying libFLAC parser FLAC__StreamDecoder *mDecoder; @@ -377,109 +388,41 @@ void FLACParser::errorCallback(FLAC__StreamDecoderErrorStatus status) mErrorStatus = status; } -// Copy samples from FLAC native 32-bit non-interleaved to 16-bit interleaved. -// These are candidates for optimization if needed. - -static void copyMono8( - short *dst, - const int *const *src, - unsigned nSamples, - unsigned /* nChannels */) { - for (unsigned i = 0; i < nSamples; ++i) { - *dst++ = src[0][i] << 8; - } -} - -static void copyStereo8( - short *dst, - const int *const *src, - unsigned nSamples, - unsigned /* nChannels */) { - for (unsigned i = 0; i < nSamples; ++i) { - *dst++ = src[0][i] << 8; - *dst++ = src[1][i] << 8; - } -} - -static void copyMultiCh8(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels) +void FLACParser::copyBuffer(short *dst, const int *const *src, unsigned nSamples) { - for (unsigned i = 0; i < nSamples; ++i) { - for (unsigned c = 0; c < nChannels; ++c) { - *dst++ = src[c][i] << 8; - } - } -} - -static void copyMono16( - short *dst, - const int *const *src, - unsigned nSamples, - unsigned /* nChannels */) { - for (unsigned i = 0; i < nSamples; ++i) { - *dst++ = src[0][i]; - } -} - -static void copyStereo16( - short *dst, - const int *const *src, - unsigned nSamples, - unsigned /* nChannels */) { - for (unsigned i = 0; i < nSamples; ++i) { - *dst++ = src[0][i]; - *dst++ = src[1][i]; - } -} - -static void copyMultiCh16(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels) -{ - for (unsigned i = 0; i < nSamples; ++i) { - for (unsigned c = 0; c < nChannels; ++c) { - *dst++ = src[c][i]; - } - } -} - -// 24-bit versions should do dithering or noise-shaping, here or in AudioFlinger - -static void copyMono24( - short *dst, - const int *const *src, - unsigned nSamples, - unsigned /* nChannels */) { - for (unsigned i = 0; i < nSamples; ++i) { - *dst++ = src[0][i] >> 8; - } -} - -static void copyStereo24( - short *dst, - const int *const *src, - unsigned nSamples, - unsigned /* nChannels */) { - for (unsigned i = 0; i < nSamples; ++i) { - *dst++ = src[0][i] >> 8; - *dst++ = src[1][i] >> 8; - } -} - -static void copyMultiCh24(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels) -{ - for (unsigned i = 0; i < nSamples; ++i) { - for (unsigned c = 0; c < nChannels; ++c) { - *dst++ = src[c][i] >> 8; + unsigned int nChannels = getChannels(); + unsigned int nBits = getBitsPerSample(); + switch (nBits) { + case 8: + for (unsigned i = 0; i < nSamples; ++i) { + for (unsigned c = 0; c < nChannels; ++c) { + *dst++ = src[c][i] << 8; + } + } + break; + case 16: + for (unsigned i = 0; i < nSamples; ++i) { + for (unsigned c = 0; c < nChannels; ++c) { + *dst++ = src[c][i]; + } + } + break; + case 24: + case 32: + { + int32_t *out = (int32_t *)dst; + for (unsigned i = 0; i < nSamples; ++i) { + for (unsigned c = 0; c < nChannels; ++c) { + *out++ = src[c][i] << 8; + } + } + break; } + default: + TRESPASS(); } } -static void copyTrespass( - short * /* dst */, - const int *const * /* src */, - unsigned /* nSamples */, - unsigned /* nChannels */) { - TRESPASS(); -} - // FLACParser FLACParser::FLACParser( @@ -492,7 +435,6 @@ FLACParser::FLACParser( mInitCheck(false), mMaxBufferSize(0), mGroup(NULL), - mCopy(copyTrespass), mDecoder(NULL), mCurrentPos(0LL), mEOF(false), @@ -571,6 +513,8 @@ status_t FLACParser::init() } // check sample rate switch (getSampleRate()) { + case 100: + case 1000: case 8000: case 11025: case 12000: @@ -578,38 +522,18 @@ status_t FLACParser::init() case 22050: case 24000: case 32000: + case 42000: case 44100: + case 46000: case 48000: case 88200: case 96000: + case 192000: break; default: ALOGE("unsupported sample rate %u", getSampleRate()); return NO_INIT; } - // configure the appropriate copy function, defaulting to trespass - static const struct { - unsigned mChannels; - unsigned mBitsPerSample; - void (*mCopy)(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels); - } table[] = { - { 1, 8, copyMono8 }, - { 2, 8, copyStereo8 }, - { 8, 8, copyMultiCh8 }, - { 1, 16, copyMono16 }, - { 2, 16, copyStereo16 }, - { 8, 16, copyMultiCh16 }, - { 1, 24, copyMono24 }, - { 2, 24, copyStereo24 }, - { 8, 24, copyMultiCh24 }, - }; - for (unsigned i = 0; i < sizeof(table)/sizeof(table[0]); ++i) { - if (table[i].mChannels >= getChannels() && - table[i].mBitsPerSample == getBitsPerSample()) { - mCopy = table[i].mCopy; - break; - } - } // populate track metadata if (mTrackMetadata != 0) { mTrackMetadata->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW); @@ -618,6 +542,7 @@ status_t FLACParser::init() // sample rate is non-zero, so division by zero not possible mTrackMetadata->setInt64(kKeyDuration, (getTotalSamples() * 1000000LL) / getSampleRate()); + mTrackMetadata->setInt32(kKeyBitsPerSample, getBitsPerSample()); } } else { ALOGE("missing STREAMINFO"); @@ -633,7 +558,9 @@ void FLACParser::allocateBuffers() { CHECK(mGroup == NULL); mGroup = new MediaBufferGroup; - mMaxBufferSize = getMaxBlockSize() * getChannels() * sizeof(short); + // allocate enough to hold 24-bits (packed in 32 bits) + unsigned int bytesPerSample = getBitsPerSample() > 16 ? 4 : 2; + mMaxBufferSize = getMaxBlockSize() * getChannels() * bytesPerSample; mGroup->add_buffer(new MediaBuffer(mMaxBufferSize)); } @@ -686,12 +613,12 @@ MediaBuffer *FLACParser::readBuffer(bool doSeek, FLAC__uint64 sample) if (err != OK) { return NULL; } - size_t bufferSize = blocksize * getChannels() * sizeof(short); + size_t bufferSize = blocksize * getChannels() * (getBitsPerSample() > 16 ? 4 : 2); CHECK(bufferSize <= mMaxBufferSize); short *data = (short *) buffer->data(); buffer->set_range(0, bufferSize); // copy PCM from FLAC write buffer to our media buffer, with interleaving - (*mCopy)(data, mWriteBuffer, blocksize, getChannels()); + copyBuffer(data, mWriteBuffer, blocksize); // fill in buffer metadata CHECK(mWriteHeader.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); FLAC__uint64 sampleNumber = mWriteHeader.number.sample_number; @@ -726,9 +653,10 @@ FLACSource::~FLACSource() status_t FLACSource::start(MetaData * /* params */) { + CHECK(!mStarted); + ALOGV("FLACSource::start"); - CHECK(!mStarted); mParser->allocateBuffers(); mStarted = true; diff --git a/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp index 335ac842582..bb2a33c6be8 100644 --- a/media/libstagefright/WAVExtractor.cpp +++ b/media/libstagefright/WAVExtractor.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #define CHANNEL_MASK_USE_CHANNEL_ORDER 0 @@ -284,6 +285,7 @@ status_t WAVExtractor::init() { case WAVE_FORMAT_PCM: mTrackMeta->setCString( kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW); + mTrackMeta->setInt32(kKeyBitsPerSample, mBitsPerSample); break; case WAVE_FORMAT_ALAW: mTrackMeta->setCString( @@ -359,15 +361,16 @@ WAVSource::~WAVSource() { } status_t WAVSource::start(MetaData * /* params */) { - ALOGV("WAVSource::start"); - CHECK(!mStarted); + if (mStarted) { + return OK; + } mGroup = new MediaBufferGroup; mGroup->add_buffer(new MediaBuffer(kMaxFrameSize)); - if (mBitsPerSample == 8) { - // As a temporary buffer for 8->16 bit conversion. + if (mBitsPerSample == 8 || mBitsPerSample == 24) { + // As a temporary buffer for 8->16/24->32 bit conversion. mGroup->add_buffer(new MediaBuffer(kMaxFrameSize)); } @@ -427,9 +430,15 @@ status_t WAVSource::read( } // make sure that maxBytesToRead is multiple of 3, in 24-bit case - size_t maxBytesToRead = - mBitsPerSample == 8 ? kMaxFrameSize / 2 : - (mBitsPerSample == 24 ? 3*(kMaxFrameSize/3): kMaxFrameSize); + size_t maxBytesToRead; + if(8 == mBitsPerSample) + maxBytesToRead = kMaxFrameSize / 2; + else if (24 == mBitsPerSample) { + maxBytesToRead = 3*(kMaxFrameSize/4); + } else + maxBytesToRead = kMaxFrameSize; + ALOGV("%s mBitsPerSample %d, kMaxFrameSize %d, ", + __func__, mBitsPerSample, kMaxFrameSize); size_t maxBytesAvailable = (mCurrentPos - mOffset >= (off64_t)mSize) @@ -488,23 +497,24 @@ status_t WAVSource::read( buffer->release(); buffer = tmp; } else if (mBitsPerSample == 24) { - // Convert 24-bit signed samples to 16-bit signed. - - const uint8_t *src = - (const uint8_t *)buffer->data() + buffer->range_offset(); - int16_t *dst = (int16_t *)src; - - size_t numSamples = buffer->range_length() / 3; - for (size_t i = 0; i < numSamples; ++i) { - int32_t x = (int32_t)(src[0] | src[1] << 8 | src[2] << 16); - x = (x << 8) >> 8; // sign extension - - x = x >> 8; - *dst++ = (int16_t)x; - src += 3; + // Padding done here to convert to 32-bit samples + MediaBuffer *tmp; + CHECK_EQ(mGroup->acquire_buffer(&tmp), (status_t)OK); + ssize_t numBytes = buffer->range_length() / 3; + tmp->set_range(0, 4 * numBytes); + int8_t *dst = (int8_t *)tmp->data(); + const uint8_t *src = (const uint8_t *)buffer->data(); + ALOGV("numBytes = %d", numBytes); + while(numBytes-- > 0) { + *dst++ = 0x0; + *dst++ = src[0]; + *dst++ = src[1]; + *dst++ = src[2]; + src += 3; } - - buffer->set_range(buffer->range_offset(), 2 * numSamples); + buffer->release(); + buffer = tmp; + ALOGV("length = %d", buffer->range_length()); } } From be4e19f93e7fb5119d5394d4e0055d2174247108 Mon Sep 17 00:00:00 2001 From: Steve Kondik Date: Sat, 17 Oct 2015 19:30:49 -0700 Subject: [PATCH 54/73] stagefright: Support MP3 in MPEG4 containers Change-Id: I8e13a68cc10fafc43dd8f7d350644c7638d5d5e3 --- media/libstagefright/MPEG4Extractor.cpp | 30 +++++++++++++++++-------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index cd50365c259..107b4f6fdaa 100755 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -315,6 +315,9 @@ static const char *FourCC2MIME(uint32_t fourcc) { case FOURCC('m', 'p', '4', 'a'): return MEDIA_MIMETYPE_AUDIO_AAC; + case FOURCC('.', 'm', 'p', '3'): + return MEDIA_MIMETYPE_AUDIO_MPEG; + case FOURCC('s', 'a', 'm', 'r'): return MEDIA_MIMETYPE_AUDIO_AMR_NB; @@ -838,7 +841,7 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { && chunk_type != FOURCC('c', 'o', 'v', 'r') && mPath.size() == 5 && underMetaDataPath(mPath)) { off64_t stop_offset = *offset + chunk_size; - *offset = data_offset; + *offset = stop_offset; while (*offset < stop_offset) { status_t err = parseChunk(offset, depth + 1); if (err != OK) { @@ -1352,7 +1355,14 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { mLastTrack->meta->setInt32(kKeySampleRate, sample_rate); off64_t stop_offset = *offset + chunk_size; - *offset = data_offset + sizeof(buffer); + if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_MPEG, FourCC2MIME(chunk_type)) || + !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, FourCC2MIME(chunk_type))) { + // ESD is not required in mp3 + // amr wb with damr atom corrupted can cause the clip to not play + *offset = stop_offset; + } else { + *offset = data_offset + sizeof(buffer); + } while (*offset < stop_offset) { status_t err = parseChunk(offset, depth + 1); if (err != OK) { @@ -2974,12 +2984,12 @@ status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio( return OK; } - if (objectTypeIndication == 0x6b) { - // The media subtype is MP3 audio - // Our software MP3 audio decoder may not be able to handle - // packetized MP3 audio; for now, lets just return ERROR_UNSUPPORTED - ALOGE("MP3 track in MP4/3GPP file is not supported"); - return ERROR_UNSUPPORTED; + if (objectTypeIndication == 0x6b + || objectTypeIndication == 0x69) { + // This is mpeg1/2 audio content, set mimetype to mpeg + mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG); + ALOGD("objectTypeIndication:0x%x, set mimetype to mpeg ",objectTypeIndication); + return OK; } const uint8_t *csd; @@ -4602,7 +4612,9 @@ static bool LegacySniffMPEG4( return false; } - if (!memcmp(header, "ftyp3gp", 7) || !memcmp(header, "ftypmp42", 8) + if (!memcmp(header, "ftyp3g2a", 8) || !memcmp(header, "ftyp3g2b", 8) + || !memcmp(header, "ftyp3g2c", 8) + || !memcmp(header, "ftyp3gp", 7) || !memcmp(header, "ftypmp42", 8) || !memcmp(header, "ftyp3gr6", 8) || !memcmp(header, "ftyp3gs6", 8) || !memcmp(header, "ftyp3ge6", 8) || !memcmp(header, "ftyp3gg6", 8) || !memcmp(header, "ftypisom", 8) || !memcmp(header, "ftypM4V ", 8) From c752af9775121485c6dc3992305664f9077443b6 Mon Sep 17 00:00:00 2001 From: Surajit Podder Date: Thu, 23 Jan 2014 13:24:34 +0530 Subject: [PATCH 55/73] DataSource: Remove global variables in DataSource related to sniff Remove global variables related to sniff, and added Sniffer class to implement the sniff functionality with non-static members. Change-Id: I6fbd0ba5b686e09fda11d78cdd687a69c81a6bdf CRs-Fixed: 567753 --- include/media/stagefright/DataSource.h | 38 ++++++++++-- media/libstagefright/DataSource.cpp | 86 ++++++++++++++------------ 2 files changed, 80 insertions(+), 44 deletions(-) diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h index 0c31e726bc7..de31ff05c7a 100644 --- a/include/media/stagefright/DataSource.h +++ b/include/media/stagefright/DataSource.h @@ -36,6 +36,37 @@ class IDataSource; struct IMediaHTTPService; class String8; struct HTTPBase; +class DataSource; + +class Sniffer : public RefBase { +public: + Sniffer(); + + //////////////////////////////////////////////////////////////////////////// + + bool sniff(DataSource *source, String8 *mimeType, float *confidence, sp *meta); + + // The sniffer can optionally fill in "meta" with an AMessage containing + // a dictionary of values that helps the corresponding extractor initialize + // its state without duplicating effort already exerted by the sniffer. + typedef bool (*SnifferFunc)( + const sp &source, String8 *mimeType, + float *confidence, sp *meta); + + //if isExtendedExtractor = true, store the location of the sniffer to register + void registerSniffer_l(SnifferFunc func); + void registerDefaultSniffers(); + + virtual ~Sniffer() {} + +private: + Mutex mSnifferMutex; + List mSniffers; + List::iterator extendedSnifferPosition; + + Sniffer(const Sniffer &); + Sniffer &operator=(const Sniffer &); +}; class DataSource : public RefBase { public: @@ -57,7 +88,7 @@ class DataSource : public RefBase { static sp CreateMediaHTTP(const sp &httpService); static sp CreateFromIDataSource(const sp &source); - DataSource() {} + DataSource() : mSniffer(new Sniffer()) {} virtual status_t initCheck() const = 0; @@ -111,10 +142,7 @@ class DataSource : public RefBase { protected: virtual ~DataSource() {} -private: - static Mutex gSnifferMutex; - static List gSniffers; - static bool gSniffersRegistered; + sp mSniffer; static void RegisterSniffer_l(SnifferFunc func); diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp index 85d0292b389..92303293662 100644 --- a/media/libstagefright/DataSource.cpp +++ b/media/libstagefright/DataSource.cpp @@ -112,29 +112,42 @@ status_t DataSource::getSize(off64_t *size) { //////////////////////////////////////////////////////////////////////////////// -Mutex DataSource::gSnifferMutex; -List DataSource::gSniffers; -bool DataSource::gSniffersRegistered = false; - bool DataSource::sniff( String8 *mimeType, float *confidence, sp *meta) { + + return mSniffer->sniff(this, mimeType, confidence, meta); +} + +// static +void DataSource::RegisterSniffer_l(SnifferFunc func) { + return; +} + +// static +void DataSource::RegisterDefaultSniffers() { + return; +} + +//////////////////////////////////////////////////////////////////////////////// + +Sniffer::Sniffer() { + registerDefaultSniffers(); +} + +bool Sniffer::sniff( + DataSource *source, String8 *mimeType, float *confidence, sp *meta) { + *mimeType = ""; *confidence = 0.0f; meta->clear(); - { - Mutex::Autolock autoLock(gSnifferMutex); - if (!gSniffersRegistered) { - return false; - } - } - - for (List::iterator it = gSniffers.begin(); - it != gSniffers.end(); ++it) { + Mutex::Autolock autoLock(mSnifferMutex); + for (List::iterator it = mSniffers.begin(); + it != mSniffers.end(); ++it) { String8 newMimeType; float newConfidence; sp newMeta; - if ((*it)(this, &newMimeType, &newConfidence, &newMeta)) { + if ((*it)(source, &newMimeType, &newConfidence, &newMeta)) { if (newConfidence > *confidence) { *mimeType = newMimeType; *confidence = newConfidence; @@ -146,45 +159,40 @@ bool DataSource::sniff( return *confidence > 0.0; } -// static -void DataSource::RegisterSniffer_l(SnifferFunc func) { - for (List::iterator it = gSniffers.begin(); - it != gSniffers.end(); ++it) { +void Sniffer::registerSniffer_l(SnifferFunc func) { + + for (List::iterator it = mSniffers.begin(); + it != mSniffers.end(); ++it) { if (*it == func) { return; } } - gSniffers.push_back(func); + mSniffers.push_back(func); } -// static -void DataSource::RegisterDefaultSniffers() { - Mutex::Autolock autoLock(gSnifferMutex); - if (gSniffersRegistered) { - return; - } - - RegisterSniffer_l(SniffMPEG4); - RegisterSniffer_l(SniffMatroska); - RegisterSniffer_l(SniffOgg); - RegisterSniffer_l(SniffWAV); - RegisterSniffer_l(SniffFLAC); - RegisterSniffer_l(SniffAMR); - RegisterSniffer_l(SniffMPEG2TS); - RegisterSniffer_l(SniffMP3); - RegisterSniffer_l(SniffAAC); - RegisterSniffer_l(SniffMPEG2PS); - RegisterSniffer_l(SniffWVM); +void Sniffer::registerDefaultSniffers() { + Mutex::Autolock autoLock(mSnifferMutex); + + registerSniffer_l(SniffMPEG4); + registerSniffer_l(SniffMatroska); + registerSniffer_l(SniffOgg); + registerSniffer_l(SniffWAV); + registerSniffer_l(SniffFLAC); + registerSniffer_l(SniffAMR); + registerSniffer_l(SniffMPEG2TS); + registerSniffer_l(SniffMP3); + registerSniffer_l(SniffAAC); + registerSniffer_l(SniffMPEG2PS); + registerSniffer_l(SniffWVM); RegisterSniffer_l(SniffMidi); RegisterSniffer_l(AVUtils::get()->getExtendedSniffer()); char value[PROPERTY_VALUE_MAX]; if (property_get("drm.service.enabled", value, NULL) && (!strcmp(value, "1") || !strcasecmp(value, "true"))) { - RegisterSniffer_l(SniffDRM); + registerSniffer_l(SniffDRM); } - gSniffersRegistered = true; } // static From 4d370448eec9cec522a4eb2890274237cf48a0b1 Mon Sep 17 00:00:00 2001 From: Steve Kondik Date: Sat, 29 Nov 2014 11:43:23 -0800 Subject: [PATCH 56/73] stagefright: Support HEVC tracks in Matroska containers * Pass the HVCC atom to Stagefright. Change-Id: I7fdca25e20b9051925936a34e594808b18a3a3bd --- .../matroska/MatroskaExtractor.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp index 0ecbf5839d5..a66ca6dfd6c 100644 --- a/media/libstagefright/matroska/MatroskaExtractor.cpp +++ b/media/libstagefright/matroska/MatroskaExtractor.cpp @@ -137,6 +137,7 @@ struct MatroskaSource : public MediaSource { enum Type { AVC, AAC, + HEVC, OTHER }; @@ -235,6 +236,18 @@ MatroskaSource::MatroskaSource( mNALSizeLen = 1 + (avcc[4] & 3); ALOGV("mNALSizeLen = %zu", mNALSizeLen); + } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)) { + mType = HEVC; + + uint32_t type; + const void *data; + size_t size; + CHECK(meta->findData(kKeyHVCC, &type, &data, &size)); + + const uint8_t *ptr = (const uint8_t *)data; + CHECK(size >= 7); + mNALSizeLen = 1 + (ptr[14 + 7] & 3); + ALOGV("mNALSizeLen = %zu", mNALSizeLen); } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { mType = AAC; } @@ -604,7 +617,7 @@ status_t MatroskaSource::read( MediaBuffer *frame = *mPendingFrames.begin(); mPendingFrames.erase(mPendingFrames.begin()); - if (mType != AVC) { + if (mType != AVC && mType != HEVC) { if (targetSampleTimeUs >= 0ll) { frame->meta_data()->setInt64( kKeyTargetTime, targetSampleTimeUs); @@ -1013,6 +1026,10 @@ void MatroskaExtractor::addTracks() { codecID); continue; } + } else if (!strcmp("V_MPEGH/ISO/HEVC", codecID)) { + meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_HEVC); + meta->setData(kKeyHVCC, 0, codecPrivate, codecPrivateSize); + } else if (!strcmp("V_VP8", codecID)) { meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_VP8); } else if (!strcmp("V_VP9", codecID)) { From 50b21185dc558829b3daba20f98171215aa66646 Mon Sep 17 00:00:00 2001 From: Steve Kondik Date: Thu, 25 Jul 2013 17:33:47 +0800 Subject: [PATCH 57/73] libstagefright: Extended media support via FFMPEG * Original work by Michael Chen - https://github.com/omxcodec * Kitkat port by Chih-Wei Huang / Android X86 project * Additional fixes by Arcee and Cyanogen * High resolution support by Cyanogen * Lollipop port and refactoring by Cyanogen * Marshmallow port and refactoring by Cyanogen ------ libstagefright: add null checking to addPlugin libstagefright: fix error handling of dlsym() According 'man dlsym', a NULL return from dlsym() doesn't indicate an error. The correct way to test for an error is to call dlerror() to clear any old error conditions, then call dlsym(), and then call dlerror() again to check whether its return value is not NULL. libstagefright: add more media mimetypes This is the first step to add the ffmpeg plugins. libstagefright: add ExtractorPlugin The patch allows to load an ExtractorPlugin to extend the functions of DataSource::sniff and MediaExtractor. A plugin has to implement a C function getExtractorPlugin to fill the MediaExtractor::Plugin struct. The filename of the plugin could be specified by the media.stagefright.extractor-plugin property. Change-Id: I995a37a4f1ab4bba6ca3c24c7001a27a1e3ccb90 FLACExtractor: Add more sample rates support In FLACExtractor.cpp, it has function to check file's sample rate. If the input sample rate is not in its list, it will return "unsupported sample rate" issue. Modify code to make other sample rates (100,1k,42k,46k) pass the check Issue: AXIA-1441 Change-Id: I48f91119275560ec6d00feb0dedc70d10aa55262 Signed-off-by: Xiaobing Feng Signed-off-by: Matt Gumbel libstagefright: add ffmpeg components libstagefright: add more decoders Add support for wma, wmv, ra, ape, dts decoders. Change-Id: Iaf48a806aa0cef7d9bcb848383fc3d778c8bd248 libstagefright: allow to use the extended extractor in priority If the meta contains the string "extended-extractor-use", use the extended extractor first. add support for rv20, rv30 add ffmpeg heuristic decoder Change-Id: I5eed11b563ca7f15d44bacfb795d6f3da08ab883 add HEVC(H.265) decoder and cleanup Squashed the following commits of branch cm_maguro-10.1 from https://github.com/omxcodec/android_frameworks_av.git by Michael Chen defb904 remove MEDIA_MIMETYPE_AUDIO_MP2 8036958 add fetchUriFromFd func to get file name 91bc7d5 fix videoCompressionFormatString and audioCodingTypeString funcs f03069f reset FRAME_DROP_FREQ to 0 718b99a add HEVC(H.265) decoder 84f8bf6 cleanup f026c93 cleanup 440614a add debug info Change-Id: Ie75db0778f633357e2280aef6d47a0fa3beb823e AwesomePlayer: use AwesomeLocalRenderer for OMX.ffmpeg.* components stagefright: Remove duplicate types from QC media defs Change-Id: I50ecafe79a2985d0868a1ac82464d6ca448aa2c5 Signed-off-by: Josue Rivera Conflicts: media/libstagefright/ExtendedMediaDefs.cpp media/libstagefright/OMXCodec.cpp libstagefright: Re-introduce a QCOM_HARDWARE ifdef after the FFMPEG commit Fixes a build error on non QCOM hardware. Change-Id: I4a4268b351d0d8bf748dd03ccea0fbab20ed4314 DataSource: Split off ffmpeg sniffer to a second pass, and only if necessary ffmpeg's sniffer is intended as a grab-all-that-doesn't-work-elsewhere extractor. Unfortunately, this causes two issues: - As written, it requires ffmpeg to whitelist any extractors supported by stagefright, or else it will blindly override them. This has codebase sync issues, as shown by the VP9 and WAV accidental overrides - It imposes an in-depth analysis of _all_ media, even that which we want to be processed quickly by shipping stagefright plugins (hardware or not). This is mostly noticeable in network streams and thumbnail generation. This patch moves FFmpegExtractor to an independent sniffer queue, and it only invokes it when the regular MediaExtractor hits 1 of 3 conditions: 1 - The confidence in the identified container type is low 2 - No container is identified at all 3 - A video container was found by other extractors, but only 1 stream (audio or video) was identified. Change-Id: Ib96ff4f6bc06223fe0e819a57560d3c872a79ddd stagefright: OMX.ffmpeg.* are software decoders, ensure they're treated as such Wherever the component name for OMX.google soft decoders is used to identify a software-based component, do the same for ffmpeg. Things like memory management and window buffers care about this. Change-Id: Ib83561936c7383e8726edb073cea9d78f7d1312f libstagefright: Don't invoke FFMPEG for MP3 Change-Id: Ia30d25d1a994328827f14a286661cd2e1eaa1181 stagefright: Fix audio codec fallthru * We shouldn't return an error from setAudioFormat unless it's really an error since fallthru is necessary. * We don't even need to do this, since the component name is checked before calling into mm-parser or FFMPEG. * Fixes Vorbis decoding after FFMPEG patch. Change-Id: I4871c62044c6693e5698119dee3a10c20c26e2c7 stagefright: Fix codec lookup bugs on NuPlayer * Fix use of WMA/WMV software codecs * Fix mpeg2 software codec name * Don't override the component name in ACodec. This actually breaks stuff because the format isn't available in the kInit message. Change-Id: I93c292e039de5f24c2ccbd6ae2242b06d28fe518 stagefright: Cleanup and improve format parsing * Move FFMPEG-specific exceptions to FFMPEGSoftCodec * Add handling for AAC MAIN profile * Use the new OMX_AUDIO_CodingAndroidAC3 to handle AC3 Change-Id: Ibb806cd2b9dd23dc1e1b2c862fcde40605023a49 stagefright: Keep track of the bit width in the RAW codec * We need this to push 24-bit PCM around Stagefright and OMX Change-Id: Ic94ec972162a01545d5dd0ad0bf3eb6c6731f42e stagefright: Adjust confidence threshold for extended sniffers * Some sniffers return 0.2 for cases where they only find an audio track in some containers. * Change the comparison to also examine files right on this threshold. * This allows us to score ONE FUCKING HUNDRED PERCENT on the Antutu Video Test \o/ Change-Id: I78b6ab8a634771e0e290f669801f5b08d6a32a51 stagefright: Fix FFMPEG catchall decoders * Get this metadata properly flowing * Allows us to play tracks such as Apple Lossless :) Change-Id: I2990b30eef5b672da339d24444424c61a43b85c2 stagefright: Fix metadata/message conversion issues * Remove duplication of code between ExtendedCodec and FFMPEGSoftCodec, just call into ExtendedCodec and properly ifdef QCOM-only parts. * Fix CSD not being converted when AV_ENHANCEMENTS wasn't set- this was breaking the software video codecs on Hammerhead. Change-Id: I9cd4316ce19b15baabf12b78b992498ce48e2697 Fix compile error after I9cd4316ce19b15baabf12b78b992498ce48e2697 frameworks/av/media/libstagefright/ExtendedCodec.cpp:1187:1: error: expected '}' at end of input Change-Id: I7d75e69160f794b177f4235f4a6bb5a188dc0d08 stagefright: Fix AC3 playback * Skip setupAC3Codec in ACodec for non-Google components. Change-Id: I5090485ba020f7ad1c0962fc977e38675b4c8314 stagefright: Guard against crash with mismatched codecs * Return unsupported error if WMV file can't be scanned. Change-Id: Ia4a1ac7a299990f8b9c05a93736cb2fa9d0ee965 stagefright: Correct ifdeffage of some QC codecs Change-Id: Ie8cc7287967b84e09941283559ca542efd928d91 stagefright: Create native window for FFMPEG software codecs Change-Id: I178f334f1fa1ea9edc6898fb61e72902c2cb2651 stagefright: Don't ever try to use extended sniffers on DRM * This can cause long retry intervals during key exchange. Don't do it! Change-Id: Id9a87dcbe43cd0cc9919fe07f0a963e087baccad stagefright: Be more tolerant of missing metadata for FFMPEG codecs * If these codecs are instantiated programatically and required metadata isn't sent, just set some defaults instead of crashing on an assert. * This fixes testAllNonTunneledVideoCodecsSupportFlexibleYUV in MR1 CTS Change-Id: I69bf6105a1be529298de574bd5d3b6813e7a4e8f stagefright: Fix issues with software decoders * Fix MKV thumbnails * Fix VC1 thumbnails * Fix FFMPEG thumbnails * Fix trial decoder * Fix edge cases with WMV3/VC1 playback * Fix a state issue which caused some codecs to get wrong configuration Change-Id: I09599166aa24bcff53f91e43de096c4fad8ca7ad stagefright: ffmpeg: Slightly raise the threshold for the ffmpeg scanner 0.2 is the success value for the OMX.google soft audio sniffers, which was making ffmpeg own the unpacking of those streams needlessly. Fixes CYNGNOS-282 Change-Id: I75f50ed838cb8af9acdf99aa284b80a070555284 stagefright: Add support for loading a custom OMXPlugin * To facilitate moving the stagefright-plugins glue out of the framework, support is added to OMXMaster to load multiple external plugins besides internal/vendor versions. * This is currently limited to one plugin, defined by the "mm.sf.omx-plugin" system property. The code will allow any number of libraries to be loaded, though. * Should also be useful for nonstandard vendor implementations too. Change-Id: I27d7e16ad56baa17754d8ea47a8c608a0d73d6f1 stagefright: Move a bunch of FFMPEG stuff out of here * Get rid of some of the glue code for stagefright-plugins and use the new extension header and plugin. * Still a bunch of TODOs on this, but it works. Change-Id: If07d3213952b624d48035e5f58ad883b2a4049b0 stagefright: Remove deprecated FFMPEG config Change-Id: I1fcdb4eeba72e2420493b89ddd6fc718d170ced7 stagefright: Support for 24-bit audio in StageFright * Plumb bit depth thru ACodec and OMX * Add support for 24-bit PCM offload in NuPlayer on QC devices * Use new AudioFlinger features for mixing multi formats without offload * Clean up a bunch of code Change-Id: I018d3a995b63450a38c6c43eaa37c86be30fd893 nuplayer: Fix PCM offload turning on all the time * Remove the extra condition, since this will be set even if PCM offload was denied. Change-Id: I8f33ef68562d8e057e7a86c5ae6187d0049bf3aa stagefright: Cleanup of PCM offload checks * Put the checks in a single place. Change-Id: I2d0d5b542593896e78bf989296de1a1d1e3a4963 stagefright: Add bit-depth plumbing for new formats Change-Id: I13cfd75e4b4819543b64babf20cc9af57ea2978f nuplayer: Fix bitrate propagation * We use "bitrate" rather than "bit-rate". Change-Id: I4699194e3e3f7ef55b4eb554f5de7a6b5f6b80ce libstagefright: Implement fallback mechanism to SW decoder Implement fallback mechanism to software decoder when hardware decoder configuration fails in ACodec Change-Id: Idf4c445942b03e28b264c91a20e69d52224727bd --- include/media/stagefright/ACodec.h | 11 +- include/media/stagefright/DataSource.h | 4 + include/media/stagefright/FFMPEGSoftCodec.h | 133 ++ include/media/stagefright/FileSource.h | 6 + include/media/stagefright/MediaDefs.h | 35 + include/media/stagefright/MediaExtractor.h | 15 +- include/media/stagefright/MetaData.h | 50 + .../mediaplayerservice/AVNuUtils.cpp | 60 +- media/libavextensions/stagefright/AVUtils.cpp | 6 +- .../libmediaplayerservice/nuplayer/Android.mk | 3 +- .../nuplayer/NuPlayerDecoder.cpp | 10 +- .../nuplayer/NuPlayerRenderer.cpp | 15 +- media/libstagefright/ACodec.cpp | 168 ++- media/libstagefright/Android.mk | 4 + media/libstagefright/DataSource.cpp | 68 +- media/libstagefright/FFMPEGSoftCodec.cpp | 1149 +++++++++++++++++ media/libstagefright/FileSource.cpp | 16 + media/libstagefright/MediaCodec.cpp | 3 +- media/libstagefright/MediaDefs.cpp | 28 + media/libstagefright/MediaExtractor.cpp | 26 +- media/libstagefright/OMXClient.cpp | 1 + .../StagefrightMediaScanner.cpp | 6 +- media/libstagefright/Utils.cpp | 27 +- media/libstagefright/codecs/raw/SoftRaw.cpp | 6 +- media/libstagefright/codecs/raw/SoftRaw.h | 1 + media/libstagefright/include/AwesomePlayer.h | 1 + .../matroska/MatroskaExtractor.cpp | 13 +- services/audioflinger/AudioMixer.h | 1 + 28 files changed, 1799 insertions(+), 67 deletions(-) create mode 100644 include/media/stagefright/FFMPEGSoftCodec.h create mode 100644 media/libstagefright/FFMPEGSoftCodec.cpp diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h index a346e2b7fa4..2e621fe2c14 100644 --- a/include/media/stagefright/ACodec.h +++ b/include/media/stagefright/ACodec.h @@ -28,6 +28,8 @@ #include #include +#include + #define TRACK_BUFFER_TIMING 0 namespace android { @@ -345,9 +347,11 @@ struct ACodec : public AHierarchicalStateMachine, public CodecBase { int32_t maxOutputChannelCount, const drcParams_t& drc, int32_t pcmLimiterEnable); - status_t setupAC3Codec(bool encoder, int32_t numChannels, int32_t sampleRate); + status_t setupAC3Codec(bool encoder, int32_t numChannels, int32_t sampleRate, + int32_t bitsPerSample = 16); - status_t setupEAC3Codec(bool encoder, int32_t numChannels, int32_t sampleRate); + status_t setupEAC3Codec(bool encoder, int32_t numChannels, int32_t sampleRate, + int32_t bitsPerSample = 16); status_t selectAudioPortFormat( OMX_U32 portIndex, OMX_AUDIO_CODINGTYPE desiredFormat); @@ -359,7 +363,8 @@ struct ACodec : public AHierarchicalStateMachine, public CodecBase { bool encoder, int32_t numChannels, int32_t sampleRate, int32_t compressionLevel); status_t setupRawAudioFormat( - OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels); + OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels, + int32_t bitsPerSample = 16); status_t setPriority(int32_t priority); status_t setOperatingRate(float rateFloat, bool isVideo); diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h index de31ff05c7a..56abe71c7e2 100644 --- a/include/media/stagefright/DataSource.h +++ b/include/media/stagefright/DataSource.h @@ -62,8 +62,11 @@ class Sniffer : public RefBase { private: Mutex mSnifferMutex; List mSniffers; + List mExtraSniffers; List::iterator extendedSnifferPosition; + void registerSnifferPlugin(); + Sniffer(const Sniffer &); Sniffer &operator=(const Sniffer &); }; @@ -145,6 +148,7 @@ class DataSource : public RefBase { sp mSniffer; static void RegisterSniffer_l(SnifferFunc func); + static void RegisterSnifferPlugin(); DataSource(const DataSource &); DataSource &operator=(const DataSource &); diff --git a/include/media/stagefright/FFMPEGSoftCodec.h b/include/media/stagefright/FFMPEGSoftCodec.h new file mode 100644 index 00000000000..83373d03b1b --- /dev/null +++ b/include/media/stagefright/FFMPEGSoftCodec.h @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2014 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef FFMPEG_SOFT_CODEC_H_ +#define FFMPEG_SOFT_CODEC_H_ + +#include +#include + +#include +#include + +#include + +#include +#include + +namespace android { + +struct FFMPEGSoftCodec { + + enum { + kPortIndexInput = 0, + kPortIndexOutput = 1 + }; + + static void convertMessageToMetaDataFF( + const sp &msg, sp &meta); + + static void convertMetaDataToMessageFF( + const sp &meta, sp *format); + + static const char* overrideComponentName( + uint32_t quirks, const sp &meta, + const char *mime, bool isEncoder); + + static void overrideComponentName( + uint32_t quirks, const sp &msg, + AString* componentName, AString* mime, + int32_t isEncoder); + + static status_t setSupportedRole( + const sp &omx, IOMX::node_id node, + bool isEncoder, const char *mime); + + static status_t setAudioFormat( + const sp &msg, const char* mime, + sp OMXhandle, IOMX::node_id nodeID); + + static status_t setVideoFormat( + const sp &msg, const char* mime, + sp OMXhandle,IOMX::node_id nodeID, + bool isEncoder, OMX_VIDEO_CODINGTYPE *compressionFormat); + + static status_t getAudioPortFormat( + OMX_U32 portIndex, int coding, + sp ¬ify, sp OMXhandle, IOMX::node_id nodeID); + + static status_t getVideoPortFormat( + OMX_U32 portIndex, int coding, + sp ¬ify, sp OMXhandle, IOMX::node_id nodeID); + +private: + static const char* getMsgKey(int key); + + static status_t setWMVFormat( + const sp &msg, sp OMXhandle, + IOMX::node_id nodeID); + + static status_t setRVFormat( + const sp &msg, sp OMXhandle, + IOMX::node_id nodeID); + + static status_t setFFmpegVideoFormat( + const sp &msg, sp OMXhandle, + IOMX::node_id nodeID); + + static status_t setRawAudioFormat( + const sp &msg, sp OMXhandle, + IOMX::node_id nodeID); + + static status_t setWMAFormat( + const sp &msg, sp OMXhandle, + IOMX::node_id nodeID); + + static status_t setVORBISFormat( + const sp &msg, sp OMXhandle, + IOMX::node_id nodeID); + + static status_t setRAFormat( + const sp &msg, sp OMXhandle, + IOMX::node_id nodeID); + + static status_t setFLACFormat( + const sp &msg, sp OMXhandle, + IOMX::node_id nodeID); + + static status_t setMP2Format( + const sp &msg, sp OMXhandle, + IOMX::node_id nodeID); + + static status_t setAC3Format( + const sp &msg, sp OMXhandle, + IOMX::node_id nodeID); + + static status_t setAPEFormat( + const sp &msg, sp OMXhandle, + IOMX::node_id nodeID); + + static status_t setDTSFormat( + const sp &msg, sp OMXhandle, + IOMX::node_id nodeID); + + static status_t setFFmpegAudioFormat( + const sp &msg, sp OMXhandle, + IOMX::node_id nodeID); + +}; + +} +#endif diff --git a/include/media/stagefright/FileSource.h b/include/media/stagefright/FileSource.h index a981d1c2d63..21844ca1a9a 100644 --- a/include/media/stagefright/FileSource.h +++ b/include/media/stagefright/FileSource.h @@ -39,6 +39,10 @@ class FileSource : public DataSource { virtual status_t getSize(off64_t *size); + virtual String8 getUri() { + return mUri; + } + virtual sp DrmInitialization(const char *mime); virtual void getDrmInfo(sp &handle, DrmManagerClient **client); @@ -48,6 +52,7 @@ class FileSource : public DataSource { private: int mFd; + String8 mUri; int64_t mOffset; int64_t mLength; Mutex mLock; @@ -60,6 +65,7 @@ class FileSource : public DataSource { unsigned char *mDrmBuf; ssize_t readAtDRM(off64_t offset, void *data, size_t size); + void fetchUriFromFd(int fd); FileSource(const FileSource &); FileSource &operator=(const FileSource &); diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h index 8b1e63b2cd2..ffbd20c6e08 100644 --- a/include/media/stagefright/MediaDefs.h +++ b/include/media/stagefright/MediaDefs.h @@ -66,6 +66,41 @@ extern const char *MEDIA_MIMETYPE_TEXT_VTT; extern const char *MEDIA_MIMETYPE_TEXT_CEA_608; extern const char *MEDIA_MIMETYPE_DATA_TIMED_ID3; +extern const char *MEDIA_MIMETYPE_AUDIO_EAC3_JOC; +extern const char *MEDIA_MIMETYPE_AUDIO_EAC3; + +extern const char *MEDIA_MIMETYPE_VIDEO_FLV1; +extern const char *MEDIA_MIMETYPE_VIDEO_MJPEG; +extern const char *MEDIA_MIMETYPE_VIDEO_RV; +extern const char *MEDIA_MIMETYPE_VIDEO_VC1; +extern const char *MEDIA_MIMETYPE_VIDEO_WMV; +extern const char *MEDIA_MIMETYPE_VIDEO_HEVC; +extern const char *MEDIA_MIMETYPE_VIDEO_FFMPEG; + +extern const char *MEDIA_MIMETYPE_AUDIO_AC3; +extern const char *MEDIA_MIMETYPE_AUDIO_PCM; +extern const char *MEDIA_MIMETYPE_AUDIO_RA; +extern const char *MEDIA_MIMETYPE_AUDIO_WMA; +extern const char *MEDIA_MIMETYPE_AUDIO_FFMPEG; + +extern const char *MEDIA_MIMETYPE_CONTAINER_APE; +extern const char *MEDIA_MIMETYPE_CONTAINER_DIVX; +extern const char *MEDIA_MIMETYPE_CONTAINER_DTS; +extern const char *MEDIA_MIMETYPE_CONTAINER_FLAC; +extern const char *MEDIA_MIMETYPE_CONTAINER_FLV; +extern const char *MEDIA_MIMETYPE_CONTAINER_MOV; +extern const char *MEDIA_MIMETYPE_CONTAINER_MP2; +extern const char *MEDIA_MIMETYPE_CONTAINER_MPG; +extern const char *MEDIA_MIMETYPE_CONTAINER_RA; +extern const char *MEDIA_MIMETYPE_CONTAINER_RM; +extern const char *MEDIA_MIMETYPE_CONTAINER_TS; +extern const char *MEDIA_MIMETYPE_CONTAINER_WEBM; +extern const char *MEDIA_MIMETYPE_CONTAINER_VC1; +extern const char *MEDIA_MIMETYPE_CONTAINER_HEVC; +extern const char *MEDIA_MIMETYPE_CONTAINER_WMA; +extern const char *MEDIA_MIMETYPE_CONTAINER_WMV; +extern const char *MEDIA_MIMETYPE_CONTAINER_FFMPEG; + } // namespace android #include diff --git a/include/media/stagefright/MediaExtractor.h b/include/media/stagefright/MediaExtractor.h index 32925ca6585..2f2057fff3b 100644 --- a/include/media/stagefright/MediaExtractor.h +++ b/include/media/stagefright/MediaExtractor.h @@ -19,15 +19,27 @@ #define MEDIA_EXTRACTOR_H_ #include +#include namespace android { -class DataSource; class MediaSource; class MetaData; class MediaExtractor : public RefBase { public: + typedef MediaExtractor *(*CreateFunc)(const sp &source, + const char *mime, const sp &meta); + + struct Plugin { + DataSource::SnifferFunc sniff; + CreateFunc create; + }; + + static Plugin *getPlugin() { + return &sPlugin; + } + static sp Create( const sp &source, const char *mime = NULL, const uint32_t flags = 0); @@ -76,6 +88,7 @@ class MediaExtractor : public RefBase { private: bool mIsDrm; + static Plugin sPlugin; MediaExtractor(const MediaExtractor &); MediaExtractor &operator=(const MediaExtractor &); diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h index 8d4e15a5c14..275ef55d124 100644 --- a/include/media/stagefright/MetaData.h +++ b/include/media/stagefright/MetaData.h @@ -50,6 +50,10 @@ enum { kKeySampleRate = 'srte', // int32_t (audio sampling rate Hz) kKeyFrameRate = 'frmR', // int32_t (video frame rate fps) kKeyBitRate = 'brte', // int32_t (bps) + kKeyCodecId = 'cdid', // int32_t + kKeyBitsPerSample = 'sbit', // int32_t (DUPE of kKeySampleBits) + kKeyCodedSampleBits = 'cosb', // int32_t + kKeySampleFormat = 'sfmt', // int32_t kKeyESDS = 'esds', // raw data kKeyAACProfile = 'aacp', // int32_t kKeyAVCC = 'avcc', // raw data @@ -131,6 +135,23 @@ enum { kKeyIsUnreadable = 'unre', // bool (int32_t) + kKeyRawCodecSpecificData = 'rcsd', // raw data - added to support mmParser + kKeyDivXVersion = 'DivX', // int32_t + kKeyDivXDrm = 'QDrm', // void * + kKeyWMAEncodeOpt = 'eopt', // int32_t + kKeyWMABlockAlign = 'blka', // int32_t + kKeyWMAVersion = 'wmav', // int32_t + kKeyWMAAdvEncOpt1 = 'ade1', // int16_t + kKeyWMAAdvEncOpt2 = 'ade2', // int32_t + kKeyWMAFormatTag = 'fmtt', // int64_t + kKeyWMABitspersample = 'bsps', // int64_t + kKeyWMAVirPktSize = 'vpks', // int64_t + kKeyWMVProfile = 'wmvp', // int32_t + + kKeyWMVVersion = 'wmvv', // int32_t + kKeyRVVersion = '#rvv', // int32_t + kKeyBlockAlign = 'blk', // int32_t , should be different from kKeyWMABlockAlign + // An indication that a video buffer has been rendered. kKeyRendered = 'rend', // bool (int32_t) @@ -181,6 +202,9 @@ enum { // H264 supplemental enhancement information offsets/sizes kKeySEI = 'sei ', // raw data + + kKeyPCMFormat = 'pfmt', + kKeyArbitraryMode = 'ArbM', }; enum { @@ -190,6 +214,32 @@ enum { kTypeD263 = 'd263', }; +enum { + kTypeDivXVer_3_11, + kTypeDivXVer_4, + kTypeDivXVer_5, + kTypeDivXVer_6, +}; + +enum { + kTypeWMA, + kTypeWMAPro, + kTypeWMALossLess, +}; + +enum { + kTypeWMVVer_7, // WMV1 + kTypeWMVVer_8, // WMV2 + kTypeWMVVer_9, // WMV3 +}; + +// http://en.wikipedia.org/wiki/RealVideo +enum { + kTypeRVVer_G2, // rv20: RealVideo G2 + kTypeRVVer_8, // rv30: RealVideo 8 + kTypeRVVer_9, // rv40: RealVideo 9 +}; + class MetaData : public RefBase { public: MetaData(); diff --git a/media/libavextensions/mediaplayerservice/AVNuUtils.cpp b/media/libavextensions/mediaplayerservice/AVNuUtils.cpp index c254a70c56d..abfe9d2c6c7 100644 --- a/media/libavextensions/mediaplayerservice/AVNuUtils.cpp +++ b/media/libavextensions/mediaplayerservice/AVNuUtils.cpp @@ -33,6 +33,8 @@ #include #include +#include + #include #include #include @@ -52,12 +54,29 @@ bool AVNuUtils::pcmOffloadException(const sp &) { return true; } -bool AVNuUtils::isRAWFormat(const sp &) { - return false; +bool AVNuUtils::isRAWFormat(const sp &meta) { + const char *mime = {0}; + if (meta == NULL) { + return false; + } + CHECK(meta->findCString(kKeyMIMEType, &mime)); + if (!strncasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW, 9)) + return true; + else + return false; } -bool AVNuUtils::isRAWFormat(const sp &) { - return false; +bool AVNuUtils::isRAWFormat(const sp &format) { + AString mime; + if (format == NULL) { + return false; + } + CHECK(format->findString("mime", &mime)); + if (!strncasecmp(mime.c_str(), MEDIA_MIMETYPE_AUDIO_RAW, 9)) + return true; + else + return false; + } bool AVNuUtils::isVorbisFormat(const sp &) { @@ -69,20 +88,39 @@ int AVNuUtils::updateAudioBitWidth(audio_format_t /*audioFormat*/, return 16; } -audio_format_t AVNuUtils::getKeyPCMFormat(const sp &) { - return AUDIO_FORMAT_INVALID; -} +audio_format_t AVNuUtils::getKeyPCMFormat(const sp &meta) { + int32_t pcmFormat = 0; + if (meta->findInt32('pfmt', &pcmFormat)) + return (audio_format_t)pcmFormat; -void AVNuUtils::setKeyPCMFormat(const sp &, audio_format_t /*audioFormat*/) { + return AUDIO_FORMAT_PCM_16_BIT; +} +void AVNuUtils::setKeyPCMFormat(const sp &meta, audio_format_t audioFormat) { + if (audio_is_linear_pcm(audioFormat)) + meta->setInt32('pfmt', audioFormat); } -audio_format_t AVNuUtils::getPCMFormat(const sp &) { +audio_format_t AVNuUtils::getPCMFormat(const sp &format) { + int32_t pcmFormat = 0; + if (format->findInt32("pcm-format", &pcmFormat)) + return (audio_format_t)pcmFormat; + + int32_t bits = 16; + if (format->findInt32("bit-width", &bits)) { + if (bits == 8) + return AUDIO_FORMAT_PCM_8_BIT; + if (bits == 24) + return AUDIO_FORMAT_PCM_32_BIT; + if (bits == 32) + return AUDIO_FORMAT_PCM_FLOAT; + } return AUDIO_FORMAT_PCM_16_BIT; } -void AVNuUtils::setPCMFormat(const sp &, audio_format_t /*audioFormat*/) { - +void AVNuUtils::setPCMFormat(const sp &format, audio_format_t audioFormat) { + if (audio_is_linear_pcm(audioFormat)) + format->setInt32("pcm-format", audioFormat); } void AVNuUtils::setSourcePCMFormat(const sp &) { diff --git a/media/libavextensions/stagefright/AVUtils.cpp b/media/libavextensions/stagefright/AVUtils.cpp index 324ff9b6e73..50c0f89dc8e 100644 --- a/media/libavextensions/stagefright/AVUtils.cpp +++ b/media/libavextensions/stagefright/AVUtils.cpp @@ -66,8 +66,10 @@ int AVUtils::getAudioSampleBits(const sp &) { return 16; } -int AVUtils::getAudioSampleBits(const sp &) { - return 16; +int AVUtils::getAudioSampleBits(const sp &format) { + int32_t bits = 16; + format->findInt32("bit-width", &bits); + return bits; } void AVUtils::setPcmSampleBits(const sp &, int32_t /*bitWidth*/) { diff --git a/media/libmediaplayerservice/nuplayer/Android.mk b/media/libmediaplayerservice/nuplayer/Android.mk index 005cb4b4252..6729cd55c11 100644 --- a/media/libmediaplayerservice/nuplayer/Android.mk +++ b/media/libmediaplayerservice/nuplayer/Android.mk @@ -24,7 +24,8 @@ LOCAL_C_INCLUDES := \ $(TOP)/frameworks/av/media/libstagefright/timedtext \ $(TOP)/frameworks/av/media/libmediaplayerservice \ $(TOP)/frameworks/native/include/media/openmax \ - $(TOP)/frameworks/av/media/libavextensions \ + $(TOP)/frameworks/av/media/libavextensions \ + $(TOP)/frameworks/av/include/media \ LOCAL_CFLAGS += -Werror -Wall diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index baea834304f..3cf5b29a56b 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -35,6 +35,7 @@ #include #include +#include #include #include "avc_utils.h" @@ -257,9 +258,16 @@ void NuPlayer::Decoder::onConfigure(const sp &format) { ALOGV("[%s] onConfigure (surface=%p)", mComponentName.c_str(), mSurface.get()); mCodec = AVUtils::get()->createCustomComponentByName(mCodecLooper, mime.c_str(), false /* encoder */, format); + FFMPEGSoftCodec::overrideComponentName(0, format, &mComponentName, &mime, false); + if (mCodec == NULL) { - mCodec = MediaCodec::CreateByType(mCodecLooper, mime.c_str(), false /* encoder */); + if (!mComponentName.startsWith(mime.c_str())) { + mCodec = MediaCodec::CreateByComponentName(mCodecLooper, mComponentName.c_str()); + } else { + mCodec = MediaCodec::CreateByType(mCodecLooper, mime.c_str(), false /* encoder */); + } } + int32_t secure = 0; if (format->findInt32("secure", &secure) && secure != 0) { if (mCodec != NULL) { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index 9d2f134cc0c..b034459911f 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -1678,13 +1679,17 @@ status_t NuPlayer::Renderer::onOpenAudioSink( channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER; } + int32_t bitWidth = 16; + format->findInt32("bit-width", &bitWidth); + int32_t sampleRate; CHECK(format->findInt32("sample-rate", &sampleRate)); + AString mime; + CHECK(format->findString("mime", &mime)); + if (offloadingAudio()) { audio_format_t audioFormat = AUDIO_FORMAT_PCM_16_BIT; - AString mime; - CHECK(format->findString("mime", &mime)); status_t err = mapMimeToAudioFormat(audioFormat, mime.c_str()); if (err != OK) { @@ -1692,15 +1697,11 @@ status_t NuPlayer::Renderer::onOpenAudioSink( "audio_format", mime.c_str()); onDisableOffloadAudio(); } else { - int32_t bitWidth = 16; - ALOGV("Mime \"%s\" mapped to audio_format 0x%x", - mime.c_str(), audioFormat); - audioFormat = AVUtils::get()->updateAudioFormat(audioFormat, format); bitWidth = AVUtils::get()->getAudioSampleBits(format); int avgBitRate = -1; - format->findInt32("bit-rate", &avgBitRate); + format->findInt32("bitrate", &avgBitRate); int32_t aacProfile = -1; if (audioFormat == AUDIO_FORMAT_AAC diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index f40a3c4b845..83954f90a35 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -44,6 +44,8 @@ #include #include #include +#include + #include #include @@ -541,7 +543,12 @@ ACodec::ACodec() ACodec::~ACodec() { } -status_t ACodec::setupCustomCodec(status_t err, const char *, const sp &) { +status_t ACodec::setupCustomCodec(status_t err, const char *mime, const sp &msg) { + if (!strncmp(mComponentName.c_str(), "OMX.ffmpeg.", 11) && !mIsEncoder) { + return FFMPEGSoftCodec::setAudioFormat( + msg, mime, mOMX, mNode); + } + return err; } @@ -1589,7 +1596,11 @@ status_t ACodec::setComponentRole( } if (i == kNumMimeToRole) { - return ERROR_UNSUPPORTED; + status_t err = ERROR_UNSUPPORTED; + if (!strncmp(mComponentName.c_str(), "OMX.ffmpeg.", 11)) { + err = FFMPEGSoftCodec::setSupportedRole(mOMX, mNode, isEncoder, mime); + } + return err; } const char *role = @@ -1910,7 +1921,8 @@ status_t ACodec::configureCodec( if (video) { // determine need for software renderer bool usingSwRenderer = false; - if (haveNativeWindow && mComponentName.startsWith("OMX.google.")) { + if (haveNativeWindow && (mComponentName.startsWith("OMX.google.") || + mComponentName.startsWith("OMX.ffmpeg."))) { usingSwRenderer = true; haveNativeWindow = false; } @@ -1995,10 +2007,12 @@ status_t ACodec::configureCodec( // and have the decoder figure it all out. err = OK; } else { + int32_t bitsPerSample = 16; + msg->findInt32("bit-width", &bitsPerSample); err = setupRawAudioFormat( encoder ? kPortIndexInput : kPortIndexOutput, sampleRate, - numChannels); + numChannels, bitsPerSample); } } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { int32_t numChannels, sampleRate; @@ -2073,11 +2087,7 @@ status_t ACodec::configureCodec( } err = setupG711Codec(encoder, sampleRate, numChannels); } -#ifdef QTI_FLAC_DECODER } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC) && encoder) { -#else - } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC)) { -#endif int32_t numChannels = 0, sampleRate = 0, compressionLevel = -1; if (encoder && (!msg->findInt32("channel-count", &numChannels) @@ -2113,16 +2123,21 @@ status_t ACodec::configureCodec( || !msg->findInt32("sample-rate", &sampleRate)) { err = INVALID_OPERATION; } else { - err = setupRawAudioFormat(kPortIndexInput, sampleRate, numChannels); + int32_t bitsPerSample = 16; + msg->findInt32("bit-width", &bitsPerSample); + err = setupRawAudioFormat(kPortIndexInput, sampleRate, numChannels, bitsPerSample); } - } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AC3)) { + } else if (!strncmp(mComponentName.c_str(), "OMX.google.", 11) + && !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AC3)) { int32_t numChannels; int32_t sampleRate; if (!msg->findInt32("channel-count", &numChannels) || !msg->findInt32("sample-rate", &sampleRate)) { err = INVALID_OPERATION; } else { - err = setupAC3Codec(encoder, numChannels, sampleRate); + int32_t bitsPerSample = 16; + msg->findInt32("bit-width", &bitsPerSample); + err = setupAC3Codec(encoder, numChannels, sampleRate, bitsPerSample); } } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_EAC3)) { int32_t numChannels; @@ -2131,7 +2146,9 @@ status_t ACodec::configureCodec( || !msg->findInt32("sample-rate", &sampleRate)) { err = INVALID_OPERATION; } else { - err = setupEAC3Codec(encoder, numChannels, sampleRate); + int32_t bitsPerSample = 16; + msg->findInt32("bit-width", &bitsPerSample); + err = setupEAC3Codec(encoder, numChannels, sampleRate, bitsPerSample); } } else { err = setupCustomCodec(err, mime, msg); @@ -2448,9 +2465,9 @@ status_t ACodec::setupAACCodec( } status_t ACodec::setupAC3Codec( - bool encoder, int32_t numChannels, int32_t sampleRate) { + bool encoder, int32_t numChannels, int32_t sampleRate, int32_t bitsPerSample) { status_t err = setupRawAudioFormat( - encoder ? kPortIndexInput : kPortIndexOutput, sampleRate, numChannels); + encoder ? kPortIndexInput : kPortIndexOutput, sampleRate, numChannels, bitsPerSample); if (err != OK) { return err; @@ -2486,9 +2503,9 @@ status_t ACodec::setupAC3Codec( } status_t ACodec::setupEAC3Codec( - bool encoder, int32_t numChannels, int32_t sampleRate) { + bool encoder, int32_t numChannels, int32_t sampleRate, int32_t bitsPerSample) { status_t err = setupRawAudioFormat( - encoder ? kPortIndexInput : kPortIndexOutput, sampleRate, numChannels); + encoder ? kPortIndexInput : kPortIndexOutput, sampleRate, numChannels, bitsPerSample); if (err != OK) { return err; @@ -2634,7 +2651,7 @@ status_t ACodec::setupFlacCodec( } status_t ACodec::setupRawAudioFormat( - OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels) { + OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels, int32_t bitsPerSample) { OMX_PARAM_PORTDEFINITIONTYPE def; InitOMXParams(&def); def.nPortIndex = portIndex; @@ -2669,7 +2686,7 @@ status_t ACodec::setupRawAudioFormat( pcmParams.nChannels = numChannels; pcmParams.eNumData = OMX_NumericalDataSigned; pcmParams.bInterleaved = OMX_TRUE; - pcmParams.nBitPerSample = 16; + pcmParams.nBitPerSample = bitsPerSample; pcmParams.nSamplingRate = sampleRate; pcmParams.ePCMMode = OMX_AUDIO_PCMModeLinear; @@ -2896,7 +2913,13 @@ status_t ACodec::setupVideoDecoder( status_t err = GetVideoCodingTypeFromMime(mime, &compressionFormat); if (err != OK) { - return err; + if (!strncmp(mComponentName.c_str(), "OMX.ffmpeg.", 11)) { + err = FFMPEGSoftCodec::setVideoFormat( + msg, mime, mOMX, mNode, mIsEncoder, &compressionFormat); + } + if (err != OK) { + return err; + } } err = setVideoPortFormatType( @@ -3046,7 +3069,14 @@ status_t ACodec::setupVideoEncoder(const char *mime, const sp &msg) { err = GetVideoCodingTypeFromMime(mime, &compressionFormat); if (err != OK) { - return err; + if (!strncmp(mComponentName.c_str(), "OMX.ffmpeg.", 11)) { + err = FFMPEGSoftCodec::setVideoFormat( + msg, mime, mOMX, mNode, mIsEncoder, &compressionFormat); + } + if (err != OK) { + ALOGE("Not a supported video mime type: %s", mime); + return err; + } } err = setVideoPortFormatType( @@ -4154,6 +4184,14 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp ¬ify) { default: { + if (!strncmp(mComponentName.c_str(), "OMX.ffmpeg.", 11)) { + err = FFMPEGSoftCodec::getVideoPortFormat(portIndex, + (int)videoDef->eCompressionFormat, notify, mOMX, mNode); + } + if (err == OK) { + break; + } + if (mIsEncoder ^ (portIndex == kPortIndexOutput)) { // should be CodingUnused ALOGE("Raw port video compression format is %s(%d)", @@ -4200,7 +4238,9 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp ¬ify) { if (params.nChannels <= 0 || (params.nChannels != 1 && !params.bInterleaved) || (params.nBitPerSample != 16u - && params.nBitPerSample != 24u)// we support 16/24 bit s/w decoding + && params.nBitPerSample != 24u + && params.nBitPerSample != 32u + && params.nBitPerSample != 8u)// we support 8/16/24/32 bit s/w decoding || params.eNumData != OMX_NumericalDataSigned || params.ePCMMode != OMX_AUDIO_PCMModeLinear) { ALOGE("unsupported PCM port: %u channels%s, %u-bit, %s(%d), %s(%d) mode ", @@ -4216,6 +4256,7 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp ¬ify) { notify->setInt32("channel-count", params.nChannels); notify->setInt32("sample-rate", params.nSamplingRate); notify->setInt32("bit-width", params.nBitPerSample); + if (mChannelMaskPresent) { notify->setInt32("channel-mask", mChannelMask); } @@ -4265,6 +4306,7 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp ¬ify) { case OMX_AUDIO_CodingFLAC: { + if (portIndex == kPortIndexInput) { OMX_AUDIO_PARAM_FLACTYPE params; InitOMXParams(¶ms); params.nPortIndex = portIndex; @@ -4279,6 +4321,7 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp ¬ify) { notify->setInt32("channel-count", params.nChannels); notify->setInt32("sample-rate", params.nSampleRate); break; + } } case OMX_AUDIO_CodingMP3: @@ -4419,6 +4462,14 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp ¬ify) { } default: + if (!strncmp(mComponentName.c_str(), "OMX.ffmpeg.", 11)) { + err = FFMPEGSoftCodec::getAudioPortFormat(portIndex, + (int)audioDef->eEncoding, notify, mOMX, mNode); + } + if (err == OK) { + break; + } + ALOGE("Unsupported audio coding: %s(%d)\n", asString(audioDef->eEncoding), audioDef->eEncoding); return BAD_TYPE; @@ -5718,8 +5769,79 @@ bool ACodec::LoadedState::onConfigureComponent( ALOGE("[%s] configureCodec returning error %d", mCodec->mComponentName.c_str(), err); - mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err)); - return false; + int32_t encoder; + if (!msg->findInt32("encoder", &encoder)) { + encoder = false; + } + + if (!encoder && !strncmp(mime.c_str(), "video/", strlen("video/"))) { + Vector matchingCodecs; + + OMXCodec::findMatchingCodecs( + mime.c_str(), + encoder, // createEncoder + NULL, // matchComponentName + 0, // flags + &matchingCodecs); + + status_t err = mCodec->mOMX->freeNode(mCodec->mNode); + + if (err != OK) { + ALOGE("Failed to freeNode"); + mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err)); + return false; + } + + mCodec->mNode = 0; + AString componentName; + sp observer = new CodecObserver; + + err = NAME_NOT_FOUND; + for (size_t matchIndex = 0; matchIndex < matchingCodecs.size(); + ++matchIndex) { + componentName = matchingCodecs.itemAt(matchIndex).mName.string(); + if (!strcmp(mCodec->mComponentName.c_str(), componentName.c_str())) { + continue; + } + + pid_t tid = gettid(); + int prevPriority = androidGetThreadPriority(tid); + androidSetThreadPriority(tid, ANDROID_PRIORITY_FOREGROUND); + err = mCodec->mOMX->allocateNode(componentName.c_str(), observer, &mCodec->mNode); + androidSetThreadPriority(tid, prevPriority); + + if (err == OK) { + break; + } else { + ALOGW("Allocating component '%s' failed, try next one.", componentName.c_str()); + } + + mCodec->mNode = 0; + } + + if (mCodec->mNode == 0) { + if (!mime.empty()) { + ALOGE("Unable to instantiate a %scoder for type '%s' with err %#x.", + encoder ? "en" : "de", mime.c_str(), err); + } else { + ALOGE("Unable to instantiate codec '%s' with err %#x.", componentName.c_str(), err); + } + + mCodec->signalError((OMX_ERRORTYPE)err, makeNoSideEffectStatus(err)); + return false; + } + + sp notify = new AMessage(kWhatOMXMessageList, mCodec); + observer->setNotificationMessage(notify); + mCodec->mComponentName = componentName; + + err = mCodec->configureCodec(mime.c_str(), msg); + + if (err != OK) { + mCodec->signalError((OMX_ERRORTYPE)err, makeNoSideEffectStatus(err)); + return false; + } + } } { diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index 36b1cf4daf1..09ff30259c4 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -70,6 +70,7 @@ LOCAL_SRC_FILES:= \ XINGSeeker.cpp \ avc_utils.cpp \ APE.cpp \ + FFMPEGSoftCodec.cpp \ LOCAL_C_INCLUDES:= \ $(TOP)/frameworks/av/include/media/ \ @@ -140,6 +141,9 @@ endif LOCAL_CLANG := true +# FFMPEG plugin +LOCAL_C_INCLUDES += $(TOP)/external/stagefright-plugins/include + LOCAL_MODULE:= libstagefright LOCAL_MODULE_TAGS := optional diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp index 92303293662..39326c9d56c 100644 --- a/media/libstagefright/DataSource.cpp +++ b/media/libstagefright/DataSource.cpp @@ -47,11 +47,28 @@ #include #include +#include + +#include #include namespace android { +static void *loadExtractorPlugin() { + void *ret = NULL; + char lib[PROPERTY_VALUE_MAX]; + if (property_get("media.sf.extractor-plugin", lib, NULL)) { + if (void *extractorLib = ::dlopen(lib, RTLD_LAZY)) { + ret = ::dlsym(extractorLib, "getExtractorPlugin"); + ALOGW_IF(!ret, "Failed to find symbol, dlerror: %s", ::dlerror()); + } else { + ALOGV("Failed to load %s, dlerror: %s", lib, ::dlerror()); + } + } + return ret; +} + bool DataSource::getUInt16(off64_t offset, uint16_t *x) { *x = 0; @@ -119,7 +136,7 @@ bool DataSource::sniff( } // static -void DataSource::RegisterSniffer_l(SnifferFunc func) { +void DataSource::RegisterSniffer_l(SnifferFunc /* func */) { return; } @@ -137,6 +154,13 @@ Sniffer::Sniffer() { bool Sniffer::sniff( DataSource *source, String8 *mimeType, float *confidence, sp *meta) { + bool forceExtraSniffers = false; + + if (*confidence == 3.14f) { + // Magic value, as set by MediaExtractor when a video container looks incomplete + forceExtraSniffers = true; + } + *mimeType = ""; *confidence = 0.0f; meta->clear(); @@ -156,6 +180,23 @@ bool Sniffer::sniff( } } + /* Only do the deeper sniffers if the results are null or in doubt */ + if (mimeType->length() == 0 || *confidence < 0.21f || forceExtraSniffers) { + for (List::iterator it = mExtraSniffers.begin(); + it != mExtraSniffers.end(); ++it) { + String8 newMimeType; + float newConfidence; + sp newMeta; + if ((*it)(source, &newMimeType, &newConfidence, &newMeta)) { + if (newConfidence > *confidence) { + *mimeType = newMimeType; + *confidence = newConfidence; + *meta = newMeta; + } + } + } + } + return *confidence > 0.0; } @@ -171,6 +212,26 @@ void Sniffer::registerSniffer_l(SnifferFunc func) { mSniffers.push_back(func); } +void Sniffer::registerSnifferPlugin() { + static void (*getExtractorPlugin)(MediaExtractor::Plugin *) = + (void (*)(MediaExtractor::Plugin *))loadExtractorPlugin(); + + MediaExtractor::Plugin *plugin = MediaExtractor::getPlugin(); + if (!plugin->sniff && getExtractorPlugin) { + getExtractorPlugin(plugin); + } + if (plugin->sniff) { + for (List::iterator it = mExtraSniffers.begin(); + it != mExtraSniffers.end(); ++it) { + if (*it == plugin->sniff) { + return; + } + } + + mExtraSniffers.push_back(plugin->sniff); + } +} + void Sniffer::registerDefaultSniffers() { Mutex::Autolock autoLock(mSnifferMutex); @@ -185,8 +246,9 @@ void Sniffer::registerDefaultSniffers() { registerSniffer_l(SniffAAC); registerSniffer_l(SniffMPEG2PS); registerSniffer_l(SniffWVM); - RegisterSniffer_l(SniffMidi); - RegisterSniffer_l(AVUtils::get()->getExtendedSniffer()); + registerSniffer_l(SniffMidi); + registerSniffer_l(AVUtils::get()->getExtendedSniffer()); + registerSnifferPlugin(); char value[PROPERTY_VALUE_MAX]; if (property_get("drm.service.enabled", value, NULL) diff --git a/media/libstagefright/FFMPEGSoftCodec.cpp b/media/libstagefright/FFMPEGSoftCodec.cpp new file mode 100644 index 00000000000..3e6692b8825 --- /dev/null +++ b/media/libstagefright/FFMPEGSoftCodec.cpp @@ -0,0 +1,1149 @@ +/* + * Copyright (C) 2014 The CyanogenMod Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_NDEBUG 0 +#define LOG_TAG "FFMPEGSoftCodec" +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +namespace android { + +enum MetaKeyType{ + INT32, INT64, STRING, DATA, CSD +}; + +struct MetaKeyEntry{ + int MetaKey; + const char* MsgKey; + MetaKeyType KeyType; +}; + +static const MetaKeyEntry MetaKeyTable[] { + {kKeyAACAOT , "aac-profile" , INT32}, + {kKeyArbitraryMode , "use-arbitrary-mode" , INT32}, + {kKeyBitRate , "bitrate" , INT32}, + {kKeyBitsPerSample , "bit-width" , INT32}, + {kKeyBlockAlign , "block-align" , INT32}, + {kKeyChannelCount , "channel-count" , INT32}, + {kKeyCodecId , "codec-id" , INT32}, + {kKeyCodedSampleBits , "coded-sample-bits" , INT32}, + {kKeyRawCodecSpecificData , "raw-codec-specific-data", CSD}, + {kKeyRVVersion , "rv-version" , INT32}, + {kKeySampleFormat , "sample-format" , INT32}, + {kKeySampleRate , "sample-rate" , INT32}, + {kKeyWMAVersion , "wma-version" , INT32}, // int32_t + {kKeyWMVVersion , "wmv-version" , INT32}, + {kKeyPCMFormat , "pcm-format" , INT32}, +}; + +const char* FFMPEGSoftCodec::getMsgKey(int key) { + static const size_t numMetaKeys = + sizeof(MetaKeyTable) / sizeof(MetaKeyTable[0]); + size_t i; + for (i = 0; i < numMetaKeys; ++i) { + if (key == MetaKeyTable[i].MetaKey) { + return MetaKeyTable[i].MsgKey; + } + } + return "unknown"; +} + +void FFMPEGSoftCodec::convertMetaDataToMessageFF( + const sp &meta, sp *format) { + const char * str_val; + int32_t int32_val; + int64_t int64_val; + uint32_t data_type; + const void * data; + size_t size; + static const size_t numMetaKeys = + sizeof(MetaKeyTable) / sizeof(MetaKeyTable[0]); + size_t i; + for (i = 0; i < numMetaKeys; ++i) { + if (MetaKeyTable[i].KeyType == INT32 && + meta->findInt32(MetaKeyTable[i].MetaKey, &int32_val)) { + ALOGV("found metakey %s of type int32", MetaKeyTable[i].MsgKey); + format->get()->setInt32(MetaKeyTable[i].MsgKey, int32_val); + } else if (MetaKeyTable[i].KeyType == INT64 && + meta->findInt64(MetaKeyTable[i].MetaKey, &int64_val)) { + ALOGV("found metakey %s of type int64", MetaKeyTable[i].MsgKey); + format->get()->setInt64(MetaKeyTable[i].MsgKey, int64_val); + } else if (MetaKeyTable[i].KeyType == STRING && + meta->findCString(MetaKeyTable[i].MetaKey, &str_val)) { + ALOGV("found metakey %s of type string", MetaKeyTable[i].MsgKey); + format->get()->setString(MetaKeyTable[i].MsgKey, str_val); + } else if ( (MetaKeyTable[i].KeyType == DATA || + MetaKeyTable[i].KeyType == CSD) && + meta->findData(MetaKeyTable[i].MetaKey, &data_type, &data, &size)) { + ALOGV("found metakey %s of type data", MetaKeyTable[i].MsgKey); + if (MetaKeyTable[i].KeyType == CSD) { + const char *mime; + CHECK(meta->findCString(kKeyMIMEType, &mime)); + if (strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { + sp buffer = new ABuffer(size); + memcpy(buffer->data(), data, size); + buffer->meta()->setInt32("csd", true); + buffer->meta()->setInt64("timeUs", 0); + format->get()->setBuffer("csd-0", buffer); + } else { + const uint8_t *ptr = (const uint8_t *)data; + CHECK(size >= 8); + int seqLength = 0, picLength = 0; + for (size_t i = 4; i < (size - 4); i++) + { + if ((*(ptr + i) == 0) && (*(ptr + i + 1) == 0) && + (*(ptr + i + 2) == 0) && (*(ptr + i + 3) == 1)) + seqLength = i; + } + sp buffer = new ABuffer(seqLength); + memcpy(buffer->data(), data, seqLength); + buffer->meta()->setInt32("csd", true); + buffer->meta()->setInt64("timeUs", 0); + format->get()->setBuffer("csd-0", buffer); + picLength=size-seqLength; + sp buffer1 = new ABuffer(picLength); + memcpy(buffer1->data(), (const uint8_t *)data + seqLength, picLength); + buffer1->meta()->setInt32("csd", true); + buffer1->meta()->setInt64("timeUs", 0); + format->get()->setBuffer("csd-1", buffer1); + } + } else { + sp buffer = new ABuffer(size); + memcpy(buffer->data(), data, size); + format->get()->setBuffer(MetaKeyTable[i].MsgKey, buffer); + } + } + + } +} + +void FFMPEGSoftCodec::convertMessageToMetaDataFF( + const sp &msg, sp &meta) { + AString str_val; + int32_t int32_val; + int64_t int64_val; + static const size_t numMetaKeys = + sizeof(MetaKeyTable) / sizeof(MetaKeyTable[0]); + size_t i; + for (i = 0; i < numMetaKeys; ++i) { + if (MetaKeyTable[i].KeyType == INT32 && + msg->findInt32(MetaKeyTable[i].MsgKey, &int32_val)) { + ALOGV("found metakey %s of type int32", MetaKeyTable[i].MsgKey); + meta->setInt32(MetaKeyTable[i].MetaKey, int32_val); + } else if (MetaKeyTable[i].KeyType == INT64 && + msg->findInt64(MetaKeyTable[i].MsgKey, &int64_val)) { + ALOGV("found metakey %s of type int64", MetaKeyTable[i].MsgKey); + meta->setInt64(MetaKeyTable[i].MetaKey, int64_val); + } else if (MetaKeyTable[i].KeyType == STRING && + msg->findString(MetaKeyTable[i].MsgKey, &str_val)) { + ALOGV("found metakey %s of type string", MetaKeyTable[i].MsgKey); + meta->setCString(MetaKeyTable[i].MetaKey, str_val.c_str()); + } + } +} + + +template +static void InitOMXParams(T *params) { + params->nSize = sizeof(T); + params->nVersion.s.nVersionMajor = 1; + params->nVersion.s.nVersionMinor = 0; + params->nVersion.s.nRevision = 0; + params->nVersion.s.nStep = 0; +} + +void FFMPEGSoftCodec::overrideComponentName( + uint32_t /*quirks*/, const sp &msg, AString* componentName, AString* mime, int32_t isEncoder) { + + int32_t wmvVersion = 0; + if (!strncasecmp(mime->c_str(), MEDIA_MIMETYPE_VIDEO_WMV, strlen(MEDIA_MIMETYPE_VIDEO_WMV)) && + msg->findInt32(getMsgKey(kKeyWMVVersion), &wmvVersion)) { + ALOGD("Found WMV version key %d", wmvVersion); + if (wmvVersion == 1) { + ALOGD("Use FFMPEG for unsupported WMV track"); + componentName->setTo("OMX.ffmpeg.wmv.decoder"); + } + } + + int32_t encodeOptions = 0; + if (!isEncoder && !strncasecmp(mime->c_str(), MEDIA_MIMETYPE_AUDIO_WMA, strlen(MEDIA_MIMETYPE_AUDIO_WMA)) && + !msg->findInt32(getMsgKey(kKeyWMAEncodeOpt), &encodeOptions)) { + ALOGD("Use FFMPEG for unsupported WMA track"); + componentName->setTo("OMX.ffmpeg.wma.decoder"); + } + + // Google's decoder doesn't support MAIN profile + int32_t aacProfile = 0; + if (!isEncoder && !strncasecmp(mime->c_str(), MEDIA_MIMETYPE_AUDIO_AAC, strlen(MEDIA_MIMETYPE_AUDIO_AAC)) && + msg->findInt32(getMsgKey(kKeyAACAOT), &aacProfile)) { + if (aacProfile == OMX_AUDIO_AACObjectMain) { + ALOGD("Use FFMPEG for AAC MAIN profile"); + componentName->setTo("OMX.ffmpeg.aac.decoder"); + } + } +} + +status_t FFMPEGSoftCodec::setVideoFormat( + const sp &msg, const char* mime, sp OMXhandle, + IOMX::node_id nodeID, bool isEncoder, + OMX_VIDEO_CODINGTYPE *compressionFormat) { + status_t err = OK; + + if (isEncoder) { + ALOGE("Encoding not supported"); + err = BAD_VALUE; + + } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_WMV, mime)) { + err = setWMVFormat(msg, OMXhandle, nodeID); + if (err != OK) { + ALOGE("setWMVFormat() failed (err = %d)", err); + } else { + *compressionFormat = OMX_VIDEO_CodingWMV; + } + } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_RV, mime)) { + err = setRVFormat(msg, OMXhandle, nodeID); + if (err != OK) { + ALOGE("setRVFormat() failed (err = %d)", err); + } else { + *compressionFormat = OMX_VIDEO_CodingRV; + } + } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_VC1, mime)) { + *compressionFormat = (OMX_VIDEO_CODINGTYPE)OMX_VIDEO_CodingVC1; + } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_FLV1, mime)) { + *compressionFormat = (OMX_VIDEO_CODINGTYPE)OMX_VIDEO_CodingFLV1; + } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX, mime)) { + *compressionFormat = (OMX_VIDEO_CODINGTYPE)OMX_VIDEO_CodingDIVX; + } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) { + *compressionFormat = (OMX_VIDEO_CODINGTYPE)OMX_VIDEO_CodingHEVC; + } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_FFMPEG, mime)) { + ALOGV("Setting the OMX_VIDEO_PARAM_FFMPEGTYPE params"); + err = setFFmpegVideoFormat(msg, OMXhandle, nodeID); + if (err != OK) { + ALOGE("setFFmpegVideoFormat() failed (err = %d)", err); + } else { + *compressionFormat = OMX_VIDEO_CodingAutoDetect; + } + } else { + err = BAD_TYPE; + } + + return err; +} + +status_t FFMPEGSoftCodec::getVideoPortFormat(OMX_U32 portIndex, int coding, + sp ¬ify, sp OMXHandle, IOMX::node_id nodeId) { + + status_t err = BAD_TYPE; + switch (coding) { + case OMX_VIDEO_CodingWMV: + { + OMX_VIDEO_PARAM_WMVTYPE params; + InitOMXParams(¶ms); + params.nPortIndex = portIndex; + + err = OMXHandle->getParameter( + nodeId, OMX_IndexParamVideoWmv, ¶ms, sizeof(params)); + if (err != OK) { + return err; + } + + int32_t version; + if (params.eFormat == OMX_VIDEO_WMVFormat7) { + version = kTypeWMVVer_7; + } else if (params.eFormat == OMX_VIDEO_WMVFormat8) { + version = kTypeWMVVer_8; + } else { + version = kTypeWMVVer_9; + } + notify->setString("mime", MEDIA_MIMETYPE_VIDEO_WMV); + notify->setInt32("wmv-version", version); + break; + } + case OMX_VIDEO_CodingAutoDetect: + { + OMX_VIDEO_PARAM_FFMPEGTYPE params; + InitOMXParams(¶ms); + params.nPortIndex = portIndex; + + err = OMXHandle->getParameter( + nodeId, (OMX_INDEXTYPE)OMX_IndexParamVideoFFmpeg, ¶ms, sizeof(params)); + if (err != OK) { + return err; + } + + notify->setString("mime", MEDIA_MIMETYPE_VIDEO_FFMPEG); + notify->setInt32("codec-id", params.eCodecId); + break; + } + case OMX_VIDEO_CodingRV: + { + OMX_VIDEO_PARAM_RVTYPE params; + InitOMXParams(¶ms); + params.nPortIndex = portIndex; + + err = OMXHandle->getParameter( + nodeId, (OMX_INDEXTYPE)OMX_IndexParamVideoRv, ¶ms, sizeof(params)); + if (err != OK) { + return err; + } + + int32_t version; + if (params.eFormat == OMX_VIDEO_RVFormatG2) { + version = kTypeRVVer_G2; + } else if (params.eFormat == OMX_VIDEO_RVFormat8) { + version = kTypeRVVer_8; + } else { + version = kTypeRVVer_9; + } + notify->setString("mime", MEDIA_MIMETYPE_VIDEO_RV); + break; + } + } + return err; +} + +status_t FFMPEGSoftCodec::getAudioPortFormat(OMX_U32 portIndex, int coding, + sp ¬ify, sp OMXHandle, IOMX::node_id nodeId) { + + status_t err = BAD_TYPE; + switch (coding) { + case OMX_AUDIO_CodingRA: + { + OMX_AUDIO_PARAM_RATYPE params; + InitOMXParams(¶ms); + params.nPortIndex = portIndex; + + err = OMXHandle->getParameter( + nodeId, OMX_IndexParamAudioRa, ¶ms, sizeof(params)); + if (err != OK) { + return err; + } + + notify->setString("mime", MEDIA_MIMETYPE_AUDIO_RA); + notify->setInt32("channel-count", params.nChannels); + notify->setInt32("sample-rate", params.nSamplingRate); + break; + } + case OMX_AUDIO_CodingMP2: + { + OMX_AUDIO_PARAM_MP2TYPE params; + InitOMXParams(¶ms); + params.nPortIndex = portIndex; + + err = OMXHandle->getParameter( + nodeId, (OMX_INDEXTYPE)OMX_IndexParamAudioMp2, ¶ms, sizeof(params)); + if (err != OK) { + return err; + } + + notify->setString("mime", MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II); + notify->setInt32("channel-count", params.nChannels); + notify->setInt32("sample-rate", params.nSampleRate); + break; + } + case OMX_AUDIO_CodingWMA: + { + OMX_AUDIO_PARAM_WMATYPE params; + InitOMXParams(¶ms); + params.nPortIndex = portIndex; + + err = OMXHandle->getParameter( + nodeId, OMX_IndexParamAudioWma, ¶ms, sizeof(params)); + if (err != OK) { + return err; + } + + notify->setString("mime", MEDIA_MIMETYPE_AUDIO_WMA); + notify->setInt32("channel-count", params.nChannels); + notify->setInt32("sample-rate", params.nSamplingRate); + break; + } + case OMX_AUDIO_CodingAPE: + { + OMX_AUDIO_PARAM_APETYPE params; + InitOMXParams(¶ms); + params.nPortIndex = portIndex; + + err = OMXHandle->getParameter( + nodeId, (OMX_INDEXTYPE)OMX_IndexParamAudioApe, ¶ms, sizeof(params)); + if (err != OK) { + return err; + } + + notify->setString("mime", MEDIA_MIMETYPE_AUDIO_APE); + notify->setInt32("channel-count", params.nChannels); + notify->setInt32("sample-rate", params.nSamplingRate); + notify->setInt32("bit-width", params.nBitsPerSample); + break; + } + case OMX_AUDIO_CodingFLAC: + { + OMX_AUDIO_PARAM_FLACTYPE params; + InitOMXParams(¶ms); + params.nPortIndex = portIndex; + + err = OMXHandle->getParameter( + nodeId, (OMX_INDEXTYPE)OMX_IndexParamAudioFlac, ¶ms, sizeof(params)); + if (err != OK) { + return err; + } + + notify->setString("mime", MEDIA_MIMETYPE_AUDIO_FLAC); + notify->setInt32("channel-count", params.nChannels); + notify->setInt32("sample-rate", params.nSampleRate); + notify->setInt32("bit-width", params.nCompressionLevel); // piggyback + break; + } + + case OMX_AUDIO_CodingDTS: + { + OMX_AUDIO_PARAM_DTSTYPE params; + InitOMXParams(¶ms); + params.nPortIndex = portIndex; + + err = OMXHandle->getParameter( + nodeId, (OMX_INDEXTYPE)OMX_IndexParamAudioDts, ¶ms, sizeof(params)); + if (err != OK) { + return err; + } + + notify->setString("mime", MEDIA_MIMETYPE_AUDIO_DTS); + notify->setInt32("channel-count", params.nChannels); + notify->setInt32("sample-rate", params.nSamplingRate); + break; + } + case OMX_AUDIO_CodingAC3: + { + OMX_AUDIO_PARAM_ANDROID_AC3TYPE params; + InitOMXParams(¶ms); + params.nPortIndex = portIndex; + + err = OMXHandle->getParameter( + nodeId, (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3, ¶ms, sizeof(params)); + if (err != OK) { + return err; + } + + notify->setString("mime", MEDIA_MIMETYPE_AUDIO_AC3); + notify->setInt32("channel-count", params.nChannels); + notify->setInt32("sample-rate", params.nSampleRate); + break; + } + + case OMX_AUDIO_CodingAutoDetect: + { + OMX_AUDIO_PARAM_FFMPEGTYPE params; + InitOMXParams(¶ms); + params.nPortIndex = portIndex; + + err = OMXHandle->getParameter( + nodeId, (OMX_INDEXTYPE)OMX_IndexParamAudioFFmpeg, ¶ms, sizeof(params)); + if (err != OK) { + return err; + } + + notify->setString("mime", MEDIA_MIMETYPE_AUDIO_FFMPEG); + notify->setInt32("channel-count", params.nChannels); + notify->setInt32("sample-rate", params.nSampleRate); + break; + } + } + return err; +} + +status_t FFMPEGSoftCodec::setAudioFormat( + const sp &msg, const char* mime, sp OMXhandle, + IOMX::node_id nodeID) { + ALOGV("setAudioFormat called"); + status_t err = OK; + + ALOGV("setAudioFormat: %s", msg->debugString(0).c_str()); + + if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_WMA, mime)) { + err = setWMAFormat(msg, OMXhandle, nodeID); + if (err != OK) { + ALOGE("setWMAFormat() failed (err = %d)", err); + } + } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_VORBIS, mime)) { + err = setVORBISFormat(msg, OMXhandle, nodeID); + if (err != OK) { + ALOGE("setVORBISFormat() failed (err = %d)", err); + } + } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_RA, mime)) { + err = setRAFormat(msg, OMXhandle, nodeID); + if (err != OK) { + ALOGE("setRAFormat() failed (err = %d)", err); + } + } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_FLAC, mime)) { + err = setFLACFormat(msg, OMXhandle, nodeID); + if (err != OK) { + ALOGE("setFLACFormat() failed (err = %d)", err); + } + } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II, mime)) { + err = setMP2Format(msg, OMXhandle, nodeID); + if (err != OK) { + ALOGE("setMP2Format() failed (err = %d)", err); + } + } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AC3, mime)) { + err = setAC3Format(msg, OMXhandle, nodeID); + if (err != OK) { + ALOGE("setAC3Format() failed (err = %d)", err); + } + } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_APE, mime)) { + err = setAPEFormat(msg, OMXhandle, nodeID); + if (err != OK) { + ALOGE("setAPEFormat() failed (err = %d)", err); + } + } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_DTS, mime)) { + err = setDTSFormat(msg, OMXhandle, nodeID); + if (err != OK) { + ALOGE("setDTSFormat() failed (err = %d)", err); + } + } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_FFMPEG, mime)) { + err = setFFmpegAudioFormat(msg, OMXhandle, nodeID); + if (err != OK) { + ALOGE("setFFmpegAudioFormat() failed (err = %d)", err); + } + } + + return err; +} + +status_t FFMPEGSoftCodec::setSupportedRole( + const sp &omx, IOMX::node_id node, + bool isEncoder, const char *mime) { + + ALOGV("setSupportedRole Called %s", mime); + + struct MimeToRole { + const char *mime; + const char *decoderRole; + const char *encoderRole; + }; + + static const MimeToRole kFFMPEGMimeToRole[] = { + { MEDIA_MIMETYPE_AUDIO_AAC, + "audio_decoder.aac", NULL }, + { MEDIA_MIMETYPE_AUDIO_MPEG, + "audio_decoder.mp3", NULL }, + { MEDIA_MIMETYPE_AUDIO_VORBIS, + "audio_decoder.vorbis", NULL }, + { MEDIA_MIMETYPE_AUDIO_WMA, + "audio_decoder.wma", NULL }, + { MEDIA_MIMETYPE_AUDIO_RA, + "audio_decoder.ra" , NULL }, + { MEDIA_MIMETYPE_AUDIO_FLAC, + "audio_decoder.flac", NULL }, + { MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II, + "audio_decoder.mp2", NULL }, + { MEDIA_MIMETYPE_AUDIO_AC3, + "audio_decoder.ac3", NULL }, + { MEDIA_MIMETYPE_AUDIO_APE, + "audio_decoder.ape", NULL }, + { MEDIA_MIMETYPE_AUDIO_DTS, + "audio_decoder.dts", NULL }, + { MEDIA_MIMETYPE_VIDEO_MPEG2, + "video_decoder.mpeg2", NULL }, + { MEDIA_MIMETYPE_VIDEO_DIVX, + "video_decoder.divx", NULL }, + { MEDIA_MIMETYPE_VIDEO_DIVX4, + "video_decoder.divx", NULL }, + { MEDIA_MIMETYPE_VIDEO_DIVX311, + "video_decoder.divx", NULL }, + { MEDIA_MIMETYPE_VIDEO_WMV, + "video_decoder.wmv", NULL }, + { MEDIA_MIMETYPE_VIDEO_VC1, + "video_decoder.vc1", NULL }, + { MEDIA_MIMETYPE_VIDEO_RV, + "video_decoder.rv", NULL }, + { MEDIA_MIMETYPE_VIDEO_FLV1, + "video_decoder.flv1", NULL }, + { MEDIA_MIMETYPE_VIDEO_HEVC, + "video_decoder.hevc", NULL }, + { MEDIA_MIMETYPE_AUDIO_FFMPEG, + "audio_decoder.trial", NULL }, + { MEDIA_MIMETYPE_VIDEO_FFMPEG, + "video_decoder.trial", NULL }, + }; + static const size_t kNumMimeToRole = + sizeof(kFFMPEGMimeToRole) / sizeof(kFFMPEGMimeToRole[0]); + + size_t i; + for (i = 0; i < kNumMimeToRole; ++i) { + if (!strcasecmp(mime, kFFMPEGMimeToRole[i].mime)) { + break; + } + } + + if (i == kNumMimeToRole) { + return ERROR_UNSUPPORTED; + } + + const char *role = + isEncoder ? kFFMPEGMimeToRole[i].encoderRole + : kFFMPEGMimeToRole[i].decoderRole; + + if (role != NULL) { + OMX_PARAM_COMPONENTROLETYPE roleParams; + InitOMXParams(&roleParams); + + strncpy((char *)roleParams.cRole, + role, OMX_MAX_STRINGNAME_SIZE - 1); + + roleParams.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0'; + + status_t err = omx->setParameter( + node, OMX_IndexParamStandardComponentRole, + &roleParams, sizeof(roleParams)); + + if (err != OK) { + ALOGW("Failed to set standard component role '%s'.", role); + return err; + } + } + return OK; +} + +//video +status_t FFMPEGSoftCodec::setWMVFormat( + const sp &msg, sp OMXhandle, IOMX::node_id nodeID) +{ + int32_t version = -1; + OMX_VIDEO_PARAM_WMVTYPE paramWMV; + + if (!msg->findInt32(getMsgKey(kKeyWMVVersion), &version)) { + ALOGE("WMV version not detected"); + } + + InitOMXParams(¶mWMV); + paramWMV.nPortIndex = kPortIndexInput; + + status_t err = OMXhandle->getParameter( + nodeID, OMX_IndexParamVideoWmv, ¶mWMV, sizeof(paramWMV)); + if (err != OK) { + return err; + } + + if (version == kTypeWMVVer_7) { + paramWMV.eFormat = OMX_VIDEO_WMVFormat7; + } else if (version == kTypeWMVVer_8) { + paramWMV.eFormat = OMX_VIDEO_WMVFormat8; + } else if (version == kTypeWMVVer_9) { + paramWMV.eFormat = OMX_VIDEO_WMVFormat9; + } + + err = OMXhandle->setParameter( + nodeID, OMX_IndexParamVideoWmv, ¶mWMV, sizeof(paramWMV)); + return err; +} + +status_t FFMPEGSoftCodec::setRVFormat( + const sp &msg, sp OMXhandle, IOMX::node_id nodeID) +{ + int32_t version = kTypeRVVer_G2; + OMX_VIDEO_PARAM_RVTYPE paramRV; + + if (!msg->findInt32(getMsgKey(kKeyRVVersion), &version)) { + ALOGE("RV version not detected"); + } + + InitOMXParams(¶mRV); + paramRV.nPortIndex = kPortIndexInput; + + status_t err = OMXhandle->getParameter( + nodeID, OMX_IndexParamVideoRv, ¶mRV, sizeof(paramRV)); + if (err != OK) + return err; + + if (version == kTypeRVVer_G2) { + paramRV.eFormat = OMX_VIDEO_RVFormatG2; + } else if (version == kTypeRVVer_8) { + paramRV.eFormat = OMX_VIDEO_RVFormat8; + } else if (version == kTypeRVVer_9) { + paramRV.eFormat = OMX_VIDEO_RVFormat9; + } + + err = OMXhandle->setParameter( + nodeID, OMX_IndexParamVideoRv, ¶mRV, sizeof(paramRV)); + return err; +} + +status_t FFMPEGSoftCodec::setFFmpegVideoFormat( + const sp &msg, sp OMXhandle, IOMX::node_id nodeID) +{ + int32_t codec_id = 0; + int32_t width = 0; + int32_t height = 0; + OMX_VIDEO_PARAM_FFMPEGTYPE param; + + ALOGD("setFFmpegVideoFormat"); + + if (msg->findInt32(getMsgKey(kKeyWidth), &width)) { + ALOGE("No video width specified"); + } + if (msg->findInt32(getMsgKey(kKeyHeight), &height)) { + ALOGE("No video height specified"); + } + if (!msg->findInt32(getMsgKey(kKeyCodecId), &codec_id)) { + ALOGE("No codec id sent for FFMPEG catch-all codec!"); + } + + InitOMXParams(¶m); + param.nPortIndex = kPortIndexInput; + + status_t err = OMXhandle->getParameter( + nodeID, (OMX_INDEXTYPE)OMX_IndexParamVideoFFmpeg, ¶m, sizeof(param)); + if (err != OK) + return err; + + param.eCodecId = codec_id; + param.nWidth = width; + param.nHeight = height; + + err = OMXhandle->setParameter( + nodeID, (OMX_INDEXTYPE)OMX_IndexParamVideoFFmpeg, ¶m, sizeof(param)); + return err; +} + +//audio +status_t FFMPEGSoftCodec::setRawAudioFormat( + const sp &msg, sp OMXhandle, IOMX::node_id nodeID) +{ + int32_t numChannels = 0; + int32_t sampleRate = 0; + int32_t bitsPerSample = 16; + + CHECK(msg->findInt32(getMsgKey(kKeyChannelCount), &numChannels)); + CHECK(msg->findInt32(getMsgKey(kKeySampleRate), &sampleRate)); + if (!msg->findInt32(getMsgKey(kKeyBitsPerSample), &bitsPerSample)) { + ALOGD("No PCM format specified, using 16 bit"); + } + + OMX_PARAM_PORTDEFINITIONTYPE def; + InitOMXParams(&def); + def.nPortIndex = kPortIndexOutput; + + status_t err = OMXhandle->getParameter( + nodeID, OMX_IndexParamPortDefinition, &def, sizeof(def)); + + if (err != OK) { + return err; + } + + def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; + + err = OMXhandle->setParameter( + nodeID, OMX_IndexParamPortDefinition, &def, sizeof(def)); + + if (err != OK) { + return err; + } + + OMX_AUDIO_PARAM_PCMMODETYPE pcmParams; + InitOMXParams(&pcmParams); + pcmParams.nPortIndex = kPortIndexOutput; + + err = OMXhandle->getParameter( + nodeID, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams)); + + if (err != OK) { + return err; + } + + pcmParams.nChannels = numChannels; + pcmParams.eNumData = OMX_NumericalDataSigned; + pcmParams.bInterleaved = OMX_TRUE; + pcmParams.nBitPerSample = bitsPerSample; + pcmParams.nSamplingRate = sampleRate; + pcmParams.ePCMMode = OMX_AUDIO_PCMModeLinear; + + if (getOMXChannelMapping(numChannels, pcmParams.eChannelMapping) != OK) { + return OMX_ErrorNone; + } + + return OMXhandle->setParameter( + nodeID, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams)); +} + +status_t FFMPEGSoftCodec::setWMAFormat( + const sp &msg, sp OMXhandle, IOMX::node_id nodeID) +{ + int32_t version = 0; + int32_t numChannels = 0; + int32_t bitRate = 0; + int32_t sampleRate = 0; + int32_t blockAlign = 0; + int32_t bitsPerSample = 0; + + OMX_AUDIO_PARAM_WMATYPE paramWMA; + + CHECK(msg->findInt32(getMsgKey(kKeyChannelCount), &numChannels)); + CHECK(msg->findInt32(getMsgKey(kKeySampleRate), &sampleRate)); + CHECK(msg->findInt32(getMsgKey(kKeyBitRate), &bitRate)); + if (!msg->findInt32(getMsgKey(kKeyBlockAlign), &blockAlign)) { + // we should be last on the codec list, but another sniffer may + // have handled it and there is no hardware codec. + if (!msg->findInt32(getMsgKey(kKeyWMABlockAlign), &blockAlign)) { + return ERROR_UNSUPPORTED; + } + } + + // mm-parser may want a different bit depth + if (msg->findInt32(getMsgKey(kKeyWMABitspersample), &bitsPerSample)) { + msg->setInt32("bit-width", bitsPerSample); + } + + ALOGV("Channels: %d, SampleRate: %d, BitRate: %d, blockAlign: %d", + numChannels, sampleRate, bitRate, blockAlign); + + CHECK(msg->findInt32(getMsgKey(kKeyWMAVersion), &version)); + + status_t err = setRawAudioFormat(msg, OMXhandle, nodeID); + if (err != OK) + return err; + + InitOMXParams(¶mWMA); + paramWMA.nPortIndex = kPortIndexInput; + + err = OMXhandle->getParameter( + nodeID, OMX_IndexParamAudioWma, ¶mWMA, sizeof(paramWMA)); + if (err != OK) + return err; + + paramWMA.nChannels = numChannels; + paramWMA.nSamplingRate = sampleRate; + paramWMA.nBitRate = bitRate; + paramWMA.nBlockAlign = blockAlign; + + // http://msdn.microsoft.com/en-us/library/ff819498(v=vs.85).aspx + if (version == kTypeWMA) { + paramWMA.eFormat = OMX_AUDIO_WMAFormat7; + } else if (version == kTypeWMAPro) { + paramWMA.eFormat = OMX_AUDIO_WMAFormat8; + } else if (version == kTypeWMALossLess) { + paramWMA.eFormat = OMX_AUDIO_WMAFormat9; + } + + return OMXhandle->setParameter( + nodeID, OMX_IndexParamAudioWma, ¶mWMA, sizeof(paramWMA)); +} + +status_t FFMPEGSoftCodec::setVORBISFormat( + const sp &msg, sp OMXhandle, IOMX::node_id nodeID) +{ + int32_t numChannels = 0; + int32_t sampleRate = 0; + OMX_AUDIO_PARAM_VORBISTYPE param; + + CHECK(msg->findInt32(getMsgKey(kKeyChannelCount), &numChannels)); + CHECK(msg->findInt32(getMsgKey(kKeySampleRate), &sampleRate)); + + ALOGV("Channels: %d, SampleRate: %d", + numChannels, sampleRate); + + status_t err = setRawAudioFormat(msg, OMXhandle, nodeID); + if (err != OK) + return err; + + InitOMXParams(¶m); + param.nPortIndex = kPortIndexInput; + + err = OMXhandle->getParameter( + nodeID, OMX_IndexParamAudioVorbis, ¶m, sizeof(param)); + if (err != OK) + return err; + + param.nChannels = numChannels; + param.nSampleRate = sampleRate; + + return OMXhandle->setParameter( + nodeID, OMX_IndexParamAudioVorbis, ¶m, sizeof(param)); +} + +status_t FFMPEGSoftCodec::setRAFormat( + const sp &msg, sp OMXhandle, IOMX::node_id nodeID) +{ + int32_t numChannels = 0; + int32_t bitRate = 0; + int32_t sampleRate = 0; + int32_t blockAlign = 0; + OMX_AUDIO_PARAM_RATYPE paramRA; + + CHECK(msg->findInt32(getMsgKey(kKeyChannelCount), &numChannels)); + CHECK(msg->findInt32(getMsgKey(kKeySampleRate), &sampleRate)); + msg->findInt32(getMsgKey(kKeyBitRate), &bitRate); + CHECK(msg->findInt32(getMsgKey(kKeyBlockAlign), &blockAlign)); + + ALOGV("Channels: %d, SampleRate: %d, BitRate: %d, blockAlign: %d", + numChannels, sampleRate, bitRate, blockAlign); + + status_t err = setRawAudioFormat(msg, OMXhandle, nodeID); + if (err != OK) + return err; + + InitOMXParams(¶mRA); + paramRA.nPortIndex = kPortIndexInput; + + err = OMXhandle->getParameter( + nodeID, OMX_IndexParamAudioRa, ¶mRA, sizeof(paramRA)); + if (err != OK) + return err; + + paramRA.eFormat = OMX_AUDIO_RAFormatUnused; // FIXME, cook only??? + paramRA.nChannels = numChannels; + paramRA.nSamplingRate = sampleRate; + // FIXME, HACK!!!, I use the nNumRegions parameter pass blockAlign!!! + // the cook audio codec need blockAlign! + paramRA.nNumRegions = blockAlign; + + return OMXhandle->setParameter( + nodeID, OMX_IndexParamAudioRa, ¶mRA, sizeof(paramRA)); +} + +status_t FFMPEGSoftCodec::setFLACFormat( + const sp &msg, sp OMXhandle, IOMX::node_id nodeID) +{ + int32_t numChannels = 0; + int32_t sampleRate = 0; + int32_t bitsPerSample = 16; + OMX_AUDIO_PARAM_FLACTYPE param; + + CHECK(msg->findInt32(getMsgKey(kKeyChannelCount), &numChannels)); + CHECK(msg->findInt32(getMsgKey(kKeySampleRate), &sampleRate)); + CHECK(msg->findInt32(getMsgKey(kKeyBitsPerSample), &bitsPerSample)); + + ALOGV("Channels: %d, SampleRate: %d BitsPerSample: %d", + numChannels, sampleRate, bitsPerSample); + + status_t err = setRawAudioFormat(msg, OMXhandle, nodeID); + if (err != OK) + return err; + + InitOMXParams(¶m); + param.nPortIndex = kPortIndexInput; + + err = OMXhandle->getParameter( + nodeID, OMX_IndexParamAudioFlac, ¶m, sizeof(param)); + if (err != OK) + return err; + + param.nChannels = numChannels; + param.nSampleRate = sampleRate; + param.nCompressionLevel = bitsPerSample; // piggyback hax! + + return OMXhandle->setParameter( + nodeID, OMX_IndexParamAudioFlac, ¶m, sizeof(param)); +} + +status_t FFMPEGSoftCodec::setMP2Format( + const sp &msg, sp OMXhandle, IOMX::node_id nodeID) +{ + int32_t numChannels = 0; + int32_t sampleRate = 0; + OMX_AUDIO_PARAM_MP2TYPE param; + + CHECK(msg->findInt32(getMsgKey(kKeyChannelCount), &numChannels)); + CHECK(msg->findInt32(getMsgKey(kKeySampleRate), &sampleRate)); + + ALOGV("Channels: %d, SampleRate: %d", + numChannels, sampleRate); + + status_t err = setRawAudioFormat(msg, OMXhandle, nodeID); + if (err != OK) + return err; + + InitOMXParams(¶m); + param.nPortIndex = kPortIndexInput; + + err = OMXhandle->getParameter( + nodeID, (OMX_INDEXTYPE)OMX_IndexParamAudioMp2, ¶m, sizeof(param)); + if (err != OK) + return err; + + param.nChannels = numChannels; + param.nSampleRate = sampleRate; + + return OMXhandle->setParameter( + nodeID, (OMX_INDEXTYPE)OMX_IndexParamAudioMp2, ¶m, sizeof(param)); +} + +status_t FFMPEGSoftCodec::setAC3Format( + const sp &msg, sp OMXhandle, IOMX::node_id nodeID) +{ + int32_t numChannels = 0; + int32_t sampleRate = 0; + OMX_AUDIO_PARAM_ANDROID_AC3TYPE param; + + CHECK(msg->findInt32(getMsgKey(kKeyChannelCount), &numChannels)); + CHECK(msg->findInt32(getMsgKey(kKeySampleRate), &sampleRate)); + + ALOGV("Channels: %d, SampleRate: %d", + numChannels, sampleRate); + + status_t err = setRawAudioFormat(msg, OMXhandle, nodeID); + if (err != OK) + return err; + + InitOMXParams(¶m); + param.nPortIndex = kPortIndexInput; + + err = OMXhandle->getParameter( + nodeID, (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3, ¶m, sizeof(param)); + if (err != OK) + return err; + + param.nChannels = numChannels; + param.nSampleRate = sampleRate; + + return OMXhandle->setParameter( + nodeID, (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3, ¶m, sizeof(param)); +} + +status_t FFMPEGSoftCodec::setAPEFormat( + const sp &msg, sp OMXhandle, IOMX::node_id nodeID) +{ + int32_t numChannels = 0; + int32_t sampleRate = 0; + int32_t bitsPerSample = 0; + OMX_AUDIO_PARAM_APETYPE param; + + CHECK(msg->findInt32(getMsgKey(kKeyChannelCount), &numChannels)); + CHECK(msg->findInt32(getMsgKey(kKeySampleRate), &sampleRate)); + CHECK(msg->findInt32(getMsgKey(kKeyBitsPerSample), &bitsPerSample)); + + ALOGV("Channels:%d, SampleRate:%d, bitsPerSample:%d", + numChannels, sampleRate, bitsPerSample); + + status_t err = setRawAudioFormat(msg, OMXhandle, nodeID); + if (err != OK) + return err; + + InitOMXParams(¶m); + param.nPortIndex = kPortIndexInput; + + err = OMXhandle->getParameter( + nodeID, (OMX_INDEXTYPE)OMX_IndexParamAudioApe, ¶m, sizeof(param)); + if (err != OK) + return err; + + param.nChannels = numChannels; + param.nSamplingRate = sampleRate; + param.nBitsPerSample = bitsPerSample; + + return OMXhandle->setParameter( + nodeID, (OMX_INDEXTYPE)OMX_IndexParamAudioApe, ¶m, sizeof(param)); +} + +status_t FFMPEGSoftCodec::setDTSFormat( + const sp &msg, sp OMXhandle, IOMX::node_id nodeID) +{ + int32_t numChannels = 0; + int32_t sampleRate = 0; + OMX_AUDIO_PARAM_DTSTYPE param; + + CHECK(msg->findInt32(getMsgKey(kKeyChannelCount), &numChannels)); + CHECK(msg->findInt32(getMsgKey(kKeySampleRate), &sampleRate)); + + ALOGV("Channels: %d, SampleRate: %d", + numChannels, sampleRate); + + status_t err = setRawAudioFormat(msg, OMXhandle, nodeID); + if (err != OK) + return err; + + InitOMXParams(¶m); + param.nPortIndex = kPortIndexInput; + + err = OMXhandle->getParameter( + nodeID, (OMX_INDEXTYPE)OMX_IndexParamAudioDts, ¶m, sizeof(param)); + if (err != OK) + return err; + + param.nChannels = numChannels; + param.nSamplingRate = sampleRate; + + return OMXhandle->setParameter( + nodeID, (OMX_INDEXTYPE)OMX_IndexParamAudioDts, ¶m, sizeof(param)); +} + +status_t FFMPEGSoftCodec::setFFmpegAudioFormat( + const sp &msg, sp OMXhandle, IOMX::node_id nodeID) +{ + int32_t codec_id = 0; + int32_t numChannels = 0; + int32_t bitRate = 0; + int32_t bitsPerSample = 16; + int32_t sampleRate = 0; + int32_t blockAlign = 0; + int32_t sampleFormat = 0; + int32_t codedSampleBits = 0; + OMX_AUDIO_PARAM_FFMPEGTYPE param; + + ALOGD("setFFmpegAudioFormat"); + + CHECK(msg->findInt32(getMsgKey(kKeyCodecId), &codec_id)); + CHECK(msg->findInt32(getMsgKey(kKeyChannelCount), &numChannels)); + CHECK(msg->findInt32(getMsgKey(kKeySampleFormat), &sampleFormat)); + msg->findInt32(getMsgKey(kKeyBitRate), &bitRate); + msg->findInt32(getMsgKey(kKeyBitsPerSample), &bitsPerSample); + msg->findInt32(getMsgKey(kKeySampleRate), &sampleRate); + msg->findInt32(getMsgKey(kKeyBlockAlign), &blockAlign); + msg->findInt32(getMsgKey(kKeyBitsPerSample), &bitsPerSample); + msg->findInt32(getMsgKey(kKeyCodedSampleBits), &codedSampleBits); + + status_t err = setRawAudioFormat(msg, OMXhandle, nodeID); + if (err != OK) + return err; + + InitOMXParams(¶m); + param.nPortIndex = kPortIndexInput; + + err = OMXhandle->getParameter( + nodeID, (OMX_INDEXTYPE)OMX_IndexParamAudioFFmpeg, ¶m, sizeof(param)); + if (err != OK) + return err; + + param.eCodecId = codec_id; + param.nChannels = numChannels; + param.nBitRate = bitRate; + param.nBitsPerSample = codedSampleBits; + param.nSampleRate = sampleRate; + param.nBlockAlign = blockAlign; + param.eSampleFormat = sampleFormat; + + return OMXhandle->setParameter( + nodeID, (OMX_INDEXTYPE)OMX_IndexParamAudioFFmpeg, ¶m, sizeof(param)); +} + +} diff --git a/media/libstagefright/FileSource.cpp b/media/libstagefright/FileSource.cpp index 565f1562c43..f7b1a0299b1 100644 --- a/media/libstagefright/FileSource.cpp +++ b/media/libstagefright/FileSource.cpp @@ -30,6 +30,7 @@ namespace android { FileSource::FileSource(const char *filename) : mFd(-1), + mUri(filename), mOffset(0), mLength(-1), mDecryptHandle(NULL), @@ -58,6 +59,7 @@ FileSource::FileSource(int fd, int64_t offset, int64_t length) mDrmBuf(NULL){ CHECK(offset >= 0); CHECK(length >= 0); + fetchUriFromFd(fd); } FileSource::~FileSource() { @@ -188,4 +190,18 @@ ssize_t FileSource::readAtDRM(off64_t offset, void *data, size_t size) { return mDrmManagerClient->pread(mDecryptHandle, data, size, offset + mOffset); } } + +void FileSource::fetchUriFromFd(int fd) { + ssize_t len = 0; + char path[PATH_MAX] = {0}; + char link[PATH_MAX] = {0}; + + mUri.clear(); + + snprintf(path, PATH_MAX, "/proc/%d/fd/%d", getpid(), fd); + if ((len = readlink(path, link, sizeof(link)-1)) != -1) { + link[len] = '\0'; + mUri.setTo(link); + } +} } // namespace android diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index 7f7c7fa19b2..b74836f3e86 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -1143,7 +1143,8 @@ void MediaCodec::onMessageReceived(const sp &msg) { CHECK(msg->findString("componentName", &mComponentName)); - if (mComponentName.startsWith("OMX.google.")) { + if (mComponentName.startsWith("OMX.google.") || + mComponentName.startsWith("OMX.ffmpeg.")) { mFlags |= kFlagUsesSoftwareRenderer; } else { mFlags &= ~kFlagUsesSoftwareRenderer; diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp index 2a5069223c4..089c150c300 100644 --- a/media/libstagefright/MediaDefs.cpp +++ b/media/libstagefright/MediaDefs.cpp @@ -64,4 +64,32 @@ const char *MEDIA_MIMETYPE_TEXT_VTT = "text/vtt"; const char *MEDIA_MIMETYPE_TEXT_CEA_608 = "text/cea-608"; const char *MEDIA_MIMETYPE_DATA_TIMED_ID3 = "application/x-id3v4"; +const char *MEDIA_MIMETYPE_VIDEO_FLV1 = "video/x-flv"; +const char *MEDIA_MIMETYPE_VIDEO_MJPEG = "video/x-jpeg"; +const char *MEDIA_MIMETYPE_VIDEO_RV = "video/vnd.rn-realvideo"; +const char *MEDIA_MIMETYPE_VIDEO_VC1 = "video/vc1"; +const char *MEDIA_MIMETYPE_VIDEO_FFMPEG = "video/ffmpeg"; + +const char *MEDIA_MIMETYPE_AUDIO_PCM = "audio/x-pcm"; +const char *MEDIA_MIMETYPE_AUDIO_RA = "audio/vnd.rn-realaudio"; +const char *MEDIA_MIMETYPE_AUDIO_FFMPEG = "audio/ffmpeg"; + +const char *MEDIA_MIMETYPE_CONTAINER_APE = "audio/x-ape"; +const char *MEDIA_MIMETYPE_CONTAINER_DIVX = "video/divx"; +const char *MEDIA_MIMETYPE_CONTAINER_DTS = "audio/vnd.dts"; +const char *MEDIA_MIMETYPE_CONTAINER_FLAC = "audio/flac"; +const char *MEDIA_MIMETYPE_CONTAINER_FLV = "video/x-flv"; +const char *MEDIA_MIMETYPE_CONTAINER_MOV = "video/quicktime"; +const char *MEDIA_MIMETYPE_CONTAINER_MP2 = "audio/mpeg2"; +const char *MEDIA_MIMETYPE_CONTAINER_MPG = "video/mpeg"; +const char *MEDIA_MIMETYPE_CONTAINER_RA = "audio/vnd.rn-realaudio"; +const char *MEDIA_MIMETYPE_CONTAINER_RM = "video/vnd.rn-realvideo"; +const char *MEDIA_MIMETYPE_CONTAINER_TS = "video/mp2t"; +const char *MEDIA_MIMETYPE_CONTAINER_WEBM = "video/webm"; +const char *MEDIA_MIMETYPE_CONTAINER_WMA = "audio/x-ms-wma"; +const char *MEDIA_MIMETYPE_CONTAINER_WMV = "video/x-ms-wmv"; +const char *MEDIA_MIMETYPE_CONTAINER_VC1 = "video/vc1"; +const char *MEDIA_MIMETYPE_CONTAINER_HEVC = "video/hevc"; +const char *MEDIA_MIMETYPE_CONTAINER_FFMPEG = "video/ffmpeg"; + } // namespace android diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp index bfb2a16ed85..fc96e2f33ee 100644 --- a/media/libstagefright/MediaExtractor.cpp +++ b/media/libstagefright/MediaExtractor.cpp @@ -44,6 +44,8 @@ namespace android { +MediaExtractor::Plugin MediaExtractor::sPlugin; + sp MediaExtractor::getMetaData() { return new MetaData; } @@ -58,9 +60,15 @@ sp MediaExtractor::Create( const uint32_t flags) { sp meta; + bool secondPass = false; + String8 tmp; - if (mime == NULL) { +retry: + if (secondPass || mime == NULL) { float confidence; + if (secondPass) { + confidence = 3.14f; + } if (!source->sniff(&tmp, &confidence, &meta)) { ALOGV("FAILED to autodetect media content."); @@ -95,7 +103,12 @@ sp MediaExtractor::Create( } sp ret = NULL; + AString extractorName; if ((ret = AVFactory::get()->createExtendedExtractor(source, mime, meta, flags)) != NULL) { + } else if (meta.get() && meta->findString("extended-extractor-use", &extractorName) + && sPlugin.create) { + ALOGI("Use extended extractor for the special mime(%s) or codec", mime); + ret = sPlugin.create(source, mime, meta); } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4) || !strcasecmp(mime, "audio/mp4")) { ret = new MPEG4Extractor(source); @@ -123,6 +136,8 @@ sp MediaExtractor::Create( ret = new MPEG2PSExtractor(source); } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MIDI)) { ret = new MidiExtractor(source); + } else if (!isDrm && sPlugin.create) { + ret = sPlugin.create(source, mime, meta); } ret = AVFactory::get()->updateExtractor(ret, source, mime, meta, flags); @@ -134,6 +149,15 @@ sp MediaExtractor::Create( } } + if (ret != NULL) { + + if (!secondPass && ( ret->countTracks() == 0 || + (!strncasecmp("video/", mime, 6) && ret->countTracks() < 2) ) ) { + secondPass = true; + goto retry; + } + } + return ret; } diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp index e69890daa54..ac925f72943 100644 --- a/media/libstagefright/OMXClient.cpp +++ b/media/libstagefright/OMXClient.cpp @@ -181,6 +181,7 @@ bool MuxOMX::isLocalNode_l(node_id node) const { } // static + bool MuxOMX::CanLiveLocally(const char *name) { #ifdef __LP64__ (void)name; // disable unused parameter warning diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp index a757181d049..c5018aee604 100644 --- a/media/libstagefright/StagefrightMediaScanner.cpp +++ b/media/libstagefright/StagefrightMediaScanner.cpp @@ -42,7 +42,11 @@ static bool FileHasAcceptableExtension(const char *extension) { ".mpeg", ".ogg", ".mid", ".smf", ".imy", ".wma", ".aac", ".wav", ".amr", ".midi", ".xmf", ".rtttl", ".rtx", ".ota", ".mkv", ".mka", ".webm", ".ts", ".fl", ".flac", ".mxmf", - ".avi", ".mpeg", ".mpg", ".awb", ".mpga" + ".adts", ".dm", ".m2ts", ".mp3d", ".wmv", ".asf", ".flv", + ".mov", ".ra", ".rm", ".rmvb", ".ac3", ".ape", ".dts", + ".mp1", ".mp2", ".f4v", "hlv", "nrg", "m2v", ".swf", + ".avi", ".mpg", ".mpeg", ".awb", ".vc1", ".vob", ".divx", + ".mpga", ".mov", ".qcp", ".ec3" }; static const size_t kNumValidExtensions = sizeof(kValidExtensions) / sizeof(kValidExtensions[0]); diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp index 436aaf8189f..a1e7a93c6b3 100644 --- a/media/libstagefright/Utils.cpp +++ b/media/libstagefright/Utils.cpp @@ -36,6 +36,7 @@ #include #include +#include namespace android { @@ -106,7 +107,7 @@ status_t convertMetaDataToMessage( int avgBitRate; if (meta->findInt32(kKeyBitRate, &avgBitRate)) { - msg->setInt32("bit-rate", avgBitRate); + msg->setInt32("bitrate", avgBitRate); } int32_t isSync; @@ -205,6 +206,11 @@ status_t convertMetaDataToMessage( msg->setInt32("frame-rate", fps); } + int32_t bitsPerSample; + if (meta->findInt32(kKeyBitsPerSample, &bitsPerSample)) { + msg->setInt32("bit-width", bitsPerSample); + } + uint32_t type; const void *data; size_t size; @@ -314,6 +320,7 @@ status_t convertMetaDataToMessage( ALOGE("b/23680780"); return BAD_VALUE; } + uint8_t profile __unused = ptr[1] & 31; uint8_t level __unused = ptr[12]; ptr += 22; @@ -456,8 +463,14 @@ status_t convertMetaDataToMessage( } AVUtils::get()->convertMetaDataToMessage(meta, &msg); + + FFMPEGSoftCodec::convertMetaDataToMessageFF(meta, &msg); *format = msg; + ALOGI("convertMetaDataToMessage from:"); + meta->dumpToLog(); + ALOGI(" to: %s", msg->debugString(0).c_str()); + return OK; } @@ -649,6 +662,11 @@ void convertMessageToMetaData(const sp &msg, sp &meta) { if (msg->findInt32("is-adts", &isADTS)) { meta->setInt32(kKeyIsADTS, isADTS); } + + int32_t bitsPerSample; + if (msg->findInt32("bit-width", &bitsPerSample)) { + meta->setInt32(kKeyBitsPerSample, bitsPerSample); + } } int32_t maxInputSize; @@ -700,10 +718,10 @@ void convertMessageToMetaData(const sp &msg, sp &meta) { // XXX TODO add whatever other keys there are -#if 0 - ALOGI("converted %s to:", msg->debugString(0).c_str()); + FFMPEGSoftCodec::convertMessageToMetaDataFF(msg, meta); + + ALOGI("convertMessageToMetaData from %s to:", msg->debugString(0).c_str()); meta->dumpToLog(); -#endif } AString MakeUserAgent() { @@ -849,6 +867,7 @@ bool canOffloadStream(const sp& meta, bool hasVideo, if (AVUtils::get()->canOffloadAPE(meta) != true) { return false; } + ALOGV("Mime type \"%s\" mapped to audio_format %d", mime, info.format); // Redefine aac format according to its profile // Offloading depends on audio DSP capabilities. diff --git a/media/libstagefright/codecs/raw/SoftRaw.cpp b/media/libstagefright/codecs/raw/SoftRaw.cpp index b78b36fbd52..0d800984198 100644 --- a/media/libstagefright/codecs/raw/SoftRaw.cpp +++ b/media/libstagefright/codecs/raw/SoftRaw.cpp @@ -42,7 +42,8 @@ SoftRaw::SoftRaw( : SimpleSoftOMXComponent(name, callbacks, appData, component), mSignalledError(false), mChannelCount(2), - mSampleRate(44100) { + mSampleRate(44100), + mBitsPerSample(16) { initPorts(); CHECK_EQ(initDecoder(), (status_t)OK); } @@ -110,7 +111,7 @@ OMX_ERRORTYPE SoftRaw::internalGetParameter( pcmParams->eNumData = OMX_NumericalDataSigned; pcmParams->eEndian = OMX_EndianBig; pcmParams->bInterleaved = OMX_TRUE; - pcmParams->nBitPerSample = 16; + pcmParams->nBitPerSample = mBitsPerSample; pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear; pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF; pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF; @@ -154,6 +155,7 @@ OMX_ERRORTYPE SoftRaw::internalSetParameter( mChannelCount = pcmParams->nChannels; mSampleRate = pcmParams->nSamplingRate; + mBitsPerSample = pcmParams->nBitPerSample; return OMX_ErrorNone; } diff --git a/media/libstagefright/codecs/raw/SoftRaw.h b/media/libstagefright/codecs/raw/SoftRaw.h index 94b0ef17579..894889f0bb6 100644 --- a/media/libstagefright/codecs/raw/SoftRaw.h +++ b/media/libstagefright/codecs/raw/SoftRaw.h @@ -50,6 +50,7 @@ struct SoftRaw : public SimpleSoftOMXComponent { int32_t mChannelCount; int32_t mSampleRate; + int32_t mBitsPerSample; void initPorts(); status_t initDecoder(); diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h index 758b2c9d37a..c72f9f6cc9d 100644 --- a/media/libstagefright/include/AwesomePlayer.h +++ b/media/libstagefright/include/AwesomePlayer.h @@ -193,6 +193,7 @@ struct AwesomePlayer { uint32_t mFlags; uint32_t mExtractorFlags; uint32_t mSinceLastDropped; + bool mDropFramesDisable; // hevc test int64_t mTimeSourceDeltaUs; int64_t mVideoTimeUs; diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp index a66ca6dfd6c..ff8137928af 100644 --- a/media/libstagefright/matroska/MatroskaExtractor.cpp +++ b/media/libstagefright/matroska/MatroskaExtractor.cpp @@ -240,13 +240,12 @@ MatroskaSource::MatroskaSource( mType = HEVC; uint32_t type; - const void *data; + const uint8_t *data; size_t size; - CHECK(meta->findData(kKeyHVCC, &type, &data, &size)); + CHECK(meta->findData(kKeyHVCC, &type, (const void **)&data, &size)); - const uint8_t *ptr = (const uint8_t *)data; CHECK(size >= 7); - mNALSizeLen = 1 + (ptr[14 + 7] & 3); + mNALSizeLen = 1 + (data[14 + 7] & 3); ALOGV("mNALSizeLen = %zu", mNALSizeLen); } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { mType = AAC; @@ -1028,7 +1027,7 @@ void MatroskaExtractor::addTracks() { } } else if (!strcmp("V_MPEGH/ISO/HEVC", codecID)) { meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_HEVC); - meta->setData(kKeyHVCC, 0, codecPrivate, codecPrivateSize); + meta->setData(kKeyHVCC, kTypeHVCC, codecPrivate, codecPrivateSize); } else if (!strcmp("V_VP8", codecID)) { meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_VP8); @@ -1051,7 +1050,9 @@ void MatroskaExtractor::addTracks() { if (!strcmp("A_AAC", codecID)) { meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC); - CHECK(codecPrivateSize >= 2); + if (codecPrivateSize < 2) { + return; + } addESDSFromCodecPrivate( meta, true, codecPrivate, codecPrivateSize); diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h index 7165c6c4bc5..f0ae4ec018a 100644 --- a/services/audioflinger/AudioMixer.h +++ b/services/audioflinger/AudioMixer.h @@ -137,6 +137,7 @@ class AudioMixer case AUDIO_FORMAT_PCM_8_BIT: case AUDIO_FORMAT_PCM_16_BIT: case AUDIO_FORMAT_PCM_24_BIT_PACKED: + case AUDIO_FORMAT_PCM_8_24_BIT: case AUDIO_FORMAT_PCM_32_BIT: case AUDIO_FORMAT_PCM_FLOAT: return true; From d6eb700ea9e5b2b5f7053b1534c697c9196b479a Mon Sep 17 00:00:00 2001 From: Scott Mertz Date: Thu, 29 Oct 2015 01:36:11 -0700 Subject: [PATCH 58/73] libstagefright: fix size_t printf format size_t should use the portable %zu Change-Id: I974d4be7d4921a8c3fc684d24721a231c5b91170 --- media/libstagefright/WAVExtractor.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp index bb2a33c6be8..d86dffb069d 100644 --- a/media/libstagefright/WAVExtractor.cpp +++ b/media/libstagefright/WAVExtractor.cpp @@ -437,7 +437,7 @@ status_t WAVSource::read( maxBytesToRead = 3*(kMaxFrameSize/4); } else maxBytesToRead = kMaxFrameSize; - ALOGV("%s mBitsPerSample %d, kMaxFrameSize %d, ", + ALOGV("%s mBitsPerSample %d, kMaxFrameSize %zu, ", __func__, mBitsPerSample, kMaxFrameSize); size_t maxBytesAvailable = @@ -504,7 +504,7 @@ status_t WAVSource::read( tmp->set_range(0, 4 * numBytes); int8_t *dst = (int8_t *)tmp->data(); const uint8_t *src = (const uint8_t *)buffer->data(); - ALOGV("numBytes = %d", numBytes); + ALOGV("numBytes = %zd", numBytes); while(numBytes-- > 0) { *dst++ = 0x0; *dst++ = src[0]; @@ -514,7 +514,7 @@ status_t WAVSource::read( } buffer->release(); buffer = tmp; - ALOGV("length = %d", buffer->range_length()); + ALOGV("length = %zu", buffer->range_length()); } } From 2e7814398a85b5304eb11901eafc372e37c08447 Mon Sep 17 00:00:00 2001 From: Steve Kondik Date: Thu, 5 Nov 2015 02:43:05 -0800 Subject: [PATCH 59/73] stagefright: Unbreak video encoding * Fix logic for the FFMPEG video case- we should have only been checking for errors when actually calling into our extension. Change-Id: Ic9fa6ad3913f259c09f0dd37b1720d996ecc386c --- media/libstagefright/ACodec.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 48ffbfa5c83..d3be54754e5 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -4191,9 +4191,9 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp ¬ify) { if (!strncmp(mComponentName.c_str(), "OMX.ffmpeg.", 11)) { err = FFMPEGSoftCodec::getVideoPortFormat(portIndex, (int)videoDef->eCompressionFormat, notify, mOMX, mNode); - } - if (err == OK) { - break; + if (err == OK) { + break; + } } if (mIsEncoder ^ (portIndex == kPortIndexOutput)) { From 8724c007273aa70c5e7fdf62367ae838342f1eb8 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Wed, 16 Sep 2015 15:49:30 -0700 Subject: [PATCH 60/73] audio policy: bind setMode() and setPhoneState() operations No routing operation should be allowed between setMode() and setPhoneState() when starting a call as the audio HAL relies on a precise sequence of mode change and routing change to select the initial audio device for the call. Bug: 24083591. Change-Id: I2d5ef62c11cf7aedc2ec7ca5e5fadd7ac875afbc --- services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp index 58ecb111446..a228798f00a 100644 --- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp +++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp @@ -76,10 +76,14 @@ status_t AudioPolicyService::setPhoneState(audio_mode_t state) ALOGV("setPhoneState()"); + // acquire lock before calling setMode() so that setMode() + setPhoneState() are an atomic + // operation from policy manager standpoint (no other operation (e.g track start or stop) + // can be interleaved). + Mutex::Autolock _l(mLock); + // TODO: check if it is more appropriate to do it in platform specific policy manager AudioSystem::setMode(state); - Mutex::Autolock _l(mLock); mAudioPolicyManager->setPhoneState(state); mPhoneState = state; return NO_ERROR; From 8480535368652ca77c6b389f65801ff6fc383abd Mon Sep 17 00:00:00 2001 From: dcashman Date: Fri, 11 Sep 2015 09:33:01 -0700 Subject: [PATCH 61/73] Add DUMP permission check to ResourceManagerService. Bug: 23999740 Change-Id: I3165404add455528b22951ba47b682a075b50087 (cherry picked from commit 014e91e471edba3f9b2c71ff6025274716b0f587) --- services/mediaresourcemanager/ResourceManagerService.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp index e54cc5a9c06..47907540040 100644 --- a/services/mediaresourcemanager/ResourceManagerService.cpp +++ b/services/mediaresourcemanager/ResourceManagerService.cpp @@ -96,6 +96,15 @@ status_t ResourceManagerService::dump(int fd, const Vector& /* args */ const size_t SIZE = 256; char buffer[SIZE]; + if (checkCallingPermission(String16("android.permission.DUMP")) == false) { + result.format("Permission Denial: " + "can't dump ResourceManagerService from pid=%d, uid=%d\n", + IPCThreadState::self()->getCallingPid(), + IPCThreadState::self()->getCallingUid()); + write(fd, result.string(), result.size()); + return PERMISSION_DENIED; + } + snprintf(buffer, SIZE, "ResourceManagerService: %p\n", this); result.append(buffer); result.append(" Policies:\n"); From 661a4e2d666e4a2ace7b0e82256417e8809d0742 Mon Sep 17 00:00:00 2001 From: Jeff Tinker Date: Wed, 16 Sep 2015 13:21:51 -0700 Subject: [PATCH 62/73] DO NOT MERGE Fix vulnerability in mediaserver ICrypto.cpp: ASLR bypass using DECRYPT IPC bug: 24074485 Change-Id: I61cd77f0894140547f666a80526ebfe1ec3d2db6 --- media/libmedia/ICrypto.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/media/libmedia/ICrypto.cpp b/media/libmedia/ICrypto.cpp index 53b105d7a7e..24e027e1167 100644 --- a/media/libmedia/ICrypto.cpp +++ b/media/libmedia/ICrypto.cpp @@ -301,7 +301,7 @@ status_t BnCrypto::onTransact( secureBufferId = reinterpret_cast(static_cast(data.readInt64())); AVMediaUtils::get()->readCustomData(&data, &secureBufferId); } else { - dstPtr = malloc(totalSize); + dstPtr = calloc(1, totalSize); CHECK(dstPtr != NULL); } From 34d6542935215eabc10d26be7e078f0efd32a062 Mon Sep 17 00:00:00 2001 From: Flanker Date: Fri, 11 Sep 2015 19:05:47 +0800 Subject: [PATCH 63/73] stagefright: fix AMessage::FromParcel Add check for incoming mNumItems. Also add check readCString return value. Fix style & add log. Bug: 24123723 Change-Id: If41a5312c27d868f481893eef56019b6807c39b7 --- media/libstagefright/foundation/AMessage.cpp | 28 +++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/media/libstagefright/foundation/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp index e549ff65a32..725a5742995 100644 --- a/media/libstagefright/foundation/AMessage.cpp +++ b/media/libstagefright/foundation/AMessage.cpp @@ -601,13 +601,24 @@ sp AMessage::FromParcel(const Parcel &parcel) { msg->setWhat(what); msg->mNumItems = static_cast(parcel.readInt32()); + if (msg->mNumItems > kMaxNumItems) { + ALOGE("Too large number of items clipped."); + msg->mNumItems = kMaxNumItems; + } + for (size_t i = 0; i < msg->mNumItems; ++i) { Item *item = &msg->mItems[i]; const char *name = parcel.readCString(); - item->setName(name, strlen(name)); - item->mType = static_cast(parcel.readInt32()); + if (name == NULL) { + ALOGE("Failed reading name for an item. Parsing aborted."); + msg->mNumItems = i; + break; + } + item->mType = static_cast(parcel.readInt32()); + // setName() happens below so that we don't leak memory when parsing + // is aborted in the middle. switch (item->mType) { case kTypeInt32: { @@ -641,7 +652,16 @@ sp AMessage::FromParcel(const Parcel &parcel) { case kTypeString: { - item->u.stringValue = new AString(parcel.readCString()); + const char *stringValue = parcel.readCString(); + if (stringValue == NULL) { + ALOGE("Failed reading string value from a parcel. " + "Parsing aborted."); + msg->mNumItems = i; + continue; + // The loop will terminate subsequently. + } else { + item->u.stringValue = new AString(stringValue); + } break; } @@ -660,6 +680,8 @@ sp AMessage::FromParcel(const Parcel &parcel) { TRESPASS(); } } + + item->setName(name, strlen(name)); } return msg; From 473b0d59c7bd43769f7cc2ec47be6da3f37772ce Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Mon, 28 Sep 2015 14:50:47 -0700 Subject: [PATCH 64/73] MPEG4Extractor: ensure buffer size is not less than 8 for LastCommentData. Bug: 24346430 Change-Id: I897a724e968841d9160f819d06c0ce22f6d743c4 --- media/libstagefright/MPEG4Extractor.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index 107b4f6fdaa..1c3b2da6b4d 100755 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -2583,6 +2583,12 @@ status_t MPEG4Extractor::parseITunesMetaData(off64_t offset, size_t size) { mLastCommentName.setTo((const char *)buffer + 4); break; case FOURCC('d', 'a', 't', 'a'): + if (size < 8) { + delete[] buffer; + buffer = NULL; + ALOGE("b/24346430"); + return ERROR_MALFORMED; + } mLastCommentData.setTo((const char *)buffer + 8); break; } From 70680ce524edb41ef0cd23530ac650485f24da2e Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Mon, 28 Sep 2015 11:32:23 -0700 Subject: [PATCH 65/73] OMX: allow only secure codec to remotely call allocateBuffer. Bug: 24310423 Change-Id: Iebcfc58b447f925ec2134898060af2ef227266a3 --- include/media/IOMX.h | 6 ++++++ media/libmedia/IOMX.cpp | 6 ++++++ media/libstagefright/include/OMX.h | 2 ++ media/libstagefright/include/OMXNodeInstance.h | 5 +++++ media/libstagefright/omx/OMX.cpp | 5 +++++ media/libstagefright/omx/OMXNodeInstance.cpp | 1 + 6 files changed, 25 insertions(+) diff --git a/include/media/IOMX.h b/include/media/IOMX.h index 3d29e4a5199..27ad694c116 100644 --- a/include/media/IOMX.h +++ b/include/media/IOMX.h @@ -249,6 +249,12 @@ class BnOMX : public BnInterface { virtual status_t onTransact( uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags = 0); + +protected: + // check if the codec is secure. + virtual bool isSecure(IOMX::node_id node) { + return false; + } }; class BnOMXObserver : public BnInterface { diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp index ac2e87258c4..5356494ce9d 100644 --- a/media/libmedia/IOMX.cpp +++ b/media/libmedia/IOMX.cpp @@ -965,6 +965,12 @@ status_t BnOMX::onTransact( node_id node = (node_id)data.readInt32(); OMX_U32 port_index = data.readInt32(); + if (!isSecure(node) || port_index != 0 /* kPortIndexInput */) { + ALOGE("b/24310423"); + reply->writeInt32(INVALID_OPERATION); + return NO_ERROR; + } + size_t size = data.readInt64(); buffer_id buffer; diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h index d468dfc3532..e7c4f6d5874 100644 --- a/media/libstagefright/include/OMX.h +++ b/media/libstagefright/include/OMX.h @@ -140,6 +140,8 @@ class OMX : public BnOMX, virtual void binderDied(const wp &the_late_who); + virtual bool isSecure(IOMX::node_id node); + OMX_ERRORTYPE OnEvent( node_id node, OMX_IN OMX_EVENTTYPE eEvent, diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h index f68e0a91b1c..e5fb45b0b33 100644 --- a/media/libstagefright/include/OMXNodeInstance.h +++ b/media/libstagefright/include/OMXNodeInstance.h @@ -125,6 +125,10 @@ struct OMXNodeInstance { const void *data, size_t size); + bool isSecure() const { + return mIsSecure; + } + // handles messages and removes them from the list void onMessages(std::list &messages); void onMessage(const omx_message &msg); @@ -142,6 +146,7 @@ struct OMXNodeInstance { OMX_HANDLETYPE mHandle; sp mObserver; bool mDying; + bool mIsSecure; // Lock only covers mGraphicBufferSource. We can't always use mLock // because of rare instances where we'd end up locking it recursively. diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp index 2ef30e3a088..efb1a1cdab1 100644 --- a/media/libstagefright/omx/OMX.cpp +++ b/media/libstagefright/omx/OMX.cpp @@ -194,6 +194,11 @@ void OMX::binderDied(const wp &the_late_who) { instance->onObserverDied(mMaster); } +bool OMX::isSecure(node_id node) { + OMXNodeInstance *instance = findInstance(node); + return (instance == NULL ? false : instance->isSecure()); +} + bool OMX::livesLocally(node_id /* node */, pid_t pid) { return pid == getpid(); } diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp index bdd1039d10d..4bcc732371e 100644 --- a/media/libstagefright/omx/OMXNodeInstance.cpp +++ b/media/libstagefright/omx/OMXNodeInstance.cpp @@ -206,6 +206,7 @@ OMXNodeInstance::OMXNodeInstance( mDebugLevelBumpPendingBuffers[1] = 0; mMetadataType[0] = kMetadataBufferTypeInvalid; mMetadataType[1] = kMetadataBufferTypeInvalid; + mIsSecure = AString(name).endsWith(".secure"); } OMXNodeInstance::~OMXNodeInstance() { From ad55db4be6b8bac6b3528e0bddb9f4ca3f29010a Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Mon, 5 Oct 2015 10:46:11 -0700 Subject: [PATCH 66/73] Don't crash when there's no conceal frame Bug: 24630158 Change-Id: If042aebebb58c218eb7bbf01dcddbcbd05dca1d6 --- media/libstagefright/codecs/m4v_h263/dec/src/conceal.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/media/libstagefright/codecs/m4v_h263/dec/src/conceal.cpp b/media/libstagefright/codecs/m4v_h263/dec/src/conceal.cpp index e9ead016a41..03e4119b957 100644 --- a/media/libstagefright/codecs/m4v_h263/dec/src/conceal.cpp +++ b/media/libstagefright/codecs/m4v_h263/dec/src/conceal.cpp @@ -19,6 +19,7 @@ #include "vlc_decode.h" #include "bitstream.h" #include "scaling.h" +#include "log/log.h" /* ====================================================================== / Function : ConcealTexture_I() @@ -137,6 +138,10 @@ Modified: 6/04/2001 rewrote the function ****************************************************************************/ void CopyVopMB(Vop *curr, uint8 *prevFrame, int mbnum, int width_Y, int height) { + if (curr == NULL || prevFrame == NULL) { + ALOGE("b/24630158"); + return; + } int width_C = width_Y >> 1; int row = MB_SIZE; uint8 *y1, *y2, *u1, *u2, *v1, *v2; From ee79ab836ddd7b8f1936bbda4988b7cdce425edc Mon Sep 17 00:00:00 2001 From: Wei Jia Date: Mon, 5 Oct 2015 10:44:23 -0700 Subject: [PATCH 67/73] ID3: check possible integer overflow for extendedHeaderSize and paddingSize. Bug: 24623447 Change-Id: Ifbc74454d6e28ad7136efe35ab638a07e46398b1 --- media/libstagefright/id3/ID3.cpp | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp index d9a198dae7f..76d65f0621f 100644 --- a/media/libstagefright/id3/ID3.cpp +++ b/media/libstagefright/id3/ID3.cpp @@ -194,6 +194,13 @@ struct id3_header { if (header.version_major == 4) { void *copy = malloc(size); + if (copy == NULL) { + free(mData); + mData = NULL; + ALOGE("b/24623447, no more memory"); + return false; + } + memcpy(copy, mData, size); bool success = removeUnsynchronizationV2_4(false /* iTunesHack */); @@ -234,7 +241,14 @@ struct id3_header { return false; } - size_t extendedHeaderSize = U32_AT(&mData[0]) + 4; + size_t extendedHeaderSize = U32_AT(&mData[0]); + if (extendedHeaderSize > SIZE_MAX - 4) { + free(mData); + mData = NULL; + ALOGE("b/24623447, extendedHeaderSize is too large"); + return false; + } + extendedHeaderSize += 4; if (extendedHeaderSize > mSize) { free(mData); @@ -252,7 +266,10 @@ struct id3_header { if (extendedHeaderSize >= 10) { size_t paddingSize = U32_AT(&mData[6]); - if (mFirstFrameOffset + paddingSize > mSize) { + if (paddingSize > SIZE_MAX - mFirstFrameOffset) { + ALOGE("b/24623447, paddingSize is too large"); + } + if (paddingSize > mSize - mFirstFrameOffset) { free(mData); mData = NULL; From 75295367b545c0a13bd424bc7df589cd5c3da55d Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Fri, 2 Oct 2015 15:12:00 -0700 Subject: [PATCH 68/73] Check NAL size before use Bug: 24441553 Bug: 24445122 Change-Id: Ib7f025769adbafd5a2cb64fae5562a0a565945c2 --- media/libstagefright/MPEG4Extractor.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index 1c3b2da6b4d..eee13c73630 100755 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -4169,7 +4169,10 @@ status_t MPEG4Source::read( (const uint8_t *)mBuffer->data() + mBuffer->range_offset(); size_t nal_size = parseNALSize(src); - if (mBuffer->range_length() < mNALLengthSize + nal_size) { + if (mNALLengthSize > SIZE_MAX - nal_size) { + ALOGE("b/24441553, b/24445122"); + } + if (mBuffer->range_length() - mNALLengthSize < nal_size) { ALOGE("incomplete NAL unit."); mBuffer->release(); @@ -4456,7 +4459,11 @@ status_t MPEG4Source::fragmentedRead( (const uint8_t *)mBuffer->data() + mBuffer->range_offset(); size_t nal_size = parseNALSize(src); - if (mBuffer->range_length() < mNALLengthSize + nal_size) { + if (mNALLengthSize > SIZE_MAX - nal_size) { + ALOGE("b/24441553, b/24445122"); + } + + if (mBuffer->range_length() - mNALLengthSize < nal_size) { ALOGE("incomplete NAL unit."); mBuffer->release(); From cb3b5b50e1367916dec1a9ddc9cb74a0668680e4 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Mon, 12 Oct 2015 17:10:31 -0700 Subject: [PATCH 69/73] stagefright: check bounds for MediaCodecList.getCodecInfo Bug: 24445127 Change-Id: I1c6cb9e2518b852d48d5d0d625b54409bd4e13ec --- include/media/stagefright/MediaCodecList.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/media/stagefright/MediaCodecList.h b/include/media/stagefright/MediaCodecList.h index 3aaa0322b4e..bf4db87e96e 100644 --- a/include/media/stagefright/MediaCodecList.h +++ b/include/media/stagefright/MediaCodecList.h @@ -47,6 +47,10 @@ struct MediaCodecList : public BnMediaCodecList { virtual size_t countCodecs() const; virtual sp getCodecInfo(size_t index) const { + if (index >= mCodecInfos.size()) { + ALOGE("b/24445127"); + return NULL; + } return mCodecInfos.itemAt(index); } From 4024479c6680acde1023ef67007c43f10afada96 Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Mon, 21 Sep 2015 12:44:54 -0700 Subject: [PATCH 70/73] AudioFlinger: Clear record buffers when starting RecordThread Bug: 24211743 Bug: 24267152 Change-Id: I58c55e56b85067b71e4e300f947b4dfc159637ba --- services/audioflinger/FastCapture.cpp | 4 +++- services/audioflinger/Threads.cpp | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/services/audioflinger/FastCapture.cpp b/services/audioflinger/FastCapture.cpp index 79ac12b500b..1bba5f651ec 100644 --- a/services/audioflinger/FastCapture.cpp +++ b/services/audioflinger/FastCapture.cpp @@ -131,7 +131,9 @@ void FastCapture::onStateChange() // FIXME new may block for unbounded time at internal mutex of the heap // implementation; it would be better to have normal capture thread allocate for // us to avoid blocking here and to prevent possible priority inversion - (void)posix_memalign(&mReadBuffer, 32, frameCount * Format_frameSize(mFormat)); + size_t bufferSize = frameCount * Format_frameSize(mFormat); + (void)posix_memalign(&mReadBuffer, 32, bufferSize); + memset(mReadBuffer, 0, bufferSize); // if posix_memalign fails, will segv here. mPeriodNs = (frameCount * 1000000000LL) / mSampleRate; // 1.00 mUnderrunNs = (frameCount * 1750000000LL) / mSampleRate; // 1.75 mOverrunNs = (frameCount * 500000000LL) / mSampleRate; // 0.50 diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 8dfdca624ed..f4750f7a5f4 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -6951,6 +6951,7 @@ void AudioFlinger::RecordThread::readInputParameters_l() mRsmpInFrames = mFrameCount * 7; mRsmpInFramesP2 = roundup(mRsmpInFrames); free(mRsmpInBuffer); + mRsmpInBuffer = NULL; // TODO optimize audio capture buffer sizes ... // Here we calculate the size of the sliding buffer used as a source @@ -6960,7 +6961,9 @@ void AudioFlinger::RecordThread::readInputParameters_l() // The current value is higher than necessary. However it should not add to latency. // Over-allocate beyond mRsmpInFramesP2 to permit a HAL read past end of buffer - (void)posix_memalign(&mRsmpInBuffer, 32, (mRsmpInFramesP2 + mFrameCount - 1) * mFrameSize); + size_t bufferSize = (mRsmpInFramesP2 + mFrameCount - 1) * mFrameSize; + (void)posix_memalign(&mRsmpInBuffer, 32, bufferSize); + memset(mRsmpInBuffer, 0, bufferSize); // if posix_memalign fails, will segv here. // AudioRecord mSampleRate and mChannelCount are constant due to AudioRecord API constraints. // But if thread's mSampleRate or mChannelCount changes, how will that affect active tracks? From aab7a8d5b32c0a7010114c521f62047191b3f507 Mon Sep 17 00:00:00 2001 From: Zach Jang Date: Tue, 27 Oct 2015 01:24:55 +0000 Subject: [PATCH 71/73] Revert "AudioPolicyService: fix race in AudioCommandThread" This reverts commit 74ce88ff0f24a8c08fdab3a1140212183089c2b5. Change-Id: I39114c8cdd3021951ba93716aaa0c1c03e68538d --- .../service/AudioPolicyService.cpp | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp index 41dd40ce578..d6890657ca4 100644 --- a/services/audiopolicy/service/AudioPolicyService.cpp +++ b/services/audiopolicy/service/AudioPolicyService.cpp @@ -577,28 +577,22 @@ bool AudioPolicyService::AudioCommandThread::threadLoop() } } waitTime = INT64_MAX; - // release mLock before releasing strong reference on the service as - // AudioPolicyService destructor calls AudioCommandThread::exit() which - // acquires mLock. - mLock.unlock(); - svc.clear(); - mLock.lock(); } else { waitTime = mAudioCommands[0]->mTime - curTime; break; } } - - // release delayed commands wake lock if the queue is empty - if (mAudioCommands.isEmpty()) { + // release mLock before releasing strong reference on the service as + // AudioPolicyService destructor calls AudioCommandThread::exit() which acquires mLock. + mLock.unlock(); + svc.clear(); + mLock.lock(); + if (!exitPending() && (mAudioCommands.isEmpty() || waitTime != INT64_MAX)) { + // release delayed commands wake lock release_wake_lock(mName.string()); - } - - // At this stage we have either an empty command queue or the first command in the queue - // has a finite delay. So unless we are exiting it is safe to wait. - if (!exitPending()) { ALOGV("AudioCommandThread() going to sleep"); mWaitWorkCV.waitRelative(mLock, waitTime); + ALOGV("AudioCommandThread() waking up"); } } // release delayed commands wake lock before quitting @@ -1011,8 +1005,6 @@ void AudioPolicyService::AudioCommandThread::exit() requestExit(); mWaitWorkCV.signal(); } - // Note that we can call it from the thread loop if all other references have been released - // but it will safely return WOULD_BLOCK in this case requestExitAndWait(); } From 84b7e7c06334d33396699739ac5abb9b4db8dc16 Mon Sep 17 00:00:00 2001 From: Zach Jang Date: Tue, 27 Oct 2015 01:25:27 +0000 Subject: [PATCH 72/73] Revert "audio policy: bind setMode() and setPhoneState() operations" This reverts commit 9ddf1c76121caef55a05c537d6a9a1d76c1d17be. Change-Id: I860ecc288a1798605dff46f39107f4450ca5cd56 --- services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp index a228798f00a..58ecb111446 100644 --- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp +++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp @@ -76,14 +76,10 @@ status_t AudioPolicyService::setPhoneState(audio_mode_t state) ALOGV("setPhoneState()"); - // acquire lock before calling setMode() so that setMode() + setPhoneState() are an atomic - // operation from policy manager standpoint (no other operation (e.g track start or stop) - // can be interleaved). - Mutex::Autolock _l(mLock); - // TODO: check if it is more appropriate to do it in platform specific policy manager AudioSystem::setMode(state); + Mutex::Autolock _l(mLock); mAudioPolicyManager->setPhoneState(state); mPhoneState = state; return NO_ERROR; From 42fe6b7a49615da0f3fa1799683e895b6ae48c03 Mon Sep 17 00:00:00 2001 From: MonoIith Date: Wed, 23 Dec 2015 21:13:50 -0500 Subject: [PATCH 73/73] stagefright: Fix size of metadata key * Causes build failure with Clang Orig-Change-Id: I957c9ad2f1a46c784b38e284063b5310bf9cc7ed --- include/media/stagefright/MetaData.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h index 275ef55d124..0dd5995595d 100644 --- a/include/media/stagefright/MetaData.h +++ b/include/media/stagefright/MetaData.h @@ -150,7 +150,7 @@ enum { kKeyWMVVersion = 'wmvv', // int32_t kKeyRVVersion = '#rvv', // int32_t - kKeyBlockAlign = 'blk', // int32_t , should be different from kKeyWMABlockAlign + kKeyBlockAlign = 'ablk', // int32_t , should be different from kKeyWMABlockAlign // An indication that a video buffer has been rendered. kKeyRendered = 'rend', // bool (int32_t)