summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--camera/CameraParameters.cpp18
-rw-r--r--camera/ICameraClient.cpp17
-rw-r--r--drm/libdrmframework/Android.mk2
-rw-r--r--include/camera/CameraParameters.h8
-rw-r--r--include/camera/CameraParametersExtra.h35
-rw-r--r--include/media/AudioParameter.h1
-rw-r--r--include/media/AudioTrack.h4
-rw-r--r--include/media/MediaPlayerInterface.h2
-rwxr-xr-x[-rw-r--r--]include/media/MediaProfiles.h27
-rw-r--r--include/media/mediaplayer.h11
-rwxr-xr-x[-rw-r--r--]include/media/mediarecorder.h24
-rw-r--r--include/media/stagefright/ACodec.h59
-rw-r--r--include/media/stagefright/AudioSource.h14
-rw-r--r--include/media/stagefright/CameraSource.h4
-rw-r--r--include/media/stagefright/CameraSourceTimeLapse.h5
-rw-r--r--include/media/stagefright/DataSource.h45
-rw-r--r--include/media/stagefright/ExtendedMediaDefs.h69
-rw-r--r--include/media/stagefright/FFMPEGSoftCodec.h133
-rw-r--r--include/media/stagefright/FileSource.h6
-rw-r--r--include/media/stagefright/MPEG4Writer.h5
-rw-r--r--include/media/stagefright/MediaCodec.h1
-rw-r--r--include/media/stagefright/MediaCodecSource.h2
-rw-r--r--include/media/stagefright/MediaDefs.h37
-rw-r--r--include/media/stagefright/MediaExtractor.h19
-rw-r--r--include/media/stagefright/MediaHTTP.h2
-rw-r--r--include/media/stagefright/MetaData.h50
-rw-r--r--media/libavextensions/Android.mk92
-rw-r--r--media/libavextensions/common/AVExtensionsCommon.h67
-rw-r--r--media/libavextensions/common/ExtensionsLoader.hpp93
-rw-r--r--media/libavextensions/media/AVMediaExtensions.h76
-rw-r--r--media/libavextensions/media/AVMediaUtils.cpp66
-rw-r--r--media/libavextensions/mediaplayerservice/AVMediaServiceExtensions.h92
-rw-r--r--media/libavextensions/mediaplayerservice/AVMediaServiceFactory.cpp72
-rw-r--r--media/libavextensions/mediaplayerservice/AVMediaServiceUtils.cpp103
-rw-r--r--media/libavextensions/mediaplayerservice/AVNuExtensions.h96
-rw-r--r--media/libavextensions/mediaplayerservice/AVNuFactory.cpp89
-rw-r--r--media/libavextensions/mediaplayerservice/AVNuUtils.cpp167
-rw-r--r--media/libavextensions/stagefright/AVExtensions.h215
-rw-r--r--media/libavextensions/stagefright/AVFactory.cpp135
-rw-r--r--media/libavextensions/stagefright/AVUtils.cpp190
-rw-r--r--media/libavextensions/stagefright/ExtendedMediaDefs.cpp68
-rw-r--r--media/libeffects/downmix/EffectDownmix.c9
-rw-r--r--media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp55
-rw-r--r--media/libeffects/lvm/wrapper/Bundle/EffectBundle.h2
-rw-r--r--media/libmedia/Android.mk12
-rw-r--r--media/libmedia/AudioParameter.cpp1
-rw-r--r--media/libmedia/AudioRecord.cpp3
-rw-r--r--media/libmedia/AudioTrack.cpp142
-rw-r--r--media/libmedia/ICrypto.cpp6
-rw-r--r--media/libmedia/IEffectClient.cpp4
-rw-r--r--media/libmedia/IOMX.cpp3
-rwxr-xr-x[-rw-r--r--]media/libmedia/MediaProfiles.cpp63
-rw-r--r--media/libmedia/MediaScanner.cpp4
-rw-r--r--media/libmedia/ToneGenerator.cpp8
-rw-r--r--media/libmedia/mediaplayer.cpp4
-rw-r--r--media/libmediaplayerservice/Android.mk7
-rw-r--r--media/libmediaplayerservice/MediaPlayerFactory.cpp75
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.cpp46
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.h1
-rw-r--r--media/libmediaplayerservice/MediaRecorderClient.cpp6
-rw-r--r--media/libmediaplayerservice/MetadataRetrieverClient.cpp18
-rw-r--r--media/libmediaplayerservice/StagefrightPlayer.cpp230
-rw-r--r--media/libmediaplayerservice/StagefrightPlayer.h80
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.cpp99
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.h22
-rw-r--r--media/libmediaplayerservice/nuplayer/Android.mk4
-rw-r--r--media/libmediaplayerservice/nuplayer/GenericSource.cpp33
-rw-r--r--media/libmediaplayerservice/nuplayer/GenericSource.h9
-rw-r--r--media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp21
-rw-r--r--media/libmediaplayerservice/nuplayer/HTTPLiveSource.h4
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayer.cpp111
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayer.h23
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp40
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h4
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp14
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h11
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp8
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp114
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h12
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerSource.h6
-rw-r--r--media/libmediaplayerservice/nuplayer/RTSPSource.cpp20
-rw-r--r--media/libstagefright/AACExtractor.cpp27
-rw-r--r--media/libstagefright/ACodec.cpp228
-rw-r--r--media/libstagefright/APE.cpp125
-rw-r--r--media/libstagefright/Android.mk40
-rw-r--r--media/libstagefright/AudioSource.cpp4
-rw-r--r--media/libstagefright/CameraSource.cpp28
-rw-r--r--media/libstagefright/CameraSourceTimeLapse.cpp9
-rw-r--r--media/libstagefright/DataSource.cpp171
-rw-r--r--media/libstagefright/FFMPEGSoftCodec.cpp1149
-rw-r--r--media/libstagefright/FLACExtractor.cpp188
-rw-r--r--media/libstagefright/FileSource.cpp16
-rwxr-xr-xmedia/libstagefright/MPEG4Extractor.cpp53
-rw-r--r--media/libstagefright/MPEG4Writer.cpp131
-rw-r--r--media/libstagefright/MediaBuffer.cpp1
-rw-r--r--media/libstagefright/MediaCodec.cpp11
-rw-r--r--media/libstagefright/MediaCodecList.cpp11
-rw-r--r--media/libstagefright/MediaCodecSource.cpp29
-rw-r--r--media/libstagefright/MediaDefs.cpp28
-rw-r--r--media/libstagefright/MediaExtractor.cpp37
-rw-r--r--media/libstagefright/OMXClient.cpp1
-rw-r--r--media/libstagefright/OMXCodec.cpp43
-rw-r--r--media/libstagefright/StagefrightMediaScanner.cpp11
-rw-r--r--media/libstagefright/StagefrightMetadataRetriever.cpp42
-rw-r--r--media/libstagefright/SurfaceMediaSource.cpp6
-rw-r--r--media/libstagefright/Utils.cpp47
-rw-r--r--media/libstagefright/VideoFrameScheduler.cpp3
-rw-r--r--media/libstagefright/WAVExtractor.cpp56
-rw-r--r--media/libstagefright/avc_utils.cpp20
-rw-r--r--media/libstagefright/codecs/aacdec/SoftAAC2.cpp41
-rw-r--r--media/libstagefright/codecs/aacdec/SoftAAC2.h3
-rw-r--r--media/libstagefright/codecs/amrnb/dec/Android.mk1
-rw-r--r--media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp9
-rw-r--r--media/libstagefright/codecs/mp3dec/SoftMP3.cpp44
-rw-r--r--media/libstagefright/codecs/mp3dec/SoftMP3.h3
-rw-r--r--media/libstagefright/codecs/raw/SoftRaw.cpp10
-rw-r--r--media/libstagefright/codecs/raw/SoftRaw.h3
-rw-r--r--media/libstagefright/data/media_codecs_google_video.xml9
-rw-r--r--media/libstagefright/foundation/ABuffer.cpp10
-rw-r--r--media/libstagefright/httplive/LiveSession.cpp5
-rw-r--r--media/libstagefright/httplive/LiveSession.h25
-rw-r--r--media/libstagefright/httplive/PlaylistFetcher.cpp8
-rw-r--r--media/libstagefright/httplive/PlaylistFetcher.h3
-rw-r--r--media/libstagefright/id3/ID3.cpp5
-rw-r--r--media/libstagefright/include/AACExtractor.h4
-rw-r--r--media/libstagefright/include/APE.h43
-rw-r--r--media/libstagefright/include/AwesomePlayer.h1
-rw-r--r--media/libstagefright/include/NuCachedSource2.h2
-rw-r--r--media/libstagefright/matroska/MatroskaExtractor.cpp58
-rw-r--r--media/libstagefright/omx/Android.mk6
-rw-r--r--media/libstagefright/omx/OMX.cpp18
-rw-r--r--media/libstagefright/omx/OMXMaster.cpp67
-rw-r--r--media/libstagefright/omx/OMXMaster.h7
-rw-r--r--media/libstagefright/omx/OMXNodeInstance.cpp8
-rwxr-xr-xmedia/libstagefright/omx/SoftOMXPlugin.cpp9
-rw-r--r--media/libstagefright/rtsp/AH263Assembler.cpp5
-rw-r--r--media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp5
-rw-r--r--media/libstagefright/rtsp/ARTPConnection.cpp10
-rw-r--r--media/libstagefright/rtsp/ARTPConnection.h7
-rw-r--r--media/libstagefright/rtsp/ARTSPConnection.cpp13
-rw-r--r--media/libstagefright/rtsp/ARTSPConnection.h7
-rw-r--r--media/libstagefright/rtsp/ASessionDescription.cpp5
-rw-r--r--media/libstagefright/rtsp/Android.mk6
-rw-r--r--media/libstagefright/rtsp/MyHandler.h69
-rw-r--r--media/mediaserver/Android.mk4
-rw-r--r--media/mtp/MtpServer.cpp6
-rw-r--r--media/mtp/MtpServer.h1
-rw-r--r--services/audioflinger/Android.mk22
-rw-r--r--services/audioflinger/AudioFlinger.cpp37
-rw-r--r--services/audioflinger/AudioMixer.cpp13
-rw-r--r--services/audioflinger/AudioMixer.h1
-rw-r--r--services/audioflinger/AudioResampler.cpp25
-rw-r--r--services/audioflinger/AudioResampler.h3
-rw-r--r--services/audioflinger/AudioResamplerQTI.cpp168
-rw-r--r--services/audioflinger/AudioResamplerQTI.h52
-rw-r--r--services/audioflinger/BufferProviders.cpp2
-rw-r--r--services/audioflinger/Effects.cpp15
-rw-r--r--services/audioflinger/Threads.cpp33
-rw-r--r--services/audioflinger/Threads.h1
-rw-r--r--services/audioflinger/Tracks.cpp2
-rw-r--r--services/audiopolicy/common/managerdefinitions/Android.mk21
-rw-r--r--services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h2
-rw-r--r--services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h36
-rw-r--r--services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp4
-rwxr-xr-xservices/audiopolicy/enginedefault/Android.mk5
-rwxr-xr-xservices/audiopolicy/enginedefault/src/Engine.cpp34
-rw-r--r--services/audiopolicy/managerdefault/AudioPolicyManager.cpp37
-rw-r--r--services/audiopolicy/managerdefault/AudioPolicyManager.h14
-rw-r--r--services/audiopolicy/service/AudioPolicyEffects.cpp1
-rw-r--r--services/audiopolicy/service/AudioPolicyEffects.h3
-rw-r--r--services/audiopolicy/service/AudioPolicyService.cpp10
-rw-r--r--services/camera/libcameraservice/Android.mk8
-rw-r--r--services/camera/libcameraservice/CameraService.cpp6
-rw-r--r--services/camera/libcameraservice/CameraService.h4
-rw-r--r--services/camera/libcameraservice/api1/CameraClient.cpp36
-rw-r--r--services/camera/libcameraservice/api1/CameraClient.h3
-rw-r--r--services/camera/libcameraservice/device1/CameraHardwareInterface.h27
177 files changed, 6110 insertions, 1125 deletions
diff --git a/camera/CameraParameters.cpp b/camera/CameraParameters.cpp
index 68969cf..42b0884 100644
--- a/camera/CameraParameters.cpp
+++ b/camera/CameraParameters.cpp
@@ -21,6 +21,7 @@
#include <string.h>
#include <stdlib.h>
#include <camera/CameraParameters.h>
+#include <camera/CameraParametersExtra.h>
#include <system/graphics.h>
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 &params)
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);
@@ -247,6 +257,14 @@ void CameraParameters::set(const char *key, const char *value)
//XXX ALOGE("Value \"%s\"contains invalid character (= or ;)", value);
return;
}
+#ifdef QCOM_HARDWARE
+ // qcom cameras default to delivering an extra zero-exposure frame on HDR.
+ // The android SDK only wants one frame, so disable this unless the app
+ // explicitly asks for it
+ if (!get("hdr-need-1x")) {
+ mMap.replaceValueFor(String8("hdr-need-1x"), String8("false"));
+ }
+#endif
mMap.replaceValueFor(String8(key), String8(value));
}
diff --git a/camera/ICameraClient.cpp b/camera/ICameraClient.cpp
index 179a341..4f43796 100644
--- a/camera/ICameraClient.cpp
+++ b/camera/ICameraClient.cpp
@@ -46,7 +46,12 @@ public:
data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
data.writeInt32(msgType);
data.writeInt32(ext1);
- data.writeInt32(ext2);
+ if ((msgType == CAMERA_MSG_PREVIEW_FRAME) && (ext1 == CAMERA_FRAME_DATA_FD)) {
+ ALOGD("notifyCallback: CAMERA_MSG_PREVIEW_FRAME fd = %d", ext2);
+ data.writeFileDescriptor(ext2);
+ } else {
+ data.writeInt32(ext2);
+ }
remote()->transact(NOTIFY_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
}
@@ -91,8 +96,14 @@ status_t BnCameraClient::onTransact(
ALOGV("NOTIFY_CALLBACK");
CHECK_INTERFACE(ICameraClient, data, reply);
int32_t msgType = data.readInt32();
- int32_t ext1 = data.readInt32();
- int32_t ext2 = data.readInt32();
+ int32_t ext1 = data.readInt32();
+ int32_t ext2 = 0;
+ if ((msgType == CAMERA_MSG_PREVIEW_FRAME) && (ext1 == CAMERA_FRAME_DATA_FD)) {
+ ext2 = data.readFileDescriptor();
+ ALOGD("onTransact: CAMERA_MSG_PREVIEW_FRAME fd = %d", ext2);
+ } else {
+ ext2 = data.readInt32();
+ }
notifyCallback(msgType, ext1, ext2);
return NO_ERROR;
} break;
diff --git a/drm/libdrmframework/Android.mk b/drm/libdrmframework/Android.mk
index 33f9d3b..b7eb70b 100644
--- a/drm/libdrmframework/Android.mk
+++ b/drm/libdrmframework/Android.mk
@@ -31,7 +31,7 @@ LOCAL_SHARED_LIBRARIES := \
libbinder \
libdl
-LOCAL_STATIC_LIBRARIES := \
+LOCAL_WHOLE_STATIC_LIBRARIES := \
libdrmframeworkcommon
LOCAL_C_INCLUDES += \
diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h
index ba33ffe..d85050d 100644
--- a/include/camera/CameraParameters.h
+++ b/include/camera/CameraParameters.h
@@ -19,6 +19,7 @@
#include <utils/KeyedVector.h>
#include <utils/String8.h>
+#include <camera/CameraParametersExtra.h>
namespace android {
@@ -554,6 +555,7 @@ public:
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 @@ public:
// 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 0000000..80a67cc
--- /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/AudioParameter.h b/include/media/AudioParameter.h
index 891bc4b..c769c4b 100644
--- a/include/media/AudioParameter.h
+++ b/include/media/AudioParameter.h
@@ -48,6 +48,7 @@ public:
static const char * const keyFrameCount;
static const char * const keyInputSource;
static const char * const keyScreenState;
+ static const char * const keyDevShutdown;
String8 toString();
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index e02f1b7..42fa3be 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -31,6 +31,7 @@ namespace android {
struct audio_track_cblk_t;
class AudioTrackClientProxy;
class StaticAudioTrackClientProxy;
+struct ExtendedMediaUtils;
// ----------------------------------------------------------------------------
@@ -623,6 +624,7 @@ private:
*/
status_t obtainBuffer(Buffer* audioBuffer, const struct timespec *requested,
struct timespec *elapsed = NULL, size_t *nonContig = NULL);
+ friend struct ExtendedMediaUtils;
public:
/* Public API for TRANSFER_OBTAIN mode.
@@ -940,6 +942,7 @@ protected:
// 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 {
@@ -957,6 +960,7 @@ private:
pid_t mClientPid;
sp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
+ friend struct ExtendedMediaUtils;
};
class TimedAudioTrack : public AudioTrack
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index de82554..745151b 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -46,12 +46,12 @@ class IGraphicBufferProducer;
template<typename T> class SortedVector;
enum player_type {
- STAGEFRIGHT_PLAYER = 3,
NU_PLAYER = 4,
// Test players are available only in the 'test' and 'eng' builds.
// The shared library with the test player is passed passed as an
// argument to the 'test:' url in the setDataSource call.
TEST_PLAYER = 5,
+ DASH_PLAYER = 6,
};
diff --git a/include/media/MediaProfiles.h b/include/media/MediaProfiles.h
index e02918f..c67bae9 100644..100755
--- a/include/media/MediaProfiles.h
+++ b/include/media/MediaProfiles.h
@@ -1,4 +1,6 @@
/*
+ ** Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ ** Not a Contribution.
**
** Copyright 2010, The Android Open Source Project.
**
@@ -56,6 +58,16 @@ enum camcorder_quality {
CAMCORDER_QUALITY_HIGH_SPEED_1080P = 2004,
CAMCORDER_QUALITY_HIGH_SPEED_2160P = 2005,
CAMCORDER_QUALITY_HIGH_SPEED_LIST_END = 2005,
+
+ CAMCORDER_QUALITY_VENDOR_START = 10000,
+ CAMCORDER_QUALITY_VGA = 10000,
+ CAMCORDER_QUALITY_4KDCI = 10001,
+ CAMCORDER_QUALITY_TIME_LAPSE_VGA = 10002,
+ CAMCORDER_QUALITY_TIME_LAPSE_4KDCI = 10003,
+ CAMCORDER_QUALITY_HIGH_SPEED_CIF = 10004,
+ CAMCORDER_QUALITY_HIGH_SPEED_VGA = 10005,
+ CAMCORDER_QUALITY_HIGH_SPEED_4KDCI = 10006,
+ CAMCORDER_QUALITY_VENDOR_END = 10006,
};
enum video_decoder {
@@ -126,6 +138,9 @@ public:
* enc.vid.bps.max - max bit rate in bits per second
* enc.vid.fps.min - min frame rate in frames per second
* enc.vid.fps.max - max frame rate in frames per second
+ * enc.vid.hfr.width.max - max hfr video frame width
+ * enc.vid.hfr.height.max - max hfr video frame height
+ * enc.vid.hfr.mode.max - max hfr mode
*/
int getVideoEncoderParamByName(const char *name, video_encoder codec) const;
@@ -264,12 +279,16 @@ private:
int minBitRate, int maxBitRate,
int minFrameWidth, int maxFrameWidth,
int minFrameHeight, int maxFrameHeight,
- int minFrameRate, int maxFrameRate)
+ int minFrameRate, int maxFrameRate,
+ int maxHFRFrameWidth, int maxHFRFrameHeight,
+ int maxHFRMode)
: mCodec(codec),
mMinBitRate(minBitRate), mMaxBitRate(maxBitRate),
mMinFrameWidth(minFrameWidth), mMaxFrameWidth(maxFrameWidth),
mMinFrameHeight(minFrameHeight), mMaxFrameHeight(maxFrameHeight),
- mMinFrameRate(minFrameRate), mMaxFrameRate(maxFrameRate) {}
+ mMinFrameRate(minFrameRate), mMaxFrameRate(maxFrameRate),
+ mMaxHFRFrameWidth(maxHFRFrameWidth), mMaxHFRFrameHeight(maxHFRFrameHeight),
+ mMaxHFRMode(maxHFRMode) {}
~VideoEncoderCap() {}
@@ -278,6 +297,8 @@ private:
int mMinFrameWidth, mMaxFrameWidth;
int mMinFrameHeight, mMaxFrameHeight;
int mMinFrameRate, mMaxFrameRate;
+ int mMaxHFRFrameWidth, mMaxHFRFrameHeight;
+ int mMaxHFRMode;
};
struct AudioEncoderCap {
@@ -392,6 +413,8 @@ private:
static VideoEncoderCap* createDefaultH263VideoEncoderCap();
static VideoEncoderCap* createDefaultM4vVideoEncoderCap();
static AudioEncoderCap* createDefaultAmrNBEncoderCap();
+ static AudioEncoderCap* createDefaultAacEncoderCap();
+ static AudioEncoderCap* createDefaultLpcmEncoderCap();
static int findTagForName(const NameToTagMap *map, size_t nMappings, const char *name);
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 3fe749c..1f6ddad 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -53,7 +53,7 @@ enum media_event_type {
MEDIA_ERROR = 100,
MEDIA_INFO = 200,
MEDIA_SUBTITLE_DATA = 201,
- MEDIA_META_DATA = 202,
+ MEDIA_META_DATA = 202
};
// Generic error codes for the media player framework. Errors are fatal, the
@@ -209,7 +209,7 @@ public:
void died();
void disconnect();
- status_t setDataSource(
+ virtual status_t setDataSource(
const sp<IMediaHTTPService> &httpService,
const char *url,
const KeyedVector<String8, String8> *headers);
@@ -224,7 +224,7 @@ public:
status_t prepareAsync();
status_t start();
status_t stop();
- status_t pause();
+ virtual status_t pause();
bool isPlaying();
status_t setPlaybackSettings(const AudioPlaybackRate& rate);
status_t getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */);
@@ -234,7 +234,7 @@ public:
float* videoFps /* nonnull */);
status_t getVideoWidth(int *w);
status_t getVideoHeight(int *h);
- status_t seekTo(int msec);
+ virtual status_t seekTo(int msec);
status_t getCurrentPosition(int *msec);
status_t getDuration(int *msec);
status_t reset();
@@ -243,7 +243,7 @@ public:
status_t setLooping(int loop);
bool isLooping();
status_t setVolume(float leftVolume, float rightVolume);
- void notify(int msg, int ext1, int ext2, const Parcel *obj = NULL);
+ virtual void notify(int msg, int ext1, int ext2, const Parcel *obj = NULL);
status_t invoke(const Parcel& request, Parcel *reply);
status_t setMetadataFilter(const Parcel& filter);
status_t getMetadata(bool update_only, bool apply_filter, Parcel *metadata);
@@ -289,6 +289,7 @@ private:
float mSendLevel;
struct sockaddr_in mRetransmitEndpoint;
bool mRetransmitEndpointValid;
+ friend class QCMediaPlayer;
};
}; // namespace android
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
index 15ff82d..93b5d67 100644..100755
--- a/include/media/mediarecorder.h
+++ b/include/media/mediarecorder.h
@@ -1,4 +1,7 @@
/*
+ ** Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ ** Not a Contribution.
+ **
** Copyright (C) 2008 The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
@@ -74,6 +77,9 @@ enum output_format {
/* VP8/VORBIS data in a WEBM container */
OUTPUT_FORMAT_WEBM = 9,
+ OUTPUT_FORMAT_QCP = 20,
+ OUTPUT_FORMAT_WAVE = 21,
+
OUTPUT_FORMAT_LIST_END // must be last - used to validate format type
};
@@ -86,6 +92,10 @@ enum audio_encoder {
AUDIO_ENCODER_AAC_ELD = 5,
AUDIO_ENCODER_VORBIS = 6,
+ AUDIO_ENCODER_EVRC = 10,
+ AUDIO_ENCODER_QCELP = 11,
+ AUDIO_ENCODER_LPCM = 12,
+
AUDIO_ENCODER_LIST_END // must be the last - used to validate the audio encoder type
};
@@ -96,7 +106,11 @@ enum video_encoder {
VIDEO_ENCODER_MPEG_4_SP = 3,
VIDEO_ENCODER_VP8 = 4,
- VIDEO_ENCODER_LIST_END // must be the last - used to validate the video encoder type
+ VIDEO_ENCODER_LIST_END, // must be the last - used to validate the video encoder type
+
+ VIDEO_ENCODER_LIST_VENDOR_START = 1000,
+ VIDEO_ENCODER_H265 = 1001,
+ VIDEO_ENCODER_LIST_VENDOR_END,
};
/*
@@ -225,13 +239,13 @@ public:
status_t setOutputFile(int fd, int64_t offset, int64_t length);
status_t setVideoSize(int width, int height);
status_t setVideoFrameRate(int frames_per_second);
- status_t setParameters(const String8& params);
+ virtual status_t setParameters(const String8& params);
status_t setListener(const sp<MediaRecorderListener>& listener);
status_t setClientName(const String16& clientName);
status_t prepare();
status_t getMaxAmplitude(int* max);
- status_t start();
- status_t stop();
+ virtual status_t start();
+ virtual status_t stop();
status_t reset();
status_t init();
status_t close();
@@ -240,7 +254,7 @@ public:
status_t setInputSurface(const sp<PersistentSurface>& surface);
sp<IGraphicBufferProducer> querySurfaceMediaSourceFromMediaServer();
-private:
+protected:
void doCleanUp();
status_t doReset();
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index 8b5b862..2e621fe 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -28,6 +28,8 @@
#include <media/stagefright/SkipCutBuffer.h>
#include <OMX_Audio.h>
+#include <system/audio.h>
+
#define TRACK_BUFFER_TIMING 0
namespace android {
@@ -93,8 +95,11 @@ struct ACodec : public AHierarchicalStateMachine, public CodecBase {
protected:
virtual ~ACodec();
+ virtual status_t setupCustomCodec(
+ status_t err, const char *mime, const sp<AMessage> &msg);
+ virtual status_t GetVideoCodingTypeFromMime(
+ const char *mime, OMX_VIDEO_CODINGTYPE *codingType);
-private:
struct BaseState;
struct UninitializedState;
struct LoadedState;
@@ -152,6 +157,7 @@ private:
};
struct BufferInfo {
+ BufferInfo() : mCustomData(-1) {}
enum Status {
OWNED_BY_US,
OWNED_BY_COMPONENT,
@@ -173,6 +179,7 @@ private:
sp<GraphicBuffer> mGraphicBuffer;
int mFenceFd;
FrameRenderTracker::Info *mRenderInfo;
+ int mCustomData;
// The following field and 4 methods are used for debugging only
bool mIsReadFence;
@@ -271,7 +278,7 @@ private:
status_t setCyclicIntraMacroblockRefresh(const sp<AMessage> &msg, int32_t mode);
status_t allocateBuffersOnPort(OMX_U32 portIndex);
status_t freeBuffersOnPort(OMX_U32 portIndex);
- status_t freeBuffer(OMX_U32 portIndex, size_t i);
+ virtual status_t freeBuffer(OMX_U32 portIndex, size_t i);
status_t handleSetSurface(const sp<Surface> &surface);
status_t setupNativeWindowSizeFormatAndUsage(
@@ -300,8 +307,8 @@ private:
uint32_t portIndex, IOMX::buffer_id bufferID,
ssize_t *index = NULL);
- status_t setComponentRole(bool isEncoder, const char *mime);
- status_t configureCodec(const char *mime, const sp<AMessage> &msg);
+ virtual status_t setComponentRole(bool isEncoder, const char *mime);
+ virtual status_t configureCodec(const char *mime, const sp<AMessage> &msg);
status_t configureTunneledVideoPlayback(int32_t audioHwSync,
const sp<ANativeWindow> &nativeWindow);
@@ -314,10 +321,10 @@ private:
status_t setSupportedOutputFormat(bool getLegacyFlexibleFormat);
- status_t setupVideoDecoder(
+ virtual status_t setupVideoDecoder(
const char *mime, const sp<AMessage> &msg, bool usingNativeBuffers);
- status_t setupVideoEncoder(
+ virtual status_t setupVideoEncoder(
const char *mime, const sp<AMessage> &msg);
status_t setVideoFormatOnPort(
@@ -340,9 +347,11 @@ private:
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);
@@ -354,7 +363,8 @@ private:
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);
@@ -372,7 +382,7 @@ private:
status_t configureBitrate(
int32_t bitrate, OMX_VIDEO_CONTROLRATETYPE bitrateMode);
- status_t setupErrorCorrectionParameters();
+ virtual status_t setupErrorCorrectionParameters();
status_t initNativeWindow();
@@ -408,7 +418,7 @@ private:
bool dropIncomplete = false, FrameRenderTracker::Info *until = NULL);
void sendFormatChange(const sp<AMessage> &reply);
- status_t getPortFormat(OMX_U32 portIndex, sp<AMessage> &notify);
+ virtual status_t getPortFormat(OMX_U32 portIndex, sp<AMessage> &notify);
void signalError(
OMX_ERRORTYPE error = OMX_ErrorUndefined,
@@ -420,11 +430,36 @@ private:
DescribeColorFormatParams &describeParams);
status_t requestIDRFrame();
- status_t setParameters(const sp<AMessage> &params);
+ virtual status_t setParameters(const sp<AMessage> &params);
// Send EOS on input stream.
void onSignalEndOfInputStream();
+ virtual void setBFrames(OMX_VIDEO_PARAM_MPEG4TYPE *mpeg4type) {}
+ virtual void setBFrames(OMX_VIDEO_PARAM_AVCTYPE *h264type,
+ const int32_t iFramesInterval, const int32_t frameRate) {}
+
+ virtual status_t getVQZIPInfo(const sp<AMessage> &msg) {
+ return OK;
+ }
+ virtual bool canAllocateBuffer(OMX_U32 /* portIndex */) {
+ return false;
+ }
+ virtual void enableCustomAllocationMode(const sp<AMessage> &/* msg */) {}
+ virtual status_t allocateBuffer(
+ OMX_U32 portIndex, size_t bufSize, BufferInfo &info);
+
+ virtual status_t setDSModeHint(sp<AMessage>& msg,
+ OMX_U32 flags, int64_t timeUs) {
+ return UNKNOWN_ERROR;
+ }
+
+ virtual bool getDSModeHint(const sp<AMessage>& msg) {
+ return false;
+ }
+
+ sp<IOMXObserver> createObserver();
+
DISALLOW_EVIL_CONSTRUCTORS(ACodec);
};
diff --git a/include/media/stagefright/AudioSource.h b/include/media/stagefright/AudioSource.h
index 3074910..9750bcd 100644
--- a/include/media/stagefright/AudioSource.h
+++ b/include/media/stagefright/AudioSource.h
@@ -46,6 +46,8 @@ struct AudioSource : public MediaSource, public MediaBufferObserver {
virtual status_t stop() { return reset(); }
virtual sp<MetaData> getFormat();
+ virtual status_t pause() { return ERROR_UNSUPPORTED; }
+
// Returns the maximum amplitude since last call.
int16_t getMaxAmplitude();
@@ -58,9 +60,11 @@ struct AudioSource : public MediaSource, public MediaBufferObserver {
protected:
virtual ~AudioSource();
-private:
+protected:
enum {
- kMaxBufferSize = 2048,
+ //calculated for max duration 80 msec with 48K sampling rate.
+ kMaxBufferSize = 30720,
+
// After the initial mute, we raise the volume linearly
// over kAutoRampDurationUs.
@@ -68,7 +72,7 @@ private:
// This is the initial mute duration to suppress
// the video recording signal tone
- kAutoRampStartUs = 0,
+ kAutoRampStartUs = 500000,
};
Mutex mLock;
@@ -100,10 +104,10 @@ private:
int32_t startFrame, int32_t rampDurationFrames,
uint8_t *data, size_t bytes);
- void queueInputBuffer_l(MediaBuffer *buffer, int64_t timeUs);
+ virtual void queueInputBuffer_l(MediaBuffer *buffer, int64_t timeUs);
void releaseQueuedFrames_l();
void waitOutstandingEncodingFrames_l();
- status_t reset();
+ virtual status_t reset();
AudioSource(const AudioSource &);
AudioSource &operator=(const AudioSource &);
diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h
index 069e897..527ee15 100644
--- a/include/media/stagefright/CameraSource.h
+++ b/include/media/stagefright/CameraSource.h
@@ -92,6 +92,8 @@ public:
virtual status_t read(
MediaBuffer **buffer, const ReadOptions *options = NULL);
+ virtual status_t pause() { return ERROR_UNSUPPORTED; }
+
/**
* Check whether a CameraSource object is properly initialized.
* Must call this method before stop().
@@ -189,7 +191,7 @@ protected:
void releaseCamera();
-private:
+protected:
friend struct CameraSourceListener;
Mutex mLock;
diff --git a/include/media/stagefright/CameraSourceTimeLapse.h b/include/media/stagefright/CameraSourceTimeLapse.h
index 34213be..f264d98 100644
--- a/include/media/stagefright/CameraSourceTimeLapse.h
+++ b/include/media/stagefright/CameraSourceTimeLapse.h
@@ -20,6 +20,7 @@
#include <pthread.h>
+#include <media/stagefright/CameraSource.h>
#include <utils/RefBase.h>
#include <utils/threads.h>
#include <utils/String16.h>
@@ -56,7 +57,7 @@ public:
// returning quickly.
void startQuickReadReturns();
-private:
+protected:
// size of the encoded video.
int32_t mVideoWidth;
int32_t mVideoHeight;
@@ -152,7 +153,7 @@ private:
// the frame needs to be encoded, it returns false and also modifies
// the time stamp to be one frame time ahead of the last encoded
// frame's time stamp.
- bool skipFrameAndModifyTimeStamp(int64_t *timestampUs);
+ virtual bool skipFrameAndModifyTimeStamp(int64_t *timestampUs);
// Wrapper to enter threadTimeLapseEntry()
static void *ThreadTimeLapseWrapper(void *me);
diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h
index dcde36f..56abe71 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<AMessage> *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<DataSource> &source, String8 *mimeType,
+ float *confidence, sp<AMessage> *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<SnifferFunc> mSniffers;
+ List<SnifferFunc> mExtraSniffers;
+ List<SnifferFunc>::iterator extendedSnifferPosition;
+
+ void registerSnifferPlugin();
+
+ Sniffer(const Sniffer &);
+ Sniffer &operator=(const Sniffer &);
+};
class DataSource : public RefBase {
public:
@@ -51,12 +85,13 @@ public:
const char *uri,
const KeyedVector<String8, String8> *headers = NULL,
String8 *contentType = NULL,
- HTTPBase *httpSource = NULL);
+ HTTPBase *httpSource = NULL,
+ bool useExtendedCache = false);
static sp<DataSource> CreateMediaHTTP(const sp<IMediaHTTPService> &httpService);
static sp<DataSource> CreateFromIDataSource(const sp<IDataSource> &source);
- DataSource() {}
+ DataSource() : mSniffer(new Sniffer()) {}
virtual status_t initCheck() const = 0;
@@ -110,12 +145,10 @@ public:
protected:
virtual ~DataSource() {}
-private:
- static Mutex gSnifferMutex;
- static List<SnifferFunc> gSniffers;
- static bool gSniffersRegistered;
+ sp<Sniffer> mSniffer;
static void RegisterSniffer_l(SnifferFunc func);
+ static void RegisterSnifferPlugin();
DataSource(const DataSource &);
DataSource &operator=(const DataSource &);
diff --git a/include/media/stagefright/ExtendedMediaDefs.h b/include/media/stagefright/ExtendedMediaDefs.h
new file mode 100644
index 0000000..18b5e9a
--- /dev/null
+++ b/include/media/stagefright/ExtendedMediaDefs.h
@@ -0,0 +1,69 @@
+/*Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _EXTENDED_MEDIA_DEFS_H_
+#define _EXTENDED_MEDIA_DEFS_H_
+
+namespace android {
+
+extern const char *MEDIA_MIMETYPE_AUDIO_EVRC;
+extern const char *MEDIA_MIMETYPE_VIDEO_WMV;
+extern const char *MEDIA_MIMETYPE_VIDEO_WMV_VC1;
+extern const char *MEDIA_MIMETYPE_AUDIO_WMA;
+extern const char *MEDIA_MIMETYPE_AUDIO_WMA_PRO;
+extern const char *MEDIA_MIMETYPE_AUDIO_WMA_LOSSLESS;
+extern const char *MEDIA_MIMETYPE_CONTAINER_ASF;
+extern const char *MEDIA_MIMETYPE_VIDEO_DIVX;
+extern const char *MEDIA_MIMETYPE_CONTAINER_AAC;
+extern const char *MEDIA_MIMETYPE_CONTAINER_QCP;
+extern const char *MEDIA_MIMETYPE_VIDEO_DIVX311;
+extern const char *MEDIA_MIMETYPE_VIDEO_DIVX4;
+extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG2;
+extern const char *MEDIA_MIMETYPE_CONTAINER_3G2;
+extern const char *MEDIA_MIMETYPE_AUDIO_DTS;
+extern const char *MEDIA_MIMETYPE_AUDIO_DTS_LBR;
+extern const char *MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS;
+extern const char *MEDIA_MIMETYPE_AUDIO_AIFF;
+extern const char *MEDIA_MIMETYPE_AUDIO_ALAC;
+extern const char *MEDIA_MIMETYPE_AUDIO_APE;
+extern const char *MEDIA_MIMETYPE_CONTAINER_QCAMR_NB;
+extern const char *MEDIA_MIMETYPE_CONTAINER_QCAMR_WB;
+extern const char *MEDIA_MIMETYPE_CONTAINER_QCMPEG;
+extern const char *MEDIA_MIMETYPE_CONTAINER_QCWAV;
+extern const char *MEDIA_MIMETYPE_CONTAINER_QCMPEG2TS;
+extern const char *MEDIA_MIMETYPE_CONTAINER_QCMPEG2PS;
+extern const char *MEDIA_MIMETYPE_CONTAINER_QCMPEG4;
+extern const char *MEDIA_MIMETYPE_CONTAINER_QCMATROSKA;
+extern const char *MEDIA_MIMETYPE_CONTAINER_QCOGG;
+extern const char *MEDIA_MIMETYPE_CONTAINER_QCFLV;
+extern const char *MEDIA_MIMETYPE_VIDEO_VPX;
+extern const char *MEDIA_MIMETYPE_CONTAINER_QTIFLAC;
+extern const char *MEDIA_MIMETYPE_VIDEO_MPEG4_DP;
+
+} // namespace android
+
+#endif // _EXTENDED_MEDIA_DEFS_H_
diff --git a/include/media/stagefright/FFMPEGSoftCodec.h b/include/media/stagefright/FFMPEGSoftCodec.h
new file mode 100644
index 0000000..83373d0
--- /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 <media/IOMX.h>
+#include <media/MediaCodecInfo.h>
+
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/AString.h>
+
+#include <media/stagefright/MetaData.h>
+
+#include <OMX_Audio.h>
+#include <OMX_Video.h>
+
+namespace android {
+
+struct FFMPEGSoftCodec {
+
+ enum {
+ kPortIndexInput = 0,
+ kPortIndexOutput = 1
+ };
+
+ static void convertMessageToMetaDataFF(
+ const sp<AMessage> &msg, sp<MetaData> &meta);
+
+ static void convertMetaDataToMessageFF(
+ const sp<MetaData> &meta, sp<AMessage> *format);
+
+ static const char* overrideComponentName(
+ uint32_t quirks, const sp<MetaData> &meta,
+ const char *mime, bool isEncoder);
+
+ static void overrideComponentName(
+ uint32_t quirks, const sp<AMessage> &msg,
+ AString* componentName, AString* mime,
+ int32_t isEncoder);
+
+ static status_t setSupportedRole(
+ const sp<IOMX> &omx, IOMX::node_id node,
+ bool isEncoder, const char *mime);
+
+ static status_t setAudioFormat(
+ const sp<AMessage> &msg, const char* mime,
+ sp<IOMX> OMXhandle, IOMX::node_id nodeID);
+
+ static status_t setVideoFormat(
+ const sp<AMessage> &msg, const char* mime,
+ sp<IOMX> OMXhandle,IOMX::node_id nodeID,
+ bool isEncoder, OMX_VIDEO_CODINGTYPE *compressionFormat);
+
+ static status_t getAudioPortFormat(
+ OMX_U32 portIndex, int coding,
+ sp<AMessage> &notify, sp<IOMX> OMXhandle, IOMX::node_id nodeID);
+
+ static status_t getVideoPortFormat(
+ OMX_U32 portIndex, int coding,
+ sp<AMessage> &notify, sp<IOMX> OMXhandle, IOMX::node_id nodeID);
+
+private:
+ static const char* getMsgKey(int key);
+
+ static status_t setWMVFormat(
+ const sp<AMessage> &msg, sp<IOMX> OMXhandle,
+ IOMX::node_id nodeID);
+
+ static status_t setRVFormat(
+ const sp<AMessage> &msg, sp<IOMX> OMXhandle,
+ IOMX::node_id nodeID);
+
+ static status_t setFFmpegVideoFormat(
+ const sp<AMessage> &msg, sp<IOMX> OMXhandle,
+ IOMX::node_id nodeID);
+
+ static status_t setRawAudioFormat(
+ const sp<AMessage> &msg, sp<IOMX> OMXhandle,
+ IOMX::node_id nodeID);
+
+ static status_t setWMAFormat(
+ const sp<AMessage> &msg, sp<IOMX> OMXhandle,
+ IOMX::node_id nodeID);
+
+ static status_t setVORBISFormat(
+ const sp<AMessage> &msg, sp<IOMX> OMXhandle,
+ IOMX::node_id nodeID);
+
+ static status_t setRAFormat(
+ const sp<AMessage> &msg, sp<IOMX> OMXhandle,
+ IOMX::node_id nodeID);
+
+ static status_t setFLACFormat(
+ const sp<AMessage> &msg, sp<IOMX> OMXhandle,
+ IOMX::node_id nodeID);
+
+ static status_t setMP2Format(
+ const sp<AMessage> &msg, sp<IOMX> OMXhandle,
+ IOMX::node_id nodeID);
+
+ static status_t setAC3Format(
+ const sp<AMessage> &msg, sp<IOMX> OMXhandle,
+ IOMX::node_id nodeID);
+
+ static status_t setAPEFormat(
+ const sp<AMessage> &msg, sp<IOMX> OMXhandle,
+ IOMX::node_id nodeID);
+
+ static status_t setDTSFormat(
+ const sp<AMessage> &msg, sp<IOMX> OMXhandle,
+ IOMX::node_id nodeID);
+
+ static status_t setFFmpegAudioFormat(
+ const sp<AMessage> &msg, sp<IOMX> OMXhandle,
+ IOMX::node_id nodeID);
+
+};
+
+}
+#endif
diff --git a/include/media/stagefright/FileSource.h b/include/media/stagefright/FileSource.h
index a981d1c..21844ca 100644
--- a/include/media/stagefright/FileSource.h
+++ b/include/media/stagefright/FileSource.h
@@ -39,6 +39,10 @@ public:
virtual status_t getSize(off64_t *size);
+ virtual String8 getUri() {
+ return mUri;
+ }
+
virtual sp<DecryptHandle> DrmInitialization(const char *mime);
virtual void getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client);
@@ -48,6 +52,7 @@ protected:
private:
int mFd;
+ String8 mUri;
int64_t mOffset;
int64_t mLength;
Mutex mLock;
@@ -60,6 +65,7 @@ private:
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/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index a195fe8..055c079 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -108,6 +108,8 @@ private:
sp<AMessage> mMetaKeys;
+ bool mIsVideoHEVC;
+
void setStartTimestampUs(int64_t timeUs);
int64_t getStartTimestampUs(); // Not const
status_t startTracks(MetaData *params);
@@ -181,6 +183,9 @@ private:
// By default, real time recording is on.
bool isRealTimeRecording() const;
+ // To use 3gp4 box for clips with AMR audio
+ bool mIsAudioAMR;
+
void lock();
void unlock();
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index c10963d..b0ae83b 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -51,6 +51,7 @@ struct MediaCodec : public AHandler {
BUFFER_FLAG_SYNCFRAME = 1,
BUFFER_FLAG_CODECCONFIG = 2,
BUFFER_FLAG_EOS = 4,
+ BUFFER_FLAG_EXTRADATA = 0x1000,
};
enum {
diff --git a/include/media/stagefright/MediaCodecSource.h b/include/media/stagefright/MediaCodecSource.h
index 71f58a9..d41d87b 100644
--- a/include/media/stagefright/MediaCodecSource.h
+++ b/include/media/stagefright/MediaCodecSource.h
@@ -28,7 +28,7 @@ class AMessage;
struct AReplyToken;
class IGraphicBufferProducer;
class IGraphicBufferConsumer;
-class MediaCodec;
+struct MediaCodec;
class MetaData;
struct MediaCodecSource : public MediaSource,
diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h
index 21eb04a..ffbd20c 100644
--- a/include/media/stagefright/MediaDefs.h
+++ b/include/media/stagefright/MediaDefs.h
@@ -66,6 +66,43 @@ 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 <media/stagefright/ExtendedMediaDefs.h>
+
#endif // MEDIA_DEFS_H_
diff --git a/include/media/stagefright/MediaExtractor.h b/include/media/stagefright/MediaExtractor.h
index 183933a..2f2057f 100644
--- a/include/media/stagefright/MediaExtractor.h
+++ b/include/media/stagefright/MediaExtractor.h
@@ -19,17 +19,30 @@
#define MEDIA_EXTRACTOR_H_
#include <utils/RefBase.h>
+#include <media/stagefright/DataSource.h>
namespace android {
-class DataSource;
class MediaSource;
class MetaData;
class MediaExtractor : public RefBase {
public:
+ typedef MediaExtractor *(*CreateFunc)(const sp<DataSource> &source,
+ const char *mime, const sp<AMessage> &meta);
+
+ struct Plugin {
+ DataSource::SnifferFunc sniff;
+ CreateFunc create;
+ };
+
+ static Plugin *getPlugin() {
+ return &sPlugin;
+ }
+
static sp<MediaExtractor> Create(
- const sp<DataSource> &source, const char *mime = NULL);
+ const sp<DataSource> &source, const char *mime = NULL,
+ const uint32_t flags = 0);
virtual size_t countTracks() = 0;
virtual sp<MediaSource> getTrack(size_t index) = 0;
@@ -67,6 +80,7 @@ public:
}
virtual void setUID(uid_t uid) {
}
+ virtual void setExtraFlags(uint32_t flag) {}
protected:
MediaExtractor() : mIsDrm(false) {}
@@ -74,6 +88,7 @@ protected:
private:
bool mIsDrm;
+ static Plugin sPlugin;
MediaExtractor(const MediaExtractor &);
MediaExtractor &operator=(const MediaExtractor &);
diff --git a/include/media/stagefright/MediaHTTP.h b/include/media/stagefright/MediaHTTP.h
index 006d8d8..88683bd 100644
--- a/include/media/stagefright/MediaHTTP.h
+++ b/include/media/stagefright/MediaHTTP.h
@@ -54,7 +54,7 @@ protected:
virtual String8 getUri();
virtual String8 getMIMEType() const;
-private:
+protected:
status_t mInitCheck;
sp<IMediaHTTPConnection> mHTTPConnection;
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 8d4e15a..0dd5995 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
new file mode 100644
index 0000000..3918857
--- /dev/null
+++ b/media/libavextensions/Android.mk
@@ -0,0 +1,92 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ stagefright/ExtendedMediaDefs.cpp \
+ stagefright/AVUtils.cpp \
+ stagefright/AVFactory.cpp \
+
+LOCAL_C_INCLUDES:= \
+ $(TOP)/frameworks/av/include/media/ \
+ $(TOP)/frameworks/av/media/libavextensions \
+ $(TOP)/frameworks/native/include/media/hardware \
+ $(TOP)/frameworks/native/include/media/openmax \
+ $(TOP)/external/flac/include \
+ $(TOP)/$(call project-path-for,qcom-media)/mm-core/inc \
+ $(TOP)/frameworks/av/media/libstagefright \
+
+LOCAL_CFLAGS += -Wno-multichar -Werror
+
+ifeq ($(TARGET_ENABLE_QC_AV_ENHANCEMENTS),true)
+ LOCAL_CFLAGS += -DENABLE_AV_ENHANCEMENTS
+endif
+
+LOCAL_MODULE:= libavextensions
+LOCAL_CLANG := false
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_STATIC_LIBRARY)
+
+########################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ media/AVMediaUtils.cpp \
+
+LOCAL_C_INCLUDES:= \
+ $(TOP)/frameworks/av/include/media/ \
+ $(TOP)/frameworks/av/media/libavextensions \
+ $(TOP)/frameworks/native/include/media/hardware \
+ $(TOP)/frameworks/native/include/media/openmax \
+ $(TOP)/external/flac/include \
+ $(TOP)/$(call project-path-for,qcom-media)/mm-core/inc
+
+LOCAL_CFLAGS += -Wno-multichar -Werror
+
+ifeq ($(TARGET_ENABLE_QC_AV_ENHANCEMENTS),true)
+ LOCAL_CFLAGS += -DENABLE_AV_ENHANCEMENTS
+endif
+
+LOCAL_MODULE:= libavmediaextentions
+LOCAL_CLANG := false
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_STATIC_LIBRARY)
+
+########################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ mediaplayerservice/AVMediaServiceFactory.cpp \
+ mediaplayerservice/AVMediaServiceUtils.cpp \
+ mediaplayerservice/AVNuFactory.cpp \
+ mediaplayerservice/AVNuUtils.cpp \
+
+LOCAL_C_INCLUDES:= \
+ $(TOP)/frameworks/av/include/media/ \
+ $(TOP)/frameworks/av/media/libmediaplayerservice \
+ $(TOP)/frameworks/av/media/libavextensions \
+ $(TOP)/frameworks/av/media/libstagefright/include \
+ $(TOP)/frameworks/av/media/libstagefright/rtsp \
+ $(TOP)/frameworks/native/include/media/hardware \
+ $(TOP)/frameworks/native/include/media/openmax \
+ $(TOP)/external/flac/include \
+ $(TOP)/$(call project-path-for,qcom-media)/mm-core/inc
+
+LOCAL_CFLAGS += -Wno-multichar -Werror
+
+ifeq ($(TARGET_ENABLE_QC_AV_ENHANCEMENTS),true)
+ LOCAL_CFLAGS += -DENABLE_AV_ENHANCEMENTS
+endif
+
+LOCAL_MODULE:= libavmediaserviceextensions
+LOCAL_CLANG := false
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_STATIC_LIBRARY)
+
diff --git a/media/libavextensions/common/AVExtensionsCommon.h b/media/libavextensions/common/AVExtensionsCommon.h
new file mode 100644
index 0000000..c39872e
--- /dev/null
+++ b/media/libavextensions/common/AVExtensionsCommon.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2013 - 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _AV_EXTENSIONS_COMMON_H_
+#define _AV_EXTENSIONS_COMMON_H_
+
+namespace android {
+
+typedef void *(*createFunction_t)(void);
+
+template <typename T>
+struct ExtensionsLoader {
+
+ static T *createInstance(const char *createFunctionName);
+
+private:
+ static void loadLib();
+ static createFunction_t loadCreateFunction(const char *createFunctionName);
+ static void *mLibHandle;
+};
+
+/*
+ * Boiler-plate to declare the class as a singleton (with a static getter)
+ * which can be loaded (dlopen'd) via ExtensionsLoader
+ */
+#define DECLARE_LOADABLE_SINGLETON(className) \
+protected: \
+ className(); \
+ virtual ~className(); \
+ static className *sInst; \
+private: \
+ className(const className&); \
+ className &operator=(className &); \
+public: \
+ static className *get() { \
+ return sInst; \
+ } \
+ friend struct ExtensionsLoader<className>;
+
+} //namespace android
+
+#endif // _AV_EXTENSIONS_COMMON_H_
diff --git a/media/libavextensions/common/ExtensionsLoader.hpp b/media/libavextensions/common/ExtensionsLoader.hpp
new file mode 100644
index 0000000..e03979c
--- /dev/null
+++ b/media/libavextensions/common/ExtensionsLoader.hpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2013 - 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <dlfcn.h>
+#include <common/AVExtensionsCommon.h>
+
+namespace android {
+
+static const char * CUSTOMIZATION_LIB_NAME = "libavenhancements.so";
+
+/*
+ * Create strongly-typed objects of type T
+ * If the customization library exists and does contain a "named" constructor,
+ * invoke and create an instance
+ * Else create the object of type T itself
+ *
+ * Contains a static instance to dlopen'd library, But may end up
+ * opening the library mutiple times. Following snip from dlopen man page is
+ * reassuring "...Only a single copy of an object file is brought into the
+ * address space, even if dlopen() is invoked multiple times in reference to
+ * the file, and even if different pathnames are used to reference the file.."
+ */
+
+template <typename T>
+T *ExtensionsLoader<T>::createInstance(const char *createFunctionName) {
+ ALOGV("createInstance(%dbit) : %s", sizeof(intptr_t)*8, createFunctionName);
+ // create extended object if extensions-lib is available and
+ // AV_ENHANCEMENTS is enabled
+#if ENABLE_AV_ENHANCEMENTS
+ createFunction_t createFunc = loadCreateFunction(createFunctionName);
+ if (createFunc) {
+ return reinterpret_cast<T *>((*createFunc)());
+ }
+#endif
+ // Else, create the default object
+ return new T;
+}
+
+template <typename T>
+void ExtensionsLoader<T>::loadLib() {
+ if (!mLibHandle) {
+ mLibHandle = ::dlopen(CUSTOMIZATION_LIB_NAME, RTLD_LAZY);
+ if (!mLibHandle) {
+ ALOGV("%s", dlerror());
+ return;
+ }
+ ALOGV("Opened %s", CUSTOMIZATION_LIB_NAME);
+ }
+}
+
+template <typename T>
+createFunction_t ExtensionsLoader<T>::loadCreateFunction(const char *createFunctionName) {
+ loadLib();
+ if (!mLibHandle) {
+ return NULL;
+ }
+ createFunction_t func = (createFunction_t)dlsym(mLibHandle, createFunctionName);
+ if (!func) {
+ ALOGW("symbol %s not found: %s",createFunctionName, dlerror());
+ }
+ return func;
+}
+
+//static
+template <typename T>
+void *ExtensionsLoader<T>::mLibHandle = NULL;
+
+} //namespace android
diff --git a/media/libavextensions/media/AVMediaExtensions.h b/media/libavextensions/media/AVMediaExtensions.h
new file mode 100644
index 0000000..ae26143
--- /dev/null
+++ b/media/libavextensions/media/AVMediaExtensions.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2013 - 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _AV_MEDIA_EXTENSIONS_H_
+#define _AV_MEDIA_EXTENSIONS_H_
+
+#include <common/AVExtensionsCommon.h>
+#include <hardware/audio.h>
+#include <media/AudioTrack.h>
+
+namespace android {
+
+class MediaRecorder;
+class Parcel;
+/*
+ * Common delegate to the classes in libstagefright
+ */
+struct AVMediaUtils {
+
+ virtual bool AudioTrackIsPcmOffloaded(const audio_format_t /*format*/) {
+ return false;
+ }
+ virtual status_t AudioTrackGetPosition(AudioTrack* /*track*/,
+ uint32_t* /*position*/) {
+ return NO_INIT;
+ }
+
+ virtual status_t AudioTrackGetTimestamp(AudioTrack* /*track*/,
+ AudioTimestamp* /*timestamp*/) {
+ return NO_INIT;
+ }
+
+ virtual size_t AudioTrackGetOffloadFrameCount(size_t frameCount) {
+ return frameCount;
+ }
+
+ virtual sp<MediaRecorder> createMediaRecorder(const String16& opPackageName);
+ virtual void writeCustomData(
+ Parcel * /* reply */, void * /* buffer_data */) {}
+ virtual void readCustomData(
+ const Parcel * /* reply */, void ** /*buffer_data */ ) {}
+ virtual void closeFileDescriptor(void * /* buffer_ptr */) {}
+ // ----- NO TRESSPASSING BEYOND THIS LINE ------
+ DECLARE_LOADABLE_SINGLETON(AVMediaUtils);
+};
+
+} //namespace android
+
+#endif //_AV_MEDIA_EXTENSIONS_H_
+
diff --git a/media/libavextensions/media/AVMediaUtils.cpp b/media/libavextensions/media/AVMediaUtils.cpp
new file mode 100644
index 0000000..0f9e9eb
--- /dev/null
+++ b/media/libavextensions/media/AVMediaUtils.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2013 - 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "AVMediaUtils"
+#include <utils/Log.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaCodecList.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/ACodec.h>
+
+#include <media/AudioTrack.h>
+#include <media/mediarecorder.h>
+
+#include "common/ExtensionsLoader.hpp"
+#include "media/AVMediaExtensions.h"
+
+namespace android {
+
+// ----- NO TRESSPASSING BEYOND THIS LINE ------
+AVMediaUtils::AVMediaUtils() {
+}
+
+AVMediaUtils::~AVMediaUtils() {
+}
+
+sp<MediaRecorder> AVMediaUtils::createMediaRecorder(const String16& opPackageName) {
+ return new MediaRecorder(opPackageName);
+}
+
+//static
+AVMediaUtils *AVMediaUtils::sInst =
+ ExtensionsLoader<AVMediaUtils>::createInstance("createExtendedMediaUtils");
+
+} //namespace android
+
diff --git a/media/libavextensions/mediaplayerservice/AVMediaServiceExtensions.h b/media/libavextensions/mediaplayerservice/AVMediaServiceExtensions.h
new file mode 100644
index 0000000..f2c789e
--- /dev/null
+++ b/media/libavextensions/mediaplayerservice/AVMediaServiceExtensions.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2013 - 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _AV_MEDIA_SERVICE_EXTENSIONS_H_
+#define _AV_MEDIA_SERVICE_EXTENSIONS_H_
+
+#include <common/AVExtensionsCommon.h>
+#include <MediaPlayerFactory.h>
+
+#include <utils/List.h>
+#include <utils/RefBase.h>
+#include <utils/String16.h>
+
+#include <media/Metadata.h>
+
+namespace android {
+
+struct StagefrightRecorder;
+struct ARTSPConnection;
+struct ARTPConnection;
+struct AString;
+struct MyHandler;
+struct ABuffer;
+
+/*
+ * Factory to create objects of base-classes in libmediaplayerservice
+ */
+struct AVMediaServiceFactory {
+ virtual StagefrightRecorder *createStagefrightRecorder(const String16 &);
+
+ // RTSP extensions
+ virtual sp<ARTSPConnection> createARTSPConnection(bool uidValid, uid_t uid);
+ virtual sp<ARTPConnection> createARTPConnection();
+
+ // ----- NO TRESSPASSING BEYOND THIS LINE ------
+ DECLARE_LOADABLE_SINGLETON(AVMediaServiceFactory);
+};
+
+/*
+ * Common delegate to the classes in libmediaplayerservice
+ */
+struct AVMediaServiceUtils {
+ virtual void getDashPlayerFactory(MediaPlayerFactory::IFactory *&, player_type ) {}
+ // RTSP IPV6 utils
+ virtual bool pokeAHole(sp<MyHandler> handler, int rtpSocket, int rtcpSocket,
+ const AString &transport, const AString &sessionHost);
+ virtual void makePortPair(int *rtpSocket, int *rtcpSocket, unsigned *rtpPort,
+ bool isIPV6);
+ virtual const char* parseURL(AString *host);
+ // RTSP customization utils
+ virtual bool parseTrackURL(AString url, AString val);
+ virtual void appendRange(AString *request);
+ virtual void setServerTimeoutUs(int64_t timeout);
+ virtual void appendMeta(media::Metadata *meta);
+ virtual bool checkNPTMapping(uint32_t *rtpInfoTime, int64_t *playTimeUs,
+ bool *nptValid, uint32_t rtpTime);
+ virtual void addH263AdvancedPacket(const sp<ABuffer> &buffer,
+ List<sp<ABuffer>> *packets, uint32_t rtpTime);
+ virtual bool parseNTPRange(const char *s, float *npt1, float *npt2);
+
+ // ----- NO TRESSPASSING BEYOND THIS LINE ------
+ DECLARE_LOADABLE_SINGLETON(AVMediaServiceUtils);
+};
+
+}
+
+#endif // _AV_EXTENSIONS__H_
diff --git a/media/libavextensions/mediaplayerservice/AVMediaServiceFactory.cpp b/media/libavextensions/mediaplayerservice/AVMediaServiceFactory.cpp
new file mode 100644
index 0000000..10b66f5
--- /dev/null
+++ b/media/libavextensions/mediaplayerservice/AVMediaServiceFactory.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2013 - 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "AVMediaServiceFactory"
+#include <utils/Log.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include "ARTPConnection.h"
+#include "ARTSPConnection.h"
+
+#include "MediaRecorderClient.h"
+#include "MediaPlayerService.h"
+#include "StagefrightRecorder.h"
+
+#include "common/ExtensionsLoader.hpp"
+#include "mediaplayerservice/AVMediaServiceExtensions.h"
+
+namespace android {
+StagefrightRecorder *AVMediaServiceFactory::createStagefrightRecorder(
+ const String16 &opPackageName) {
+ return new StagefrightRecorder(opPackageName);
+}
+
+sp<ARTSPConnection> AVMediaServiceFactory::createARTSPConnection(
+ bool uidValid, uid_t uid) {
+ return new ARTSPConnection(uidValid, uid);
+}
+
+sp<ARTPConnection> AVMediaServiceFactory::createARTPConnection() {
+ return new ARTPConnection();
+}
+
+// ----- NO TRESSPASSING BEYOND THIS LINE ------
+AVMediaServiceFactory::AVMediaServiceFactory() {
+}
+
+AVMediaServiceFactory::~AVMediaServiceFactory() {
+}
+
+//static
+AVMediaServiceFactory *AVMediaServiceFactory::sInst =
+ ExtensionsLoader<AVMediaServiceFactory>::createInstance("createExtendedMediaServiceFactory");
+
+} //namespace android
+
diff --git a/media/libavextensions/mediaplayerservice/AVMediaServiceUtils.cpp b/media/libavextensions/mediaplayerservice/AVMediaServiceUtils.cpp
new file mode 100644
index 0000000..0e42367
--- /dev/null
+++ b/media/libavextensions/mediaplayerservice/AVMediaServiceUtils.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2013 - 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "AVMediaServiceUtils"
+#include <utils/Log.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+#include "ARTPConnection.h"
+#include "ASessionDescription.h"
+#include "MyHandler.h"
+
+#include "common/ExtensionsLoader.hpp"
+#include "mediaplayerservice/AVMediaServiceExtensions.h"
+
+namespace android {
+
+bool AVMediaServiceUtils::pokeAHole(sp<MyHandler> handler, int rtpSocket, int rtcpSocket,
+ const AString &transport, const AString &/*sessionHost*/) {
+ if (handler == NULL) {
+ ALOGW("MyHandler is NULL");
+ return false;
+ }
+ return handler->pokeAHole(rtpSocket, rtcpSocket, transport);
+}
+
+void AVMediaServiceUtils::makePortPair(int *rtpSocket, int *rtcpSocket, unsigned *rtpPort,
+ bool /*isIPV6*/) {
+ return ARTPConnection::MakePortPair(rtpSocket, rtcpSocket, rtpPort);
+}
+
+const char* AVMediaServiceUtils::parseURL(AString *host) {
+ return strchr(host->c_str(), ':');
+}
+
+bool AVMediaServiceUtils::parseTrackURL(AString /*url*/, AString /*val*/) {
+ return false;
+}
+
+void AVMediaServiceUtils::appendRange(AString * /*request*/) {
+ return;
+}
+
+void AVMediaServiceUtils::setServerTimeoutUs(int64_t /*timeout*/) {
+ return;
+}
+
+void AVMediaServiceUtils::addH263AdvancedPacket(const sp<ABuffer> &/*buffer*/,
+ List<sp<ABuffer>> * /*packets*/, uint32_t /*rtpTime*/) {
+ return;
+}
+
+void AVMediaServiceUtils::appendMeta(media::Metadata * /*meta*/) {
+ return;
+}
+
+bool AVMediaServiceUtils::checkNPTMapping(uint32_t * /*rtpInfoTime*/, int64_t * /*playTimeUs*/,
+ bool * /*nptValid*/, uint32_t /*rtpTime*/) {
+ return false;
+}
+
+bool AVMediaServiceUtils::parseNTPRange(const char *s, float *npt1, float *npt2) {
+ return ASessionDescription::parseNTPRange(s, npt1, npt2);
+}
+
+// ----- NO TRESSPASSING BEYOND THIS LINE ------
+AVMediaServiceUtils::AVMediaServiceUtils() {
+}
+
+AVMediaServiceUtils::~AVMediaServiceUtils() {
+}
+
+//static
+AVMediaServiceUtils *AVMediaServiceUtils::sInst =
+ ExtensionsLoader<AVMediaServiceUtils>::createInstance("createExtendedMediaServiceUtils");
+
+} //namespace android
+
diff --git a/media/libavextensions/mediaplayerservice/AVNuExtensions.h b/media/libavextensions/mediaplayerservice/AVNuExtensions.h
new file mode 100644
index 0000000..5a7a0cb
--- /dev/null
+++ b/media/libavextensions/mediaplayerservice/AVNuExtensions.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2013 - 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _AV_NU_EXTENSIONS_H_
+#define _AV_NU_EXTENSIONS_H_
+
+#include <common/AVExtensionsCommon.h>
+
+namespace android {
+
+struct NuPlayer;
+/*
+ * Factory to create extended NuPlayer objects
+ */
+struct AVNuFactory {
+ virtual sp<NuPlayer> createNuPlayer(pid_t pid);
+
+ virtual sp<NuPlayer::DecoderBase> createPassThruDecoder(
+ const sp<AMessage> &notify,
+ const sp<NuPlayer::Source> &source,
+ const sp<NuPlayer::Renderer> &renderer);
+
+ virtual sp<NuPlayer::DecoderBase> createDecoder(
+ const sp<AMessage> &notify,
+ const sp<NuPlayer::Source> &source,
+ pid_t pid,
+ const sp<NuPlayer::Renderer> &renderer);
+
+ virtual sp<NuPlayer::Renderer> createRenderer(
+ const sp<MediaPlayerBase::AudioSink> &sink,
+ const sp<AMessage> &notify,
+ uint32_t flags);
+
+ // ----- NO TRESSPASSING BEYOND THIS LINE ------
+ DECLARE_LOADABLE_SINGLETON(AVNuFactory);
+};
+
+/*
+ * Common delegate to the classes in NuPlayer
+ */
+struct AVNuUtils {
+
+ virtual sp<MetaData> createPCMMetaFromSource(const sp<MetaData> &);
+ virtual bool pcmOffloadException(const sp<MetaData> &);
+ virtual bool isRAWFormat(const sp<MetaData> &);
+ virtual bool isRAWFormat(const sp<AMessage> &);
+ virtual bool isVorbisFormat(const sp<MetaData> &);
+ virtual int updateAudioBitWidth(audio_format_t audioFormat,
+ const sp<AMessage> &);
+ virtual audio_format_t getKeyPCMFormat(const sp<MetaData> &);
+ virtual void setKeyPCMFormat(const sp<MetaData> &, audio_format_t audioFormat);
+ virtual audio_format_t getPCMFormat(const sp<AMessage> &);
+ virtual void setPCMFormat(const sp<AMessage> &, audio_format_t audioFormat);
+ virtual void setSourcePCMFormat(const sp<MetaData> &);
+ virtual void setDecodedPCMFormat(const sp<AMessage> &);
+ virtual status_t convertToSinkFormatIfNeeded(const sp<ABuffer> &, sp<ABuffer> &,
+ audio_format_t sinkFormat, bool isOffload);
+ virtual uint32_t getUseSetBuffersFlag();
+ virtual bool canUseSetBuffers(const sp<MetaData> &Meta);
+
+ virtual void printFileName(int fd);
+ virtual void checkFormatChange(bool *formatChange, const sp<ABuffer> &accessUnit);
+ virtual void addFlagsInMeta(const sp<ABuffer> &buffer, int32_t flags, bool isAudio);
+
+ // ----- NO TRESSPASSING BEYOND THIS LINE ------
+ DECLARE_LOADABLE_SINGLETON(AVNuUtils);
+};
+
+}
+
+#endif // _AV_EXTENSIONS__H_
diff --git a/media/libavextensions/mediaplayerservice/AVNuFactory.cpp b/media/libavextensions/mediaplayerservice/AVNuFactory.cpp
new file mode 100644
index 0000000..ff7c074
--- /dev/null
+++ b/media/libavextensions/mediaplayerservice/AVNuFactory.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2013 - 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "AVNuFactory"
+#include <utils/Log.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+#include <nuplayer/NuPlayer.h>
+#include <nuplayer/NuPlayerDecoderBase.h>
+#include <nuplayer/NuPlayerDecoderPassThrough.h>
+#include <nuplayer/NuPlayerDecoder.h>
+#include <nuplayer/NuPlayerCCDecoder.h>
+#include <gui/Surface.h>
+#include <nuplayer/NuPlayerSource.h>
+#include <nuplayer/NuPlayerRenderer.h>
+
+#include "common/ExtensionsLoader.hpp"
+#include "mediaplayerservice/AVNuExtensions.h"
+
+namespace android {
+
+sp<NuPlayer> AVNuFactory::createNuPlayer(pid_t pid) {
+ return new NuPlayer(pid);
+}
+
+sp<NuPlayer::DecoderBase> AVNuFactory::createPassThruDecoder(
+ const sp<AMessage> &notify,
+ const sp<NuPlayer::Source> &source,
+ const sp<NuPlayer::Renderer> &renderer) {
+ return new NuPlayer::DecoderPassThrough(notify, source, renderer);
+}
+
+sp<NuPlayer::DecoderBase> AVNuFactory::createDecoder(
+ const sp<AMessage> &notify,
+ const sp<NuPlayer::Source> &source,
+ pid_t pid,
+ const sp<NuPlayer::Renderer> &renderer) {
+ return new NuPlayer::Decoder(notify, source, pid, renderer);
+}
+
+sp<NuPlayer::Renderer> AVNuFactory::createRenderer(
+ const sp<MediaPlayerBase::AudioSink> &sink,
+ const sp<AMessage> &notify,
+ uint32_t flags) {
+ return new NuPlayer::Renderer(sink, notify, flags);
+}
+
+// ----- NO TRESSPASSING BEYOND THIS LINE ------
+AVNuFactory::AVNuFactory() {
+}
+
+AVNuFactory::~AVNuFactory() {
+}
+
+//static
+AVNuFactory *AVNuFactory::sInst =
+ ExtensionsLoader<AVNuFactory>::createInstance("createExtendedNuFactory");
+
+} //namespace android
+
diff --git a/media/libavextensions/mediaplayerservice/AVNuUtils.cpp b/media/libavextensions/mediaplayerservice/AVNuUtils.cpp
new file mode 100644
index 0000000..ba837e4
--- /dev/null
+++ b/media/libavextensions/mediaplayerservice/AVNuUtils.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2013 - 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "AVNuUtils"
+#include <utils/Log.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+#include <media/stagefright/MediaDefs.h>
+
+#include <nuplayer/NuPlayer.h>
+#include <nuplayer/NuPlayerDecoderBase.h>
+#include <nuplayer/NuPlayerDecoderPassThrough.h>
+#include <nuplayer/NuPlayerSource.h>
+#include <nuplayer/NuPlayerRenderer.h>
+
+#include "common/ExtensionsLoader.hpp"
+#include "mediaplayerservice/AVNuExtensions.h"
+
+namespace android {
+
+sp<MetaData> AVNuUtils::createPCMMetaFromSource(const sp<MetaData> &sMeta) {
+ return sMeta;
+}
+
+bool AVNuUtils::pcmOffloadException(const sp<MetaData> &) {
+ return true;
+}
+
+bool AVNuUtils::isRAWFormat(const sp<MetaData> &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<AMessage> &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<MetaData> &) {
+ return false;
+}
+
+int AVNuUtils::updateAudioBitWidth(audio_format_t /*audioFormat*/,
+ const sp<AMessage> &){
+ return 16;
+}
+
+audio_format_t AVNuUtils::getKeyPCMFormat(const sp<MetaData> &meta) {
+ int32_t pcmFormat = 0;
+ if (meta->findInt32('pfmt', &pcmFormat))
+ return (audio_format_t)pcmFormat;
+
+ return AUDIO_FORMAT_PCM_16_BIT;
+}
+
+void AVNuUtils::setKeyPCMFormat(const sp<MetaData> &meta, audio_format_t audioFormat) {
+ if (audio_is_linear_pcm(audioFormat))
+ meta->setInt32('pfmt', audioFormat);
+}
+
+audio_format_t AVNuUtils::getPCMFormat(const sp<AMessage> &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<AMessage> &format, audio_format_t audioFormat) {
+ if (audio_is_linear_pcm(audioFormat))
+ format->setInt32("pcm-format", audioFormat);
+}
+
+void AVNuUtils::setSourcePCMFormat(const sp<MetaData> &) {
+
+}
+
+void AVNuUtils::setDecodedPCMFormat(const sp<AMessage> &) {
+
+}
+
+status_t AVNuUtils::convertToSinkFormatIfNeeded(const sp<ABuffer> &, sp<ABuffer> &,
+ audio_format_t /*sinkFormat*/, bool /*isOffload*/) {
+ return INVALID_OPERATION;
+}
+
+void AVNuUtils::printFileName(int) {}
+
+void AVNuUtils::checkFormatChange(bool * /*formatChange*/,
+ const sp<ABuffer> & /*accessUnit*/) {
+}
+
+void AVNuUtils::addFlagsInMeta(const sp<ABuffer> & /*buffer*/,
+ int32_t /*flags*/, bool /*isAudio*/) {
+}
+
+uint32_t AVNuUtils::getUseSetBuffersFlag() {
+ return 0;
+}
+
+bool AVNuUtils::canUseSetBuffers(const sp<MetaData> &/*Meta*/) {
+ return false;
+}
+
+// ----- NO TRESSPASSING BEYOND THIS LINE ------
+AVNuUtils::AVNuUtils() {}
+
+AVNuUtils::~AVNuUtils() {}
+
+//static
+AVNuUtils *AVNuUtils::sInst =
+ ExtensionsLoader<AVNuUtils>::createInstance("createExtendedNuUtils");
+
+} //namespace android
+
diff --git a/media/libavextensions/stagefright/AVExtensions.h b/media/libavextensions/stagefright/AVExtensions.h
new file mode 100644
index 0000000..937180f
--- /dev/null
+++ b/media/libavextensions/stagefright/AVExtensions.h
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2013 - 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _AV_EXTENSIONS_H_
+#define _AV_EXTENSIONS_H_
+
+#include <media/stagefright/DataSource.h>
+#include <common/AVExtensionsCommon.h>
+#include <system/audio.h>
+#include <camera/ICamera.h>
+#include <media/mediarecorder.h>
+#include <media/IOMX.h>
+
+namespace android {
+
+class AudioParameter;
+class MetaData;
+class MediaExtractor;
+class MPEG4Writer;
+struct ABuffer;
+struct ACodec;
+struct ALooper;
+struct IMediaHTTPConnection;
+struct MediaCodec;
+struct MediaSource;
+struct MediaHTTP;
+struct NuCachedSource2;
+class CameraParameters;
+class MediaBuffer;
+struct AudioSource;
+class CameraSource;
+class CameraSourceTimeLapse;
+class ICamera;
+class ICameraRecordingProxy;
+class String16;
+class IGraphicBufferProducer;
+struct Size;
+
+/*
+ * Factory to create objects of base-classes in libstagefright
+ */
+struct AVFactory {
+ virtual sp<ACodec> createACodec();
+ virtual MediaExtractor* createExtendedExtractor(
+ const sp<DataSource> &source, const char *mime,
+ const sp<AMessage> &meta, const uint32_t flags);
+ virtual sp<MediaExtractor> updateExtractor(
+ sp<MediaExtractor> ext, const sp<DataSource> &source,
+ const char *mime, const sp<AMessage> &meta, const uint32_t flags);
+ virtual sp<NuCachedSource2> createCachedSource(
+ const sp<DataSource> &source,
+ const char *cacheConfig = NULL,
+ bool disconnectAtHighwatermark = false);
+ virtual MediaHTTP* createMediaHTTP(
+ const sp<IMediaHTTPConnection> &conn);
+
+ virtual AudioSource* createAudioSource(
+ audio_source_t inputSource,
+ const String16 &opPackageName,
+ uint32_t sampleRate,
+ uint32_t channels,
+ uint32_t outSampleRate = 0);
+
+ virtual CameraSource *CreateCameraSourceFromCamera(
+ const sp<ICamera> &camera,
+ const sp<ICameraRecordingProxy> &proxy,
+ int32_t cameraId,
+ const String16& clientName,
+ uid_t clientUid,
+ Size videoSize,
+ int32_t frameRate,
+ const sp<IGraphicBufferProducer>& surface,
+ bool storeMetaDataInVideoBuffers = true);
+
+ virtual CameraSourceTimeLapse *CreateCameraSourceTimeLapseFromCamera(
+ const sp<ICamera> &camera,
+ const sp<ICameraRecordingProxy> &proxy,
+ int32_t cameraId,
+ const String16& clientName,
+ uid_t clientUid,
+ Size videoSize,
+ int32_t videoFrameRate,
+ const sp<IGraphicBufferProducer>& surface,
+ int64_t timeBetweenFrameCaptureUs,
+ bool storeMetaDataInVideoBuffers = true);
+ // ----- NO TRESSPASSING BEYOND THIS LINE ------
+ DECLARE_LOADABLE_SINGLETON(AVFactory);
+};
+
+/*
+ * Common delegate to the classes in libstagefright
+ */
+struct AVUtils {
+
+ virtual status_t convertMetaDataToMessage(
+ const sp<MetaData> &meta, sp<AMessage> *format);
+ virtual DataSource::SnifferFunc getExtendedSniffer();
+ virtual status_t mapMimeToAudioFormat( audio_format_t& format, const char* mime);
+ virtual status_t sendMetaDataToHal(const sp<MetaData>& meta, AudioParameter *param);
+
+ virtual sp<MediaCodec> createCustomComponentByName(const sp<ALooper> &looper,
+ const char* mime, bool encoder, const sp<AMessage> &format);
+ virtual bool isEnhancedExtension(const char *extension);
+
+ virtual bool is24bitPCMOffloadEnabled();
+ virtual bool is16bitPCMOffloadEnabled();
+ virtual int getAudioSampleBits(const sp<MetaData> &);
+ virtual int getAudioSampleBits(const sp<AMessage> &);
+ virtual void setPcmSampleBits(const sp<MetaData> &, int32_t /*bitWidth*/);
+ virtual void setPcmSampleBits(const sp<AMessage> &, int32_t /*bitWidth*/);
+
+ virtual audio_format_t updateAudioFormat(audio_format_t audioFormat,
+ const sp<MetaData> &);
+
+ virtual audio_format_t updateAudioFormat(audio_format_t audioFormat,
+ const sp<AMessage> &);
+
+ virtual bool canOffloadAPE(const sp<MetaData> &meta);
+
+ virtual int32_t getAudioMaxInputBufferSize(audio_format_t audioFormat,
+ const sp<AMessage> &);
+
+ virtual bool mapAACProfileToAudioFormat(const sp<MetaData> &,
+ audio_format_t &,
+ uint64_t /*eAacProfile*/);
+
+ virtual bool mapAACProfileToAudioFormat(const sp<AMessage> &,
+ audio_format_t &,
+ uint64_t /*eAacProfile*/);
+
+ virtual void extractCustomCameraKeys(
+ const CameraParameters& /*params*/, sp<MetaData> &/*meta*/) {}
+ virtual void printFileName(int /*fd*/) {}
+ virtual void addDecodingTimesFromBatch(MediaBuffer * /*buf*/,
+ List<int64_t> &/*decodeTimeQueue*/) {}
+
+ virtual bool useQCHWEncoder(const sp<AMessage> &, AString &) { return false; }
+
+ virtual bool canDeferRelease(const sp<MetaData> &/*meta*/) { return false; }
+ virtual void setDeferRelease(sp<MetaData> &/*meta*/) {}
+
+ struct HEVCMuxer {
+
+ virtual bool reassembleHEVCCSD(const AString &mime, sp<ABuffer> csd0, sp<MetaData> &meta);
+
+ virtual void writeHEVCFtypBox(MPEG4Writer *writer);
+
+ virtual status_t makeHEVCCodecSpecificData(const uint8_t *data,
+ size_t size, void** codecSpecificData,
+ size_t *codecSpecificDataSize);
+
+ virtual const char *getFourCCForMime(const char *mime);
+
+ virtual void writeHvccBox(MPEG4Writer *writer,
+ void* codecSpecificData, size_t codecSpecificDataSize,
+ bool useNalLengthFour);
+
+ virtual bool isVideoHEVC(const char* mime);
+
+ virtual void getHEVCCodecSpecificDataFromInputFormatIfPossible(
+ sp<MetaData> meta, void **codecSpecificData,
+ size_t *codecSpecificDataSize, bool *gotAllCodecSpecificData);
+
+ protected:
+ HEVCMuxer() {};
+ virtual ~HEVCMuxer() {};
+ friend struct AVUtils;
+ };
+
+ virtual inline HEVCMuxer& HEVCMuxerUtils() {
+ return mHEVCMuxer;
+ }
+
+ virtual bool isAudioMuxFormatSupported(const char *mime);
+ virtual void cacheCaptureBuffers(sp<ICamera> camera, video_encoder encoder);
+ virtual const char *getCustomCodecsLocation();
+
+ virtual void setIntraPeriod(
+ int nPFrames, int nBFrames, const sp<IOMX> OMXhandle,
+ IOMX::node_id nodeID);
+
+private:
+ HEVCMuxer mHEVCMuxer;
+ // ----- NO TRESSPASSING BEYOND THIS LINE ------
+ DECLARE_LOADABLE_SINGLETON(AVUtils);
+};
+
+}
+
+#endif // _AV_EXTENSIONS__H_
diff --git a/media/libavextensions/stagefright/AVFactory.cpp b/media/libavextensions/stagefright/AVFactory.cpp
new file mode 100644
index 0000000..f6d5f53
--- /dev/null
+++ b/media/libavextensions/stagefright/AVFactory.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2013 - 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "AVFactory"
+#include <utils/Log.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaCodecList.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/ACodec.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MediaHTTP.h>
+#include <media/stagefright/AudioSource.h>
+#include <media/stagefright/CameraSource.h>
+#include <media/stagefright/CameraSourceTimeLapse.h>
+#include <camera/CameraParameters.h>
+
+#include "common/ExtensionsLoader.hpp"
+#include "stagefright/AVExtensions.h"
+#include "include/NuCachedSource2.h"
+
+namespace android {
+
+sp<ACodec> AVFactory::createACodec() {
+ return new ACodec;
+}
+
+MediaExtractor* AVFactory::createExtendedExtractor(
+ const sp<DataSource> &, const char *, const sp<AMessage> &,
+ const uint32_t) {
+ return NULL;
+}
+
+sp<MediaExtractor> AVFactory::updateExtractor(
+ sp<MediaExtractor> ext, const sp<DataSource> &,
+ const char *, const sp<AMessage> &, const uint32_t) {
+ return ext;
+}
+
+sp<NuCachedSource2> AVFactory::createCachedSource(
+ const sp<DataSource> &source,
+ const char *cacheConfig,
+ bool disconnectAtHighwatermark) {
+ return NuCachedSource2::Create(source, cacheConfig, disconnectAtHighwatermark);
+}
+
+MediaHTTP* AVFactory::createMediaHTTP(
+ const sp<IMediaHTTPConnection> &conn) {
+ return new MediaHTTP(conn);
+}
+
+AudioSource* AVFactory::createAudioSource(
+ audio_source_t inputSource,
+ const String16 &opPackageName,
+ uint32_t sampleRate,
+ uint32_t channels,
+ uint32_t outSampleRate) {
+ return new AudioSource(inputSource, opPackageName, sampleRate,
+ channels, outSampleRate);
+}
+
+CameraSource* AVFactory::CreateCameraSourceFromCamera(
+ const sp<ICamera> &camera,
+ const sp<ICameraRecordingProxy> &proxy,
+ int32_t cameraId,
+ const String16& clientName,
+ uid_t clientUid,
+ Size videoSize,
+ int32_t frameRate,
+ const sp<IGraphicBufferProducer>& surface,
+ bool storeMetaDataInVideoBuffers) {
+ return CameraSource::CreateFromCamera(camera, proxy, cameraId,
+ clientName, clientUid, videoSize, frameRate, surface,
+ storeMetaDataInVideoBuffers);
+}
+
+CameraSourceTimeLapse* AVFactory::CreateCameraSourceTimeLapseFromCamera(
+ const sp<ICamera> &camera,
+ const sp<ICameraRecordingProxy> &proxy,
+ int32_t cameraId,
+ const String16& clientName,
+ uid_t clientUid,
+ Size videoSize,
+ int32_t videoFrameRate,
+ const sp<IGraphicBufferProducer>& surface,
+ int64_t timeBetweenFrameCaptureUs,
+ bool storeMetaDataInVideoBuffers) {
+ return CameraSourceTimeLapse::CreateFromCamera(camera, proxy, cameraId,
+ clientName, clientUid, videoSize, videoFrameRate, surface,
+ timeBetweenFrameCaptureUs, storeMetaDataInVideoBuffers);
+}
+// ----- NO TRESSPASSING BEYOND THIS LINE ------
+AVFactory::AVFactory() {
+}
+
+AVFactory::~AVFactory() {
+}
+
+//static
+AVFactory *AVFactory::sInst =
+ ExtensionsLoader<AVFactory>::createInstance("createExtendedFactory");
+
+} //namespace android
+
diff --git a/media/libavextensions/stagefright/AVUtils.cpp b/media/libavextensions/stagefright/AVUtils.cpp
new file mode 100644
index 0000000..50c0f89
--- /dev/null
+++ b/media/libavextensions/stagefright/AVUtils.cpp
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2013 - 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "AVUtils"
+#include <utils/Log.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaCodecList.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/ACodec.h>
+#include <media/stagefright/MediaCodec.h>
+
+#include "common/ExtensionsLoader.hpp"
+#include "stagefright/AVExtensions.h"
+
+namespace android {
+
+status_t AVUtils::convertMetaDataToMessage(
+ const sp<MetaData> &, sp<AMessage> *) {
+ return OK;
+}
+
+status_t AVUtils::mapMimeToAudioFormat(
+ audio_format_t&, const char* ) {
+ return OK;
+}
+
+status_t AVUtils::sendMetaDataToHal(
+ const sp<MetaData>&, AudioParameter *){
+ return OK;
+}
+
+bool AVUtils::is24bitPCMOffloadEnabled() {return false;}
+bool AVUtils::is16bitPCMOffloadEnabled() {return false;}
+
+int AVUtils::getAudioSampleBits(const sp<MetaData> &) {
+ return 16;
+}
+
+int AVUtils::getAudioSampleBits(const sp<AMessage> &format) {
+ int32_t bits = 16;
+ format->findInt32("bit-width", &bits);
+ return bits;
+}
+
+void AVUtils::setPcmSampleBits(const sp<AMessage> &, int32_t /*bitWidth*/) {
+}
+
+void AVUtils::setPcmSampleBits(const sp<MetaData> &, int32_t /*bitWidth*/) {
+}
+
+audio_format_t AVUtils::updateAudioFormat(audio_format_t audioFormat,
+ const sp<MetaData> &){
+ return audioFormat;
+}
+
+audio_format_t AVUtils::updateAudioFormat(audio_format_t audioFormat,
+ const sp<AMessage> &){
+ return audioFormat;
+}
+
+static bool dumbSniffer(
+ const sp<DataSource> &, String8 *,
+ float *, sp<AMessage> *) {
+ return false;
+}
+
+DataSource::SnifferFunc AVUtils::getExtendedSniffer() {
+ return dumbSniffer;
+}
+
+sp<MediaCodec> AVUtils::createCustomComponentByName(
+ const sp<ALooper> &, const char* , bool, const sp<AMessage> &) {
+ return NULL;
+}
+
+bool AVUtils::canOffloadAPE(const sp<MetaData> &) {
+ return true;
+}
+
+int32_t AVUtils::getAudioMaxInputBufferSize(audio_format_t, const sp<AMessage> &) {
+ return 0;
+}
+
+bool AVUtils::mapAACProfileToAudioFormat(const sp<MetaData> &, audio_format_t &,
+ uint64_t /*eAacProfile*/) {
+ return false ;
+}
+
+bool AVUtils::mapAACProfileToAudioFormat(const sp<AMessage> &, audio_format_t &,
+ uint64_t /*eAacProfile*/) {
+ return false ;
+}
+
+bool AVUtils::isEnhancedExtension(const char *) {
+ return false;
+}
+
+bool AVUtils::HEVCMuxer::reassembleHEVCCSD(const AString &/*mime*/, sp<ABuffer> /*csd0*/, sp<MetaData> &/*meta*/) {
+ return false;
+}
+
+void AVUtils::HEVCMuxer::writeHEVCFtypBox(MPEG4Writer * /*writer*/) {
+ return;
+}
+
+status_t AVUtils::HEVCMuxer::makeHEVCCodecSpecificData(const uint8_t * /*data*/,
+ size_t /*size*/, void ** /*codecSpecificData*/,
+ size_t * /*codecSpecificDataSize*/) {
+ return UNKNOWN_ERROR;
+}
+
+const char *AVUtils::HEVCMuxer::getFourCCForMime(const char * /*mime*/) {
+ return NULL;
+}
+
+void AVUtils::HEVCMuxer::writeHvccBox(MPEG4Writer * /*writer*/,
+ void * /*codecSpecificData*/, size_t /*codecSpecificDataSize*/,
+ bool /*useNalLengthFour*/) {
+ return;
+}
+
+bool AVUtils::HEVCMuxer::isVideoHEVC(const char * /*mime*/) {
+ return false;
+}
+
+void AVUtils::HEVCMuxer::getHEVCCodecSpecificDataFromInputFormatIfPossible(
+ sp<MetaData> /*meta*/, void ** /*codecSpecificData*/,
+ size_t * /*codecSpecificDataSize*/, bool * /*gotAllCodecSpecificData*/) {
+ return;
+}
+
+bool AVUtils::isAudioMuxFormatSupported(const char *) {
+ return true;
+}
+
+void AVUtils::cacheCaptureBuffers(sp<ICamera>, video_encoder) {
+ return;
+}
+
+const char *AVUtils::getCustomCodecsLocation() {
+ return "/etc/media_codecs.xml";
+}
+
+void AVUtils::setIntraPeriod(
+ int, int, const sp<IOMX>,
+ IOMX::node_id) {
+ return;
+}
+
+// ----- NO TRESSPASSING BEYOND THIS LINE ------
+AVUtils::AVUtils() {}
+
+AVUtils::~AVUtils() {}
+
+//static
+AVUtils *AVUtils::sInst =
+ ExtensionsLoader<AVUtils>::createInstance("createExtendedUtils");
+
+} //namespace android
+
diff --git a/media/libavextensions/stagefright/ExtendedMediaDefs.cpp b/media/libavextensions/stagefright/ExtendedMediaDefs.cpp
new file mode 100644
index 0000000..cf2683c
--- /dev/null
+++ b/media/libavextensions/stagefright/ExtendedMediaDefs.cpp
@@ -0,0 +1,68 @@
+/*Copyright (c) 2012 - 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stagefright/ExtendedMediaDefs.h>
+
+namespace android {
+
+const char *MEDIA_MIMETYPE_AUDIO_EVRC = "audio/evrc";
+const char *MEDIA_MIMETYPE_VIDEO_WMV = "video/x-ms-wmv";
+const char *MEDIA_MIMETYPE_VIDEO_WMV_VC1 = "video/wvc1";
+const char *MEDIA_MIMETYPE_AUDIO_WMA = "audio/x-ms-wma";
+const char *MEDIA_MIMETYPE_AUDIO_WMA_PRO = "audio/x-ms-wma-pro";
+const char *MEDIA_MIMETYPE_AUDIO_WMA_LOSSLESS = "audio/x-ms-wma-lossless";
+const char *MEDIA_MIMETYPE_CONTAINER_ASF = "video/x-ms-asf";
+const char *MEDIA_MIMETYPE_VIDEO_DIVX = "video/divx";
+const char *MEDIA_MIMETYPE_CONTAINER_AAC = "audio/aac";
+const char *MEDIA_MIMETYPE_CONTAINER_QCP = "audio/vnd.qcelp";
+const char *MEDIA_MIMETYPE_VIDEO_DIVX311 = "video/divx311";
+const char *MEDIA_MIMETYPE_VIDEO_DIVX4 = "video/divx4";
+const char *MEDIA_MIMETYPE_CONTAINER_MPEG2 = "video/mp2";
+const char *MEDIA_MIMETYPE_CONTAINER_3G2 = "video/3g2";
+const char *MEDIA_MIMETYPE_AUDIO_DTS = "audio/dts";
+const char *MEDIA_MIMETYPE_AUDIO_DTS_LBR = "audio/dts-lbr";
+const char *MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS = "audio/amr-wb-plus";
+const char *MEDIA_MIMETYPE_AUDIO_AIFF = "audio/x-aiff";
+const char *MEDIA_MIMETYPE_AUDIO_ALAC = "audio/alac";
+const char *MEDIA_MIMETYPE_AUDIO_APE = "audio/x-ape";
+const char *MEDIA_MIMETYPE_CONTAINER_QCAMR_NB = "audio/qc-amr";
+const char *MEDIA_MIMETYPE_CONTAINER_QCAMR_WB = "audio/qc-amr-wb";
+const char *MEDIA_MIMETYPE_CONTAINER_QCMPEG = "audio/qc-mpeg";
+const char *MEDIA_MIMETYPE_CONTAINER_QCWAV = "audio/qc-wav";
+const char *MEDIA_MIMETYPE_CONTAINER_QCMPEG2TS = "video/qc-mp2ts";
+const char *MEDIA_MIMETYPE_CONTAINER_QCMPEG2PS = "video/qc-mp2ps";
+const char *MEDIA_MIMETYPE_CONTAINER_QCMPEG4 = "video/qc-mp4";
+const char *MEDIA_MIMETYPE_CONTAINER_QCMATROSKA = "video/qc-matroska";
+const char *MEDIA_MIMETYPE_CONTAINER_QCOGG = "video/qc-ogg";
+const char *MEDIA_MIMETYPE_CONTAINER_QCFLV = "video/qc-flv";
+const char *MEDIA_MIMETYPE_VIDEO_VPX = "video/x-vnd.on2.vp8"; //backward compatibility
+const char *MEDIA_MIMETYPE_CONTAINER_QTIFLAC = "audio/qti-flac";
+const char *MEDIA_MIMETYPE_VIDEO_MPEG4_DP = "video/mp4v-esdp";
+
+} // namespace android
diff --git a/media/libeffects/downmix/EffectDownmix.c b/media/libeffects/downmix/EffectDownmix.c
index 4a41037..18059b2 100644
--- a/media/libeffects/downmix/EffectDownmix.c
+++ b/media/libeffects/downmix/EffectDownmix.c
@@ -624,9 +624,12 @@ int Downmix_Configure(downmix_module_t *pDwmModule, effect_config_t *pConfig, bo
pDownmixer->apply_volume_correction = false;
pDownmixer->input_channel_count = 8; // matches default input of AUDIO_CHANNEL_OUT_7POINT1
} else {
- // when configuring the effect, do not allow a blank channel mask
- if (pConfig->inputCfg.channels == 0) {
- ALOGE("Downmix_Configure error: input channel mask can't be 0");
+ // when configuring the effect, do not allow a blank or unsupported channel mask
+ if ((pConfig->inputCfg.channels == 0) ||
+ (Downmix_foldGeneric(pConfig->inputCfg.channels,
+ NULL, NULL, 0, false) == false)) {
+ ALOGE("Downmix_Configure error: input channel mask(0x%x) not supported",
+ pConfig->inputCfg.channels);
return -EINVAL;
}
pDownmixer->input_channel_count =
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index af904a6..e01c414 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -29,6 +29,7 @@
#include "EffectBundle.h"
#include "math.h"
+#include <media/stagefright/foundation/ADebug.h>
// effect_handle_t interface implementation for bass boost
extern "C" const struct effect_interface_s gLvmEffectInterface;
@@ -226,7 +227,7 @@ extern "C" int EffectCreate(const effect_uuid_t *uuid,
pContext->pBundledContext->bVirtualizerTempDisabled = LVM_FALSE;
pContext->pBundledContext->nOutputDevice = AUDIO_DEVICE_NONE;
pContext->pBundledContext->nVirtualizerForcedDevice = AUDIO_DEVICE_NONE;
- pContext->pBundledContext->NumberEffectsEnabled = 0;
+ pContext->pBundledContext->EffectsBitMap = 0;
pContext->pBundledContext->NumberEffectsCalled = 0;
pContext->pBundledContext->firstVolume = LVM_TRUE;
pContext->pBundledContext->volume = 0;
@@ -366,28 +367,28 @@ extern "C" int EffectRelease(effect_handle_t handle){
ALOGV("\tEffectRelease LVM_BASS_BOOST Clearing global intstantiated flag");
pSessionContext->bBassInstantiated = LVM_FALSE;
if(pContext->pBundledContext->SamplesToExitCountBb > 0){
- pContext->pBundledContext->NumberEffectsEnabled--;
+ pContext->pBundledContext->EffectsBitMap &= ~(1 << LVM_BASS_BOOST);
}
pContext->pBundledContext->SamplesToExitCountBb = 0;
} else if(pContext->EffectType == LVM_VIRTUALIZER) {
ALOGV("\tEffectRelease LVM_VIRTUALIZER Clearing global intstantiated flag");
pSessionContext->bVirtualizerInstantiated = LVM_FALSE;
if(pContext->pBundledContext->SamplesToExitCountVirt > 0){
- pContext->pBundledContext->NumberEffectsEnabled--;
+ pContext->pBundledContext->EffectsBitMap &= ~(1 << LVM_VIRTUALIZER);
}
pContext->pBundledContext->SamplesToExitCountVirt = 0;
} else if(pContext->EffectType == LVM_EQUALIZER) {
ALOGV("\tEffectRelease LVM_EQUALIZER Clearing global intstantiated flag");
pSessionContext->bEqualizerInstantiated =LVM_FALSE;
if(pContext->pBundledContext->SamplesToExitCountEq > 0){
- pContext->pBundledContext->NumberEffectsEnabled--;
+ pContext->pBundledContext->EffectsBitMap &= ~(1 << LVM_EQUALIZER);
}
pContext->pBundledContext->SamplesToExitCountEq = 0;
} else if(pContext->EffectType == LVM_VOLUME) {
ALOGV("\tEffectRelease LVM_VOLUME Clearing global intstantiated flag");
pSessionContext->bVolumeInstantiated = LVM_FALSE;
if (pContext->pBundledContext->bVolumeEnabled == LVM_TRUE){
- pContext->pBundledContext->NumberEffectsEnabled--;
+ pContext->pBundledContext->EffectsBitMap &= ~(1 << LVM_VOLUME);
}
} else {
ALOGV("\tLVM_ERROR : EffectRelease : Unsupported effect\n\n\n\n\n\n\n");
@@ -563,6 +564,7 @@ int LvmBundle_init(EffectContext *pContext){
for (int i=0; i<LVM_NR_MEMORY_REGIONS; i++){
if (MemTab.Region[i].Size != 0){
MemTab.Region[i].pBaseAddress = malloc(MemTab.Region[i].Size);
+ CHECK(MemTab.Region[i].pBaseAddress != NULL);
if (MemTab.Region[i].pBaseAddress == LVM_NULL){
ALOGV("\tLVM_ERROR :LvmBundle_init CreateInstance Failed to allocate %" PRIu32
@@ -729,6 +731,7 @@ int LvmBundle_process(LVM_INT16 *pIn,
}
pContext->pBundledContext->workBuffer =
(LVM_INT16 *)malloc(frameCount * sizeof(LVM_INT16) * 2);
+ CHECK(pContext->pBundledContext->workBuffer != NULL);
pContext->pBundledContext->frameCount = frameCount;
}
pOutTmp = pContext->pBundledContext->workBuffer;
@@ -2753,7 +2756,7 @@ int Effect_setEnabled(EffectContext *pContext, bool enabled)
return -EINVAL;
}
if(pContext->pBundledContext->SamplesToExitCountBb <= 0){
- pContext->pBundledContext->NumberEffectsEnabled++;
+ pContext->pBundledContext->EffectsBitMap |= (1 << LVM_BASS_BOOST);
}
pContext->pBundledContext->SamplesToExitCountBb =
(LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*0.1);
@@ -2766,7 +2769,7 @@ int Effect_setEnabled(EffectContext *pContext, bool enabled)
return -EINVAL;
}
if(pContext->pBundledContext->SamplesToExitCountEq <= 0){
- pContext->pBundledContext->NumberEffectsEnabled++;
+ pContext->pBundledContext->EffectsBitMap |= (1 << LVM_EQUALIZER);
}
pContext->pBundledContext->SamplesToExitCountEq =
(LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*0.1);
@@ -2778,7 +2781,7 @@ int Effect_setEnabled(EffectContext *pContext, bool enabled)
return -EINVAL;
}
if(pContext->pBundledContext->SamplesToExitCountVirt <= 0){
- pContext->pBundledContext->NumberEffectsEnabled++;
+ pContext->pBundledContext->EffectsBitMap |= (1 << LVM_VIRTUALIZER);
}
pContext->pBundledContext->SamplesToExitCountVirt =
(LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*0.1);
@@ -2790,7 +2793,7 @@ int Effect_setEnabled(EffectContext *pContext, bool enabled)
ALOGV("\tEffect_setEnabled() LVM_VOLUME is already enabled");
return -EINVAL;
}
- pContext->pBundledContext->NumberEffectsEnabled++;
+ pContext->pBundledContext->EffectsBitMap |= (1 << LVM_VOLUME);
pContext->pBundledContext->bVolumeEnabled = LVM_TRUE;
break;
default:
@@ -2807,6 +2810,9 @@ int Effect_setEnabled(EffectContext *pContext, bool enabled)
ALOGV("\tEffect_setEnabled() LVM_BASS_BOOST is already disabled");
return -EINVAL;
}
+ if(pContext->pBundledContext->SamplesToExitCountBb <= 0) {
+ pContext->pBundledContext->EffectsBitMap &= ~(1 << LVM_BASS_BOOST);
+ }
pContext->pBundledContext->bBassEnabled = LVM_FALSE;
break;
case LVM_EQUALIZER:
@@ -2814,6 +2820,9 @@ int Effect_setEnabled(EffectContext *pContext, bool enabled)
ALOGV("\tEffect_setEnabled() LVM_EQUALIZER is already disabled");
return -EINVAL;
}
+ if(pContext->pBundledContext->SamplesToExitCountEq <= 0) {
+ pContext->pBundledContext->EffectsBitMap &= ~(1 << LVM_EQUALIZER);
+ }
pContext->pBundledContext->bEqualizerEnabled = LVM_FALSE;
break;
case LVM_VIRTUALIZER:
@@ -2821,6 +2830,9 @@ int Effect_setEnabled(EffectContext *pContext, bool enabled)
ALOGV("\tEffect_setEnabled() LVM_VIRTUALIZER is already disabled");
return -EINVAL;
}
+ if(pContext->pBundledContext->SamplesToExitCountVirt <= 0) {
+ pContext->pBundledContext->EffectsBitMap &= ~(1 << LVM_VIRTUALIZER);
+ }
pContext->pBundledContext->bVirtualizerEnabled = LVM_FALSE;
break;
case LVM_VOLUME:
@@ -2828,6 +2840,7 @@ int Effect_setEnabled(EffectContext *pContext, bool enabled)
ALOGV("\tEffect_setEnabled() LVM_VOLUME is already disabled");
return -EINVAL;
}
+ pContext->pBundledContext->EffectsBitMap &= ~(1 << LVM_VOLUME);
pContext->pBundledContext->bVolumeEnabled = LVM_FALSE;
break;
default:
@@ -2877,7 +2890,7 @@ int Effect_process(effect_handle_t self,
LVM_INT16 *out = (LVM_INT16 *)outBuffer->raw;
//ALOGV("\tEffect_process Start : Enabled = %d Called = %d (%8d %8d %8d)",
-//pContext->pBundledContext->NumberEffectsEnabled,pContext->pBundledContext->NumberEffectsCalled,
+//popcount(pContext->pBundledContext->EffectsBitMap), pContext->pBundledContext->NumberEffectsCalled,
// pContext->pBundledContext->SamplesToExitCountBb,
// pContext->pBundledContext->SamplesToExitCountVirt,
// pContext->pBundledContext->SamplesToExitCountEq);
@@ -2911,7 +2924,7 @@ int Effect_process(effect_handle_t self,
}
if(pContext->pBundledContext->SamplesToExitCountBb <= 0) {
status = -ENODATA;
- pContext->pBundledContext->NumberEffectsEnabled--;
+ pContext->pBundledContext->EffectsBitMap &= ~(1 << LVM_BASS_BOOST);
ALOGV("\tEffect_process() this is the last frame for LVM_BASS_BOOST");
}
}
@@ -2919,7 +2932,7 @@ int Effect_process(effect_handle_t self,
(pContext->EffectType == LVM_VOLUME)){
//ALOGV("\tEffect_process() LVM_VOLUME Effect is not enabled");
status = -ENODATA;
- pContext->pBundledContext->NumberEffectsEnabled--;
+ pContext->pBundledContext->EffectsBitMap &= ~(1 << LVM_VOLUME);
}
if ((pContext->pBundledContext->bEqualizerEnabled == LVM_FALSE)&&
(pContext->EffectType == LVM_EQUALIZER)){
@@ -2931,7 +2944,7 @@ int Effect_process(effect_handle_t self,
}
if(pContext->pBundledContext->SamplesToExitCountEq <= 0) {
status = -ENODATA;
- pContext->pBundledContext->NumberEffectsEnabled--;
+ pContext->pBundledContext->EffectsBitMap &= ~(1 << LVM_EQUALIZER);
ALOGV("\tEffect_process() this is the last frame for LVM_EQUALIZER");
}
}
@@ -2945,7 +2958,7 @@ int Effect_process(effect_handle_t self,
}
if(pContext->pBundledContext->SamplesToExitCountVirt <= 0) {
status = -ENODATA;
- pContext->pBundledContext->NumberEffectsEnabled--;
+ pContext->pBundledContext->EffectsBitMap &= ~(1 << LVM_VIRTUALIZER);
ALOGV("\tEffect_process() this is the last frame for LVM_VIRTUALIZER");
}
}
@@ -2955,9 +2968,9 @@ int Effect_process(effect_handle_t self,
}
if(pContext->pBundledContext->NumberEffectsCalled ==
- pContext->pBundledContext->NumberEffectsEnabled){
+ popcount(pContext->pBundledContext->EffectsBitMap)){
//ALOGV("\tEffect_process Calling process with %d effects enabled, %d called: Effect %d",
- //pContext->pBundledContext->NumberEffectsEnabled,
+ //popcount(pContext->pBundledContext->EffectsBitMap),
//pContext->pBundledContext->NumberEffectsCalled, pContext->EffectType);
if(status == -ENODATA){
@@ -2976,7 +2989,7 @@ int Effect_process(effect_handle_t self,
}
} else {
//ALOGV("\tEffect_process Not Calling process with %d effects enabled, %d called: Effect %d",
- //pContext->pBundledContext->NumberEffectsEnabled,
+ //popcount(pContext->pBundledContext->EffectsBitMap),
//pContext->pBundledContext->NumberEffectsCalled, pContext->EffectType);
// 2 is for stereo input
if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
@@ -3028,9 +3041,9 @@ int Effect_command(effect_handle_t self,
// called the number of effect called could be greater
// pContext->pBundledContext->NumberEffectsCalled = 0;
- //ALOGV("\tEffect_command NumberEffectsCalled = %d, NumberEffectsEnabled = %d",
- // pContext->pBundledContext->NumberEffectsCalled,
- // pContext->pBundledContext->NumberEffectsEnabled);
+ //ALOGV("\tEffect_command: Enabled = %d Called = %d",
+ // popcount(pContext->pBundledContext->EffectsBitMap),
+ // pContext->pBundledContext->NumberEffectsCalled);
switch (cmdCode){
case EFFECT_CMD_INIT:
@@ -3311,7 +3324,7 @@ int Effect_command(effect_handle_t self,
(device == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)){
ALOGV("\tEFFECT_CMD_SET_DEVICE device is invalid for LVM_BASS_BOOST %d",
*(int32_t *)pCmdData);
- ALOGV("\tEFFECT_CMD_SET_DEVICE temporary disable LVM_BAS_BOOST");
+ ALOGV("\tEFFECT_CMD_SET_DEVICE temporary disable LVM_BASS_BOOST");
// If a device doesnt support bassboost the effect must be temporarily disabled
// the effect must still report its original state as this can only be changed
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
index 9459b87..5fa5668 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
@@ -75,8 +75,8 @@ struct BundledEffectContext{
bool bVirtualizerTempDisabled; /* Flag for effect to be re-enabled */
audio_devices_t nOutputDevice; /* Output device for the effect */
audio_devices_t nVirtualizerForcedDevice; /* Forced device virtualization mode*/
- int NumberEffectsEnabled; /* Effects in this session */
int NumberEffectsCalled; /* Effects called so far */
+ uint32_t EffectsBitMap; /* Effects enable bit mask */
bool firstVolume; /* No smoothing on first Vol change */
// Saved parameters for each effect */
// Bass Boost
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index a3c3d3c..74e4eb1 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -69,12 +69,21 @@ LOCAL_SRC_FILES:= \
StringArray.cpp \
AudioPolicy.cpp
+
+#QTI Resampler
+ifeq ($(call is-vendor-board-platform,QCOM), true)
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_EXTN_RESAMPLER)), true)
+LOCAL_CFLAGS += -DQTI_RESAMPLER
+endif
+endif
+#QTI Resampler
+
LOCAL_SHARED_LIBRARIES := \
libui liblog libcutils libutils libbinder libsonivox libicuuc libicui18n libexpat \
libcamera_client libstagefright_foundation \
libgui libdl libaudioutils libnbaio
-LOCAL_WHOLE_STATIC_LIBRARIES := libmedia_helper
+LOCAL_WHOLE_STATIC_LIBRARIES := libmedia_helper libavmediaextentions
LOCAL_MODULE:= libmedia
@@ -84,6 +93,7 @@ LOCAL_C_INCLUDES := \
$(TOP)/frameworks/native/include/media/openmax \
$(TOP)/frameworks/av/include/media/ \
$(TOP)/frameworks/av/media/libstagefright \
+ $(TOP)/frameworks/av/media/libavextensions \
$(call include-path-for, audio-effects) \
$(call include-path-for, audio-utils)
diff --git a/media/libmedia/AudioParameter.cpp b/media/libmedia/AudioParameter.cpp
index 8c8cf45..535f459 100644
--- a/media/libmedia/AudioParameter.cpp
+++ b/media/libmedia/AudioParameter.cpp
@@ -32,6 +32,7 @@ const char * const AudioParameter::keyChannels = AUDIO_PARAMETER_STREAM_CHANNELS
const char * const AudioParameter::keyFrameCount = AUDIO_PARAMETER_STREAM_FRAME_COUNT;
const char * const AudioParameter::keyInputSource = AUDIO_PARAMETER_STREAM_INPUT_SOURCE;
const char * const AudioParameter::keyScreenState = AUDIO_PARAMETER_KEY_SCREEN_STATE;
+const char * const AudioParameter::keyDevShutdown = AUDIO_PARAMETER_KEY_DEV_SHUTDOWN;
AudioParameter::AudioParameter(const String8& keyValuePairs)
{
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 011b31f..6dc52cd 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -26,6 +26,7 @@
#include <utils/Log.h>
#include <private/media/AudioTrackShared.h>
#include <media/IAudioFlinger.h>
+#include "SeempLog.h"
#define WAIT_PERIOD_MS 10
@@ -293,6 +294,7 @@ status_t AudioRecord::set(
status_t AudioRecord::start(AudioSystem::sync_event_t event, int triggerSession)
{
ALOGV("start, sync event %d trigger session %d", event, triggerSession);
+ SEEMPLOG_RECORD(89,"");
AutoMutex lock(mLock);
if (mActive) {
@@ -340,6 +342,7 @@ status_t AudioRecord::start(AudioSystem::sync_event_t event, int triggerSession)
void AudioRecord::stop()
{
+ SEEMPLOG_RECORD(90,"");
AutoMutex lock(mLock);
if (!mActive) {
return;
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index ab3d66a..946c118 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -30,6 +30,8 @@
#include <media/IAudioFlinger.h>
#include <media/AudioPolicyHelper.h>
#include <media/AudioResamplerPublic.h>
+#include "media/AVMediaExtensions.h"
+#include <cutils/properties.h>
#define WAIT_PERIOD_MS 10
#define WAIT_STREAM_END_TIMEOUT_SEC 120
@@ -167,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;
@@ -197,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,
@@ -227,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,
@@ -541,6 +546,12 @@ status_t AudioTrack::start()
// force refresh of remaining frames by processAudioBuffer() as last
// write before stop could be partial.
mRefreshRemaining = true;
+
+ // for static track, clear the old flags when start from stopped state
+ if (mSharedBuffer != 0)
+ android_atomic_and(
+ ~(CBLK_LOOP_CYCLE | CBLK_LOOP_FINAL | CBLK_BUFFER_END),
+ &mCblk->mFlags);
}
mNewPosition = mPosition + mUpdatePeriod;
int32_t flags = android_atomic_and(~CBLK_DISABLED, &mCblk->mFlags);
@@ -706,7 +717,7 @@ status_t AudioTrack::setVolume(float left, float right)
mProxy->setVolumeLR(gain_minifloat_pack(gain_from_float(left), gain_from_float(right)));
- if (isOffloaded_l()) {
+ if (isOffloaded_l() && mAudioTrack != NULL) {
mAudioTrack->signal();
}
return NO_ERROR;
@@ -846,6 +857,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;
}
@@ -1001,10 +1021,18 @@ status_t AudioTrack::getPosition(uint32_t *position)
return NO_ERROR;
}
+ if (AVMediaUtils::get()->AudioTrackIsPcmOffloaded(mFormat) &&
+ AVMediaUtils::get()->AudioTrackGetPosition(this, position) == NO_ERROR) {
+ return NO_ERROR;
+ }
+
if (mOutput != AUDIO_IO_HANDLE_NONE) {
uint32_t halFrames; // actually unused
- (void) AudioSystem::getRenderPosition(mOutput, &halFrames, &dspFrames);
- // FIXME: on getRenderPosition() error, we return OK with frame position 0.
+ status_t status = AudioSystem::getRenderPosition(mOutput, &halFrames, &dspFrames);
+ if (status != NO_ERROR) {
+ ALOGW("failed to getRenderPosition for offload session status %d", status);
+ return INVALID_OPERATION;
+ }
}
// FIXME: dspFrames may not be zero in (mState == STATE_STOPPED || mState == STATE_FLUSHED)
// due to hardware latency. We leave this behavior for now.
@@ -1129,11 +1157,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,"
@@ -1203,6 +1236,7 @@ status_t AudioTrack::createTrack_l()
frameCount = mSharedBuffer->size();
} else if (frameCount == 0) {
frameCount = mAfFrameCount;
+ frameCount = AVMediaUtils::get()->AudioTrackGetOffloadFrameCount(frameCount);
}
if (mNotificationFramesAct != frameCount) {
mNotificationFramesAct = frameCount;
@@ -1838,6 +1872,36 @@ nsecs_t AudioTrack::processAudioBuffer()
// get anchor time to account for callbacks.
const nsecs_t timeBeforeCallbacks = systemTime();
+ // perform callbacks while unlocked
+ if (newUnderrun) {
+ mCbf(EVENT_UNDERRUN, mUserData, NULL);
+ }
+ while (loopCountNotifications > 0) {
+ mCbf(EVENT_LOOP_END, mUserData, NULL);
+ --loopCountNotifications;
+ }
+ if (flags & CBLK_BUFFER_END) {
+ mCbf(EVENT_BUFFER_END, mUserData, NULL);
+ }
+ if (markerReached) {
+ mCbf(EVENT_MARKER, mUserData, &markerPosition);
+ }
+ while (newPosCount > 0) {
+ size_t temp = newPosition;
+ mCbf(EVENT_NEW_POS, mUserData, &temp);
+ newPosition += updatePeriod;
+ newPosCount--;
+ }
+
+ if (mObservedSequence != sequence) {
+ mObservedSequence = sequence;
+ mCbf(EVENT_NEW_IAUDIOTRACK, mUserData, NULL);
+ // for offloaded tracks, just wait for the upper layers to recreate the track
+ if (isOffloadedOrDirect()) {
+ return NS_INACTIVE;
+ }
+ }
+
if (waitStreamEnd) {
// FIXME: Instead of blocking in proxy->waitStreamEndDone(), Callback thread
// should wait on proxy futex and handle CBLK_STREAM_END_DONE within this function
@@ -1852,6 +1916,12 @@ nsecs_t AudioTrack::processAudioBuffer()
case NO_ERROR:
case DEAD_OBJECT:
case TIMED_OUT:
+ if (isOffloaded_l()) {
+ if (mCblk->mFlags & (CBLK_INVALID)){
+ // will trigger EVENT_STREAM_END in next iteration
+ return 0;
+ }
+ }
mCbf(EVENT_STREAM_END, mUserData, NULL);
{
AutoMutex lock(mLock);
@@ -1872,36 +1942,6 @@ nsecs_t AudioTrack::processAudioBuffer()
return 0;
}
- // perform callbacks while unlocked
- if (newUnderrun) {
- mCbf(EVENT_UNDERRUN, mUserData, NULL);
- }
- while (loopCountNotifications > 0) {
- mCbf(EVENT_LOOP_END, mUserData, NULL);
- --loopCountNotifications;
- }
- if (flags & CBLK_BUFFER_END) {
- mCbf(EVENT_BUFFER_END, mUserData, NULL);
- }
- if (markerReached) {
- mCbf(EVENT_MARKER, mUserData, &markerPosition);
- }
- while (newPosCount > 0) {
- size_t temp = newPosition;
- mCbf(EVENT_NEW_POS, mUserData, &temp);
- newPosition += updatePeriod;
- newPosCount--;
- }
-
- if (mObservedSequence != sequence) {
- mObservedSequence = sequence;
- mCbf(EVENT_NEW_IAUDIOTRACK, mUserData, NULL);
- // for offloaded tracks, just wait for the upper layers to recreate the track
- if (isOffloadedOrDirect()) {
- return NS_INACTIVE;
- }
- }
-
// if inactive, then don't run me again until re-started
if (!active) {
return NS_INACTIVE;
@@ -2232,14 +2272,21 @@ status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp)
}
}
- // The presented frame count must always lag behind the consumed frame count.
- // To avoid a race, read the presented frames first. This ensures that presented <= consumed.
- status_t status = mAudioTrack->getTimestamp(timestamp);
- if (status != NO_ERROR) {
- ALOGV_IF(status != WOULD_BLOCK, "getTimestamp error:%#x", status);
- return status;
+ status_t status = UNKNOWN_ERROR;
+ //do not call Timestamp if its PCM offloaded
+ if (!AVMediaUtils::get()->AudioTrackIsPcmOffloaded(mFormat)) {
+ // The presented frame count must always lag behind the consumed frame count.
+ // To avoid a race, read the presented frames first. This ensures that presented <= consumed.
+
+ status = mAudioTrack->getTimestamp(timestamp);
+ if (status != NO_ERROR) {
+ ALOGV_IF(status != WOULD_BLOCK, "getTimestamp error:%#x", status);
+ return status;
+ }
+
}
- if (isOffloadedOrDirect_l()) {
+
+ if (isOffloadedOrDirect_l() && !AVMediaUtils::get()->AudioTrackIsPcmOffloaded(mFormat)) {
if (isOffloaded_l() && (mState == STATE_PAUSED || mState == STATE_PAUSED_STOPPING)) {
// use cached paused position in case another offloaded track is running.
timestamp.mPosition = mPausedPosition;
@@ -2297,6 +2344,11 @@ 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) {
+ return NO_ERROR;
+ }
+
(void) updateAndGetPosition_l();
// Server consumed (mServer) and presented both use the same server time base,
// and server consumed is always >= presented.
diff --git a/media/libmedia/ICrypto.cpp b/media/libmedia/ICrypto.cpp
index a398ff7..5d822cf 100644
--- a/media/libmedia/ICrypto.cpp
+++ b/media/libmedia/ICrypto.cpp
@@ -24,6 +24,7 @@
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AString.h>
+#include <media/AVMediaExtensions.h>
namespace android {
@@ -136,6 +137,7 @@ struct BpCrypto : public BpInterface<ICrypto> {
if (secure) {
data.writeInt64(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(dstPtr)));
+ AVMediaUtils::get()->writeCustomData(&data, dstPtr);
}
remote()->transact(DECRYPT, data, &reply);
@@ -235,6 +237,7 @@ status_t BnCrypto::onTransact(
if (opaqueSize > 0) {
opaqueData = malloc(opaqueSize);
+ CHECK(opaqueData != NULL);
data.read(opaqueData, opaqueSize);
}
@@ -296,6 +299,7 @@ status_t BnCrypto::onTransact(
void *secureBufferId, *dstPtr;
if (secure) {
secureBufferId = reinterpret_cast<void *>(static_cast<uintptr_t>(data.readInt64()));
+ AVMediaUtils::get()->readCustomData(&data, &secureBufferId);
} else {
dstPtr = calloc(1, totalSize);
}
@@ -348,6 +352,8 @@ status_t BnCrypto::onTransact(
}
free(dstPtr);
dstPtr = NULL;
+ } else {
+ AVMediaUtils::get()->closeFileDescriptor(secureBufferId);
}
delete[] subSamples;
diff --git a/media/libmedia/IEffectClient.cpp b/media/libmedia/IEffectClient.cpp
index 1322e72..531f767 100644
--- a/media/libmedia/IEffectClient.cpp
+++ b/media/libmedia/IEffectClient.cpp
@@ -22,6 +22,8 @@
#include <sys/types.h>
#include <media/IEffectClient.h>
+#include <media/stagefright/foundation/ADebug.h>
+
namespace android {
enum {
@@ -117,12 +119,14 @@ status_t BnEffectClient::onTransact(
char *cmd = NULL;
if (cmdSize) {
cmd = (char *)malloc(cmdSize);
+ CHECK(cmd != NULL);
data.read(cmd, cmdSize);
}
uint32_t replySize = data.readInt32();
char *resp = NULL;
if (replySize) {
resp = (char *)malloc(replySize);
+ CHECK(resp != NULL);
data.read(resp, replySize);
}
commandExecuted(cmdCode, cmdSize, cmd, replySize, resp);
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index 5423c2a..5356494 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -22,6 +22,7 @@
#include <binder/Parcel.h>
#include <media/IOMX.h>
#include <media/stagefright/foundation/ADebug.h>
+#include <media/AVMediaExtensions.h>
namespace android {
@@ -472,6 +473,7 @@ public:
*buffer = (buffer_id)reply.readInt32();
*buffer_data = (void *)reply.readInt64();
+ AVMediaUtils::get()->readCustomData(&reply, buffer_data);
return err;
}
@@ -980,6 +982,7 @@ status_t BnOMX::onTransact(
if (err == OK) {
reply->writeInt32((int32_t)buffer);
reply->writeInt64((uintptr_t)buffer_data);
+ AVMediaUtils::get()->writeCustomData(reply, buffer_data);
}
return NO_ERROR;
diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp
index c5790fb..87ec309 100644..100755
--- a/media/libmedia/MediaProfiles.cpp
+++ b/media/libmedia/MediaProfiles.cpp
@@ -1,4 +1,6 @@
/*
+** Copyright (c) 2014, The Linux Foundation. All rights reserved.
+** Not a Contribution.
**
** Copyright 2010, The Android Open Source Project
**
@@ -37,7 +39,8 @@ MediaProfiles *MediaProfiles::sInstance = NULL;
const MediaProfiles::NameToTagMap MediaProfiles::sVideoEncoderNameMap[] = {
{"h263", VIDEO_ENCODER_H263},
{"h264", VIDEO_ENCODER_H264},
- {"m4v", VIDEO_ENCODER_MPEG_4_SP}
+ {"m4v", VIDEO_ENCODER_MPEG_4_SP},
+ {"h265", VIDEO_ENCODER_H265}
};
const MediaProfiles::NameToTagMap MediaProfiles::sAudioEncoderNameMap[] = {
@@ -45,7 +48,8 @@ const MediaProfiles::NameToTagMap MediaProfiles::sAudioEncoderNameMap[] = {
{"amrwb", AUDIO_ENCODER_AMR_WB},
{"aac", AUDIO_ENCODER_AAC},
{"heaac", AUDIO_ENCODER_HE_AAC},
- {"aaceld", AUDIO_ENCODER_AAC_ELD}
+ {"aaceld", AUDIO_ENCODER_AAC_ELD},
+ {"lpcm", AUDIO_ENCODER_LPCM},
};
const MediaProfiles::NameToTagMap MediaProfiles::sFileFormatMap[] = {
@@ -88,6 +92,15 @@ const MediaProfiles::NameToTagMap MediaProfiles::sCamcorderQualityNameMap[] = {
{"highspeed720p", CAMCORDER_QUALITY_HIGH_SPEED_720P},
{"highspeed1080p", CAMCORDER_QUALITY_HIGH_SPEED_1080P},
{"highspeed2160p", CAMCORDER_QUALITY_HIGH_SPEED_2160P},
+
+ // Vendor-specific profiles
+ {"vga", CAMCORDER_QUALITY_VGA},
+ {"4kdci", CAMCORDER_QUALITY_4KDCI},
+ {"timelapsevga", CAMCORDER_QUALITY_TIME_LAPSE_VGA},
+ {"timelapse4kdci", CAMCORDER_QUALITY_TIME_LAPSE_4KDCI},
+ {"highspeedcif", CAMCORDER_QUALITY_HIGH_SPEED_CIF},
+ {"highspeedvga", CAMCORDER_QUALITY_HIGH_SPEED_VGA},
+ {"highspeed4kdci", CAMCORDER_QUALITY_HIGH_SPEED_4KDCI},
};
#if LOG_NDEBUG
@@ -126,6 +139,8 @@ MediaProfiles::logVideoEncoderCap(const MediaProfiles::VideoEncoderCap& cap UNUS
ALOGV("frame width: min = %d and max = %d", cap.mMinFrameWidth, cap.mMaxFrameWidth);
ALOGV("frame height: min = %d and max = %d", cap.mMinFrameHeight, cap.mMaxFrameHeight);
ALOGV("frame rate: min = %d and max = %d", cap.mMinFrameRate, cap.mMaxFrameRate);
+ ALOGV("max HFR width: = %d max HFR height: = %d", cap.mMaxHFRFrameWidth, cap.mMaxHFRFrameHeight);
+ ALOGV("max HFR mode: = %d", cap.mMaxHFRMode);
}
/*static*/ void
@@ -261,10 +276,23 @@ MediaProfiles::createVideoEncoderCap(const char **atts)
const int codec = findTagForName(sVideoEncoderNameMap, nMappings, atts[1]);
CHECK(codec != -1);
+ int maxHFRWidth = 0, maxHFRHeight = 0, maxHFRMode = 0;
+ // Check if there are enough (start through end) attributes in the
+ // 0-terminated list, to include our additional HFR params. Then check
+ // if each of those match the expected names.
+ if (atts[20] && atts[21] && !strcmp("maxHFRFrameWidth", atts[20]) &&
+ atts[22] && atts[23] && !strcmp("maxHFRFrameHeight", atts[22]) &&
+ atts[24] && atts[25] && !strcmp("maxHFRMode", atts[24])) {
+ maxHFRWidth = atoi(atts[21]);
+ maxHFRHeight = atoi(atts[23]);
+ maxHFRMode = atoi(atts[25]);
+ }
+
MediaProfiles::VideoEncoderCap *cap =
new MediaProfiles::VideoEncoderCap(static_cast<video_encoder>(codec),
atoi(atts[5]), atoi(atts[7]), atoi(atts[9]), atoi(atts[11]), atoi(atts[13]),
- atoi(atts[15]), atoi(atts[17]), atoi(atts[19]));
+ atoi(atts[15]), atoi(atts[17]), atoi(atts[19]),
+ maxHFRWidth, maxHFRHeight, maxHFRMode);
logVideoEncoderCap(*cap);
return cap;
}
@@ -423,8 +451,10 @@ MediaProfiles::startElementHandler(void *userData, const char *name, const char
}
static bool isCamcorderProfile(camcorder_quality quality) {
- return quality >= CAMCORDER_QUALITY_LIST_START &&
- quality <= CAMCORDER_QUALITY_LIST_END;
+ return (quality >= CAMCORDER_QUALITY_LIST_START &&
+ quality <= CAMCORDER_QUALITY_LIST_END) ||
+ (quality >= CAMCORDER_QUALITY_VENDOR_START &&
+ quality <= CAMCORDER_QUALITY_VENDOR_END);
}
static bool isTimelapseProfile(camcorder_quality quality) {
@@ -616,14 +646,14 @@ MediaProfiles::getInstance()
MediaProfiles::createDefaultH263VideoEncoderCap()
{
return new MediaProfiles::VideoEncoderCap(
- VIDEO_ENCODER_H263, 192000, 420000, 176, 352, 144, 288, 1, 20);
+ VIDEO_ENCODER_H263, 192000, 420000, 176, 352, 144, 288, 1, 20, 0, 0, 0);
}
/*static*/ MediaProfiles::VideoEncoderCap*
MediaProfiles::createDefaultM4vVideoEncoderCap()
{
return new MediaProfiles::VideoEncoderCap(
- VIDEO_ENCODER_MPEG_4_SP, 192000, 420000, 176, 352, 144, 288, 1, 20);
+ VIDEO_ENCODER_MPEG_4_SP, 192000, 420000, 176, 352, 144, 288, 1, 20, 0, 0, 0);
}
@@ -778,6 +808,8 @@ MediaProfiles::createDefaultCamcorderProfiles(MediaProfiles *profiles)
MediaProfiles::createDefaultAudioEncoders(MediaProfiles *profiles)
{
profiles->mAudioEncoders.add(createDefaultAmrNBEncoderCap());
+ profiles->mAudioEncoders.add(createDefaultAacEncoderCap());
+ profiles->mAudioEncoders.add(createDefaultLpcmEncoderCap());
}
/*static*/ void
@@ -812,6 +844,20 @@ MediaProfiles::createDefaultAmrNBEncoderCap()
AUDIO_ENCODER_AMR_NB, 5525, 12200, 8000, 8000, 1, 1);
}
+/*static*/ MediaProfiles::AudioEncoderCap*
+MediaProfiles::createDefaultAacEncoderCap()
+{
+ return new MediaProfiles::AudioEncoderCap(
+ AUDIO_ENCODER_AAC, 64000, 156000, 8000, 48000, 1, 2);
+}
+
+/*static*/ MediaProfiles::AudioEncoderCap*
+MediaProfiles::createDefaultLpcmEncoderCap()
+{
+ return new MediaProfiles::AudioEncoderCap(
+ AUDIO_ENCODER_LPCM, 768000, 4608000, 8000, 48000, 1, 6);
+}
+
/*static*/ void
MediaProfiles::createDefaultImageEncodingQualityLevels(MediaProfiles *profiles)
{
@@ -927,6 +973,9 @@ int MediaProfiles::getVideoEncoderParamByName(const char *name, video_encoder co
if (!strcmp("enc.vid.bps.max", name)) return mVideoEncoders[index]->mMaxBitRate;
if (!strcmp("enc.vid.fps.min", name)) return mVideoEncoders[index]->mMinFrameRate;
if (!strcmp("enc.vid.fps.max", name)) return mVideoEncoders[index]->mMaxFrameRate;
+ if (!strcmp("enc.vid.hfr.width.max", name)) return mVideoEncoders[index]->mMaxHFRFrameWidth;
+ if (!strcmp("enc.vid.hfr.height.max", name)) return mVideoEncoders[index]->mMaxHFRFrameHeight;
+ if (!strcmp("enc.vid.hfr.mode.max", name)) return mVideoEncoders[index]->mMaxHFRMode;
ALOGE("The given video encoder param name %s is not found", name);
return -1;
diff --git a/media/libmedia/MediaScanner.cpp b/media/libmedia/MediaScanner.cpp
index dcbb769..dac0a9e 100644
--- a/media/libmedia/MediaScanner.cpp
+++ b/media/libmedia/MediaScanner.cpp
@@ -24,6 +24,8 @@
#include <sys/stat.h>
#include <dirent.h>
+#include <media/stagefright/foundation/ADebug.h>
+
namespace android {
MediaScanner::MediaScanner()
@@ -240,6 +242,7 @@ MediaScanResult MediaScanner::doProcessDirectoryEntry(
MediaAlbumArt *MediaAlbumArt::clone() {
size_t byte_size = this->size() + sizeof(MediaAlbumArt);
MediaAlbumArt *result = reinterpret_cast<MediaAlbumArt *>(malloc(byte_size));
+ CHECK(result != NULL);
result->mSize = this->size();
memcpy(&result->mData[0], &this->mData[0], this->size());
return result;
@@ -253,6 +256,7 @@ void MediaAlbumArt::init(MediaAlbumArt *instance, int32_t dataSize, const void *
MediaAlbumArt *MediaAlbumArt::fromData(int32_t dataSize, const void* data) {
size_t byte_size = sizeof(MediaAlbumArt) + dataSize;
MediaAlbumArt *result = reinterpret_cast<MediaAlbumArt *>(malloc(byte_size));
+ CHECK(result != NULL);
init(result, dataSize, data);
return result;
}
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index 6da5348..53b229e 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -804,6 +804,12 @@ ToneGenerator::ToneGenerator(audio_stream_type_t streamType, float volume, bool
ALOGE("Unable to marshal AudioFlinger");
return;
}
+
+ if (mSamplingRate > 48000) {
+ ALOGW("mSamplingRate %d . limit to 48k", mSamplingRate);
+ mSamplingRate = 48000;
+ }
+
mThreadCanCallJava = threadCanCallJava;
mStreamType = streamType;
mVolume = volume;
@@ -1046,7 +1052,7 @@ bool ToneGenerator::initAudioTrack() {
ALOGV("Create Track: %p", mpAudioTrack.get());
mpAudioTrack->set(mStreamType,
- 0, // sampleRate
+ mSamplingRate,
AUDIO_FORMAT_PCM_16_BIT,
AUDIO_CHANNEL_OUT_MONO,
0, // frameCount
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 502ab2d..6c0606c 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -395,6 +395,10 @@ bool MediaPlayer::isPlaying()
ALOGE("internal/external state mismatch corrected");
mCurrentState = MEDIA_PLAYER_STARTED;
}
+ if ((mCurrentState & MEDIA_PLAYER_PLAYBACK_COMPLETE) && temp) {
+ ALOGE("internal/external state mismatch corrected");
+ mCurrentState = MEDIA_PLAYER_STARTED;
+ }
return temp;
}
ALOGV("isPlaying: no active player");
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index 4d1b587..c4c5b47 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -18,7 +18,6 @@ LOCAL_SRC_FILES:= \
MetadataRetrieverClient.cpp \
RemoteDisplay.cpp \
SharedLibrary.cpp \
- StagefrightPlayer.cpp \
StagefrightRecorder.cpp \
TestPlayerStub.cpp \
@@ -46,6 +45,9 @@ LOCAL_STATIC_LIBRARIES := \
libstagefright_nuplayer \
libstagefright_rtsp \
+LOCAL_WHOLE_STATIC_LIBRARIES := \
+ libavmediaserviceextensions \
+
LOCAL_C_INCLUDES := \
$(TOP)/frameworks/av/media/libstagefright/include \
$(TOP)/frameworks/av/media/libstagefright/rtsp \
@@ -53,13 +55,14 @@ LOCAL_C_INCLUDES := \
$(TOP)/frameworks/av/media/libstagefright/webm \
$(TOP)/frameworks/native/include/media/openmax \
$(TOP)/external/tremolo/Tremolo \
+ $(TOP)/frameworks/av/media/libavextensions \
LOCAL_CFLAGS += -Werror -Wno-error=deprecated-declarations -Wall
LOCAL_CLANG := true
LOCAL_MODULE:= libmediaplayerservice
-LOCAL_32_BIT_ONLY := true
+#LOCAL_32_BIT_ONLY := true
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
index d5d12f7..f0afc5a 100644
--- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
+++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
@@ -31,8 +31,8 @@
#include "MediaPlayerFactory.h"
#include "TestPlayerStub.h"
-#include "StagefrightPlayer.h"
#include "nuplayer/NuPlayerDriver.h"
+#include <mediaplayerservice/AVMediaServiceExtensions.h>
namespace android {
@@ -64,12 +64,6 @@ status_t MediaPlayerFactory::registerFactory_l(IFactory* factory,
}
static player_type getDefaultPlayerType() {
- char value[PROPERTY_VALUE_MAX];
- if (property_get("media.stagefright.use-awesome", value, NULL)
- && (!strcmp("1", value) || !strcasecmp("true", value))) {
- return STAGEFRIGHT_PLAYER;
- }
-
return NU_PLAYER;
}
@@ -87,7 +81,7 @@ void MediaPlayerFactory::unregisterFactory(player_type type) {
#define GET_PLAYER_TYPE_IMPL(a...) \
Mutex::Autolock lock_(&sLock); \
\
- player_type ret = STAGEFRIGHT_PLAYER; \
+ player_type ret = NU_PLAYER; \
float bestScore = 0.0; \
\
for (size_t i = 0; i < sFactoryMap.size(); ++i) { \
@@ -176,63 +170,6 @@ sp<MediaPlayerBase> MediaPlayerFactory::createPlayer(
* *
*****************************************************************************/
-class StagefrightPlayerFactory :
- public MediaPlayerFactory::IFactory {
- public:
- virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
- int fd,
- int64_t offset,
- int64_t length,
- float /*curScore*/) {
- if (legacyDrm()) {
- sp<DataSource> source = new FileSource(dup(fd), offset, length);
- String8 mimeType;
- float confidence;
- if (SniffWVM(source, &mimeType, &confidence, NULL /* format */)) {
- return 1.0;
- }
- }
-
- if (getDefaultPlayerType() == STAGEFRIGHT_PLAYER) {
- char buf[20];
- lseek(fd, offset, SEEK_SET);
- read(fd, buf, sizeof(buf));
- lseek(fd, offset, SEEK_SET);
-
- uint32_t ident = *((uint32_t*)buf);
-
- // Ogg vorbis?
- if (ident == 0x5367674f) // 'OggS'
- return 1.0;
- }
-
- return 0.0;
- }
-
- virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
- const char* url,
- float /*curScore*/) {
- if (legacyDrm() && !strncasecmp("widevine://", url, 11)) {
- return 1.0;
- }
- return 0.0;
- }
-
- virtual sp<MediaPlayerBase> createPlayer(pid_t /* pid */) {
- ALOGV(" create StagefrightPlayer");
- return new StagefrightPlayer();
- }
- private:
- bool legacyDrm() {
- char value[PROPERTY_VALUE_MAX];
- if (property_get("persist.sys.media.legacy-drm", value, NULL)
- && (!strcmp("1", value) || !strcasecmp("true", value))) {
- return true;
- }
- return false;
- }
-};
-
class NuPlayerFactory : public MediaPlayerFactory::IFactory {
public:
virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
@@ -305,14 +242,20 @@ class TestPlayerFactory : public MediaPlayerFactory::IFactory {
};
void MediaPlayerFactory::registerBuiltinFactories() {
+
+ MediaPlayerFactory::IFactory* pCustomFactory = NULL;
Mutex::Autolock lock_(&sLock);
if (sInitComplete)
return;
- registerFactory_l(new StagefrightPlayerFactory(), STAGEFRIGHT_PLAYER);
registerFactory_l(new NuPlayerFactory(), NU_PLAYER);
registerFactory_l(new TestPlayerFactory(), TEST_PLAYER);
+ AVMediaServiceUtils::get()->getDashPlayerFactory(pCustomFactory, DASH_PLAYER);
+ if(pCustomFactory != NULL) {
+ ALOGV("Registering DASH_PLAYER");
+ registerFactory_l(pCustomFactory, DASH_PLAYER);
+ }
sInitComplete = true;
}
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index bcfd83a..6e104a4 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -21,6 +21,7 @@
#define LOG_TAG "MediaPlayerService"
#include <utils/Log.h>
+#include <inttypes.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
@@ -73,7 +74,6 @@
#include "MediaPlayerFactory.h"
#include "TestPlayerStub.h"
-#include "StagefrightPlayer.h"
#include "nuplayer/NuPlayerDriver.h"
#include <OMX.h>
@@ -148,7 +148,7 @@ bool unmarshallFilter(const Parcel& p,
if (p.dataAvail() < size)
{
- ALOGE("Filter too short expected %d but got %d", size, p.dataAvail());
+ ALOGE("Filter too short expected %zu but got %zu", size, p.dataAvail());
*status = NOT_ENOUGH_DATA;
return false;
}
@@ -733,7 +733,7 @@ status_t MediaPlayerService::Client::setDataSource(
status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length)
{
- ALOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length);
+ ALOGV("setDataSource fd=%d, offset=%" PRId64 ", length=%" PRId64 "", fd, offset, length);
struct stat sb;
int ret = fstat(fd, &sb);
if (ret != 0) {
@@ -741,11 +741,11 @@ status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64
return UNKNOWN_ERROR;
}
- ALOGV("st_dev = %llu", static_cast<uint64_t>(sb.st_dev));
+ ALOGV("st_dev = %" PRIu64 "", static_cast<uint64_t>(sb.st_dev));
ALOGV("st_mode = %u", sb.st_mode);
ALOGV("st_uid = %lu", static_cast<unsigned long>(sb.st_uid));
ALOGV("st_gid = %lu", static_cast<unsigned long>(sb.st_gid));
- ALOGV("st_size = %llu", sb.st_size);
+ ALOGV("st_size = %" PRId64 "", sb.st_size);
if (offset >= sb.st_size) {
ALOGE("offset error");
@@ -754,7 +754,7 @@ status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64
}
if (offset + length > sb.st_size) {
length = sb.st_size - offset;
- ALOGV("calculated length = %lld", length);
+ ALOGV("calculated length = %" PRId64 "", length);
}
player_type playerType = MediaPlayerFactory::getPlayerType(this,
@@ -1249,8 +1249,17 @@ void MediaPlayerService::Client::notify(
if (msg == MEDIA_PLAYBACK_COMPLETE && client->mNextClient != NULL) {
if (client->mAudioOutput != NULL)
client->mAudioOutput->switchToNextOutput();
- client->mNextClient->start();
- client->mNextClient->mClient->notify(MEDIA_INFO, MEDIA_INFO_STARTED_AS_NEXT, 0, obj);
+ ALOGD("gapless:current track played back");
+ ALOGD("gapless:try to do a gapless switch to next track");
+ status_t ret;
+ ret = client->mNextClient->start();
+ if (ret == NO_ERROR) {
+ client->mNextClient->mClient->notify(MEDIA_INFO,
+ MEDIA_INFO_STARTED_AS_NEXT, 0, obj);
+ } else {
+ client->mClient->notify(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN , 0, obj);
+ ALOGW("gapless:start playback for next track failed");
+ }
}
}
@@ -1366,6 +1375,7 @@ MediaPlayerService::AudioOutput::AudioOutput(int sessionId, int uid, int pid,
}
setMinBufferCount();
+ mBitWidth = 16;
}
MediaPlayerService::AudioOutput::~AudioOutput()
@@ -1622,6 +1632,15 @@ status_t MediaPlayerService::AudioOutput::open(
} else if (mRecycledTrack->format() != format) {
reuse = false;
}
+
+ if (bothOffloaded) {
+ if (mBitWidth != offloadInfo->bit_width) {
+ ALOGV("output bit width differs %d v/s %d",
+ mBitWidth, offloadInfo->bit_width);
+ reuse = false;
+ }
+ }
+
} else {
ALOGV("no track available to recycle");
}
@@ -1702,7 +1721,7 @@ status_t MediaPlayerService::AudioOutput::open(
if (!bothOffloaded) {
if (mRecycledTrack->frameCount() != t->frameCount()) {
- ALOGV("framecount differs: %u/%u frames",
+ ALOGV("framecount differs: %zu/%zu frames",
mRecycledTrack->frameCount(), t->frameCount());
reuse = false;
}
@@ -1737,6 +1756,13 @@ status_t MediaPlayerService::AudioOutput::open(
mFlags = flags;
mMsecsPerFrame = 1E3f / (mPlaybackRate.mSpeed * sampleRate);
mFrameSize = t->frameSize();
+
+ if (offloadInfo) {
+ mBitWidth = offloadInfo->bit_width;
+ } else {
+ mBitWidth = 16;
+ }
+
uint32_t pos;
if (t->getPosition(&pos) == OK) {
mBytesWritten = uint64_t(pos) * mFrameSize;
@@ -1837,6 +1863,7 @@ void MediaPlayerService::AudioOutput::switchToNextOutput() {
mNextOutput->mBytesWritten = mBytesWritten;
mNextOutput->mFlags = mFlags;
mNextOutput->mFrameSize = mFrameSize;
+ mNextOutput->mBitWidth = mBitWidth;
close_l();
mCallbackData = NULL; // destruction handled by mNextOutput
} else {
@@ -2101,6 +2128,7 @@ bool CallbackThread::threadLoop() {
if (mBuffer == NULL) {
mBufferSize = sink->bufferSize();
mBuffer = malloc(mBufferSize);
+ CHECK(mBuffer != NULL);
}
size_t actualSize =
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 60d4617..748b25f 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -160,6 +160,7 @@ class MediaPlayerService : public BnMediaPlayerService
// static variables below not protected by mutex
static bool mIsOnEmulator;
static int mMinBufferCount; // 12 for emulator; otherwise 4
+ uint16_t mBitWidth;
// CallbackData is what is passed to the AudioTrack as the "user" data.
// We need to be able to target this to a different Output on the fly,
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index f761dec..6f242e5 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -18,6 +18,7 @@
#define LOG_TAG "MediaRecorderService"
#include <utils/Log.h>
+#include <inttypes.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
@@ -39,6 +40,7 @@
#include "StagefrightRecorder.h"
#include <gui/IGraphicBufferProducer.h>
+#include "mediaplayerservice/AVMediaServiceExtensions.h"
namespace android {
@@ -166,7 +168,7 @@ status_t MediaRecorderClient::setAudioEncoder(int ae)
status_t MediaRecorderClient::setOutputFile(int fd, int64_t offset, int64_t length)
{
- ALOGV("setOutputFile(%d, %lld, %lld)", fd, offset, length);
+ ALOGV("setOutputFile(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
Mutex::Autolock lock(mLock);
if (mRecorder == NULL) {
ALOGE("recorder is not initialized");
@@ -305,7 +307,7 @@ MediaRecorderClient::MediaRecorderClient(const sp<MediaPlayerService>& service,
{
ALOGV("Client constructor");
mPid = pid;
- mRecorder = new StagefrightRecorder(opPackageName);
+ mRecorder = AVMediaServiceFactory::get()->createStagefrightRecorder(opPackageName);
mMediaPlayerService = service;
}
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index a5a1fa5..894a855 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -19,6 +19,7 @@
#define LOG_TAG "MetadataRetrieverClient"
#include <utils/Log.h>
+#include <inttypes.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
@@ -84,7 +85,6 @@ static sp<MediaMetadataRetrieverBase> createRetriever(player_type playerType)
{
sp<MediaMetadataRetrieverBase> p;
switch (playerType) {
- case STAGEFRIGHT_PLAYER:
case NU_PLAYER:
{
p = new StagefrightMetadataRetriever;
@@ -133,7 +133,7 @@ status_t MetadataRetrieverClient::setDataSource(
status_t MetadataRetrieverClient::setDataSource(int fd, int64_t offset, int64_t length)
{
- ALOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length);
+ ALOGV("setDataSource fd=%d, offset=%" PRId64 ", length=%" PRId64 "", fd, offset, length);
Mutex::Autolock lock(mLock);
struct stat sb;
int ret = fstat(fd, &sb);
@@ -141,20 +141,20 @@ status_t MetadataRetrieverClient::setDataSource(int fd, int64_t offset, int64_t
ALOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
return BAD_VALUE;
}
- ALOGV("st_dev = %llu", static_cast<uint64_t>(sb.st_dev));
+ ALOGV("st_dev = %" PRIu64 "", static_cast<uint64_t>(sb.st_dev));
ALOGV("st_mode = %u", sb.st_mode);
ALOGV("st_uid = %lu", static_cast<unsigned long>(sb.st_uid));
ALOGV("st_gid = %lu", static_cast<unsigned long>(sb.st_gid));
- ALOGV("st_size = %llu", sb.st_size);
+ ALOGV("st_size = %" PRIu64 "", sb.st_size);
if (offset >= sb.st_size) {
- ALOGE("offset (%lld) bigger than file size (%llu)", offset, sb.st_size);
+ ALOGE("offset (%" PRId64 ") bigger than file size (%" PRIu64 ")", offset, sb.st_size);
::close(fd);
return BAD_VALUE;
}
if (offset + length > sb.st_size) {
length = sb.st_size - offset;
- ALOGV("calculated length = %lld", length);
+ ALOGV("calculated length = %" PRId64 "", length);
}
player_type playerType =
@@ -195,7 +195,7 @@ Mutex MetadataRetrieverClient::sLock;
sp<IMemory> MetadataRetrieverClient::getFrameAtTime(int64_t timeUs, int option)
{
- ALOGV("getFrameAtTime: time(%lld us) option(%d)", timeUs, option);
+ ALOGV("getFrameAtTime: time(%" PRId64 " us) option(%d)", timeUs, option);
Mutex::Autolock lock(mLock);
Mutex::Autolock glock(sLock);
mThumbnail.clear();
@@ -217,7 +217,7 @@ sp<IMemory> MetadataRetrieverClient::getFrameAtTime(int64_t timeUs, int option)
}
mThumbnail = new MemoryBase(heap, 0, size);
if (mThumbnail == NULL) {
- ALOGE("not enough memory for VideoFrame size=%u", size);
+ ALOGE("not enough memory for VideoFrame size=%zu", size);
delete frame;
return NULL;
}
@@ -258,7 +258,7 @@ sp<IMemory> MetadataRetrieverClient::extractAlbumArt()
}
mAlbumArt = new MemoryBase(heap, 0, size);
if (mAlbumArt == NULL) {
- ALOGE("not enough memory for MediaAlbumArt size=%u", size);
+ ALOGE("not enough memory for MediaAlbumArt size=%zu", size);
delete albumArt;
return NULL;
}
diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp
deleted file mode 100644
index 3fedd9b..0000000
--- a/media/libmediaplayerservice/StagefrightPlayer.cpp
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * 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 "StagefrightPlayer"
-#include <utils/Log.h>
-
-#include "StagefrightPlayer.h"
-
-#include "AwesomePlayer.h"
-
-#include <media/Metadata.h>
-#include <media/stagefright/MediaExtractor.h>
-
-namespace android {
-
-StagefrightPlayer::StagefrightPlayer()
- : mPlayer(new AwesomePlayer) {
- ALOGV("StagefrightPlayer");
-
- mPlayer->setListener(this);
-}
-
-StagefrightPlayer::~StagefrightPlayer() {
- ALOGV("~StagefrightPlayer");
- reset();
-
- delete mPlayer;
- mPlayer = NULL;
-}
-
-status_t StagefrightPlayer::initCheck() {
- ALOGV("initCheck");
- return OK;
-}
-
-status_t StagefrightPlayer::setUID(uid_t uid) {
- mPlayer->setUID(uid);
-
- return OK;
-}
-
-status_t StagefrightPlayer::setDataSource(
- const sp<IMediaHTTPService> &httpService,
- const char *url,
- const KeyedVector<String8, String8> *headers) {
- return mPlayer->setDataSource(httpService, url, headers);
-}
-
-// Warning: The filedescriptor passed into this method will only be valid until
-// the method returns, if you want to keep it, dup it!
-status_t StagefrightPlayer::setDataSource(int fd, int64_t offset, int64_t length) {
- ALOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
- return mPlayer->setDataSource(dup(fd), offset, length);
-}
-
-status_t StagefrightPlayer::setDataSource(const sp<IStreamSource> &source) {
- return mPlayer->setDataSource(source);
-}
-
-status_t StagefrightPlayer::setVideoSurfaceTexture(
- const sp<IGraphicBufferProducer> &bufferProducer) {
- ALOGV("setVideoSurfaceTexture");
-
- return mPlayer->setSurfaceTexture(bufferProducer);
-}
-
-status_t StagefrightPlayer::prepare() {
- return mPlayer->prepare();
-}
-
-status_t StagefrightPlayer::prepareAsync() {
- return mPlayer->prepareAsync();
-}
-
-status_t StagefrightPlayer::start() {
- ALOGV("start");
-
- return mPlayer->play();
-}
-
-status_t StagefrightPlayer::stop() {
- ALOGV("stop");
-
- return pause(); // what's the difference?
-}
-
-status_t StagefrightPlayer::pause() {
- ALOGV("pause");
-
- return mPlayer->pause();
-}
-
-bool StagefrightPlayer::isPlaying() {
- ALOGV("isPlaying");
- return mPlayer->isPlaying();
-}
-
-status_t StagefrightPlayer::seekTo(int msec) {
- ALOGV("seekTo %.2f secs", msec / 1E3);
-
- status_t err = mPlayer->seekTo((int64_t)msec * 1000);
-
- return err;
-}
-
-status_t StagefrightPlayer::getCurrentPosition(int *msec) {
- ALOGV("getCurrentPosition");
-
- int64_t positionUs;
- status_t err = mPlayer->getPosition(&positionUs);
-
- if (err != OK) {
- return err;
- }
-
- *msec = (positionUs + 500) / 1000;
-
- return OK;
-}
-
-status_t StagefrightPlayer::getDuration(int *msec) {
- ALOGV("getDuration");
-
- int64_t durationUs;
- status_t err = mPlayer->getDuration(&durationUs);
-
- if (err != OK) {
- *msec = 0;
- return OK;
- }
-
- *msec = (durationUs + 500) / 1000;
-
- return OK;
-}
-
-status_t StagefrightPlayer::reset() {
- ALOGV("reset");
-
- mPlayer->reset();
-
- return OK;
-}
-
-status_t StagefrightPlayer::setLooping(int loop) {
- ALOGV("setLooping");
-
- return mPlayer->setLooping(loop);
-}
-
-player_type StagefrightPlayer::playerType() {
- ALOGV("playerType");
- return STAGEFRIGHT_PLAYER;
-}
-
-status_t StagefrightPlayer::invoke(const Parcel &request, Parcel *reply) {
- ALOGV("invoke()");
- return mPlayer->invoke(request, reply);
-}
-
-void StagefrightPlayer::setAudioSink(const sp<AudioSink> &audioSink) {
- MediaPlayerInterface::setAudioSink(audioSink);
-
- mPlayer->setAudioSink(audioSink);
-}
-
-status_t StagefrightPlayer::setParameter(int key, const Parcel &request) {
- ALOGV("setParameter(key=%d)", key);
- return mPlayer->setParameter(key, request);
-}
-
-status_t StagefrightPlayer::getParameter(int key, Parcel *reply) {
- ALOGV("getParameter");
- return mPlayer->getParameter(key, reply);
-}
-
-status_t StagefrightPlayer::setPlaybackSettings(const AudioPlaybackRate &rate) {
- return mPlayer->setPlaybackSettings(rate);
-}
-
-status_t StagefrightPlayer::getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */) {
- return mPlayer->getPlaybackSettings(rate);
-}
-
-status_t StagefrightPlayer::getMetadata(
- const media::Metadata::Filter& /* ids */, Parcel *records) {
- using media::Metadata;
-
- uint32_t flags = mPlayer->flags();
-
- Metadata metadata(records);
-
- metadata.appendBool(
- Metadata::kPauseAvailable,
- flags & MediaExtractor::CAN_PAUSE);
-
- metadata.appendBool(
- Metadata::kSeekBackwardAvailable,
- flags & MediaExtractor::CAN_SEEK_BACKWARD);
-
- metadata.appendBool(
- Metadata::kSeekForwardAvailable,
- flags & MediaExtractor::CAN_SEEK_FORWARD);
-
- metadata.appendBool(
- Metadata::kSeekAvailable,
- flags & MediaExtractor::CAN_SEEK);
-
- return OK;
-}
-
-status_t StagefrightPlayer::dump(int fd, const Vector<String16> &args) const {
- return mPlayer->dump(fd, args);
-}
-
-} // namespace android
diff --git a/media/libmediaplayerservice/StagefrightPlayer.h b/media/libmediaplayerservice/StagefrightPlayer.h
deleted file mode 100644
index 96013df..0000000
--- a/media/libmediaplayerservice/StagefrightPlayer.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
-**
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** 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 ANDROID_STAGEFRIGHTPLAYER_H
-#define ANDROID_STAGEFRIGHTPLAYER_H
-
-#include <media/MediaPlayerInterface.h>
-
-namespace android {
-
-struct AwesomePlayer;
-
-class StagefrightPlayer : public MediaPlayerInterface {
-public:
- StagefrightPlayer();
- virtual ~StagefrightPlayer();
-
- virtual status_t initCheck();
-
- virtual status_t setUID(uid_t uid);
-
- virtual status_t setDataSource(
- const sp<IMediaHTTPService> &httpService,
- const char *url,
- const KeyedVector<String8, String8> *headers);
-
- virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
-
- virtual status_t setDataSource(const sp<IStreamSource> &source);
-
- virtual status_t setVideoSurfaceTexture(
- const sp<IGraphicBufferProducer> &bufferProducer);
- virtual status_t prepare();
- virtual status_t prepareAsync();
- virtual status_t start();
- virtual status_t stop();
- virtual status_t pause();
- virtual bool isPlaying();
- virtual status_t seekTo(int msec);
- virtual status_t getCurrentPosition(int *msec);
- virtual status_t getDuration(int *msec);
- virtual status_t reset();
- virtual status_t setLooping(int loop);
- virtual player_type playerType();
- virtual status_t invoke(const Parcel &request, Parcel *reply);
- virtual void setAudioSink(const sp<AudioSink> &audioSink);
- virtual status_t setParameter(int key, const Parcel &request);
- virtual status_t getParameter(int key, Parcel *reply);
- virtual status_t setPlaybackSettings(const AudioPlaybackRate &rate);
- virtual status_t getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */);
-
- virtual status_t getMetadata(
- const media::Metadata::Filter& ids, Parcel *records);
-
- virtual status_t dump(int fd, const Vector<String16> &args) const;
-
-private:
- AwesomePlayer *mPlayer;
-
- StagefrightPlayer(const StagefrightPlayer &);
- StagefrightPlayer &operator=(const StagefrightPlayer &);
-};
-
-} // namespace android
-
-#endif // ANDROID_STAGEFRIGHTPLAYER_H
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index e521fae..80d5ac2 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -19,6 +19,7 @@
#include <inttypes.h>
#include <utils/Log.h>
+#include <inttypes.h>
#include "WebmWriter.h"
#include "StagefrightRecorder.h"
@@ -55,9 +56,12 @@
#include <system/audio.h>
#include "ARTPWriter.h"
+#include <stagefright/AVExtensions.h>
namespace android {
+static const int64_t kMax32BitFileSize = 0x00ffffffffLL; // 4GB
+
// To collect the encoder usage for the battery app
static void addBatteryData(uint32_t params) {
sp<IBinder> binder =
@@ -249,7 +253,7 @@ status_t StagefrightRecorder::setInputSurface(
}
status_t StagefrightRecorder::setOutputFile(int fd, int64_t offset, int64_t length) {
- ALOGV("setOutputFile: %d, %lld, %lld", fd, offset, length);
+ ALOGV("setOutputFile: %d, %" PRId64 ", %" PRId64 "", fd, offset, length);
// These don't make any sense, do they?
CHECK_EQ(offset, 0ll);
CHECK_EQ(length, 0ll);
@@ -364,7 +368,7 @@ status_t StagefrightRecorder::setParamAudioSamplingRate(int32_t sampleRate) {
status_t StagefrightRecorder::setParamAudioNumberOfChannels(int32_t channels) {
ALOGV("setParamAudioNumberOfChannels: %d", channels);
- if (channels <= 0 || channels >= 3) {
+ if (channels <= 0 || channels >= 7) {
ALOGE("Invalid number of audio channels: %d", channels);
return BAD_VALUE;
}
@@ -416,42 +420,46 @@ status_t StagefrightRecorder::setParamVideoRotation(int32_t degrees) {
}
status_t StagefrightRecorder::setParamMaxFileDurationUs(int64_t timeUs) {
- ALOGV("setParamMaxFileDurationUs: %lld us", timeUs);
+ ALOGV("setParamMaxFileDurationUs: %" PRId64 " us", timeUs);
// This is meant for backward compatibility for MediaRecorder.java
if (timeUs <= 0) {
- ALOGW("Max file duration is not positive: %lld us. Disabling duration limit.", timeUs);
+ ALOGW("Max file duration is not positive: %" PRId64 " us. Disabling duration limit.", timeUs);
timeUs = 0; // Disable the duration limit for zero or negative values.
} else if (timeUs <= 100000LL) { // XXX: 100 milli-seconds
- ALOGE("Max file duration is too short: %lld us", timeUs);
+ ALOGE("Max file duration is too short: %" PRId64 " us", timeUs);
return BAD_VALUE;
}
if (timeUs <= 15 * 1000000LL) {
- ALOGW("Target duration (%lld us) too short to be respected", timeUs);
+ ALOGW("Target duration (%" PRId64 " us) too short to be respected", timeUs);
}
mMaxFileDurationUs = timeUs;
return OK;
}
status_t StagefrightRecorder::setParamMaxFileSizeBytes(int64_t bytes) {
- ALOGV("setParamMaxFileSizeBytes: %lld bytes", bytes);
+ ALOGV("setParamMaxFileSizeBytes: %" PRId64 " bytes", bytes);
// This is meant for backward compatibility for MediaRecorder.java
if (bytes <= 0) {
- ALOGW("Max file size is not positive: %lld bytes. "
+ ALOGW("Max file size is not positive: %" PRId64 " bytes. "
"Disabling file size limit.", bytes);
bytes = 0; // Disable the file size limit for zero or negative values.
} else if (bytes <= 1024) { // XXX: 1 kB
- ALOGE("Max file size is too small: %lld bytes", bytes);
+ ALOGE("Max file size is too small: %" PRId64 " bytes", bytes);
return BAD_VALUE;
}
if (bytes <= 100 * 1024) {
- ALOGW("Target file size (%lld bytes) is too small to be respected", bytes);
+ ALOGW("Target file size (%" PRId64 " bytes) is too small to be respected", bytes);
}
mMaxFileSizeBytes = bytes;
+
+ // If requested size is >4GB, force 64-bit offsets
+ mUse64BitFileOffset |= (bytes >= kMax32BitFileSize);
+
return OK;
}
@@ -500,9 +508,9 @@ status_t StagefrightRecorder::setParamVideoCameraId(int32_t cameraId) {
}
status_t StagefrightRecorder::setParamTrackTimeStatus(int64_t timeDurationUs) {
- ALOGV("setParamTrackTimeStatus: %lld", timeDurationUs);
+ ALOGV("setParamTrackTimeStatus: %" PRId64 "", timeDurationUs);
if (timeDurationUs < 20000) { // Infeasible if shorter than 20 ms?
- ALOGE("Tracking time duration too short: %lld us", timeDurationUs);
+ ALOGE("Tracking time duration too short: %" PRId64 " us", timeDurationUs);
return BAD_VALUE;
}
mTrackEveryTimeDurationUs = timeDurationUs;
@@ -581,11 +589,11 @@ status_t StagefrightRecorder::setParamCaptureFpsEnable(int32_t captureFpsEnable)
status_t StagefrightRecorder::setParamCaptureFps(float fps) {
ALOGV("setParamCaptureFps: %.2f", fps);
- int64_t timeUs = (int64_t) (1000000.0 / fps + 0.5f);
+ int64_t timeUs = (int64_t) (1000000.0f / fps + 0.5f);
// Not allowing time more than a day
if (timeUs <= 0 || timeUs > 86400*1E6) {
- ALOGE("Time between frame capture (%lld) is out of range [0, 1 Day]", timeUs);
+ ALOGE("Time between frame capture (%" PRId64 ") is out of range [0, 1 Day]", timeUs);
return BAD_VALUE;
}
@@ -814,8 +822,10 @@ status_t StagefrightRecorder::prepareInternal() {
break;
default:
- ALOGE("Unsupported output file format: %d", mOutputFormat);
- status = UNKNOWN_ERROR;
+ if (handleCustomRecording() != OK) {
+ ALOGE("Unsupported output file format: %d", mOutputFormat);
+ status = UNKNOWN_ERROR;
+ }
break;
}
@@ -879,8 +889,10 @@ status_t StagefrightRecorder::start() {
default:
{
- ALOGE("Unsupported output file format: %d", mOutputFormat);
- status = UNKNOWN_ERROR;
+ if (handleCustomOutputFormats() != OK) {
+ ALOGE("Unsupported output file format: %d", mOutputFormat);
+ status = UNKNOWN_ERROR;
+ }
break;
}
}
@@ -927,13 +939,12 @@ sp<MediaSource> StagefrightRecorder::createAudioSource() {
}
}
- sp<AudioSource> audioSource =
- new AudioSource(
- mAudioSource,
- mOpPackageName,
- sourceSampleRate,
- mAudioChannels,
- mSampleRate);
+ sp<AudioSource> audioSource = AVFactory::get()->createAudioSource(
+ mAudioSource,
+ mOpPackageName,
+ sourceSampleRate,
+ mAudioChannels,
+ mSampleRate);
status_t err = audioSource->initCheck();
@@ -965,8 +976,10 @@ sp<MediaSource> StagefrightRecorder::createAudioSource() {
break;
default:
- ALOGE("Unknown audio encoder: %d", mAudioEncoder);
- return NULL;
+ if (handleCustomAudioSource(format) != OK) {
+ ALOGE("Unknown audio encoder: %d", mAudioEncoder);
+ return NULL;
+ }
}
int32_t maxInputSize;
@@ -984,6 +997,13 @@ sp<MediaSource> StagefrightRecorder::createAudioSource() {
sp<MediaSource> audioEncoder =
MediaCodecSource::Create(mLooper, format, audioSource);
+ // If encoder could not be created (as in LPCM), then
+ // use the AudioSource directly as the MediaSource.
+ if (audioEncoder == NULL &&
+ mAudioEncoder == AUDIO_ENCODER_LPCM) {
+ ALOGD("No encoder is needed for linear PCM format");
+ audioEncoder = audioSource;
+ }
mAudioSourceNode = audioSource;
if (audioEncoder == NULL) {
@@ -1440,22 +1460,23 @@ status_t StagefrightRecorder::setupCameraSource(
videoSize.height = mVideoHeight;
if (mCaptureFpsEnable) {
if (mTimeBetweenCaptureUs < 0) {
- ALOGE("Invalid mTimeBetweenTimeLapseFrameCaptureUs value: %lld",
+ ALOGE("Invalid mTimeBetweenTimeLapseFrameCaptureUs value: %" PRId64 "",
mTimeBetweenCaptureUs);
return BAD_VALUE;
}
- mCameraSourceTimeLapse = CameraSourceTimeLapse::CreateFromCamera(
+ mCameraSourceTimeLapse = AVFactory::get()->CreateCameraSourceTimeLapseFromCamera(
mCamera, mCameraProxy, mCameraId, mClientName, mClientUid,
videoSize, mFrameRate, mPreviewSurface,
mTimeBetweenCaptureUs);
*cameraSource = mCameraSourceTimeLapse;
} else {
- *cameraSource = CameraSource::CreateFromCamera(
+ *cameraSource = AVFactory::get()->CreateCameraSourceFromCamera(
mCamera, mCameraProxy, mCameraId, mClientName, mClientUid,
videoSize, mFrameRate,
mPreviewSurface);
}
+ AVUtils::get()->cacheCaptureBuffers(mCamera, mVideoEncoder);
mCamera.clear();
mCameraProxy.clear();
if (*cameraSource == NULL) {
@@ -1487,6 +1508,11 @@ status_t StagefrightRecorder::setupCameraSource(
return OK;
}
+bool StagefrightRecorder::setCustomVideoEncoderMime(const video_encoder /*videoEncoder*/,
+ sp<AMessage> /*format*/) {
+ return false;
+}
+
status_t StagefrightRecorder::setupVideoEncoder(
sp<MediaSource> cameraSource,
sp<MediaSource> *source) {
@@ -1512,6 +1538,9 @@ status_t StagefrightRecorder::setupVideoEncoder(
break;
default:
+ if (setCustomVideoEncoderMime(mVideoEncoder, format)) {
+ break;
+ }
CHECK(!"Should not be here, unsupported video encoding.");
break;
}
@@ -1541,7 +1570,7 @@ status_t StagefrightRecorder::setupVideoEncoder(
// set up time lapse/slow motion for surface source
if (mCaptureFpsEnable) {
if (mTimeBetweenCaptureUs <= 0) {
- ALOGE("Invalid mTimeBetweenCaptureUs value: %lld",
+ ALOGE("Invalid mTimeBetweenCaptureUs value: %" PRId64 "",
mTimeBetweenCaptureUs);
return BAD_VALUE;
}
@@ -1549,6 +1578,8 @@ status_t StagefrightRecorder::setupVideoEncoder(
}
}
+ setupCustomVideoEncoderParams(cameraSource, format);
+
format->setInt32("bitrate", mVideoBitRate);
format->setInt32("frame-rate", mFrameRate);
format->setInt32("i-frame-interval", mIFramesIntervalSec);
@@ -1614,8 +1645,10 @@ status_t StagefrightRecorder::setupAudioEncoder(const sp<MediaWriter>& writer) {
break;
default:
- ALOGE("Unsupported audio encoder: %d", mAudioEncoder);
- return UNKNOWN_ERROR;
+ if (handleCustomAudioEncoder() != OK) {
+ ALOGE("Unsupported audio encoder: %d", mAudioEncoder);
+ return UNKNOWN_ERROR;
+ }
}
sp<MediaSource> audioEncoder = createAudioSource();
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index da00bc7..d2ff62d 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -39,6 +39,7 @@ class IGraphicBufferConsumer;
class IGraphicBufferProducer;
class SurfaceMediaSource;
struct ALooper;
+struct AMessage;
struct StagefrightRecorder : public MediaRecorderBase {
StagefrightRecorder(const String16 &opPackageName);
@@ -70,7 +71,7 @@ struct StagefrightRecorder : public MediaRecorderBase {
// Querying a SurfaceMediaSourcer
virtual sp<IGraphicBufferProducer> querySurfaceMediaSource() const;
-private:
+protected:
sp<ICamera> mCamera;
sp<ICameraRecordingProxy> mCameraProxy;
sp<IGraphicBufferProducer> mPreviewSurface;
@@ -131,7 +132,7 @@ private:
static const int kMaxHighSpeedFps = 1000;
- status_t prepareInternal();
+ virtual status_t prepareInternal();
status_t setupMPEG4orWEBMRecording();
void setupMPEG4orWEBMMetaData(sp<MetaData> *meta);
status_t setupAMRRecording();
@@ -139,8 +140,8 @@ private:
status_t setupRawAudioRecording();
status_t setupRTPRecording();
status_t setupMPEG2TSRecording();
- sp<MediaSource> createAudioSource();
- status_t checkVideoEncoderCapabilities();
+ virtual sp<MediaSource> createAudioSource();
+ virtual status_t checkVideoEncoderCapabilities();
status_t checkAudioEncoderCapabilities();
// Generic MediaSource set-up. Returns the appropriate
// source (CameraSource or SurfaceMediaSource)
@@ -148,10 +149,13 @@ private:
status_t setupMediaSource(sp<MediaSource> *mediaSource);
status_t setupCameraSource(sp<CameraSource> *cameraSource);
status_t setupAudioEncoder(const sp<MediaWriter>& writer);
- status_t setupVideoEncoder(sp<MediaSource> cameraSource, sp<MediaSource> *source);
+ virtual status_t setupVideoEncoder(sp<MediaSource> cameraSource, sp<MediaSource> *source);
+ virtual void setupCustomVideoEncoderParams(sp<MediaSource> /*cameraSource*/,
+ sp<AMessage> &/*format*/) {}
+ virtual bool setCustomVideoEncoderMime(const video_encoder videoEncoder, sp<AMessage> format);
// Encoding parameter handling utilities
- status_t setParameter(const String8 &key, const String8 &value);
+ virtual status_t setParameter(const String8 &key, const String8 &value);
status_t setParamAudioEncodingBitRate(int32_t bitRate);
status_t setParamAudioNumberOfChannels(int32_t channles);
status_t setParamAudioSamplingRate(int32_t sampleRate);
@@ -181,7 +185,11 @@ private:
void clipAudioSampleRate();
void clipNumberOfAudioChannels();
void setDefaultProfileIfNecessary();
- void setDefaultVideoEncoderIfNecessary();
+ virtual void setDefaultVideoEncoderIfNecessary();
+ virtual status_t handleCustomOutputFormats() {return UNKNOWN_ERROR;}
+ virtual status_t handleCustomRecording() {return UNKNOWN_ERROR;}
+ virtual status_t handleCustomAudioSource(sp<AMessage> /*format*/) {return UNKNOWN_ERROR;}
+ virtual status_t handleCustomAudioEncoder() {return UNKNOWN_ERROR;}
StagefrightRecorder(const StagefrightRecorder &);
diff --git a/media/libmediaplayerservice/nuplayer/Android.mk b/media/libmediaplayerservice/nuplayer/Android.mk
index cd20837..6729cd5 100644
--- a/media/libmediaplayerservice/nuplayer/Android.mk
+++ b/media/libmediaplayerservice/nuplayer/Android.mk
@@ -23,7 +23,9 @@ LOCAL_C_INCLUDES := \
$(TOP)/frameworks/av/media/libstagefright/rtsp \
$(TOP)/frameworks/av/media/libstagefright/timedtext \
$(TOP)/frameworks/av/media/libmediaplayerservice \
- $(TOP)/frameworks/native/include/media/openmax
+ $(TOP)/frameworks/native/include/media/openmax \
+ $(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 b3eb5fd..7be4d23 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -37,6 +37,7 @@
#include "../../libstagefright/include/NuCachedSource2.h"
#include "../../libstagefright/include/WVMExtractor.h"
#include "../../libstagefright/include/HTTPBase.h"
+#include "mediaplayerservice/AVNuExtensions.h"
namespace android {
@@ -60,6 +61,7 @@ NuPlayer::GenericSource::GenericSource(
mAudioIsVorbis(false),
mIsWidevine(false),
mIsSecure(false),
+ mUseSetBuffers(false),
mIsStreaming(false),
mUIDValid(uidValid),
mUID(uid),
@@ -172,7 +174,8 @@ status_t NuPlayer::GenericSource::initFromDataSource() {
extractor = mWVMExtractor;
} else {
extractor = MediaExtractor::Create(mDataSource,
- mimeType.isEmpty() ? NULL : mimeType.string());
+ mimeType.isEmpty() ? NULL : mimeType.string(),
+ mIsStreaming ? 0 : AVNuUtils::get()->getUseSetBuffersFlag());
}
if (extractor == NULL) {
@@ -202,6 +205,11 @@ status_t NuPlayer::GenericSource::initFromDataSource() {
}
}
+ if (AVNuUtils::get()->canUseSetBuffers(mFileMeta)) {
+ mUseSetBuffers = true;
+ ALOGI("setBuffers mode enabled");
+ }
+
int32_t totalBitrate = 0;
size_t numtracks = extractor->countTracks();
@@ -318,7 +326,7 @@ int64_t NuPlayer::GenericSource::getLastReadPosition() {
status_t NuPlayer::GenericSource::setBuffers(
bool audio, Vector<MediaBuffer *> &buffers) {
- if (mIsSecure && !audio) {
+ if ((mIsSecure || mUseSetBuffers) && !audio) {
return mVideoTrack.mSource->setBuffers(buffers);
}
return INVALID_OPERATION;
@@ -374,7 +382,8 @@ void NuPlayer::GenericSource::onPrepareAsync() {
mDataSource = DataSource::CreateFromURI(
mHTTPService, uri, &mUriHeaders, &contentType,
- static_cast<HTTPBase *>(mHttpSource.get()));
+ static_cast<HTTPBase *>(mHttpSource.get()),
+ true /*use extended cache*/);
} else {
mIsWidevine = false;
@@ -427,7 +436,8 @@ void NuPlayer::GenericSource::onPrepareAsync() {
| FLAG_CAN_PAUSE
| FLAG_CAN_SEEK_BACKWARD
| FLAG_CAN_SEEK_FORWARD
- | FLAG_CAN_SEEK);
+ | FLAG_CAN_SEEK
+ | (mUseSetBuffers ? FLAG_USE_SET_BUFFERS : 0));
if (mIsSecure) {
// secure decoders must be instantiated before starting widevine source
@@ -1022,7 +1032,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);
}
@@ -1366,7 +1377,7 @@ sp<ABuffer> NuPlayer::GenericSource::mediaBufferToABuffer(
}
sp<ABuffer> 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();
@@ -1481,7 +1492,9 @@ void NuPlayer::GenericSource::readBuffer(
break;
case MEDIA_TRACK_TYPE_AUDIO:
track = &mAudioTrack;
- if (mIsWidevine) {
+ if (mHttpSource != NULL && getTrackCount() == 1) {
+ maxBuffers = 16;
+ } else if (mIsWidevine || (mHttpSource != NULL)) {
maxBuffers = 8;
} else {
maxBuffers = 64;
@@ -1512,9 +1525,10 @@ void NuPlayer::GenericSource::readBuffer(
if (seekTimeUs >= 0) {
options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
seeking = true;
+ track->mPackets->clear();
}
- if (mIsWidevine) {
+ if (mIsWidevine || mUseSetBuffers) {
options.setNonBlocking();
}
@@ -1536,7 +1550,8 @@ void NuPlayer::GenericSource::readBuffer(
queueDiscontinuityIfNeeded(seeking, formatChange, trackType, track);
sp<ABuffer> buffer = mediaBufferToABuffer(
- mbuf, trackType, seekTimeUs, actualTimeUs);
+ mbuf, trackType, seekTimeUs,
+ numBuffers == 0 ? actualTimeUs : NULL);
track->mPackets->queueAccessUnit(buffer);
formatChange = false;
seeking = false;
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index ac980ef..bdcf706 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -42,7 +42,7 @@ class WVMExtractor;
struct NuPlayer::GenericSource : public NuPlayer::Source {
GenericSource(const sp<AMessage> &notify, bool uidValid, uid_t uid);
- status_t setDataSource(
+ virtual status_t setDataSource(
const sp<IMediaHTTPService> &httpService,
const char *url,
const KeyedVector<String8, String8> *headers);
@@ -84,7 +84,7 @@ protected:
virtual sp<MetaData> getFormatMeta(bool audio);
-private:
+protected:
enum {
kWhatPrepareAsync,
kWhatFetchSubtitleData,
@@ -126,6 +126,7 @@ private:
bool mAudioIsVorbis;
bool mIsWidevine;
bool mIsSecure;
+ bool mUseSetBuffers;
bool mIsStreaming;
bool mUIDValid;
uid_t mUID;
@@ -164,7 +165,7 @@ private:
int64_t getLastReadPosition();
void setDrmPlaybackStatusIfNeeded(int playbackStatus, int64_t position);
- void notifyPreparedAndCleanup(status_t err);
+ virtual void notifyPreparedAndCleanup(status_t err);
void onSecureDecodersInstantiated(status_t err);
void finishPrepareAsync();
status_t startSources();
@@ -181,7 +182,7 @@ private:
void onSeek(sp<AMessage> msg);
status_t doSeek(int64_t seekTimeUs);
- void onPrepareAsync();
+ virtual void onPrepareAsync();
void fetchTextData(
uint32_t what, media_track_type type,
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index 126625a..a57fdc1 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -30,6 +30,8 @@
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/Utils.h>
+
namespace android {
@@ -118,6 +120,19 @@ sp<AMessage> NuPlayer::HTTPLiveSource::getFormat(bool audio) {
return format;
}
+sp<MetaData> NuPlayer::HTTPLiveSource::getFormatMeta(bool audio) {
+ sp<AMessage> format = getFormat(audio);
+
+ if (format == NULL) {
+ return NULL;
+ }
+
+ sp<MetaData> meta = new MetaData;
+ convertMessageToMetaData(format, meta);
+ return meta;
+}
+
+
status_t NuPlayer::HTTPLiveSource::feedMoreTSData() {
return OK;
}
@@ -197,7 +212,11 @@ status_t NuPlayer::HTTPLiveSource::selectTrack(size_t trackIndex, bool select, i
}
status_t NuPlayer::HTTPLiveSource::seekTo(int64_t seekTimeUs) {
- return mLiveSession->seekTo(seekTimeUs);
+ if (mLiveSession->isSeekable()) {
+ return mLiveSession->seekTo(seekTimeUs);
+ } else {
+ return INVALID_OPERATION;
+ }
}
void NuPlayer::HTTPLiveSource::pollForRawData(
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
index 9e0ec2f..388156c 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
@@ -39,6 +39,7 @@ struct NuPlayer::HTTPLiveSource : public NuPlayer::Source {
virtual status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
virtual sp<AMessage> getFormat(bool audio);
+ virtual sp<MetaData> getFormatMeta(bool audio);
virtual status_t feedMoreTSData();
virtual status_t getDuration(int64_t *durationUs);
@@ -53,7 +54,6 @@ protected:
virtual void onMessageReceived(const sp<AMessage> &msg);
-private:
enum Flags {
// Don't log any URLs.
kFlagIncognito = 1,
@@ -78,7 +78,7 @@ private:
bool mHasMetadata;
bool mMetadataSelected;
- void onSessionNotify(const sp<AMessage> &msg);
+ virtual void onSessionNotify(const sp<AMessage> &msg);
void pollForRawData(
const sp<AMessage> &msg, int32_t currentGeneration,
LiveSession::StreamType fetchType, int32_t pushWhat);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index c0146d5..ec1ab79 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -56,6 +56,7 @@
#include "ESDS.h"
#include <media/stagefright/Utils.h>
+#include "mediaplayerservice/AVNuExtensions.h"
namespace android {
@@ -130,6 +131,23 @@ private:
DISALLOW_EVIL_CONSTRUCTORS(FlushDecoderAction);
};
+struct NuPlayer::InstantiateDecoderAction : public Action {
+ InstantiateDecoderAction(bool audio, sp<DecoderBase> *decoder)
+ : mAudio(audio),
+ mdecoder(decoder) {
+ }
+
+ virtual void execute(NuPlayer *player) {
+ player->instantiateDecoder(mAudio, mdecoder);
+ }
+
+private:
+ bool mAudio;
+ sp<DecoderBase> *mdecoder;
+
+ DISALLOW_EVIL_CONSTRUCTORS(InstantiateDecoderAction);
+};
+
struct NuPlayer::PostMessageAction : public Action {
PostMessageAction(const sp<AMessage> &msg)
: mMessage(msg) {
@@ -216,7 +234,7 @@ void NuPlayer::setDataSourceAsync(const sp<IStreamSource> &source) {
msg->post();
}
-static bool IsHTTPLiveURL(const char *url) {
+bool NuPlayer::IsHTTPLiveURL(const char *url) {
if (!strncasecmp("http://", url, 7)
|| !strncasecmp("https://", url, 8)
|| !strncasecmp("file://", url, 7)) {
@@ -1092,6 +1110,12 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
int32_t reason;
CHECK(msg->findInt32("reason", &reason));
ALOGV("Tear down audio with reason %d.", reason);
+
+ if (ifDecodedPCMOffload()) {
+ tearDownPCMOffload(msg);
+ break;
+ }
+
mAudioDecoder.clear();
++mAudioDecoderGeneration;
bool needsToCreateAudioDecoder = true;
@@ -1145,6 +1169,9 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
FLUSH_CMD_SHUTDOWN /* video */));
mDeferredActions.push_back(
+ new SimpleAction(&NuPlayer::closeAudioSink));
+
+ mDeferredActions.push_back(
new SimpleAction(&NuPlayer::performReset));
processDeferredActions();
@@ -1295,6 +1322,7 @@ void NuPlayer::onStart(int64_t startPositionUs) {
}
sp<MetaData> audioMeta = mSource->getFormatMeta(true /* audio */);
+ AVNuUtils::get()->setSourcePCMFormat(audioMeta);
audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
if (mAudioSink != NULL) {
streamType = mAudioSink->getAudioStreamType();
@@ -1304,6 +1332,10 @@ void NuPlayer::onStart(int64_t startPositionUs) {
mOffloadAudio =
canOffloadStream(audioMeta, (videoFormat != NULL), mSource->isStreaming(), streamType);
+ if (!mOffloadAudio) {
+ mOffloadAudio = canOffloadDecodedPCMStream(audioMeta, (videoFormat != NULL), mSource->isStreaming(), streamType);
+ }
+
if (mOffloadAudio) {
flags |= Renderer::FLAG_OFFLOAD_AUDIO;
}
@@ -1311,7 +1343,7 @@ void NuPlayer::onStart(int64_t startPositionUs) {
sp<AMessage> notify = new AMessage(kWhatRendererNotify, this);
++mRendererGeneration;
notify->setInt32("generation", mRendererGeneration);
- mRenderer = new Renderer(mAudioSink, notify, flags);
+ mRenderer = AVNuFactory::get()->createRenderer(mAudioSink, notify, flags);
mRendererLooper = new ALooper;
mRendererLooper->setName("NuPlayerRenderer");
mRendererLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
@@ -1440,7 +1472,7 @@ void NuPlayer::tryOpenAudioSinkForOffload(const sp<AMessage> &format, bool hasVi
// is possible; otherwise the decoders call the renderer openAudioSink directly.
status_t err = mRenderer->openAudioSink(
- format, true /* offloadOnly */, hasVideo, AUDIO_OUTPUT_FLAG_NONE, &mOffloadAudio);
+ format, true /* offloadOnly */, hasVideo, AUDIO_OUTPUT_FLAG_NONE, &mOffloadAudio, mSource->isStreaming());
if (err != OK) {
// Any failure we turn off mOffloadAudio.
mOffloadAudio = false;
@@ -1470,8 +1502,11 @@ void NuPlayer::determineAudioModeChange() {
sp<AMessage> videoFormat = mSource->getFormat(false /* audio */);
audio_stream_type_t streamType = mAudioSink->getAudioStreamType();
const bool hasVideo = (videoFormat != NULL);
- const bool canOffload = canOffloadStream(
+ bool canOffload = canOffloadStream(
audioMeta, hasVideo, mSource->isStreaming(), streamType);
+ if (!canOffload) {
+ canOffload = canOffloadDecodedPCMStream(audioMeta, (videoFormat != NULL), mSource->isStreaming(), streamType);
+ }
if (canOffload) {
if (!mOffloadAudio) {
mRenderer->signalEnableOffloadAudio();
@@ -1483,6 +1518,7 @@ void NuPlayer::determineAudioModeChange() {
if (mOffloadAudio) {
mRenderer->signalDisableOffloadAudio();
mOffloadAudio = false;
+ setDecodedPcmOffload(false);
}
}
}
@@ -1493,7 +1529,10 @@ status_t NuPlayer::instantiateDecoder(bool audio, sp<DecoderBase> *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<AMessage> format = mSource->getFormat(audio);
if (format == NULL) {
@@ -1531,12 +1570,17 @@ status_t NuPlayer::instantiateDecoder(bool audio, sp<DecoderBase> *decoder) {
notify->setInt32("generation", mAudioDecoderGeneration);
determineAudioModeChange();
- if (mOffloadAudio) {
+
+ if (AVNuUtils::get()->isRAWFormat(format)) {
+ AVNuUtils::get()->setPCMFormat(format,
+ AVNuUtils::get()->getKeyPCMFormat(mSource->getFormatMeta(true /* audio */)));
+ }
+ if (mOffloadAudio && !ifDecodedPCMOffload()) {
const bool hasVideo = (mSource->getFormat(false /*audio */) != NULL);
format->setInt32("has-video", hasVideo);
- *decoder = new DecoderPassThrough(notify, mSource, mRenderer);
+ *decoder = AVNuFactory::get()->createPassThruDecoder(notify, mSource, mRenderer);
} else {
- *decoder = new Decoder(notify, mSource, mPID, mRenderer);
+ *decoder = AVNuFactory::get()->createDecoder(notify, mSource, mPID, mRenderer);
}
} else {
sp<AMessage> notify = new AMessage(kWhatVideoNotify, this);
@@ -1561,7 +1605,8 @@ status_t NuPlayer::instantiateDecoder(bool audio, sp<DecoderBase> *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<sp<ABuffer> > inputBufs;
CHECK_EQ((*decoder)->getInputBuffers(&inputBufs), (status_t)OK);
@@ -2217,6 +2262,13 @@ void NuPlayer::onSourceNotify(const sp<AMessage> &msg) {
break;
}
+ case Source::kWhatRTCPByeReceived:
+ {
+ ALOGV("notify the client that Bye message is received");
+ notifyListener(MEDIA_INFO, 2000, 0);
+ break;
+ }
+
default:
TRESPASS();
}
@@ -2362,4 +2414,45 @@ void NuPlayer::Source::onMessageReceived(const sp<AMessage> & /* msg */) {
TRESPASS();
}
+void NuPlayer::tearDownPCMOffload(const sp<AMessage> &msg) {
+ int32_t reason;
+ CHECK(msg->findInt32("reason", &reason));
+
+ if (mAudioDecoder != NULL) {
+ switch (mFlushingAudio) {
+ case NONE:
+ case FLUSHING_DECODER:
+ mDeferredActions.push_back(
+ new FlushDecoderAction(FLUSH_CMD_SHUTDOWN /* audio */,
+ FLUSH_CMD_NONE /* video */));
+
+ if (reason == Renderer::kDueToError) {
+ mDeferredActions.push_back(
+ new InstantiateDecoderAction(true /* audio */, &mAudioDecoder));
+ }
+
+ int64_t positionUs;
+ if (!msg->findInt64("positionUs", &positionUs)) {
+ positionUs = mPreviousSeekTimeUs;
+ }
+ mDeferredActions.push_back(new SeekAction(positionUs));
+ break;
+ default:
+ ALOGW("tearDownPCMOffload while flushing audio in %d", mFlushingAudio);
+ break;
+ }
+ }
+
+ if (mRenderer != NULL) {
+ closeAudioSink();
+ mRenderer->flush(
+ true /* audio */, false /* notifyComplete */);
+ if (mVideoDecoder != NULL) {
+ mRenderer->flush(
+ false /* audio */, false /* notifyComplete */);
+ }
+ }
+ processDeferredActions();
+}
+
} // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index c9f0bbd..73e196e 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -41,7 +41,7 @@ struct NuPlayer : public AHandler {
void setDataSourceAsync(const sp<IStreamSource> &source);
- void setDataSourceAsync(
+ virtual void setDataSourceAsync(
const sp<IMediaHTTPService> &httpService,
const char *url,
const KeyedVector<String8, String8> *headers);
@@ -86,12 +86,15 @@ protected:
virtual ~NuPlayer();
virtual void onMessageReceived(const sp<AMessage> &msg);
-
+ virtual bool ifDecodedPCMOffload() {return false;}
+ virtual void setDecodedPcmOffload(bool /*decodePcmOffload*/) {}
+ virtual bool canOffloadDecodedPCMStream(const sp<MetaData> /*meta*/,
+ bool /*hasVideo*/, bool /*isStreaming*/, audio_stream_type_t /*streamType*/) {return false;}
+ static bool IsHTTPLiveURL(const char *url);
public:
struct NuPlayerStreamListener;
struct Source;
-private:
struct Decoder;
struct DecoderBase;
struct DecoderPassThrough;
@@ -106,9 +109,11 @@ private:
struct SetSurfaceAction;
struct ResumeDecoderAction;
struct FlushDecoderAction;
+ struct InstantiateDecoderAction;
struct PostMessageAction;
struct SimpleAction;
+protected:
enum {
kWhatSetDataSource = '=DaS',
kWhatPrepare = 'prep',
@@ -221,11 +226,11 @@ private:
mFlushComplete[1][1] = false;
}
- void tryOpenAudioSinkForOffload(const sp<AMessage> &format, bool hasVideo);
+ virtual void tryOpenAudioSinkForOffload(const sp<AMessage> &format, bool hasVideo);
void closeAudioSink();
void determineAudioModeChange();
- status_t instantiateDecoder(bool audio, sp<DecoderBase> *decoder);
+ virtual status_t instantiateDecoder(bool audio, sp<DecoderBase> *decoder);
status_t onInstantiateSecureDecoders();
@@ -233,7 +238,7 @@ private:
const sp<AMessage> &inputFormat,
const sp<AMessage> &outputFormat = NULL);
- void notifyListener(int msg, int ext1, int ext2, const Parcel *in = NULL);
+ virtual void notifyListener(int msg, int ext1, int ext2, const Parcel *in = NULL);
void handleFlushComplete(bool audio, bool isDecoder);
void finishFlushIfPossible();
@@ -256,14 +261,14 @@ private:
void processDeferredActions();
- void performSeek(int64_t seekTimeUs);
+ virtual void performSeek(int64_t seekTimeUs);
void performDecoderFlush(FlushCommand audio, FlushCommand video);
void performReset();
void performScanSources();
void performSetSurface(const sp<Surface> &wrapper);
void performResumeDecoders(bool needNotify);
- void onSourceNotify(const sp<AMessage> &msg);
+ virtual void onSourceNotify(const sp<AMessage> &msg);
void onClosedCaptionNotify(const sp<AMessage> &msg);
void queueDecoderShutdown(
@@ -275,6 +280,8 @@ private:
void writeTrackInfo(Parcel* reply, const sp<AMessage> format) const;
+ void tearDownPCMOffload(const sp<AMessage> &msg);
+
DISALLOW_EVIL_CONSTRUCTORS(NuPlayer);
};
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 3646828..9ca8c9f 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -34,10 +34,14 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
+#include <stagefright/AVExtensions.h>
+#include <stagefright/FFMPEGSoftCodec.h>
#include <gui/Surface.h>
#include "avc_utils.h"
#include "ATSParser.h"
+#include "mediaplayerservice/AVNuExtensions.h"
+
namespace android {
@@ -78,7 +82,9 @@ NuPlayer::Decoder::Decoder(
}
NuPlayer::Decoder::~Decoder() {
- mCodec->release();
+ if (mCodec != NULL) {
+ mCodec->release();
+ }
releaseAndResetMediaBuffers();
}
@@ -251,8 +257,17 @@ void NuPlayer::Decoder::onConfigure(const sp<AMessage> &format) {
mComponentName.append(" decoder");
ALOGV("[%s] onConfigure (surface=%p)", mComponentName.c_str(), mSurface.get());
- mCodec = MediaCodec::CreateByType(
- mCodecLooper, mime.c_str(), false /* encoder */, NULL /* err */, mPid);
+ mCodec = AVUtils::get()->createCustomComponentByName(mCodecLooper, mime.c_str(), false /* encoder */, format);
+ FFMPEGSoftCodec::overrideComponentName(0, format, &mComponentName, &mime, false);
+
+ if (mCodec == NULL) {
+ 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) {
@@ -357,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) {
@@ -558,6 +580,11 @@ bool NuPlayer::Decoder::handleAnOutputBuffer(
sp<ABuffer> buffer;
mCodec->getOutputBuffer(index, &buffer);
+ if (buffer == NULL) {
+ handleError(UNKNOWN_ERROR);
+ return false;
+ }
+
if (index >= mOutputBuffers.size()) {
for (size_t i = mOutputBuffers.size(); i <= index; ++i) {
mOutputBuffers.add();
@@ -569,6 +596,8 @@ bool NuPlayer::Decoder::handleAnOutputBuffer(
buffer->setRange(offset, size);
buffer->meta()->clear();
buffer->meta()->setInt64("timeUs", timeUs);
+ setPcmFormat(buffer->meta());
+ AVNuUtils::get()->addFlagsInMeta(buffer, flags, mIsAudio);
bool eos = flags & MediaCodec::BUFFER_FLAG_EOS;
// we do not expect CODECCONFIG or SYNCFRAME for decoder
@@ -636,7 +665,7 @@ void NuPlayer::Decoder::handleOutputFormatChange(const sp<AMessage> &format) {
}
mRenderer->openAudioSink(
- format, false /* offloadOnly */, hasVideo, flags, NULL /* isOffloaed */);
+ format, false /* offloadOnly */, hasVideo, flags, NULL /* isOffloaed */, mSource->isStreaming());
}
}
@@ -708,6 +737,7 @@ status_t NuPlayer::Decoder::fetchInputData(sp<AMessage> &reply) {
// treat seamless format change separately
formatChange = !seamlessFormatChange;
}
+ AVNuUtils::get()->checkFormatChange(&formatChange, accessUnit);
// For format or time change, return EOS to queue EOS input,
// then wait for EOS on output.
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
index eeb4af4..5f84a06 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
@@ -49,8 +49,8 @@ protected:
virtual void onFlush();
virtual void onShutdown(bool notifyComplete);
virtual bool doRequestBuffers();
+ virtual void setPcmFormat(const sp<AMessage> & /*format*/) {}
-private:
enum {
kWhatCodecNotify = 'cdcN',
kWhatRenderBuffer = 'rndr',
@@ -103,7 +103,7 @@ private:
size_t size,
int64_t timeUs,
int32_t flags);
- void handleOutputFormatChange(const sp<AMessage> &format);
+ virtual void handleOutputFormatChange(const sp<AMessage> &format);
void releaseAndResetMediaBuffers();
void requestCodecNotification();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
index 30146c4..937936d 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
@@ -29,14 +29,12 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MediaErrors.h>
+#include "mediaplayerservice/AVNuExtensions.h"
#include "ATSParser.h"
namespace android {
-// TODO optimize buffer size for power consumption
-// The offload read buffer size is 32 KB but 24 KB uses less power.
-static const size_t kAggregateBufferSizeBytes = 24 * 1024;
static const size_t kMaxCachedBytes = 200000;
NuPlayer::DecoderPassThrough::DecoderPassThrough(
@@ -46,6 +44,9 @@ NuPlayer::DecoderPassThrough::DecoderPassThrough(
: DecoderBase(notify),
mSource(source),
mRenderer(renderer),
+ // TODO optimize buffer size for power consumption
+ // The offload read buffer size is 32 KB but 24 KB uses less power.
+ mAggregateBufferSizeBytes(24 * 1024),
mSkipRenderingUntilMediaTimeUs(-1ll),
mPaused(false),
mReachedEOS(true),
@@ -76,7 +77,7 @@ void NuPlayer::DecoderPassThrough::onConfigure(const sp<AMessage> &format) {
// format is different.
status_t err = mRenderer->openAudioSink(
format, true /* offloadOnly */, hasVideo,
- AUDIO_OUTPUT_FLAG_NONE /* flags */, NULL /* isOffloaded */);
+ AUDIO_OUTPUT_FLAG_NONE /* flags */, NULL /* isOffloaded */, mSource->isStreaming());
if (err != OK) {
handleError(err);
}
@@ -173,9 +174,9 @@ sp<ABuffer> NuPlayer::DecoderPassThrough::aggregateBuffer(
size_t smallSize = accessUnit->size();
if ((mAggregateBuffer == NULL)
// Don't bother if only room for a few small buffers.
- && (smallSize < (kAggregateBufferSizeBytes / 3))) {
+ && (smallSize < (mAggregateBufferSizeBytes / 3))) {
// Create a larger buffer for combining smaller buffers from the extractor.
- mAggregateBuffer = new ABuffer(kAggregateBufferSizeBytes);
+ mAggregateBuffer = new ABuffer(mAggregateBufferSizeBytes);
mAggregateBuffer->setRange(0, 0); // start empty
}
@@ -201,6 +202,7 @@ sp<ABuffer> NuPlayer::DecoderPassThrough::aggregateBuffer(
if ((bigSize == 0) && smallTimestampValid) {
mAggregateBuffer->meta()->setInt64("timeUs", timeUs);
}
+ setPcmFormat(mAggregateBuffer->meta());
// Append small buffer to the bigger buffer.
memcpy(mAggregateBuffer->base() + bigSize, accessUnit->data(), smallSize);
bigSize += smallSize;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
index db33e87..629e266 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
@@ -43,25 +43,27 @@ protected:
virtual void onFlush();
virtual void onShutdown(bool notifyComplete);
virtual bool doRequestBuffers();
+ virtual void setPcmFormat(const sp<AMessage> & /*format*/) {}
+ virtual sp<ABuffer> aggregateBuffer(const sp<ABuffer> &accessUnit);
-private:
enum {
kWhatBufferConsumed = 'bufC',
};
sp<Source> mSource;
sp<Renderer> mRenderer;
+ size_t mAggregateBufferSizeBytes;
int64_t mSkipRenderingUntilMediaTimeUs;
bool mPaused;
-
- bool mReachedEOS;
+ bool mReachedEOS;
// Used by feedDecoderInputData to aggregate small buffers into
// one large buffer.
+ status_t mPendingAudioErr;
sp<ABuffer> mPendingAudioAccessUnit;
- status_t mPendingAudioErr;
sp<ABuffer> mAggregateBuffer;
+private:
// mPendingBuffersToDrain are only for debugging. It can be removed
// when the power investigation is done.
size_t mPendingBuffersToDrain;
@@ -72,7 +74,6 @@ private:
bool isDoneFetching() const;
status_t dequeueAccessUnit(sp<ABuffer> *accessUnit);
- sp<ABuffer> aggregateBuffer(const sp<ABuffer> &accessUnit);
status_t fetchInputData(sp<AMessage> &reply);
void doFlush(bool notifyComplete);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 7370224..a294d36 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -31,6 +31,9 @@
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
+#include "mediaplayerservice/AVNuExtensions.h"
+#include "mediaplayerservice/AVMediaServiceExtensions.h"
+
namespace android {
NuPlayerDriver::NuPlayerDriver(pid_t pid)
@@ -55,7 +58,7 @@ NuPlayerDriver::NuPlayerDriver(pid_t pid)
true, /* canCallJava */
PRIORITY_AUDIO);
- mPlayer = new NuPlayer(pid);
+ mPlayer = AVNuFactory::get()->createNuPlayer(pid);
mLooper->registerHandler(mPlayer);
mPlayer->setDriver(this);
@@ -114,6 +117,7 @@ status_t NuPlayerDriver::setDataSource(int fd, int64_t offset, int64_t length) {
mCondition.wait(mLock);
}
+ AVNuUtils::get()->printFileName(fd);
return mAsyncResult;
}
@@ -607,6 +611,8 @@ status_t NuPlayerDriver::getMetadata(
Metadata::kSeekAvailable,
mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK);
+ AVMediaServiceUtils::get()->appendMeta(&meta);
+
return OK;
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 776dba8..490a0d2 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -26,12 +26,15 @@
#include <media/stagefright/foundation/AUtils.h>
#include <media/stagefright/foundation/AWakeLock.h>
#include <media/stagefright/MediaClock.h>
+#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
#include <media/stagefright/VideoFrameScheduler.h>
#include <inttypes.h>
+#include "mediaplayerservice/AVNuExtensions.h"
+#include "stagefright/AVExtensions.h"
namespace android {
@@ -81,6 +84,16 @@ const NuPlayer::Renderer::PcmInfo NuPlayer::Renderer::AUDIO_PCMINFO_INITIALIZER
// static
const int64_t NuPlayer::Renderer::kMinPositionUpdateDelayUs = 100000ll;
+static bool sFrameAccurateAVsync = false;
+
+static void readProperties() {
+ char value[PROPERTY_VALUE_MAX];
+ if (property_get("persist.sys.media.avsync", value, NULL)) {
+ sFrameAccurateAVsync =
+ !strcmp("1", value) || !strcasecmp("true", value);
+ }
+}
+
NuPlayer::Renderer::Renderer(
const sp<MediaPlayerBase::AudioSink> &sink,
const sp<AMessage> &notify,
@@ -102,6 +115,7 @@ NuPlayer::Renderer::Renderer(
mVideoLateByUs(0ll),
mHasAudio(false),
mHasVideo(false),
+ mFoundAudioEOS(false),
mNotifyCompleteAudio(false),
mNotifyCompleteVideo(false),
mSyncQueues(false),
@@ -122,6 +136,7 @@ NuPlayer::Renderer::Renderer(
mMediaClock = new MediaClock;
mPlaybackRate = mPlaybackSettings.mSpeed;
mMediaClock->setPlaybackRate(mPlaybackRate);
+ readProperties();
}
NuPlayer::Renderer::~Renderer() {
@@ -312,7 +327,8 @@ void NuPlayer::Renderer::setVideoFrameRate(float fps) {
// Called on any threads.
status_t NuPlayer::Renderer::getCurrentPosition(int64_t *mediaUs) {
- return mMediaClock->getMediaTime(ALooper::GetNowUs(), mediaUs);
+ return mMediaClock->getMediaTime(
+ ALooper::GetNowUs(), mediaUs, (mHasAudio && mFoundAudioEOS));
}
void NuPlayer::Renderer::clearAudioFirstAnchorTime_l() {
@@ -348,18 +364,20 @@ status_t NuPlayer::Renderer::openAudioSink(
bool offloadOnly,
bool hasVideo,
uint32_t flags,
- bool *isOffloaded) {
+ bool *isOffloaded,
+ bool isStreaming) {
sp<AMessage> msg = new AMessage(kWhatOpenAudioSink, this);
msg->setMessage("format", format);
msg->setInt32("offload-only", offloadOnly);
msg->setInt32("has-video", hasVideo);
msg->setInt32("flags", flags);
+ msg->setInt32("isStreaming", isStreaming);
sp<AMessage> response;
- msg->postAndAwaitResponse(&response);
+ status_t postStatus = msg->postAndAwaitResponse(&response);
int32_t err;
- if (!response->findInt32("err", &err)) {
+ if (postStatus != OK || !response->findInt32("err", &err)) {
err = INVALID_OPERATION;
} else if (err == OK && isOffloaded != NULL) {
int32_t offload;
@@ -392,7 +410,10 @@ void NuPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) {
uint32_t flags;
CHECK(msg->findInt32("flags", (int32_t *)&flags));
- status_t err = onOpenAudioSink(format, offloadOnly, hasVideo, flags);
+ uint32_t isStreaming;
+ CHECK(msg->findInt32("isStreaming", (int32_t *)&isStreaming));
+
+ status_t err = onOpenAudioSink(format, offloadOnly, hasVideo, flags, isStreaming);
sp<AMessage> response = new AMessage;
response->setInt32("err", err);
@@ -435,9 +456,10 @@ void NuPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) {
if (onDrainAudioQueue()) {
uint32_t numFramesPlayed;
- CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed),
- (status_t)OK);
-
+ if (mAudioSink->getPosition(&numFramesPlayed) != OK) {
+ ALOGW("mAudioSink->getPosition failed");
+ break;
+ }
uint32_t numFramesPendingPlayout =
mNumFramesWritten - numFramesPlayed;
@@ -1074,6 +1096,11 @@ void NuPlayer::Renderer::postDrainVideoQueue() {
ALOGW_IF(delayUs > 500000, "unusually high delayUs: %" PRId64, delayUs);
// post 2 display refreshes before rendering is due
+ // FIXME currently this increases power consumption, so unless frame-accurate
+ // AV sync is requested, post closer to required render time (at 0.63 vsyncs)
+ if (!sFrameAccurateAVsync) {
+ twoVsyncsUs >>= 4;
+ }
msg->post(delayUs > twoVsyncsUs ? delayUs - twoVsyncsUs : 0);
mDrainVideoQueuePending = true;
@@ -1164,6 +1191,9 @@ void NuPlayer::Renderer::notifyVideoRenderingStart() {
}
void NuPlayer::Renderer::notifyEOS(bool audio, status_t finalResult, int64_t delayUs) {
+ if (audio) {
+ mFoundAudioEOS = true;
+ }
sp<AMessage> notify = mNotify->dup();
notify->setInt32("what", kWhatEOS);
notify->setInt32("audio", static_cast<int32_t>(audio));
@@ -1479,6 +1509,7 @@ void NuPlayer::Renderer::onPause() {
mDrainAudioQueuePending = false;
mDrainVideoQueuePending = false;
+ mVideoRenderingStarted = false; // force-notify NOTE_INFO MEDIA_INFO_RENDERING_START after resume
if (mHasAudio) {
mAudioSink->pause();
@@ -1490,15 +1521,18 @@ void NuPlayer::Renderer::onPause() {
}
void NuPlayer::Renderer::onResume() {
+ readProperties();
+
if (!mPaused) {
return;
}
if (mHasAudio) {
+ status_t status = NO_ERROR;
cancelAudioOffloadPauseTimeout();
- status_t err = mAudioSink->start();
- if (err != OK) {
- ALOGE("cannot start AudioSink err %d", err);
+ status = mAudioSink->start();
+ if (offloadingAudio() && status != NO_ERROR && status != INVALID_OPERATION) {
+ ALOGD("received error :%d on resume for offload track posting TEAR_DOWN event",status);
notifyAudioTearDown();
}
}
@@ -1559,6 +1593,7 @@ int64_t NuPlayer::Renderer::getPlayedOutAudioDurationUs(int64_t nowUs) {
int64_t numFramesPlayedAt;
AudioTimestamp ts;
static const int64_t kStaleTimestamp100ms = 100000;
+ int64_t durationUs;
status_t res = mAudioSink->getTimestamp(ts);
if (res == OK) { // case 1: mixing audio tracks and offloaded tracks.
@@ -1585,14 +1620,20 @@ int64_t NuPlayer::Renderer::getPlayedOutAudioDurationUs(int64_t nowUs) {
// numFramesPlayed, (long long)numFramesPlayedAt);
} else { // case 3: transitory at new track or audio fast tracks.
res = mAudioSink->getPosition(&numFramesPlayed);
- CHECK_EQ(res, (status_t)OK);
- numFramesPlayedAt = nowUs;
- numFramesPlayedAt += 1000LL * mAudioSink->latency() / 2; /* XXX */
+ if (res != OK) {
+ //query to getPosition fails, use media clock to simulate render position
+ getCurrentPosition(&durationUs);
+ durationUs = durationUs - mAnchorTimeMediaUs;
+ return durationUs;
+ } else {
+ numFramesPlayedAt = nowUs;
+ numFramesPlayedAt += 1000LL * mAudioSink->latency() / 2; /* XXX */
+ }
//ALOGD("getPosition: %u %lld", numFramesPlayed, (long long)numFramesPlayedAt);
}
//CHECK_EQ(numFramesPlayed & (1 << 31), 0); // can't be negative until 12.4 hrs, test
- int64_t durationUs = getDurationUsIfPlayedAtSampleRate(numFramesPlayed)
+ durationUs = getDurationUsIfPlayedAtSampleRate(numFramesPlayed)
+ nowUs - numFramesPlayedAt;
if (durationUs < 0) {
// Occurs when numFramesPlayed position is very small and the following:
@@ -1650,7 +1691,8 @@ status_t NuPlayer::Renderer::onOpenAudioSink(
const sp<AMessage> &format,
bool offloadOnly,
bool hasVideo,
- uint32_t flags) {
+ uint32_t flags,
+ bool isStreaming) {
ALOGV("openAudioSink: offloadOnly(%d) offloadingAudio(%d)",
offloadOnly, offloadingAudio());
bool audioSinkChanged = false;
@@ -1664,13 +1706,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) {
@@ -1678,22 +1724,34 @@ status_t NuPlayer::Renderer::onOpenAudioSink(
"audio_format", mime.c_str());
onDisableOffloadAudio();
} else {
- 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
&& format->findInt32("aac-profile", &aacProfile)) {
// Redefine AAC format as per aac profile
- mapAACProfileToAudioFormat(
- audioFormat,
- aacProfile);
+ int32_t isADTSSupported;
+ isADTSSupported = AVUtils::get()->mapAACProfileToAudioFormat(format,
+ audioFormat,
+ aacProfile);
+ if (!isADTSSupported) {
+ mapAACProfileToAudioFormat(audioFormat,
+ aacProfile);
+ } else {
+ ALOGV("Format is AAC ADTS\n");
+ }
}
+ int32_t offloadBufferSize =
+ AVUtils::get()->getAudioMaxInputBufferSize(
+ audioFormat,
+ format);
audio_offload_info_t offloadInfo = AUDIO_INFO_INITIALIZER;
+
offloadInfo.duration_us = -1;
format->findInt64(
"durationUs", &offloadInfo.duration_us);
@@ -1703,7 +1761,9 @@ status_t NuPlayer::Renderer::onOpenAudioSink(
offloadInfo.stream_type = AUDIO_STREAM_MUSIC;
offloadInfo.bit_rate = avgBitRate;
offloadInfo.has_video = hasVideo;
- offloadInfo.is_streaming = true;
+ offloadInfo.is_streaming = isStreaming;
+ offloadInfo.bit_width = bitWidth;
+ offloadInfo.offload_buffer_size = offloadBufferSize;
if (memcmp(&mCurrentOffloadInfo, &offloadInfo, sizeof(offloadInfo)) == 0) {
ALOGV("openAudioSink: no change in offload mode");
@@ -1767,7 +1827,7 @@ status_t NuPlayer::Renderer::onOpenAudioSink(
const PcmInfo info = {
(audio_channel_mask_t)channelMask,
(audio_output_flags_t)pcmFlags,
- AUDIO_FORMAT_PCM_16_BIT, // TODO: change to audioFormat
+ AVNuUtils::get()->getPCMFormat(format),
numChannels,
sampleRate
};
@@ -1802,7 +1862,7 @@ status_t NuPlayer::Renderer::onOpenAudioSink(
sampleRate,
numChannels,
(audio_channel_mask_t)channelMask,
- AUDIO_FORMAT_PCM_16_BIT,
+ AVNuUtils::get()->getPCMFormat(format),
0 /* bufferCount - unused */,
mUseAudioCallback ? &NuPlayer::Renderer::AudioSinkCallback : NULL,
mUseAudioCallback ? this : NULL,
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index 87bcbf9..50bd0a9 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -73,12 +73,15 @@ struct NuPlayer::Renderer : public AHandler {
status_t getCurrentPosition(int64_t *mediaUs);
int64_t getVideoLateByUs();
+ virtual audio_stream_type_t getAudioStreamType(){return AUDIO_STREAM_DEFAULT;}
+
status_t openAudioSink(
const sp<AMessage> &format,
bool offloadOnly,
bool hasVideo,
uint32_t flags,
- bool *isOffloaded);
+ bool *isOffloaded,
+ bool isStreaming);
void closeAudioSink();
enum {
@@ -101,7 +104,6 @@ protected:
virtual void onMessageReceived(const sp<AMessage> &msg);
-private:
enum {
kWhatDrainAudioQueue = 'draA',
kWhatDrainVideoQueue = 'draV',
@@ -162,6 +164,7 @@ private:
int64_t mVideoLateByUs;
bool mHasAudio;
bool mHasVideo;
+ bool mFoundAudioEOS;
bool mNotifyCompleteAudio;
bool mNotifyCompleteVideo;
@@ -228,7 +231,7 @@ private:
void prepareForMediaRenderingStart_l();
void notifyIfMediaRenderingStarted_l();
- void onQueueBuffer(const sp<AMessage> &msg);
+ virtual void onQueueBuffer(const sp<AMessage> &msg);
void onQueueEOS(const sp<AMessage> &msg);
void onFlush(const sp<AMessage> &msg);
void onAudioSinkChanged();
@@ -250,7 +253,8 @@ private:
const sp<AMessage> &format,
bool offloadOnly,
bool hasVideo,
- uint32_t flags);
+ uint32_t flags,
+ bool isStreaming);
void onCloseAudioSink();
void notifyEOS(bool audio, status_t finalResult, int64_t delayUs = 0);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
index 11a6a9f..b248316 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 {
@@ -57,6 +58,7 @@ struct NuPlayer::Source : public AHandler {
kWhatQueueDecoderShutdown,
kWhatDrmNoLicense,
kWhatInstantiateSecureDecoders,
+ kWhatRTCPByeReceived,
};
// The provides message is used to notify the player about various
@@ -132,10 +134,10 @@ protected:
void notifyFlagsChanged(uint32_t flags);
void notifyVideoSizeChanged(const sp<AMessage> &format = NULL);
void notifyInstantiateSecureDecoders(const sp<AMessage> &reply);
- void notifyPrepared(status_t err = OK);
+ virtual void notifyPrepared(status_t err = OK);
-private:
sp<AMessage> mNotify;
+private:
DISALLOW_EVIL_CONSTRUCTORS(Source);
};
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index af0351e..35567a5 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -27,6 +27,7 @@
#include <media/IMediaHTTPService.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
+#include <mediaplayerservice/AVMediaServiceExtensions.h>
namespace android {
@@ -131,6 +132,10 @@ void NuPlayer::RTSPSource::pause() {
// Check if EOS or ERROR is received
if (source != NULL && source->isFinished(mediaDurationUs)) {
+ if (mHandler != NULL) {
+ ALOGI("Nearing EOS...No Pause is issued");
+ mHandler->cancelTimeoutCheck();
+ }
return;
}
}
@@ -476,8 +481,11 @@ void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
if (!info->mNPTMappingValid) {
// This is a live stream, we didn't receive any normal
// playtime mapping. We won't map to npt time.
- source->queueAccessUnit(accessUnit);
- break;
+ if (!AVMediaServiceUtils::get()->checkNPTMapping(&info->mRTPTime,
+ &info->mNormalPlaytimeUs, &info->mNPTMappingValid, rtpTime)) {
+ source->queueAccessUnit(accessUnit);
+ break;
+ }
}
int64_t nptUs =
@@ -563,6 +571,14 @@ void NuPlayer::RTSPSource::onMessageReceived(const sp<AMessage> &msg) {
break;
}
+ case MyHandler::kWhatByeReceived:
+ {
+ sp<AMessage> msg = dupNotify();
+ msg->setInt32("what", kWhatRTCPByeReceived);
+ msg->post();
+ break;
+ }
+
case SDPLoader::kWhatSDPLoaded:
{
onSDPLoaded(msg);
diff --git a/media/libstagefright/AACExtractor.cpp b/media/libstagefright/AACExtractor.cpp
index 45e8a30..1353e3f 100644
--- a/media/libstagefright/AACExtractor.cpp
+++ b/media/libstagefright/AACExtractor.cpp
@@ -136,7 +136,8 @@ AACExtractor::AACExtractor(
const sp<DataSource> &source, const sp<AMessage> &_meta)
: mDataSource(source),
mInitCheck(NO_INIT),
- mFrameDurationUs(0) {
+ mFrameDurationUs(0),
+ mApeMeta(new MetaData) {
sp<AMessage> 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<MetaData> AACExtractor::getMetaData() {
- sp<MetaData> 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 8d9bd21..a81bca5 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -44,6 +44,8 @@
#include <media/stagefright/OMXCodec.h>
#include <media/stagefright/PersistentSurface.h>
#include <media/stagefright/SurfaceUtils.h>
+#include <media/stagefright/FFMPEGSoftCodec.h>
+
#include <media/hardware/HardwareAPI.h>
#include <OMX_AudioExt.h>
@@ -54,6 +56,8 @@
#include "include/avc_utils.h"
+#include <stagefright/AVExtensions.h>
+
namespace android {
// OMX errors are directly mapped into status_t range if
@@ -539,6 +543,15 @@ ACodec::ACodec()
ACodec::~ACodec() {
}
+status_t ACodec::setupCustomCodec(status_t err, const char *mime, const sp<AMessage> &msg) {
+ if (!strncmp(mComponentName.c_str(), "OMX.ffmpeg.", 11) && !mIsEncoder) {
+ return FFMPEGSoftCodec::setAudioFormat(
+ msg, mime, mOMX, mNode);
+ }
+
+ return err;
+}
+
void ACodec::setNotificationMessage(const sp<AMessage> &msg) {
mNotify = msg;
}
@@ -613,8 +626,8 @@ void ACodec::initiateShutdown(bool keepComponentAllocated) {
msg->setInt32("keepComponentAllocated", keepComponentAllocated);
msg->post();
if (!keepComponentAllocated) {
- // ensure shutdown completes in 3 seconds
- (new AMessage(kWhatReleaseCodecInstance, this))->post(3000000);
+ // ensure shutdown completes in 30 seconds
+ (new AMessage(kWhatReleaseCodecInstance, this))->post(30000000);
}
}
@@ -828,15 +841,11 @@ status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) {
: OMXCodec::kRequiresAllocateBufferOnOutputPorts;
if ((portIndex == kPortIndexInput && (mFlags & kFlagIsSecure))
- || (portIndex == kPortIndexOutput && usingMetadataOnEncoderOutput())) {
+ || (portIndex == kPortIndexOutput && usingMetadataOnEncoderOutput())
+ || canAllocateBuffer(portIndex)) {
mem.clear();
- void *ptr;
- err = mOMX->allocateBuffer(
- mNode, portIndex, bufSize, &info.mBufferID,
- &ptr);
-
- info.mData = new ABuffer(ptr, bufSize);
+ err = allocateBuffer(portIndex, bufSize, info);
} else if (mQuirks & requiresAllocateBufferBit) {
err = mOMX->allocateBufferWithBackup(
mNode, portIndex, mem, &info.mBufferID, allottedSize);
@@ -1587,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 =
@@ -1639,6 +1652,8 @@ status_t ACodec::configureCodec(
return err;
}
+ enableCustomAllocationMode(msg);
+
int32_t bitRate = 0;
// FLAC encoder doesn't need a bitrate, other encoders do
if (encoder && strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC)
@@ -1906,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;
}
@@ -1991,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;
@@ -2069,7 +2087,7 @@ status_t ACodec::configureCodec(
}
err = setupG711Codec(encoder, sampleRate, numChannels);
}
- } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC)) {
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC) && encoder) {
int32_t numChannels = 0, sampleRate = 0, compressionLevel = -1;
if (encoder &&
(!msg->findInt32("channel-count", &numChannels)
@@ -2105,16 +2123,21 @@ status_t ACodec::configureCodec(
|| !msg->findInt32("sample-rate", &sampleRate)) {
err = INVALID_OPERATION;
} else {
- err = setupRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
+ int32_t bitsPerSample = 16;
+ msg->findInt32("bit-width", &bitsPerSample);
+ err = setupRawAudioFormat(kPortIndexInput, sampleRate, numChannels, bitsPerSample);
}
- } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AC3)) {
+ } else if (!strncmp(mComponentName.c_str(), "OMX.google.", 11)
+ && !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AC3)) {
int32_t numChannels;
int32_t sampleRate;
if (!msg->findInt32("channel-count", &numChannels)
|| !msg->findInt32("sample-rate", &sampleRate)) {
err = INVALID_OPERATION;
} else {
- err = setupAC3Codec(encoder, numChannels, sampleRate);
+ int32_t bitsPerSample = 16;
+ msg->findInt32("bit-width", &bitsPerSample);
+ err = setupAC3Codec(encoder, numChannels, sampleRate, bitsPerSample);
}
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_EAC3)) {
int32_t numChannels;
@@ -2123,8 +2146,12 @@ 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);
}
if (err != OK) {
@@ -2438,9 +2465,9 @@ status_t ACodec::setupAACCodec(
}
status_t ACodec::setupAC3Codec(
- bool encoder, int32_t numChannels, int32_t sampleRate) {
+ bool encoder, int32_t numChannels, int32_t sampleRate, int32_t bitsPerSample) {
status_t err = setupRawAudioFormat(
- encoder ? kPortIndexInput : kPortIndexOutput, sampleRate, numChannels);
+ encoder ? kPortIndexInput : kPortIndexOutput, sampleRate, numChannels, bitsPerSample);
if (err != OK) {
return err;
@@ -2476,9 +2503,9 @@ status_t ACodec::setupAC3Codec(
}
status_t ACodec::setupEAC3Codec(
- bool encoder, int32_t numChannels, int32_t sampleRate) {
+ bool encoder, int32_t numChannels, int32_t sampleRate, int32_t bitsPerSample) {
status_t err = setupRawAudioFormat(
- encoder ? kPortIndexInput : kPortIndexOutput, sampleRate, numChannels);
+ encoder ? kPortIndexInput : kPortIndexOutput, sampleRate, numChannels, bitsPerSample);
if (err != OK) {
return err;
@@ -2624,7 +2651,7 @@ status_t ACodec::setupFlacCodec(
}
status_t ACodec::setupRawAudioFormat(
- OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels) {
+ OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels, int32_t bitsPerSample) {
OMX_PARAM_PORTDEFINITIONTYPE def;
InitOMXParams(&def);
def.nPortIndex = portIndex;
@@ -2659,7 +2686,7 @@ status_t ACodec::setupRawAudioFormat(
pcmParams.nChannels = numChannels;
pcmParams.eNumData = OMX_NumericalDataSigned;
pcmParams.bInterleaved = OMX_TRUE;
- pcmParams.nBitPerSample = 16;
+ pcmParams.nBitPerSample = bitsPerSample;
pcmParams.nSamplingRate = sampleRate;
pcmParams.ePCMMode = OMX_AUDIO_PCMModeLinear;
@@ -2835,13 +2862,14 @@ static const struct VideoCodingMapEntry {
{ MEDIA_MIMETYPE_VIDEO_AVC, OMX_VIDEO_CodingAVC },
{ MEDIA_MIMETYPE_VIDEO_HEVC, OMX_VIDEO_CodingHEVC },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, OMX_VIDEO_CodingMPEG4 },
+ { MEDIA_MIMETYPE_VIDEO_MPEG4_DP, OMX_VIDEO_CodingMPEG4 },
{ MEDIA_MIMETYPE_VIDEO_H263, OMX_VIDEO_CodingH263 },
{ MEDIA_MIMETYPE_VIDEO_MPEG2, OMX_VIDEO_CodingMPEG2 },
{ MEDIA_MIMETYPE_VIDEO_VP8, OMX_VIDEO_CodingVP8 },
{ MEDIA_MIMETYPE_VIDEO_VP9, OMX_VIDEO_CodingVP9 },
};
-static status_t GetVideoCodingTypeFromMime(
+status_t ACodec::GetVideoCodingTypeFromMime(
const char *mime, OMX_VIDEO_CODINGTYPE *codingType) {
for (size_t i = 0;
i < sizeof(kVideoCodingMapEntry) / sizeof(kVideoCodingMapEntry[0]);
@@ -2885,7 +2913,13 @@ status_t ACodec::setupVideoDecoder(
status_t err = GetVideoCodingTypeFromMime(mime, &compressionFormat);
if (err != OK) {
- return err;
+ if (!strncmp(mComponentName.c_str(), "OMX.ffmpeg.", 11)) {
+ err = FFMPEGSoftCodec::setVideoFormat(
+ msg, mime, mOMX, mNode, mIsEncoder, &compressionFormat);
+ }
+ if (err != OK) {
+ return err;
+ }
}
err = setVideoPortFormatType(
@@ -3035,7 +3069,14 @@ status_t ACodec::setupVideoEncoder(const char *mime, const sp<AMessage> &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(
@@ -3228,6 +3269,7 @@ status_t ACodec::setupMPEG4EncoderParameters(const sp<AMessage> &msg) {
mpeg4type.eLevel = static_cast<OMX_VIDEO_MPEG4LEVELTYPE>(level);
}
+ setBFrames(&mpeg4type);
err = mOMX->setParameter(
mNode, OMX_IndexParamVideoMpeg4, &mpeg4type, sizeof(mpeg4type));
@@ -3425,6 +3467,8 @@ status_t ACodec::setupAVCEncoderParameters(const sp<AMessage> &msg) {
err = verifySupportForProfileAndLevel(profile, level);
if (err != OK) {
+ ALOGE("%s does not support profile %x @ level %x",
+ mComponentName.c_str(), profile, level);
return err;
}
@@ -3433,11 +3477,14 @@ status_t ACodec::setupAVCEncoderParameters(const sp<AMessage> &msg) {
}
// XXX
+ // Allow higher profiles to be set since the encoder seems to support
+#if 0
if (h264type.eProfile != OMX_VIDEO_AVCProfileBaseline) {
ALOGW("Use baseline profile instead of %d for AVC recording",
h264type.eProfile);
h264type.eProfile = OMX_VIDEO_AVCProfileBaseline;
}
+#endif
if (h264type.eProfile == OMX_VIDEO_AVCProfileBaseline) {
h264type.nSliceHeaderSpacing = 0;
@@ -3458,6 +3505,7 @@ status_t ACodec::setupAVCEncoderParameters(const sp<AMessage> &msg) {
h264type.nCabacInitIdc = 0;
}
+ setBFrames(&h264type, iFrameInterval, frameRate);
if (h264type.nBFrames != 0) {
h264type.nAllowedPictureTypes |= OMX_VIDEO_PictureTypeB;
}
@@ -3498,6 +3546,8 @@ status_t ACodec::setupHEVCEncoderParameters(const sp<AMessage> &msg) {
frameRate = (float)tmp;
}
+ AVUtils::get()->setIntraPeriod(setPFramesSpacing(iFrameInterval, frameRate), 0, mOMX, mNode);
+
OMX_VIDEO_PARAM_HEVCTYPE hevcType;
InitOMXParams(&hevcType);
hevcType.nPortIndex = kPortIndexOutput;
@@ -4134,6 +4184,14 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp<AMessage> &notify) {
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)",
@@ -4179,7 +4237,10 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp<AMessage> &notify) {
if (params.nChannels <= 0
|| (params.nChannels != 1 && !params.bInterleaved)
- || params.nBitPerSample != 16u
+ || (params.nBitPerSample != 16u
+ && 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 ",
@@ -4194,6 +4255,7 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp<AMessage> &notify) {
notify->setString("mime", MEDIA_MIMETYPE_AUDIO_RAW);
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);
@@ -4244,6 +4306,7 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp<AMessage> &notify) {
case OMX_AUDIO_CodingFLAC:
{
+ if (portIndex == kPortIndexInput) {
OMX_AUDIO_PARAM_FLACTYPE params;
InitOMXParams(&params);
params.nPortIndex = portIndex;
@@ -4258,6 +4321,7 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp<AMessage> &notify) {
notify->setInt32("channel-count", params.nChannels);
notify->setInt32("sample-rate", params.nSampleRate);
break;
+ }
}
case OMX_AUDIO_CodingMP3:
@@ -4398,6 +4462,14 @@ status_t ACodec::getPortFormat(OMX_U32 portIndex, sp<AMessage> &notify) {
}
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;
@@ -4448,6 +4520,8 @@ void ACodec::sendFormatChange(const sp<AMessage> &reply) {
mEncoderPadding * frameSize);
}
+ getVQZIPInfo(notify);
+
notify->post();
mSentFormat = true;
@@ -4596,6 +4670,7 @@ bool ACodec::BaseState::onMessageReceived(const sp<AMessage> &msg) {
ALOGI("[%s] forcing the release of codec",
mCodec->mComponentName.c_str());
status_t err = mCodec->mOMX->freeNode(mCodec->mNode);
+ mCodec->changeState(mCodec->mUninitializedState);
ALOGE_IF("[%s] failed to release codec instance: err=%d",
mCodec->mComponentName.c_str(), err);
sp<AMessage> notify = mCodec->mNotify->dup();
@@ -5180,6 +5255,7 @@ bool ACodec::BaseState::onOMXFillBufferDone(
mCodec->mSkipCutBuffer->submit(info->mData);
}
info->mData->meta()->setInt64("timeUs", timeUs);
+ info->mData->meta()->setObject("graphic-buffer", info->mGraphicBuffer);
sp<AMessage> notify = mCodec->mNotify->dup();
notify->setInt32("what", CodecBase::kWhatDrainThisBuffer);
@@ -5189,6 +5265,8 @@ bool ACodec::BaseState::onOMXFillBufferDone(
reply->setInt32("buffer-id", info->mBufferID);
+ (void)mCodec->setDSModeHint(reply, flags, timeUs);
+
notify->setMessage("reply", reply);
notify->post();
@@ -5243,8 +5321,9 @@ void ACodec::BaseState::onOutputBufferDrained(const sp<AMessage> &msg) {
ALOGW_IF(err != NO_ERROR, "failed to set crop: %d", err);
}
+ bool skip = mCodec->getDSModeHint(msg);
int32_t render;
- if (mCodec->mNativeWindow != NULL
+ if (!skip && mCodec->mNativeWindow != NULL
&& msg->findInt32("render", &render) && render != 0
&& info->mData != NULL && info->mData->size() != 0) {
ATRACE_NAME("render");
@@ -5690,13 +5769,85 @@ 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<OMXCodec::CodecNameAndQuirks> 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<CodecObserver> 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<AMessage> 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;
+ }
+ }
}
{
sp<AMessage> notify = mCodec->mNotify->dup();
notify->setInt32("what", CodecBase::kWhatComponentConfigured);
+ notify->setString("componentName", mCodec->mComponentName.c_str());
notify->setMessage("input-format", mCodec->mInputFormat);
notify->setMessage("output-format", mCodec->mOutputFormat);
notify->post();
@@ -6359,6 +6510,23 @@ void ACodec::onSignalEndOfInputStream() {
notify->post();
}
+sp<IOMXObserver> ACodec::createObserver() {
+ sp<CodecObserver> observer = new CodecObserver;
+ sp<AMessage> notify = new AMessage(kWhatOMXMessageList, this);
+ observer->setNotificationMessage(notify);
+ return observer;
+}
+
+status_t ACodec::allocateBuffer(
+ OMX_U32 portIndex, size_t bufSize, BufferInfo &info) {
+ void *ptr;
+ status_t err = mOMX->allocateBuffer(
+ mNode, portIndex, bufSize, &info.mBufferID, &ptr);
+
+ info.mData = new ABuffer(ptr, bufSize);
+ return err;
+}
+
bool ACodec::ExecutingState::onOMXFrameRendered(int64_t mediaTimeUs, nsecs_t systemNano) {
mCodec->onFrameRendered(mediaTimeUs, systemNano);
return true;
diff --git a/media/libstagefright/APE.cpp b/media/libstagefright/APE.cpp
new file mode 100644
index 0000000..74ca7dc
--- /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 <utils/Log.h>
+
+#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<DataSource> &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<DataSource> &source, off64_t offset,
+ sp<MetaData> &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 2529aa7..725789a 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -69,9 +69,12 @@ LOCAL_SRC_FILES:= \
WVMExtractor.cpp \
XINGSeeker.cpp \
avc_utils.cpp \
+ APE.cpp \
+ FFMPEGSoftCodec.cpp \
LOCAL_C_INCLUDES:= \
$(TOP)/frameworks/av/include/media/ \
+ $(TOP)/frameworks/av/media/libavextensions \
$(TOP)/frameworks/av/include/media/stagefright/timedtext \
$(TOP)/frameworks/native/include/media/hardware \
$(TOP)/frameworks/native/include/media/openmax \
@@ -104,7 +107,7 @@ LOCAL_SHARED_LIBRARIES := \
libutils \
libvorbisidec \
libz \
- libpowermanager
+ libpowermanager \
LOCAL_STATIC_LIBRARIES := \
libstagefright_color_conversion \
@@ -120,6 +123,30 @@ LOCAL_STATIC_LIBRARIES := \
libFLAC \
libmedia_helper \
+LOCAL_WHOLE_STATIC_LIBRARIES := libavextensions
+
+ifeq ($(BOARD_USE_S3D_SUPPORT), true)
+ifeq ($(BOARD_USES_HWC_SERVICES), true)
+LOCAL_CFLAGS += -DUSE_S3D_SUPPORT -DHWC_SERVICES
+LOCAL_C_INCLUDES += \
+ $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include \
+ $(TOP)/hardware/samsung_slsi/openmax/include/exynos \
+ $(TOP)/hardware/samsung_slsi/$(TARGET_BOARD_PLATFORM)-insignal/libhwcService \
+ $(TOP)/hardware/samsung_slsi/$(TARGET_BOARD_PLATFORM)-insignal/libhwc \
+ $(TOP)/hardware/samsung_slsi/$(TARGET_BOARD_PLATFORM)-insignal/include \
+ $(TOP)/hardware/samsung_slsi/$(TARGET_SOC)/libhwcmodule \
+ $(TOP)/hardware/samsung_slsi/$(TARGET_SOC)/include \
+ $(TOP)/hardware/samsung_slsi/exynos/libexynosutils \
+ $(TOP)/hardware/samsung_slsi/exynos/include
+
+LOCAL_ADDITIONAL_DEPENDENCIES := \
+ $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+
+LOCAL_SHARED_LIBRARIES += \
+ libExynosHWCService
+endif
+endif
+
LOCAL_SHARED_LIBRARIES += \
libstagefright_enc_common \
libstagefright_avc_common \
@@ -136,6 +163,17 @@ endif
LOCAL_CLANG := true
+ifeq ($(BOARD_USE_SAMSUNG_CAMERAFORMAT_NV21), true)
+# This needs flag requires the following string constant in
+# CameraParametersExtra.h:
+#
+# const char CameraParameters::PIXEL_FORMAT_YUV420SP_NV21[] = "nv21";
+LOCAL_CFLAGS += -DUSE_SAMSUNG_CAMERAFORMAT_NV21
+endif
+
+# FFMPEG plugin
+LOCAL_C_INCLUDES += $(TOP)/external/stagefright-plugins/include
+
LOCAL_MODULE:= libstagefright
LOCAL_MODULE_TAGS := optional
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index 6e4a1dd..dc9c37b 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -61,7 +61,7 @@ AudioSource::AudioSource(
mNumClientOwnedBuffers(0) {
ALOGV("sampleRate: %u, outSampleRate: %u, channelCount: %u",
sampleRate, outSampleRate, channelCount);
- CHECK(channelCount == 1 || channelCount == 2);
+ CHECK(channelCount == 1 || channelCount == 2 || channelCount == 6);
CHECK(sampleRate > 0);
size_t minFrameCount;
@@ -124,6 +124,8 @@ status_t AudioSource::start(MetaData *params) {
int64_t startTimeUs;
if (params && params->findInt64(kKeyTime, &startTimeUs)) {
mStartTimeUs = startTimeUs;
+ } else {
+ mStartTimeUs = systemTime() / 1000ll;
}
status_t err = mRecord->start();
if (err == OK) {
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 66280da..aea0f13 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -33,6 +33,8 @@
#include <utils/String8.h>
#include <cutils/properties.h>
+#include <stagefright/AVExtensions.h>
+
#if LOG_NDEBUG
#define UNUSED_UNLESS_VERBOSE(x) (void)(x)
#else
@@ -98,6 +100,11 @@ void CameraSourceListener::postDataTimestamp(
}
static int32_t getColorFormat(const char* colorFormat) {
+ if (!colorFormat) {
+ ALOGE("Invalid color format");
+ return -1;
+ }
+
if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV420P)) {
return OMX_COLOR_FormatYUV420Planar;
}
@@ -110,6 +117,13 @@ static int32_t getColorFormat(const char* colorFormat) {
return OMX_COLOR_FormatYUV420SemiPlanar;
}
+#ifdef USE_SAMSUNG_CAMERAFORMAT_NV21
+ if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV420SP_NV21)) {
+ static const int OMX_SEC_COLOR_FormatNV21Linear = 0x7F000011;
+ return OMX_SEC_COLOR_FormatNV21Linear;
+ }
+#endif /* USE_SAMSUNG_CAMERAFORMAT_NV21 */
+
if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV422I)) {
return OMX_COLOR_FormatYCbYCr;
}
@@ -298,6 +312,12 @@ status_t CameraSource::isCameraColorFormatSupported(
return OK;
}
+static int32_t getHighSpeedFrameRate(const CameraParameters& params) {
+ const char* hsr = params.get("video-hsr");
+ int32_t rate = (hsr != NULL && strncmp(hsr, "off", 3)) ? atoi(hsr) : 0;
+ return rate > 240 ? 240 : rate;
+}
+
/*
* Configure the camera to use the requested video size
* (width and height) and/or frame rate. If both width and
@@ -350,6 +370,10 @@ status_t CameraSource::configureCamera(
params->get(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES);
CHECK(supportedFrameRates != NULL);
ALOGV("Supported frame rates: %s", supportedFrameRates);
+ if (getHighSpeedFrameRate(*params)) {
+ ALOGI("Use default 30fps for HighSpeed %dfps", frameRate);
+ frameRate = 30;
+ }
char buf[4];
snprintf(buf, 4, "%d", frameRate);
if (strstr(supportedFrameRates, buf) == NULL) {
@@ -451,6 +475,8 @@ status_t CameraSource::checkFrameRate(
ALOGE("Failed to retrieve preview frame rate (%d)", frameRateActual);
return UNKNOWN_ERROR;
}
+ int32_t highSpeedRate = getHighSpeedFrameRate(params);
+ frameRateActual = highSpeedRate ? highSpeedRate : frameRateActual;
// Check the actual video frame rate against the target/requested
// video frame rate.
@@ -575,6 +601,8 @@ status_t CameraSource::initWithCameraAccess(
mMeta->setInt32(kKeyStride, mVideoSize.width);
mMeta->setInt32(kKeySliceHeight, mVideoSize.height);
mMeta->setInt32(kKeyFrameRate, mVideoFrameRate);
+ AVUtils::get()->extractCustomCameraKeys(params, mMeta);
+
return OK;
}
diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp
index 0acd9d0..926e95c 100644
--- a/media/libstagefright/CameraSourceTimeLapse.cpp
+++ b/media/libstagefright/CameraSourceTimeLapse.cpp
@@ -279,7 +279,8 @@ bool CameraSourceTimeLapse::skipFrameAndModifyTimeStamp(int64_t *timestampUs) {
// The first 2 output frames from the encoder are: decoder specific info and
// the compressed video frame data for the first input video frame.
if (mNumFramesEncoded >= 1 && *timestampUs <
- (mLastTimeLapseFrameRealTimestampUs + mTimeBetweenFrameCaptureUs)) {
+ (mLastTimeLapseFrameRealTimestampUs + mTimeBetweenFrameCaptureUs) &&
+ (mTimeBetweenFrameCaptureUs > mTimeBetweenTimeLapseVideoFramesUs + 1)) {
// Skip all frames from last encoded frame until
// sufficient time (mTimeBetweenFrameCaptureUs) has passed.
// Tell the camera to release its recording frame and return.
@@ -294,6 +295,12 @@ bool CameraSourceTimeLapse::skipFrameAndModifyTimeStamp(int64_t *timestampUs) {
mLastTimeLapseFrameRealTimestampUs = *timestampUs;
*timestampUs = mLastFrameTimestampUs + mTimeBetweenTimeLapseVideoFramesUs;
+ // Update start-time once the captured-time reaches the expected start-time.
+ // Not doing so will result in CameraSource always dropping frames since
+ // updated-timestamp will never intersect start-timestamp
+ if ((mNumFramesReceived == 0 && mLastTimeLapseFrameRealTimestampUs >= mStartTimeUs)) {
+ mStartTimeUs = *timestampUs;
+ }
return false;
}
return false;
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index 5020c6c..2df045f 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -47,9 +47,28 @@
#include <utils/String8.h>
#include <cutils/properties.h>
+#include <cutils/log.h>
+
+#include <dlfcn.h>
+
+#include <stagefright/AVExtensions.h>
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;
@@ -110,29 +129,49 @@ status_t DataSource::getSize(off64_t *size) {
////////////////////////////////////////////////////////////////////////////////
-Mutex DataSource::gSnifferMutex;
-List<DataSource::SnifferFunc> DataSource::gSniffers;
-bool DataSource::gSniffersRegistered = false;
-
bool DataSource::sniff(
String8 *mimeType, float *confidence, sp<AMessage> *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<AMessage> *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<SnifferFunc>::iterator it = gSniffers.begin();
- it != gSniffers.end(); ++it) {
+ Mutex::Autolock autoLock(mSnifferMutex);
+ for (List<SnifferFunc>::iterator it = mSniffers.begin();
+ it != mSniffers.end(); ++it) {
String8 newMimeType;
float newConfidence;
sp<AMessage> newMeta;
- if ((*it)(this, &newMimeType, &newConfidence, &newMeta)) {
+ if ((*it)(source, &newMimeType, &newConfidence, &newMeta)) {
if (newConfidence > *confidence) {
*mimeType = newMimeType;
*confidence = newConfidence;
@@ -141,47 +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<SnifferFunc>::iterator it = mExtraSniffers.begin();
+ it != mExtraSniffers.end(); ++it) {
+ String8 newMimeType;
+ float newConfidence;
+ sp<AMessage> 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<SnifferFunc>::iterator it = gSniffers.begin();
- it != gSniffers.end(); ++it) {
+void Sniffer::registerSniffer_l(SnifferFunc func) {
+
+ for (List<SnifferFunc>::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<SnifferFunc>::iterator it = mExtraSniffers.begin();
+ it != mExtraSniffers.end(); ++it) {
+ if (*it == plugin->sniff) {
+ return;
+ }
+ }
- RegisterSniffer_l(SniffMPEG4);
- RegisterSniffer_l(SniffMatroska);
- RegisterSniffer_l(SniffOgg);
- RegisterSniffer_l(SniffWAV);
- RegisterSniffer_l(SniffFLAC);
- RegisterSniffer_l(SniffAMR);
- RegisterSniffer_l(SniffMPEG2TS);
- RegisterSniffer_l(SniffMP3);
- RegisterSniffer_l(SniffAAC);
- RegisterSniffer_l(SniffMPEG2PS);
- RegisterSniffer_l(SniffWVM);
- RegisterSniffer_l(SniffMidi);
+ mExtraSniffers.push_back(plugin->sniff);
+ }
+}
+
+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
@@ -190,7 +263,8 @@ sp<DataSource> DataSource::CreateFromURI(
const char *uri,
const KeyedVector<String8, String8> *headers,
String8 *contentType,
- HTTPBase *httpSource) {
+ HTTPBase *httpSource,
+ bool useExtendedCache) {
if (contentType != NULL) {
*contentType = "";
}
@@ -214,7 +288,7 @@ sp<DataSource> DataSource::CreateFromURI(
ALOGE("Failed to make http connection from http service!");
return NULL;
}
- httpSource = new MediaHTTP(conn);
+ httpSource = AVFactory::get()->createMediaHTTP(conn);
}
String8 tmp;
@@ -246,10 +320,17 @@ sp<DataSource> DataSource::CreateFromURI(
*contentType = httpSource->getMIMEType();
}
- source = NuCachedSource2::Create(
- httpSource,
- cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
- disconnectAtHighwatermark);
+ if (useExtendedCache) {
+ source = AVFactory::get()->createCachedSource(
+ httpSource,
+ cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
+ disconnectAtHighwatermark);
+ } else {
+ source = NuCachedSource2::Create(
+ httpSource,
+ cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
+ disconnectAtHighwatermark);
+ }
} else {
// We do not want that prefetching, caching, datasource wrapper
// in the widevine:// case.
@@ -278,7 +359,7 @@ sp<DataSource> DataSource::CreateMediaHTTP(const sp<IMediaHTTPService> &httpServ
if (conn == NULL) {
return NULL;
} else {
- return new MediaHTTP(conn);
+ return AVFactory::get()->createMediaHTTP(conn);
}
}
diff --git a/media/libstagefright/FFMPEGSoftCodec.cpp b/media/libstagefright/FFMPEGSoftCodec.cpp
new file mode 100644
index 0000000..3e6692b
--- /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 <utils/Log.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ABitReader.h>
+
+#include <media/stagefright/FFMPEGSoftCodec.h>
+
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaCodecList.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/OMXCodec.h>
+#include <media/stagefright/Utils.h>
+
+#include <OMX_Component.h>
+#include <OMX_AudioExt.h>
+#include <OMX_IndexExt.h>
+
+#include <OMX_FFMPEG_Extn.h>
+
+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<MetaData> &meta, sp<AMessage> *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<ABuffer> 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<ABuffer> 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<ABuffer> 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<ABuffer> buffer = new ABuffer(size);
+ memcpy(buffer->data(), data, size);
+ format->get()->setBuffer(MetaKeyTable[i].MsgKey, buffer);
+ }
+ }
+
+ }
+}
+
+void FFMPEGSoftCodec::convertMessageToMetaDataFF(
+ const sp<AMessage> &msg, sp<MetaData> &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<class T>
+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<AMessage> &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<AMessage> &msg, const char* mime, sp<IOMX> 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<AMessage> &notify, sp<IOMX> OMXHandle, IOMX::node_id nodeId) {
+
+ status_t err = BAD_TYPE;
+ switch (coding) {
+ case OMX_VIDEO_CodingWMV:
+ {
+ OMX_VIDEO_PARAM_WMVTYPE params;
+ InitOMXParams(&params);
+ params.nPortIndex = portIndex;
+
+ err = OMXHandle->getParameter(
+ nodeId, OMX_IndexParamVideoWmv, &params, 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(&params);
+ params.nPortIndex = portIndex;
+
+ err = OMXHandle->getParameter(
+ nodeId, (OMX_INDEXTYPE)OMX_IndexParamVideoFFmpeg, &params, 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(&params);
+ params.nPortIndex = portIndex;
+
+ err = OMXHandle->getParameter(
+ nodeId, (OMX_INDEXTYPE)OMX_IndexParamVideoRv, &params, 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<AMessage> &notify, sp<IOMX> OMXHandle, IOMX::node_id nodeId) {
+
+ status_t err = BAD_TYPE;
+ switch (coding) {
+ case OMX_AUDIO_CodingRA:
+ {
+ OMX_AUDIO_PARAM_RATYPE params;
+ InitOMXParams(&params);
+ params.nPortIndex = portIndex;
+
+ err = OMXHandle->getParameter(
+ nodeId, OMX_IndexParamAudioRa, &params, 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(&params);
+ params.nPortIndex = portIndex;
+
+ err = OMXHandle->getParameter(
+ nodeId, (OMX_INDEXTYPE)OMX_IndexParamAudioMp2, &params, 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(&params);
+ params.nPortIndex = portIndex;
+
+ err = OMXHandle->getParameter(
+ nodeId, OMX_IndexParamAudioWma, &params, 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(&params);
+ params.nPortIndex = portIndex;
+
+ err = OMXHandle->getParameter(
+ nodeId, (OMX_INDEXTYPE)OMX_IndexParamAudioApe, &params, 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(&params);
+ params.nPortIndex = portIndex;
+
+ err = OMXHandle->getParameter(
+ nodeId, (OMX_INDEXTYPE)OMX_IndexParamAudioFlac, &params, 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(&params);
+ params.nPortIndex = portIndex;
+
+ err = OMXHandle->getParameter(
+ nodeId, (OMX_INDEXTYPE)OMX_IndexParamAudioDts, &params, 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(&params);
+ params.nPortIndex = portIndex;
+
+ err = OMXHandle->getParameter(
+ nodeId, (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3, &params, 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(&params);
+ params.nPortIndex = portIndex;
+
+ err = OMXHandle->getParameter(
+ nodeId, (OMX_INDEXTYPE)OMX_IndexParamAudioFFmpeg, &params, 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<AMessage> &msg, const char* mime, sp<IOMX> 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<IOMX> &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<AMessage> &msg, sp<IOMX> 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(&paramWMV);
+ paramWMV.nPortIndex = kPortIndexInput;
+
+ status_t err = OMXhandle->getParameter(
+ nodeID, OMX_IndexParamVideoWmv, &paramWMV, 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, &paramWMV, sizeof(paramWMV));
+ return err;
+}
+
+status_t FFMPEGSoftCodec::setRVFormat(
+ const sp<AMessage> &msg, sp<IOMX> 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(&paramRV);
+ paramRV.nPortIndex = kPortIndexInput;
+
+ status_t err = OMXhandle->getParameter(
+ nodeID, OMX_IndexParamVideoRv, &paramRV, 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, &paramRV, sizeof(paramRV));
+ return err;
+}
+
+status_t FFMPEGSoftCodec::setFFmpegVideoFormat(
+ const sp<AMessage> &msg, sp<IOMX> 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(&param);
+ param.nPortIndex = kPortIndexInput;
+
+ status_t err = OMXhandle->getParameter(
+ nodeID, (OMX_INDEXTYPE)OMX_IndexParamVideoFFmpeg, &param, 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, &param, sizeof(param));
+ return err;
+}
+
+//audio
+status_t FFMPEGSoftCodec::setRawAudioFormat(
+ const sp<AMessage> &msg, sp<IOMX> 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<AMessage> &msg, sp<IOMX> 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(&paramWMA);
+ paramWMA.nPortIndex = kPortIndexInput;
+
+ err = OMXhandle->getParameter(
+ nodeID, OMX_IndexParamAudioWma, &paramWMA, 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, &paramWMA, sizeof(paramWMA));
+}
+
+status_t FFMPEGSoftCodec::setVORBISFormat(
+ const sp<AMessage> &msg, sp<IOMX> 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(&param);
+ param.nPortIndex = kPortIndexInput;
+
+ err = OMXhandle->getParameter(
+ nodeID, OMX_IndexParamAudioVorbis, &param, sizeof(param));
+ if (err != OK)
+ return err;
+
+ param.nChannels = numChannels;
+ param.nSampleRate = sampleRate;
+
+ return OMXhandle->setParameter(
+ nodeID, OMX_IndexParamAudioVorbis, &param, sizeof(param));
+}
+
+status_t FFMPEGSoftCodec::setRAFormat(
+ const sp<AMessage> &msg, sp<IOMX> 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(&paramRA);
+ paramRA.nPortIndex = kPortIndexInput;
+
+ err = OMXhandle->getParameter(
+ nodeID, OMX_IndexParamAudioRa, &paramRA, 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, &paramRA, sizeof(paramRA));
+}
+
+status_t FFMPEGSoftCodec::setFLACFormat(
+ const sp<AMessage> &msg, sp<IOMX> 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(&param);
+ param.nPortIndex = kPortIndexInput;
+
+ err = OMXhandle->getParameter(
+ nodeID, OMX_IndexParamAudioFlac, &param, sizeof(param));
+ if (err != OK)
+ return err;
+
+ param.nChannels = numChannels;
+ param.nSampleRate = sampleRate;
+ param.nCompressionLevel = bitsPerSample; // piggyback hax!
+
+ return OMXhandle->setParameter(
+ nodeID, OMX_IndexParamAudioFlac, &param, sizeof(param));
+}
+
+status_t FFMPEGSoftCodec::setMP2Format(
+ const sp<AMessage> &msg, sp<IOMX> 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(&param);
+ param.nPortIndex = kPortIndexInput;
+
+ err = OMXhandle->getParameter(
+ nodeID, (OMX_INDEXTYPE)OMX_IndexParamAudioMp2, &param, sizeof(param));
+ if (err != OK)
+ return err;
+
+ param.nChannels = numChannels;
+ param.nSampleRate = sampleRate;
+
+ return OMXhandle->setParameter(
+ nodeID, (OMX_INDEXTYPE)OMX_IndexParamAudioMp2, &param, sizeof(param));
+}
+
+status_t FFMPEGSoftCodec::setAC3Format(
+ const sp<AMessage> &msg, sp<IOMX> 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(&param);
+ param.nPortIndex = kPortIndexInput;
+
+ err = OMXhandle->getParameter(
+ nodeID, (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3, &param, sizeof(param));
+ if (err != OK)
+ return err;
+
+ param.nChannels = numChannels;
+ param.nSampleRate = sampleRate;
+
+ return OMXhandle->setParameter(
+ nodeID, (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidAc3, &param, sizeof(param));
+}
+
+status_t FFMPEGSoftCodec::setAPEFormat(
+ const sp<AMessage> &msg, sp<IOMX> 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(&param);
+ param.nPortIndex = kPortIndexInput;
+
+ err = OMXhandle->getParameter(
+ nodeID, (OMX_INDEXTYPE)OMX_IndexParamAudioApe, &param, sizeof(param));
+ if (err != OK)
+ return err;
+
+ param.nChannels = numChannels;
+ param.nSamplingRate = sampleRate;
+ param.nBitsPerSample = bitsPerSample;
+
+ return OMXhandle->setParameter(
+ nodeID, (OMX_INDEXTYPE)OMX_IndexParamAudioApe, &param, sizeof(param));
+}
+
+status_t FFMPEGSoftCodec::setDTSFormat(
+ const sp<AMessage> &msg, sp<IOMX> 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(&param);
+ param.nPortIndex = kPortIndexInput;
+
+ err = OMXhandle->getParameter(
+ nodeID, (OMX_INDEXTYPE)OMX_IndexParamAudioDts, &param, sizeof(param));
+ if (err != OK)
+ return err;
+
+ param.nChannels = numChannels;
+ param.nSamplingRate = sampleRate;
+
+ return OMXhandle->setParameter(
+ nodeID, (OMX_INDEXTYPE)OMX_IndexParamAudioDts, &param, sizeof(param));
+}
+
+status_t FFMPEGSoftCodec::setFFmpegAudioFormat(
+ const sp<AMessage> &msg, sp<IOMX> 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(&param);
+ param.nPortIndex = kPortIndexInput;
+
+ err = OMXhandle->getParameter(
+ nodeID, (OMX_INDEXTYPE)OMX_IndexParamAudioFFmpeg, &param, 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, &param, sizeof(param));
+}
+
+}
diff --git a/media/libstagefright/FLACExtractor.cpp b/media/libstagefright/FLACExtractor.cpp
index 89a91f7..87345e1 100644
--- a/media/libstagefright/FLACExtractor.cpp
+++ b/media/libstagefright/FLACExtractor.cpp
@@ -32,6 +32,13 @@
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MediaBuffer.h>
+#ifdef ENABLE_AV_ENHANCEMENTS
+#include "QCMediaDefs.h"
+#include "QCMetaData.h"
+#endif
+
+#include <system/audio.h>
+
namespace android {
class FLACParser;
@@ -72,6 +79,8 @@ private:
class FLACParser : public RefBase {
+friend class FLACSource;
+
public:
FLACParser(
const sp<DataSource> &dataSource,
@@ -103,6 +112,8 @@ public:
// 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 @@ public:
protected:
virtual ~FLACParser();
+
private:
sp<DataSource> mDataSource;
sp<MetaData> mFileMetadata;
@@ -122,7 +134,6 @@ private:
// 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 565f156..f7b1a02 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 a1af3aa..eee13c7 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;
@@ -535,6 +538,7 @@ status_t MPEG4Extractor::readMetaData() {
}
if (psshsize > 0 && psshsize <= UINT32_MAX) {
char *buf = (char*)malloc(psshsize);
+ CHECK(buf != NULL);
char *ptr = buf;
for (size_t i = 0; i < mPssh.size(); i++) {
memcpy(ptr, mPssh[i].uuid, 20); // uuid + length
@@ -837,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) {
@@ -1351,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) {
@@ -1590,13 +1601,21 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
return ERROR_MALFORMED;
*offset += chunk_size;
+ // Ignore stss block for audio even if its present
+ // All audio sample are sync samples itself,
+ // self decodeable and playable.
+ // Parsing this block for audio restricts audio seek to few entries
+ // available in this block, sometimes 0, which is undesired.
+ const char *mime;
+ CHECK(mLastTrack->meta->findCString(kKeyMIMEType, &mime));
+ if (strncasecmp("audio/", mime, 6)) {
+ status_t err =
+ mLastTrack->sampleTable->setSyncSampleParams(
+ data_offset, chunk_data_size);
- status_t err =
- mLastTrack->sampleTable->setSyncSampleParams(
- data_offset, chunk_data_size);
-
- if (err != OK) {
- return err;
+ if (err != OK) {
+ return err;
+ }
}
break;
@@ -2971,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;
@@ -3129,7 +3148,7 @@ status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio(
extensionFlag, objectType);
}
- if (numChannels == 0) {
+ if (numChannels == 0 && (br.numBitsLeft() > 0)) {
int32_t channelsEffectiveNum = 0;
int32_t channelsNum = 0;
if (br.numBitsLeft() < 32) {
@@ -4606,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 47f114a..cb9df29 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -38,10 +38,11 @@
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/Utils.h>
#include <media/mediarecorder.h>
+#include <stagefright/AVExtensions.h>
#include <cutils/properties.h>
#include "include/ESDS.h"
-
+#include <stagefright/AVExtensions.h>
#ifndef __predict_false
#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
@@ -91,6 +92,7 @@ public:
bool isAvc() const { return mIsAvc; }
bool isAudio() const { return mIsAudio; }
bool isMPEG4() const { return mIsMPEG4; }
+ bool isHEVC() const { return mIsHEVC; }
void addChunkOffset(off64_t offset);
int32_t getTrackId() const { return mTrackId; }
status_t dump(int fd, const Vector<String16>& args) const;
@@ -236,6 +238,7 @@ private:
bool mIsAvc;
bool mIsAudio;
bool mIsMPEG4;
+ bool mIsHEVC;
int32_t mTrackId;
int64_t mTrackDurationUs;
int64_t mMaxChunkDurationUs;
@@ -385,7 +388,9 @@ MPEG4Writer::MPEG4Writer(int fd)
mLongitudex10000(0),
mAreGeoTagsAvailable(false),
mStartTimeOffsetMs(-1),
- mMetaKeys(new AMessage()) {
+ mMetaKeys(new AMessage()),
+ mIsVideoHEVC(false),
+ mIsAudioAMR(false) {
addDeviceMeta();
// Verify mFd is seekable
@@ -463,6 +468,8 @@ const char *MPEG4Writer::Track::getFourCCForMime(const char *mime) {
return "s263";
} else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
return "avc1";
+ } else {
+ return AVUtils::get()->HEVCMuxerUtils().getFourCCForMime(mime);
}
} else {
ALOGE("Track (%s) other than video or audio is not supported", mime);
@@ -488,10 +495,23 @@ status_t MPEG4Writer::addSource(const sp<MediaSource> &source) {
const char *mime;
source->getFormat()->findCString(kKeyMIMEType, &mime);
bool isAudio = !strncasecmp(mime, "audio/", 6);
+ bool isVideo = !strncasecmp(mime, "video/", 6);
if (Track::getFourCCForMime(mime) == NULL) {
ALOGE("Unsupported mime '%s'", mime);
return ERROR_UNSUPPORTED;
}
+ mIsAudioAMR = isAudio && (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime) ||
+ !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime));
+
+
+ if (isVideo) {
+ mIsVideoHEVC = AVUtils::get()->HEVCMuxerUtils().isVideoHEVC(mime);
+ }
+
+ if (isAudio && !AVUtils::get()->isAudioMuxFormatSupported(mime)) {
+ ALOGE("Muxing is not supported for %s", mime);
+ return ERROR_UNSUPPORTED;
+ }
// At this point, we know the track to be added is either
// video or audio. Thus, we only need to check whether it
@@ -580,7 +600,7 @@ int64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) {
// If the estimation is wrong, we will pay the price of wasting
// some reserved space. This should not happen so often statistically.
- static const int32_t factor = mUse32BitOffset? 1: 2;
+ int32_t factor = mUse32BitOffset? 1: 2;
static const int64_t MIN_MOOV_BOX_SIZE = 3 * 1024; // 3 KB
static const int64_t MAX_MOOV_BOX_SIZE = (180 * 3000000 * 6LL / 8000);
int64_t size = MIN_MOOV_BOX_SIZE;
@@ -677,8 +697,6 @@ status_t MPEG4Writer::start(MetaData *param) {
mIsRealTimeRecording = isRealTimeRecording;
}
- mStartTimestampUs = -1;
-
if (mStarted) {
if (mPaused) {
mPaused = false;
@@ -687,6 +705,8 @@ status_t MPEG4Writer::start(MetaData *param) {
return OK;
}
+ mStartTimestampUs = -1;
+
if (!param ||
!param->findInt32(kKeyTimeScale, &mTimeScale)) {
mTimeScale = 1000;
@@ -1047,8 +1067,10 @@ void MPEG4Writer::writeFtypBox(MetaData *param) {
beginBox("ftyp");
int32_t fileType;
- if (param && param->findInt32(kKeyFileType, &fileType) &&
- fileType != OUTPUT_FORMAT_MPEG_4) {
+ if (mIsVideoHEVC) {
+ AVUtils::get()->HEVCMuxerUtils().writeHEVCFtypBox(this);
+ } else if (mIsAudioAMR || (param && param->findInt32(kKeyFileType, &fileType) &&
+ fileType != OUTPUT_FORMAT_MPEG_4)) {
writeFourcc("3gp4");
writeInt32(0);
writeFourcc("isom");
@@ -1464,6 +1486,12 @@ MPEG4Writer::Track::Track(
mIsAudio = !strncasecmp(mime, "audio/", 6);
mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC);
+ mIsHEVC = AVUtils::get()->HEVCMuxerUtils().isVideoHEVC(mime);
+
+ if (mIsHEVC) {
+ AVUtils::get()->HEVCMuxerUtils().getHEVCCodecSpecificDataFromInputFormatIfPossible(
+ mMeta, &mCodecSpecificData, &mCodecSpecificDataSize, &mGotAllCodecSpecificData);
+ }
setTimeScale();
}
@@ -1562,6 +1590,7 @@ void MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() {
size_t size;
if (mMeta->findData(kKeyAVCC, &type, &data, &size)) {
mCodecSpecificData = malloc(size);
+ CHECK(mCodecSpecificData != NULL);
mCodecSpecificDataSize = size;
memcpy(mCodecSpecificData, data, size);
mGotAllCodecSpecificData = true;
@@ -1575,6 +1604,7 @@ void MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() {
ESDS esds(data, size);
if (esds.getCodecSpecificInfo(&data, &size) == OK) {
mCodecSpecificData = malloc(size);
+ CHECK(mCodecSpecificData != NULL);
mCodecSpecificDataSize = size;
memcpy(mCodecSpecificData, data, size);
mGotAllCodecSpecificData = true;
@@ -1657,7 +1687,7 @@ void MPEG4Writer::writeChunkToFile(Chunk* chunk) {
while (!chunk->mSamples.empty()) {
List<MediaBuffer *>::iterator it = chunk->mSamples.begin();
- off64_t offset = chunk->mTrack->isAvc()
+ off64_t offset = (chunk->mTrack->isAvc() || chunk->mTrack->isHEVC())
? addLengthPrefixedSample_l(*it)
: addSample_l(*it);
@@ -1881,6 +1911,10 @@ status_t MPEG4Writer::Track::stop() {
status_t err = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy));
ALOGD("%s track stopped", mIsAudio? "Audio": "Video");
+ if (mOwner->exceedsFileSizeLimit() && mStszTableEntries->count() == 0) {
+ ALOGE(" Filesize limit exceeded and zero samples written ");
+ return ERROR_END_OF_STREAM;
+ }
return err;
}
@@ -1971,6 +2005,7 @@ status_t MPEG4Writer::Track::copyAVCCodecSpecificData(
mCodecSpecificDataSize = size;
mCodecSpecificData = malloc(size);
+ CHECK(mCodecSpecificData != NULL);
memcpy(mCodecSpecificData, data, size);
return OK;
}
@@ -2093,6 +2128,7 @@ status_t MPEG4Writer::Track::makeAVCCodecSpecificData(
// ISO 14496-15: AVC file format
mCodecSpecificDataSize += 7; // 7 more bytes in the header
mCodecSpecificData = malloc(mCodecSpecificDataSize);
+ CHECK(mCodecSpecificData != NULL);
uint8_t *header = (uint8_t *)mCodecSpecificData;
header[0] = 1; // version
header[1] = mProfileIdc; // profile indication
@@ -2227,10 +2263,18 @@ status_t MPEG4Writer::Track::threadEntry() {
} else if (mIsMPEG4) {
mCodecSpecificDataSize = buffer->range_length();
mCodecSpecificData = malloc(mCodecSpecificDataSize);
+ CHECK(mCodecSpecificData != NULL);
memcpy(mCodecSpecificData,
(const uint8_t *)buffer->data()
+ buffer->range_offset(),
buffer->range_length());
+ } else if (mIsHEVC) {
+ status_t err = AVUtils::get()->HEVCMuxerUtils().makeHEVCCodecSpecificData(
+ (const uint8_t *)buffer->data() + buffer->range_offset(),
+ buffer->range_length(), &mCodecSpecificData, &mCodecSpecificDataSize);
+ if ((status_t)OK != err) {
+ return err;
+ }
}
buffer->release();
@@ -2240,20 +2284,28 @@ 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) StripStartcode(copy);
+ if (mIsAvc || mIsHEVC) StripStartcode(copy);
size_t sampleSize = copy->range_length();
- if (mIsAvc) {
+ if (mIsAvc || mIsHEVC) {
if (mOwner->useNalLengthFour()) {
sampleSize += 4;
} else {
@@ -2287,6 +2339,7 @@ status_t MPEG4Writer::Track::threadEntry() {
previousPausedDurationUs = mStartTimestampUs;
}
+#if 0
if (mResumed) {
int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs;
if (WARN_UNLESS(durExcludingEarlierPausesUs >= 0ll, "for %s track", trackName)) {
@@ -2303,6 +2356,7 @@ status_t MPEG4Writer::Track::threadEntry() {
previousPausedDurationUs += pausedDurationUs - lastDurationUs;
mResumed = false;
}
+#endif
timestampUs -= previousPausedDurationUs;
if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) {
@@ -2320,8 +2374,8 @@ status_t MPEG4Writer::Track::threadEntry() {
CHECK(meta_data->findInt64(kKeyDecodingTime, &decodingTimeUs));
decodingTimeUs -= previousPausedDurationUs;
cttsOffsetTimeUs =
- timestampUs + kMaxCttsOffsetTimeUs - decodingTimeUs;
- if (WARN_UNLESS(cttsOffsetTimeUs >= 0ll, "for %s track", trackName)) {
+ timestampUs - decodingTimeUs;
+ if (WARN_UNLESS(kMaxCttsOffsetTimeUs >= decodingTimeUs - timestampUs, "for %s track", trackName)) {
copy->release();
return ERROR_MALFORMED;
}
@@ -2453,7 +2507,7 @@ status_t MPEG4Writer::Track::threadEntry() {
trackProgressStatus(timestampUs);
}
if (!hasMultipleTracks) {
- off64_t offset = mIsAvc? mOwner->addLengthPrefixedSample_l(copy)
+ off64_t offset = (mIsAvc || mIsHEVC)? mOwner->addLengthPrefixedSample_l(copy)
: mOwner->addSample_l(copy);
uint32_t count = (mOwner->use32BitFileOffset()
@@ -2546,8 +2600,13 @@ status_t MPEG4Writer::Track::threadEntry() {
if (mIsAudio) {
ALOGI("Audio track drift time: %" PRId64 " us", mOwner->getDriftTimeUs());
}
-
- if (err == ERROR_END_OF_STREAM) {
+ // if err is ERROR_IO (ex: during SSR), return OK to save the
+ // recorded file successfully. Session tear down will happen as part of
+ // client callback
+ if (mIsAudio && (err == ERROR_IO)) {
+ return OK;
+ }
+ else if (err == ERROR_END_OF_STREAM) {
return OK;
}
return err;
@@ -2705,7 +2764,8 @@ status_t MPEG4Writer::Track::checkCodecSpecificData() const {
CHECK(mMeta->findCString(kKeyMIMEType, &mime));
if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime) ||
!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) ||
- !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
+ !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime) ||
+ mIsHEVC) {
if (!mCodecSpecificData ||
mCodecSpecificDataSize <= 0) {
ALOGE("Missing codec specific data");
@@ -2726,6 +2786,11 @@ void MPEG4Writer::Track::writeTrackHeader(bool use32BitOffset) {
ALOGV("%s track time scale: %d",
mIsAudio? "Audio": "Video", mTimeScale);
+ if (mMdatSizeBytes == 0) {
+ ALOGW("Track data is not available.");
+ return;
+ }
+
uint32_t now = getMpeg4Time();
mOwner->beginBox("trak");
writeTkhdBox(now);
@@ -2803,17 +2868,22 @@ void MPEG4Writer::Track::writeVideoFourCCBox() {
mOwner->writeInt16(0x18); // depth
mOwner->writeInt16(-1); // predefined
- CHECK_LT(23 + mCodecSpecificDataSize, 128);
-
if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
writeMp4vEsdsBox();
} else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
writeD263Box();
} else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
writeAvccBox();
+ } else if (mIsHEVC) {
+ AVUtils::get()->HEVCMuxerUtils().writeHvccBox(mOwner, mCodecSpecificData,
+ mCodecSpecificDataSize,
+ mOwner->useNalLengthFour());
+ }
+
+ if (!mIsHEVC) {
+ writePaspBox();
}
- writePaspBox();
mOwner->endBox(); // mp4v, s263 or avc1
}
@@ -2898,6 +2968,9 @@ void MPEG4Writer::Track::writeMp4vEsdsBox() {
CHECK_GT(mCodecSpecificDataSize, 0);
mOwner->beginBox("esds");
+ // Make sure all sizes encode to a single byte.
+ CHECK_LT(mCodecSpecificDataSize + 23, 128);
+
mOwner->writeInt32(0); // version=0, flags=0
mOwner->writeInt8(0x03); // ES_DescrTag
@@ -3086,7 +3159,7 @@ void MPEG4Writer::Track::writePaspBox() {
int32_t MPEG4Writer::Track::getStartTimeOffsetScaledTime() const {
int64_t trackStartTimeOffsetUs = 0;
int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
- if (mStartTimestampUs != moovStartTimeUs) {
+ if (mStartTimestampUs != moovStartTimeUs && mStszTableEntries->count() != 0) {
CHECK_GT(mStartTimestampUs, moovStartTimeUs);
trackStartTimeOffsetUs = mStartTimestampUs - moovStartTimeUs;
}
diff --git a/media/libstagefright/MediaBuffer.cpp b/media/libstagefright/MediaBuffer.cpp
index 1f80a47..525a156 100644
--- a/media/libstagefright/MediaBuffer.cpp
+++ b/media/libstagefright/MediaBuffer.cpp
@@ -54,6 +54,7 @@ MediaBuffer::MediaBuffer(size_t size)
mOwnsData(true),
mMetaData(new MetaData),
mOriginal(NULL) {
+ CHECK(mData != NULL);
}
MediaBuffer::MediaBuffer(const sp<GraphicBuffer>& graphicBuffer)
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 7019537..45e9a79 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -51,6 +51,7 @@
#include <private/android_filesystem_config.h>
#include <utils/Log.h>
#include <utils/Singleton.h>
+#include <stagefright/AVExtensions.h>
namespace android {
@@ -306,7 +307,7 @@ status_t MediaCodec::init(const AString &name, bool nameIsType, bool encoder) {
// queue.
if (nameIsType || !strncasecmp(name.c_str(), "omx.", 4)) {
- mCodec = new ACodec;
+ mCodec = AVFactory::get()->createACodec();
} else if (!nameIsType
&& !strncasecmp(name.c_str(), "android.filter.", 15)) {
mCodec = new MediaFilter;
@@ -984,6 +985,9 @@ bool MediaCodec::handleDequeueOutputBuffer(const sp<AReplyToken> &replyID, bool
if (omxFlags & OMX_BUFFERFLAG_EOS) {
flags |= BUFFER_FLAG_EOS;
}
+ if (omxFlags & OMX_BUFFERFLAG_EXTRADATA) {
+ flags |= BUFFER_FLAG_EXTRADATA;
+ }
response->setInt32("flags", flags);
response->postReply(replyID);
@@ -1140,7 +1144,8 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &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;
@@ -1177,6 +1182,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
// reset input surface flag
mHaveInputSurface = false;
+ CHECK(msg->findString("componentName", &mComponentName));
CHECK(msg->findMessage("input-format", &mInputFormat));
CHECK(msg->findMessage("output-format", &mOutputFormat));
@@ -2269,6 +2275,7 @@ size_t MediaCodec::updateBuffers(
uint32_t bufferID;
CHECK(msg->findInt32("buffer-id", (int32_t*)&bufferID));
+ Mutex::Autolock al(mBufferLock);
Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index 5edc04c..ff94314 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -40,6 +40,7 @@
#include <cutils/properties.h>
#include <libexpat/expat.h>
+#include <stagefright/AVExtensions.h>
namespace android {
@@ -174,7 +175,7 @@ MediaCodecList::MediaCodecList()
: mInitCheck(NO_INIT),
mUpdate(false),
mGlobalSettings(new AMessage()) {
- parseTopLevelXMLFile("/etc/media_codecs.xml");
+ parseTopLevelXMLFile(AVUtils::get()->getCustomCodecsLocation());
parseTopLevelXMLFile("/etc/media_codecs_performance.xml", true/* ignore_errors */);
parseTopLevelXMLFile(kProfilingResults, true/* ignore_errors */);
}
@@ -939,7 +940,13 @@ status_t MediaCodecList::addLimit(const char **attrs) {
// complexity: range + default
bool found;
- if (name == "aspect-ratio" || name == "bitrate" || name == "block-count"
+ // VT specific limits
+ if (name.find("vt-") == 0) {
+ AString value;
+ if (msg->findString("value", &value) && value.size()) {
+ mCurrentInfo->addDetail(name, value);
+ }
+ } else if (name == "aspect-ratio" || name == "bitrate" || name == "block-count"
|| name == "blocks-per-second" || name == "complexity"
|| name == "frame-rate" || name == "quality" || name == "size"
|| name == "measured-blocks-per-second" || name.startsWith("measured-frame-rate-")) {
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index 7f9f824..925be14 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -36,6 +36,8 @@
#include <media/stagefright/MetaData.h>
#include <media/stagefright/PersistentSurface.h>
#include <media/stagefright/Utils.h>
+#include <OMX_Core.h>
+#include <stagefright/AVExtensions.h>
namespace android {
@@ -399,10 +401,14 @@ status_t MediaCodecSource::initEncoder() {
}
AString outputMIME;
+ AString role;
CHECK(mOutputFormat->findString("mime", &outputMIME));
-
- mEncoder = MediaCodec::CreateByType(
+ if (AVUtils::get()->useQCHWEncoder(mOutputFormat, role)) {
+ mEncoder = MediaCodec::CreateByComponentName(mCodecLooper, role.c_str());
+ } else {
+ mEncoder = MediaCodec::CreateByType(
mCodecLooper, outputMIME.c_str(), true /* encoder */);
+ }
if (mEncoder == NULL) {
return NO_INIT;
@@ -514,6 +520,9 @@ void MediaCodecSource::signalEOS(status_t err) {
mOutputBufferQueue.clear();
mEncoderReachedEOS = true;
mErrorCode = err;
+ if (err == OMX_ErrorHardware) {
+ mErrorCode = ERROR_IO;
+ }
mOutputBufferCond.signal();
}
@@ -572,6 +581,9 @@ status_t MediaCodecSource::feedEncoderInputBuffers() {
// push decoding time for video, or drift time for audio
if (mIsVideo) {
mDecodingTimeQueue.push_back(timeUs);
+ if (mFlags & FLAG_USE_METADATA_INPUT) {
+ AVUtils::get()->addDecodingTimesFromBatch(mbuf, mDecodingTimeQueue);
+ }
} else {
#if DEBUG_DRIFT_TIME
if (mFirstSampleTimeUs < 0ll) {
@@ -591,7 +603,7 @@ status_t MediaCodecSource::feedEncoderInputBuffers() {
status_t err = mEncoder->getInputBuffer(bufferIndex, &inbuf);
if (err != OK || inbuf == NULL) {
mbuf->release();
- signalEOS();
+ signalEOS(err);
break;
}
@@ -633,6 +645,9 @@ status_t MediaCodecSource::onStart(MetaData *params) {
resume();
} else {
CHECK(mPuller != NULL);
+ if (mIsVideo) {
+ mEncoder->requestIDRFrame();
+ }
mPuller->resume();
}
return OK;
@@ -738,12 +753,14 @@ void MediaCodecSource::onMessageReceived(const sp<AMessage> &msg) {
sp<ABuffer> outbuf;
status_t err = mEncoder->getOutputBuffer(index, &outbuf);
if (err != OK || outbuf == NULL) {
- signalEOS();
+ signalEOS(err);
break;
}
MediaBuffer *mbuf = new MediaBuffer(outbuf->size());
memcpy(mbuf->data(), outbuf->data(), outbuf->size());
+ sp<MetaData> meta = mbuf->meta_data();
+ AVUtils::get()->setDeferRelease(meta);
if (!(flags & MediaCodec::BUFFER_FLAG_CODECCONFIG)) {
if (mIsVideo) {
@@ -799,7 +816,7 @@ void MediaCodecSource::onMessageReceived(const sp<AMessage> &msg) {
CHECK(msg->findInt32("err", &err));
ALOGE("Encoder (%s) reported error : 0x%x",
mIsVideo ? "video" : "audio", err);
- signalEOS();
+ signalEOS(err);
}
break;
}
@@ -852,7 +869,7 @@ void MediaCodecSource::onMessageReceived(const sp<AMessage> &msg) {
}
case kWhatPause:
{
- if (mFlags && FLAG_USE_SURFACE_INPUT) {
+ if (mFlags & FLAG_USE_SURFACE_INPUT) {
suspend();
} else {
CHECK(mPuller != NULL);
diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp
index 2a50692..089c150 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 e21fe6e..fc96e2f 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -40,8 +40,12 @@
#include <media/stagefright/MetaData.h>
#include <utils/String8.h>
+#include <stagefright/AVExtensions.h>
+
namespace android {
+MediaExtractor::Plugin MediaExtractor::sPlugin;
+
sp<MetaData> MediaExtractor::getMetaData() {
return new MetaData;
}
@@ -52,12 +56,19 @@ uint32_t MediaExtractor::flags() const {
// static
sp<MediaExtractor> MediaExtractor::Create(
- const sp<DataSource> &source, const char *mime) {
+ const sp<DataSource> &source, const char *mime,
+ const uint32_t flags) {
sp<AMessage> 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.");
@@ -91,8 +102,14 @@ sp<MediaExtractor> MediaExtractor::Create(
}
}
- MediaExtractor *ret = NULL;
- if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4)
+ sp<MediaExtractor> ret = NULL;
+ AString extractorName;
+ if ((ret = AVFactory::get()->createExtendedExtractor(source, mime, meta, flags)) != NULL) {
+ } else if (meta.get() && meta->findString("extended-extractor-use", &extractorName)
+ && sPlugin.create) {
+ ALOGI("Use extended extractor for the special mime(%s) or codec", mime);
+ ret = sPlugin.create(source, mime, meta);
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4)
|| !strcasecmp(mime, "audio/mp4")) {
ret = new MPEG4Extractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
@@ -119,8 +136,11 @@ sp<MediaExtractor> MediaExtractor::Create(
ret = new MPEG2PSExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MIDI)) {
ret = new MidiExtractor(source);
+ } else if (!isDrm && sPlugin.create) {
+ ret = sPlugin.create(source, mime, meta);
}
+ ret = AVFactory::get()->updateExtractor(ret, source, mime, meta, flags);
if (ret != NULL) {
if (isDrm) {
ret->setDrmFlag(true);
@@ -129,6 +149,15 @@ sp<MediaExtractor> 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 e69890d..ac925f7 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/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index b1dde80..8d0bccd 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -56,6 +56,11 @@
#include "include/avc_utils.h"
+#ifdef USE_S3D_SUPPORT
+#include "Exynos_OMX_Def.h"
+#include "ExynosHWCService.h"
+#endif
+
namespace android {
// Treat time out as an error if we have not received any output
@@ -1821,6 +1826,10 @@ status_t OMXCodec::allocateOutputBuffersFromNativeWindow() {
if (mFlags & kEnableGrallocUsageProtected) {
usage |= GRALLOC_USAGE_PROTECTED;
+#ifdef GRALLOC_USAGE_PRIVATE_NONSECURE
+ if (!(mFlags & kUseSecureInputBuffers))
+ usage |= GRALLOC_USAGE_PRIVATE_NONSECURE;
+#endif
}
err = setNativeWindowSizeFormatAndUsage(
@@ -2373,7 +2382,41 @@ void OMXCodec::onEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
break;
}
#endif
+#ifdef USE_S3D_SUPPORT
+ case (OMX_EVENTTYPE)OMX_EventS3DInformation:
+ {
+ if (mFlags & kClientNeedsFramebuffer)
+ break;
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<android::IExynosHWCService> hwc = interface_cast<android::IExynosHWCService>(
+ sm->getService(String16("Exynos.HWCService")));
+ if (hwc != NULL) {
+ if (data1 == OMX_TRUE) {
+ int eS3DMode;
+ switch (data2) {
+ case OMX_SEC_FPARGMT_SIDE_BY_SIDE:
+ eS3DMode = S3D_SBS;
+ break;
+ case OMX_SEC_FPARGMT_TOP_BOTTOM:
+ eS3DMode = S3D_TB;
+ break;
+ case OMX_SEC_FPARGMT_CHECKERBRD_INTERL: // unsupport format at HDMI
+ case OMX_SEC_FPARGMT_COLUMN_INTERL:
+ case OMX_SEC_FPARGMT_ROW_INTERL:
+ case OMX_SEC_FPARGMT_TEMPORAL_INTERL:
+ default:
+ eS3DMode = S3D_NONE;
+ }
+
+ hwc->setHdmiResolution(0, eS3DMode);
+ }
+ } else {
+ ALOGE("Exynos.HWCService is unavailable");
+ }
+ break;
+ }
+#endif
default:
{
CODEC_LOGV("EVENT(%d, %u, %u)", event, data1, data2);
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index db33e83..c5018ae 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -28,6 +28,8 @@
#include <media/mediametadataretriever.h>
#include <private/media/VideoFrame.h>
+#include <stagefright/AVExtensions.h>
+
namespace android {
StagefrightMediaScanner::StagefrightMediaScanner() {}
@@ -40,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]);
@@ -75,7 +81,8 @@ MediaScanResult StagefrightMediaScanner::processFileInternal(
return MEDIA_SCAN_RESULT_SKIPPED;
}
- if (!FileHasAcceptableExtension(extension)) {
+ if (!FileHasAcceptableExtension(extension)
+ && !AVUtils::get()->isEnhancedExtension(extension)) {
return MEDIA_SCAN_RESULT_SKIPPED;
}
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index e37e909..c3adac4 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -23,6 +23,7 @@
#include <gui/Surface.h>
#include "include/StagefrightMetadataRetriever.h"
+#include "include/HTTPBase.h"
#include <media/ICrypto.h>
#include <media/IMediaHTTPService.h>
@@ -44,6 +45,8 @@
#include <CharacterEncodingDetector.h>
+#include <stagefright/AVExtensions.h>
+
namespace android {
static const int64_t kBufferTimeOutUs = 30000ll; // 30 msec
@@ -62,6 +65,12 @@ StagefrightMetadataRetriever::~StagefrightMetadataRetriever() {
ALOGV("~StagefrightMetadataRetriever()");
clearMetadata();
mClient.disconnect();
+
+ if (mSource != NULL &&
+ (mSource->flags() & DataSource::kIsHTTPBasedSource)) {
+ mExtractor.clear();
+ static_cast<HTTPBase *>(mSource.get())->disconnect();
+ }
}
status_t StagefrightMetadataRetriever::setDataSource(
@@ -97,6 +106,7 @@ status_t StagefrightMetadataRetriever::setDataSource(
fd = dup(fd);
ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
+ AVUtils::get()->printFileName(fd);
clearMetadata();
mSource = new FileSource(fd, offset, length);
@@ -154,6 +164,8 @@ static VideoFrame *extractVideoFrame(
// TODO: Use Flexible color instead
videoFormat->setInt32("color-format", OMX_COLOR_FormatYUV420Planar);
+ videoFormat->setInt32("thumbnail-mode", 1);
+
status_t err;
sp<ALooper> looper = new ALooper;
looper->start();
@@ -214,6 +226,7 @@ static VideoFrame *extractVideoFrame(
err = decoder->getInputBuffers(&inputBuffers);
if (err != OK) {
ALOGW("failed to get input buffers: %d (%s)", err, asString(err));
+ source->stop();
decoder->release();
return NULL;
}
@@ -222,6 +235,7 @@ static VideoFrame *extractVideoFrame(
err = decoder->getOutputBuffers(&outputBuffers);
if (err != OK) {
ALOGW("failed to get output buffers: %d (%s)", err, asString(err));
+ source->stop();
decoder->release();
return NULL;
}
@@ -346,9 +360,11 @@ static VideoFrame *extractVideoFrame(
}
}
- int32_t width, height;
+ int32_t width, height, stride, slice_height;
CHECK(outputFormat->findInt32("width", &width));
CHECK(outputFormat->findInt32("height", &height));
+ CHECK(outputFormat->findInt32("stride", &stride));
+ CHECK(outputFormat->findInt32("slice-height", &slice_height));
int32_t crop_left, crop_top, crop_right, crop_bottom;
if (!outputFormat->findRect("crop", &crop_left, &crop_top, &crop_right, &crop_bottom)) {
@@ -386,7 +402,7 @@ static VideoFrame *extractVideoFrame(
if (converter.isValid()) {
err = converter.convert(
(const uint8_t *)videoFrameBuffer->data(),
- width, height,
+ stride, slice_height,
crop_left, crop_top, crop_right, crop_bottom,
frame->mData,
frame->mWidth,
@@ -442,6 +458,10 @@ VideoFrame *StagefrightMetadataRetriever::getFrameAtTime(
for (i = 0; i < n; ++i) {
sp<MetaData> meta = mExtractor->getTrackMetaData(i);
+ if (meta == NULL) {
+ continue;
+ }
+
const char *mime;
CHECK(meta->findCString(kKeyMIMEType, &mime));
@@ -481,7 +501,7 @@ VideoFrame *StagefrightMetadataRetriever::getFrameAtTime(
mime,
false, /* encoder */
NULL, /* matchComponentName */
- OMXCodec::kPreferSoftwareCodecs,
+ 0 /* OMXCodec::kPreferSoftwareCodecs */,
&matchingCodecs);
for (size_t i = 0; i < matchingCodecs.size(); ++i) {
@@ -612,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);
@@ -635,6 +659,9 @@ void StagefrightMetadataRetriever::parseMetaData() {
String8 timedTextLang;
for (size_t i = 0; i < numTracks; ++i) {
sp<MetaData> trackMeta = mExtractor->getTrackMetaData(i);
+ if (trackMeta == NULL) {
+ continue;
+ }
int64_t durationUs;
if (trackMeta->findInt64(kKeyDuration, &durationUs)) {
@@ -661,9 +688,12 @@ void StagefrightMetadataRetriever::parseMetaData() {
}
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
const char *lang;
- trackMeta->findCString(kKeyMediaLanguage, &lang);
- timedTextLang.append(String8(lang));
- timedTextLang.append(String8(":"));
+ if (trackMeta->findCString(kKeyMediaLanguage, &lang)) {
+ timedTextLang.append(String8(lang));
+ timedTextLang.append(String8(":"));
+ } else {
+ ALOGE("No language found for timed text");
+ }
}
}
}
diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
index e8abf48..7da5a9f 100644
--- a/media/libstagefright/SurfaceMediaSource.cpp
+++ b/media/libstagefright/SurfaceMediaSource.cpp
@@ -360,7 +360,11 @@ status_t SurfaceMediaSource::read(
mNumFramesEncoded++;
// Pass the data to the MediaBuffer. Pass in only the metadata
-
+ if (mSlots[mCurrentSlot].mGraphicBuffer == NULL) {
+ ALOGV("Read: SurfaceMediaSource mGraphicBuffer is null. Returning"
+ "ERROR_END_OF_STREAM.");
+ return ERROR_END_OF_STREAM;
+ }
passMetadataBuffer(buffer, mSlots[mCurrentSlot].mGraphicBuffer->handle);
(*buffer)->setObserver(this);
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 17f0201..6e4a1a4 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -35,6 +35,9 @@
#include <media/stagefright/Utils.h>
#include <media/AudioParameter.h>
+#include <stagefright/AVExtensions.h>
+#include <media/stagefright/FFMPEGSoftCodec.h>
+
namespace android {
uint16_t U16_AT(const uint8_t *ptr) {
@@ -104,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;
@@ -203,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;
@@ -453,8 +461,15 @@ status_t convertMetaDataToMessage(
msg->setBuffer("csd-2", buffer);
}
+ 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;
}
@@ -646,6 +661,11 @@ void convertMessageToMetaData(const sp<AMessage> &msg, sp<MetaData> &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;
@@ -685,6 +705,8 @@ void convertMessageToMetaData(const sp<AMessage> &msg, sp<MetaData> &meta) {
// for transporting the CSD to muxers.
reassembleESDS(csd0, esds);
meta->setData(kKeyESDS, kKeyESDS, esds, sizeof(esds));
+ } else {
+ AVUtils::get()->HEVCMuxerUtils().reassembleHEVCCSD(mime, csd0, meta);
}
}
@@ -695,10 +717,10 @@ void convertMessageToMetaData(const sp<AMessage> &msg, sp<MetaData> &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() {
@@ -744,6 +766,7 @@ status_t sendMetaDataToHal(sp<MediaPlayerBase::AudioSink>& sink,
param.addInt(String8(AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES), paddingSamples);
}
+ AVUtils::get()->sendMetaDataToHal(meta, &param);
ALOGV("sendMetaDataToHal: bitRate %d, sampleRate %d, chanMask %d,"
"delaySample %d, paddingSample %d", bitRate, sampleRate,
channelMask, delaySamples, paddingSamples);
@@ -779,7 +802,7 @@ const struct mime_conv_t* p = &mimeLookup[0];
++p;
}
- return BAD_VALUE;
+ return AVUtils::get()->mapMimeToAudioFormat(format, mime);
}
struct aac_format_conv_t {
@@ -833,18 +856,28 @@ bool canOffloadStream(const sp<MetaData>& meta, bool hasVideo,
} else {
ALOGV("Mime type \"%s\" mapped to audio_format %d", mime, info.format);
}
-
+ info.format = AVUtils::get()->updateAudioFormat(info.format, meta);
if (AUDIO_FORMAT_INVALID == info.format) {
// can't offload if we don't know what the source format is
ALOGE("mime type \"%s\" not a known audio format", mime);
return false;
}
+ 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.
int32_t aacaot = -1;
if (meta->findInt32(kKeyAACAOT, &aacaot)) {
- mapAACProfileToAudioFormat(info.format,(OMX_AUDIO_AACPROFILETYPE) aacaot);
+ bool isADTSSupported = false;
+ isADTSSupported = AVUtils::get()->mapAACProfileToAudioFormat(meta, info.format,
+ (OMX_AUDIO_AACPROFILETYPE) aacaot);
+ if (!isADTSSupported) {
+ mapAACProfileToAudioFormat(info.format,(OMX_AUDIO_AACPROFILETYPE) aacaot);
+ }
}
int32_t srate = -1;
diff --git a/media/libstagefright/VideoFrameScheduler.cpp b/media/libstagefright/VideoFrameScheduler.cpp
index 5fe9bf9..02b8783 100644
--- a/media/libstagefright/VideoFrameScheduler.cpp
+++ b/media/libstagefright/VideoFrameScheduler.cpp
@@ -257,8 +257,7 @@ void VideoFrameScheduler::PLL::prime(size_t numSamplesToUse) {
mPhase = firstTime;
}
}
- ALOGV("priming[%zu] phase:%lld period:%lld",
- numSamplesToUse, (long long)mPhase, (long long)mPeriod);
+ ALOGV("priming[%zu] phase:%lld period:%lld ", numSamplesToUse, (long long)mPhase, (long long)mPeriod);
}
nsecs_t VideoFrameScheduler::PLL::addSample(nsecs_t time) {
diff --git a/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp
index 335ac84..d86dffb 100644
--- a/media/libstagefright/WAVExtractor.cpp
+++ b/media/libstagefright/WAVExtractor.cpp
@@ -29,6 +29,7 @@
#include <media/stagefright/MetaData.h>
#include <utils/String8.h>
#include <cutils/bitops.h>
+#include <system/audio.h>
#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 8ef2dca..98b5c0e 100644
--- a/media/libstagefright/avc_utils.cpp
+++ b/media/libstagefright/avc_utils.cpp
@@ -25,6 +25,7 @@
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MetaData.h>
#include <utils/misc.h>
@@ -393,7 +394,7 @@ sp<MetaData> MakeAVCCodecSpecificData(const sp<ABuffer> &accessUnit) {
meta->setInt32(kKeyWidth, width);
meta->setInt32(kKeyHeight, height);
- if (sarWidth > 1 || sarHeight > 1) {
+ if (sarWidth > 1 && sarHeight > 1) {
// We treat 0:0 (unspecified) as 1:1.
meta->setInt32(kKeySARWidth, sarWidth);
@@ -443,25 +444,34 @@ bool IsIDR(const sp<ABuffer> &buffer) {
}
bool IsAVCReferenceFrame(const sp<ABuffer> &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<MetaData> MakeAACCodecSpecificData(
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
index 965c55e..c945305 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
@@ -68,6 +68,8 @@ SoftAAC2::SoftAAC2(
mOutputBufferCount(0),
mSignalledError(false),
mLastInHeader(NULL),
+ mLastHeaderTimeUs(-1),
+ mNextOutBufferTimeUs(0),
mOutputPortSettingsChange(NONE) {
initPorts();
CHECK_EQ(initDecoder(), (status_t)OK);
@@ -492,6 +494,27 @@ int32_t SoftAAC2::outputDelayRingBufferSpaceLeft() {
return mOutputDelayRingBufferSize - outputDelayRingBufferSamplesAvailable();
}
+void SoftAAC2::updateTimeStamp(int64_t inHeaderTimeUs) {
+ // use new input buffer timestamp as Anchor Time if its
+ // a) first buffer or
+ // b) first buffer post seek or
+ // c) different from last buffer timestamp
+ //If input buffer timestamp is same as last input buffer timestamp then
+ //treat this as a erroneous timestamp and ignore new input buffer
+ //timestamp and use last output buffer timestamp as Anchor Time.
+ int64_t anchorTimeUs = 0;
+ if ((mLastHeaderTimeUs != inHeaderTimeUs)) {
+ anchorTimeUs = inHeaderTimeUs;
+ mLastHeaderTimeUs = inHeaderTimeUs;
+ //Store current buffer's timestamp so that it can used as reference
+ //in cases where first frame/buffer is skipped/dropped.
+ //e.g to compensate decoder delay
+ mNextOutBufferTimeUs = inHeaderTimeUs;
+ } else {
+ anchorTimeUs = mNextOutBufferTimeUs;
+ }
+ mBufferTimestamps.add(anchorTimeUs);
+}
void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) {
if (mSignalledError || mOutputPortSettingsChange != NONE) {
@@ -618,7 +641,7 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) {
// insert buffer size and time stamp
mBufferSizes.add(inBufferLength[0]);
if (mLastInHeader != inHeader) {
- mBufferTimestamps.add(inHeader->nTimeStamp);
+ updateTimeStamp(inHeader->nTimeStamp);
mLastInHeader = inHeader;
} else {
int64_t currentTime = mBufferTimestamps.top();
@@ -630,7 +653,7 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) {
inBuffer[0] = inHeader->pBuffer + inHeader->nOffset;
inBufferLength[0] = inHeader->nFilledLen;
mLastInHeader = inHeader;
- mBufferTimestamps.add(inHeader->nTimeStamp);
+ updateTimeStamp(inHeader->nTimeStamp);
mBufferSizes.add(inHeader->nFilledLen);
}
@@ -755,6 +778,14 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) {
if (inHeader && inHeader->nFilledLen == 0) {
inInfo->mOwnedByUs = false;
mInputBufferCount++;
+
+ //During Port reconfiguration current frames is skipped and next frame
+ //is sent for decoding.
+ //Update mNextOutBufferTimeUs with current frame's timestamp if port reconfiguration is
+ //happening in last frame of current buffer otherwise LastOutBufferTimeUs
+ //will be zero(post seek).
+ mNextOutBufferTimeUs = mBufferTimestamps.top() + mStreamInfo->aacSamplesPerFrame *
+ 1000000ll / mStreamInfo->aacSampleRate;
inQueue.erase(inQueue.begin());
mLastInHeader = NULL;
inInfo = NULL;
@@ -875,6 +906,7 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) {
*currentBufLeft -= decodedSize;
*nextTimeStamp += mStreamInfo->aacSamplesPerFrame *
1000000ll / mStreamInfo->aacSampleRate;
+ mNextOutBufferTimeUs = *nextTimeStamp;
ALOGV("adjusted nextTimeStamp/size to %lld/%d",
(long long) *nextTimeStamp, *currentBufLeft);
} else {
@@ -882,6 +914,7 @@ void SoftAAC2::onQueueFilled(OMX_U32 /* portIndex */) {
if (mBufferTimestamps.size() > 0) {
mBufferTimestamps.removeAt(0);
nextTimeStamp = &mBufferTimestamps.editItemAt(0);
+ mNextOutBufferTimeUs = *nextTimeStamp;
mBufferSizes.removeAt(0);
currentBufLeft = &mBufferSizes.editItemAt(0);
ALOGV("moved to next time/size: %lld/%d",
@@ -976,6 +1009,8 @@ void SoftAAC2::onPortFlushCompleted(OMX_U32 portIndex) {
mDecodedSizes.clear();
mLastInHeader = NULL;
mEndOfInput = false;
+ mLastHeaderTimeUs = -1;
+ mNextOutBufferTimeUs = 0;
} else {
int avail;
while ((avail = outputDelayRingBufferSamplesAvailable()) > 0) {
@@ -1038,6 +1073,8 @@ void SoftAAC2::onReset() {
mBufferSizes.clear();
mDecodedSizes.clear();
mLastInHeader = NULL;
+ mLastHeaderTimeUs = -1;
+ mNextOutBufferTimeUs = 0;
// To make the codec behave the same before and after a reset, we need to invalidate the
// streaminfo struct. This does that:
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.h b/media/libstagefright/codecs/aacdec/SoftAAC2.h
index c3e4459..3fe958e 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.h
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.h
@@ -59,6 +59,8 @@ private:
size_t mOutputBufferCount;
bool mSignalledError;
OMX_BUFFERHEADERTYPE *mLastInHeader;
+ int64_t mLastHeaderTimeUs;
+ int64_t mNextOutBufferTimeUs;
Vector<int32_t> mBufferSizes;
Vector<int32_t> mDecodedSizes;
Vector<int64_t> mBufferTimestamps;
@@ -90,6 +92,7 @@ private:
int32_t outputDelayRingBufferGetSamples(INT_PCM *samples, int numSamples);
int32_t outputDelayRingBufferSamplesAvailable();
int32_t outputDelayRingBufferSpaceLeft();
+ void updateTimeStamp(int64_t inHeaderTimesUs);
DISALLOW_EVIL_CONSTRUCTORS(SoftAAC2);
};
diff --git a/media/libstagefright/codecs/amrnb/dec/Android.mk b/media/libstagefright/codecs/amrnb/dec/Android.mk
index 76a7f40..21109d9 100644
--- a/media/libstagefright/codecs/amrnb/dec/Android.mk
+++ b/media/libstagefright/codecs/amrnb/dec/Android.mk
@@ -80,6 +80,7 @@ LOCAL_SHARED_LIBRARIES := \
libstagefright_amrnb_common
LOCAL_MODULE := libstagefright_soft_amrdec
+LOCAL_CLANG := false
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp b/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp
index a9723ea..f8316fd 100644
--- a/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp
+++ b/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp
@@ -352,7 +352,14 @@ void SoftAMR::onQueueFilled(OMX_U32 /* portIndex */) {
}
size_t frameSize = getFrameSize(mode);
- CHECK_GE(inHeader->nFilledLen, frameSize);
+ if (inHeader->nFilledLen < frameSize) {
+ ALOGE("Filled length vs frameSize %u vs %lu. Corrupt clip?",
+ inHeader->nFilledLen, frameSize);
+
+ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+ mSignalledError = true;
+ return;
+ }
int16_t *outPtr = (int16_t *)outHeader->pBuffer;
diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
index f743b1c..4c4da60 100644
--- a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
+++ b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
@@ -51,7 +51,9 @@ SoftMP3::SoftMP3(
mSignalledError(false),
mSawInputEos(false),
mSignalledOutputEos(false),
- mOutputPortSettingsChange(NONE) {
+ mOutputPortSettingsChange(NONE),
+ mLastAnchorTimeUs(-1),
+ mNextOutBufferTimeUs(0) {
initPorts();
initDecoder();
}
@@ -112,7 +114,7 @@ void SoftMP3::initPorts() {
void SoftMP3::initDecoder() {
mConfig->equalizerType = flat;
mConfig->crcEnabled = false;
-
+ mConfig->samplingRate = mSamplingRate;
uint32_t memRequirements = pvmp3_decoderMemRequirements();
mDecoderBuf = malloc(memRequirements);
@@ -212,7 +214,7 @@ void SoftMP3::onQueueFilled(OMX_U32 /* portIndex */) {
List<BufferInfo *> &inQueue = getPortQueue(0);
List<BufferInfo *> &outQueue = getPortQueue(1);
-
+ int64_t tmpTime = 0;
while ((!inQueue.empty() || (mSawInputEos && !mSignalledOutputEos)) && !outQueue.empty()) {
BufferInfo *inInfo = NULL;
OMX_BUFFERHEADERTYPE *inHeader = NULL;
@@ -227,7 +229,20 @@ void SoftMP3::onQueueFilled(OMX_U32 /* portIndex */) {
if (inHeader) {
if (inHeader->nOffset == 0 && inHeader->nFilledLen) {
- mAnchorTimeUs = inHeader->nTimeStamp;
+ // use new input buffer timestamp as Anchor Time if its
+ // a) first buffer or
+ // b) first buffer post seek or
+ // c) different from last buffer timestamp
+ //If input buffer timestamp is same as last input buffer timestamp then
+ //treat this as a erroneous timestamp and ignore new input buffer
+ //timestamp and use last output buffer timestamp as Anchor Time.
+ if ((mLastAnchorTimeUs != inHeader->nTimeStamp)) {
+ mAnchorTimeUs = inHeader->nTimeStamp;
+ mLastAnchorTimeUs = inHeader->nTimeStamp;
+ } else {
+ mAnchorTimeUs = mNextOutBufferTimeUs;
+ }
+
mNumFramesOutput = 0;
}
@@ -259,10 +274,13 @@ void SoftMP3::onQueueFilled(OMX_U32 /* portIndex */) {
if (decoderErr != NO_ENOUGH_MAIN_DATA_ERROR
&& decoderErr != SIDE_INFO_ERROR) {
ALOGE("mp3 decoder returned error %d", decoderErr);
-
- notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
- mSignalledError = true;
- return;
+ if(decoderErr == SYNCH_LOST_ERROR) {
+ mConfig->outputFrameSize = kOutputBufferSize / sizeof(int16_t);
+ } else {
+ notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
+ mSignalledError = true;
+ return;
+ }
}
if (mConfig->outputFrameSize == 0) {
@@ -323,7 +341,7 @@ void SoftMP3::onQueueFilled(OMX_U32 /* portIndex */) {
outHeader->nTimeStamp =
mAnchorTimeUs + (mNumFramesOutput * 1000000ll) / mSamplingRate;
-
+ tmpTime = outHeader->nTimeStamp;
if (inHeader) {
CHECK_GE(inHeader->nFilledLen, mConfig->inputBufferUsedLength);
@@ -348,6 +366,10 @@ void SoftMP3::onQueueFilled(OMX_U32 /* portIndex */) {
notifyFillBufferDone(outHeader);
outHeader = NULL;
}
+
+ if (tmpTime > 0) {
+ mNextOutBufferTimeUs = tmpTime;
+ }
}
void SoftMP3::onPortFlushCompleted(OMX_U32 portIndex) {
@@ -359,6 +381,8 @@ void SoftMP3::onPortFlushCompleted(OMX_U32 portIndex) {
mSignalledError = false;
mSawInputEos = false;
mSignalledOutputEos = false;
+ mLastAnchorTimeUs = -1;
+ mNextOutBufferTimeUs = 0;
}
}
@@ -395,6 +419,8 @@ void SoftMP3::onReset() {
mSawInputEos = false;
mSignalledOutputEos = false;
mOutputPortSettingsChange = NONE;
+ mLastAnchorTimeUs = -1;
+ mNextOutBufferTimeUs = 0;
}
} // namespace android
diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.h b/media/libstagefright/codecs/mp3dec/SoftMP3.h
index f9e7b53..c769795 100644
--- a/media/libstagefright/codecs/mp3dec/SoftMP3.h
+++ b/media/libstagefright/codecs/mp3dec/SoftMP3.h
@@ -70,6 +70,9 @@ private:
AWAITING_ENABLED
} mOutputPortSettingsChange;
+ int64_t mLastAnchorTimeUs;
+ int64_t mNextOutBufferTimeUs;
+
void initPorts();
void initDecoder();
diff --git a/media/libstagefright/codecs/raw/SoftRaw.cpp b/media/libstagefright/codecs/raw/SoftRaw.cpp
index 9d514a6..0d80098 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);
}
@@ -58,7 +59,7 @@ void SoftRaw::initPorts() {
def.eDir = OMX_DirInput;
def.nBufferCountMin = kNumBuffers;
def.nBufferCountActual = def.nBufferCountMin;
- def.nBufferSize = 32 * 1024;
+ def.nBufferSize = 192 * 1024;
def.bEnabled = OMX_TRUE;
def.bPopulated = OMX_FALSE;
def.eDomain = OMX_PortDomainAudio;
@@ -76,7 +77,7 @@ void SoftRaw::initPorts() {
def.eDir = OMX_DirOutput;
def.nBufferCountMin = kNumBuffers;
def.nBufferCountActual = def.nBufferCountMin;
- def.nBufferSize = 32 * 1024;
+ def.nBufferSize = 192 * 1024;
def.bEnabled = OMX_TRUE;
def.bPopulated = OMX_FALSE;
def.eDomain = OMX_PortDomainAudio;
@@ -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 015c4a3..894889f 100644
--- a/media/libstagefright/codecs/raw/SoftRaw.h
+++ b/media/libstagefright/codecs/raw/SoftRaw.h
@@ -43,13 +43,14 @@ protected:
private:
enum {
- kNumBuffers = 4
+ kNumBuffers = 8
};
bool mSignalledError;
int32_t mChannelCount;
int32_t mSampleRate;
+ int32_t mBitsPerSample;
void initPorts();
status_t initDecoder();
diff --git a/media/libstagefright/data/media_codecs_google_video.xml b/media/libstagefright/data/media_codecs_google_video.xml
index 81a6d00..07e26a2 100644
--- a/media/libstagefright/data/media_codecs_google_video.xml
+++ b/media/libstagefright/data/media_codecs_google_video.xml
@@ -16,7 +16,14 @@
<Included>
<Decoders>
- <MediaCodec name="OMX.google.mpeg4.decoder" type="video/mp4v-es">
+ <MediaCodec name="OMX.google.mpeg4.decoder">
+ <Type name="video/mp4v-es" />
+ <!--
+ Use Google mpeg4 decoder for mpeg4 DP content which is not
+ supported by HW. A component can be used to support several
+ mimetypes, so non-DP mpeg4 usecases will not be affected by this.
+ -->
+ <Type name="video/mp4v-esdp" />
<!-- profiles and levels: ProfileSimple : Level3 -->
<Limit name="size" min="2x2" max="352x288" />
<Limit name="alignment" value="2x2" />
diff --git a/media/libstagefright/foundation/ABuffer.cpp b/media/libstagefright/foundation/ABuffer.cpp
index a5b81a8..3ebbbd9 100644
--- a/media/libstagefright/foundation/ABuffer.cpp
+++ b/media/libstagefright/foundation/ABuffer.cpp
@@ -29,13 +29,9 @@ ABuffer::ABuffer(size_t capacity)
mInt32Data(0),
mOwnsData(true) {
mData = malloc(capacity);
- if (mData == NULL) {
- mCapacity = 0;
- mRangeLength = 0;
- } else {
- mCapacity = capacity;
- mRangeLength = capacity;
- }
+ CHECK(mData != NULL);
+ mCapacity = capacity;
+ mRangeLength = capacity;
}
ABuffer::ABuffer(void *data, size_t capacity)
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 1557401..1b0b1c5 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -54,7 +54,7 @@ const int64_t LiveSession::kReadyMarkUs = 5000000ll;
const int64_t LiveSession::kPrepareMarkUs = 1500000ll;
const int64_t LiveSession::kUnderflowMarkUs = 1000000ll;
-struct LiveSession::BandwidthEstimator : public RefBase {
+struct LiveSession::BandwidthEstimator : public LiveSession::BandwidthBaseEstimator {
BandwidthEstimator();
void addBandwidthMeasurement(size_t numBytes, int64_t delayUs);
@@ -1064,6 +1064,7 @@ void LiveSession::onMasterPlaylistFetched(const sp<AMessage> &msg) {
itemsWithVideo.push(item);
}
}
+#if 0
// remove the audio-only variants if we have at least one with video
if (!itemsWithVideo.empty()
&& itemsWithVideo.size() < mBandwidthItems.size()) {
@@ -1072,7 +1073,7 @@ void LiveSession::onMasterPlaylistFetched(const sp<AMessage> &msg) {
mBandwidthItems.push(itemsWithVideo[i]);
}
}
-
+#endif
CHECK_GT(mBandwidthItems.size(), 0u);
initialBandwidth = mBandwidthItems[0].mBandwidth;
diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h
index 90d56d0..0d504e4 100644
--- a/media/libstagefright/httplive/LiveSession.h
+++ b/media/libstagefright/httplive/LiveSession.h
@@ -73,7 +73,7 @@ struct LiveSession : public AHandler {
const sp<IMediaHTTPService> &httpService);
int64_t calculateMediaTimeUs(int64_t firstTimeUs, int64_t timeUs, int32_t discontinuitySeq);
- status_t dequeueAccessUnit(StreamType stream, sp<ABuffer> *accessUnit);
+ virtual status_t dequeueAccessUnit(StreamType stream, sp<ABuffer> *accessUnit);
status_t getStreamFormat(StreamType stream, sp<AMessage> *format);
@@ -117,7 +117,6 @@ protected:
virtual void onMessageReceived(const sp<AMessage> &msg);
-private:
friend struct PlaylistFetcher;
enum {
@@ -142,6 +141,14 @@ private:
static const int64_t kPrepareMarkUs;
static const int64_t kUnderflowMarkUs;
+ struct BandwidthBaseEstimator : public RefBase {
+ virtual void addBandwidthMeasurement(size_t numBytes, int64_t delayUs) = 0;
+ virtual bool estimateBandwidth(
+ int32_t *bandwidth,
+ bool *isStable = NULL,
+ int32_t *shortTermBps = NULL) = 0;
+ };
+
struct BandwidthEstimator;
struct BandwidthItem {
size_t mPlaylistIndex;
@@ -201,7 +208,7 @@ private:
ssize_t mOrigBandwidthIndex;
int32_t mLastBandwidthBps;
bool mLastBandwidthStable;
- sp<BandwidthEstimator> mBandwidthEstimator;
+ sp<BandwidthBaseEstimator> mBandwidthEstimator;
sp<M3UParser> mPlaylist;
int32_t mMaxWidth;
@@ -251,10 +258,10 @@ private:
KeyedVector<size_t, int64_t> mDiscontinuityAbsStartTimesUs;
KeyedVector<size_t, int64_t> mDiscontinuityOffsetTimesUs;
- sp<PlaylistFetcher> addFetcher(const char *uri);
+ virtual sp<PlaylistFetcher> addFetcher(const char *uri);
void onConnect(const sp<AMessage> &msg);
- void onMasterPlaylistFetched(const sp<AMessage> &msg);
+ virtual void onMasterPlaylistFetched(const sp<AMessage> &msg);
void onSeek(const sp<AMessage> &msg);
bool UriIsSameAsIndex( const AString &uri, int32_t index, bool newUri);
@@ -269,7 +276,7 @@ private:
float getAbortThreshold(
ssize_t currentBWIndex, ssize_t targetBWIndex) const;
void addBandwidthMeasurement(size_t numBytes, int64_t delayUs);
- size_t getBandwidthIndex(int32_t bandwidthBps);
+ virtual size_t getBandwidthIndex(int32_t bandwidthBps);
ssize_t getLowestValidBandwidthIndex() const;
HLSTime latestMediaSegmentStartTime() const;
@@ -284,7 +291,7 @@ private:
void onChangeConfiguration2(const sp<AMessage> &msg);
void onChangeConfiguration3(const sp<AMessage> &msg);
- void swapPacketSource(StreamType stream);
+ virtual void swapPacketSource(StreamType stream);
void tryToFinishBandwidthSwitch(const AString &oldUri);
void cancelBandwidthSwitch(bool resume = false);
bool checkSwitchProgress(
@@ -296,7 +303,7 @@ private:
void schedulePollBuffering();
void cancelPollBuffering();
void restartPollBuffering();
- void onPollBuffering();
+ virtual void onPollBuffering();
bool checkBuffering(bool &underflow, bool &ready, bool &down, bool &up);
void startBufferingIfNecessary();
void stopBufferingIfNecessary();
@@ -304,7 +311,7 @@ private:
void finishDisconnect();
- void postPrepared(status_t err);
+ virtual void postPrepared(status_t err);
void postError(status_t err);
DISALLOW_EVIL_CONSTRUCTORS(LiveSession);
diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp
index 72d832e..023de93 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.cpp
+++ b/media/libstagefright/httplive/PlaylistFetcher.cpp
@@ -975,7 +975,9 @@ bool PlaylistFetcher::initDownloadState(
if (mSegmentStartTimeUs < 0) {
if (!mPlaylist->isComplete() && !mPlaylist->isEvent()) {
// If this is a live session, start 3 segments from the end on connect
- mSeqNumber = lastSeqNumberInPlaylist - 3;
+ if (!getSeqNumberInLiveStreaming()) {
+ mSeqNumber = lastSeqNumberInPlaylist - 3;
+ }
if (mSeqNumber < firstSeqNumberInPlaylist) {
mSeqNumber = firstSeqNumberInPlaylist;
}
@@ -1418,6 +1420,10 @@ void PlaylistFetcher::onDownloadNext() {
}
}
+ if (checkSwitchBandwidth()) {
+ return;
+ }
+
++mSeqNumber;
// if adapting, pause after found the next starting point
diff --git a/media/libstagefright/httplive/PlaylistFetcher.h b/media/libstagefright/httplive/PlaylistFetcher.h
index c8ca457..6b60b65 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.h
+++ b/media/libstagefright/httplive/PlaylistFetcher.h
@@ -89,7 +89,6 @@ protected:
virtual ~PlaylistFetcher();
virtual void onMessageReceived(const sp<AMessage> &msg);
-private:
enum {
kMaxNumRetries = 5,
};
@@ -249,6 +248,8 @@ private:
void updateDuration();
void updateTargetDuration();
+ virtual bool checkSwitchBandwidth() { return false; }
+ virtual bool getSeqNumberInLiveStreaming() { return false; }
DISALLOW_EVIL_CONSTRUCTORS(PlaylistFetcher);
};
diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index 4410579..76d65f0 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -503,8 +503,9 @@ void ID3::Iterator::getString(String8 *id, String8 *comment) const {
void ID3::Iterator::getstring(String8 *id, bool otherdata) const {
id->setTo("");
- const uint8_t *frameData = mFrameData;
- if (frameData == NULL) {
+ size_t size;
+ const uint8_t *frameData = getData(&size);
+ if ((size == 0) || (frameData == NULL)) {
return;
}
diff --git a/media/libstagefright/include/AACExtractor.h b/media/libstagefright/include/AACExtractor.h
index e98ca82..9a0ba2f 100644
--- a/media/libstagefright/include/AACExtractor.h
+++ b/media/libstagefright/include/AACExtractor.h
@@ -21,6 +21,7 @@
#include <media/stagefright/MediaExtractor.h>
#include <utils/Vector.h>
+#include "include/APE.h"
namespace android {
@@ -48,6 +49,9 @@ private:
Vector<uint64_t> mOffsetVector;
int64_t mFrameDurationUs;
+ APE ape;
+ sp<MetaData> 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 0000000..db49bb0
--- /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 <utils/RefBase.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MetaData.h>
+
+namespace android {
+
+class APE{
+public:
+ APE();
+ ~APE();
+ bool isAPE(uint8_t *apeTag) const;
+ bool parseAPE(const sp<DataSource> &source, off64_t offset,
+ sp<MetaData> &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 758b2c9..c72f9f6 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -193,6 +193,7 @@ private:
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/NuCachedSource2.h b/media/libstagefright/include/NuCachedSource2.h
index a29bdf9..afa91ae 100644
--- a/media/libstagefright/include/NuCachedSource2.h
+++ b/media/libstagefright/include/NuCachedSource2.h
@@ -69,7 +69,7 @@ struct NuCachedSource2 : public DataSource {
protected:
virtual ~NuCachedSource2();
-private:
+protected:
friend struct AHandlerReflector<NuCachedSource2>;
NuCachedSource2(
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index ecc2573..ff81379 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -31,6 +31,7 @@
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
#include <utils/String8.h>
+#include <media/stagefright/foundation/ABitReader.h>
#include <inttypes.h>
@@ -136,6 +137,7 @@ private:
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<MediaBuffer *>::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<MetaData> &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/Android.mk b/media/libstagefright/omx/Android.mk
index 5f0f567..d16d5df 100644
--- a/media/libstagefright/omx/Android.mk
+++ b/media/libstagefright/omx/Android.mk
@@ -30,6 +30,12 @@ LOCAL_SHARED_LIBRARIES := \
libstagefright_foundation \
libdl
+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_MODULE:= libstagefright_omx
LOCAL_CFLAGS += -Werror -Wall
LOCAL_CLANG := true
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index 7f357c9..efb1a1c 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -468,6 +468,10 @@ OMX_ERRORTYPE OMX::OnEvent(
findInstance(node)->onEvent(eEvent, nData1, nData2);
sp<OMX::CallbackDispatcher> dispatcher = findDispatcher(node);
+ if (dispatcher == NULL) {
+ ALOGW("OnEvent Callback dispatcher NULL, skip post");
+ return OMX_ErrorNone;
+ }
// output rendered events are not processed as regular events until they hit the observer
if (eEvent == OMX_EventOutputRendered) {
@@ -513,7 +517,12 @@ OMX_ERRORTYPE OMX::OnEmptyBufferDone(
msg.fenceFd = fenceFd;
msg.u.buffer_data.buffer = buffer;
- findDispatcher(node)->post(msg);
+ sp<OMX::CallbackDispatcher> callbackDispatcher = findDispatcher(node);
+ if (callbackDispatcher != NULL) {
+ callbackDispatcher->post(msg);
+ } else {
+ ALOGW("OnEmptyBufferDone Callback dispatcher NULL, skip post");
+ }
return OMX_ErrorNone;
}
@@ -532,7 +541,12 @@ OMX_ERRORTYPE OMX::OnFillBufferDone(
msg.u.extended_buffer_data.flags = pBuffer->nFlags;
msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp;
- findDispatcher(node)->post(msg);
+ sp<OMX::CallbackDispatcher> callbackDispatcher = findDispatcher(node);
+ if (callbackDispatcher != NULL) {
+ callbackDispatcher->post(msg);
+ } else {
+ ALOGW("OnFillBufferDone Callback dispatcher NULL, skip post");
+ }
return OMX_ErrorNone;
}
diff --git a/media/libstagefright/omx/OMXMaster.cpp b/media/libstagefright/omx/OMXMaster.cpp
index ae3cb33..f7bb733 100644
--- a/media/libstagefright/omx/OMXMaster.cpp
+++ b/media/libstagefright/omx/OMXMaster.cpp
@@ -25,52 +25,58 @@
#include <dlfcn.h>
#include <media/stagefright/foundation/ADebug.h>
+#include <cutils/properties.h>
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<OMXPluginBase *>::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 6069741..c07fed3 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<OMXPluginBase *> mPlugins;
+ KeyedVector<OMXPluginBase *, void *> mPlugins;
KeyedVector<String8, OMXPluginBase *> mPluginByComponentName;
KeyedVector<OMX_COMPONENTTYPE *, OMXPluginBase *> 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 94a213a..4bcc732 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -122,7 +122,8 @@ struct BufferMeta {
}
// check component returns proper range
- sp<ABuffer> codec = getBuffer(header, false /* backup */, true /* limit */);
+ sp<ABuffer> codec = getBuffer(header, false /* backup */,
+ !(header->nFlags & OMX_BUFFERFLAG_EXTRADATA));
memcpy((OMX_U8 *)mMem->pointer() + header->nOffset, codec->data(), codec->size());
}
@@ -132,9 +133,11 @@ struct BufferMeta {
return;
}
+ size_t bytesToCopy = header->nFlags & OMX_BUFFERFLAG_EXTRADATA ?
+ header->nAllocLen - header->nOffset : header->nFilledLen;
memcpy(header->pBuffer + header->nOffset,
(const OMX_U8 *)mMem->pointer() + header->nOffset,
- header->nFilledLen);
+ bytesToCopy);
}
// return either the codec or the backup buffer
@@ -279,6 +282,7 @@ status_t OMXNodeInstance::freeNode(OMXMaster *master) {
OMX_STATETYPE state;
CHECK_EQ(OMX_GetState(mHandle, &state), OMX_ErrorNone);
switch (state) {
+ case OMX_StatePause:
case OMX_StateExecuting:
{
ALOGV("forcing Executing->Idle");
diff --git a/media/libstagefright/omx/SoftOMXPlugin.cpp b/media/libstagefright/omx/SoftOMXPlugin.cpp
index 0f9c00c..4afd5d5 100755
--- a/media/libstagefright/omx/SoftOMXPlugin.cpp
+++ b/media/libstagefright/omx/SoftOMXPlugin.cpp
@@ -59,6 +59,9 @@ static const struct {
{ "OMX.google.raw.decoder", "rawdec", "audio_decoder.raw" },
{ "OMX.google.flac.encoder", "flacenc", "audio_encoder.flac" },
{ "OMX.google.gsm.decoder", "gsmdec", "audio_decoder.gsm" },
+#ifdef QTI_FLAC_DECODER
+ { "OMX.qti.audio.decoder.flac", "flacdec", "audio_decoder.flac" },
+#endif
};
static const size_t kNumComponents =
@@ -74,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;
@@ -91,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 **);
@@ -101,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/rtsp/AH263Assembler.cpp b/media/libstagefright/rtsp/AH263Assembler.cpp
index 75cd911..28594e2 100644
--- a/media/libstagefright/rtsp/AH263Assembler.cpp
+++ b/media/libstagefright/rtsp/AH263Assembler.cpp
@@ -27,6 +27,8 @@
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/Utils.h>
+#include <mediaplayerservice/AVMediaServiceExtensions.h>
+
namespace android {
AH263Assembler::AH263Assembler(const sp<AMessage> &notify)
@@ -63,7 +65,8 @@ ARTPAssembler::AssemblyStatus AH263Assembler::addPacket(
if ((uint32_t)(*it)->int32Data() >= mNextExpectedSeqNo) {
break;
}
-
+ AVMediaServiceUtils::get()->addH263AdvancedPacket(
+ *it, &mPackets, mAccessUnitRTPTime);
it = queue->erase(it);
}
diff --git a/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp b/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
index a1a6576..d239e7b 100644
--- a/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
+++ b/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
@@ -420,6 +420,11 @@ sp<ABuffer> AMPEG4AudioAssembler::removeLATMFraming(const sp<ABuffer> &buffer) {
CHECK_LE(offset + (mOtherDataLenBits / 8), buffer->size());
offset += mOtherDataLenBits / 8;
}
+
+ if (i < mNumSubFrames && offset >= buffer->size()) {
+ ALOGW("Skip subframes after %d, total %d", (int)i, (int)mNumSubFrames);
+ break;
+ }
}
if (offset < buffer->size()) {
diff --git a/media/libstagefright/rtsp/ARTPConnection.cpp b/media/libstagefright/rtsp/ARTPConnection.cpp
index a86ab74..e021b29 100644
--- a/media/libstagefright/rtsp/ARTPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTPConnection.cpp
@@ -81,7 +81,8 @@ void ARTPConnection::addStream(
const sp<ASessionDescription> &sessionDesc,
size_t index,
const sp<AMessage> &notify,
- bool injected) {
+ bool injected,
+ bool isIPV6) {
sp<AMessage> msg = new AMessage(kWhatAddStream, this);
msg->setInt32("rtp-socket", rtpSocket);
msg->setInt32("rtcp-socket", rtcpSocket);
@@ -89,6 +90,7 @@ void ARTPConnection::addStream(
msg->setSize("index", index);
msg->setMessage("notify", notify);
msg->setInt32("injected", injected);
+ msg->setInt32("isIPV6", isIPV6);
msg->post();
}
@@ -145,6 +147,10 @@ void ARTPConnection::MakePortPair(
TRESPASS();
}
+size_t ARTPConnection::sockAddrSize() {
+ return sizeof(struct sockaddr_in);
+}
+
void ARTPConnection::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
case kWhatAddStream:
@@ -345,7 +351,7 @@ void ARTPConnection::onPollStreams() {
n = sendto(
s->mRTCPSocket, buffer->data(), buffer->size(), 0,
(const struct sockaddr *)&s->mRemoteRTCPAddr,
- sizeof(s->mRemoteRTCPAddr));
+ sockAddrSize());
} while (n < 0 && errno == EINTR);
if (n <= 0) {
diff --git a/media/libstagefright/rtsp/ARTPConnection.h b/media/libstagefright/rtsp/ARTPConnection.h
index edbcc35..057007b 100644
--- a/media/libstagefright/rtsp/ARTPConnection.h
+++ b/media/libstagefright/rtsp/ARTPConnection.h
@@ -38,7 +38,8 @@ struct ARTPConnection : public AHandler {
int rtpSocket, int rtcpSocket,
const sp<ASessionDescription> &sessionDesc, size_t index,
const sp<AMessage> &notify,
- bool injected);
+ bool injected,
+ bool isIPV6 = false);
void removeStream(int rtpSocket, int rtcpSocket);
@@ -53,8 +54,8 @@ struct ARTPConnection : public AHandler {
protected:
virtual ~ARTPConnection();
virtual void onMessageReceived(const sp<AMessage> &msg);
+ virtual size_t sockAddrSize();
-private:
enum {
kWhatAddStream,
kWhatRemoveStream,
@@ -72,7 +73,7 @@ private:
bool mPollEventPending;
int64_t mLastReceiverReportTimeUs;
- void onAddStream(const sp<AMessage> &msg);
+ virtual void onAddStream(const sp<AMessage> &msg);
void onRemoveStream(const sp<AMessage> &msg);
void onPollStreams();
void onInjectPacket(const sp<AMessage> &msg);
diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp
index 855ffdc..b2c1fd1 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTSPConnection.cpp
@@ -26,6 +26,7 @@
#include <media/stagefright/foundation/base64.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/Utils.h>
+#include <mediaplayerservice/AVMediaServiceExtensions.h>
#include <arpa/inet.h>
#include <fcntl.h>
@@ -170,7 +171,7 @@ bool ARTSPConnection::ParseURL(
}
}
- const char *colonPos = strchr(host->c_str(), ':');
+ const char *colonPos = AVMediaServiceUtils::get()->parseURL(host);
if (colonPos != NULL) {
unsigned long x;
@@ -252,6 +253,11 @@ void ARTSPConnection::onConnect(const sp<AMessage> &msg) {
ALOGV("user = '%s', pass = '%s'", mUser.c_str(), mPass.c_str());
}
+ performConnect(reply, host, port);
+}
+
+void ARTSPConnection::performConnect(const sp<AMessage> &reply,
+ AString host, unsigned port) {
struct hostent *ent = gethostbyname(host.c_str());
if (ent == NULL) {
ALOGE("Unknown host %s", host.c_str());
@@ -381,7 +387,12 @@ void ARTSPConnection::onCompleteConnection(const sp<AMessage> &msg) {
socklen_t optionLen = sizeof(err);
CHECK_EQ(getsockopt(mSocket, SOL_SOCKET, SO_ERROR, &err, &optionLen), 0);
CHECK_EQ(optionLen, (socklen_t)sizeof(err));
+ performCompleteConnection(msg, err);
+}
+void ARTSPConnection::performCompleteConnection(const sp<AMessage> &msg, int err) {
+ sp<AMessage> reply;
+ CHECK(msg->findMessage("reply", &reply));
if (err != 0) {
ALOGE("err = %d (%s)", err, strerror(err));
diff --git a/media/libstagefright/rtsp/ARTSPConnection.h b/media/libstagefright/rtsp/ARTSPConnection.h
index 1fe9c99..c4ebe1d 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.h
+++ b/media/libstagefright/rtsp/ARTSPConnection.h
@@ -42,6 +42,8 @@ struct ARTSPConnection : public AHandler {
void observeBinaryData(const sp<AMessage> &reply);
+ virtual bool isIPV6() { return false; }
+
static bool ParseURL(
const char *url, AString *host, unsigned *port, AString *path,
AString *user, AString *pass);
@@ -49,8 +51,11 @@ struct ARTSPConnection : public AHandler {
protected:
virtual ~ARTSPConnection();
virtual void onMessageReceived(const sp<AMessage> &msg);
+ virtual void performConnect(const sp<AMessage> &reply,
+ AString host, unsigned port);
+ virtual void performCompleteConnection(const sp<AMessage> &msg,
+ int err);
-private:
enum State {
DISCONNECTED,
CONNECTING,
diff --git a/media/libstagefright/rtsp/ASessionDescription.cpp b/media/libstagefright/rtsp/ASessionDescription.cpp
index 98498e9..92ad1ec 100644
--- a/media/libstagefright/rtsp/ASessionDescription.cpp
+++ b/media/libstagefright/rtsp/ASessionDescription.cpp
@@ -22,7 +22,7 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AString.h>
-
+#include <mediaplayerservice/AVMediaServiceExtensions.h>
#include <stdlib.h>
namespace android {
@@ -264,7 +264,8 @@ bool ASessionDescription::getDurationUs(int64_t *durationUs) const {
}
float from, to;
- if (!parseNTPRange(value.c_str() + 4, &from, &to)) {
+ if (!AVMediaServiceUtils::get()->parseNTPRange(
+ value.c_str() + 4, &from, &to)) {
return false;
}
diff --git a/media/libstagefright/rtsp/Android.mk b/media/libstagefright/rtsp/Android.mk
index c5e8c35..8bc4295 100644
--- a/media/libstagefright/rtsp/Android.mk
+++ b/media/libstagefright/rtsp/Android.mk
@@ -22,8 +22,10 @@ LOCAL_SRC_FILES:= \
LOCAL_SHARED_LIBRARIES += libcrypto
LOCAL_C_INCLUDES:= \
- $(TOP)/frameworks/av/media/libstagefright \
- $(TOP)/frameworks/native/include/media/openmax
+ $(TOP)/frameworks/av/media/libstagefright \
+ $(TOP)/frameworks/av/media/libavextensions \
+ $(TOP)/frameworks/native/include/media/openmax \
+ $(TOP)/frameworks/av/media/libmediaplayerservice \
LOCAL_MODULE:= libstagefright_rtsp
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 0d0baf3..7290ee2 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -32,6 +32,7 @@
#include "ASessionDescription.h"
#include <ctype.h>
+#include <cutils/properties.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -39,6 +40,7 @@
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/Utils.h>
+#include <mediaplayerservice/AVMediaServiceExtensions.h>
#include <arpa/inet.h>
#include <sys/socket.h>
@@ -64,6 +66,8 @@ static int64_t kDefaultKeepAliveTimeoutUs = 60000000ll;
static int64_t kPauseDelayUs = 3000000ll;
+static int64_t kTearDownTimeoutUs = 3000000ll;
+
namespace android {
static bool GetAttribute(const char *s, const char *key, AString *value) {
@@ -105,6 +109,8 @@ struct MyHandler : public AHandler {
kWhatEOS = 'eos!',
kWhatSeekDiscontinuity = 'seeD',
kWhatNormalPlayTimeMapping = 'nptM',
+ kWhatCancelCheck = 'canC',
+ kWhatByeReceived = 'byeR',
};
MyHandler(
@@ -115,8 +121,6 @@ struct MyHandler : public AHandler {
mUIDValid(uidValid),
mUID(uid),
mNetLooper(new ALooper),
- mConn(new ARTSPConnection(mUIDValid, mUID)),
- mRTPConn(new ARTPConnection),
mOriginalSessionURL(url),
mSessionURL(url),
mSetupTracksSuccessful(false),
@@ -140,11 +144,22 @@ struct MyHandler : public AHandler {
mPausing(false),
mPauseGeneration(0),
mPlayResponseParsed(false) {
+ mConn = AVMediaServiceFactory::get()->createARTSPConnection(
+ mUIDValid, uid);
+ mRTPConn = AVMediaServiceFactory::get()->createARTPConnection();
mNetLooper->setName("rtsp net");
mNetLooper->start(false /* runOnCallingThread */,
false /* canCallJava */,
PRIORITY_HIGHEST);
+ char value[PROPERTY_VALUE_MAX] = {0};
+ property_get("rtsp.transport.TCP", value, "false");
+ if (!strcasecmp(value, "true")) {
+ mTryTCPInterleaving = true;
+ } else {
+ mTryTCPInterleaving = false;
+ }
+
// Strip any authentication info from the session url, we don't
// want to transmit user/pass in cleartext.
AString host, path, user, pass;
@@ -244,6 +259,11 @@ struct MyHandler : public AHandler {
msg->post();
}
+ void cancelTimeoutCheck() {
+ sp<AMessage> msg = new AMessage('canC', this);
+ msg->post();
+ }
+
static void addRR(const sp<ABuffer> &buf) {
uint8_t *ptr = buf->data() + buf->size();
ptr[0] = 0x80 | 0;
@@ -703,6 +723,7 @@ struct MyHandler : public AHandler {
timeoutSecs);
}
}
+ AVMediaServiceUtils::get()->setServerTimeoutUs(mKeepAliveTimeoutUs);
i = mSessionID.find(";");
if (i >= 0) {
@@ -722,16 +743,19 @@ struct MyHandler : public AHandler {
// We are going to continue even if we were
// unable to poke a hole into the firewall...
- pokeAHole(
+ AVMediaServiceUtils::get()->pokeAHole(
+ this,
track->mRTPSocket,
track->mRTCPSocket,
- transport);
+ transport,
+ mSessionHost);
}
mRTPConn->addStream(
track->mRTPSocket, track->mRTCPSocket,
mSessionDesc, index,
- notify, track->mUsingInterleavedTCP);
+ notify, track->mUsingInterleavedTCP,
+ mConn->isIPV6());
mSetupTracksSuccessful = true;
} else {
@@ -774,6 +798,7 @@ struct MyHandler : public AHandler {
request.append(mSessionID);
request.append("\r\n");
+ AVMediaServiceUtils::get()->appendRange(&request);
request.append("\r\n");
sp<AMessage> reply = new AMessage('play', this);
@@ -922,6 +947,15 @@ struct MyHandler : public AHandler {
request.append("\r\n");
mConn->sendRequest(request.c_str(), reply);
+
+ // If the response of teardown hasn't been received in 3 seconds,
+ // post 'tear' message to avoid ANR.
+ if (!msg->findInt32("reconnect", &reconnect) || !reconnect) {
+ sp<AMessage> teardown = new AMessage('tear', this);
+ teardown->setInt32("result", -ECONNABORTED);
+ teardown->post(kTearDownTimeoutUs);
+ }
+
break;
}
@@ -1020,6 +1054,13 @@ struct MyHandler : public AHandler {
int32_t eos;
if (msg->findInt32("eos", &eos)) {
ALOGI("received BYE on track index %zu", trackIndex);
+ char value[PROPERTY_VALUE_MAX] = {0};
+ if (property_get("rtcp.bye.notify", value, "false")
+ && !strcasecmp(value, "true")) {
+ sp<AMessage> msg = mNotify->dup();
+ msg->setInt32("what", kWhatByeReceived);
+ msg->post();
+ }
if (!mAllTracksHaveTime && dataReceivedOnAllChannels()) {
ALOGI("No time established => fake existing data");
@@ -1386,6 +1427,13 @@ struct MyHandler : public AHandler {
break;
}
+ case 'canC':
+ {
+ ALOGV("cancel checking timeout");
+ mCheckGeneration++;
+ break;
+ }
+
default:
TRESPASS();
break;
@@ -1471,7 +1519,9 @@ struct MyHandler : public AHandler {
size_t trackIndex = 0;
while (trackIndex < mTracks.size()
- && !(val == mTracks.editItemAt(trackIndex).mURL)) {
+ && !(AVMediaServiceUtils::get()->parseTrackURL(
+ mTracks.editItemAt(trackIndex).mURL, val)
+ || val == mTracks.editItemAt(trackIndex).mURL)) {
++trackIndex;
}
CHECK_LT(trackIndex, mTracks.size());
@@ -1648,8 +1698,9 @@ private:
request.append(interleaveIndex + 1);
} else {
unsigned rtpPort;
- ARTPConnection::MakePortPair(
- &info->mRTPSocket, &info->mRTCPSocket, &rtpPort);
+ AVMediaServiceUtils::get()->makePortPair(
+ &info->mRTPSocket, &info->mRTCPSocket, &rtpPort,
+ mConn->isIPV6());
if (mUIDValid) {
HTTPBase::RegisterSocketUserTag(info->mRTPSocket, mUID,
@@ -1860,7 +1911,7 @@ private:
mLastMediaTimeUs = mediaTimeUs;
}
- if (mediaTimeUs < 0) {
+ if (mediaTimeUs < 0 && !mSeekable) {
ALOGV("dropping early accessUnit.");
return false;
}
diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
index b6de0d9..8aeabf0 100644
--- a/media/mediaserver/Android.mk
+++ b/media/mediaserver/Android.mk
@@ -50,6 +50,10 @@ LOCAL_C_INCLUDES := \
frameworks/av/services/radio \
external/sonic
+ifneq ($(BOARD_NUMBER_OF_CAMERAS),)
+ LOCAL_CFLAGS += -DMAX_CAMERAS=$(BOARD_NUMBER_OF_CAMERAS)
+endif
+
LOCAL_MODULE:= mediaserver
LOCAL_32_BIT_ONLY := true
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 07199e3..6a334e6 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -95,6 +95,7 @@ static const MtpEventCode kSupportedEventCodes[] = {
MTP_EVENT_STORE_ADDED,
MTP_EVENT_STORE_REMOVED,
MTP_EVENT_DEVICE_PROP_CHANGED,
+ MTP_EVENT_OBJECT_PROP_CHANGED,
};
MtpServer::MtpServer(int fd, MtpDatabase* database, bool ptp,
@@ -253,6 +254,11 @@ void MtpServer::sendObjectRemoved(MtpObjectHandle handle) {
sendEvent(MTP_EVENT_OBJECT_REMOVED, handle);
}
+void MtpServer::sendObjectUpdated(MtpObjectHandle handle) {
+ ALOGV("sendObjectUpdated %d\n", handle);
+ sendEvent(MTP_EVENT_OBJECT_PROP_CHANGED, handle);
+}
+
void MtpServer::sendStoreAdded(MtpStorageID id) {
ALOGV("sendStoreAdded %08X\n", id);
sendEvent(MTP_EVENT_STORE_ADDED, id);
diff --git a/media/mtp/MtpServer.h b/media/mtp/MtpServer.h
index b3a11e0..8bd0472 100644
--- a/media/mtp/MtpServer.h
+++ b/media/mtp/MtpServer.h
@@ -105,6 +105,7 @@ public:
void sendObjectAdded(MtpObjectHandle handle);
void sendObjectRemoved(MtpObjectHandle handle);
void sendDevicePropertyChanged(MtpDeviceProperty property);
+ void sendObjectUpdated(MtpObjectHandle handle);
private:
void sendStoreAdded(MtpStorageID id);
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 9b4ba79..474fb46 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -60,6 +60,14 @@ LOCAL_STATIC_LIBRARIES := \
libcpustats \
libmedia_helper
+#QTI Resampler
+ifeq ($(call is-vendor-board-platform,QCOM), true)
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_EXTN_RESAMPLER)), true)
+LOCAL_CFLAGS += -DQTI_RESAMPLER
+endif
+endif
+#QTI Resampler
+
LOCAL_MODULE:= libaudioflinger
LOCAL_32_BIT_ONLY := true
@@ -123,7 +131,19 @@ LOCAL_C_INCLUDES := \
LOCAL_SHARED_LIBRARIES := \
libcutils \
libdl \
- liblog
+ liblog \
+ libaudioutils
+
+#QTI Resampler
+ifeq ($(call is-vendor-board-platform,QCOM), true)
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_EXTN_RESAMPLER)), true)
+LOCAL_SRC_FILES_$(TARGET_2ND_ARCH) += AudioResamplerQTI.cpp.arm
+LOCAL_C_INCLUDES_$(TARGET_2ND_ARCH) += $(TARGET_OUT_HEADERS)/mm-audio/audio-src
+LOCAL_SHARED_LIBRARIES_$(TARGET_2ND_ARCH) += libqct_resampler
+LOCAL_CFLAGS_$(TARGET_2ND_ARCH) += -DQTI_RESAMPLER
+endif
+endif
+#QTI Resampler
LOCAL_MODULE := libaudioresampler
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 9ec5802..d7af22c 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -131,6 +131,14 @@ const char *formatToString(audio_format_t format) {
case AUDIO_FORMAT_OPUS: return "opus";
case AUDIO_FORMAT_AC3: return "ac-3";
case AUDIO_FORMAT_E_AC3: return "e-ac-3";
+ case AUDIO_FORMAT_PCM_OFFLOAD:
+ switch (format) {
+ case AUDIO_FORMAT_PCM_16_BIT_OFFLOAD: return "pcm-16bit-offload";
+ case AUDIO_FORMAT_PCM_24_BIT_OFFLOAD: return "pcm-24bit-offload";
+ default:
+ break;
+ }
+ break;
default:
break;
}
@@ -1053,9 +1061,24 @@ status_t AudioFlinger::setParameters(audio_io_handle_t ioHandle, const String8&
}
mHardwareStatus = AUDIO_HW_IDLE;
}
- // disable AEC and NS if the device is a BT SCO headset supporting those pre processings
+
AudioParameter param = AudioParameter(keyValuePairs);
- String8 value;
+ String8 value, key;
+ key = String8("SND_CARD_STATUS");
+ if (param.get(key, value) == NO_ERROR) {
+ ALOGV("Set keySoundCardStatus:%s", value.string());
+ if ((value.find("OFFLINE", 0) != -1) ) {
+ ALOGV("OFFLINE detected - call InvalidateTracks()");
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+ PlaybackThread *thread = mPlaybackThreads.valueAt(i).get();
+ if( thread->getOutput()->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD ){
+ thread->invalidateTracks(AUDIO_STREAM_MUSIC);
+ }
+ }
+ }
+ }
+
+ // disable AEC and NS if the device is a BT SCO headset supporting those pre processings
if (param.get(String8(AUDIO_PARAMETER_KEY_BT_NREC), value) == NO_ERROR) {
bool btNrecIsOff = (value == AUDIO_PARAMETER_VALUE_OFF);
if (mBtNrecIsOff != btNrecIsOff) {
@@ -1353,11 +1376,10 @@ AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid)
: RefBase(),
mAudioFlinger(audioFlinger),
// FIXME should be a "k" constant not hard-coded, in .h or ro. property, see 4 lines below
- mMemoryDealer(new MemoryDealer(1024*1024, "AudioFlinger::Client")),
+ mMemoryDealer(new MemoryDealer(4100*1024, "AudioFlinger::Client")), //4MB + 1 more 4k page
mPid(pid),
mTimedTrackCount(0)
{
- // 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer
}
// Client destructor must be called with AudioFlinger::mClientLock held
@@ -1818,7 +1840,11 @@ sp<AudioFlinger::PlaybackThread> AudioFlinger::openOutput_l(audio_module_handle_
|| !isValidPcmSinkFormat(config->format)
|| !isValidPcmSinkChannelMask(config->channel_mask)) {
thread = new DirectOutputThread(this, outputStream, *output, devices, mSystemReady);
- ALOGV("openOutput_l() created direct output: ID %d thread %p", *output, thread);
+ ALOGV("openOutput_l() created direct output: ID %d thread %p ", *output, thread);
+ //Check if this is DirectPCM, if so
+ if (flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM) {
+ thread->mIsDirectPcm = true;
+ }
} else {
thread = new MixerThread(this, outputStream, *output, devices, mSystemReady);
ALOGV("openOutput_l() created mixer output: ID %d thread %p", *output, thread);
@@ -2960,6 +2986,7 @@ void AudioFlinger::dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_hand
bool firstRead = true;
#define TEE_SINK_READ 1024 // frames per I/O operation
void *buffer = malloc(TEE_SINK_READ * frameSize);
+ CHECK (buffer != NULL);
for (;;) {
size_t count = TEE_SINK_READ;
ssize_t actual = teeSource->read(buffer, count,
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index 8a9a837..27a2f65 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -85,6 +85,9 @@ static const bool kUseFloat = true;
// Set to default copy buffer size in frames for input processing.
static const size_t kCopyBufferFrameCount = 256;
+#ifdef QTI_RESAMPLER
+#define QTI_RESAMPLER_MAX_SAMPLERATE 192000
+#endif
namespace android {
// ----------------------------------------------------------------------------
@@ -779,6 +782,13 @@ bool AudioMixer::track_t::setResampler(uint32_t trackSampleRate, uint32_t devSam
// but if none exists, it is the channel count (1 for mono).
const int resamplerChannelCount = downmixerBufferProvider != NULL
? mMixerChannelCount : channelCount;
+#ifdef QTI_RESAMPLER
+ if ((trackSampleRate <= QTI_RESAMPLER_MAX_SAMPLERATE) &&
+ (trackSampleRate > devSampleRate * 2) &&
+ ((devSampleRate == 48000)||(devSampleRate == 44100))) {
+ quality = AudioResampler::QTI_QUALITY;
+ }
+#endif
ALOGVV("Creating resampler:"
" format(%#x) channels(%d) devSampleRate(%u) quality(%d)\n",
mMixerInFormat, resamplerChannelCount, devSampleRate, quality);
@@ -1644,6 +1654,9 @@ void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state,
// Note: In case of later int16_t sink output,
// conversion and clamping is done by memcpy_to_i16_from_float().
} while (--outFrames);
+ //assign fout to out, when no more frames are available, so that 0s
+ //can be filled at the right place
+ out = (int32_t *)fout;
break;
case AUDIO_FORMAT_PCM_16_BIT:
if (CC_UNLIKELY(uint32_t(vl) > UNITY_GAIN_INT || uint32_t(vr) > UNITY_GAIN_INT)) {
diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h
index 7165c6c..f0ae4ec 100644
--- a/services/audioflinger/AudioMixer.h
+++ b/services/audioflinger/AudioMixer.h
@@ -137,6 +137,7 @@ public:
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/AudioResampler.cpp b/services/audioflinger/AudioResampler.cpp
index e49b7b1..ab3294a 100644
--- a/services/audioflinger/AudioResampler.cpp
+++ b/services/audioflinger/AudioResampler.cpp
@@ -28,6 +28,10 @@
#include "AudioResamplerCubic.h"
#include "AudioResamplerDyn.h"
+#ifdef QTI_RESAMPLER
+#include "AudioResamplerQTI.h"
+#endif
+
#ifdef __arm__
#define ASM_ARM_RESAMP1 // enable asm optimisation for ResamplerOrder1
#endif
@@ -90,6 +94,9 @@ bool AudioResampler::qualityIsSupported(src_quality quality)
case DYN_LOW_QUALITY:
case DYN_MED_QUALITY:
case DYN_HIGH_QUALITY:
+#ifdef QTI_RESAMPLER
+ case QTI_QUALITY:
+#endif
return true;
default:
return false;
@@ -110,7 +117,11 @@ void AudioResampler::init_routine()
if (*endptr == '\0') {
defaultQuality = (src_quality) l;
ALOGD("forcing AudioResampler quality to %d", defaultQuality);
+#ifdef QTI_RESAMPLER
+ if (defaultQuality < DEFAULT_QUALITY || defaultQuality > QTI_QUALITY) {
+#else
if (defaultQuality < DEFAULT_QUALITY || defaultQuality > DYN_HIGH_QUALITY) {
+#endif
defaultQuality = DEFAULT_QUALITY;
}
}
@@ -129,6 +140,9 @@ uint32_t AudioResampler::qualityMHz(src_quality quality)
case HIGH_QUALITY:
return 20;
case VERY_HIGH_QUALITY:
+#ifdef QTI_RESAMPLER
+ case QTI_QUALITY: //for QTI_QUALITY, currently assuming same as VHQ
+#endif
return 34;
case DYN_LOW_QUALITY:
return 4;
@@ -204,6 +218,11 @@ AudioResampler* AudioResampler::create(audio_format_t format, int inChannelCount
case DYN_HIGH_QUALITY:
quality = DYN_MED_QUALITY;
break;
+#ifdef QTI_RESAMPLER
+ case QTI_QUALITY:
+ quality = DYN_HIGH_QUALITY;
+ break;
+#endif
}
}
pthread_mutex_unlock(&mutex);
@@ -250,6 +269,12 @@ AudioResampler* AudioResampler::create(audio_format_t format, int inChannelCount
}
}
break;
+#ifdef QTI_RESAMPLER
+ case QTI_QUALITY:
+ ALOGV("Create QTI_QUALITY Resampler = %d",quality);
+ resampler = new AudioResamplerQTI(format, inChannelCount, sampleRate);
+ break;
+#endif
}
// initialize resampler
diff --git a/services/audioflinger/AudioResampler.h b/services/audioflinger/AudioResampler.h
index a8e3e6f..6669a85 100644
--- a/services/audioflinger/AudioResampler.h
+++ b/services/audioflinger/AudioResampler.h
@@ -47,6 +47,9 @@ public:
DYN_LOW_QUALITY=5,
DYN_MED_QUALITY=6,
DYN_HIGH_QUALITY=7,
+#ifdef QTI_RESAMPLER
+ QTI_QUALITY=8,
+#endif
};
static const CONSTEXPR float UNITY_GAIN_FLOAT = 1.0f;
diff --git a/services/audioflinger/AudioResamplerQTI.cpp b/services/audioflinger/AudioResamplerQTI.cpp
new file mode 100644
index 0000000..44b741e
--- /dev/null
+++ b/services/audioflinger/AudioResamplerQTI.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.
+ */
+
+#include "AudioResamplerQTI.h"
+#include "QCT_Resampler.h"
+#include <sys/time.h>
+#include <audio_utils/primitives.h>
+
+namespace android {
+AudioResamplerQTI::AudioResamplerQTI(int format,
+ int inChannelCount, int32_t sampleRate)
+ :AudioResampler(inChannelCount, sampleRate, QTI_QUALITY),
+ mOutFrameCount(0), mTmpBuf(0), mResamplerOutBuf(0), mFrameIndex(0)
+{
+ stateSize = QCT_Resampler::MemAlloc(format, inChannelCount, sampleRate, sampleRate);
+ mState = new int16_t[stateSize];
+ mVolume[0] = mVolume[1] = 0;
+ mBuffer.frameCount = 0;
+}
+
+AudioResamplerQTI::~AudioResamplerQTI()
+{
+ if (mState) {
+ delete [] mState;
+ }
+ if (mTmpBuf) {
+ delete [] mTmpBuf;
+ }
+ if(mResamplerOutBuf) {
+ delete [] mResamplerOutBuf;
+ }
+}
+
+size_t AudioResamplerQTI::resample(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider)
+{
+ int16_t vl = mVolume[0];
+ int16_t vr = mVolume[1];
+ int16_t *pBuf;
+
+ size_t inFrameRequest;
+ size_t inFrameCount = getNumInSample(outFrameCount);
+ size_t index = 0;
+ size_t frameIndex = mFrameIndex;
+ size_t out_count = outFrameCount * 2;
+ float *fout = reinterpret_cast<float *>(out);
+
+ if (mChannelCount == 1) {
+ inFrameRequest = inFrameCount;
+ } else {
+ inFrameRequest = inFrameCount * 2;
+ }
+
+ if (mOutFrameCount < outFrameCount) {
+ mOutFrameCount = outFrameCount;
+ if (mTmpBuf) {
+ delete [] mTmpBuf;
+ }
+ if(mResamplerOutBuf) {
+ delete [] mResamplerOutBuf;
+ }
+ mTmpBuf = new int16_t[inFrameRequest + 16];
+ mResamplerOutBuf = new int32_t[out_count];
+ }
+
+ if (mChannelCount == 1) {
+ // buffer is empty, fetch a new one
+ while (index < inFrameCount) {
+ if (!mBuffer.frameCount) {
+ mBuffer.frameCount = inFrameCount;
+ provider->getNextBuffer(&mBuffer);
+ frameIndex = 0;
+ }
+
+ if (mBuffer.raw == NULL) {
+ while (index < inFrameCount) {
+ mTmpBuf[index++] = 0;
+ }
+ QCT_Resampler::Resample90dB(mState, mTmpBuf, mResamplerOutBuf, inFrameCount, outFrameCount);
+ goto resample_exit;
+ }
+
+ mTmpBuf[index++] = clamp16_from_float(*((float *)mBuffer.raw + frameIndex++));
+
+ if (frameIndex >= mBuffer.frameCount) {
+ provider->releaseBuffer(&mBuffer);
+ }
+ }
+
+ QCT_Resampler::Resample90dB(mState, mTmpBuf, mResamplerOutBuf, inFrameCount, outFrameCount);
+ } else {
+ pBuf = &mTmpBuf[inFrameCount];
+ // buffer is empty, fetch a new one
+ while (index < inFrameCount) {
+ if (!mBuffer.frameCount) {
+ mBuffer.frameCount = inFrameCount;
+ provider->getNextBuffer(&mBuffer);
+ frameIndex = 0;
+ }
+ if (mBuffer.raw == NULL) {
+ while (index < inFrameCount) {
+ mTmpBuf[index] = 0;
+ pBuf[index++] = 0;
+ }
+ QCT_Resampler::Resample90dB(mState, mTmpBuf, mResamplerOutBuf, inFrameCount, outFrameCount);
+ goto resample_exit;
+ }
+
+ mTmpBuf[index] = clamp16_from_float(*((float *)mBuffer.raw + frameIndex++));
+ pBuf[index++] = clamp16_from_float(*((float *)mBuffer.raw + frameIndex++));
+ if (frameIndex >= mBuffer.frameCount * 2) {
+ provider->releaseBuffer(&mBuffer);
+ }
+ }
+
+ QCT_Resampler::Resample90dB(mState, mTmpBuf, mResamplerOutBuf, inFrameCount, outFrameCount);
+ }
+
+resample_exit:
+ for (int i = 0; i < out_count; i += 2) {
+ fout[i] += float_from_q4_27(mResamplerOutBuf[i] * vl);
+ fout[i+1] += float_from_q4_27(mResamplerOutBuf[i+1] * vr);
+ }
+
+ mFrameIndex = frameIndex;
+ return index;
+}
+
+void AudioResamplerQTI::setSampleRate(int32_t inSampleRate)
+{
+ if (mInSampleRate != inSampleRate) {
+ mInSampleRate = inSampleRate;
+ init();
+ }
+}
+
+void AudioResamplerQTI::init()
+{
+ QCT_Resampler::Init(mState, mChannelCount, mInSampleRate, mSampleRate);
+}
+
+size_t AudioResamplerQTI::getNumInSample(size_t outFrameCount)
+{
+ size_t size = (size_t)QCT_Resampler::GetNumInSamp(mState, outFrameCount);
+ return size;
+}
+
+void AudioResamplerQTI::reset()
+{
+ AudioResampler::reset();
+}
+
+}; // namespace android
diff --git a/services/audioflinger/AudioResamplerQTI.h b/services/audioflinger/AudioResamplerQTI.h
new file mode 100644
index 0000000..0b30a9f
--- /dev/null
+++ b/services/audioflinger/AudioResamplerQTI.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <cutils/log.h>
+
+#include "AudioResampler.h"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class AudioResamplerQTI : public AudioResampler {
+public:
+ AudioResamplerQTI(int format, int inChannelCount, int32_t sampleRate);
+ ~AudioResamplerQTI();
+ size_t resample(int32_t* out, size_t outFrameCount,
+ AudioBufferProvider* provider);
+ void setSampleRate(int32_t inSampleRate);
+ size_t getNumInSample(size_t outFrameCount);
+
+ int16_t *mState;
+ int16_t *mTmpBuf;
+ int32_t *mResamplerOutBuf;
+ size_t mFrameIndex;
+ size_t stateSize;
+ size_t mOutFrameCount;
+
+ static const int kNumTmpBufSize = 1024;
+
+ void init();
+ void reset();
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/services/audioflinger/BufferProviders.cpp b/services/audioflinger/BufferProviders.cpp
index a8be206..434a514 100644
--- a/services/audioflinger/BufferProviders.cpp
+++ b/services/audioflinger/BufferProviders.cpp
@@ -24,6 +24,7 @@
#include <media/EffectsFactoryApi.h>
#include <utils/Log.h>
+#include <media/stagefright/foundation/ADebug.h>
#include "Configuration.h"
#include "BufferProviders.h"
@@ -205,6 +206,7 @@ DownmixerBufferProvider::DownmixerBufferProvider(
const int downmixParamSize =
sizeof(effect_param_t) + psizePadded + sizeof(downmix_type_t);
effect_param_t * const param = (effect_param_t *) malloc(downmixParamSize);
+ CHECK(param != NULL);
param->psize = sizeof(downmix_params_t);
const downmix_params_t downmixParam = DOWNMIX_PARAM_TYPE;
memcpy(param->data, &downmixParam, param->psize);
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 949c91d..54ca6c3 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -318,6 +318,7 @@ void AudioFlinger::EffectModule::reset_l()
status_t AudioFlinger::EffectModule::configure()
{
status_t status;
+ status_t cmdStatus = 0;
sp<ThreadBase> thread;
uint32_t size;
audio_channel_mask_t channelMask;
@@ -383,7 +384,6 @@ status_t AudioFlinger::EffectModule::configure()
ALOGV("configure() %p thread %p buffer %p framecount %d",
this, thread.get(), mConfig.inputCfg.buffer.raw, mConfig.inputCfg.buffer.frameCount);
- status_t cmdStatus;
size = sizeof(int);
status = (*mEffectInterface)->command(mEffectInterface,
EFFECT_CMD_SET_CONFIG,
@@ -434,7 +434,7 @@ status_t AudioFlinger::EffectModule::init()
if (mEffectInterface == NULL) {
return NO_INIT;
}
- status_t cmdStatus;
+ status_t cmdStatus = 0;
uint32_t size = sizeof(status_t);
status_t status = (*mEffectInterface)->command(mEffectInterface,
EFFECT_CMD_INIT,
@@ -476,7 +476,7 @@ status_t AudioFlinger::EffectModule::start_l()
if (mStatus != NO_ERROR) {
return mStatus;
}
- status_t cmdStatus;
+ status_t cmdStatus = 0;
uint32_t size = sizeof(status_t);
status_t status = (*mEffectInterface)->command(mEffectInterface,
EFFECT_CMD_ENABLE,
@@ -677,7 +677,7 @@ status_t AudioFlinger::EffectModule::setVolume(uint32_t *left, uint32_t *right,
if (isProcessEnabled() &&
((mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK) == EFFECT_FLAG_VOLUME_CTRL ||
(mDescriptor.flags & EFFECT_FLAG_VOLUME_MASK) == EFFECT_FLAG_VOLUME_IND)) {
- status_t cmdStatus;
+ status_t cmdStatus = 0;
uint32_t volume[2];
uint32_t *pVolume = NULL;
uint32_t size = sizeof(volume);
@@ -712,7 +712,7 @@ status_t AudioFlinger::EffectModule::setDevice(audio_devices_t device)
}
status_t status = NO_ERROR;
if ((mDescriptor.flags & EFFECT_FLAG_DEVICE_MASK) == EFFECT_FLAG_DEVICE_IND) {
- status_t cmdStatus;
+ status_t cmdStatus = 0;
uint32_t size = sizeof(status_t);
uint32_t cmd = audio_is_output_devices(device) ? EFFECT_CMD_SET_DEVICE :
EFFECT_CMD_SET_INPUT_DEVICE;
@@ -734,7 +734,7 @@ status_t AudioFlinger::EffectModule::setMode(audio_mode_t mode)
}
status_t status = NO_ERROR;
if ((mDescriptor.flags & EFFECT_FLAG_AUDIO_MODE_MASK) == EFFECT_FLAG_AUDIO_MODE_IND) {
- status_t cmdStatus;
+ status_t cmdStatus = 0;
uint32_t size = sizeof(status_t);
status = (*mEffectInterface)->command(mEffectInterface,
EFFECT_CMD_SET_AUDIO_MODE,
@@ -1113,7 +1113,8 @@ status_t AudioFlinger::EffectHandle::enable()
mEnabled = false;
} else {
if (thread != 0) {
- if (thread->type() == ThreadBase::OFFLOAD) {
+ if ((thread->type() == ThreadBase::OFFLOAD) ||
+ (thread->type() == ThreadBase::DIRECT && thread->mIsDirectPcm)) {
PlaybackThread *t = (PlaybackThread *)thread.get();
Mutex::Autolock _l(t->mLock);
t->broadcast_l();
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index f586291..cdf8b1e 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -544,6 +544,7 @@ AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, audio
mSystemReady(systemReady)
{
memset(&mPatch, 0, sizeof(struct audio_patch));
+ mIsDirectPcm = false;
}
AudioFlinger::ThreadBase::~ThreadBase()
@@ -1154,7 +1155,8 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l(
// Reject any effect on Direct output threads for now, since the format of
// mSinkBuffer is not guaranteed to be compatible with effect processing (PCM 16 stereo).
- if (mType == DIRECT) {
+ // Exception: allow effects for Direct PCM
+ if (mType == DIRECT && !mIsDirectPcm) {
ALOGW("createEffect_l() Cannot add effect %s on Direct output type thread %s",
desc->name, mThreadName);
lStatus = BAD_VALUE;
@@ -1171,12 +1173,17 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l(
}
// Allow global effects only on offloaded and mixer threads
+ // Exception: allow effects for Direct PCM
if (sessionId == AUDIO_SESSION_OUTPUT_MIX) {
switch (mType) {
case MIXER:
case OFFLOAD:
break;
case DIRECT:
+ if (mIsDirectPcm) {
+ // Allow effects when direct PCM enabled on Direct output
+ break;
+ }
case DUPLICATING:
case RECORD:
default:
@@ -1229,7 +1236,13 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l(
if (lStatus != NO_ERROR) {
goto Exit;
}
- effect->setOffloaded(mType == OFFLOAD, mId);
+
+ bool setVal = false;
+ if (mType == OFFLOAD || (mType == DIRECT && mIsDirectPcm)) {
+ setVal = true;
+ }
+
+ effect->setOffloaded(setVal, mId);
lStatus = chain->addEffect_l(effect);
if (lStatus != NO_ERROR) {
@@ -1313,7 +1326,13 @@ status_t AudioFlinger::ThreadBase::addEffect_l(const sp<EffectModule>& effect)
return BAD_VALUE;
}
- effect->setOffloaded(mType == OFFLOAD, mId);
+ bool setval = false;
+
+ if ((mType == OFFLOAD) || (mType == DIRECT && mIsDirectPcm)) {
+ setval = true;
+ }
+
+ effect->setOffloaded(setval, mId);
status_t status = chain->addEffect_l(effect);
if (status != NO_ERROR) {
@@ -5295,6 +5314,8 @@ void AudioFlinger::DuplicatingThread::threadLoop_mix()
} else {
if (mMixerBufferValid) {
memset(mMixerBuffer, 0, mMixerBufferSize);
+ } else if (mEffectBufferValid) {
+ memset(mEffectBuffer, 0, mEffectBufferSize);
} else {
memset(mSinkBuffer, 0, mSinkBufferSize);
}
@@ -5316,7 +5337,11 @@ void AudioFlinger::DuplicatingThread::threadLoop_sleepTime()
} else if (mBytesWritten != 0) {
if (mMixerStatus == MIXER_TRACKS_ENABLED) {
writeFrames = mNormalFrameCount;
- memset(mSinkBuffer, 0, mSinkBufferSize);
+ if (mMixerBufferValid) {
+ memset(mMixerBuffer, 0, mMixerBufferSize);
+ } else {
+ memset(mSinkBuffer, 0, mSinkBufferSize);
+ }
} else {
// flush remaining overflow buffers in output tracks
writeFrames = 0;
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 46ac300..9e32ea1 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -457,6 +457,7 @@ protected:
static const size_t kLogSize = 4 * 1024;
sp<NBLog::Writer> mNBLogWriter;
bool mSystemReady;
+ bool mIsDirectPcm; // flag to indicate unique Direct thread
};
// --- PlaybackThread ---
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index b3fac0b..98eb87f 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -24,6 +24,7 @@
#include <math.h>
#include <sys/syscall.h>
#include <utils/Log.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <private/media/AudioTrackShared.h>
@@ -1774,6 +1775,7 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(void* data, uint32_t frame
if (mBufferQueue.size() < kMaxOverFlowBuffers) {
pInBuffer = new Buffer;
pInBuffer->mBuffer = malloc(inBuffer.frameCount * mFrameSize);
+ CHECK(pInBuffer->mBuffer != NULL);
pInBuffer->frameCount = inBuffer.frameCount;
pInBuffer->raw = pInBuffer->mBuffer;
memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * mFrameSize);
diff --git a/services/audiopolicy/common/managerdefinitions/Android.mk b/services/audiopolicy/common/managerdefinitions/Android.mk
index 8728ff3..8c6a53c 100644
--- a/services/audiopolicy/common/managerdefinitions/Android.mk
+++ b/services/audiopolicy/common/managerdefinitions/Android.mk
@@ -31,6 +31,27 @@ LOCAL_C_INCLUDES += \
LOCAL_EXPORT_C_INCLUDE_DIRS := \
$(LOCAL_PATH)/include
+ifeq ($(call is-vendor-board-platform,QCOM),true)
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_FLAC_OFFLOAD)),true)
+LOCAL_CFLAGS += -DFLAC_OFFLOAD_ENABLED
+endif
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_PROXY_DEVICE)),true)
+LOCAL_CFLAGS += -DAUDIO_EXTN_AFE_PROXY_ENABLED
+endif
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_WMA_OFFLOAD)),true)
+LOCAL_CFLAGS += -DWMA_OFFLOAD_ENABLED
+endif
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_ALAC_OFFLOAD)),true)
+LOCAL_CFLAGS += -DALAC_OFFLOAD_ENABLED
+endif
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_APE_OFFLOAD)),true)
+LOCAL_CFLAGS += -DAPE_OFFLOAD_ENABLED
+endif
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_AAC_ADTS_OFFLOAD)),true)
+LOCAL_CFLAGS += -DAAC_ADTS_OFFLOAD_ENABLED
+endif
+endif
+
LOCAL_MODULE := libaudiopolicycomponents
include $(BUILD_STATIC_LIBRARY)
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 50f622d..e1c2999 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -72,6 +72,7 @@ public:
sp<AudioPort> 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 @@ public:
virtual void toAudioPort(struct audio_port *port) const;
const sp<IOProfile> 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/ConfigParsingUtils.h b/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h
index 78d2cdf..4a394bb 100644
--- a/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h
+++ b/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h
@@ -74,6 +74,9 @@ const StringToEnum sDeviceTypeToEnumTable[] = {
STRING_TO_ENUM(AUDIO_DEVICE_OUT_FM),
STRING_TO_ENUM(AUDIO_DEVICE_OUT_AUX_LINE),
STRING_TO_ENUM(AUDIO_DEVICE_OUT_IP),
+#ifdef AUDIO_EXTN_AFE_PROXY_ENABLED
+ STRING_TO_ENUM(AUDIO_DEVICE_OUT_PROXY),
+#endif
STRING_TO_ENUM(AUDIO_DEVICE_IN_AMBIENT),
STRING_TO_ENUM(AUDIO_DEVICE_IN_BUILTIN_MIC),
STRING_TO_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET),
@@ -153,6 +156,7 @@ const StringToEnum sDeviceNameToEnumTable[] = {
const StringToEnum sOutputFlagNameToEnumTable[] = {
STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DIRECT),
+ STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DIRECT_PCM),
STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_PRIMARY),
STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_FAST),
STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DEEP_BUFFER),
@@ -198,6 +202,33 @@ const StringToEnum sFormatNameToEnumTable[] = {
STRING_TO_ENUM(AUDIO_FORMAT_E_AC3),
STRING_TO_ENUM(AUDIO_FORMAT_DTS),
STRING_TO_ENUM(AUDIO_FORMAT_DTS_HD),
+#ifdef FLAC_OFFLOAD_ENABLED
+ STRING_TO_ENUM(AUDIO_FORMAT_FLAC),
+#endif
+#ifdef WMA_OFFLOAD_ENABLED
+ STRING_TO_ENUM(AUDIO_FORMAT_WMA),
+ STRING_TO_ENUM(AUDIO_FORMAT_WMA_PRO),
+#endif
+ STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT_OFFLOAD),
+ STRING_TO_ENUM(AUDIO_FORMAT_PCM_24_BIT_OFFLOAD),
+#ifdef ALAC_OFFLOAD_ENABLED
+ STRING_TO_ENUM(AUDIO_FORMAT_ALAC),
+#endif
+#ifdef APE_OFFLOAD_ENABLED
+ STRING_TO_ENUM(AUDIO_FORMAT_APE),
+#endif
+#ifdef AAC_ADTS_OFFLOAD_ENABLED
+ STRING_TO_ENUM(AUDIO_FORMAT_AAC_ADTS_MAIN),
+ STRING_TO_ENUM(AUDIO_FORMAT_AAC_ADTS_LC),
+ STRING_TO_ENUM(AUDIO_FORMAT_AAC_ADTS_SSR),
+ STRING_TO_ENUM(AUDIO_FORMAT_AAC_ADTS_LTP),
+ STRING_TO_ENUM(AUDIO_FORMAT_AAC_ADTS_HE_V1),
+ STRING_TO_ENUM(AUDIO_FORMAT_AAC_ADTS_SCALABLE),
+ STRING_TO_ENUM(AUDIO_FORMAT_AAC_ADTS_ERLC),
+ STRING_TO_ENUM(AUDIO_FORMAT_AAC_ADTS_LD),
+ STRING_TO_ENUM(AUDIO_FORMAT_AAC_ADTS_HE_V2),
+ STRING_TO_ENUM(AUDIO_FORMAT_AAC_ADTS_ELD),
+#endif
};
const StringToEnum sOutChannelsNameToEnumTable[] = {
@@ -206,12 +237,17 @@ const StringToEnum sOutChannelsNameToEnumTable[] = {
STRING_TO_ENUM(AUDIO_CHANNEL_OUT_QUAD),
STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1),
STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1),
+ STRING_TO_ENUM(AUDIO_CHANNEL_OUT_2POINT1),
+ STRING_TO_ENUM(AUDIO_CHANNEL_OUT_SURROUND),
+ STRING_TO_ENUM(AUDIO_CHANNEL_OUT_PENTA),
+ STRING_TO_ENUM(AUDIO_CHANNEL_OUT_6POINT1),
};
const StringToEnum sInChannelsNameToEnumTable[] = {
STRING_TO_ENUM(AUDIO_CHANNEL_IN_MONO),
STRING_TO_ENUM(AUDIO_CHANNEL_IN_STEREO),
STRING_TO_ENUM(AUDIO_CHANNEL_IN_FRONT_BACK),
+ STRING_TO_ENUM(AUDIO_CHANNEL_IN_5POINT1),
};
const StringToEnum sIndexChannelsNameToEnumTable[] = {
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index a278375..5ddeaed 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<AudioPort>& 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<IOProfile>& 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/enginedefault/Android.mk b/services/audiopolicy/enginedefault/Android.mk
index 8d43b89..de84e96 100755
--- a/services/audiopolicy/enginedefault/Android.mk
+++ b/services/audiopolicy/enginedefault/Android.mk
@@ -31,6 +31,11 @@ LOCAL_C_INCLUDES := \
$(call include-path-for, bionic) \
$(TOPDIR)frameworks/av/services/audiopolicy/common/include
+ifeq ($(call is-vendor-board-platform,QCOM),true)
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_PROXY_DEVICE)),true)
+LOCAL_CFLAGS += -DAUDIO_EXTN_AFE_PROXY_ENABLED
+endif
+endif
LOCAL_MODULE := libaudiopolicyenginedefault
LOCAL_MODULE_TAGS := optional
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index 0686414..8b4a085 100755
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -408,9 +408,10 @@ audio_devices_t Engine::getDeviceForStrategy(routing_strategy strategy) const
if (device) break;
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_AUX_DIGITAL;
if (device) break;
- device = availableOutputDevicesType & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
- if (device) break;
}
+ // Allow voice call on USB ANLG DOCK headset
+ device = availableOutputDevicesType & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+ if (device) break;
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_EARPIECE;
if (device) break;
device = mApmObserver->getDefaultOutputDevice()->type();
@@ -450,6 +451,13 @@ audio_devices_t Engine::getDeviceForStrategy(routing_strategy strategy) const
}
break;
}
+
+ if (isInCall() && (device == AUDIO_DEVICE_NONE)) {
+ // when in call, get the device for Phone strategy
+ device = getDeviceForStrategy(STRATEGY_PHONE);
+ break;
+ }
+
break;
case STRATEGY_SONIFICATION:
@@ -498,6 +506,13 @@ audio_devices_t Engine::getDeviceForStrategy(routing_strategy strategy) const
case STRATEGY_REROUTING:
case STRATEGY_MEDIA: {
uint32_t device2 = AUDIO_DEVICE_NONE;
+
+ if (isInCall() && (device == AUDIO_DEVICE_NONE)) {
+ // when in call, get the device for Phone strategy
+ device = getDeviceForStrategy(STRATEGY_PHONE);
+ break;
+ }
+
if (strategy != STRATEGY_SONIFICATION) {
// no sonification on remote submix (e.g. WFD)
if (availableOutputDevices.getDevice(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, String8("0")) != 0) {
@@ -541,14 +556,23 @@ audio_devices_t Engine::getDeviceForStrategy(routing_strategy strategy) const
if (device2 == AUDIO_DEVICE_NONE) {
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
}
- if ((device2 == AUDIO_DEVICE_NONE) && (strategy != STRATEGY_SONIFICATION)) {
+ if ((strategy != STRATEGY_SONIFICATION) && (device == AUDIO_DEVICE_NONE)
+ && (device2 == AUDIO_DEVICE_NONE)) {
// no sonification on aux digital (e.g. HDMI)
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_AUX_DIGITAL;
}
if ((device2 == AUDIO_DEVICE_NONE) &&
- (mForceUse[AUDIO_POLICY_FORCE_FOR_DOCK] == AUDIO_POLICY_FORCE_ANALOG_DOCK)) {
+ (mForceUse[AUDIO_POLICY_FORCE_FOR_DOCK] == AUDIO_POLICY_FORCE_ANALOG_DOCK)
+ && (strategy != STRATEGY_SONIFICATION)) {
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
}
+#ifdef AUDIO_EXTN_AFE_PROXY_ENABLED
+ if ((strategy != STRATEGY_SONIFICATION) && (device == AUDIO_DEVICE_NONE)
+ && (device2 == AUDIO_DEVICE_NONE)) {
+ // no sonification on WFD sink
+ device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_PROXY;
+ }
+#endif
if (device2 == AUDIO_DEVICE_NONE) {
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER;
}
@@ -671,6 +695,8 @@ audio_devices_t Engine::getDeviceForInputSource(audio_source_t inputSource) cons
device = AUDIO_DEVICE_IN_WIRED_HEADSET;
} else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {
device = AUDIO_DEVICE_IN_USB_DEVICE;
+ } else if (availableDeviceTypes & AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET) {
+ device = AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET;
} else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
device = AUDIO_DEVICE_IN_BUILTIN_MIC;
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 8419ed5..acdd23d 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -351,6 +351,14 @@ void AudioPolicyManager::updateCallRouting(audio_devices_t rxDevice, int delayMs
AUDIO_OUTPUT_FLAG_NONE,
AUDIO_FORMAT_INVALID);
if (output != AUDIO_IO_HANDLE_NONE) {
+ // close active input (if any) before opening new input
+ audio_io_handle_t activeInput = mInputs.getActiveInput();
+ if (activeInput != 0) {
+ ALOGV("updateCallRouting() close active input before opening new input");
+ sp<AudioInputDescriptor> activeDesc = mInputs.valueFor(activeInput);
+ stopInput(activeInput, activeDesc->mSessions.itemAt(0));
+ releaseInput(activeInput, activeDesc->mSessions.itemAt(0));
+ }
sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
ALOG_ASSERT(!outputDesc->isDuplicated(),
"updateCallRouting() RX device output is duplicated");
@@ -1336,6 +1344,12 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
ALOGW("getInputForAttr() could not find device for source %d", inputSource);
return BAD_VALUE;
}
+ // block request to open input on USB during voice call
+ if((AUDIO_MODE_IN_CALL == mEngine->getPhoneState()) &&
+ (device == AUDIO_DEVICE_IN_USB_DEVICE)) {
+ ALOGV("getInputForAttr(): blocking the request to open input on USB device");
+ return BAD_VALUE;
+ }
if (policyMix != NULL) {
address = policyMix->mRegistrationId;
if (policyMix->mMixType == MIX_TYPE_RECORDERS) {
@@ -1356,20 +1370,6 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
} else {
*inputType = API_INPUT_LEGACY;
}
- // adapt channel selection to input source
- switch (inputSource) {
- case AUDIO_SOURCE_VOICE_UPLINK:
- channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK;
- break;
- case AUDIO_SOURCE_VOICE_DOWNLINK:
- channelMask = AUDIO_CHANNEL_IN_VOICE_DNLINK;
- break;
- case AUDIO_SOURCE_VOICE_CALL:
- channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK | AUDIO_CHANNEL_IN_VOICE_DNLINK;
- break;
- default:
- break;
- }
if (inputSource == AUDIO_SOURCE_HOTWORD) {
ssize_t index = mSoundTriggerSessions.indexOfKey(session);
if (index >= 0) {
@@ -1773,6 +1773,7 @@ audio_io_handle_t AudioPolicyManager::selectOutputForEffects(
audio_io_handle_t outputOffloaded = 0;
audio_io_handle_t outputDeepBuffer = 0;
+ audio_io_handle_t outputDirectPcm = 0;
for (size_t i = 0; i < outputs.size(); i++) {
sp<SwAudioOutputDescriptor> desc = mOutputs.valueFor(outputs[i]);
@@ -1780,6 +1781,9 @@ audio_io_handle_t AudioPolicyManager::selectOutputForEffects(
if ((desc->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
outputOffloaded = outputs[i];
}
+ if ((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT_PCM) != 0) {
+ outputDirectPcm = outputs[i];
+ }
if ((desc->mFlags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) != 0) {
outputDeepBuffer = outputs[i];
}
@@ -1790,6 +1794,9 @@ audio_io_handle_t AudioPolicyManager::selectOutputForEffects(
if (outputOffloaded != 0) {
return outputOffloaded;
}
+ if (outputDirectPcm != 0) {
+ return outputDirectPcm;
+ }
if (outputDeepBuffer != 0) {
return outputDeepBuffer;
}
@@ -3781,7 +3788,7 @@ void AudioPolicyManager::checkOutputForStrategy(routing_strategy strategy)
{
audio_devices_t oldDevice = getDeviceForStrategy(strategy, true /*fromCache*/);
audio_devices_t newDevice = getDeviceForStrategy(strategy, false /*fromCache*/);
- SortedVector<audio_io_handle_t> srcOutputs = getOutputsForDevice(oldDevice, mPreviousOutputs);
+ SortedVector<audio_io_handle_t> srcOutputs = getOutputsForDevice(oldDevice, mOutputs);
SortedVector<audio_io_handle_t> dstOutputs = getOutputsForDevice(newDevice, mOutputs);
// also take into account external policy-related changes: add all outputs which are
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index bbdf396..c40a435 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -350,7 +350,7 @@ protected:
// handle special cases for sonification strategy while in call: mute streams or replace by
// a special tone in the device used for communication
- void handleIncallSonification(audio_stream_type_t stream, bool starting, bool stateChange);
+ virtual void handleIncallSonification(audio_stream_type_t stream, bool starting, bool stateChange);
audio_mode_t getPhoneState();
@@ -397,7 +397,7 @@ protected:
// must be called every time a condition that affects the device choice for a given output is
// changed: connected device, phone state, force use, output start, output stop..
// see getDeviceForStrategy() for the use of fromCache parameter
- audio_devices_t getNewOutputDevice(const sp<AudioOutputDescriptor>& outputDesc,
+ virtual audio_devices_t getNewOutputDevice(const sp<AudioOutputDescriptor>& outputDesc,
bool fromCache);
// updates cache of device used by all strategies (mDeviceForStrategy[])
@@ -484,11 +484,11 @@ protected:
// if argument "device" is different from AUDIO_DEVICE_NONE, startSource() will force
// the re-evaluation of the output device.
- status_t startSource(sp<AudioOutputDescriptor> outputDesc,
+ virtual status_t startSource(sp<AudioOutputDescriptor> outputDesc,
audio_stream_type_t stream,
audio_devices_t device,
uint32_t *delayMs);
- status_t stopSource(sp<AudioOutputDescriptor> outputDesc,
+ virtual status_t stopSource(sp<AudioOutputDescriptor> outputDesc,
audio_stream_type_t stream,
bool forceDeviceUpdate);
@@ -571,7 +571,7 @@ protected:
// Audio Policy Engine Interface.
AudioPolicyManagerInterface *mEngine;
-private:
+protected:
// updates device caching and output for streams that can influence the
// routing of notifications
void handleNotificationRoutingForStream(audio_stream_type_t stream);
@@ -586,7 +586,7 @@ private:
SortedVector<audio_io_handle_t>& outputs /*out*/);
uint32_t curAudioPortGeneration() const { return mAudioPortGeneration; }
// internal method to return the output handle for the given device and format
- audio_io_handle_t getOutputForDevice(
+ virtual audio_io_handle_t getOutputForDevice(
audio_devices_t device,
audio_session_t session,
audio_stream_type_t stream,
@@ -610,7 +610,7 @@ private:
AudioMix **policyMix = NULL);
// Called by setDeviceConnectionState().
- status_t setDeviceConnectionStateInt(audio_devices_t device,
+ virtual status_t setDeviceConnectionStateInt(audio_devices_t device,
audio_policy_dev_state_t state,
const char *device_address,
const char *device_name);
diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp
index 282ddeb..e71d7a5 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.cpp
+++ b/services/audiopolicy/service/AudioPolicyEffects.cpp
@@ -442,6 +442,7 @@ effect_param_t *AudioPolicyEffects::loadEffectParameter(cnode *root)
size_t curSize = sizeof(effect_param_t);
size_t totSize = sizeof(effect_param_t) + 2 * sizeof(int);
effect_param_t *fx_param = (effect_param_t *)malloc(totSize);
+ CHECK(fx_param != NULL);
param = config_find(root, PARAM_TAG);
value = config_find(root, VALUE_TAG);
diff --git a/services/audiopolicy/service/AudioPolicyEffects.h b/services/audiopolicy/service/AudioPolicyEffects.h
index 3dec437..3845050 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.h
+++ b/services/audiopolicy/service/AudioPolicyEffects.h
@@ -27,6 +27,8 @@
#include <utils/Vector.h>
#include <utils/SortedVector.h>
+#include <media/stagefright/foundation/ADebug.h>
+
namespace android {
// ----------------------------------------------------------------------------
@@ -102,6 +104,7 @@ private:
((origParam->psize + 3) & ~3) +
((origParam->vsize + 3) & ~3);
effect_param_t *dupParam = (effect_param_t *) malloc(origSize);
+ CHECK(dupParam != NULL);
memcpy(dupParam, origParam, origSize);
// This works because the param buffer allocation is also done by
// multiples of 4 bytes originally. In theory we should memcpy only
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index c77cc45..41dd40c 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -899,10 +899,12 @@ void AudioPolicyService::AudioCommandThread::insertCommand_l(sp<AudioCommand>& c
} else {
data2->mKeyValuePairs = param2.toString();
}
- command->mTime = command2->mTime;
- // force delayMs to non 0 so that code below does not request to wait for
- // command status as the command is now delayed
- delayMs = 1;
+ if (!data2->mKeyValuePairs.compare(data->mKeyValuePairs)) {
+ command->mTime = command2->mTime;
+ // force delayMs to non 0 so that code below does not request to wait for
+ // command status as the command is now delayed
+ delayMs = 1;
+ }
} break;
case SET_VOLUME: {
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index 45900c4..ab09cb3 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -79,6 +79,14 @@ LOCAL_C_INCLUDES += \
LOCAL_CFLAGS += -Wall -Wextra
+ifeq ($(BOARD_NEEDS_MEMORYHEAPION),true)
+ LOCAL_CFLAGS += -DUSE_MEMORY_HEAP_ION
+endif
+
+ifneq ($(BOARD_NUMBER_OF_CAMERAS),)
+ LOCAL_CFLAGS += -DMAX_CAMERAS=$(BOARD_NUMBER_OF_CAMERAS)
+endif
+
LOCAL_MODULE:= libcameraservice
include $(BUILD_SHARED_LIBRARY)
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 2aaefe9..db6272b 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -2082,7 +2082,11 @@ sp<CameraService::Client> 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 cd97b08..b3903d4 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -49,6 +49,10 @@
#include <memory>
#include <utility>
+#ifndef MAX_CAMERAS
+#define MAX_CAMERAS 2
+#endif
+
namespace android {
extern volatile int32_t gLogLevel;
diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp
index 38e35cd..1bb2910 100644
--- a/services/camera/libcameraservice/api1/CameraClient.cpp
+++ b/services/camera/libcameraservice/api1/CameraClient.cpp
@@ -56,6 +56,9 @@ CameraClient::CameraClient(const sp<CameraService>& cameraService,
mOrientation = getOrientation(0, mCameraFacing == CAMERA_FACING_FRONT);
mLegacyMode = legacyMode;
mPlayShutterSound = true;
+
+ mLongshotEnabled = false;
+ mBurstCnt = 0;
LOG1("CameraClient::CameraClient X (pid %d, id %d)", callingPid, cameraId);
}
@@ -360,12 +363,14 @@ status_t CameraClient::setPreviewCallbackTarget(
// start preview mode
status_t CameraClient::startPreview() {
+ Mutex::Autolock lock(mLock);
LOG1("startPreview (pid %d)", getCallingPid());
return startCameraMode(CAMERA_PREVIEW_MODE);
}
// start recording mode
status_t CameraClient::startRecording() {
+ Mutex::Autolock lock(mLock);
LOG1("startRecording (pid %d)", getCallingPid());
return startCameraMode(CAMERA_RECORDING_MODE);
}
@@ -373,7 +378,6 @@ status_t CameraClient::startRecording() {
// start preview or recording
status_t CameraClient::startCameraMode(camera_mode mode) {
LOG1("startCameraMode(%d)", mode);
- Mutex::Autolock lock(mLock);
status_t result = checkPidAndHardware();
if (result != NO_ERROR) return result;
@@ -553,6 +557,10 @@ status_t CameraClient::takePicture(int msgType) {
CAMERA_MSG_COMPRESSED_IMAGE);
enableMsgType(picMsgType);
+ mBurstCnt = mHardware->getParameters().getInt("num-snaps-per-shutter");
+ if(mBurstCnt <= 0)
+ mBurstCnt = 1;
+ LOG1("mBurstCnt = %d", mBurstCnt);
return mHardware->takePicture();
}
@@ -655,6 +663,20 @@ status_t CameraClient::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) {
} else if (cmd == CAMERA_CMD_PING) {
// If mHardware is 0, checkPidAndHardware will return error.
return OK;
+ } else if (cmd == CAMERA_CMD_HISTOGRAM_ON) {
+ enableMsgType(CAMERA_MSG_STATS_DATA);
+ } else if (cmd == CAMERA_CMD_HISTOGRAM_OFF) {
+ disableMsgType(CAMERA_MSG_STATS_DATA);
+ } else if (cmd == CAMERA_CMD_METADATA_ON) {
+ enableMsgType(CAMERA_MSG_META_DATA);
+ } else if (cmd == CAMERA_CMD_METADATA_OFF) {
+ disableMsgType(CAMERA_MSG_META_DATA);
+ } else if ( cmd == CAMERA_CMD_LONGSHOT_ON ) {
+ mLongshotEnabled = true;
+ } else if ( cmd == CAMERA_CMD_LONGSHOT_OFF ) {
+ mLongshotEnabled = false;
+ disableMsgType(CAMERA_MSG_SHUTTER);
+ disableMsgType(CAMERA_MSG_COMPRESSED_IMAGE);
}
return mHardware->sendCommand(cmd, arg1, arg2);
@@ -797,7 +819,9 @@ void CameraClient::handleShutter(void) {
c->notifyCallback(CAMERA_MSG_SHUTTER, 0, 0);
if (!lockIfMessageWanted(CAMERA_MSG_SHUTTER)) return;
}
- disableMsgType(CAMERA_MSG_SHUTTER);
+ if ( !mLongshotEnabled ) {
+ disableMsgType(CAMERA_MSG_SHUTTER);
+ }
// Shutters only happen in response to takePicture, so mark device as
// idle now, until preview is restarted
@@ -882,7 +906,13 @@ void CameraClient::handleRawPicture(const sp<IMemory>& mem) {
// picture callback - compressed picture ready
void CameraClient::handleCompressedPicture(const sp<IMemory>& mem) {
- disableMsgType(CAMERA_MSG_COMPRESSED_IMAGE);
+ if (mBurstCnt)
+ mBurstCnt--;
+
+ if (!mBurstCnt && !mLongshotEnabled) {
+ LOG1("handleCompressedPicture mBurstCnt = %d", mBurstCnt);
+ disableMsgType(CAMERA_MSG_COMPRESSED_IMAGE);
+ }
sp<ICameraClient> c = mRemoteCallback;
mLock.unlock();
diff --git a/services/camera/libcameraservice/api1/CameraClient.h b/services/camera/libcameraservice/api1/CameraClient.h
index 95616b2..9d2d02f 100644
--- a/services/camera/libcameraservice/api1/CameraClient.h
+++ b/services/camera/libcameraservice/api1/CameraClient.h
@@ -162,6 +162,9 @@ private:
// This function keeps trying to grab mLock, or give up if the message
// is found to be disabled. It returns true if mLock is grabbed.
bool lockIfMessageWanted(int32_t msgType);
+
+ bool mLongshotEnabled;
+ int mBurstCnt;
};
}
diff --git a/services/camera/libcameraservice/device1/CameraHardwareInterface.h b/services/camera/libcameraservice/device1/CameraHardwareInterface.h
index 7f14cd4..35947a9 100644
--- a/services/camera/libcameraservice/device1/CameraHardwareInterface.h
+++ b/services/camera/libcameraservice/device1/CameraHardwareInterface.h
@@ -25,7 +25,10 @@
#include <camera/Camera.h>
#include <camera/CameraParameters.h>
#include <system/window.h>
-#include <hardware/camera.h>
+#include "hardware/camera.h"
+#ifdef USE_MEMORY_HEAP_ION
+#include <binder/MemoryHeapIon.h>
+#endif
namespace android {
@@ -322,6 +325,10 @@ public:
void releaseRecordingFrame(const sp<IMemory>& mem)
{
ALOGV("%s(%s)", __FUNCTION__, mName.string());
+ if (mem == NULL) {
+ ALOGE("%s: NULL memory reference", __FUNCTION__);
+ return;
+ }
if (mDevice->ops->release_recording_frame) {
ssize_t offset;
size_t size;
@@ -501,7 +508,11 @@ private:
mBufSize(buf_size),
mNumBufs(num_buffers)
{
+#ifdef USE_MEMORY_HEAP_ION
+ mHeap = new MemoryHeapIon(fd, buf_size * num_buffers);
+#else
mHeap = new MemoryHeapBase(fd, buf_size * num_buffers);
+#endif
commonInitialization();
}
@@ -509,7 +520,11 @@ private:
mBufSize(buf_size),
mNumBufs(num_buffers)
{
+#ifdef USE_MEMORY_HEAP_ION
+ mHeap = new MemoryHeapIon(buf_size * num_buffers);
+#else
mHeap = new MemoryHeapBase(buf_size * num_buffers);
+#endif
commonInitialization();
}
@@ -541,14 +556,24 @@ private:
camera_memory_t handle;
};
+#ifdef USE_MEMORY_HEAP_ION
+ static camera_memory_t* __get_memory(int fd, size_t buf_size, uint_t num_bufs,
+ void *ion_fd)
+ {
+#else
static camera_memory_t* __get_memory(int fd, size_t buf_size, uint_t num_bufs,
void *user __attribute__((unused)))
{
+#endif
CameraHeapMemory *mem;
if (fd < 0)
mem = new CameraHeapMemory(buf_size, num_bufs);
else
mem = new CameraHeapMemory(fd, buf_size, num_bufs);
+#ifdef USE_MEMORY_HEAP_ION
+ if (ion_fd)
+ *((int *) ion_fd) = mem->mHeap->getHeapID();
+#endif
mem->incStrong(mem);
return &mem->handle;
}