diff --git a/camera/CameraParameters.cpp b/camera/CameraParameters.cpp index 68969cf649d..d35519d3089 100644 --- a/camera/CameraParameters.cpp +++ b/camera/CameraParameters.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include namespace android { @@ -106,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"; @@ -168,11 +170,16 @@ 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"; const char CameraParameters::LIGHTFX_HDR[] = "high-dynamic-range"; +#ifdef CAMERA_PARAMETERS_EXTRA_C +CAMERA_PARAMETERS_EXTRA_C +#endif + CameraParameters::CameraParameters() : mMap() { @@ -237,6 +244,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); 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; diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h index ba33ffe63b9..d85050d6084 100644 --- a/include/camera/CameraParameters.h +++ b/include/camera/CameraParameters.h @@ -19,6 +19,7 @@ #include #include +#include namespace android { @@ -554,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[]; @@ -677,12 +679,18 @@ 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[]; // 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[]; +*/ 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/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/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 0c31e726bc7..56abe71c7e2 100644 --- a/include/media/stagefright/DataSource.h +++ b/include/media/stagefright/DataSource.h @@ -36,6 +36,40 @@ 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 mExtraSniffers; + List::iterator extendedSnifferPosition; + + void registerSnifferPlugin(); + + Sniffer(const Sniffer &); + Sniffer &operator=(const Sniffer &); +}; class DataSource : public RefBase { public: @@ -57,7 +91,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,12 +145,10 @@ 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); + 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/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/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); } 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 183933a77ee..2f2057fff3b 100644 --- a/include/media/stagefright/MediaExtractor.h +++ b/include/media/stagefright/MediaExtractor.h @@ -19,17 +19,30 @@ #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 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 +80,7 @@ class MediaExtractor : public RefBase { } virtual void setUID(uid_t uid) { } + virtual void setExtraFlags(uint32_t flag) {} protected: MediaExtractor() : mIsDrm(false) {} @@ -74,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..0dd5995595d 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 = 'ablk', // 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/Android.mk b/media/libavextensions/Android.mk index 038013528eb..391885773ba 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 @@ -41,7 +41,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 @@ -75,7 +75,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 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/libavextensions/mediaplayerservice/AVNuExtensions.h b/media/libavextensions/mediaplayerservice/AVNuExtensions.h index a10937dc5ef..1d45c005ad2 100644 --- a/media/libavextensions/mediaplayerservice/AVNuExtensions.h +++ b/media/libavextensions/mediaplayerservice/AVNuExtensions.h @@ -80,9 +80,12 @@ struct AVNuUtils { virtual void setDecodedPCMFormat(const sp &); virtual status_t convertToSinkFormatIfNeeded(const sp &, sp &, audio_format_t sinkFormat, bool isOffload); + virtual uint32_t getFlags(); + virtual bool canUseSetBuffers(const sp &Meta); 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 aacf76a18bc..59075cba70c 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 &) { @@ -104,6 +142,16 @@ void AVNuUtils::checkFormatChange(bool * /*formatChange*/, const sp & /*accessUnit*/) { } +uint32_t AVNuUtils::getFlags() { + return 0; +} + +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 9c712e45488..0b70c089a56 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; @@ -68,10 +67,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, @@ -161,6 +160,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/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/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/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 2d9fcf711f5..22c66dbe5af 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," @@ -2318,7 +2336,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; } diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index a3f014b8835..0bf503a7ad4 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); @@ -1104,13 +1104,15 @@ 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(); - uint32_t latencyMs; - audio_io_handle_t output; + uint32_t latencyMs = 0; + 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); @@ -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(); @@ -1186,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) { @@ -1223,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) { @@ -1233,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) { @@ -1245,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) { @@ -1255,16 +1259,18 @@ 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(); 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); @@ -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 334844169a8..76b5924fad3 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, @@ -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); @@ -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)); @@ -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) { @@ -1238,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) { @@ -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); diff --git a/media/libmedia/ICrypto.cpp b/media/libmedia/ICrypto.cpp index 8f05936c0ec..24e027e1167 100644 --- a/media/libmedia/ICrypto.cpp +++ b/media/libmedia/ICrypto.cpp @@ -301,14 +301,32 @@ 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); } 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( 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); 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); 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/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/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index 6957a905a54..c0355d7d13c 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), @@ -126,6 +128,7 @@ status_t NuPlayer::GenericSource::setDataSource( status_t NuPlayer::GenericSource::setDataSource(const sp& source) { resetDataSource(); + Mutex::Autolock _l(mSourceLock); mDataSource = source; return OK; } @@ -153,7 +156,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( @@ -172,7 +180,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()->getFlags()); } if (extractor == NULL) { @@ -202,6 +211,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 +332,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; @@ -372,6 +386,7 @@ void NuPlayer::GenericSource::onPrepareAsync() { } } + Mutex::Autolock _l(mSourceLock); mDataSource = DataSource::CreateFromURI( mHTTPService, uri, &mUriHeaders, &contentType, static_cast(mHttpSource.get()), @@ -379,6 +394,7 @@ void NuPlayer::GenericSource::onPrepareAsync() { } else { mIsWidevine = false; + Mutex::Autolock _l(mSourceLock); mDataSource = new FileSource(mFd, mOffset, mLength); mFd = -1; } @@ -428,7 +444,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 @@ -468,9 +485,12 @@ void NuPlayer::GenericSource::finishPrepareAsync() { void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) { if (err != OK) { - mDataSource.clear(); - mCachedSource.clear(); - mHttpSource.clear(); + { + Mutex::Autolock _l(mSourceLock); + mDataSource.clear(); + mCachedSource.clear(); + mHttpSource.clear(); + } mBitrate = -1; cancelPollBuffering(); @@ -523,13 +543,20 @@ void NuPlayer::GenericSource::resume() { } void NuPlayer::GenericSource::disconnect() { - if (mDataSource != NULL) { + sp dataSource, 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(); } } @@ -1008,7 +1035,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 +1380,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 +1531,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..9f8556e35d4 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; @@ -136,6 +137,7 @@ struct NuPlayer::GenericSource : public NuPlayer::Source { int64_t mOffset; int64_t mLength; + Mutex mSourceLock; sp mDataSource; sp mCachedSource; sp mHttpSource; @@ -153,6 +155,7 @@ struct NuPlayer::GenericSource : public NuPlayer::Source { int32_t mPrevBufferPercentage; mutable Mutex mReadBufferLock; + mutable Mutex mDisconnectLock; sp mLooper; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 356c5191bc3..ec1ab795d4c 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; } } @@ -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)); @@ -1526,7 +1529,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) { @@ -1599,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/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index f83eaf6419e..0ade769c835 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) { @@ -364,7 +372,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) { @@ -590,6 +605,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/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/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/AACExtractor.cpp b/media/libstagefright/AACExtractor.cpp index 45e8a300b1d..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,11 +171,25 @@ 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) { - return; + break; } mOffsetVector.push(offset); @@ -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/ACodec.cpp b/media/libstagefright/ACodec.cpp index 18d221b2eb1..d3be54754e5 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; } @@ -619,8 +626,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); } } @@ -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; @@ -2113,16 +2127,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 +2150,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 +2469,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 +2507,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 +2655,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 +2690,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 +2917,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 +3073,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 +4188,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 +4242,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 +4260,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 +4310,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 +4325,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 +4466,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 +5773,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/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..9f9ae26ceec 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -69,6 +69,8 @@ LOCAL_SRC_FILES:= \ WVMExtractor.cpp \ XINGSeeker.cpp \ avc_utils.cpp \ + APE.cpp \ + FFMPEGSoftCodec.cpp \ LOCAL_C_INCLUDES:= \ $(TOP)/frameworks/av/include/media/ \ @@ -132,13 +134,27 @@ LOCAL_SHARED_LIBRARIES += \ LOCAL_CFLAGS += -Wno-multichar -Werror -Wno-error=deprecated-declarations -Wall +ifeq ($(TARGET_USES_QCOM_BSP), true) + LOCAL_C_INCLUDES += $(call project-path-for,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 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 +# 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 85d0292b389..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; @@ -112,29 +129,49 @@ 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) { + + 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(); - { - 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; @@ -143,48 +180,81 @@ bool DataSource::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; } -// 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; +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); + } +} - 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()); +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()); + registerSnifferPlugin(); 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 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/FLACExtractor.cpp b/media/libstagefright/FLACExtractor.cpp index 89a91f7e250..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; @@ -845,12 +773,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; } 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/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index cd50365c259..eee13c73630 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) { @@ -2573,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; } @@ -2974,12 +2990,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; @@ -4153,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(); @@ -4440,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(); @@ -4602,7 +4625,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) diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index 94f40b4841a..8dfc54c8a86 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; @@ -2284,15 +2286,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/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index 7f7c7fa19b2..1418040af91 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; } @@ -987,6 +989,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); @@ -1143,7 +1148,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; @@ -2631,6 +2637,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); 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) { 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 0f656a1b76f..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; } @@ -54,12 +56,19 @@ 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; + 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."); @@ -94,7 +103,12 @@ sp MediaExtractor::Create( } sp ret = NULL; - if ((ret = AVFactory::get()->createExtendedExtractor(source, mime, meta)) != 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); @@ -122,9 +136,11 @@ 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); + ret = AVFactory::get()->updateExtractor(ret, source, mime, meta, flags); if (ret != NULL) { if (isDrm) { ret->setDrmFlag(true); @@ -133,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/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp index c438d3ced3d..578171f9e6f 100644 --- a/media/libstagefright/OggExtractor.cpp +++ b/media/libstagefright/OggExtractor.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -1202,84 +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; - } - } - - size_t outLen = 3 * size / 4 - padding; - - *outSize = outLen; - - void *buffer = malloc(outLen); - CHECK(buffer != 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 != '=') { - return NULL; - } else { - if (i < n - padding) { - return NULL; - } - - 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; - } - } - - 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; @@ -1289,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); @@ -1316,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]); @@ -1324,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]); @@ -1332,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", @@ -1342,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/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/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp index 6c795ac2e08..c3adac4732a 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); @@ -455,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)); @@ -625,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); @@ -648,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)) { diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp index 7da5a9f4001..147eb455d76 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()); diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp index e7d36dc35af..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; @@ -213,8 +219,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 +248,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 +280,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 +316,11 @@ 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 +339,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 +353,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; @@ -436,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; } @@ -629,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; @@ -680,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() { @@ -829,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/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp index 335ac842582..d86dffb069d 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 %zu, ", + __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 = %zd", 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 = %zu", buffer->range_length()); } } 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( 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; 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/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; 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) { 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; 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_ 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/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/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/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp index ecc2573bb08..ff8137928af 100644 --- a/media/libstagefright/matroska/MatroskaExtractor.cpp +++ b/media/libstagefright/matroska/MatroskaExtractor.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include @@ -136,6 +137,7 @@ struct MatroskaSource : public MediaSource { enum Type { AVC, AAC, + HEVC, OTHER }; @@ -234,6 +236,17 @@ 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 uint8_t *data; + size_t size; + CHECK(meta->findData(kKeyHVCC, &type, (const void **)&data, &size)); + + CHECK(size >= 7); + mNALSizeLen = 1 + (data[14 + 7] & 3); + ALOGV("mNALSizeLen = %zu", mNALSizeLen); } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { mType = AAC; } @@ -521,8 +534,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 +556,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; } @@ -581,7 +616,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); @@ -819,6 +854,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); @@ -979,6 +1025,10 @@ void MatroskaExtractor::addTracks() { codecID); continue; } + } else if (!strcmp("V_MPEGH/ISO/HEVC", codecID)) { + meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_HEVC); + meta->setData(kKeyHVCC, kTypeHVCC, codecPrivate, codecPrivateSize); + } else if (!strcmp("V_VP8", codecID)) { meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_VP8); } else if (!strcmp("V_VP9", codecID)) { @@ -1000,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/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/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/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() { 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(); 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; 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); }; 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; 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? 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/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/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) { 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]; 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); } 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; } diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index 9a1101a8df2..3d706c129e9 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, @@ -2024,7 +2032,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 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 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");