Merge tag 'android-4.4.3_r1.1' into HEAD
Android 4.4.3 release 1.1
Change-Id: Ic939fc64cbacba0f0aba987d9d834c7798020dd1
diff --git a/NOTICE b/NOTICE
index 152be20..6f652a2 100644
--- a/NOTICE
+++ b/NOTICE
@@ -322,3 +322,32 @@
shall not be used in advertising or otherwise to promote the sale, use
or other dealings in these Data Files or Software without prior written
authorization of the copyright holder.
+
+
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/camera/Android.mk b/camera/Android.mk
index 5cedab0..3d5afab 100644
--- a/camera/Android.mk
+++ b/camera/Android.mk
@@ -36,6 +36,17 @@
LOCAL_C_INCLUDES += \
system/media/camera/include \
+ifeq ($(BOARD_CAMERA_HAVE_ISO),true)
+ LOCAL_CFLAGS += -DHAVE_ISO
+endif
+
+ifeq ($(BOARD_USES_QCOM_HARDWARE),true)
+ LOCAL_CFLAGS += -DQCOM_HARDWARE
+endif
+ifeq ($(BOARD_USES_QCOM_LEGACY_CAM_PARAMS),true)
+ LOCAL_CFLAGS += -DQCOM_LEGACY_CAM_PARAMS
+endif
+
LOCAL_MODULE:= libcamera_client
include $(BUILD_SHARED_LIBRARY)
diff --git a/camera/CameraParameters.cpp b/camera/CameraParameters.cpp
index c51f265..75ec676 100644
--- a/camera/CameraParameters.cpp
+++ b/camera/CameraParameters.cpp
@@ -26,15 +26,51 @@
// Parameter keys to communicate between camera application and driver.
const char CameraParameters::KEY_PREVIEW_SIZE[] = "preview-size";
const char CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES[] = "preview-size-values";
+#ifdef QCOM_HARDWARE
+const char CameraParameters::KEY_SUPPORTED_HFR_SIZES[] = "hfr-size-values";
+#endif
const char CameraParameters::KEY_PREVIEW_FORMAT[] = "preview-format";
const char CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS[] = "preview-format-values";
const char CameraParameters::KEY_PREVIEW_FRAME_RATE[] = "preview-frame-rate";
const char CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES[] = "preview-frame-rate-values";
const char CameraParameters::KEY_PREVIEW_FPS_RANGE[] = "preview-fps-range";
const char CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE[] = "preview-fps-range-values";
+#ifdef QCOM_HARDWARE
+const char CameraParameters::KEY_PREVIEW_FRAME_RATE_MODE[] = "preview-frame-rate-mode";
+const char CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATE_MODES[] = "preview-frame-rate-modes";
+const char CameraParameters::KEY_PREVIEW_FRAME_RATE_AUTO_MODE[] = "frame-rate-auto";
+const char CameraParameters::KEY_PREVIEW_FRAME_RATE_FIXED_MODE[] = "frame-rate-fixed";
+#ifdef QCOM_LEGACY_CAM_PARAMS
+//Values for Continuous AF
+const char CameraParameters::CAF_OFF[] = "caf-off";
+const char CameraParameters::CAF_ON[] = "caf-on";
+//Same, for CodeAurora-based blobs
+const char CameraParameters::CAPTURE_MODE_NORMAL[] = "normal";
+const char CameraParameters::CAPTURE_MODE_BURST[] = "burst";
+const char CameraParameters::CAPTURE_MODE_CONTI_BURST[] = "contiburst";
+const char CameraParameters::CAPTURE_MODE_HDR[] = "hdr";
+const char CameraParameters::CAPTURE_MODE_HJR[] = "hjr";
+const char CameraParameters::CAPTURE_MODE_PANORAMA[] = "panorama";
+const char CameraParameters::CONTINUOUS_AF_OFF[] = "caf-off";
+const char CameraParameters::CONTINUOUS_AF_ON[] = "caf-on";
+const char CameraParameters::KEY_CONTINUOUS_AF[] = "continuous-af";
+const char CameraParameters::KEY_CAF[] = "continuous-af";
+const char CameraParameters::KEY_CAPTURE_MODE[] = "capture-mode";
+const char CameraParameters::KEY_PICTURE_COUNT[] = "picture-count";
+const char CameraParameters::KEY_MAX_BURST_PICTURE_COUNT[] = "max-burst-picture-count";
+const char CameraParameters::KEY_SUPPORTED_CONTINUOUS_AF[] = "continuous-af-mode";
+const char CameraParameters::KEY_SUPPORTED_CAF[] = "continuous-af-values";
+const char CameraParameters::KEY_SUPPORTED_CAPTURE_MODES[] = "capture-mode-values";
+const char CameraParameters::KEY_TAKING_PICTURE_ZOOM[] = "taking-picture-zoom";
+const char CameraParameters::KEY_PANORAMA_MODE[] = "panorama-mode";
+const char CameraParameters::PANORAMA_MODE_NOT_INPROGRESS[] = "not-in-progress";
+const char CameraParameters::PANORAMA_MODE_INPROGRESS[] = "in-progress";
+#endif
+#endif
const char CameraParameters::KEY_PICTURE_SIZE[] = "picture-size";
const char CameraParameters::KEY_SUPPORTED_PICTURE_SIZES[] = "picture-size-values";
const char CameraParameters::KEY_PICTURE_FORMAT[] = "picture-format";
+const char CameraParameters::KEY_SUPPORTED_3D_FILE_FORMAT[] = "3d-file-format";
const char CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS[] = "picture-format-values";
const char CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH[] = "jpeg-thumbnail-width";
const char CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT[] = "jpeg-thumbnail-height";
@@ -51,10 +87,20 @@
const char CameraParameters::KEY_SUPPORTED_WHITE_BALANCE[] = "whitebalance-values";
const char CameraParameters::KEY_EFFECT[] = "effect";
const char CameraParameters::KEY_SUPPORTED_EFFECTS[] = "effect-values";
+#ifdef QCOM_HARDWARE
+const char CameraParameters::KEY_TOUCH_AF_AEC[] = "touch-af-aec";
+const char CameraParameters::KEY_SUPPORTED_TOUCH_AF_AEC[] = "touch-af-aec-values";
+const char CameraParameters::KEY_TOUCH_INDEX_AEC[] = "touch-index-aec";
+const char CameraParameters::KEY_TOUCH_INDEX_AF[] = "touch-index-af";
+#endif
const char CameraParameters::KEY_ANTIBANDING[] = "antibanding";
const char CameraParameters::KEY_SUPPORTED_ANTIBANDING[] = "antibanding-values";
const char CameraParameters::KEY_SCENE_MODE[] = "scene-mode";
const char CameraParameters::KEY_SUPPORTED_SCENE_MODES[] = "scene-mode-values";
+#ifdef QCOM_HARDWARE
+const char CameraParameters::KEY_SCENE_DETECT[] = "scene-detect";
+const char CameraParameters::KEY_SUPPORTED_SCENE_DETECT[] = "scene-detect-values";
+#endif QCOM_HARDWARE
const char CameraParameters::KEY_FLASH_MODE[] = "flash-mode";
const char CameraParameters::KEY_SUPPORTED_FLASH_MODES[] = "flash-mode-values";
const char CameraParameters::KEY_FOCUS_MODE[] = "focus-mode";
@@ -81,6 +127,32 @@
const char CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED[] = "smooth-zoom-supported";
const char CameraParameters::KEY_FOCUS_DISTANCES[] = "focus-distances";
const char CameraParameters::KEY_VIDEO_FRAME_FORMAT[] = "video-frame-format";
+#ifdef QCOM_HARDWARE
+const char CameraParameters::KEY_ISO_MODE[] = "iso";
+const char CameraParameters::KEY_SUPPORTED_ISO_MODES[] = "iso-values";
+const char CameraParameters::KEY_LENSSHADE[] = "lensshade";
+const char CameraParameters::KEY_SUPPORTED_LENSSHADE_MODES[] = "lensshade-values";
+#ifdef SAMSUNG_CAMERA_LEGACY
+const char CameraParameters::KEY_AUTO_EXPOSURE[] = "metering";
+#else
+const char CameraParameters::KEY_AUTO_EXPOSURE[] = "auto-exposure";
+#endif
+const char CameraParameters::KEY_SUPPORTED_AUTO_EXPOSURE[] = "auto-exposure-values";
+const char CameraParameters::KEY_DENOISE[] = "denoise";
+const char CameraParameters::KEY_SUPPORTED_DENOISE[] = "denoise-values";
+const char CameraParameters::KEY_SELECTABLE_ZONE_AF[] = "selectable-zone-af";
+const char CameraParameters::KEY_SUPPORTED_SELECTABLE_ZONE_AF[] = "selectable-zone-af-values";
+const char CameraParameters::KEY_FACE_DETECTION[] = "face-detection";
+const char CameraParameters::KEY_SUPPORTED_FACE_DETECTION[] = "face-detection-values";
+const char CameraParameters::KEY_MEMORY_COLOR_ENHANCEMENT[] = "mce";
+const char CameraParameters::KEY_SUPPORTED_MEM_COLOR_ENHANCE_MODES[] = "mce-values";
+const char CameraParameters::KEY_VIDEO_HIGH_FRAME_RATE[] = "video-hfr";
+const char CameraParameters::KEY_SUPPORTED_VIDEO_HIGH_FRAME_RATE_MODES[] = "video-hfr-values";
+const char CameraParameters::KEY_REDEYE_REDUCTION[] = "redeye-reduction";
+const char CameraParameters::KEY_SUPPORTED_REDEYE_REDUCTION[] = "redeye-reduction-values";
+const char CameraParameters::KEY_HIGH_DYNAMIC_RANGE_IMAGING[] = "hdr";
+const char CameraParameters::KEY_SUPPORTED_HDR_IMAGING_MODES[] = "hdr-values";
+#endif
const char CameraParameters::KEY_VIDEO_SIZE[] = "video-size";
const char CameraParameters::KEY_SUPPORTED_VIDEO_SIZES[] = "video-size-values";
const char CameraParameters::KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO[] = "preferred-preview-size-for-video";
@@ -88,9 +160,101 @@
const char CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW[] = "max-num-detected-faces-sw";
const char CameraParameters::KEY_RECORDING_HINT[] = "recording-hint";
const char CameraParameters::KEY_VIDEO_SNAPSHOT_SUPPORTED[] = "video-snapshot-supported";
+const char CameraParameters::KEY_FULL_VIDEO_SNAP_SUPPORTED[] = "full-video-snap-supported";
const char CameraParameters::KEY_VIDEO_STABILIZATION[] = "video-stabilization";
const char CameraParameters::KEY_VIDEO_STABILIZATION_SUPPORTED[] = "video-stabilization-supported";
const char CameraParameters::KEY_LIGHTFX[] = "light-fx";
+#ifdef QCOM_HARDWARE
+const char CameraParameters::KEY_ZSL[] = "zsl";
+const char CameraParameters::KEY_SUPPORTED_ZSL_MODES[] = "zsl-values";
+const char CameraParameters::KEY_CAMERA_MODE[] = "camera-mode";
+const char CameraParameters::KEY_POWER_MODE[] = "power-mode";
+const char CameraParameters::KEY_POWER_MODE_SUPPORTED[] = "power-mode-supported";
+#endif
+const char CameraParameters::KEY_AE_BRACKET_HDR[] = "ae-bracket-hdr";
+
+/*only effective when KEY_AE_BRACKET_HDR set to ae_bracketing*/
+//const char CameraParameters::KEY_AE_BRACKET_SETTING_KEY[] = "ae-bracket-setting";
+
+#ifdef HAVE_ISO
+const char CameraParameters::KEY_SUPPORTED_ISO_MODES[] = "iso-values";
+const char CameraParameters::KEY_ISO_MODE[] = "iso";
+#endif
+
+#ifdef SAMSUNG_CAMERA_HARDWARE
+const char CameraParameters::KEY_ANTI_SHAKE_MODE[] = "anti-shake";
+const char CameraParameters::KEY_METERING[] = "metering";
+const char CameraParameters::KEY_WDR[] = "wdr";
+const char CameraParameters::KEY_WEATHER[] = "weather";
+const char CameraParameters::KEY_CITYID[] = "contextualtag-cityid";
+#endif
+
+#ifdef HTC_CAMERA_HARDWARE
+const char CameraParameters::KEY_TIME_CONS_POST_PROCESSING[] = "time-cons-post-processing";
+const char CameraParameters::KEY_OIS_MODE[] = "ois_mode";
+const char CameraParameters::KEY_APP_OIS_SETTING[] = "ois-setting";
+const char CameraParameters::KEY_OIS_SUPPORT[] = "ois_support";
+const char CameraParameters::KEY_CONTIBURST_TYPE[] = "contiburst-type";
+const char CameraParameters::KEY_CAPTURE_MODE[] = "capture-mode";
+const char CameraParameters::CAPTURE_MODE_NORMAL[] = "normal";
+const char CameraParameters::CAPTURE_MODE_CONTI_ZOE[] = "contizoe";
+const char CameraParameters::CAPTURE_MODE_CONTI_BURST[] = "contiburst";
+const char CameraParameters::CAPTURE_MODE_CONTI_BURST_ONE_SHOT[] = "contiburst-one-shot";
+const char CameraParameters::CAPTURE_MODE_HDR[] = "hdr";
+const char CameraParameters::CAPTURE_MODE_PANORAMA[] = "panorama";
+const char CameraParameters::CAPTURE_MODE_ZOE[] = "zoe";
+const char CameraParameters::KEY_CONTI_BURST_STATE[] = "contiburst-state";
+const char CameraParameters::KEY_SUPPORTED_CAPTURE_MODES[] = "capture-mode-values";
+const char CameraParameters::KEY_MIN_CONTRAST[] = "contrast-min";
+const char CameraParameters::KEY_DEF_CONTRAST[] = "contrast-def";
+const char CameraParameters::KEY_MIN_SHARPNESS[] = "sharpness-min";
+const char CameraParameters::KEY_DEF_SHARPNESS[] = "sharpness-def";
+const char CameraParameters::KEY_MIN_SATURATION[] = "saturation-min";
+const char CameraParameters::KEY_DEF_SATURATION[] = "saturation-def";
+const char CameraParameters::KEY_SINGLE_ISP_OUTPUT_ENABLED[] = "single-isp-output-enabled";
+const char CameraParameters::POST_PROCESSING_ENABLE[] = "enable";
+const char CameraParameters::POST_PROCESSING_BYPASS[] = "bypass";
+const char CameraParameters::POST_PROCESSING_DELAY[] = "delay";
+const char CameraParameters::SCENE_MODE_OFF[] = "off";
+const char CameraParameters::SCENE_MODE_TEXT[] = "text";
+const char CameraParameters::BURST_MODE_LIMIT20[] = "limit-20";
+const char CameraParameters::BURST_MODE_UNLIMITED[] = "unlimited";
+const char CameraParameters::OIS_MODE_OFF[] = "off";
+const char CameraParameters::OIS_MODE_ON[] = "on";
+const char CameraParameters::CONTI_BURST_CAPTURING[] = "contiburst-capturing";
+const char CameraParameters::CONTI_BURST_CAPTURE_DONE[] = "contiburst-done";
+const char CameraParameters::APP_OIS_SETTING_FALSE[] = "false";
+const char CameraParameters::APP_OIS_SETTING_TRUE[] = "true";
+const char CameraParameters::KEY_GPU_EFFECT[] = "GPU-effect";
+const char CameraParameters::KEY_GPU_EFFECT_PARAM_0[] = "GE-param0";
+const char CameraParameters::KEY_GPU_EFFECT_PARAM_1[] = "GE-param1";
+const char CameraParameters::KEY_GPU_EFFECT_PARAM_2[] = "GE-param2";
+const char CameraParameters::KEY_GPU_EFFECT_PARAM_3[] = "GE-param3";
+const char CameraParameters::KEY_FORCE_USE_AUDIO_ENABLED[] = "forceuseaudio";
+#endif
+
+#ifdef LG_CAMERA_HARDWARE
+const char CameraParameters::AUDIO_ZOOM_OFF[] = "audio-zoom";
+const char CameraParameters::AUDIO_ZOOM_ON[] = "audio-zoom";
+const char CameraParameters::BEAUTY_SHOT_OFF[] = "beauty-shot";
+const char CameraParameters::BEAUTY_SHOT_ON[] = "beauty-shot";
+const char CameraParameters::BURST_SHOT_OFF[] = "burst-shot";
+const char CameraParameters::BURST_SHOT_ON[] = "burst-shot";
+const char CameraParameters::KEY_AUDIO_ZOOM[] = "audio-zoom";
+const char CameraParameters::KEY_AUDIO_ZOOM_SUPPORTED[] = "audio-zoom-supported";
+const char CameraParameters::KEY_BEAUTY_SHOT[] = "beauty-shot";
+const char CameraParameters::KEY_BEAUTY_SHOT_SUPPORTED[] = "beauty-shot-supported";
+const char CameraParameters::KEY_BURST_SHOT[] = "burst-shot";
+const char CameraParameters::KEY_BURST_SHOT_SUPPORTED[] = "burst-shot-supported";
+const char CameraParameters::KEY_FOCUS_MODE_OBJECT_TRACKING[] = "object-tracking";
+const char CameraParameters::KEY_FOCUS_MODE_OBJECT_TRACKING_SUPPORTED[] = "object-tracking-supported";
+const char CameraParameters::KEY_VIDEO_WDR[] = "video-wdr";
+const char CameraParameters::KEY_VIDEO_WDR_SUPPORTED[] = "video-wdr-supported";
+const char CameraParameters::VIDEO_WDR_OFF[] = "video-wdr";
+const char CameraParameters::VIDEO_WDR_ON[] = "video-wdr";
+const char CameraParameters::OBJECT_TRACKING_ON[] = "object-tracking";
+const char CameraParameters::OBJECT_TRACKING_OFF[] = "object-tracking";
+#endif
const char CameraParameters::TRUE[] = "true";
const char CameraParameters::FALSE[] = "false";
@@ -116,6 +280,24 @@
const char CameraParameters::EFFECT_WHITEBOARD[] = "whiteboard";
const char CameraParameters::EFFECT_BLACKBOARD[] = "blackboard";
const char CameraParameters::EFFECT_AQUA[] = "aqua";
+#ifdef SAMSUNG_CAMERA_HARDWARE
+const char CameraParameters::EFFECT_CARTOONIZE[] = "cartoonize";
+const char CameraParameters::EFFECT_POINT_RED_YELLOW[] = "point-red-yellow";
+const char CameraParameters::EFFECT_POINT_GREEN[] = "point-green";
+const char CameraParameters::EFFECT_POINT_BLUE[] = "point-blue";
+const char CameraParameters::EFFECT_VINTAGE_COLD[] = "vintage-cold";
+const char CameraParameters::EFFECT_VINTAGE_WARM[] = "vintage-warm";
+const char CameraParameters::EFFECT_WASHED[] = "washed";
+#endif
+#ifdef QCOM_HARDWARE
+const char CameraParameters::EFFECT_EMBOSS[] = "emboss";
+const char CameraParameters::EFFECT_SKETCH[] = "sketch";
+const char CameraParameters::EFFECT_NEON[] = "neon";
+
+// Values for auto exposure settings.
+const char CameraParameters::TOUCH_AF_AEC_OFF[] = "touch-off";
+const char CameraParameters::TOUCH_AF_AEC_ON[] = "touch-on";
+#endif
// Values for antibanding settings.
const char CameraParameters::ANTIBANDING_AUTO[] = "auto";
@@ -131,7 +313,8 @@
const char CameraParameters::FLASH_MODE_TORCH[] = "torch";
// Values for scene mode settings.
-const char CameraParameters::SCENE_MODE_AUTO[] = "auto";
+const char CameraParameters::SCENE_MODE_AUTO[] = "auto"; // corresponds to CAMERA_BESTSHOT_OFF in HAL
+const char CameraParameters::SCENE_MODE_ASD[] = "asd"; // corresponds to CAMERA_BESTSHOT_AUTO in HAL
const char CameraParameters::SCENE_MODE_ACTION[] = "action";
const char CameraParameters::SCENE_MODE_PORTRAIT[] = "portrait";
const char CameraParameters::SCENE_MODE_LANDSCAPE[] = "landscape";
@@ -146,11 +329,32 @@
const char CameraParameters::SCENE_MODE_SPORTS[] = "sports";
const char CameraParameters::SCENE_MODE_PARTY[] = "party";
const char CameraParameters::SCENE_MODE_CANDLELIGHT[] = "candlelight";
+#ifdef QCOM_HARDWARE
+#ifdef SAMSUNG_CAMERA_LEGACY
+const char CameraParameters::SCENE_MODE_BACKLIGHT[] = "back-light";
+#else
+const char CameraParameters::SCENE_MODE_BACKLIGHT[] = "backlight";
+#endif
+const char CameraParameters::SCENE_MODE_FLOWERS[] = "flowers";
+#endif
const char CameraParameters::SCENE_MODE_BARCODE[] = "barcode";
-const char CameraParameters::SCENE_MODE_HDR[] = "hdr";
+const char CameraParameters::SCENE_MODE_HDR[] = "hdr";
+#ifdef QCOM_HARDWARE
+const char CameraParameters::SCENE_MODE_AR[] = "AR";
+
+// Values for auto scene detection settings.
+const char CameraParameters::SCENE_DETECT_OFF[] = "off";
+const char CameraParameters::SCENE_DETECT_ON[] = "on";
+#endif
+
+
+// Formats for setPreviewFormat and setPictureFormat.
const char CameraParameters::PIXEL_FORMAT_YUV422SP[] = "yuv422sp";
const char CameraParameters::PIXEL_FORMAT_YUV420SP[] = "yuv420sp";
+#ifdef QCOM_HARDWARE
+const char CameraParameters::PIXEL_FORMAT_YUV420SP_ADRENO[] = "yuv420sp-adreno";
+#endif
const char CameraParameters::PIXEL_FORMAT_YUV422I[] = "yuv422i-yuyv";
const char CameraParameters::PIXEL_FORMAT_YUV420P[] = "yuv420p";
const char CameraParameters::PIXEL_FORMAT_RGB565[] = "rgb565";
@@ -159,6 +363,12 @@
const char CameraParameters::PIXEL_FORMAT_BAYER_RGGB[] = "bayer-rggb";
const char CameraParameters::PIXEL_FORMAT_ANDROID_OPAQUE[] = "android-opaque";
+#ifdef QCOM_HARDWARE
+const char CameraParameters::PIXEL_FORMAT_RAW[] = "raw";
+const char CameraParameters::PIXEL_FORMAT_YV12[] = "yuv420p";
+const char CameraParameters::PIXEL_FORMAT_NV12[] = "nv12";
+#endif
+
// Values for focus mode settings.
const char CameraParameters::FOCUS_MODE_AUTO[] = "auto";
const char CameraParameters::FOCUS_MODE_INFINITY[] = "infinity";
@@ -167,6 +377,161 @@
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";
+#if defined(QCOM_HARDWARE)
+#ifdef QCOM_LEGACY_CAM_PARAMS
+const char CameraParameters::FOCUS_MODE_CONTINUOUS_CAMERA[] = "continuous-camera";
+#endif
+const char CameraParameters::FOCUS_MODE_NORMAL[] = "normal";
+
+
+const char CameraParameters::KEY_SKIN_TONE_ENHANCEMENT[] = "skinToneEnhancement";
+const char CameraParameters::KEY_SUPPORTED_SKIN_TONE_ENHANCEMENT_MODES[] = "skinToneEnhancement-values";
+
+// Values for ISO Settings
+const char CameraParameters::ISO_AUTO[] = "auto";
+const char CameraParameters::ISO_HJR[] = "ISO_HJR";
+const char CameraParameters::ISO_100[] = "ISO100";
+const char CameraParameters::ISO_200[] = "ISO200";
+const char CameraParameters::ISO_400[] = "ISO400";
+const char CameraParameters::ISO_800[] = "ISO800";
+const char CameraParameters::ISO_1600[] = "ISO1600";
+const char CameraParameters::ISO_3200[] = "ISO3200";
+const char CameraParameters::ISO_6400[] = "ISO6400";
+
+ //Values for Lens Shading
+const char CameraParameters::LENSSHADE_ENABLE[] = "enable";
+const char CameraParameters::LENSSHADE_DISABLE[] = "disable";
+
+// Values for auto exposure settings.
+const char CameraParameters::AUTO_EXPOSURE_FRAME_AVG[] = "frame-average";
+const char CameraParameters::AUTO_EXPOSURE_CENTER_WEIGHTED[] = "center-weighted";
+const char CameraParameters::AUTO_EXPOSURE_SPOT_METERING[] = "spot-metering";
+
+const char CameraParameters::KEY_GPS_LATITUDE_REF[] = "gps-latitude-ref";
+const char CameraParameters::KEY_GPS_LONGITUDE_REF[] = "gps-longitude-ref";
+const char CameraParameters::KEY_GPS_ALTITUDE_REF[] = "gps-altitude-ref";
+const char CameraParameters::KEY_GPS_STATUS[] = "gps-status";
+const char CameraParameters::KEY_EXIF_DATETIME[] = "exif-datetime";
+
+const char CameraParameters::KEY_HISTOGRAM[] = "histogram";
+const char CameraParameters::KEY_SUPPORTED_HISTOGRAM_MODES[] = "histogram-values";
+//Values for Histogram Shading
+const char CameraParameters::HISTOGRAM_ENABLE[] = "enable";
+const char CameraParameters::HISTOGRAM_DISABLE[] = "disable";
+
+//Values for Skin Tone Enhancement Modes
+const char CameraParameters::SKIN_TONE_ENHANCEMENT_ENABLE[] = "enable";
+const char CameraParameters::SKIN_TONE_ENHANCEMENT_DISABLE[] = "disable";
+
+const char CameraParameters::KEY_SHARPNESS[] = "sharpness";
+#ifdef QCOM_LEGACY_CAM_PARAMS
+const char CameraParameters::KEY_MAX_SHARPNESS[] = "sharpness-max";
+const char CameraParameters::KEY_MIN_SHARPNESS[] = "sharpness-min";
+#else
+const char CameraParameters::KEY_MAX_SHARPNESS[] = "max-sharpness";
+#endif
+const char CameraParameters::KEY_CONTRAST[] = "contrast";
+#ifdef QCOM_LEGACY_CAM_PARAMS
+const char CameraParameters::KEY_MAX_CONTRAST[] = "contrast-max";
+const char CameraParameters::KEY_MIN_CONTRAST[] = "contrast-min";
+#else
+const char CameraParameters::KEY_MAX_CONTRAST[] = "max-contrast";
+#endif
+const char CameraParameters::KEY_SATURATION[] = "saturation";
+#ifdef QCOM_LEGACY_CAM_PARAMS
+const char CameraParameters::KEY_MAX_SATURATION[] = "saturation-max";
+const char CameraParameters::KEY_MIN_SATURATION[] = "saturation-min";
+#else
+const char CameraParameters::KEY_MAX_SATURATION[] = "max-saturation";
+#endif
+
+//Values for DENOISE
+const char CameraParameters::DENOISE_OFF[] = "denoise-off";
+const char CameraParameters::DENOISE_ON[] = "denoise-on";
+// Values for selectable zone af Settings
+const char CameraParameters::SELECTABLE_ZONE_AF_AUTO[] = "auto";
+const char CameraParameters::SELECTABLE_ZONE_AF_SPOT_METERING[] = "spot-metering";
+const char CameraParameters::SELECTABLE_ZONE_AF_CENTER_WEIGHTED[] = "center-weighted";
+const char CameraParameters::SELECTABLE_ZONE_AF_FRAME_AVERAGE[] = "frame-average";
+
+// Values for Face Detection settings.
+const char CameraParameters::FACE_DETECTION_OFF[] = "off";
+const char CameraParameters::FACE_DETECTION_ON[] = "on";
+
+const char CameraParameters::FILE_FORMAT_MPO[] = "mpo";
+const char CameraParameters::FILE_FORMAT_JPS[] = "jps";
+
+// Values for MCE settings.
+const char CameraParameters::MCE_ENABLE[] = "enable";
+const char CameraParameters::MCE_DISABLE[] = "disable";
+
+// Values for HFR settings.
+const char CameraParameters::VIDEO_HFR_OFF[] = "off";
+const char CameraParameters::VIDEO_HFR_2X[] = "60";
+const char CameraParameters::VIDEO_HFR_3X[] = "90";
+const char CameraParameters::VIDEO_HFR_4X[] = "120";
+
+// Values for Redeye Reduction settings.
+const char CameraParameters::REDEYE_REDUCTION_ENABLE[] = "enable";
+const char CameraParameters::REDEYE_REDUCTION_DISABLE[] = "disable";
+// Values for HDR settings.
+const char CameraParameters::HDR_ENABLE[] = "enable";
+const char CameraParameters::HDR_DISABLE[] = "disable";
+
+// Values for ZSL settings.
+const char CameraParameters::ZSL_OFF[] = "off";
+const char CameraParameters::ZSL_ON[] = "on";
+
+// Values for HDR Bracketing settings.
+const char CameraParameters::AE_BRACKET_HDR_OFF[] = "Off";
+const char CameraParameters::AE_BRACKET_HDR[] = "HDR";
+const char CameraParameters::AE_BRACKET[] = "AE-Bracket";
+
+const char CameraParameters::LOW_POWER[] = "Low_Power";
+const char CameraParameters::NORMAL_POWER[] = "Normal_Power";
+
+#if defined(QCOM_HARDWARE) && defined(SAMSUNG_CAMERA_LEGACY)
+const char CameraParameters::FOCUS_MODE_FACEDETECT[] = "facedetect";
+const char CameraParameters::FOCUS_MODE_TOUCHAF[] = "touchaf";
+const char CameraParameters::ISO_50[] = "ISO50";
+const char CameraParameters::KEY_ANTI_SHAKE_MODE[] = "antishake";
+const char CameraParameters::KEY_AUTO_CONTRAST[] = "auto-contrast";
+const char CameraParameters::KEY_BEAUTY_MODE[] = "beauty";
+const char CameraParameters::KEY_BLUR_MODE[] = "blur";
+const char CameraParameters::KEY_VINTAGE_MODE[] = "vintagemode";
+const char CameraParameters::KEY_WDR_MODE[] = "wdr";
+const char CameraParameters::VINTAGE_MODE_BNW[] = "bnw";
+const char CameraParameters::VINTAGE_MODE_COOL[] = "cool";
+const char CameraParameters::VINTAGE_MODE_NORMAL[] = "normal";
+const char CameraParameters::VINTAGE_MODE_OFF[] = "off";
+const char CameraParameters::VINTAGE_MODE_WARM[] = "warm";
+const char CameraParameters::SCENE_MODE_DAWN[] = "dusk-dawn";
+const char CameraParameters::SCENE_MODE_DUSKDAWN[] = "dusk-dawn";
+const char CameraParameters::SCENE_MODE_FALL[] = "fall-color";
+const char CameraParameters::SCENE_MODE_FALL_COLOR[] = "fall-color";
+const char CameraParameters::SCENE_MODE_TEXT[] = "text";
+#endif
+
+static const char* portrait = "portrait";
+static const char* landscape = "landscape";
+
+int CameraParameters::getOrientation() const
+{
+ const char* orientation = get("orientation");
+ if (orientation && !strcmp(orientation, portrait))
+ return CAMERA_ORIENTATION_PORTRAIT;
+ return CAMERA_ORIENTATION_LANDSCAPE;
+}
+void CameraParameters::setOrientation(int orientation)
+{
+ if (orientation == CAMERA_ORIENTATION_PORTRAIT) {
+ set("orientation", portrait);
+ } else {
+ set("orientation", landscape);
+ }
+}
+#endif
+
// Values for light fx settings
const char CameraParameters::LIGHTFX_LOWLIGHT[] = "low-light";
@@ -236,6 +601,9 @@
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);
@@ -253,7 +621,7 @@
void CameraParameters::set(const char *key, int value)
{
char str[16];
- sprintf(str, "%d", value);
+ snprintf(str, sizeof(str), "%d", value);
set(key, str);
}
@@ -280,6 +648,13 @@
return strtol(v, 0, 0);
}
+#ifdef SAMSUNG_CAMERA_HARDWARE
+int CameraParameters::getInt64(const char *key) const
+{
+ return -1;
+}
+#endif
+
float CameraParameters::getFloat(const char *key) const
{
const char *v = get(key);
@@ -318,6 +693,32 @@
return 0;
}
+// Parse string like "(1, 2, 3, 4, ..., N)"
+// num is pointer to an allocated array of size N
+static int parseNDimVector(const char *str, int *num, int N, char delim = ',')
+{
+ char *start, *end;
+ if(num == NULL) {
+ ALOGE("Invalid output array (num == NULL)");
+ return -1;
+ }
+ //check if string starts and ends with parantheses
+ if(str[0] != '(' || str[strlen(str)-1] != ')') {
+ ALOGE("Invalid format of string %s, valid format is (n1, n2, n3, n4 ...)", str);
+ return -1;
+ }
+ start = (char*) str;
+ start++;
+ for(int i=0; i<N; i++) {
+ *(num+i) = (int) strtol(start, &end, 10);
+ if(*end != delim && i < N-1) {
+ ALOGE("Cannot find delimeter '%c' in string \"%s\". end = %c", delim, str, *end);
+ return -1;
+ }
+ start = end+1;
+ }
+ return 0;
+}
static void parseSizesList(const char *sizesStr, Vector<Size> &sizes)
{
if (sizesStr == 0) {
@@ -346,7 +747,7 @@
void CameraParameters::setPreviewSize(int width, int height)
{
char str[32];
- sprintf(str, "%dx%d", width, height);
+ snprintf(str, sizeof(str), "%dx%d", width, height);
set(KEY_PREVIEW_SIZE, str);
}
@@ -373,6 +774,28 @@
parseSizesList(previewSizesStr, sizes);
}
+#ifdef QCOM_HARDWARE
+#ifdef QCOM_LEGACY_CAM_PARAMS
+void CameraParameters::setPostviewSize(int width, int height)
+{
+ // dummy
+}
+#endif
+
+void CameraParameters::getSupportedHfrSizes(Vector<Size> &sizes) const
+{
+ const char *hfrSizesStr = get(KEY_SUPPORTED_HFR_SIZES);
+ parseSizesList(hfrSizesStr, sizes);
+}
+
+void CameraParameters::setPreviewFpsRange(int minFPS, int maxFPS)
+{
+ char str[32];
+ snprintf(str, sizeof(str), "%d,%d",minFPS,maxFPS);
+ set(KEY_PREVIEW_FPS_RANGE,str);
+}
+#endif
+
void CameraParameters::setVideoSize(int width, int height)
{
char str[32];
@@ -412,6 +835,18 @@
parse_pair(p, min_fps, max_fps, ',');
}
+#ifdef QCOM_HARDWARE
+void CameraParameters::setPreviewFrameRateMode(const char *mode)
+{
+ set(KEY_PREVIEW_FRAME_RATE_MODE, mode);
+}
+
+const char *CameraParameters::getPreviewFrameRateMode() const
+{
+ return get(KEY_PREVIEW_FRAME_RATE_MODE);
+}
+#endif
+
void CameraParameters::setPreviewFormat(const char *format)
{
set(KEY_PREVIEW_FORMAT, format);
@@ -444,6 +879,11 @@
parseSizesList(pictureSizesStr, sizes);
}
+void CameraParameters::set3DFileFormat(const char *format)
+{
+ set(KEY_SUPPORTED_3D_FILE_FORMAT, format);
+}
+
void CameraParameters::setPictureFormat(const char *format)
{
set(KEY_PICTURE_FORMAT, format);
@@ -465,6 +905,71 @@
}
}
+#ifdef QCOM_HARDWARE
+void CameraParameters::setTouchIndexAec(int x, int y)
+{
+ char str[32];
+ snprintf(str, sizeof(str), "%dx%d", x, y);
+ set(KEY_TOUCH_INDEX_AEC, str);
+}
+
+void CameraParameters::getTouchIndexAec(int *x, int *y) const
+{
+ *x = -1;
+ *y = -1;
+
+ // Get the current string, if it doesn't exist, leave the -1x-1
+ const char *p = get(KEY_TOUCH_INDEX_AEC);
+ if (p == 0)
+ return;
+
+ int tempX, tempY;
+ if (parse_pair(p, &tempX, &tempY, 'x') == 0) {
+ *x = tempX;
+ *y = tempY;
+ }
+}
+
+void CameraParameters::setTouchIndexAf(int x, int y)
+{
+ char str[32];
+ snprintf(str, sizeof(str), "%dx%d", x, y);
+ set(KEY_TOUCH_INDEX_AF, str);
+}
+
+void CameraParameters::getMeteringAreaCenter(int *x, int *y) const
+{
+ //Default invalid values
+ *x = -2000;
+ *y = -2000;
+
+ const char *p = get(KEY_METERING_AREAS);
+ if(p != NULL) {
+ int arr[5] = {-2000, -2000, -2000, -2000, 0};
+ parseNDimVector(p, arr, 5); //p = "(x1, y1, x2, y2, weight)"
+ *x = (arr[0] + arr[2])/2; //center_x = (x1+x2)/2
+ *y = (arr[1] + arr[3])/2; //center_y = (y1+y2)/2
+ }
+}
+
+void CameraParameters::getTouchIndexAf(int *x, int *y) const
+{
+ *x = -1;
+ *y = -1;
+
+ // Get the current string, if it doesn't exist, leave the -1x-1
+ const char *p = get(KEY_TOUCH_INDEX_AF);
+ if (p == 0)
+ return;
+
+ int tempX, tempY;
+ if (parse_pair(p, &tempX, &tempY, 'x') == 0) {
+ *x = tempX;
+ *y = tempY;
+ }
+}
+#endif
+
status_t CameraParameters::dump(int fd, const Vector<String16>& args) const
{
const size_t SIZE = 256;
diff --git a/cmds/screenrecord/screenrecord.cpp b/cmds/screenrecord/screenrecord.cpp
index 49999b5..83b6a03 100644
--- a/cmds/screenrecord/screenrecord.cpp
+++ b/cmds/screenrecord/screenrecord.cpp
@@ -49,7 +49,7 @@
static const uint32_t kMinBitRate = 100000; // 0.1Mbps
static const uint32_t kMaxBitRate = 100 * 1000000; // 100Mbps
-static const uint32_t kMaxTimeLimitSec = 180; // 3 minutes
+static const uint32_t kMaxTimeLimitSec = 3600; // 1 Hour
static const uint32_t kFallbackWidth = 1280; // 720p
static const uint32_t kFallbackHeight = 720;
diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h
index d521543..2758989 100644
--- a/include/camera/CameraParameters.h
+++ b/include/camera/CameraParameters.h
@@ -36,7 +36,21 @@
height = h;
}
};
+#ifdef QCOM_HARDWARE
+struct FPSRange{
+ int minFPS;
+ int maxFPS;
+ FPSRange(){
+ minFPS=0;
+ maxFPS=0;
+ };
+ FPSRange(int min,int max){
+ minFPS=min;
+ maxFPS=max;
+ };
+};
+#endif
class CameraParameters
{
public:
@@ -52,6 +66,9 @@
void setFloat(const char *key, float value);
const char *get(const char *key) const;
int getInt(const char *key) const;
+#ifdef SAMSUNG_CAMERA_HARDWARE
+ int getInt64(const char *key) const;
+#endif
float getFloat(const char *key) const;
void remove(const char *key);
@@ -91,13 +108,26 @@
void setPreviewFrameRate(int fps);
int getPreviewFrameRate() const;
void getPreviewFpsRange(int *min_fps, int *max_fps) const;
+#ifdef QCOM_HARDWARE
+ void setPreviewFrameRateMode(const char *mode);
+ const char *getPreviewFrameRateMode() const;
+#endif
void setPreviewFormat(const char *format);
const char *getPreviewFormat() const;
void setPictureSize(int width, int height);
void getPictureSize(int *width, int *height) const;
void getSupportedPictureSizes(Vector<Size> &sizes) const;
+ void set3DFileFormat(const char* buffer);
void setPictureFormat(const char *format);
const char *getPictureFormat() const;
+#ifdef QCOM_HARDWARE
+ void setTouchIndexAec(int x, int y);
+ void getTouchIndexAec(int *x, int *y) const;
+ void setTouchIndexAf(int x, int y);
+ void getTouchIndexAf(int *x, int *y) const;
+#endif
+
+ void getMeteringAreaCenter(int * x, int *y) const;
void dump() const;
status_t dump(int fd, const Vector<String16>& args) const;
@@ -112,6 +142,11 @@
// Supported preview frame sizes in pixels.
// Example value: "800x600,480x320". Read only.
static const char KEY_SUPPORTED_PREVIEW_SIZES[];
+#ifdef QCOM_HARDWARE
+ // Supported PREVIEW/RECORDING SIZES IN HIGH FRAME RATE recording, sizes in pixels.
+ // Example value: "800x480,432x320". Read only.
+ static const char KEY_SUPPORTED_HFR_SIZES[];
+#endif
// The current minimum and maximum preview fps. This controls the rate of
// preview frames received (CAMERA_MSG_PREVIEW_FRAME). The minimum and
// maximum fps must be one of the elements from
@@ -141,12 +176,36 @@
// Supported number of preview frames per second.
// Example value: "24,15,10". Read.
static const char KEY_SUPPORTED_PREVIEW_FRAME_RATES[];
+#ifdef QCOM_HARDWARE
+ // The mode of preview frame rate.
+ // Example value: "frame-rate-auto, frame-rate-fixed".
+ static const char KEY_PREVIEW_FRAME_RATE_MODE[];
+ static const char KEY_SUPPORTED_PREVIEW_FRAME_RATE_MODES[];
+ static const char KEY_PREVIEW_FRAME_RATE_AUTO_MODE[];
+ static const char KEY_PREVIEW_FRAME_RATE_FIXED_MODE[];
+#ifdef QCOM_LEGACY_CAM_PARAMS
+ static const char KEY_CAPTURE_MODE[];
+ static const char KEY_SUPPORTED_CAPTURE_MODES[];
+ static const char KEY_PICTURE_COUNT[];
+ static const char KEY_MAX_BURST_PICTURE_COUNT[];
+ static const char KEY_SUPPORTED_CONTINUOUS_AF[];
+ static const char KEY_SUPPORTED_CAF[];
+ static const char CAPTURE_MODE_NORMAL[];
+ static const char CAPTURE_MODE_BURST[];
+ static const char CAPTURE_MODE_CONTI_BURST[];
+ static const char CAPTURE_MODE_HDR[];
+ static const char CAPTURE_MODE_HJR[];
+ static const char CAPTURE_MODE_PANORAMA[];
+#endif
+#endif
// The dimensions for captured pictures in pixels (width x height).
// Example value: "1024x768". Read/write.
static const char KEY_PICTURE_SIZE[];
// Supported dimensions for captured pictures in pixels.
// Example value: "2048x1536,1024x768". Read only.
static const char KEY_SUPPORTED_PICTURE_SIZES[];
+ //HTC 3D color format
+ static const char KEY_SUPPORTED_3D_FILE_FORMAT[];
// The image format for captured pictures. See CAMERA_MSG_COMPRESSED_IMAGE
// in frameworks/base/include/camera/Camera.h.
// Example value: "jpeg" or PIXEL_FORMAT_XXX constants. Read/write.
@@ -203,6 +262,12 @@
// header.
// Example value: "21.0" or "-5". Write only.
static const char KEY_GPS_ALTITUDE[];
+
+#ifdef QCOM_HARDWARE
+ static const char KEY_SKIN_TONE_ENHANCEMENT[] ;
+ static const char KEY_SUPPORTED_SKIN_TONE_ENHANCEMENT_MODES[] ;
+#endif
+
// GPS timestamp (UTC in seconds since January 1, 1970). This should be
// stored in JPEG EXIF header.
// Example value: "1251192757". Write only.
@@ -222,6 +287,15 @@
// Supported color effect settings.
// Example value: "none,mono,sepia". Read only.
static const char KEY_SUPPORTED_EFFECTS[];
+#ifdef QCOM_HARDWARE
+ //Touch Af/AEC settings.
+ static const char KEY_TOUCH_AF_AEC[];
+ static const char KEY_SUPPORTED_TOUCH_AF_AEC[];
+ //Touch Index for AEC.
+ static const char KEY_TOUCH_INDEX_AEC[];
+ //Touch Index for AF.
+ static const char KEY_TOUCH_INDEX_AF[];
+#endif
// Current antibanding setting.
// Example value: "auto" or ANTIBANDING_XXX constants. Read/write.
static const char KEY_ANTIBANDING[];
@@ -234,6 +308,14 @@
// Supported scene mode settings.
// Example value: "auto,night,fireworks". Read only.
static const char KEY_SUPPORTED_SCENE_MODES[];
+#ifdef QCOM_HARDWARE
+ // Current auto scene detection mode.
+ // Example value: "off" or SCENE_DETECT_XXX constants. Read/write.
+ static const char KEY_SCENE_DETECT[];
+ // Supported auto scene detection settings.
+ // Example value: "off,backlight,snow/cloudy". Read only.
+ static const char KEY_SUPPORTED_SCENE_DETECT[];
+#endif
// Current flash mode.
// Example value: "auto" or FLASH_MODE_XXX constants. Read/write.
static const char KEY_FLASH_MODE[];
@@ -505,6 +587,23 @@
// captured pictures.
// Example value: "true" or "false". Read only.
static const char KEY_VIDEO_SNAPSHOT_SUPPORTED[];
+ static const char KEY_FULL_VIDEO_SNAP_SUPPORTED[];
+
+#ifdef QCOM_HARDWARE
+ static const char KEY_ISO_MODE[];
+ static const char KEY_SUPPORTED_ISO_MODES[];
+ static const char KEY_LENSSHADE[] ;
+ static const char KEY_SUPPORTED_LENSSHADE_MODES[] ;
+
+ static const char KEY_AUTO_EXPOSURE[];
+ static const char KEY_SUPPORTED_AUTO_EXPOSURE[];
+
+ static const char KEY_GPS_LATITUDE_REF[];
+ static const char KEY_GPS_LONGITUDE_REF[];
+ static const char KEY_GPS_ALTITUDE_REF[];
+ static const char KEY_GPS_STATUS[];
+ static const char KEY_EXIF_DATETIME[];
+#endif
// The state of the video stabilization. If set to true, both the
// preview stream and the recorded video stream are stabilized by
@@ -520,6 +619,23 @@
// has no effect on still image capture.
static const char KEY_VIDEO_STABILIZATION[];
+#ifdef QCOM_HARDWARE
+ static const char KEY_MEMORY_COLOR_ENHANCEMENT[];
+ static const char KEY_SUPPORTED_MEM_COLOR_ENHANCE_MODES[];
+
+ static const char KEY_POWER_MODE_SUPPORTED[];
+ static const char KEY_POWER_MODE[];
+
+ static const char KEY_ZSL[];
+ static const char KEY_SUPPORTED_ZSL_MODES[];
+
+ static const char KEY_CAMERA_MODE[];
+
+ static const char KEY_VIDEO_HIGH_FRAME_RATE[];
+ static const char KEY_SUPPORTED_VIDEO_HIGH_FRAME_RATE_MODES[];
+ static const char KEY_HIGH_DYNAMIC_RANGE_IMAGING[];
+ static const char KEY_SUPPORTED_HDR_IMAGING_MODES[];
+#endif
// Returns true if video stabilization is supported. That is, applications
// can set KEY_VIDEO_STABILIZATION to true and have a stabilized preview
// stream and record stabilized videos.
@@ -529,6 +645,88 @@
// Example values: "lowlight,hdr".
static const char KEY_LIGHTFX[];
+#ifdef HAVE_ISO
+ static const char KEY_SUPPORTED_ISO_MODES[];
+ static const char KEY_ISO_MODE[];
+#endif
+
+#ifdef SAMSUNG_CAMERA_HARDWARE
+ static const char KEY_ANTI_SHAKE_MODE[];
+ static const char KEY_METERING[];
+ static const char KEY_WDR[];
+ static const char KEY_WEATHER[];
+ static const char KEY_CITYID[];
+#endif
+
+#ifdef HTC_CAMERA_HARDWARE
+ static const char KEY_TIME_CONS_POST_PROCESSING[];
+ static const char KEY_OIS_MODE[];
+ static const char KEY_APP_OIS_SETTING[];
+ static const char KEY_OIS_SUPPORT[];
+ static const char KEY_CONTIBURST_TYPE[];
+ static const char KEY_CAPTURE_MODE[];
+ static const char CAPTURE_MODE_NORMAL[];
+ static const char CAPTURE_MODE_CONTI_ZOE[];
+ static const char CAPTURE_MODE_CONTI_BURST[];
+ static const char CAPTURE_MODE_CONTI_BURST_ONE_SHOT[];
+ static const char CAPTURE_MODE_HDR[];
+ static const char CAPTURE_MODE_PANORAMA[];
+ static const char CAPTURE_MODE_ZOE[];
+ static const char KEY_CONTI_BURST_STATE[];
+ static const char KEY_SUPPORTED_CAPTURE_MODES[];
+ static const char KEY_MIN_CONTRAST[];
+ static const char KEY_DEF_CONTRAST[];
+ static const char KEY_MIN_SHARPNESS[];
+ static const char KEY_DEF_SHARPNESS[];
+ static const char KEY_MIN_SATURATION[];
+ static const char KEY_DEF_SATURATION[];
+ static const char KEY_SINGLE_ISP_OUTPUT_ENABLED[];
+ static const char POST_PROCESSING_ENABLE[];
+ static const char POST_PROCESSING_BYPASS[];
+ static const char POST_PROCESSING_DELAY[];
+ static const char SCENE_MODE_OFF[];
+ static const char SCENE_MODE_TEXT[];
+ static const char BURST_MODE_LIMIT20[];
+ static const char BURST_MODE_UNLIMITED[];
+ static const char OIS_MODE_OFF[];
+ static const char OIS_MODE_ON[];
+ static const char CONTI_BURST_CAPTURING[];
+ static const char CONTI_BURST_CAPTURE_DONE[];
+ static const char APP_OIS_SETTING_FALSE[];
+ static const char APP_OIS_SETTING_TRUE[];
+ static const char KEY_GPU_EFFECT[];
+ static const char KEY_GPU_EFFECT_PARAM_0[];
+ static const char KEY_GPU_EFFECT_PARAM_1[];
+ static const char KEY_GPU_EFFECT_PARAM_2[];
+ static const char KEY_GPU_EFFECT_PARAM_3[];
+ static const char KEY_FORCE_USE_AUDIO_ENABLED[];
+#endif
+
+#ifdef LG_CAMERA_HARDWARE
+ static const char AUDIO_ZOOM_OFF[];
+ static const char AUDIO_ZOOM_ON[];
+ static const char BEAUTY_SHOT_OFF[];
+ static const char BEAUTY_SHOT_ON[];
+ static const char BURST_SHOT_OFF[];
+ static const char BURST_SHOT_ON[];
+ static const char KEY_AUDIO_ZOOM[];
+ static const char KEY_AUDIO_ZOOM_SUPPORTED[];
+ static const char KEY_BEAUTY_SHOT[];
+ static const char KEY_BEAUTY_SHOT_SUPPORTED[];
+ static const char KEY_BURST_SHOT[];
+ static const char KEY_BURST_SHOT_SUPPORTED[];
+ static const char KEY_FOCUS_MODE_OBJECT_TRACKING[];
+ static const char KEY_FOCUS_MODE_OBJECT_TRACKING_SUPPORTED[];
+ static const char KEY_VIDEO_WDR[];
+ static const char KEY_VIDEO_WDR_SUPPORTED[];
+ static const char VIDEO_WDR_OFF[];
+ static const char VIDEO_WDR_ON[];
+ static const char OBJECT_TRACKING_ON[];
+ static const char OBJECT_TRACKING_OFF[];
+#endif
+
+ static const char KEY_AE_BRACKET_HDR[];
+
// Value for KEY_ZOOM_SUPPORTED or KEY_SMOOTH_ZOOM_SUPPORTED.
static const char TRUE[];
static const char FALSE[];
@@ -536,6 +734,24 @@
// Value for KEY_FOCUS_DISTANCES.
static const char FOCUS_DISTANCE_INFINITY[];
+#ifdef QCOM_HARDWARE
+ // DENOISE
+ static const char KEY_DENOISE[];
+ static const char KEY_SUPPORTED_DENOISE[];
+
+ //Selectable zone AF.
+ static const char KEY_SELECTABLE_ZONE_AF[];
+ static const char KEY_SUPPORTED_SELECTABLE_ZONE_AF[];
+
+ //Face Detection
+ static const char KEY_FACE_DETECTION[];
+ static const char KEY_SUPPORTED_FACE_DETECTION[];
+
+ //Redeye Reduction
+ static const char KEY_REDEYE_REDUCTION[];
+ static const char KEY_SUPPORTED_REDEYE_REDUCTION[];
+#endif
+
// Values for white balance settings.
static const char WHITE_BALANCE_AUTO[];
static const char WHITE_BALANCE_INCANDESCENT[];
@@ -556,6 +772,24 @@
static const char EFFECT_WHITEBOARD[];
static const char EFFECT_BLACKBOARD[];
static const char EFFECT_AQUA[];
+#ifdef SAMSUNG_CAMERA_HARDWARE
+ static const char EFFECT_CARTOONIZE[];
+ static const char EFFECT_POINT_RED_YELLOW[];
+ static const char EFFECT_POINT_GREEN[];
+ static const char EFFECT_POINT_BLUE[];
+ static const char EFFECT_VINTAGE_COLD[];
+ static const char EFFECT_VINTAGE_WARM[];
+ static const char EFFECT_WASHED[];
+#endif
+#ifdef QCOM_HARDWARE
+ static const char EFFECT_EMBOSS[];
+ static const char EFFECT_SKETCH[];
+ static const char EFFECT_NEON[];
+
+ // Values for Touch AF/AEC
+ static const char TOUCH_AF_AEC_OFF[] ;
+ static const char TOUCH_AF_AEC_ON[] ;
+#endif
// Values for antibanding settings.
static const char ANTIBANDING_AUTO[];
@@ -580,6 +814,7 @@
// Values for scene mode settings.
static const char SCENE_MODE_AUTO[];
+ static const char SCENE_MODE_ASD[];
static const char SCENE_MODE_ACTION[];
static const char SCENE_MODE_PORTRAIT[];
static const char SCENE_MODE_LANDSCAPE[];
@@ -594,6 +829,11 @@
static const char SCENE_MODE_SPORTS[];
static const char SCENE_MODE_PARTY[];
static const char SCENE_MODE_CANDLELIGHT[];
+#ifdef QCOM_HARDWARE
+ static const char SCENE_MODE_BACKLIGHT[];
+ static const char SCENE_MODE_FLOWERS[];
+ static const char SCENE_MODE_AR[];
+#endif
// Applications are looking for a barcode. Camera driver will be optimized
// for barcode reading.
static const char SCENE_MODE_BARCODE[];
@@ -604,8 +844,15 @@
// Pixel color formats for KEY_PREVIEW_FORMAT, KEY_PICTURE_FORMAT,
// and KEY_VIDEO_FRAME_FORMAT
+#ifdef QCOM_HARDWARE
+ static const char SCENE_DETECT_OFF[];
+ static const char SCENE_DETECT_ON[];
+#endif
static const char PIXEL_FORMAT_YUV422SP[];
static const char PIXEL_FORMAT_YUV420SP[]; // NV21
+#ifdef QCOM_HARDWARE
+ static const char PIXEL_FORMAT_YUV420SP_ADRENO[]; // ADRENO
+#endif
static const char PIXEL_FORMAT_YUV422I[]; // YUY2
static const char PIXEL_FORMAT_YUV420P[]; // YV12
static const char PIXEL_FORMAT_RGB565[];
@@ -614,9 +861,16 @@
// Raw bayer format used for images, which is 10 bit precision samples
// stored in 16 bit words. The filter pattern is RGGB.
static const char PIXEL_FORMAT_BAYER_RGGB[];
+
// Pixel format is not known to the framework
static const char PIXEL_FORMAT_ANDROID_OPAQUE[];
+#ifdef QCOM_HARDWARE
+ static const char PIXEL_FORMAT_RAW[];
+ static const char PIXEL_FORMAT_YV12[]; // NV21
+ static const char PIXEL_FORMAT_NV12[]; //NV12
+#endif
+
// Values for focus mode settings.
// Auto-focus mode. Applications should call
// CameraHardwareInterface.autoFocus to start the focus in this mode.
@@ -674,6 +928,161 @@
// High-dynamic range mode
static const char LIGHTFX_HDR[];
+#ifdef QCOM_HARDWARE
+#ifdef QCOM_LEGACY_CAM_PARAMS
+ static const char FOCUS_MODE_CONTINUOUS_CAMERA[];
+
+ // Values for Continuous AF
+ static const char CAF_OFF[] ;
+ static const char CAF_ON[] ;
+ // Proprietaries from CodeAurora use these...
+ static const char CONTINUOUS_AF_OFF[] ;
+ static const char CONTINUOUS_AF_ON[] ;
+ static const char KEY_CONTINUOUS_AF[] ;
+ static const char KEY_CAF[] ;
+ static const char KEY_TAKING_PICTURE_ZOOM[];
+ static const char KEY_PANORAMA_MODE[];
+ static const char PANORAMA_MODE_NOT_INPROGRESS[];
+ static const char PANORAMA_MODE_INPROGRESS[];
+#endif
+ // Normal focus mode. Applications should call
+ // CameraHardwareInterface.autoFocus to start the focus in this mode.
+ static const char FOCUS_MODE_NORMAL[];
+ static const char ISO_AUTO[];
+ static const char ISO_HJR[] ;
+ static const char ISO_100[];
+ static const char ISO_200[] ;
+ static const char ISO_400[];
+ static const char ISO_800[];
+ static const char ISO_1600[];
+ static const char ISO_3200[];
+ static const char ISO_6400[];
+ // Values for Lens Shading
+ static const char LENSSHADE_ENABLE[] ;
+ static const char LENSSHADE_DISABLE[] ;
+
+ // Values for auto exposure settings.
+ static const char AUTO_EXPOSURE_FRAME_AVG[];
+ static const char AUTO_EXPOSURE_CENTER_WEIGHTED[];
+ static const char AUTO_EXPOSURE_SPOT_METERING[];
+
+ static const char KEY_SHARPNESS[];
+ static const char KEY_MAX_SHARPNESS[];
+#ifdef QCOM_LEGACY_CAM_PARAMS
+ static const char KEY_MIN_SHARPNESS[];
+#endif
+ static const char KEY_CONTRAST[];
+ static const char KEY_MAX_CONTRAST[];
+#ifdef QCOM_LEGACY_CAM_PARAMS
+ static const char KEY_MIN_CONTRAST[];
+#endif
+ static const char KEY_SATURATION[];
+ static const char KEY_MAX_SATURATION[];
+#ifdef QCOM_LEGACY_CAM_PARAMS
+ static const char KEY_MIN_SATURATION[];
+#endif
+
+ static const char KEY_HISTOGRAM[] ;
+ static const char KEY_SUPPORTED_HISTOGRAM_MODES[] ;
+ // Values for HISTOGRAM
+ static const char HISTOGRAM_ENABLE[] ;
+ static const char HISTOGRAM_DISABLE[] ;
+
+ // Values for SKIN TONE ENHANCEMENT
+ static const char SKIN_TONE_ENHANCEMENT_ENABLE[] ;
+ static const char SKIN_TONE_ENHANCEMENT_DISABLE[] ;
+
+ // Values for Denoise
+ static const char DENOISE_OFF[] ;
+ static const char DENOISE_ON[] ;
+
+ // Values for auto exposure settings.
+ static const char SELECTABLE_ZONE_AF_AUTO[];
+ static const char SELECTABLE_ZONE_AF_SPOT_METERING[];
+ static const char SELECTABLE_ZONE_AF_CENTER_WEIGHTED[];
+ static const char SELECTABLE_ZONE_AF_FRAME_AVERAGE[];
+
+ // Values for Face Detection settings.
+ static const char FACE_DETECTION_OFF[];
+ static const char FACE_DETECTION_ON[];
+
+ // Values for HTC 3D image settings.
+ static const char FILE_FORMAT_MPO[];
+ static const char FILE_FORMAT_JPS[];
+
+ // Values for MCE settings.
+ static const char MCE_ENABLE[];
+ static const char MCE_DISABLE[];
+
+ // Values for ZSL settings.
+ static const char ZSL_OFF[];
+ static const char ZSL_ON[];
+
+ // Values for HDR Bracketing settings.
+ static const char AE_BRACKET_HDR_OFF[];
+ static const char AE_BRACKET_HDR[];
+ static const char AE_BRACKET[];
+
+ //POWER MODE
+ static const char LOW_POWER[];
+ static const char NORMAL_POWER[];
+
+ // Values for HFR settings.
+ static const char VIDEO_HFR_OFF[];
+ static const char VIDEO_HFR_2X[];
+ static const char VIDEO_HFR_3X[];
+ static const char VIDEO_HFR_4X[];
+
+ // Values for Redeye Reduction settings.
+ static const char REDEYE_REDUCTION_ENABLE[];
+ static const char REDEYE_REDUCTION_DISABLE[];
+ // Values for HDR settings.
+ static const char HDR_ENABLE[];
+ static const char HDR_DISABLE[];
+
+#if defined(QCOM_HARDWARE) && defined(SAMSUNG_CAMERA_LEGACY)
+ static const char FOCUS_MODE_FACEDETECT[];
+ static const char FOCUS_MODE_TOUCHAF[];
+ static const char ISO_50[];
+ static const char KEY_ANTI_SHAKE_MODE[];
+ static const char KEY_AUTO_CONTRAST[];
+ static const char KEY_BEAUTY_MODE[];
+ static const char KEY_BLUR_MODE[];
+ static const char KEY_VINTAGE_MODE[];
+ static const char KEY_WDR_MODE[];
+ static const char VINTAGE_MODE_BNW[];
+ static const char VINTAGE_MODE_COOL[];
+ static const char VINTAGE_MODE_NORMAL[];
+ static const char VINTAGE_MODE_OFF[];
+ static const char VINTAGE_MODE_WARM[];
+ static const char SCENE_MODE_DAWN[];
+ static const char SCENE_MODE_DUSKDAWN[];
+ static const char SCENE_MODE_FALL[];
+ static const char SCENE_MODE_FALL_COLOR[];
+ static const char SCENE_MODE_TEXT[];
+#endif
+
+ // Values for Redeye Reduction settings.
+ // static const char REDEYE_REDUCTION_ENABLE[];
+ // static const char REDEYE_REDUCTION_DISABLE[];
+ // Values for HDR settings.
+ // static const char HDR_ENABLE[];
+ // static const char HDR_DISABLE[];
+
+ enum {
+ CAMERA_ORIENTATION_UNKNOWN = 0,
+ CAMERA_ORIENTATION_PORTRAIT = 1,
+ CAMERA_ORIENTATION_LANDSCAPE = 2,
+ };
+ int getOrientation() const;
+ void setOrientation(int orientation);
+ void setPreviewFpsRange(int minFPS,int maxFPS);
+#ifdef QCOM_LEGACY_CAM_PARAMS
+ void setPostviewSize(int x, int y);
+#endif
+ void getSupportedHfrSizes(Vector<Size> &sizes) const;
+#endif
+
private:
DefaultKeyedVector<String8,String8> mMap;
};
diff --git a/include/media/AudioParameter.h b/include/media/AudioParameter.h
index 891bc4b..bce7f21 100644
--- a/include/media/AudioParameter.h
+++ b/include/media/AudioParameter.h
@@ -1,4 +1,7 @@
/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
* Copyright (C) 2008-2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -48,6 +51,16 @@
static const char * const keyFrameCount;
static const char * const keyInputSource;
static const char * const keyScreenState;
+#ifdef QCOM_HARDWARE
+ static const char * const keyHandleFm;
+ static const char * const keyVoipCheck;
+ static const char * const keyFluenceType;
+ static const char * const keySSR;
+ static const char * const keyHandleA2dpDevice;
+ static const char * const keyADSPStatus;
+ static const char * const keyCanOpenProxy;
+ static const char * const keyFmVolume;
+#endif
String8 toString();
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index 052064d..e4cb560 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -210,8 +210,13 @@
audio_format_t format() const { return mFormat; }
uint32_t channelCount() const { return mChannelCount; }
size_t frameCount() const { return mFrameCount; }
+#ifdef QCOM_HARDWARE
+ size_t frameSize() const;
+ audio_source_t inputSource() const;
+#else
size_t frameSize() const { return mFrameSize; }
audio_source_t inputSource() const { return mInputSource; }
+#endif
/* After it's created the track is not active. Call start() to
* make it active. If set, the callback will start being called.
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 225ef76..cad455d 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -1,4 +1,6 @@
/*
+ * Copyright (c) 2012-2013, 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");
@@ -23,6 +25,9 @@
#include <system/audio_policy.h>
#include <utils/Errors.h>
#include <utils/Mutex.h>
+#ifdef QCOM_HARDWARE
+#include <media/AudioParameter.h>
+#endif
namespace android {
@@ -147,6 +152,9 @@
INPUT_CLOSED,
INPUT_CONFIG_CHANGED,
STREAM_CONFIG_CHANGED,
+#ifdef QCOM_HARDWARE
+ EFFECT_CONFIG_CHANGED,
+#endif
NUM_CONFIG_EVENTS
};
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 4736369..40a9f1f 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -1,4 +1,6 @@
/*
+ * Copyright (c) 2013, 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");
@@ -22,7 +24,10 @@
#include <media/AudioTimestamp.h>
#include <media/IAudioTrack.h>
#include <utils/threads.h>
-
+#ifdef QCOM_HARDWARE
+#include <media/IDirectTrack.h>
+#include <media/IDirectTrackClient.h>
+#endif
namespace android {
// ----------------------------------------------------------------------------
@@ -33,7 +38,12 @@
// ----------------------------------------------------------------------------
+#ifdef QCOM_HARDWARE
+class AudioTrack : public BnDirectTrackClient,
+ virtual public RefBase
+#else
class AudioTrack : public RefBase
+#endif
{
public:
enum channel_index {
@@ -66,6 +76,9 @@
EVENT_NEW_TIMESTAMP = 8, // Delivered periodically and when there's a significant change
// in the mapping from frame position to presentation time.
// See AudioTimestamp for the information included with event.
+#ifdef QCOM_HARDWARE
+ EVENT_HW_FAIL = 9, // ADSP failure.
+#endif
};
/* Client should declare Buffer on the stack and pass address to obtainBuffer()
@@ -218,9 +231,8 @@
/* Terminates the AudioTrack and unregisters it from AudioFlinger.
* Also destroys all resources associated with the AudioTrack.
*/
-protected:
+
virtual ~AudioTrack();
-public:
/* Initialize an AudioTrack that was created using the AudioTrack() constructor.
* Don't call set() more than once, or after the AudioTrack() constructors that take parameters.
@@ -264,7 +276,11 @@
* This includes the latency due to AudioTrack buffer size, AudioMixer (if any)
* and audio hardware driver.
*/
+#ifdef QCOM_HARDWARE
+ uint32_t latency() const;
+#else
uint32_t latency() const { return mLatency; }
+#endif
/* getters, see constructors and set() */
@@ -582,7 +598,11 @@
* consider implementing that at application level, based on the low resolution timestamps.
* Returns NO_ERROR if timestamp is valid.
*/
- status_t getTimestamp(AudioTimestamp& timestamp);
+ virtual status_t getTimestamp(AudioTimestamp& timestamp);
+#ifdef QCOM_HARDWARE
+ virtual void notify(int msg);
+ virtual status_t getTimeStamp(uint64_t *tstamp);
+#endif
protected:
/* copying audio tracks is not allowed */
@@ -653,6 +673,9 @@
bool isOffloaded() const
{ return (mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0; }
+#ifdef QCOM_HARDWARE
+ sp<IDirectTrack> mDirectTrack;
+#endif
// Next 3 fields may be changed if IAudioTrack is re-created, but always != 0
sp<IAudioTrack> mAudioTrack;
sp<IMemory> mCblkMemory;
@@ -720,11 +743,18 @@
uint32_t mUpdatePeriod; // in frames, zero means no EVENT_NEW_POS
audio_output_flags_t mFlags;
+#ifdef QCOM_HARDWARE
+ sp<IAudioFlinger> mAudioFlinger;
+ audio_io_handle_t mAudioDirectOutput;
+#endif
int mSessionId;
int mAuxEffectId;
mutable Mutex mLock;
+#ifdef QCOM_HARDWARE
+ void* mObserver;
+#endif
bool mIsTimed;
int mPreviousPriority; // before start()
SchedPolicy mPreviousSchedulingGroup;
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 899d79f..698b584 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -1,5 +1,7 @@
/*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (c) 2012-2013, 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.
@@ -24,6 +26,10 @@
#include <utils/RefBase.h>
#include <utils/Errors.h>
#include <binder/IInterface.h>
+#ifdef QCOM_HARDWARE
+#include <media/IDirectTrack.h>
+#include <media/IDirectTrackClient.h>
+#endif
#include <media/IAudioTrack.h>
#include <media/IAudioRecord.h>
#include <media/IAudioFlingerClient.h>
@@ -50,6 +56,9 @@
TRACK_TIMED = 1, // client requests a TimedAudioTrack
TRACK_FAST = 2, // client requests a fast AudioTrack or AudioRecord
TRACK_OFFLOAD = 4, // client requests offload to hw codec
+#ifdef QCOM_HARDWARE
+ TRACK_VOICE_COMMUNICATION = 8, //client uses voice communication
+#endif
};
typedef uint32_t track_flags_t;
@@ -77,6 +86,21 @@
int clientUid,
status_t *status) = 0;
+#ifdef QCOM_HARDWARE
+ /* create a direct audio track and registers it with AudioFlinger.
+ * return null if the track cannot be created.
+ */
+ virtual sp<IDirectTrack> createDirectTrack(
+ pid_t pid,
+ uint32_t sampleRate,
+ audio_channel_mask_t channelMask,
+ audio_io_handle_t output,
+ int *sessionId,
+ IDirectTrackClient* client,
+ audio_stream_type_t streamType,
+ status_t *status) = 0;
+#endif
+
virtual sp<IAudioRecord> openRecord(
audio_io_handle_t input,
uint32_t sampleRate,
diff --git a/include/media/IDirectTrack.h b/include/media/IDirectTrack.h
new file mode 100644
index 0000000..bfb29ec
--- /dev/null
+++ b/include/media/IDirectTrack.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2012, 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.
+ */
+
+#ifndef ANDROID_IDIRECTTRACK_H
+#define ANDROID_IDIRECTTRACK_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <binder/IInterface.h>
+#include <binder/IMemory.h>
+
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class IDirectTrack : public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(DirectTrack);
+
+ /* After it's created the track is not active. Call start() to
+ * make it active. If set, the callback will start being called.
+ */
+ virtual status_t start() = 0;
+
+ /* Stop a track. If set, the callback will cease being called and
+ * obtainBuffer will return an error. Buffers that are already released
+ * will be processed, unless flush() is called.
+ */
+ virtual void stop() = 0;
+
+ /* flush a stopped track. All pending buffers are discarded.
+ * This function has no effect if the track is not stoped.
+ */
+ virtual void flush() = 0;
+
+ /* mute or unmutes this track.
+ * While mutted, the callback, if set, is still called.
+ */
+ virtual void mute(bool) = 0;
+
+ /* Pause a track. If set, the callback will cease being called and
+ * obtainBuffer will return an error. Buffers that are already released
+ * will be processed, unless flush() is called.
+ */
+ virtual void pause() = 0;
+
+ /* set volume for both left and right channels.
+ */
+ virtual void setVolume(float l, float r) = 0;
+
+ virtual ssize_t write(const void*, size_t) = 0;
+
+ virtual int64_t getTimeStamp() = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnDirectTrack : public BnInterface<IDirectTrack>
+{
+public:
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IAUDIOTRACK_H
diff --git a/include/media/IDirectTrackClient.h b/include/media/IDirectTrackClient.h
new file mode 100644
index 0000000..703df35
--- /dev/null
+++ b/include/media/IDirectTrackClient.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012, 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.
+ */
+
+#ifndef ANDROID_IDIRECTTRACKCLIENT_H
+#define ANDROID_IDIRECTTRACKCLIENT_H
+
+#include <utils/RefBase.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+class IDirectTrackClient: public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(DirectTrackClient);
+
+ virtual void notify(int msg) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnDirectTrackClient: public BnInterface<IDirectTrackClient>
+{
+public:
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+}; // namespace android
+
+#endif // ANDROID_IDIRECTTRACKCLIENT_H
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index 26d8729..a1cbe07 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -1,4 +1,6 @@
/*
+ * Copyright (c) 2013, 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");
@@ -50,6 +52,7 @@
// 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,
};
@@ -78,8 +81,12 @@
CB_EVENT_FILL_BUFFER, // Request to write more data to buffer.
CB_EVENT_STREAM_END, // Sent after all the buffers queued in AF and HW are played
// back (after stop is called)
- CB_EVENT_TEAR_DOWN // The AudioTrack was invalidated due to use case change:
+ CB_EVENT_TEAR_DOWN, // The AudioTrack was invalidated due to use case change:
// Need to re-evaluate offloading options
+#ifdef QCOM_HARDWARE
+ CB_EVENT_UNDERRUN,
+ CB_EVENT_HW_FAIL
+#endif
};
// Callback returns the number of bytes actually written to the buffer.
@@ -95,6 +102,9 @@
virtual ssize_t channelCount() const = 0;
virtual ssize_t frameSize() const = 0;
virtual uint32_t latency() const = 0;
+#ifdef QCOM_HARDWARE
+ virtual audio_stream_type_t streamType() const {return AUDIO_STREAM_DEFAULT;}
+#endif
virtual float msecsPerFrame() const = 0;
virtual status_t getPosition(uint32_t *position) const = 0;
virtual status_t getFramesWritten(uint32_t *frameswritten) const = 0;
@@ -122,9 +132,13 @@
virtual status_t setPlaybackRatePermille(int32_t rate) { return INVALID_OPERATION; }
virtual bool needsTrailingPadding() { return true; }
-
virtual status_t setParameters(const String8& keyValuePairs) { return NO_ERROR; };
virtual String8 getParameters(const String8& keys) { return String8::empty(); };
+
+#ifdef QCOM_HARDWARE
+ virtual ssize_t sampleRate() const {return 0;};
+ virtual status_t getTimeStamp(uint64_t *tstamp) {return 0;};
+#endif
};
MediaPlayerBase() : mCookie(0), mNotify(0) {}
diff --git a/include/media/MediaProfiles.h b/include/media/MediaProfiles.h
index 9fc962c..ec3eb9b 100644
--- a/include/media/MediaProfiles.h
+++ b/include/media/MediaProfiles.h
@@ -32,8 +32,23 @@
CAMCORDER_QUALITY_480P = 4,
CAMCORDER_QUALITY_720P = 5,
CAMCORDER_QUALITY_1080P = 6,
+#ifdef QCOM_HARDWARE
CAMCORDER_QUALITY_QVGA = 7,
- CAMCORDER_QUALITY_LIST_END = 7,
+ CAMCORDER_QUALITY_FWVGA = 8,
+ CAMCORDER_QUALITY_WVGA = 9,
+ CAMCORDER_QUALITY_VGA = 10,
+ CAMCORDER_QUALITY_WQVGA = 11,
+ CAMCORDER_QUALITY_4kUHD = 12,
+ CAMCORDER_QUALITY_4kDCI = 13,
+ CAMCORDER_QUALITY_LIST_END = 13,
+#else
+ CAMCORDER_QUALITY_QVGA = 11,
+ CAMCORDER_QUALITY_FWVGA = 7,
+ CAMCORDER_QUALITY_WVGA = 8,
+ CAMCORDER_QUALITY_VGA = 9,
+ CAMCORDER_QUALITY_WQVGA = 10,
+ CAMCORDER_QUALITY_LIST_END = 11,
+#endif
CAMCORDER_QUALITY_TIME_LAPSE_LIST_START = 1000,
CAMCORDER_QUALITY_TIME_LAPSE_LOW = 1000,
@@ -44,7 +59,15 @@
CAMCORDER_QUALITY_TIME_LAPSE_720P = 1005,
CAMCORDER_QUALITY_TIME_LAPSE_1080P = 1006,
CAMCORDER_QUALITY_TIME_LAPSE_QVGA = 1007,
+#ifdef QCOM_HARDWARE
+ CAMCORDER_QUALITY_TIME_LAPSE_FWVGA = 1008,
+ CAMCORDER_QUALITY_TIME_LAPSE_WVGA = 1009,
+ CAMCORDER_QUALITY_TIME_LAPSE_VGA = 1010,
+ CAMCORDER_QUALITY_TIME_LAPSE_WQVGA = 1011,
+ CAMCORDER_QUALITY_TIME_LAPSE_LIST_END = 1011,
+#else
CAMCORDER_QUALITY_TIME_LAPSE_LIST_END = 1007,
+#endif
};
/**
@@ -456,6 +479,10 @@
static VideoEncoderCap* createDefaultH263VideoEncoderCap();
static VideoEncoderCap* createDefaultM4vVideoEncoderCap();
static AudioEncoderCap* createDefaultAmrNBEncoderCap();
+#ifdef QCOM_HARDWARE
+ static AudioEncoderCap* createDefaultAacEncoderCap();
+ static AudioEncoderCap* createDefaultLpcmEncoderCap();
+#endif
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 4c05fc3..24583ef 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -50,6 +50,9 @@
MEDIA_ERROR = 100,
MEDIA_INFO = 200,
MEDIA_SUBTITLE_DATA = 201,
+#ifdef QCOM_HARDWARE
+ MEDIA_QOE = 300,
+#endif
};
// Generic error codes for the media player framework. Errors are fatal, the
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
index 88a42a0..24dfa0f 100644
--- a/include/media/mediarecorder.h
+++ b/include/media/mediarecorder.h
@@ -67,6 +67,11 @@
/* H.264/AAC data encapsulated in MPEG2/TS */
OUTPUT_FORMAT_MPEG2TS = 8,
+#ifdef QCOM_HARDWARE
+ OUTPUT_FORMAT_QCP = 9, // QCP file format
+ OUTPUT_FORMAT_THREE_GPP2 = 10, /*3GPP2*/
+ OUTPUT_FORMAT_WAVE = 11, /*WAVE*/
+#endif
OUTPUT_FORMAT_LIST_END // must be last - used to validate format type
};
@@ -77,7 +82,11 @@
AUDIO_ENCODER_AAC = 3,
AUDIO_ENCODER_HE_AAC = 4,
AUDIO_ENCODER_AAC_ELD = 5,
-
+#ifdef QCOM_HARDWARE
+ AUDIO_ENCODER_EVRC = 6,
+ AUDIO_ENCODER_QCELP = 7,
+ AUDIO_ENCODER_LPCM = 8,
+#endif
AUDIO_ENCODER_LIST_END // must be the last - used to validate the audio encoder type
};
@@ -118,6 +127,9 @@
MEDIA_RECORDER_EVENT_LIST_START = 1,
MEDIA_RECORDER_EVENT_ERROR = 1,
MEDIA_RECORDER_EVENT_INFO = 2,
+#ifdef QCOM_HARDWARE
+ MEDIA_RECORDER_MSG_COMPRESSED_IMAGE = 8, // mzhu: TODO, where to put this?
+#endif
MEDIA_RECORDER_EVENT_LIST_END = 99,
// Track related event types
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index bf3a998..18a3100 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -200,6 +200,9 @@
bool mChannelMaskPresent;
int32_t mChannelMask;
+#ifdef QCOM_HARDWARE
+ bool mInSmoothStreamingMode;
+#endif
unsigned mDequeueCounter;
bool mStoreMetaDataInOutputBuffers;
int32_t mMetaDataBuffersToSubmit;
@@ -219,6 +222,9 @@
status_t submitOutputMetaDataBuffer();
void signalSubmitOutputMetaDataBufferIfEOS_workaround();
status_t allocateOutputBuffersFromNativeWindow();
+#ifdef USE_SAMSUNG_COLORFORMAT
+ void setNativeWindowColorFormat(OMX_COLOR_FORMATTYPE &eNativeColorFormat);
+#endif
status_t cancelBufferToNativeWindow(BufferInfo *info);
status_t freeOutputBuffersNotOwnedByComponent();
BufferInfo *dequeueBufferFromNativeWindow();
diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h
index 14afb85..f1249bb 100644
--- a/include/media/stagefright/AudioPlayer.h
+++ b/include/media/stagefright/AudioPlayer.h
@@ -1,4 +1,6 @@
/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -51,27 +53,27 @@
virtual ~AudioPlayer();
// Caller retains ownership of "source".
- void setSource(const sp<MediaSource> &source);
+ virtual void setSource(const sp<MediaSource> &source);
// Return time in us.
virtual int64_t getRealTimeUs();
- status_t start(bool sourceAlreadyStarted = false);
+ virtual status_t start(bool sourceAlreadyStarted = false);
- void pause(bool playPendingSamples = false);
- status_t resume();
+ virtual void pause(bool playPendingSamples = false);
+ virtual status_t resume();
// Returns the timestamp of the last buffer played (in us).
- int64_t getMediaTimeUs();
+ virtual int64_t getMediaTimeUs();
// Returns true iff a mapping is established, i.e. the AudioPlayer
// has played at least one frame of audio.
- bool getMediaTimeMapping(int64_t *realtime_us, int64_t *mediatime_us);
+ virtual bool getMediaTimeMapping(int64_t *realtime_us, int64_t *mediatime_us);
- status_t seekTo(int64_t time_us);
+ virtual status_t seekTo(int64_t time_us);
- bool isSeeking();
- bool reachedEOS(status_t *finalStatus);
+ virtual bool isSeeking();
+ virtual bool reachedEOS(status_t *finalStatus);
status_t setPlaybackRatePermille(int32_t ratePermille);
@@ -101,6 +103,9 @@
int64_t mSeekTimeUs;
bool mStarted;
+#ifdef QCOM_HARDWARE
+ bool mSourcePaused;
+#endif
bool mIsFirstBuffer;
status_t mFirstBufferResult;
diff --git a/include/media/stagefright/AudioSource.h b/include/media/stagefright/AudioSource.h
index 4c9aaad..3b79d0a 100644
--- a/include/media/stagefright/AudioSource.h
+++ b/include/media/stagefright/AudioSource.h
@@ -23,7 +23,7 @@
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MediaBuffer.h>
#include <utils/List.h>
-
+#include <utils/String8.h>
#include <system/audio.h>
namespace android {
@@ -85,6 +85,7 @@
int64_t mInitialReadTimeUs;
int64_t mNumFramesReceived;
int64_t mNumClientOwnedBuffers;
+ int64_t mAutoRampStartUs;
List<MediaBuffer * > mBuffersReceived;
@@ -103,6 +104,16 @@
AudioSource(const AudioSource &);
AudioSource &operator=(const AudioSource &);
+#ifdef QCOM_HARDWARE
+public:
+ AudioSource(
+ audio_source_t inputSource, const sp<MetaData>& meta );
+private:
+ audio_format_t mFormat;
+ String8 mMime;
+ int32_t mMaxBufferSize;
+ int64_t bufferDurationUs( ssize_t n );
+#endif
};
} // namespace android
diff --git a/include/media/stagefright/ExtendedCodec.h b/include/media/stagefright/ExtendedCodec.h
new file mode 100644
index 0000000..eeb31d6
--- /dev/null
+++ b/include/media/stagefright/ExtendedCodec.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef EXTENDED_CODEC_H_
+#define EXTENDED_CODEC_H_
+
+#include <android/native_window.h>
+#include <media/IOMX.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/AString.h>
+#include <utils/threads.h>
+
+#include <OMX_Audio.h>
+
+namespace android {
+
+struct MediaCodecList;
+struct OMXCodec;
+
+enum{
+ kRequiresWMAProComponent = 0x40000000,
+};
+
+
+struct ExtendedCodec {
+
+ enum {
+ kPortIndexInput = 0,
+ kPortIndexOutput = 1
+ };
+ static status_t convertMetaDataToMessage(
+ const sp<MetaData> &meta, sp<AMessage> *format);
+
+ static uint32_t getComponentQuirks (
+ const MediaCodecList *list, size_t index);
+
+ static status_t setAudioFormat(
+ const sp<MetaData> &meta, const char* mime,
+ sp<IOMX> OMXhandle,IOMX::node_id nodeID,
+ bool isEncoder);
+
+ static status_t setAudioFormat(
+ const sp<AMessage> &msg, const char* mime,
+ sp<IOMX> OMXhandle,IOMX::node_id nodeID,
+ bool isEncoder);
+
+ static status_t setVideoInputFormat(
+ const char *mime,
+ OMX_VIDEO_CODINGTYPE *compressionFormat);
+
+ static status_t setVideoOutputFormat(
+ const char *mime,
+ OMX_VIDEO_CODINGTYPE *compressionFormat);
+
+ static status_t getSupportedAudioFormatInfo(
+ const AString* mime,
+ sp<IOMX> OMXhandle,
+ IOMX::node_id nodeID,
+ int portIndex,
+ int* channelCount);
+
+ static status_t handleSupportedAudioFormats(
+ int format, AString* mime);
+
+ static const char* overrideComponentName(
+ uint32_t quirks, const sp<MetaData> &meta);
+
+ static void overrideComponentName(
+ uint32_t quirks, const sp<AMessage> &msg,
+ AString* componentName);
+
+ static void getRawCodecSpecificData(
+ const sp<MetaData> &meta,
+ const void* &data,
+ size_t& size);
+
+ static sp<ABuffer> getRawCodecSpecificData(
+ const sp<AMessage> &msg);
+
+ static void getAacCodecSpecificData(
+ const sp<MetaData> &meta,
+ const void* &data,
+ size_t& size);
+
+ static sp<ABuffer> getAacCodecSpecificData(
+ const sp<AMessage> &msg);
+
+ static status_t setSupportedRole(
+ const sp<IOMX> &omx, IOMX::node_id node,
+ bool isEncoder, const char *mime);
+
+ static void configureFramePackingFormat(
+ const sp<AMessage> &msg, sp<IOMX> OMXhandle,
+ IOMX::node_id nodeID, const char* componentName);
+
+ static void configureFramePackingFormat(
+ const sp<MetaData> &meta, sp<IOMX> OMXhandle,
+ IOMX::node_id nodeID, const char* componentName);
+
+ static void configureVideoDecoder(
+ const sp<MetaData> &meta, const char* mime,
+ sp<IOMX> OMXhandle, const uint32_t flags,
+ IOMX::node_id nodeID, const char* componentName);
+
+ static void configureVideoDecoder(
+ const sp<AMessage> &msg, const char* mime,
+ sp<IOMX> OMXhandle, const uint32_t flags,
+ IOMX::node_id nodeID, const char* componentName);
+
+ static void enableSmoothStreaming(
+ const sp<IOMX> &omx, IOMX::node_id nodeID, bool* isEnabled,
+ const char* componentName);
+
+ static bool useHWAACDecoder(const char *mime);
+
+private:
+ static const char* getMsgKey(int key );
+
+ static status_t setWMAFormat(
+ const sp<MetaData> &meta, sp<IOMX> OMXhandle,
+ IOMX::node_id nodeID, bool isEncoder );
+
+ static status_t setWMAFormat(
+ const sp<AMessage> &msg, sp<IOMX> OMXhandle,
+ IOMX::node_id nodeID, bool isEncoder );
+
+ static void setEVRCFormat(
+ int32_t numChannels, int32_t sampleRate,
+ sp<IOMX> OMXhandle, IOMX::node_id nodeID,
+ bool isEncoder );
+
+ static void setQCELPFormat(
+ int32_t numChannels, int32_t sampleRate,
+ sp<IOMX> OMXhandle, IOMX::node_id nodeID,
+ bool isEncoder );
+
+ static void setAC3Format(
+ int32_t numChannels, int32_t sampleRate,
+ sp<IOMX> OMXhandle, IOMX::node_id nodeID);
+
+ static status_t setDIVXFormat(
+ const sp<AMessage> &msg, const char* mime,
+ sp<IOMX> OMXhandle,IOMX::node_id nodeID, int port_index);
+
+};
+
+}
+#endif /*EXTENDED_CODEC_H_ */
+
diff --git a/include/media/stagefright/ExtendedWriter.h b/include/media/stagefright/ExtendedWriter.h
new file mode 100644
index 0000000..c56239f
--- /dev/null
+++ b/include/media/stagefright/ExtendedWriter.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2012 - 2013, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution
+ *
+ * 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 EXTENDED_WRITER_H_
+
+#define EXTENDED_WRITER_H_
+
+#include <stdio.h>
+
+#include <media/stagefright/MediaWriter.h>
+#include <utils/threads.h>
+#include <cutils/log.h>
+
+#define LITERAL_TO_STRING_INTERNAL(x) #x
+#define LITERAL_TO_STRING(x) LITERAL_TO_STRING_INTERNAL(x)
+
+#define CHECK_EQ(x,y) \
+ LOG_ALWAYS_FATAL_IF( \
+ (x) != (y), \
+ __FILE__ ":" LITERAL_TO_STRING(__LINE__) " " #x " != " #y)
+
+#define CHECK(x) \
+ LOG_ALWAYS_FATAL_IF( \
+ !(x), \
+ __FILE__ ":" LITERAL_TO_STRING(__LINE__) " " #x)
+
+namespace android {
+
+struct MediaSource;
+struct MetaData;
+
+struct ExtendedWriter : public MediaWriter {
+ ExtendedWriter(const char *filename);
+ ExtendedWriter(int fd);
+
+ status_t initCheck() const;
+
+ virtual status_t addSource(const sp<MediaSource> &source);
+ virtual bool reachedEOS();
+ virtual status_t start(MetaData *params = NULL);
+ virtual status_t stop();
+ virtual status_t pause();
+
+protected:
+ virtual ~ExtendedWriter();
+
+private:
+ FILE *mFile;
+ status_t mInitCheck;
+ sp<MediaSource> mSource;
+ bool mStarted;
+ volatile bool mPaused;
+ volatile bool mResumed;
+ volatile bool mDone;
+ volatile bool mReachedEOS;
+ pthread_t mThread;
+ int64_t mEstimatedSizeBytes;
+ int64_t mEstimatedDurationUs;
+
+ int32_t mFormat;
+
+ //QCP/EVRC header
+ struct QCPEVRCHeader
+ {
+ /* RIFF Section */
+ char riff[4];
+ unsigned int s_riff;
+ char qlcm[4];
+
+ /* Format chunk */
+ char fmt[4];
+ unsigned int s_fmt;
+ char mjr;
+ char mnr;
+ unsigned int data1;
+
+ /* UNIQUE ID of the codec */
+ unsigned short data2;
+ unsigned short data3;
+ char data4[8];
+ unsigned short ver;
+
+ /* Codec Info */
+ char name[80];
+ unsigned short abps;
+
+ /* average bits per sec of the codec */
+ unsigned short bytes_per_pkt;
+ unsigned short samp_per_block;
+ unsigned short samp_per_sec;
+ unsigned short bits_per_samp;
+ unsigned char vr_num_of_rates;
+
+ /* Rate Header fmt info */
+ unsigned char rvd1[3];
+ unsigned short vr_bytes_per_pkt[8];
+ unsigned int rvd2[5];
+
+ /* Vrat chunk */
+ unsigned char vrat[4];
+ unsigned int s_vrat;
+ unsigned int v_rate;
+ unsigned int size_in_pkts;
+
+ /* Data chunk */
+ unsigned char data[4];
+ unsigned int s_data;
+ } __attribute__ ((packed));
+
+ struct QCPEVRCHeader mHeader;
+ off_t mOffset; //note off_t
+
+ static void *ThreadWrapper(void *);
+ status_t threadFunc();
+ bool exceedsFileSizeLimit();
+ bool exceedsFileDurationLimit();
+
+ ExtendedWriter(const ExtendedWriter &);
+ ExtendedWriter &operator=(const ExtendedWriter &);
+
+ status_t writeQCPHeader( );
+ status_t writeEVRCHeader( );
+};
+
+} // namespace android
+
+#endif // AMR_WRITER_H_
diff --git a/include/media/stagefright/LPAPlayer.h b/include/media/stagefright/LPAPlayer.h
new file mode 100644
index 0000000..a2ae966
--- /dev/null
+++ b/include/media/stagefright/LPAPlayer.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ * 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.
+ */
+
+#ifndef LPA_PLAYER_H_
+
+#define LPA_PLAYER_H_
+
+#include "AudioPlayer.h"
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Vector.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <include/TimedEventQueue.h>
+
+// Pause timeout = 3sec
+#define LPA_PAUSE_TIMEOUT_USEC 3000000
+
+namespace android {
+
+class LPAPlayer : public AudioPlayer {
+public:
+ enum {
+ REACHED_EOS,
+ SEEK_COMPLETE
+ };
+
+ enum {
+ TRACK_DIRECT,
+ TRACK_REGULAR,
+ TRACK_NONE
+ };
+
+ LPAPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink, bool &initCheck,
+ AwesomePlayer *audioObserver = NULL);
+
+ virtual ~LPAPlayer();
+
+ // Caller retains ownership of "source".
+ virtual void setSource(const sp<MediaSource> &source);
+
+ // Return time in us.
+ virtual int64_t getRealTimeUs();
+
+ virtual status_t start(bool sourceAlreadyStarted = false);
+
+ virtual void pause(bool playPendingSamples = false);
+ virtual status_t resume();
+
+ // Returns the timestamp of the last buffer played (in us).
+ virtual int64_t getMediaTimeUs();
+
+ // Returns true iff a mapping is established, i.e. the LPAPlayer
+ // has played at least one frame of audio.
+ virtual bool getMediaTimeMapping(int64_t *realtime_us, int64_t *mediatime_us);
+
+ virtual status_t seekTo(int64_t time_us);
+
+ virtual bool isSeeking();
+ virtual bool reachedEOS(status_t *finalStatus);
+
+ static int mObjectsAlive;
+private:
+ int64_t mPositionTimeMediaUs;
+ int64_t mPositionTimeRealUs;
+ bool mInternalSeeking;
+ bool mIsAudioRouted;
+ bool mStarted;
+ bool mPaused;
+ int32_t mChannelMask;
+ int32_t mNumOutputChannels;
+ int32_t mNumInputChannels;
+ int32_t mSampleRate;
+ int64_t mLatencyUs;
+ size_t mFrameSize;
+ int64_t mTimeStarted;
+ int64_t mTimePlayed;
+ int64_t mNumFramesPlayed;
+ int64_t mNumFramesPlayedSysTimeUs;
+
+ pthread_t mDecoderThread;
+
+ //Kill Thread boolean
+ bool mKillDecoderThread;
+
+ //Thread alive boolean
+ bool mDecoderThreadAlive;
+
+ //Declare the condition Variables and Mutex
+
+ Mutex mDecoderMutex;
+
+ Condition mDecoderCv;
+
+ // make sure Decoder thread has exited
+ void requestAndWaitForDecoderThreadExit_l();
+
+ static void *decoderThreadWrapper(void *me);
+ void decoderThreadEntry();
+
+ void createThreads();
+
+ void onPauseTimeOut();
+
+ sp<MediaSource> mSource;
+
+ MediaBuffer *mInputBuffer;
+
+ Mutex mLock;
+
+ bool mSeeking;
+ bool mReachedEOS;
+ bool mReachedOutputEOS;
+ status_t mFinalStatus;
+ int64_t mSeekTimeUs;
+ int64_t mPauseTime;
+
+
+ bool mIsFirstBuffer;
+ status_t mFirstBufferResult;
+ MediaBuffer *mFirstBuffer;
+ TimedEventQueue mQueue;
+ bool mQueueStarted;
+ sp<TimedEventQueue::Event> mPauseEvent;
+ bool mPauseEventPending;
+
+ sp<MediaPlayerBase::AudioSink> mAudioSink;
+ AwesomePlayer *mObserver;
+ int mTrackType;
+
+ static size_t AudioSinkCallback(
+ MediaPlayerBase::AudioSink *audioSink,
+ void *data, size_t size, void *me,
+ MediaPlayerBase::AudioSink::cb_event_t event);
+
+ int64_t getTimeStamp();
+
+ size_t fillBuffer(void *data, size_t size);
+
+ int64_t getRealTimeUsLocked();
+
+ void reset();
+
+ status_t setupAudioSink();
+ static size_t AudioCallback(
+ MediaPlayerBase::AudioSink *audioSink,
+ void *buffer, size_t size, void *cookie);
+ size_t AudioCallback(void *cookie, void *data, size_t size);
+ int64_t getMediaTimeUs_l();
+ bool seekTooClose(int64_t);
+
+ void convertMonoToStereo(int16_t *data, size_t size);
+
+ LPAPlayer(const LPAPlayer &);
+ LPAPlayer &operator=(const LPAPlayer &);
+};
+
+struct TimedEvent : public TimedEventQueue::Event {
+ TimedEvent(LPAPlayer *player,
+ void (LPAPlayer::*method)())
+ : mPlayer(player),
+ mMethod(method) {
+ }
+
+protected:
+ virtual ~TimedEvent() {}
+
+ virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
+ (mPlayer->*mMethod)();
+ }
+
+private:
+ LPAPlayer *mPlayer;
+ void (LPAPlayer::*mMethod)();
+
+ TimedEvent(const TimedEvent &);
+ TimedEvent &operator=(const TimedEvent &);
+};
+
+} // namespace android
+
+#endif // LPA_PLAYER_H_
+
diff --git a/include/media/stagefright/LPAPlayerLegacy.h b/include/media/stagefright/LPAPlayerLegacy.h
new file mode 100755
index 0000000..cca3bd4
--- /dev/null
+++ b/include/media/stagefright/LPAPlayerLegacy.h
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * 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 LPA_PLAYER_H_
+
+#define LPA_PLAYER_H_
+
+#include "AudioPlayer.h"
+#include <media/IAudioFlinger.h>
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Vector.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <binder/IServiceManager.h>
+#include <linux/unistd.h>
+#include <include/TimedEventQueue.h>
+#include <binder/BinderService.h>
+#include <binder/MemoryDealer.h>
+#include <powermanager/IPowerManager.h>
+
+// Pause timeout = 3sec
+#define LPA_PAUSE_TIMEOUT_USEC 3000000
+
+namespace android {
+
+class LPAPlayer : public AudioPlayer {
+public:
+ enum {
+ REACHED_EOS,
+ SEEK_COMPLETE
+ };
+
+ enum {
+ TRACK_DIRECT,
+ TRACK_REGULAR,
+ TRACK_NONE
+ };
+
+ LPAPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink, bool &initCheck,
+ AwesomePlayer *audioObserver = NULL);
+
+ virtual ~LPAPlayer();
+
+ // Caller retains ownership of "source".
+ virtual void setSource(const sp<MediaSource> &source);
+
+ // Return time in us.
+ virtual int64_t getRealTimeUs();
+
+ virtual status_t start(bool sourceAlreadyStarted = false);
+
+ virtual void pause(bool playPendingSamples = false);
+ virtual status_t resume();
+
+ // Returns the timestamp of the last buffer played (in us).
+ virtual int64_t getMediaTimeUs();
+
+ // Returns true iff a mapping is established, i.e. the LPAPlayer
+ // has played at least one frame of audio.
+ virtual bool getMediaTimeMapping(int64_t *realtime_us, int64_t *mediatime_us);
+
+ virtual status_t seekTo(int64_t time_us);
+
+ virtual bool isSeeking();
+ virtual bool reachedEOS(status_t *finalStatus);
+
+ static int mObjectsAlive;
+ static bool mLpaInProgress;
+private:
+ int64_t mPositionTimeMediaUs;
+ int64_t mPositionTimeRealUs;
+ bool mInternalSeeking;
+ bool mIsAudioRouted;
+ bool mStarted;
+ bool mPaused;
+ bool mA2DPEnabled;
+ int32_t mChannelMask;
+ int32_t numChannels;
+ int32_t mNumOutputChannels;
+ int32_t mNumInputChannels;
+ int32_t mSampleRate;
+ int64_t mLatencyUs;
+ size_t mFrameSize;
+ int64_t mTimeStarted;
+ int64_t mTimePlayed;
+ int64_t mNumFramesPlayed;
+ int64_t mNumFramesPlayedSysTimeUs;
+ int64_t mNumA2DPBytesPlayed;
+
+ void clearPowerManager();
+
+ class PMDeathRecipient : public IBinder::DeathRecipient {
+ public:
+ PMDeathRecipient(void *obj){parentClass = (LPAPlayer *)obj;}
+ virtual ~PMDeathRecipient() {}
+
+ // IBinder::DeathRecipient
+ virtual void binderDied(const wp<IBinder>& who);
+
+ private:
+ LPAPlayer *parentClass;
+ PMDeathRecipient(const PMDeathRecipient&);
+ PMDeathRecipient& operator = (const PMDeathRecipient&);
+
+ friend class LPAPlayer;
+ };
+
+ friend class PMDeathRecipient;
+
+ void acquireWakeLock();
+ void releaseWakeLock();
+
+ sp<IPowerManager> mPowerManager;
+ sp<IBinder> mWakeLockToken;
+ sp<PMDeathRecipient> mDeathRecipient;
+
+ pthread_t decoderThread;
+
+ pthread_t A2DPNotificationThread;
+
+ //Kill Thread boolean
+ bool killDecoderThread;
+
+
+
+ bool killA2DPNotificationThread;
+
+ //Thread alive boolean
+ bool decoderThreadAlive;
+
+
+ bool a2dpNotificationThreadAlive;
+
+ //Declare the condition Variables and Mutex
+
+ pthread_mutex_t decoder_mutex;
+
+ pthread_mutex_t audio_sink_setup_mutex;
+
+ pthread_mutex_t a2dp_notification_mutex;
+
+
+
+ pthread_cond_t decoder_cv;
+
+
+ pthread_cond_t a2dp_notification_cv;
+
+
+ // make sure Decoder thread has exited
+ void requestAndWaitForDecoderThreadExit();
+
+
+ // make sure the Effects thread also exited
+ void requestAndWaitForA2DPNotificationThreadExit();
+
+ static void *decoderThreadWrapper(void *me);
+ void decoderThreadEntry();
+ static void *A2DPNotificationThreadWrapper(void *me);
+ void A2DPNotificationThreadEntry();
+
+ void createThreads();
+
+ volatile bool mIsA2DPEnabled;
+
+ //Structure to recieve the BT notification from the flinger.
+ class AudioFlingerLPAdecodeClient: public IBinder::DeathRecipient, public BnAudioFlingerClient {
+ public:
+ AudioFlingerLPAdecodeClient(void *obj);
+
+ LPAPlayer *pBaseClass;
+ // DeathRecipient
+ virtual void binderDied(const wp<IBinder>& who);
+
+ // IAudioFlingerClient
+
+ // indicate a change in the configuration of an output or input: keeps the cached
+ // values for output/input parameters upto date in client process
+ virtual void ioConfigChanged(int event, audio_io_handle_t ioHandle, const void *param2);
+
+ friend class LPAPlayer;
+ };
+
+ sp<IAudioFlinger> mAudioFlinger;
+
+ // helper function to obtain AudioFlinger service handle
+ void getAudioFlinger();
+
+ void handleA2DPSwitch();
+ void onPauseTimeOut();
+
+ int64_t getMediaTimeUs_l();
+ bool seekTooClose(int64_t);
+
+ sp<AudioFlingerLPAdecodeClient> AudioFlingerClient;
+ friend class AudioFlingerLPAdecodeClient;
+ Mutex AudioFlingerLock;
+ sp<MediaSource> mSource;
+
+ MediaBuffer *mInputBuffer;
+
+ Mutex mLock;
+ Mutex mResumeLock;
+
+ bool mSeeking;
+ bool mReachedEOS;
+ bool mReachedOutputEOS;
+ status_t mFinalStatus;
+ int64_t mSeekTimeUs;
+ int64_t mPauseTime;
+
+
+ bool mIsFirstBuffer;
+ status_t mFirstBufferResult;
+ MediaBuffer *mFirstBuffer;
+ TimedEventQueue mQueue;
+ bool mQueueStarted;
+ sp<TimedEventQueue::Event> mPauseEvent;
+ bool mPauseEventPending;
+
+ sp<MediaPlayerBase::AudioSink> mAudioSink;
+ AwesomePlayer *mObserver;
+ int mTrackType;
+
+ static size_t AudioSinkCallback(
+ MediaPlayerBase::AudioSink *audioSink,
+ void *data, size_t size, void *me,
+ MediaPlayerBase::AudioSink::cb_event_t event);
+
+ enum A2DPState {
+ A2DP_ENABLED,
+ A2DP_DISABLED,
+ A2DP_CONNECT,
+ A2DP_DISCONNECT
+ };
+
+ int64_t getTimeStamp(A2DPState state);
+
+ size_t fillBuffer(void *data, size_t size);
+
+ int64_t getRealTimeUsLocked();
+
+ void reset();
+
+ status_t setupAudioSink();
+ static size_t AudioCallback(
+ MediaPlayerBase::AudioSink *audioSink,
+ void *buffer, size_t size, void *cookie);
+ size_t AudioCallback(void *cookie, void *data, size_t size);
+
+ void convertMonoToStereo(int16_t *data, size_t size);
+
+ LPAPlayer(const LPAPlayer &);
+ LPAPlayer &operator=(const LPAPlayer &);
+};
+
+struct TimedEvent : public TimedEventQueue::Event {
+ TimedEvent(LPAPlayer *player,
+ void (LPAPlayer::*method)())
+ : mPlayer(player),
+ mMethod(method) {
+ }
+
+protected:
+ virtual ~TimedEvent() {}
+
+ virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
+ (mPlayer->*mMethod)();
+ }
+
+private:
+ LPAPlayer *mPlayer;
+ void (LPAPlayer::*mMethod)();
+
+ TimedEvent(const TimedEvent &);
+ TimedEvent &operator=(const TimedEvent &);
+};
+
+} // namespace android
+
+#endif // LPA_PLAYER_H_
+
diff --git a/include/media/stagefright/MediaCodecList.h b/include/media/stagefright/MediaCodecList.h
index 590623b..947f123 100644
--- a/include/media/stagefright/MediaCodecList.h
+++ b/include/media/stagefright/MediaCodecList.h
@@ -100,6 +100,8 @@
status_t addTypeFromAttributes(const char **attrs);
void addType(const char *name);
+ friend class ExtendedUtils;
+
DISALLOW_EVIL_CONSTRUCTORS(MediaCodecList);
};
diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h
index 85693d4..170e587 100644
--- a/include/media/stagefright/MediaDefs.h
+++ b/include/media/stagefright/MediaDefs.h
@@ -32,6 +32,9 @@
extern const char *MEDIA_MIMETYPE_AUDIO_AMR_NB;
extern const char *MEDIA_MIMETYPE_AUDIO_AMR_WB;
+#ifdef QCOM_HARDWARE
+extern const char *MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS;
+#endif
extern const char *MEDIA_MIMETYPE_AUDIO_MPEG; // layer III
extern const char *MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I;
extern const char *MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II;
diff --git a/include/media/stagefright/MediaExtractor.h b/include/media/stagefright/MediaExtractor.h
index 3076a96..ec3de50 100644
--- a/include/media/stagefright/MediaExtractor.h
+++ b/include/media/stagefright/MediaExtractor.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2009 The Android Open Source Project
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -49,6 +50,7 @@
CAN_SEEK_FORWARD = 2, // the "seek 10secs forward button"
CAN_PAUSE = 4,
CAN_SEEK = 8, // the "seek bar"
+ CAN_SEEK_TO_ZERO = 16, // the "previous button"
};
// If subclasses do _not_ override this, the default is
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 3a87474..c289439 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -1,6 +1,9 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ *
* 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
@@ -162,6 +165,9 @@
kKeyCryptoDefaultIVSize = 'cryS', // int32_t
kKeyPssh = 'pssh', // raw data
+#ifdef QCOM_HARDWARE
+ kKeyTunnelException = 'Ntnl', // not tunnel
+#endif
};
enum {
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index daaf20f..1247356 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -100,6 +100,13 @@
kSupportsMultipleFramesPerInputBuffer = 1024,
kRequiresLargerEncoderOutputBuffer = 2048,
kOutputBuffersAreUnreadable = 4096,
+#if defined(OMAP_ENHANCEMENT)
+ kAvoidMemcopyInputRecordingFrames = 0x20000000,
+#endif
+#ifdef QCOM_HARDWARE
+ kRequiresGlobalFlush = 0x20000000, // 2^29
+ kRequiresWMAProComponent = 0x40000000, //2^30
+#endif
};
struct CodecNameAndQuirks {
@@ -139,10 +146,18 @@
EXECUTING_TO_IDLE,
IDLE_TO_LOADED,
RECONFIGURING,
+#ifdef QCOM_HARDWARE
+ PAUSING,
+ FLUSHING,
+ PAUSED,
+#endif
ERROR
};
enum {
+#ifdef QCOM_HARDWARE
+ kPortIndexBoth = -1,
+#endif
kPortIndexInput = 0,
kPortIndexOutput = 1
};
@@ -255,7 +270,7 @@
OMX_VIDEO_CODINGTYPE compressionFormat,
OMX_COLOR_FORMATTYPE colorFormat);
- void setVideoInputFormat(
+ status_t setVideoInputFormat(
const char *mime, const sp<MetaData>& meta);
status_t setupBitRate(int32_t bitRate);
@@ -291,6 +306,9 @@
status_t allocateBuffers();
status_t allocateBuffersOnPort(OMX_U32 portIndex);
+#ifdef USE_SAMSUNG_COLORFORMAT
+ void setNativeWindowColorFormat(OMX_COLOR_FORMATTYPE &eNativeColorFormat);
+#endif
status_t allocateOutputBuffersFromNativeWindow();
status_t queueBufferToNativeWindow(BufferInfo *info);
@@ -344,6 +362,9 @@
void dumpPortStatus(OMX_U32 portIndex);
status_t configureCodec(const sp<MetaData> &meta);
+#if defined(OMAP_ENHANCEMENT)
+ void restorePatchedDataPointer(BufferInfo *info);
+#endif
status_t applyRotation();
status_t waitForBufferFilled_l();
@@ -358,6 +379,11 @@
OMXCodec(const OMXCodec &);
OMXCodec &operator=(const OMXCodec &);
+
+#ifdef QCOM_HARDWARE
+ int32_t mNumBFrames;
+ bool mInSmoothStreamingMode;
+#endif
};
struct CodecCapabilities {
diff --git a/include/media/stagefright/TunnelPlayer.h b/include/media/stagefright/TunnelPlayer.h
new file mode 100644
index 0000000..bec2485
--- /dev/null
+++ b/include/media/stagefright/TunnelPlayer.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ * 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.
+ */
+
+#ifndef TUNNEL_PLAYER_H_
+
+#define TUNNEL_PLAYER_H_
+
+#include "AudioPlayer.h"
+#include <utils/threads.h>
+#include <utils/List.h>
+#include <utils/Vector.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <include/TimedEventQueue.h>
+
+// Pause timeout = 3sec
+#define TUNNEL_PAUSE_TIMEOUT_USEC 3000000
+namespace android {
+
+class TunnelPlayer : public AudioPlayer {
+public:
+ enum {
+ REACHED_EOS,
+ SEEK_COMPLETE
+ };
+
+ TunnelPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink, bool &initCheck,
+ AwesomePlayer *audioObserver = NULL, bool hasVideo = false);
+
+ virtual ~TunnelPlayer();
+
+ // Caller retains ownership of "source".
+ virtual void setSource(const sp<MediaSource> &source);
+
+ // Return time in us.
+ virtual int64_t getRealTimeUs();
+
+ virtual status_t start(bool sourceAlreadyStarted = false);
+
+ virtual void pause(bool playPendingSamples = false);
+ virtual status_t resume();
+
+ // Returns the timestamp of the last buffer played (in us).
+ virtual int64_t getMediaTimeUs();
+
+ // Returns true iff a mapping is established, i.e. the TunnelPlayer
+ // has played at least one frame of audio.
+ virtual bool getMediaTimeMapping(int64_t *realtime_us, int64_t *mediatime_us);
+
+ virtual status_t seekTo(int64_t time_us);
+
+ virtual bool isSeeking();
+ virtual bool reachedEOS(status_t *finalStatus);
+
+
+ static int mTunnelObjectsAlive;
+ static const int getTunnelObjectsAliveMax();
+private:
+ int64_t mPositionTimeMediaUs;
+ int64_t mPositionTimeRealUs;
+ bool mInternalSeeking;
+ bool mIsAudioRouted;
+ bool mStarted;
+ bool mPaused;
+ int32_t mChannelMask;
+ int32_t numChannels;
+ int32_t mSampleRate;
+ int64_t mLatencyUs;
+ size_t mFrameSize;
+ int64_t mNumFramesPlayed;
+ int64_t mNumFramesPlayedSysTimeUs;
+ audio_format_t mFormat;
+ bool mHasVideo;
+
+ pthread_t mExtractorThread;
+
+ //Kill Thread boolean
+ bool mKillExtractorThread;
+
+ //Thread alive boolean
+ bool mExtractorThreadAlive;
+
+ //Declare the condition Variables and Mutex
+ Mutex mExtractorMutex;
+ Condition mExtractorCv;
+
+
+ // make sure Decoder thread has exited
+ void requestAndWaitForExtractorThreadExit_l();
+
+
+ static void *extractorThreadWrapper(void *me);
+ void extractorThreadEntry();
+
+ void createThreads();
+
+ void onPauseTimeOut();
+
+ sp<MediaSource> mSource;
+
+ MediaBuffer *mInputBuffer;
+
+ Mutex mLock;
+
+ bool mSeeking;
+ bool mReachedEOS;
+ bool mReachedOutputEOS;
+ status_t mFinalStatus;
+ int64_t mSeekTimeUs;
+ int64_t mPauseTime;
+
+
+ bool mIsFirstBuffer;
+ status_t mFirstBufferResult;
+ MediaBuffer *mFirstBuffer;
+ TimedEventQueue mQueue;
+ bool mQueueStarted;
+ sp<TimedEventQueue::Event> mPauseEvent;
+ bool mPauseEventPending;
+
+ sp<MediaPlayerBase::AudioSink> mAudioSink;
+ AwesomePlayer *mObserver;
+
+ static size_t AudioSinkCallback(
+ MediaPlayerBase::AudioSink *audioSink,
+ void *data, size_t size, void *me,
+ MediaPlayerBase::AudioSink::cb_event_t event);
+
+ void getPlayedTimeFromDSP_l(int64_t *timeStamp);
+ void getOffsetRealTime_l(int64_t *offsetTime);
+
+ size_t fillBuffer(void *data, size_t size);
+
+ void reset();
+ bool seekTooClose(int64_t time_us);
+
+ TunnelPlayer(const TunnelPlayer &);
+ TunnelPlayer &operator=(const TunnelPlayer &);
+};
+
+struct TunnelEvent : public TimedEventQueue::Event {
+ TunnelEvent(TunnelPlayer *player,
+ void (TunnelPlayer::*method)())
+ : mPlayer(player),
+ mMethod(method) {
+ }
+
+protected:
+ virtual ~TunnelEvent() {}
+
+ virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
+ (mPlayer->*mMethod)();
+ }
+
+private:
+ TunnelPlayer *mPlayer;
+ void (TunnelPlayer::*mMethod)();
+
+ TunnelEvent(const TunnelEvent &);
+ TunnelEvent &operator=(const TunnelEvent &);
+};
+
+} // namespace android
+
+#endif // LPA_PLAYER_H_
diff --git a/include/media/stagefright/WAVEWriter.h b/include/media/stagefright/WAVEWriter.h
new file mode 100644
index 0000000..a314008
--- /dev/null
+++ b/include/media/stagefright/WAVEWriter.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2012 - 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WAVE_WRITER_H_
+
+#define WAVE_WRITER_H_
+
+#include <stdio.h>
+
+#include <media/stagefright/MediaWriter.h>
+#include <utils/threads.h>
+
+namespace android {
+
+
+#define ID_RIFF 0x46464952
+#define ID_WAVE 0x45564157
+#define ID_FMT 0x20746d66
+#define ID_DATA 0x61746164
+#define FORMAT_PCM 1
+
+
+struct MediaSource;
+struct MetaData;
+
+struct wav_header {
+ uint32_t riff_id;
+ uint32_t riff_sz;
+ uint32_t riff_fmt;
+ uint32_t fmt_id;
+ uint32_t fmt_sz;
+ uint16_t audio_format;
+ uint16_t num_channels;
+ uint32_t sample_rate;
+ uint32_t byte_rate; /* sample_rate * num_channels * bps / 8 */
+ uint16_t block_align; /* num_channels * bps / 8 */
+ uint16_t bits_per_sample;
+ uint32_t data_id;
+ uint32_t data_sz;
+};
+
+
+struct WAVEWriter : public MediaWriter {
+ WAVEWriter(const char *filename);
+ WAVEWriter(int fd);
+
+ status_t initCheck() const;
+
+ virtual status_t addSource(const sp<MediaSource> &source);
+ virtual bool reachedEOS();
+ virtual status_t start(MetaData *params = NULL);
+ virtual status_t stop();
+ virtual status_t pause();
+
+protected:
+ virtual ~WAVEWriter();
+
+private:
+ int mFd;
+ status_t mInitCheck;
+ sp<MediaSource> mSource;
+ bool mStarted;
+ volatile bool mPaused;
+ volatile bool mResumed;
+ volatile bool mDone;
+ volatile bool mReachedEOS;
+ pthread_t mThread;
+ int64_t mEstimatedSizeBytes;
+ int64_t mEstimatedDurationUs;
+
+ static void *ThreadWrapper(void *);
+ status_t threadFunc();
+ bool exceedsFileSizeLimit();
+ bool exceedsFileDurationLimit();
+
+ WAVEWriter(const WAVEWriter &);
+ WAVEWriter &operator=(const WAVEWriter &);
+};
+
+} // namespace android
+
+#endif // WAVE_WRITER_H_
diff --git a/libvideoeditor/lvpp/Android.mk b/libvideoeditor/lvpp/Android.mk
index 2286827..4400c03 100755
--- a/libvideoeditor/lvpp/Android.mk
+++ b/libvideoeditor/lvpp/Android.mk
@@ -80,9 +80,13 @@
$(TOP)/frameworks/av/libvideoeditor/lvpp \
$(TOP)/frameworks/av/services/audioflinger \
$(TOP)/frameworks/native/include/media/editor \
- $(TOP)/frameworks/native/include/media/openmax \
$(TOP)/frameworks/native/services/audioflinger
+ifneq ($(TI_CUSTOM_DOMX_PATH),)
+LOCAL_C_INCLUDES += $(TI_CUSTOM_DOMX_PATH)/omx_core/inc
+else
+LOCAL_C_INCLUDES += $(TOP)/frameworks/native/include/media/openmax
+endif
LOCAL_SHARED_LIBRARIES += libdl
diff --git a/libvideoeditor/vss/stagefrightshells/src/VideoEditorVideoDecoder.cpp b/libvideoeditor/vss/stagefrightshells/src/VideoEditorVideoDecoder.cpp
index de91731..5386cdd 100755
--- a/libvideoeditor/vss/stagefrightshells/src/VideoEditorVideoDecoder.cpp
+++ b/libvideoeditor/vss/stagefrightshells/src/VideoEditorVideoDecoder.cpp
@@ -830,8 +830,13 @@
pDecShellContext->mCropRect.top = cropTop;
pDecShellContext->mCropRect.bottom = cropBottom;
+#ifdef QCOM_HARDWARE
+ width = vWidth;
+ height = vHeight;
+#else
width = cropRight - cropLeft + 1;
height = cropBottom - cropTop + 1;
+#endif
ALOGV("VideoDecoder_configureFromMetadata : W=%d H=%d", width, height);
VIDEOEDITOR_CHECK((0 != width) && (0 != height), M4ERR_PARAMETER);
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 56e7787..331e4dc 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -9,6 +9,17 @@
include $(BUILD_STATIC_LIBRARY)
+ifeq ($(BOARD_USES_QCOM_HARDWARE),true)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= AudioParameter.cpp
+LOCAL_MODULE:= libaudioparameter
+LOCAL_MODULE_TAGS := optional
+LOCAL_SHARED_LIBRARIES := libutils libcutils
+
+include $(BUILD_SHARED_LIBRARY)
+endif
+
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
@@ -58,6 +69,21 @@
LOCAL_SRC_FILES += ../libnbaio/roundup.c
+ifeq ($(BOARD_USES_LIBMEDIA_WITH_AUDIOPARAMETER),true)
+LOCAL_SRC_FILES+= \
+ AudioParameter.cpp
+endif
+
+ifeq ($(BOARD_USE_SAMSUNG_SEPARATEDSTREAM),true)
+LOCAL_CFLAGS += -DUSE_SAMSUNG_SEPARATEDSTREAM
+endif
+
+ifeq ($(BOARD_USES_QCOM_HARDWARE),true)
+LOCAL_SRC_FILES += \
+ IDirectTrack.cpp \
+ IDirectTrackClient.cpp
+endif
+
# for <cutils/atomic-inline.h>
LOCAL_CFLAGS += -DANDROID_SMP=$(if $(findstring true,$(TARGET_CPU_SMP)),1,0)
LOCAL_SRC_FILES += SingleStateQueue.cpp
diff --git a/media/libmedia/AudioParameter.cpp b/media/libmedia/AudioParameter.cpp
index e3fea77..4240a9a 100644
--- a/media/libmedia/AudioParameter.cpp
+++ b/media/libmedia/AudioParameter.cpp
@@ -1,4 +1,7 @@
/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
* Copyright (C) 2006-2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -32,6 +35,16 @@
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;
+#ifdef QCOM_HARDWARE
+const char * const AudioParameter::keyHandleFm = AUDIO_PARAMETER_KEY_HANDLE_FM;
+const char * const AudioParameter::keyVoipCheck = AUDIO_PARAMETER_KEY_VOIP_CHECK;
+const char * const AudioParameter::keyFluenceType = AUDIO_PARAMETER_KEY_FLUENCE_TYPE;
+const char * const AudioParameter::keySSR = AUDIO_PARAMETER_KEY_SSR;
+const char * const AudioParameter::keyHandleA2dpDevice = AUDIO_PARAMETER_KEY_HANDLE_A2DP_DEVICE;
+const char * const AudioParameter::keyADSPStatus = AUDIO_PARAMETER_KEY_ADSP_STATUS;
+const char * const AudioParameter::keyCanOpenProxy = AUDIO_CAN_OPEN_PROXY;
+const char * const AudioParameter::keyFmVolume = AUDIO_PARAMETER_KEY_FM_VOLUME;
+#endif
AudioParameter::AudioParameter(const String8& keyValuePairs)
{
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index ccbc5a3..34bb6f9 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -60,9 +60,14 @@
// We double the size of input buffer for ping pong use of record buffer.
size <<= 1;
- // Assumes audio_is_linear_pcm(format)
+#ifdef QCOM_HARDWARE
+ if (audio_is_linear_pcm(format) || format == AUDIO_FORMAT_AMR_WB) {
+#endif
uint32_t channelCount = popcount(channelMask);
size /= channelCount * audio_bytes_per_sample(format);
+#ifdef QCOM_HARDWARE
+ }
+#endif
*frameCount = size;
return NO_ERROR;
@@ -194,11 +199,13 @@
ALOGE("Invalid format %d", format);
return BAD_VALUE;
}
+#ifndef QCOM_HARDWARE
// Temporary restriction: AudioFlinger currently supports 16-bit PCM only
if (format != AUDIO_FORMAT_PCM_16_BIT) {
ALOGE("Format %d is not supported", format);
return BAD_VALUE;
}
+#endif
mFormat = format;
if (!audio_is_input_channel(channelMask)) {
@@ -206,9 +213,32 @@
return BAD_VALUE;
}
mChannelMask = channelMask;
- uint32_t channelCount = popcount(channelMask);
+ uint32_t channelCount = popcount(channelMask
+#ifdef QCOM_HARDWARE
+ &(AUDIO_CHANNEL_IN_STEREO|AUDIO_CHANNEL_IN_MONO|AUDIO_CHANNEL_IN_5POINT1));
+#else
+ );
+#endif
mChannelCount = channelCount;
+#ifdef QCOM_HARDWARE
+ mFrameSize = frameSize();
+
+ size_t inputBuffSizeInBytes = -1;
+ status_t status = AudioSystem::getInputBufferSize(sampleRate, format, channelMask, &inputBuffSizeInBytes);
+ if (status != NO_ERROR) {
+ ALOGE("AudioSystem could not query the input buffer size; status %d", status);
+ return NO_INIT;
+ }
+
+ if (inputBuffSizeInBytes == 0) {
+ ALOGE("Unsupported configuration: sampleRate %u, format %d, channelMask %#x",
+ sampleRate, format, channelMask);
+ return BAD_VALUE;
+ }
+
+ int minFrameCount = (inputBuffSizeInBytes * 2)/mFrameSize;
+#else
// Assumes audio_is_linear_pcm(format), else sizeof(uint8_t)
mFrameSize = channelCount * audio_bytes_per_sample(format);
@@ -220,6 +250,8 @@
ALOGE("getMinFrameCount() failed; status %d", status);
return status;
}
+#endif
+
ALOGV("AudioRecord::set() minFrameCount = %d", minFrameCount);
if (frameCount == 0) {
@@ -276,6 +308,13 @@
return NO_ERROR;
}
+#ifdef QCOM_HARDWARE
+audio_source_t AudioRecord::inputSource() const
+{
+ return mInputSource;
+}
+#endif
+
// -------------------------------------------------------------------------
status_t AudioRecord::start(AudioSystem::sync_event_t event, int triggerSession)
@@ -463,6 +502,12 @@
}
int originalSessionId = mSessionId;
+#ifdef QCOM_HARDWARE
+ if (inputSource() == AUDIO_SOURCE_VOICE_COMMUNICATION) {
+ ALOGV("Notify use of Voice Communication");
+ trackFlags |= IAudioFlinger::TRACK_VOICE_COMMUNICATION;
+ }
+#endif
sp<IAudioRecord> record = audioFlinger->openRecord(input,
mSampleRate, mFormat,
mChannelMask,
@@ -522,7 +567,7 @@
void *buffers = (char*)cblk + sizeof(audio_track_cblk_t);
// update proxy
- mProxy = new AudioRecordClientProxy(cblk, buffers, mFrameCount, mFrameSize);
+ mProxy = new AudioRecordClientProxy(cblk, buffers, mCblk->frameCount_, mFrameSize);
mProxy->setEpoch(epoch);
mProxy->setMinimum(mNotificationFramesAct);
@@ -952,6 +997,38 @@
return result;
}
+#ifdef QCOM_HARDWARE
+size_t AudioRecord::frameSize() const
+{
+ if (inputSource() == AUDIO_SOURCE_VOICE_COMMUNICATION) {
+ if (audio_is_linear_pcm(mFormat)) {
+ return channelCount()*audio_bytes_per_sample(mFormat);
+ } else {
+ return channelCount()*sizeof(int16_t);
+ }
+ } else {
+ if (format() ==AUDIO_FORMAT_AMR_NB) {
+ return channelCount() * AMR_FRAMESIZE; // Full rate framesize
+ } else if (format() == AUDIO_FORMAT_EVRC) {
+ return channelCount() * EVRC_FRAMESIZE; // Full rate framesize
+ } else if (format() == AUDIO_FORMAT_QCELP) {
+ return channelCount() * QCELP_FRAMESIZE; // Full rate framesize
+ } else if (format() == AUDIO_FORMAT_AAC) {
+ // Not actual framsize but for variable frame rate AAC encoding,
+ // buffer size is treated as a frame size
+ return AAC_FRAMESIZE;
+ } else if(format() == AUDIO_FORMAT_AMR_WB) {
+ return channelCount() * AMR_WB_FRAMESIZE;
+ }
+ if (audio_is_linear_pcm(mFormat)) {
+ return channelCount()*audio_bytes_per_sample(mFormat);
+ } else {
+ return sizeof(uint8_t);
+ }
+ }
+}
+#endif
+
// =========================================================================
void AudioRecord::DeathNotifier::binderDied(const wp<IBinder>& who)
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 8033c2c..1a1bfda 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -316,6 +316,11 @@
audio_stream_type_t streamType,
uint32_t* latency)
{
+#ifdef QCOM_HARDWARE
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ *latency = af->latency(output);
+#else
OutputDescriptor *outputDesc;
gLock.lock();
@@ -329,6 +334,7 @@
*latency = outputDesc->latency;
gLock.unlock();
}
+#endif
ALOGV("getLatency() streamType %d, output %d, latency %d", streamType, output, *latency);
@@ -572,6 +578,12 @@
return aps->getDeviceConnectionState(device, device_address);
}
+extern "C" audio_policy_dev_state_t _ZN7android11AudioSystem24getDeviceConnectionStateE15audio_devices_tPKc(audio_devices_t device,
+ const char *device_address)
+{
+ return AudioSystem::getDeviceConnectionState(device, device_address);
+}
+
status_t AudioSystem::setPhoneState(audio_mode_t state)
{
if (uint32_t(state) >= AUDIO_MODE_CNT) return BAD_VALUE;
@@ -608,6 +620,14 @@
return aps->getOutput(stream, samplingRate, format, channelMask, flags, offloadInfo);
}
+extern "C" audio_io_handle_t _ZN7android11AudioSystem9getOutputE19audio_stream_type_tjjj27audio_policy_output_flags_t(audio_stream_type_t stream,
+ uint32_t samplingRate,
+ uint32_t format,
+ uint32_t channels,
+ audio_output_flags_t flags) {
+ return AudioSystem::getOutput(stream,samplingRate,(audio_format_t) format, channels, flags);
+}
+
status_t AudioSystem::startOutput(audio_io_handle_t output,
audio_stream_type_t stream,
int session)
@@ -811,4 +831,13 @@
ALOGW("AudioPolicyService server died!");
}
+#ifdef USE_SAMSUNG_SEPARATEDSTREAM
+extern "C" bool _ZN7android11AudioSystem17isSeparatedStreamE19audio_stream_type_t(audio_stream_type_t stream)
+{
+ ALOGD("audio_stream_type_t: %d", stream);
+ ALOGD("isSeparatedStream: false");
+ return false;
+}
+#endif // USE_SAMSUNG_SEPARATEDSTREAM
+
}; // namespace android
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index e290627..05a0341 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -1,5 +1,6 @@
/*
-**
+** Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+** Not a Contribution.
** Copyright 2007, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
@@ -53,19 +54,22 @@
// audio_format_t format
// audio_channel_mask_t channelMask
// audio_output_flags_t flags
- uint32_t afSampleRate;
+ uint32_t afSampleRate = 0;
if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
return NO_INIT;
}
- size_t afFrameCount;
+ size_t afFrameCount = 0;
if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {
return NO_INIT;
}
- uint32_t afLatency;
+ uint32_t afLatency = 0;
if (AudioSystem::getOutputLatency(&afLatency, streamType) != NO_ERROR) {
return NO_INIT;
}
-
+ if(!afSampleRate || !afFrameCount) {
+ ALOGW("samplerate or framecount 0");
+ return NO_INIT;
+ }
// Ensure that buffer depth covers at least audio hardware latency
uint32_t minBufCount = afLatency / ((1000 * afFrameCount) / afSampleRate);
if (minBufCount < 2) {
@@ -85,8 +89,16 @@
: mStatus(NO_INIT),
mIsTimed(false),
mPreviousPriority(ANDROID_PRIORITY_NORMAL),
+#ifdef QCOM_HARDWARE
+ mPreviousSchedulingGroup(SP_DEFAULT),
+ mAudioFlinger(NULL),
+ mObserver(NULL),
+ mCblk(NULL),
+ mPausedPosition(0)
+#else
mPreviousSchedulingGroup(SP_DEFAULT),
mPausedPosition(0)
+#endif
{
}
@@ -107,8 +119,16 @@
: mStatus(NO_INIT),
mIsTimed(false),
mPreviousPriority(ANDROID_PRIORITY_NORMAL),
+#ifdef QCOM_HARDWARE
+ mPreviousSchedulingGroup(SP_DEFAULT),
+ mAudioFlinger(NULL),
+ mObserver(NULL),
+ mCblk(NULL),
+ mPausedPosition(0)
+#else
mPreviousSchedulingGroup(SP_DEFAULT),
mPausedPosition(0)
+#endif
{
mStatus = set(streamType, sampleRate, format, channelMask,
frameCount, flags, cbf, user, notificationFrames,
@@ -133,8 +153,17 @@
: mStatus(NO_INIT),
mIsTimed(false),
mPreviousPriority(ANDROID_PRIORITY_NORMAL),
+#ifdef QCOM_HARDWARE
+ mPreviousSchedulingGroup(SP_DEFAULT),
+ mProxy(NULL),
+ mAudioFlinger(NULL),
+ mObserver(NULL),
+ mCblk(NULL),
+ mPausedPosition(0)
+#else
mPreviousSchedulingGroup(SP_DEFAULT),
mPausedPosition(0)
+#endif
{
mStatus = set(streamType, sampleRate, format, channelMask,
0 /*frameCount*/, flags, cbf, user, notificationFrames,
@@ -154,10 +183,23 @@
mAudioTrackThread->requestExitAndWait();
mAudioTrackThread.clear();
}
+#ifdef QCOM_HARDWARE
+ if (mAudioTrack != 0) {
+ mAudioTrack->asBinder()->unlinkToDeath(mDeathNotifier, this);
+ mAudioTrack.clear();
+ AudioSystem::releaseAudioSessionId(mSessionId);
+ }
+
+ if (mDirectTrack != 0) {
+ mDirectTrack.clear();
+ }
+ IPCThreadState::self()->flushCommands();
+#else
mAudioTrack->asBinder()->unlinkToDeath(mDeathNotifier, this);
mAudioTrack.clear();
IPCThreadState::self()->flushCommands();
AudioSystem::releaseAudioSessionId(mSessionId);
+#endif
}
}
@@ -293,6 +335,33 @@
uint32_t channelCount = popcount(channelMask);
mChannelCount = channelCount;
+#ifdef QCOM_HARDWARE
+ if ((streamType == AUDIO_STREAM_VOICE_CALL)
+ && (channelCount == 1)
+ && ((sampleRate == 8000 || sampleRate == 16000)))
+ {
+ ALOGD("Turn on Direct Output for VOIP RX");
+ flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_VOIP_RX|AUDIO_OUTPUT_FLAG_DIRECT);
+ }
+
+ if ((audio_stream_type_t)streamType == AUDIO_STREAM_VOICE_CALL) {
+ if (audio_is_linear_pcm(format)) {
+ mFrameSize = channelCount * audio_bytes_per_sample(format);
+ mFrameSizeAF = channelCount * sizeof(int16_t);
+ } else {
+ mFrameSize = sizeof(uint16_t);
+ mFrameSizeAF = sizeof(uint16_t);
+ }
+ } else {
+ if (audio_is_linear_pcm(format)) {
+ mFrameSize = channelCount * audio_bytes_per_sample(format);
+ mFrameSizeAF = channelCount * sizeof(int16_t);
+ } else {
+ mFrameSize = sizeof(uint8_t);
+ mFrameSizeAF = sizeof(uint8_t);
+ }
+ }
+#else
if (audio_is_linear_pcm(format)) {
mFrameSize = channelCount * audio_bytes_per_sample(format);
mFrameSizeAF = channelCount * sizeof(int16_t);
@@ -300,6 +369,7 @@
mFrameSize = sizeof(uint8_t);
mFrameSizeAF = sizeof(uint8_t);
}
+#endif
audio_io_handle_t output = AudioSystem::getOutput(
streamType,
@@ -328,39 +398,77 @@
mAuxEffectId = 0;
mFlags = flags;
mCbf = cbf;
+#ifdef QCOM_HARDWARE
+ mSampleRate = sampleRate;
- if (cbf != NULL) {
- mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);
- mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/);
- }
-
- // create the IAudioTrack
- status_t status = createTrack_l(streamType,
- sampleRate,
- format,
- frameCount,
- flags,
- sharedBuffer,
- output,
- 0 /*epoch*/);
-
- if (status != NO_ERROR) {
- if (mAudioTrackThread != 0) {
- mAudioTrackThread->requestExit(); // see comment in AudioTrack.h
- mAudioTrackThread->requestExitAndWait();
- mAudioTrackThread.clear();
+ if (flags & AUDIO_OUTPUT_FLAG_LPA || flags & AUDIO_OUTPUT_FLAG_TUNNEL) {
+ ALOGV("Creating Direct Track");
+ const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
+ if (audioFlinger == 0) {
+ ALOGE("Could not get audioflinger");
+ return NO_INIT;
}
- //Use of direct and offloaded output streams is ref counted by audio policy manager.
- // As getOutput was called above and resulted in an output stream to be opened,
- // we need to release it.
- AudioSystem::releaseOutput(output);
- return status;
+ mAudioFlinger = audioFlinger;
+ status_t status = NO_ERROR;
+ mAudioDirectOutput = output;
+ mDirectTrack = audioFlinger->createDirectTrack( getpid(),
+ sampleRate,
+ channelMask,
+ mAudioDirectOutput,
+ &mSessionId,
+ this,
+ streamType,
+ &status);
+ if(status != NO_ERROR) {
+ ALOGE("createDirectTrack returned with status %d", status);
+ return status;
+ }
+ mAudioTrack = NULL;
+ mSharedBuffer = NULL;
}
+ else {
+#endif
+ if (cbf != NULL) {
+ mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);
+ mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/);
+ }
+ // create the IAudioTrack
+ status_t status = createTrack_l(streamType,
+ sampleRate,
+ format,
+ frameCount,
+ flags,
+ sharedBuffer,
+ output,
+ 0 /*epoch*/);
+
+ if (status != NO_ERROR) {
+ if (mAudioTrackThread != 0) {
+ mAudioTrackThread->requestExit(); // see comment in AudioTrack.h
+ mAudioTrackThread->requestExitAndWait();
+ mAudioTrackThread.clear();
+ }
+ //Use of direct and offloaded output streams is ref counted by audio policy manager.
+ // As getOutput was called above and resulted in an output stream to be opened,
+ // we need to release it.
+ AudioSystem::releaseOutput(output);
+ return status;
+ }
+#ifdef QCOM_HARDWARE
+ AudioSystem::acquireAudioSessionId(mSessionId);
+ mAudioDirectOutput = -1;
+ mDirectTrack = NULL;
+ mSharedBuffer = sharedBuffer;
+ }
+ mUserData = user;
+#endif
mStatus = NO_ERROR;
mStreamType = streamType;
mFormat = format;
+#ifndef QCOM_HARDWARE
mSharedBuffer = sharedBuffer;
+#endif
mState = STATE_STOPPED;
mUserData = user;
mLoopPeriod = 0;
@@ -368,7 +476,9 @@
mMarkerReached = false;
mNewPosition = 0;
mUpdatePeriod = 0;
+#ifndef QCOM_HARDWARE
AudioSystem::acquireAudioSessionId(mSessionId);
+#endif
mSequence = 1;
mObservedSequence = mSequence;
mInUnderrun = false;
@@ -379,10 +489,29 @@
// -------------------------------------------------------------------------
+#ifdef QCOM_HARDWARE
+uint32_t AudioTrack::latency() const
+{
+ if (mAudioDirectOutput != -1) {
+ return mAudioFlinger->latency(mAudioDirectOutput);
+ } else if (mOutput != 0) {
+ uint32_t afLatency = 0;
+ uint32_t newLatency = 0;
+ AudioSystem::getLatency(mOutput, mStreamType, &afLatency);
+ if (0 != mSampleRate){
+ newLatency = afLatency + (1000*mCblk->frameCount_) / mSampleRate;
+ }
+ ALOGV("latency() mLatency = %d, newLatency = %d", mLatency, newLatency);
+ return newLatency;
+ }
+ return mLatency;
+}
+#endif
+
status_t AudioTrack::start()
{
+ status_t status = NO_ERROR;
AutoMutex lock(mLock);
-
if (mState == STATE_ACTIVE) {
return INVALID_OPERATION;
}
@@ -395,6 +524,12 @@
} else {
mState = STATE_ACTIVE;
}
+#ifdef QCOM_HARDWARE
+ if (mDirectTrack != NULL) {
+ mDirectTrack->start();
+ return status;
+ }
+#endif
if (previousState == STATE_STOPPED || previousState == STATE_FLUSHED) {
// reset current position as seen by client to 0
mProxy->setEpoch(mProxy->getEpoch() - mProxy->getPosition());
@@ -418,7 +553,6 @@
androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
}
- status_t status = NO_ERROR;
if (!(flags & CBLK_INVALID)) {
status = mAudioTrack->start();
if (status == DEAD_OBJECT) {
@@ -459,29 +593,37 @@
mState = STATE_STOPPED;
}
- mProxy->interrupt();
- mAudioTrack->stop();
- // the playback head position will reset to 0, so if a marker is set, we need
- // to activate it again
- mMarkerReached = false;
+#ifdef QCOM_HARDWARE
+ if(mDirectTrack != NULL) {
+ mDirectTrack->stop();
+ } else if (mAudioTrack != NULL) {
+#endif
+ mProxy->interrupt();
+ mAudioTrack->stop();
+ // the playback head position will reset to 0, so if a marker is set, we need
+ // to activate it again
+ mMarkerReached = false;
#if 0
- // Force flush if a shared buffer is used otherwise audioflinger
- // will not stop before end of buffer is reached.
- // It may be needed to make sure that we stop playback, likely in case looping is on.
- if (mSharedBuffer != 0) {
- flush_l();
- }
+ // Force flush if a shared buffer is used otherwise audioflinger
+ // will not stop before end of buffer is reached.
+ // It may be needed to make sure that we stop playback, likely in case looping is on.
+ if (mSharedBuffer != 0) {
+ flush_l();
+ }
#endif
- sp<AudioTrackThread> t = mAudioTrackThread;
- if (t != 0) {
- if (!isOffloaded()) {
- t->pause();
+ sp<AudioTrackThread> t = mAudioTrackThread;
+ if (t != 0) {
+ if (!isOffloaded()) {
+ t->pause();
+ }
+ } else {
+ setpriority(PRIO_PROCESS, 0, mPreviousPriority);
+ set_sched_policy(0, mPreviousSchedulingGroup);
}
- } else {
- setpriority(PRIO_PROCESS, 0, mPreviousPriority);
- set_sched_policy(0, mPreviousSchedulingGroup);
+#ifdef QCOM_HARDWARE
}
+#endif
}
bool AudioTrack::stopped() const
@@ -492,10 +634,18 @@
void AudioTrack::flush()
{
+#ifdef QCOM_HARDWARE
+ if(mDirectTrack != NULL) {
+ ALOGE("mdirect track flush");
+ mDirectTrack->flush();
+ return ;
+ }
+#else
if (mSharedBuffer != 0) {
return;
}
AutoMutex lock(mLock);
+#endif
if (mState == STATE_ACTIVE || mState == STATE_FLUSHED) {
return;
}
@@ -530,8 +680,17 @@
} else {
return;
}
- mProxy->interrupt();
- mAudioTrack->pause();
+#ifdef QCOM_HARDWARE
+ if(mDirectTrack != NULL) {
+ ALOGV("mDirectTrack pause");
+ mDirectTrack->pause();
+ } else {
+#endif
+ mProxy->interrupt();
+ mAudioTrack->pause();
+#ifdef QCOM_HARDWARE
+ }
+#endif
if (isOffloaded()) {
if (mOutput != 0) {
@@ -553,8 +712,16 @@
AutoMutex lock(mLock);
mVolume[LEFT] = left;
mVolume[RIGHT] = right;
-
- mProxy->setVolumeLR((uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000));
+#ifdef QCOM_HARDWARE
+ if(mDirectTrack != NULL) {
+ ALOGV("mDirectTrack->setVolume(left = %f , right = %f)", left,right);
+ mDirectTrack->setVolume(left, right);
+ } else {
+#endif
+ mProxy->setVolumeLR((uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000));
+#ifdef QCOM_HARDWARE
+ }
+#endif
if (isOffloaded()) {
mAudioTrack->signal();
@@ -569,6 +736,11 @@
status_t AudioTrack::setAuxEffectSendLevel(float level)
{
+#ifdef QCOM_HARDWARE
+ if (mDirectTrack != NULL) {
+ return NO_ERROR;
+ }
+#endif
if (level < 0.0f || level > 1.0f) {
return BAD_VALUE;
}
@@ -616,6 +788,11 @@
}
AutoMutex lock(mLock);
+#ifdef QCOM_HARDWARE
+ if(mAudioDirectOutput != -1) {
+ return mAudioFlinger->sampleRate(mAudioDirectOutput);
+ }
+#endif
// sample rate can be updated during playback by the offloaded decoder so we need to
// query the HAL and update if needed.
@@ -629,6 +806,7 @@
}
}
}
+
return mSampleRate;
}
@@ -861,21 +1039,21 @@
// Not all of these values are needed under all conditions, but it is easier to get them all
- uint32_t afLatency;
+ uint32_t afLatency = 0;
status = AudioSystem::getLatency(output, streamType, &afLatency);
if (status != NO_ERROR) {
ALOGE("getLatency(%d) failed status %d", output, status);
return NO_INIT;
}
- size_t afFrameCount;
+ size_t afFrameCount = 0;
status = AudioSystem::getFrameCount(output, streamType, &afFrameCount);
if (status != NO_ERROR) {
ALOGE("getFrameCount(output=%d, streamType=%d) status %d", output, streamType, status);
return NO_INIT;
}
- uint32_t afSampleRate;
+ uint32_t afSampleRate = 0;
status = AudioSystem::getSamplingRate(output, streamType, &afSampleRate);
if (status != NO_ERROR) {
ALOGE("getSamplingRate(output=%d, streamType=%d) status %d", output, streamType, status);
@@ -945,6 +1123,10 @@
// FIXME move these calculations and associated checks to server
// Ensure that buffer depth covers at least audio hardware latency
+ if(!afSampleRate && !afFrameCount) {
+ ALOGW("samplerate or framecount zero");
+ return NO_INIT;
+ }
uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate);
ALOGV("afFrameCount=%d, minBufCount=%d, afSampleRate=%u, afLatency=%d",
afFrameCount, minBufCount, afSampleRate, afLatency);
@@ -1084,7 +1266,11 @@
mAudioTrack->attachAuxEffect(mAuxEffectId);
// FIXME don't believe this lie
- mLatency = afLatency + (1000*frameCount) / sampleRate;
+ if(sampleRate){
+ mLatency = afLatency + (1000*frameCount) / sampleRate;
+ }else{
+ mLatency = afLatency;
+ }
mFrameCount = frameCount;
// If IAudioTrack is re-created, don't let the requested frameCount
// decrease. This can confuse clients that cache frameCount().
@@ -1237,7 +1423,8 @@
// restart track if it was disabled by audioflinger due to previous underrun
if (mState == STATE_ACTIVE) {
audio_track_cblk_t* cblk = mCblk;
- if (android_atomic_and(~CBLK_DISABLED, &cblk->mFlags) & CBLK_DISABLED) {
+ if (cblk->mFlags & CBLK_DISABLED) {
+ android_atomic_and(~CBLK_DISABLED, &cblk->mFlags);
ALOGW("releaseBuffer() track %p name=%s disabled due to previous underrun, restarting",
this, mName.string());
// FIXME ignoring status
@@ -1250,6 +1437,13 @@
ssize_t AudioTrack::write(const void* buffer, size_t userSize)
{
+#ifdef QCOM_HARDWARE
+ if (mDirectTrack != NULL) {
+ ssize_t written = 0;
+ written = mDirectTrack->write(buffer,userSize);
+ return written;
+ }
+#endif
if (mTransfer != TRANSFER_SYNC || mIsTimed) {
return INVALID_OPERATION;
}
@@ -1803,7 +1997,13 @@
result.append(buffer);
snprintf(buffer, 255, " sample rate(%u), status(%d)\n", mSampleRate, mStatus);
result.append(buffer);
+#ifdef QCOM_HARDWARE
+ uint32_t afLatency = 0;
+ AudioSystem::getLatency(mOutput, mStreamType, &afLatency);
+ snprintf(buffer, 255, " state(%d), latency (%d)\n", mState, afLatency + (1000*mCblk->frameCount_) / mSampleRate);
+#else
snprintf(buffer, 255, " state(%d), latency (%d)\n", mState, mLatency);
+#endif
result.append(buffer);
::write(fd, result.string(), result.size());
return NO_ERROR;
@@ -1826,6 +2026,27 @@
}
}
+#ifdef QCOM_HARDWARE
+void AudioTrack::notify(int msg) {
+ if (msg == EVENT_UNDERRUN) {
+ ALOGV("Posting event underrun to Audio Sink.");
+ mCbf(EVENT_UNDERRUN, mUserData, 0);
+ }
+ if (msg == EVENT_HW_FAIL) {
+ ALOGV("Posting event HW fail to Audio Sink.");
+ mCbf(EVENT_HW_FAIL, mUserData, 0);
+ }
+}
+
+status_t AudioTrack::getTimeStamp(uint64_t *tstamp) {
+ if (mDirectTrack != NULL) {
+ *tstamp = mDirectTrack->getTimeStamp();
+ ALOGE("Timestamp %lld ", *tstamp);
+ }
+ return NO_ERROR;
+}
+#endif
+
// =========================================================================
AudioTrack::AudioTrackThread::AudioTrackThread(AudioTrack& receiver, bool bCanCallJava)
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index acfaea0..89d7a8d 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -1,5 +1,6 @@
/*
-**
+** Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+** Not a Contribution.
** Copyright 2007, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
@@ -74,6 +75,9 @@
GET_PRIMARY_OUTPUT_SAMPLING_RATE,
GET_PRIMARY_OUTPUT_FRAME_COUNT,
SET_LOW_RAM_DEVICE,
+#ifdef QCOM_HARDWARE
+ CREATE_DIRECT_TRACK,
+#endif
};
class BpAudioFlinger : public BpInterface<IAudioFlinger>
@@ -145,6 +149,49 @@
return track;
}
+#ifdef QCOM_HARDWARE
+ virtual sp<IDirectTrack> createDirectTrack(
+ pid_t pid,
+ uint32_t sampleRate,
+ audio_channel_mask_t channelMask,
+ audio_io_handle_t output,
+ int *sessionId,
+ IDirectTrackClient* client,
+ audio_stream_type_t streamType,
+ status_t *status)
+ {
+ Parcel data, reply;
+ sp<IDirectTrack> track;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(pid);
+ data.writeInt32(sampleRate);
+ data.writeInt32(channelMask);
+ data.writeInt32((int32_t)output);
+ int lSessionId = 0;
+ if (sessionId != NULL) {
+ lSessionId = *sessionId;
+ }
+ data.writeInt32(lSessionId);
+ data.write(client, sizeof(IDirectTrackClient));
+ data.writeInt32((int32_t) streamType);
+ status_t lStatus = remote()->transact(CREATE_DIRECT_TRACK, data, &reply);
+ if (lStatus != NO_ERROR) {
+ ALOGE("createDirectTrack error: %s", strerror(-lStatus));
+ } else {
+ lSessionId = reply.readInt32();
+ if (sessionId != NULL) {
+ *sessionId = lSessionId;
+ }
+ lStatus = reply.readInt32();
+ track = interface_cast<IDirectTrack>(reply.readStrongBinder());
+ }
+ if (status) {
+ *status = lStatus;
+ }
+ return track;
+ }
+#endif
+
virtual sp<IAudioRecord> openRecord(
audio_io_handle_t input,
uint32_t sampleRate,
@@ -785,6 +832,26 @@
reply->writeStrongBinder(track->asBinder());
return NO_ERROR;
} break;
+#ifdef QCOM_HARDWARE
+ case CREATE_DIRECT_TRACK: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ pid_t pid = data.readInt32();
+ uint32_t sampleRate = data.readInt32();
+ audio_channel_mask_t channelMask = data.readInt32();
+ audio_io_handle_t output = (audio_io_handle_t) data.readInt32();
+ int sessionId = data.readInt32();
+ IDirectTrackClient* client;
+ data.read(client,sizeof(IDirectTrackClient));
+ int streamType = data.readInt32();
+ status_t status;
+ sp<IDirectTrack> track = createDirectTrack(pid,
+ sampleRate, channelMask, output, &sessionId, client,(audio_stream_type_t) streamType, &status);
+ reply->writeInt32(sessionId);
+ reply->writeInt32(status);
+ reply->writeStrongBinder(track->asBinder());
+ return NO_ERROR;
+ } break;
+#endif
case OPEN_RECORD: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
audio_io_handle_t input = (audio_io_handle_t) data.readInt32();
diff --git a/media/libmedia/IAudioFlingerClient.cpp b/media/libmedia/IAudioFlingerClient.cpp
index 3c0d4cf..65dc3f6 100644
--- a/media/libmedia/IAudioFlingerClient.cpp
+++ b/media/libmedia/IAudioFlingerClient.cpp
@@ -1,4 +1,7 @@
/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -49,9 +52,12 @@
uint32_t stream = *(const uint32_t *)param2;
ALOGV("ioConfigChanged stream %d", stream);
data.writeInt32(stream);
- } else if (event != AudioSystem::OUTPUT_CLOSED && event != AudioSystem::INPUT_CLOSED) {
- const AudioSystem::OutputDescriptor *desc =
- (const AudioSystem::OutputDescriptor *)param2;
+ } else if (event != AudioSystem::OUTPUT_CLOSED && event != AudioSystem::INPUT_CLOSED
+#ifdef QCOM_HARDWARE
+ && event != AudioSystem::EFFECT_CONFIG_CHANGED
+#endif
+ ) {
+ const AudioSystem::OutputDescriptor *desc = (const AudioSystem::OutputDescriptor *)param2;
data.writeInt32(desc->samplingRate);
data.writeInt32(desc->format);
data.writeInt32(desc->channelMask);
diff --git a/media/libmedia/IDirectTrack.cpp b/media/libmedia/IDirectTrack.cpp
new file mode 100644
index 0000000..e12cd74
--- /dev/null
+++ b/media/libmedia/IDirectTrack.cpp
@@ -0,0 +1,177 @@
+/*
+** Copyright (c) 2012, The Linux Foundation. All rights reserved.
+** Not a Contribution
+**
+** Copyright 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.
+*/
+
+#define LOG_TAG "IDirectTrack"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/Parcel.h>
+
+#include <media/IDirectTrack.h>
+
+namespace android {
+
+enum {
+ START = IBinder::FIRST_CALL_TRANSACTION,
+ STOP,
+ FLUSH,
+ MUTE,
+ PAUSE,
+ SET_VOLUME,
+ WRITE,
+ GET_TIMESTAMP
+};
+
+class BpDirectTrack : public BpInterface<IDirectTrack>
+{
+public:
+ BpDirectTrack(const sp<IBinder>& impl)
+ : BpInterface<IDirectTrack>(impl)
+ {
+ }
+
+ virtual status_t start()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IDirectTrack::getInterfaceDescriptor());
+ status_t status = remote()->transact(START, data, &reply);
+ if (status == NO_ERROR) {
+ status = reply.readInt32();
+ } else {
+ ALOGW("start() error: %s", strerror(-status));
+ }
+ return status;
+ }
+
+ virtual void stop()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IDirectTrack::getInterfaceDescriptor());
+ remote()->transact(STOP, data, &reply);
+ }
+
+ virtual void flush()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IDirectTrack::getInterfaceDescriptor());
+ remote()->transact(FLUSH, data, &reply);
+ }
+
+ virtual void mute(bool e)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IDirectTrack::getInterfaceDescriptor());
+ data.writeInt32(e);
+ remote()->transact(MUTE, data, &reply);
+ }
+
+ virtual void pause()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IDirectTrack::getInterfaceDescriptor());
+ remote()->transact(PAUSE, data, &reply);
+ }
+
+ virtual void setVolume(float left, float right)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IDirectTrack::getInterfaceDescriptor());
+ remote()->transact(SET_VOLUME, data, &reply);
+ }
+
+ virtual ssize_t write(const void* buffer, size_t bytes)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IDirectTrack::getInterfaceDescriptor());
+ ssize_t bytesWritten = remote()->transact(WRITE, data, &reply);
+ return bytesWritten;
+ }
+
+ virtual int64_t getTimeStamp() {
+ Parcel data, reply;
+ data.writeInterfaceToken(IDirectTrack::getInterfaceDescriptor());
+ int64_t tstamp = remote()->transact(GET_TIMESTAMP, data, &reply);
+ return tstamp;
+ }
+};
+
+IMPLEMENT_META_INTERFACE(DirectTrack, "android.media.IDirectTrack");
+
+// ----------------------------------------------------------------------
+
+status_t BnDirectTrack::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case START: {
+ CHECK_INTERFACE(IDirectTrack, data, reply);
+ reply->writeInt32(start());
+ return NO_ERROR;
+ } break;
+ case STOP: {
+ CHECK_INTERFACE(IDirectTrack, data, reply);
+ stop();
+ return NO_ERROR;
+ } break;
+ case FLUSH: {
+ CHECK_INTERFACE(IDirectTrack, data, reply);
+ flush();
+ return NO_ERROR;
+ } break;
+ case MUTE: {
+ CHECK_INTERFACE(IDirectTrack, data, reply);
+ mute( data.readInt32() );
+ return NO_ERROR;
+ } break;
+ case PAUSE: {
+ CHECK_INTERFACE(IDirectTrack, data, reply);
+ pause();
+ return NO_ERROR;
+ }
+ case SET_VOLUME: {
+ CHECK_INTERFACE(IDirectTrack, data, reply);
+ float left = 1.0;
+ float right = 1.0;
+ setVolume(left, right);
+ return NO_ERROR;
+ }
+ case WRITE: {
+ CHECK_INTERFACE(IDirectTrack, data, reply);
+ const void *buffer = (void *)data.readInt32();
+ size_t bytes = data.readInt32();
+ ssize_t bytesWritten = write(buffer, bytes);
+ reply->writeInt32(bytesWritten);
+ return NO_ERROR;
+ }
+ case GET_TIMESTAMP: {
+ CHECK_INTERFACE(IDirectTrack, data, reply);
+ int64_t time = getTimeStamp();
+ reply->writeInt32(time);
+ return NO_ERROR;
+ }
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+}; // namespace android
+
diff --git a/media/libmedia/IDirectTrackClient.cpp b/media/libmedia/IDirectTrackClient.cpp
new file mode 100644
index 0000000..f837a14
--- /dev/null
+++ b/media/libmedia/IDirectTrackClient.cpp
@@ -0,0 +1,68 @@
+/*
+** Copyright (c) 2012, The Linux Foundation. All rights reserved.
+** Not a Contribution.
+**
+** Copyright 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 <utils/RefBase.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+#include <media/IDirectTrackClient.h>
+
+namespace android {
+
+enum {
+ NOTIFY = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+class BpDirectTrackClient: public BpInterface<IDirectTrackClient>
+{
+public:
+ BpDirectTrackClient(const sp<IBinder>& impl)
+ : BpInterface<IDirectTrackClient>(impl)
+ {
+ }
+
+ virtual void notify(int msg)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IDirectTrackClient::getInterfaceDescriptor());
+ data.writeInt32(msg);
+ remote()->transact(NOTIFY, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+};
+
+IMPLEMENT_META_INTERFACE(DirectTrackClient, "android.media.IDirectTrackClient");
+
+// ----------------------------------------------------------------------
+
+status_t BnDirectTrackClient::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch (code) {
+ case NOTIFY: {
+ CHECK_INTERFACE(IDirectTrackClient, data, reply);
+ int msg = data.readInt32();
+ notify(msg);
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+}; // namespace android
diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp
index 8319cd7..2837bab 100644
--- a/media/libmedia/MediaProfiles.cpp
+++ b/media/libmedia/MediaProfiles.cpp
@@ -45,7 +45,10 @@
{"amrwb", AUDIO_ENCODER_AMR_WB},
{"aac", AUDIO_ENCODER_AAC},
{"heaac", AUDIO_ENCODER_HE_AAC},
- {"aaceld", AUDIO_ENCODER_AAC_ELD}
+ {"aaceld", AUDIO_ENCODER_AAC_ELD},
+#ifdef QCOM_HARDWARE
+ {"lpcm", AUDIO_ENCODER_LPCM}
+#endif
};
const MediaProfiles::NameToTagMap MediaProfiles::sFileFormatMap[] = {
@@ -70,6 +73,14 @@
{"720p", CAMCORDER_QUALITY_720P},
{"1080p", CAMCORDER_QUALITY_1080P},
{"qvga", CAMCORDER_QUALITY_QVGA},
+ {"fwvga", CAMCORDER_QUALITY_FWVGA},
+ {"wvga", CAMCORDER_QUALITY_WVGA},
+ {"vga", CAMCORDER_QUALITY_VGA},
+ {"wqvga", CAMCORDER_QUALITY_WQVGA},
+#ifdef QCOM_HARDWARE
+ {"4kuhd", CAMCORDER_QUALITY_4kUHD},
+ {"4kdci", CAMCORDER_QUALITY_4kDCI},
+#endif
{"timelapselow", CAMCORDER_QUALITY_TIME_LAPSE_LOW},
{"timelapsehigh", CAMCORDER_QUALITY_TIME_LAPSE_HIGH},
@@ -79,6 +90,12 @@
{"timelapse720p", CAMCORDER_QUALITY_TIME_LAPSE_720P},
{"timelapse1080p", CAMCORDER_QUALITY_TIME_LAPSE_1080P},
{"timelapseqvga", CAMCORDER_QUALITY_TIME_LAPSE_QVGA},
+#ifdef QCOM_HARDWARE
+ {"timelapsevga", CAMCORDER_QUALITY_TIME_LAPSE_VGA},
+ {"timelapsewvga", CAMCORDER_QUALITY_TIME_LAPSE_WVGA},
+ {"timelapsefwvga", CAMCORDER_QUALITY_TIME_LAPSE_FWVGA},
+ {"timelapsewqvga", CAMCORDER_QUALITY_TIME_LAPSE_WQVGA},
+#endif
};
/*static*/ void
@@ -800,6 +817,10 @@
MediaProfiles::createDefaultAudioEncoders(MediaProfiles *profiles)
{
profiles->mAudioEncoders.add(createDefaultAmrNBEncoderCap());
+#ifdef QCOM_HARDWARE
+ profiles->mAudioEncoders.add(createDefaultAacEncoderCap());
+ profiles->mAudioEncoders.add(createDefaultLpcmEncoderCap());
+#endif
}
/*static*/ void
@@ -833,6 +854,20 @@
return new MediaProfiles::AudioEncoderCap(
AUDIO_ENCODER_AMR_NB, 5525, 12200, 8000, 8000, 1, 1);
}
+#ifdef QCOM_HARDWARE
+/*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, 48000, 48000, 1, 6);
+}
+#endif
/*static*/ void
MediaProfiles::createDefaultImageEncodingQualityLevels(MediaProfiles *profiles)
diff --git a/media/libmedia/MediaScanner.cpp b/media/libmedia/MediaScanner.cpp
index 28b5aa7..6ea5b7e 100644
--- a/media/libmedia/MediaScanner.cpp
+++ b/media/libmedia/MediaScanner.cpp
@@ -139,6 +139,18 @@
return MEDIA_SCAN_RESULT_OK;
}
+ // Completely skip all directories containing a ".noscanandnomtp" file
+ if (pathRemaining >= 15 /* strlen(".noscanandnomtp") */ ) {
+ strcpy(fileSpot, ".noscanandnomtp");
+ if (access(path, F_OK) == 0) {
+ ALOGV("found .noscanandnomtp, completely skipping");
+ return MEDIA_SCAN_RESULT_SKIPPED;
+ }
+
+ // restore path
+ fileSpot[0] = 0;
+ }
+
// Treat all files as non-media in directories that contain a ".nomedia" file
if (pathRemaining >= 8 /* strlen(".nomedia") */ ) {
strcpy(fileSpot, ".nomedia");
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 0f6d897..9a8f94e 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -683,7 +683,11 @@
}
// Allows calls from JNI in idle state to notify errors
+#ifdef QCOM_HARDWARE
+ if (!((msg == MEDIA_ERROR || msg == MEDIA_QOE) && mCurrentState == MEDIA_PLAYER_IDLE) && mPlayer == 0) {
+#else
if (!(msg == MEDIA_ERROR && mCurrentState == MEDIA_PLAYER_IDLE) && mPlayer == 0) {
+#endif
ALOGV("notify(%d, %d, %d) callback on disconnected mediaplayer", msg, ext1, ext2);
if (locked) mLock.unlock(); // release the lock when done.
return;
@@ -758,6 +762,10 @@
break;
case MEDIA_SUBTITLE_DATA:
ALOGV("Received subtitle data message");
+#ifdef QCOM_HARDWARE
+ case MEDIA_QOE:
+ ALOGV("Received QOE Message for event : %d",ext2);
+#endif
break;
default:
ALOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2);
@@ -843,4 +851,11 @@
return INVALID_OPERATION;
}
+#ifdef SAMSUNG_CAMERA_LEGACY
+extern "C" int _ZN7android11MediaPlayer18setAudioStreamTypeE19audio_stream_type_t();
+extern "C" int _ZN7android11MediaPlayer18setAudioStreamTypeEi() {
+ return _ZN7android11MediaPlayer18setAudioStreamTypeE19audio_stream_type_t();
+}
+#endif
+
}; // namespace android
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index 8f21632..badb84c 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -38,6 +38,7 @@
libstagefright_omx \
libstagefright_wfd \
libutils \
+ libdl \
libvorbisidec \
LOCAL_STATIC_LIBRARIES := \
@@ -52,8 +53,30 @@
$(TOP)/frameworks/native/include/media/openmax \
$(TOP)/external/tremolo/Tremolo \
+ifeq ($(BOARD_USES_QCOM_HARDWARE),true)
+ ifneq ($(TARGET_QCOM_MEDIA_VARIANT),)
+ LOCAL_C_INCLUDES += \
+ $(TOP)/hardware/qcom/media-$(TARGET_QCOM_MEDIA_VARIANT)/mm-core/inc
+ else
+ LOCAL_C_INCLUDES += \
+ $(TOP)/hardware/qcom/media/mm-core/inc
+ endif
+endif
+
LOCAL_MODULE:= libmediaplayerservice
+ifeq ($(TARGET_ENABLE_QC_AV_ENHANCEMENTS),true)
+ LOCAL_CFLAGS += -DENABLE_AV_ENHANCEMENTS
+ LOCAL_C_INCLUDES += $(TOP)/frameworks/av/include/media
+ ifneq ($(TARGET_QCOM_MEDIA_VARIANT),)
+ LOCAL_C_INCLUDES += \
+ $(TOP)/hardware/qcom/media-$(TARGET_QCOM_MEDIA_VARIANT)/mm-core/inc
+ else
+ LOCAL_C_INCLUDES += \
+ $(TOP)/hardware/qcom/media/mm-core/inc
+ endif
+endif #TARGET_ENABLE_QC_AV_ENHANCEMENTS
+
include $(BUILD_SHARED_LIBRARY)
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
index 90aed39..29e1edd 100644
--- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
+++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
@@ -30,6 +30,7 @@
#include "TestPlayerStub.h"
#include "StagefrightPlayer.h"
#include "nuplayer/NuPlayerDriver.h"
+#include <dlfcn.h>
namespace android {
@@ -339,6 +340,32 @@
registerFactory_l(new SonivoxPlayerFactory(), SONIVOX_PLAYER);
registerFactory_l(new TestPlayerFactory(), TEST_PLAYER);
+ const char* FACTORY_LIB = "libdashplayer.so";
+ const char* FACTORY_CREATE_FN = "CreateDASHFactory";
+
+ MediaPlayerFactory::IFactory* pFactory = NULL;
+ void* pFactoryLib = NULL;
+ typedef MediaPlayerFactory::IFactory* (*CreateDASHDriverFn)();
+ ALOGE("calling dlopen on FACTORY_LIB");
+ pFactoryLib = ::dlopen(FACTORY_LIB, RTLD_LAZY);
+ if (pFactoryLib == NULL) {
+ ALOGE("Failed to open FACTORY_LIB Error : %s ",::dlerror());
+ } else {
+ CreateDASHDriverFn pCreateFnPtr;
+ ALOGE("calling dlsym on pFactoryLib for FACTORY_CREATE_FN ");
+ pCreateFnPtr = (CreateDASHDriverFn) dlsym(pFactoryLib, FACTORY_CREATE_FN);
+ if (pCreateFnPtr == NULL) {
+ ALOGE("Could not locate pCreateFnPtr");
+ } else {
+ pFactory = pCreateFnPtr();
+ if(pFactory == NULL) {
+ ALOGE("Failed to invoke CreateDASHDriverFn...");
+ } else {
+ ALOGE("registering DASH Player factory...");
+ registerFactory_l(pFactory,DASH_PLAYER);
+ }
+ }
+ }
sInitComplete = true;
}
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 9ac9105..685e181 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1,5 +1,8 @@
/*
**
+** Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+** Not a Contribution.
+**
** Copyright 2008, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
@@ -78,6 +81,9 @@
#include "HDCP.h"
#include "HTTPBase.h"
#include "RemoteDisplay.h"
+#ifdef QCOM_HARDWARE
+#define DEFAULT_SAMPLE_RATE 44100
+#endif
namespace {
using android::media::Metadata;
@@ -1373,6 +1379,13 @@
return mTrack->latency();
}
+#ifdef QCOM_HARDWARE
+audio_stream_type_t MediaPlayerService::AudioOutput::streamType () const
+{
+ return mStreamType;
+}
+#endif
+
float MediaPlayerService::AudioOutput::msecsPerFrame() const
{
return mMsecsPerFrame;
@@ -1384,6 +1397,22 @@
return mTrack->getPosition(position);
}
+#ifdef QCOM_HARDWARE
+ssize_t MediaPlayerService::AudioOutput::sampleRate() const
+{
+ if (mTrack == 0) return NO_INIT;
+ return DEFAULT_SAMPLE_RATE;
+}
+
+status_t MediaPlayerService::AudioOutput::getTimeStamp(uint64_t *tstamp)
+{
+ if (tstamp == 0) return BAD_VALUE;
+ if (mTrack == 0) return NO_INIT;
+ mTrack->getTimeStamp(tstamp);
+ return NO_ERROR;
+}
+#endif
+
status_t MediaPlayerService::AudioOutput::getFramesWritten(uint32_t *frameswritten) const
{
if (mTrack == 0) return NO_INIT;
@@ -1439,7 +1468,50 @@
{
mCallback = cb;
mCallbackCookie = cookie;
+#ifdef QCOM_HARDWARE
+ if (flags & AUDIO_OUTPUT_FLAG_LPA || flags & AUDIO_OUTPUT_FLAG_TUNNEL) {
+ ALOGV("AudioOutput open: with flags %x",flags);
+ channelMask = audio_channel_out_mask_from_count(channelCount);
+ if (0 == channelMask) {
+ ALOGE("open() error, can't derive mask for %d audio channels", channelCount);
+ return NO_INIT;
+ }
+ AudioTrack *audioTrack = NULL;
+ CallbackData *newcbd = NULL;
+ if (mCallback != NULL) {
+ newcbd = new CallbackData(this);
+ audioTrack = new AudioTrack(
+ mStreamType,
+ sampleRate,
+ format,
+ channelMask,
+ 0,
+ flags,
+ CallbackWrapper,
+ newcbd,
+ 0,
+ mSessionId);
+ if ((audioTrack == 0) || (audioTrack->initCheck() != NO_ERROR)) {
+ ALOGE("Unable to create audio track");
+ delete audioTrack;
+ delete newcbd;
+ return NO_INIT;
+ }
+ } else {
+ ALOGE("no callback supplied");
+ return NO_INIT;
+ }
+ deleteRecycledTrack();
+ ALOGV("setVolume");
+ mCallbackData = newcbd;
+ audioTrack->setVolume(mLeftVolume, mRightVolume);
+ mSampleRateHz = sampleRate;
+ mFlags = flags;
+ mTrack = audioTrack;
+ return NO_ERROR;
+ }
+#endif
// Check argument "bufferCount" against the mininum buffer count
if (bufferCount < mMinBufferCount) {
ALOGD("bufferCount (%d) is too small and increased to %d", bufferCount, mMinBufferCount);
@@ -1672,7 +1744,6 @@
ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size)
{
- LOG_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback.");
//ALOGV("write(%p, %u)", buffer, size);
if (mTrack != 0) {
@@ -1704,7 +1775,7 @@
void MediaPlayerService::AudioOutput::close()
{
ALOGV("close");
- mTrack.clear();
+ if (mTrack != 0) mTrack.clear();
}
void MediaPlayerService::AudioOutput::setVolume(float left, float right)
@@ -1757,55 +1828,101 @@
void MediaPlayerService::AudioOutput::CallbackWrapper(
int event, void *cookie, void *info) {
//ALOGV("callbackwrapper");
- CallbackData *data = (CallbackData*)cookie;
- data->lock();
- AudioOutput *me = data->getOutput();
- AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
- if (me == NULL) {
- // no output set, likely because the track was scheduled to be reused
- // by another player, but the format turned out to be incompatible.
+#ifdef QCOM_HARDWARE
+ if (event == AudioTrack::EVENT_UNDERRUN) {
+ ALOGW("Event underrun");
+ CallbackData *data = (CallbackData*)cookie;
+ data->lock();
+ AudioOutput *me = data->getOutput();
+ if (me == NULL) {
+ // no output set, likely because the track was scheduled to be reused
+ // by another player, but the format turned out to be incompatible.
+ data->unlock();
+ return;
+ }
+ ALOGD("Callback!!!");
+ (*me->mCallback)(
+ me, NULL, (size_t)AudioTrack::EVENT_UNDERRUN, me->mCallbackCookie, CB_EVENT_UNDERRUN);
data->unlock();
- if (buffer != NULL) {
- buffer->size = 0;
+ return;
+ }
+ if (event == AudioTrack::EVENT_HW_FAIL) {
+ ALOGW("Event hardware failure");
+ CallbackData *data = (CallbackData*)cookie;
+ if (data != NULL) {
+ data->lock();
+ AudioOutput *me = data->getOutput();
+ if (me == NULL) {
+ // no output set, likely because the track was
+ // scheduled to be reused
+ // by another player, but the format turned out
+ // to be incompatible.
+ data->unlock();
+ return;
+ }
+ ALOGV("Callback!!!");
+ (*me->mCallback)(me, NULL, (size_t)AudioTrack::EVENT_HW_FAIL,
+ me->mCallbackCookie, CB_EVENT_HW_FAIL);
+ data->unlock();
}
return;
}
-
- switch(event) {
- case AudioTrack::EVENT_MORE_DATA: {
- size_t actualSize = (*me->mCallback)(
- me, buffer->raw, buffer->size, me->mCallbackCookie,
- CB_EVENT_FILL_BUFFER);
-
- if (actualSize == 0 && buffer->size > 0 && me->mNextOutput == NULL) {
- // We've reached EOS but the audio track is not stopped yet,
- // keep playing silence.
-
- memset(buffer->raw, 0, buffer->size);
- actualSize = buffer->size;
+ if (event == AudioTrack::EVENT_MORE_DATA) {
+#endif
+ CallbackData *data = (CallbackData*)cookie;
+ data->lock();
+ AudioOutput *me = data->getOutput();
+ AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
+ if (me == NULL) {
+ // no output set, likely because the track was scheduled to be reused
+ // by another player, but the format turned out to be incompatible.
+ data->unlock();
+ if (buffer != NULL) {
+ buffer->size = 0;
+ }
+ return;
}
- buffer->size = actualSize;
- } break;
+ switch(event) {
+ case AudioTrack::EVENT_MORE_DATA: {
+ size_t actualSize = (*me->mCallback)(
+ me, buffer->raw, buffer->size, me->mCallbackCookie,
+ CB_EVENT_FILL_BUFFER);
+
+ if (actualSize == 0 && buffer->size > 0 && me->mNextOutput == NULL) {
+ // We've reached EOS but the audio track is not stopped yet,
+ // keep playing silence.
+
+ memset(buffer->raw, 0, buffer->size);
+ actualSize = buffer->size;
+ }
+
+ buffer->size = actualSize;
+ } break;
- case AudioTrack::EVENT_STREAM_END:
- ALOGV("callbackwrapper: deliver EVENT_STREAM_END");
- (*me->mCallback)(me, NULL /* buffer */, 0 /* size */,
- me->mCallbackCookie, CB_EVENT_STREAM_END);
- break;
+ case AudioTrack::EVENT_STREAM_END:
+ ALOGV("callbackwrapper: deliver EVENT_STREAM_END");
+ (*me->mCallback)(me, NULL /* buffer */, 0 /* size */,
+ me->mCallbackCookie, CB_EVENT_STREAM_END);
+ break;
- case AudioTrack::EVENT_NEW_IAUDIOTRACK :
- ALOGV("callbackwrapper: deliver EVENT_TEAR_DOWN");
- (*me->mCallback)(me, NULL /* buffer */, 0 /* size */,
- me->mCallbackCookie, CB_EVENT_TEAR_DOWN);
- break;
+ case AudioTrack::EVENT_NEW_IAUDIOTRACK :
+ ALOGV("callbackwrapper: deliver EVENT_TEAR_DOWN");
+ (*me->mCallback)(me, NULL /* buffer */, 0 /* size */,
+ me->mCallbackCookie, CB_EVENT_TEAR_DOWN);
+ break;
- default:
- ALOGE("received unknown event type: %d inside CallbackWrapper !", event);
+ default:
+ ALOGE("received unknown event type: %d inside CallbackWrapper !", event);
+ }
+
+ data->unlock();
+#ifdef QCOM_HARDWARE
}
+#endif
- data->unlock();
+ return;
}
int MediaPlayerService::AudioOutput::getSessionId() const
@@ -1844,6 +1961,13 @@
return NO_ERROR;
}
+#ifdef QCOM_HARDWARE
+ssize_t MediaPlayerService::AudioCache::sampleRate() const
+{
+ return mSampleRate;
+}
+#endif
+
status_t MediaPlayerService::AudioCache::getFramesWritten(uint32_t *written) const
{
if (written == 0) return BAD_VALUE;
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 9c084e1..83b074d 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -1,5 +1,8 @@
/*
**
+** Copyright (c) 2013, The Linux Foundation. All rights reserved.
+** Not a Contribution.
+**
** Copyright 2008, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
@@ -82,6 +85,9 @@
virtual ssize_t channelCount() const;
virtual ssize_t frameSize() const;
virtual uint32_t latency() const;
+#ifdef QCOM_HARDWARE
+ virtual audio_stream_type_t streamType() const;
+#endif
virtual float msecsPerFrame() const;
virtual status_t getPosition(uint32_t *position) const;
virtual status_t getFramesWritten(uint32_t *frameswritten) const;
@@ -116,9 +122,15 @@
void setNextOutput(const sp<AudioOutput>& nextOutput);
void switchToNextOutput();
virtual bool needsTrailingPadding() { return mNextOutput == NULL; }
+
virtual status_t setParameters(const String8& keyValuePairs);
virtual String8 getParameters(const String8& keys);
+#ifdef QCOM_HARDWARE
+ virtual ssize_t sampleRate() const;
+ virtual status_t getTimeStamp(uint64_t *tstamp);
+#endif
+
private:
static void setMinBufferCount();
static void CallbackWrapper(
@@ -217,7 +229,11 @@
void setVolume(float left, float right) {}
virtual status_t setPlaybackRatePermille(int32_t ratePermille) { return INVALID_OPERATION; }
+#ifdef QCOM_HARDWARE
+ virtual ssize_t sampleRate() const;
+#else
uint32_t sampleRate() const { return mSampleRate; }
+#endif
audio_format_t format() const { return mFormat; }
size_t size() const { return mSize; }
status_t wait();
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index f9d9020..831de2c 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -18,6 +18,9 @@
#define LOG_TAG "StagefrightRecorder"
#include <utils/Log.h>
+#ifdef QCOM_HARDWARE
+#include <media/AudioParameter.h>
+#endif
#include "StagefrightRecorder.h"
#include <binder/IPCThreadState.h>
@@ -29,6 +32,10 @@
#include <media/stagefright/AudioSource.h>
#include <media/stagefright/AMRWriter.h>
#include <media/stagefright/AACWriter.h>
+#ifdef QCOM_HARDWARE
+#include <media/stagefright/ExtendedWriter.h>
+#include <media/stagefright/WAVEWriter.h>
+#endif
#include <media/stagefright/CameraSource.h>
#include <media/stagefright/CameraSourceTimeLapse.h>
#include <media/stagefright/MPEG2TSWriter.h>
@@ -42,6 +49,7 @@
#include <camera/ICamera.h>
#include <camera/CameraParameters.h>
#include <gui/Surface.h>
+#include <utils/String8.h>
#include <utils/Errors.h>
#include <sys/types.h>
@@ -49,8 +57,15 @@
#include <unistd.h>
#include <system/audio.h>
+#ifdef QCOM_HARDWARE
+#include "ExtendedUtils.h"
+#ifdef ENABLE_AV_ENHANCEMENTS
+#include <QCMediaDefs.h>
+#endif
+#endif
#include "ARTPWriter.h"
+#include <cutils/properties.h>
namespace android {
@@ -103,6 +118,11 @@
ALOGE("Invalid audio source: %d", as);
return BAD_VALUE;
}
+#ifdef QCOM_HARDWARE
+ if (ExtendedUtils::ShellProp::isAudioDisabled()) {
+ return OK;
+ }
+#endif
if (as == AUDIO_SOURCE_DEFAULT) {
mAudioSource = AUDIO_SOURCE_MIC;
@@ -155,12 +175,36 @@
return BAD_VALUE;
}
+#ifdef QCOM_HARDWARE
+ if (ExtendedUtils::ShellProp::isAudioDisabled()) {
+ return OK;
+ }
+#endif
if (ae == AUDIO_ENCODER_DEFAULT) {
mAudioEncoder = AUDIO_ENCODER_AMR_NB;
} else {
mAudioEncoder = ae;
}
+#ifdef QCOM_HARDWARE
+ if(mAudioEncoder == AUDIO_ENCODER_AAC) {
+ mSampleRate = mSampleRate ? mSampleRate : 48000;
+ mAudioChannels = mAudioChannels ? mAudioChannels : 2;
+ mAudioBitRate = mAudioBitRate ? mAudioBitRate : 156000;
+ } else if(mAudioEncoder == AUDIO_ENCODER_LPCM) {
+ mSampleRate = mSampleRate ? mSampleRate : 48000;
+ mAudioChannels = mAudioChannels ? mAudioChannels : 2;
+ mAudioBitRate = mAudioBitRate ? mAudioBitRate : 4608000;
+ } else if(mAudioEncoder == AUDIO_ENCODER_AMR_WB) {
+ mSampleRate = 16000;
+ mAudioChannels = 1;
+ mAudioBitRate = mAudioBitRate ? mAudioBitRate : 23850;
+ } else {
+ mSampleRate = mSampleRate ? mSampleRate : 8000;
+ mAudioChannels = mAudioChannels ? mAudioChannels : 1;
+ mAudioBitRate = mAudioBitRate ? mAudioBitRate : 12200;
+ }
+#endif
return OK;
}
@@ -329,7 +373,11 @@
status_t StagefrightRecorder::setParamAudioNumberOfChannels(int32_t channels) {
ALOGV("setParamAudioNumberOfChannels: %d", channels);
+#ifdef QCOM_HARDWARE
+ if (channels != 1 && channels != 2 && channels != 6) {
+#else
if (channels <= 0 || channels >= 3) {
+#endif
ALOGE("Invalid number of audio channels: %d", channels);
return BAD_VALUE;
}
@@ -416,6 +464,11 @@
ALOGW("Target file size (%lld bytes) is too small to be respected", bytes);
}
+ if (bytes >= 0xffffffffLL) {
+ ALOGW("Target file size (%lld bytes) too larger than supported, clip to 4GB", bytes);
+ bytes = 0xffffffffLL;
+ }
+
mMaxFileSizeBytes = bytes;
return OK;
}
@@ -739,7 +792,18 @@
}
status_t StagefrightRecorder::prepare() {
- return OK;
+ ALOGV(" %s E", __func__ );
+
+ if(mVideoSource != VIDEO_SOURCE_LIST_END && mVideoEncoder != VIDEO_ENCODER_LIST_END && mVideoHeight && mVideoWidth && /*Video recording*/
+ (mMaxFileDurationUs <=0 || /*Max duration is not set*/
+ (mVideoHeight * mVideoWidth < 720 * 1280 && mMaxFileDurationUs > 30*60*1000*1000) ||
+ (mVideoHeight * mVideoWidth >= 720 * 1280 && mMaxFileDurationUs > 10*60*1000*1000))) {
+ /*Above Check can be further optimized for lower resolutions to reduce file size*/
+ ALOGV("File is huge so setting 64 bit file offsets");
+ setParam64BitFileOffset(true);
+ }
+ ALOGV(" %s X", __func__ );
+ return OK;
}
status_t StagefrightRecorder::start() {
@@ -779,6 +843,16 @@
status = startMPEG2TSRecording();
break;
+#ifdef QCOM_HARDWARE
+#ifdef ENABLE_AV_ENHANCEMENTS
+ case OUTPUT_FORMAT_QCP:
+ status = startExtendedRecording( );
+ break;
+#endif
+ case OUTPUT_FORMAT_WAVE:
+ status = startWAVERecording( );
+ break;
+#endif
default:
ALOGE("Unsupported output file format: %d", mOutputFormat);
status = UNKNOWN_ERROR;
@@ -803,6 +877,54 @@
}
sp<MediaSource> StagefrightRecorder::createAudioSource() {
+#ifdef QCOM_HARDWARE
+ bool tunneledSource = false;
+ const char *tunnelMime;
+ {
+ AudioParameter param;
+ String8 key("tunneled-input-formats");
+ param.add( key, String8("get") );
+ String8 valueStr = AudioSystem::getParameters( 0, param.toString());
+ AudioParameter result(valueStr);
+ int value;
+ if ( mAudioEncoder == AUDIO_ENCODER_AMR_NB &&
+ result.getInt(String8("AMR"),value) == NO_ERROR ) {
+ tunneledSource = true;
+ tunnelMime = MEDIA_MIMETYPE_AUDIO_AMR_NB;
+ }
+#ifdef ENABLE_AV_ENHANCEMENTS
+ else if ( mAudioEncoder == AUDIO_ENCODER_QCELP &&
+ result.getInt(String8("QCELP"),value) == NO_ERROR ) {
+ tunneledSource = true;
+ tunnelMime = MEDIA_MIMETYPE_AUDIO_QCELP;
+ }
+ else if ( mAudioEncoder == AUDIO_ENCODER_EVRC &&
+ result.getInt(String8("EVRC"),value) == NO_ERROR ) {
+ tunneledSource = true;
+ tunnelMime = MEDIA_MIMETYPE_AUDIO_EVRC;
+ }
+#endif
+ else if ( mAudioEncoder == AUDIO_ENCODER_AMR_WB &&
+ result.getInt(String8("AWB"),value) == NO_ERROR ) {
+ tunneledSource = true;
+ tunnelMime = MEDIA_MIMETYPE_AUDIO_AMR_WB;
+ }
+ }
+ if ( tunneledSource ) {
+ ALOGD("tunnel recording");
+ sp<AudioSource> audioSource = NULL;
+ sp<MetaData> meta = new MetaData;
+ meta->setInt32(kKeyChannelCount, mAudioChannels);
+ meta->setInt32(kKeySampleRate, mSampleRate);
+ meta->setInt32(kKeyBitRate, mAudioBitRate);
+ if (mAudioTimeScale > 0) {
+ meta->setInt32(kKeyTimeScale, mAudioTimeScale);
+ }
+ meta->setCString( kKeyMIMEType, tunnelMime );
+ audioSource = new AudioSource( mAudioSource, meta);
+ return audioSource->initCheck( ) == OK ? audioSource : NULL;
+ }
+#endif
sp<AudioSource> audioSource =
new AudioSource(
mAudioSource,
@@ -819,6 +941,11 @@
sp<MetaData> encMeta = new MetaData;
const char *mime;
switch (mAudioEncoder) {
+#ifdef QCOM_HARDWARE
+ case AUDIO_ENCODER_LPCM:
+ mime = MEDIA_MIMETYPE_AUDIO_RAW;
+ break;
+#endif
case AUDIO_ENCODER_AMR_NB:
case AUDIO_ENCODER_DEFAULT:
mime = MEDIA_MIMETYPE_AUDIO_AMR_NB;
@@ -838,6 +965,14 @@
mime = MEDIA_MIMETYPE_AUDIO_AAC;
encMeta->setInt32(kKeyAACProfile, OMX_AUDIO_AACObjectELD);
break;
+#ifdef ENABLE_AV_ENHANCEMENTS
+ case AUDIO_ENCODER_EVRC:
+ mime = MEDIA_MIMETYPE_AUDIO_EVRC;
+ break;
+ case AUDIO_ENCODER_QCELP:
+ mime = MEDIA_MIMETYPE_AUDIO_QCELP;
+ break;
+#endif
default:
ALOGE("Unknown audio encoder: %d", mAudioEncoder);
@@ -859,9 +994,30 @@
OMXClient client;
CHECK_EQ(client.connect(), (status_t)OK);
+#ifdef ENABLE_AV_ENHANCEMENTS
+ sp<MediaSource> audioEncoder;
+ if (ExtendedUtils::UseQCHWAACEncoder(mAudioEncoder,mAudioChannels,mAudioBitRate,mSampleRate)) {
+ ALOGV("use QCOM HW AAC encoder");
+ audioEncoder = OMXCodec::Create(client.interface(), encMeta,
+ true /* createEncoder */, audioSource,"OMX.qcom.audio.encoder.aac",OMXCodec::kHardwareCodecsOnly );
+ } else {
+ audioEncoder = OMXCodec::Create(client.interface(), encMeta,
+ true /* createEncoder */, audioSource);
+ }
+#else
sp<MediaSource> audioEncoder =
OMXCodec::Create(client.interface(), encMeta,
true /* createEncoder */, audioSource);
+#endif
+#ifdef QCOM_HARDWARE
+ if (audioEncoder == NULL) {
+ ALOGD("No encoder is needed, use the AudioSource directly as the MediaSource for LPCM format");
+ audioEncoder = audioSource;
+ }
+ if (mAudioSourceNode != NULL) {
+ mAudioSourceNode.clear();
+ }
+#endif
mAudioSourceNode = audioSource;
return audioEncoder;
@@ -898,14 +1054,32 @@
mAudioEncoder);
return BAD_VALUE;
}
+ if (mSampleRate != 8000) {
+ ALOGE("Invalid sampling rate %d used for AMRNB recording",
+ mSampleRate);
+ return BAD_VALUE;
+ }
} else { // mOutputFormat must be OUTPUT_FORMAT_AMR_WB
if (mAudioEncoder != AUDIO_ENCODER_AMR_WB) {
ALOGE("Invlaid encoder %d used for AMRWB recording",
mAudioEncoder);
return BAD_VALUE;
}
+#if 0
+//This check breaks android.media.cts.MediaRecorderTest#testRecordingAudioInRawFormats, which is hardwired to test 8kHz
+ if (mSampleRate != 16000) {
+ ALOGE("Invalid sample rate %d used for AMRWB recording",
+ mSampleRate);
+ return BAD_VALUE;
+ }
+#endif
}
+ if (mAudioChannels != 1) {
+ ALOGE("Invalid number of audio channels %d used for amr recording",
+ mAudioChannels);
+ return BAD_VALUE;
+ }
mWriter = new AMRWriter(mOutputFd);
status_t status = startRawAudioRecording();
if (status != OK) {
@@ -915,6 +1089,21 @@
return status;
}
+#ifdef QCOM_HARDWARE
+status_t StagefrightRecorder::startWAVERecording() {
+ CHECK(mOutputFormat == OUTPUT_FORMAT_WAVE);
+ CHECK(mAudioEncoder == AUDIO_ENCODER_LPCM);
+ CHECK(mAudioSource != AUDIO_SOURCE_CNT);
+ mWriter = new WAVEWriter(mOutputFd);
+ status_t status = startRawAudioRecording();
+ if (status != OK) {
+ mWriter.clear();
+ mWriter = NULL;
+ }
+ return status;
+}
+#endif
+
status_t StagefrightRecorder::startRawAudioRecording() {
if (mAudioSource >= AUDIO_SOURCE_CNT) {
ALOGE("Invalid audio source: %d", mAudioSource);
@@ -1427,6 +1616,17 @@
if (mVideoTimeScale > 0) {
enc_meta->setInt32(kKeyTimeScale, mVideoTimeScale);
}
+
+#ifdef QCOM_HARDWARE
+ status_t retVal = ExtendedUtils::HFR::reCalculateFileDuration(
+ meta, enc_meta, mMaxFileDurationUs, mFrameRate, mVideoEncoder);
+ if(retVal != OK) {
+ return retVal;
+ }
+
+ ExtendedUtils::ShellProp::setEncoderProfile(mVideoEncoder, mVideoEncoderProfile);
+#endif
+
if (mVideoEncoderProfile != -1) {
enc_meta->setInt32(kKeyVideoProfile, mVideoEncoderProfile);
}
@@ -1479,6 +1679,9 @@
case AUDIO_ENCODER_AAC:
case AUDIO_ENCODER_HE_AAC:
case AUDIO_ENCODER_AAC_ELD:
+#ifdef QCOM_HARDWARE
+ case AUDIO_ENCODER_LPCM:
+#endif
break;
default:
@@ -1641,6 +1844,13 @@
mOutputFd = -1;
}
+#ifdef QCOM_HARDWARE
+ if (mAudioSourceNode != NULL) {
+ mAudioSourceNode.clear();
+ mAudioSourceNode = NULL;
+ }
+#endif
+
if (mStarted) {
mStarted = false;
@@ -1682,9 +1892,15 @@
mVideoHeight = 144;
mFrameRate = -1;
mVideoBitRate = 192000;
+#ifdef QCOM_HARDWARE
+ mSampleRate = 0;
+ mAudioChannels = 0;
+ mAudioBitRate = 0;
+#else
mSampleRate = 8000;
mAudioChannels = 1;
mAudioBitRate = 12200;
+#endif
mInterleaveDurationUs = 0;
mIFramesIntervalSec = 1;
mAudioSourceNode = 0;
@@ -1796,4 +2012,39 @@
::write(fd, result.string(), result.size());
return OK;
}
+#ifdef ENABLE_AV_ENHANCEMENTS
+status_t StagefrightRecorder::startExtendedRecording() {
+ CHECK(mOutputFormat == OUTPUT_FORMAT_QCP);
+ if (mSampleRate != 8000) {
+ ALOGE("Invalid sampling rate %d used for recording",
+ mSampleRate);
+ return BAD_VALUE;
+ }
+ if (mAudioChannels != 1) {
+ ALOGE("Invalid number of audio channels %d used for recording",
+ mAudioChannels);
+ return BAD_VALUE;
+ }
+ if (mAudioSource >= AUDIO_SOURCE_CNT) {
+ ALOGE("Invalid audio source: %d", mAudioSource);
+ return BAD_VALUE;
+ }
+ sp<MediaSource> audioEncoder = createAudioSource();
+ if (audioEncoder == NULL) {
+ ALOGE("AudioEncoder NULL");
+ return UNKNOWN_ERROR;
+ }
+ mWriter = new ExtendedWriter(dup(mOutputFd));
+ mWriter->addSource(audioEncoder);
+ if (mMaxFileDurationUs != 0) {
+ mWriter->setMaxFileDuration(mMaxFileDurationUs);
+ }
+ if (mMaxFileSizeBytes != 0) {
+ mWriter->setMaxFileSize(mMaxFileSizeBytes);
+ }
+ mWriter->setListener(mListener);
+ mWriter->start();
+ return OK;
+}
+#endif
} // namespace android
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index 31f09e0..2e834b4 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -135,6 +135,9 @@
status_t startMPEG4Recording();
status_t startAMRRecording();
status_t startAACRecording();
+#ifdef QCOM_HARDWARE
+ status_t startWAVERecording();
+#endif
status_t startRawAudioRecording();
status_t startRTPRecording();
status_t startMPEG2TSRecording();
@@ -191,6 +194,9 @@
StagefrightRecorder(const StagefrightRecorder &);
StagefrightRecorder &operator=(const StagefrightRecorder &);
+#ifdef ENABLE_AV_ENHANCEMENTS
+ status_t startExtendedRecording();
+#endif
};
} // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 2423fd5..0357a68 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -25,6 +25,9 @@
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/ACodec.h>
#include <media/stagefright/MediaDefs.h>
+#ifdef QCOM_HARDWARE
+#include <media/stagefright/ExtendedCodec.h>
+#endif
namespace android {
@@ -57,6 +60,20 @@
mCSD.push(csd);
}
+#ifdef QCOM_HARDWARE
+ sp<ABuffer> extendedCSD = ExtendedCodec::getRawCodecSpecificData(format);
+ if (extendedCSD != NULL) {
+ ALOGV("pushing extended CSD of size %d", extendedCSD->size());
+ mCSD.push(extendedCSD);
+ }
+
+ sp<ABuffer> aacCSD = ExtendedCodec::getAacCodecSpecificData(format);
+ if (aacCSD != NULL) {
+ ALOGV("pushing AAC CSD of size %d", aacCSD->size());
+ mCSD.push(aacCSD);
+ }
+#endif
+
if (mNativeWindow != NULL) {
format->setObject("native-window", mNativeWindow);
}
diff --git a/media/libnbaio/AudioStreamOutSink.cpp b/media/libnbaio/AudioStreamOutSink.cpp
index e4341d7..d5937b2 100644
--- a/media/libnbaio/AudioStreamOutSink.cpp
+++ b/media/libnbaio/AudioStreamOutSink.cpp
@@ -72,11 +72,14 @@
if (NULL == mStream)
return INVALID_OPERATION;
-
+#ifndef ICS_AUDIO_BLOB
if (NULL == mStream->get_next_write_timestamp)
return INVALID_OPERATION;
return mStream->get_next_write_timestamp(mStream, timestamp);
+#else
+ return INVALID_OPERATION;
+#endif
}
status_t AudioStreamOutSink::getTimestamp(AudioTimestamp& timestamp)
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
old mode 100644
new mode 100755
index 9276818..03a8ac3
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -32,12 +32,26 @@
#include <media/stagefright/NativeWindowWrapper.h>
#include <media/stagefright/OMXClient.h>
#include <media/stagefright/OMXCodec.h>
+#ifdef QCOM_HARDWARE
+#include <media/stagefright/ExtendedCodec.h>
+#endif
#include <media/hardware/HardwareAPI.h>
#include <OMX_Component.h>
+#ifdef USE_SAMSUNG_COLORFORMAT
+#include <sec_format.h>
+#endif
+
+#ifdef USE_TI_CUSTOM_DOMX
+#include <OMX_TI_IVCommon.h>
+#endif
+
#include "include/avc_utils.h"
+#ifdef QCOM_HARDWARE
+#include "include/ExtendedUtils.h"
+#endif
namespace android {
@@ -371,8 +385,14 @@
mDequeueCounter(0),
mStoreMetaDataInOutputBuffers(false),
mMetaDataBuffersToSubmit(0),
+#ifdef QCOM_HARDWARE
+ mRepeatFrameDelayUs(-1ll),
+ mMaxPtsGapUs(-1l),
+ mInSmoothStreamingMode(false) {
+#else
mRepeatFrameDelayUs(-1ll),
mMaxPtsGapUs(-1l) {
+#endif
mUninitializedState = new UninitializedState(this);
mLoadedState = new LoadedState(this);
mLoadedToIdleState = new LoadedToIdleState(this);
@@ -574,11 +594,22 @@
return err;
}
+#ifdef USE_SAMSUNG_COLORFORMAT
+ OMX_COLOR_FORMATTYPE eNativeColorFormat = def.format.video.eColorFormat;
+ setNativeWindowColorFormat(eNativeColorFormat);
+
+ err = native_window_set_buffers_geometry(
+ mNativeWindow.get(),
+ def.format.video.nFrameWidth,
+ def.format.video.nFrameHeight,
+ eNativeColorFormat);
+#else
err = native_window_set_buffers_geometry(
mNativeWindow.get(),
def.format.video.nFrameWidth,
def.format.video.nFrameHeight,
def.format.video.eColorFormat);
+#endif
if (err != 0) {
ALOGE("native_window_set_buffers_geometry failed: %s (%d)",
@@ -792,6 +823,25 @@
return OK;
}
+#ifdef USE_SAMSUNG_COLORFORMAT
+void ACodec::setNativeWindowColorFormat(OMX_COLOR_FORMATTYPE &eNativeColorFormat)
+{
+ // In case of Samsung decoders, we set proper native color format for the Native Window
+ if (!strcasecmp(mComponentName.c_str(), "OMX.SEC.AVC.Decoder")
+ || !strcasecmp(mComponentName.c_str(), "OMX.SEC.FP.AVC.Decoder")) {
+ switch (eNativeColorFormat) {
+ case OMX_COLOR_FormatYUV420SemiPlanar:
+ eNativeColorFormat = (OMX_COLOR_FORMATTYPE)HAL_PIXEL_FORMAT_YCbCr_420_SP;
+ break;
+ case OMX_COLOR_FormatYUV420Planar:
+ default:
+ eNativeColorFormat = (OMX_COLOR_FORMATTYPE)HAL_PIXEL_FORMAT_YCbCr_420_P;
+ break;
+ }
+ }
+}
+#endif
+
status_t ACodec::cancelBufferToNativeWindow(BufferInfo *info) {
CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_US);
@@ -955,6 +1005,10 @@
"audio_decoder.amrnb", "audio_encoder.amrnb" },
{ MEDIA_MIMETYPE_AUDIO_AMR_WB,
"audio_decoder.amrwb", "audio_encoder.amrwb" },
+#ifdef ENABLE_AV_ENHANCEMENTS
+ { MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS,
+ "audio_decoder.amrwbplus", "audio_encoder.amrwbplus" },
+#endif
{ MEDIA_MIMETYPE_AUDIO_AAC,
"audio_decoder.aac", "audio_encoder.aac" },
{ MEDIA_MIMETYPE_AUDIO_VORBIS,
@@ -992,7 +1046,11 @@
}
if (i == kNumMimeToRole) {
+#ifdef QCOM_HARDWARE
+ return ExtendedCodec::setSupportedRole(mOMX, mNode, isEncoder, mime);
+#else
return ERROR_UNSUPPORTED;
+#endif
}
const char *role =
@@ -1123,10 +1181,19 @@
mStoreMetaDataInOutputBuffers = false;
mIsConfiguredForAdaptivePlayback = false;
if (!encoder && video && haveNativeWindow) {
- err = mOMX->storeMetaDataInBuffers(mNode, kPortIndexOutput, OMX_TRUE);
- if (err != OK) {
- ALOGE("[%s] storeMetaDataInBuffers failed w/ err %d",
- mComponentName.c_str(), err);
+ int32_t preferAdaptive = 0;
+ if (msg->findInt32("prefer-adaptive-playback", &preferAdaptive)
+ && preferAdaptive == 1) {
+ ALOGI("[%s] Adaptive playback preferred", mComponentName.c_str());
+ } else {
+ preferAdaptive = 0;
+ err = mOMX->storeMetaDataInBuffers(mNode, kPortIndexOutput, OMX_TRUE);
+ }
+ if (err != OK || preferAdaptive) {
+ if (!preferAdaptive) {
+ ALOGE("[%s] storeMetaDataInBuffers failed w/ err %d",
+ mComponentName.c_str(), err);
+ }
// if adaptive playback has been requested, try JB fallback
// NOTE: THIS FALLBACK MECHANISM WILL BE REMOVED DUE TO ITS
@@ -1158,7 +1225,7 @@
if (canDoAdaptivePlayback &&
msg->findInt32("max-width", &maxWidth) &&
msg->findInt32("max-height", &maxHeight)) {
- ALOGV("[%s] prepareForAdaptivePlayback(%ldx%ld)",
+ ALOGI("[%s] prepareForAdaptivePlayback(%ldx%ld)",
mComponentName.c_str(), maxWidth, maxHeight);
err = mOMX->prepareForAdaptivePlayback(
@@ -1168,6 +1235,14 @@
mComponentName.c_str(), err);
mIsConfiguredForAdaptivePlayback = (err == OK);
}
+ // if Adaptive mode was tried first and codec failed it, try dynamic mode
+ if (err != OK && preferAdaptive) {
+ err = mOMX->storeMetaDataInBuffers(mNode, kPortIndexOutput, OMX_TRUE);
+ if (err != OK) {
+ ALOGE("[%s] storeMetaDataInBuffers failed w/ err %d",
+ mComponentName.c_str(), err);
+ }
+ }
// allow failure
err = OK;
} else {
@@ -1176,6 +1251,9 @@
mIsConfiguredForAdaptivePlayback = true;
}
+ ALOGI("DRC Mode: %s",(mStoreMetaDataInOutputBuffers ? "Dynamic Buffer Mode" :
+ (mIsConfiguredForAdaptivePlayback ? "Adaptive Mode" : "Port Reconfig Mode")));
+
int32_t push;
if (msg->findInt32("push-blank-buffers-on-shutdown", &push)
&& push != 0) {
@@ -1195,6 +1273,12 @@
err = setupVideoDecoder(mime, width, height);
}
}
+#ifdef QCOM_HARDWARE
+ if (err == OK) {
+ const char* componentName = mComponentName.c_str();
+ ExtendedCodec::configureVideoDecoder(msg, mime, mOMX, 0, mNode, componentName);
+ }
+#endif
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
int32_t numChannels, sampleRate;
if (!msg->findInt32("channel-count", &numChannels)
@@ -1277,6 +1361,21 @@
} else {
err = setupRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
}
+#ifdef QCOM_HARDWARE
+ } else {
+ if (encoder) {
+ int32_t numChannels, sampleRate;
+ if (msg->findInt32("channel-count", &numChannels)
+ && msg->findInt32("sample-rate", &sampleRate)) {
+ setupRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
+ }
+ }
+ err = ExtendedCodec::setAudioFormat(
+ msg, mime, mOMX, mNode, mIsEncoder);
+ if(err != OK) {
+ return err;
+ }
+#endif
}
if (err != OK) {
@@ -1755,7 +1854,11 @@
status_t err = GetVideoCodingTypeFromMime(mime, &compressionFormat);
if (err != OK) {
- return err;
+#ifdef QCOM_HARDWARE
+ err = ExtendedCodec::setVideoOutputFormat(mime, &compressionFormat);
+ if (err != OK)
+#endif
+ return err;
}
err = setVideoPortFormatType(
@@ -1785,6 +1888,11 @@
return err;
}
+#ifdef QCOM_HARDWARE
+ ExtendedCodec::enableSmoothStreaming(
+ mOMX, mNode, &mInSmoothStreamingMode, mComponentName.c_str());
+#endif
+
return OK;
}
@@ -1878,7 +1986,15 @@
err = GetVideoCodingTypeFromMime(mime, &compressionFormat);
if (err != OK) {
- return err;
+#ifdef QCOM_HARDWARE
+ err = ExtendedCodec::setVideoInputFormat(mime, &compressionFormat);
+ if (err != OK) {
+ ALOGE("Not a supported video mime type: %s", mime);
+#endif
+ return err;
+#ifdef QCOM_HARDWARE
+ }
+#endif
}
err = setVideoPortFormatType(
@@ -2558,6 +2674,11 @@
rect.nTop,
rect.nLeft + rect.nWidth,
rect.nTop + rect.nHeight);
+#ifdef QCOM_HARDWARE
+ reply->setInt32(
+ "color-format",
+ (int)(videoDef->eColorFormat));
+#endif
}
}
break;
@@ -2674,7 +2795,26 @@
}
default:
+ {
+#ifdef QCOM_HARDWARE
+ AString mimeType;
+ status_t err = ExtendedCodec::handleSupportedAudioFormats(
+ audioDef->eEncoding, &mimeType);
+ if (err == OK) {
+ int channelCount;
+ err = ExtendedCodec::getSupportedAudioFormatInfo(
+ &mimeType,
+ mOMX,
+ mNode,
+ kPortIndexOutput,
+ &channelCount);
+ notify->setString("mime", mimeType.c_str());
+ notify->setInt32("channel-count", channelCount);
+ break;
+ }
+#endif
TRESPASS();
+ }
}
break;
}
@@ -3429,6 +3569,15 @@
android_native_rect_t crop;
if (msg->findRect("crop",
&crop.left, &crop.top, &crop.right, &crop.bottom)) {
+#ifdef QCOM_HARDWARE
+ if (mCodec->mInSmoothStreamingMode) {
+ OMX_COLOR_FORMATTYPE eColorFormat = OMX_COLOR_FormatUnused;
+ CHECK(msg->findInt32("color-format", (int32_t*)&eColorFormat));
+ ExtendedUtils::updateNativeWindowBufferGeometry(
+ mCodec->mNativeWindow.get(), crop.right,
+ crop.bottom, eColorFormat);
+ }
+#endif
CHECK_EQ(0, native_window_set_crop(
mCodec->mNativeWindow.get(), &crop));
}
@@ -3641,6 +3790,9 @@
++matchIndex) {
componentName = matchingCodecs.itemAt(matchIndex).mName.string();
quirks = matchingCodecs.itemAt(matchIndex).mQuirks;
+#ifdef QCOM_HARDWARE
+ ExtendedCodec::overrideComponentName(quirks, msg, &componentName);
+#endif
pid_t tid = androidGetTid();
int prevPriority = androidGetThreadPriority(tid);
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 6a2a696..c819046 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -3,6 +3,10 @@
include frameworks/av/media/libstagefright/codecs/common/Config.mk
+ifeq ($(BOARD_HTC_3D_SUPPORT),true)
+ LOCAL_CFLAGS += -DHTC_3D_SUPPORT
+endif
+
LOCAL_SRC_FILES:= \
ACodec.cpp \
AACExtractor.cpp \
@@ -52,6 +56,7 @@
Utils.cpp \
VBRISeeker.cpp \
WAVExtractor.cpp \
+ WAVEWriter.cpp \
WVMExtractor.cpp \
XINGSeeker.cpp \
avc_utils.cpp \
@@ -61,12 +66,48 @@
LOCAL_C_INCLUDES:= \
$(TOP)/frameworks/av/include/media/stagefright/timedtext \
$(TOP)/frameworks/native/include/media/hardware \
- $(TOP)/frameworks/native/include/media/openmax \
$(TOP)/frameworks/native/services/connectivitymanager \
$(TOP)/external/flac/include \
$(TOP)/external/tremolo \
$(TOP)/external/openssl/include \
+ifneq ($(TI_CUSTOM_DOMX_PATH),)
+LOCAL_C_INCLUDES += $(TI_CUSTOM_DOMX_PATH)/omx_core/inc
+LOCAL_CPPFLAGS += -DUSE_TI_CUSTOM_DOMX
+else
+LOCAL_C_INCLUDES += $(TOP)/frameworks/native/include/media/openmax
+endif
+
+ifneq ($(filter caf bfam,$(TARGET_QCOM_AUDIO_VARIANT)),)
+ ifeq ($(BOARD_USES_ALSA_AUDIO),true)
+ LOCAL_SRC_FILES += LPAPlayerALSA.cpp
+ ifeq ($(call is-chipset-in-board-platform,msm8960),true)
+ LOCAL_SRC_FILES += TunnelPlayer.cpp
+ LOCAL_CFLAGS += -DUSE_TUNNEL_MODE
+ LOCAL_CFLAGS += -DTUNNEL_MODE_SUPPORTS_AMRWB
+ endif
+ ifeq ($(call is-chipset-in-board-platform,msm8974),true)
+ LOCAL_SRC_FILES += TunnelPlayer.cpp
+ LOCAL_CFLAGS += -DUSE_TUNNEL_MODE
+ endif
+ ifeq ($(NO_TUNNEL_MODE_FOR_MULTICHANNEL),true)
+ LOCAL_CFLAGS += -DNO_TUNNEL_MODE_FOR_MULTICHANNEL
+ endif
+ else
+ LOCAL_SRC_FILES += LPAPlayer.cpp
+ LOCAL_CFLAGS += -DLEGACY_LPA
+ endif
+ LOCAL_CFLAGS += -DQCOM_ENHANCED_AUDIO -DUSE_LPA_MODE
+endif
+
+ifneq ($(TARGET_QCOM_MEDIA_VARIANT),)
+LOCAL_C_INCLUDES += \
+ $(TOP)/hardware/qcom/media-$(TARGET_QCOM_MEDIA_VARIANT)/mm-core/inc
+else
+LOCAL_C_INCLUDES += \
+ $(TOP)/hardware/qcom/media/mm-core/inc
+endif
+
LOCAL_SHARED_LIBRARIES := \
libbinder \
libcamera_client \
@@ -93,6 +134,7 @@
LOCAL_STATIC_LIBRARIES := \
libstagefright_color_conversion \
+ libstagefright_mp3dec \
libstagefright_aacenc \
libstagefright_matroska \
libstagefright_timedtext \
@@ -103,6 +145,22 @@
libFLAC \
libmedia_helper
+
+LOCAL_SRC_FILES += ExtendedCodec.cpp ExtendedExtractor.cpp ExtendedUtils.cpp
+
+ifeq ($(TARGET_ENABLE_QC_AV_ENHANCEMENTS),true)
+ LOCAL_CFLAGS += -DENABLE_AV_ENHANCEMENTS
+ LOCAL_SRC_FILES += ExtendedMediaDefs.cpp ExtendedWriter.cpp
+
+ ifneq ($(TARGET_QCOM_MEDIA_VARIANT),)
+ LOCAL_C_INCLUDES += \
+ $(TOP)/hardware/qcom/media-$(TARGET_QCOM_MEDIA_VARIANT)/mm-core/inc
+ else
+ LOCAL_C_INCLUDES += \
+ $(TOP)/hardware/qcom/media/mm-core/inc
+ endif
+endif #TARGET_ENABLE_AV_ENHANCEMENTS
+
LOCAL_SRC_FILES += \
chromium_http_stub.cpp
LOCAL_CPPFLAGS += -DCHROMIUM_AVAILABLE=1
@@ -118,6 +176,26 @@
LOCAL_CFLAGS += -Wno-multichar
+ifeq ($(BOARD_USE_SAMSUNG_COLORFORMAT), true)
+LOCAL_CFLAGS += -DUSE_SAMSUNG_COLORFORMAT
+
+# Include native color format header path
+LOCAL_C_INCLUDES += \
+ $(TOP)/hardware/samsung/exynos4/hal/include \
+ $(TOP)/hardware/samsung/exynos4/include
+
+endif
+
+ifeq ($(BOARD_USE_TI_DUCATI_H264_PROFILE), true)
+LOCAL_CFLAGS += -DUSE_TI_DUCATI_H264_PROFILE
+endif
+
+ifdef DOLBY_UDC
+ LOCAL_CFLAGS += -DDOLBY_UDC
+endif #DOLBY_UDC
+ifdef DOLBY_UDC_MULTICHANNEL
+ LOCAL_CFLAGS += -DDOLBY_UDC_MULTICHANNEL
+endif #DOLBY_UDC_MULTICHANNEL
LOCAL_MODULE:= libstagefright
LOCAL_MODULE_TAGS := optional
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 05ee34e..c07d79e 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -1,4 +1,6 @@
/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -36,8 +38,7 @@
AudioPlayer::AudioPlayer(
const sp<MediaPlayerBase::AudioSink> &audioSink,
- uint32_t flags,
- AwesomePlayer *observer)
+ uint32_t flags, AwesomePlayer *observer)
: mInputBuffer(NULL),
mSampleRate(0),
mLatencyUs(0),
@@ -51,6 +52,9 @@
mFinalStatus(OK),
mSeekTimeUs(0),
mStarted(false),
+#ifdef QCOM_HARDWARE
+ mSourcePaused(false),
+#endif
mIsFirstBuffer(false),
mFirstBufferResult(OK),
mFirstBuffer(NULL),
@@ -79,6 +83,9 @@
status_t err;
if (!sourceAlreadyStarted) {
+#ifdef QCOM_HARDWARE
+ mSourcePaused = false;
+#endif
err = mSource->start();
if (err != OK) {
@@ -253,7 +260,6 @@
void AudioPlayer::pause(bool playPendingSamples) {
CHECK(mStarted);
-
if (playPendingSamples) {
if (mAudioSink.get() != NULL) {
mAudioSink->stop();
@@ -274,10 +280,23 @@
}
mPlaying = false;
+#ifdef QCOM_HARDWARE
+ CHECK(mSource != NULL);
+ if (mSource->pause() == OK) {
+ mSourcePaused = true;
+ }
+#endif
}
status_t AudioPlayer::resume() {
CHECK(mStarted);
+#ifdef QCOM_HARDWARE
+ CHECK(mSource != NULL);
+ if (mSourcePaused == true) {
+ mSourcePaused = false;
+ mSource->start();
+ }
+#endif
status_t err;
if (mAudioSink.get() != NULL) {
@@ -339,7 +358,9 @@
mInputBuffer->release();
mInputBuffer = NULL;
}
-
+#ifdef QCOM_HARDWARE
+ mSourcePaused = false;
+#endif
mSource->stop();
// The following hack is necessary to ensure that the OMX
@@ -415,6 +436,13 @@
MediaPlayerBase::AudioSink::cb_event_t event) {
AudioPlayer *me = (AudioPlayer *)cookie;
+#ifdef QCOM_HARDWARE
+ if (buffer == NULL) {
+ //Not applicable for AudioPlayer
+ ALOGE("This indicates the event underrun case for LPA/Tunnel");
+ return 0;
+ }
+#endif
switch(event) {
case MediaPlayerBase::AudioSink::CB_EVENT_FILL_BUFFER:
return me->fillBuffer(buffer, size);
@@ -668,11 +696,11 @@
{
Mutex::Autolock autoLock(mLock);
mNumFramesPlayed += size_done / mFrameSize;
- mNumFramesPlayedSysTimeUs = ALooper::GetNowUs();
if (mReachedEOS) {
mPinnedTimeUs = mNumFramesPlayedSysTimeUs;
} else {
+ mNumFramesPlayedSysTimeUs = ALooper::GetNowUs();
mPinnedTimeUs = -1ll;
}
}
@@ -691,10 +719,14 @@
int64_t AudioPlayer::getRealTimeUs() {
Mutex::Autolock autoLock(mLock);
if (useOffload()) {
+ int64_t playPosition = 0;
if (mSeeking) {
return mSeekTimeUs;
}
- mPositionTimeRealUs = getOutputPlayPositionUs_l();
+ playPosition = getOutputPlayPositionUs_l();
+ if(!mReachedEOS)
+ mPositionTimeRealUs = playPosition;
+ mPositionTimeMediaUs = mPositionTimeRealUs;
return mPositionTimeRealUs;
}
@@ -711,14 +743,21 @@
// compensate using system time.
int64_t diffUs;
if (mPinnedTimeUs >= 0ll) {
- diffUs = mPinnedTimeUs;
+ if(mReachedEOS)
+ diffUs = ALooper::GetNowUs();
+ else
+ diffUs = mPinnedTimeUs;
+
} else {
diffUs = ALooper::GetNowUs();
}
diffUs -= mNumFramesPlayedSysTimeUs;
- return result + diffUs;
+ if(result + diffUs <= mPositionTimeRealUs)
+ return result + diffUs;
+ else
+ return mPositionTimeRealUs;
}
int64_t AudioPlayer::getOutputPlayPositionUs_l()
@@ -753,12 +792,17 @@
Mutex::Autolock autoLock(mLock);
if (useOffload()) {
+ int64_t playPosition = 0;
if (mSeeking) {
return mSeekTimeUs;
}
- mPositionTimeRealUs = getOutputPlayPositionUs_l();
- ALOGV("getMediaTimeUs getOutputPlayPositionUs_l() mPositionTimeRealUs %lld",
- mPositionTimeRealUs);
+
+ playPosition = getOutputPlayPositionUs_l();
+ if (!mReachedEOS)
+ mPositionTimeRealUs = playPosition;
+ ALOGV("getMediaTimeUs getOutputPlayPositionUs_l() playPosition = %lld,\
+ mPositionTimeRealUs %lld", playPosition, mPositionTimeRealUs);
+ mPositionTimeMediaUs = mPositionTimeRealUs;
return mPositionTimeRealUs;
}
@@ -781,7 +825,11 @@
Mutex::Autolock autoLock(mLock);
if (useOffload()) {
- mPositionTimeRealUs = getOutputPlayPositionUs_l();
+ int64_t playPosition = 0;
+ playPosition = getOutputPlayPositionUs_l();
+ if(!mReachedEOS)
+ mPositionTimeRealUs = playPosition;
+ mPositionTimeMediaUs = mPositionTimeRealUs;
*realtime_us = mPositionTimeRealUs;
*mediatime_us = mPositionTimeRealUs;
} else {
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index d7223d9..17d7e1b 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -27,9 +27,15 @@
#include <media/stagefright/foundation/ALooper.h>
#include <cutils/properties.h>
#include <stdlib.h>
+#ifdef ENABLE_AV_ENHANCEMENTS
+#include <QCMediaDefs.h>
+#endif
+#include <system/audio.h>
+#define DEFAULT_TUNNEL_BUFFER_COUNT 4
namespace android {
+const static int64_t WaitLockEventTimeOutNs = 1000000000LL;
static void AudioRecordCallbackFunction(int event, void *user, void *info) {
AudioSource *source = (AudioSource *) user;
switch (event) {
@@ -49,23 +55,49 @@
AudioSource::AudioSource(
audio_source_t inputSource, uint32_t sampleRate, uint32_t channelCount)
+#ifdef QCOM_HARDWARE
+ : mRecord(NULL),
+ mStarted(false),
+#else
: mStarted(false),
+#endif
mSampleRate(sampleRate),
mPrevSampleTimeUs(0),
mNumFramesReceived(0),
+#ifdef QCOM_HARDWARE
+ mNumClientOwnedBuffers(0),
+ mFormat(AUDIO_FORMAT_PCM_16_BIT),
+ mMime(MEDIA_MIMETYPE_AUDIO_RAW) {
+#else
mNumClientOwnedBuffers(0) {
+#endif
ALOGV("sampleRate: %d, channelCount: %d", sampleRate, channelCount);
+#ifdef QCOM_HARDWARE
+ CHECK(channelCount == 1 || channelCount == 2 || channelCount == 6);
+#else
CHECK(channelCount == 1 || channelCount == 2);
+#endif
size_t minFrameCount;
status_t status = AudioRecord::getMinFrameCount(&minFrameCount,
sampleRate,
AUDIO_FORMAT_PCM_16_BIT,
audio_channel_in_mask_from_count(channelCount));
+#ifdef QCOM_HARDWARE
+ if ( NO_ERROR != AudioSystem::getInputBufferSize(
+ sampleRate, mFormat, channelCount, (size_t*)&mMaxBufferSize) ) {
+ mMaxBufferSize = kMaxBufferSize;
+ ALOGV("mMaxBufferSize = %d", mMaxBufferSize);
+ }
+#endif
if (status == OK) {
// make sure that the AudioRecord callback never returns more than the maximum
// buffer size
+#ifdef QCOM_HARDWARE
+ int frameCount = mMaxBufferSize / sizeof(int16_t) / channelCount;
+#else
int frameCount = kMaxBufferSize / sizeof(int16_t) / channelCount;
+#endif
// make sure that the AudioRecord total buffer size is large enough
int bufCount = 2;
@@ -76,16 +108,85 @@
mRecord = new AudioRecord(
inputSource, sampleRate, AUDIO_FORMAT_PCM_16_BIT,
audio_channel_in_mask_from_count(channelCount),
+#ifdef QCOM_HARDWARE
+ DEFAULT_TUNNEL_BUFFER_COUNT * mMaxBufferSize / sizeof(int16_t), /* Enable ping-pong buffers */
+#else
bufCount * frameCount,
+#endif
AudioRecordCallbackFunction,
this,
frameCount);
mInitCheck = mRecord->initCheck();
+ mAutoRampStartUs = kAutoRampStartUs;
+ uint32_t playbackLatencyMs = 0;
+ if (AudioSystem::getOutputLatency(&playbackLatencyMs,
+ AUDIO_STREAM_DEFAULT) == OK) {
+ if (2*playbackLatencyMs*1000LL > kAutoRampStartUs) {
+ mAutoRampStartUs = 2*playbackLatencyMs*1000LL;
+ }
+ }
+ ALOGD("Start autoramp from %lld", mAutoRampStartUs);
} else {
mInitCheck = status;
}
}
+#ifdef QCOM_HARDWARE
+AudioSource::AudioSource( audio_source_t inputSource, const sp<MetaData>& meta )
+ : mStarted(false),
+ mPrevSampleTimeUs(0),
+ mNumFramesReceived(0),
+ mNumClientOwnedBuffers(0),
+ mFormat(AUDIO_FORMAT_PCM_16_BIT),
+ mMime(MEDIA_MIMETYPE_AUDIO_RAW) {
+ const char * mime;
+ ALOGE("SK: in AudioSource : inputSource: %d", inputSource);
+ CHECK( meta->findCString( kKeyMIMEType, &mime ) );
+ mMime = mime;
+ int32_t sampleRate = 0; //these are the only supported values
+ int32_t channels = 0; //for the below tunnel formats
+ CHECK( meta->findInt32( kKeyChannelCount, &channels ) );
+ CHECK( meta->findInt32( kKeySampleRate, &sampleRate ) );
+ int32_t frameSize = -1;
+ mSampleRate = sampleRate;
+ if ( !strcasecmp( mime, MEDIA_MIMETYPE_AUDIO_AMR_NB ) ) {
+ mFormat = AUDIO_FORMAT_AMR_NB;
+ frameSize = AMR_FRAMESIZE;
+ mMaxBufferSize = AMR_FRAMESIZE*10;
+ }
+#ifdef ENABLE_AV_ENHANCEMENTS
+ else if ( !strcasecmp( mime, MEDIA_MIMETYPE_AUDIO_QCELP ) ) {
+ mFormat = AUDIO_FORMAT_QCELP;
+ frameSize = QCELP_FRAMESIZE;
+ mMaxBufferSize = QCELP_FRAMESIZE*10;
+ }
+ else if ( !strcasecmp( mime, MEDIA_MIMETYPE_AUDIO_EVRC ) ) {
+ mFormat = AUDIO_FORMAT_EVRC;
+ frameSize = EVRC_FRAMESIZE;
+ mMaxBufferSize = EVRC_FRAMESIZE*10;
+ }
+#endif
+ else if ( !strcasecmp( mime, MEDIA_MIMETYPE_AUDIO_AMR_WB ) ) {
+ mFormat = AUDIO_FORMAT_AMR_WB;
+ frameSize = AMR_WB_FRAMESIZE;
+ mMaxBufferSize = AMR_WB_FRAMESIZE*10;
+ }
+ else {
+ CHECK(0);
+ }
+ mAutoRampStartUs = 0;
+ CHECK(channels == 1 || channels == 2);
+ mRecord = new AudioRecord(
+ inputSource, sampleRate, mFormat,
+ channels > 1? AUDIO_CHANNEL_IN_STEREO:
+ AUDIO_CHANNEL_IN_MONO,
+ 4*mMaxBufferSize/channels/frameSize,
+ AudioRecordCallbackFunction,
+ this);
+ mInitCheck = mRecord->initCheck();
+}
+#endif
+
AudioSource::~AudioSource() {
if (mStarted) {
reset();
@@ -167,10 +268,19 @@
}
sp<MetaData> meta = new MetaData;
+#ifdef QCOM_HARDWARE
+ meta->setCString(kKeyMIMEType, mMime);
+ meta->setInt32(kKeySampleRate, mRecord->getSampleRate());
+#else
meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
meta->setInt32(kKeySampleRate, mSampleRate);
+#endif
meta->setInt32(kKeyChannelCount, mRecord->channelCount());
+#ifdef QCOM_HARDWARE
+ meta->setInt32(kKeyMaxInputSize, mMaxBufferSize);
+#else
meta->setInt32(kKeyMaxInputSize, kMaxBufferSize);
+#endif
return meta;
}
@@ -217,7 +327,9 @@
}
while (mStarted && mBuffersReceived.empty()) {
- mFrameAvailableCondition.wait(mLock);
+ status_t err = mFrameAvailableCondition.waitRelative(mLock,WaitLockEventTimeOutNs);
+ if(err == -ETIMEDOUT)
+ return (status_t)err;
}
if (!mStarted) {
return OK;
@@ -232,9 +344,12 @@
int64_t timeUs;
CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
int64_t elapsedTimeUs = timeUs - mStartTimeUs;
- if (elapsedTimeUs < kAutoRampStartUs) {
+#ifdef QCOM_HARDWARE
+ if ( mFormat == AUDIO_FORMAT_PCM_16_BIT ) {
+#endif
+ if (elapsedTimeUs < mAutoRampStartUs) {
memset((uint8_t *) buffer->data(), 0, buffer->range_length());
- } else if (elapsedTimeUs < kAutoRampStartUs + kAutoRampDurationUs) {
+ } else if (elapsedTimeUs < mAutoRampStartUs + kAutoRampDurationUs) {
int32_t autoRampDurationFrames =
((int64_t)kAutoRampDurationUs * mSampleRate + 500000LL) / 1000000LL; //Need type casting
@@ -244,10 +359,17 @@
int32_t nFrames = mNumFramesReceived - autoRampStartFrames;
rampVolume(nFrames, autoRampDurationFrames,
(uint8_t *) buffer->data(), buffer->range_length());
+ }
+#ifdef QCOM_HARDWARE
}
+#endif
// Track the max recording signal amplitude.
+#ifdef QCOM_HARDWARE
+ if (mTrackMaxAmplitude && ( mFormat == AUDIO_FORMAT_PCM_16_BIT)) {
+#else
if (mTrackMaxAmplitude) {
+#endif
trackMaxAmplitude(
(int16_t *) buffer->data(), buffer->range_length() >> 1);
}
@@ -304,6 +426,9 @@
}
CHECK_EQ(numLostBytes & 1, 0u);
+#ifdef QCOM_HARDWARE
+ if ( mFormat == AUDIO_FORMAT_PCM_16_BIT )
+#endif
CHECK_EQ(audioBuffer.size & 1, 0u);
if (numLostBytes > 0) {
// Loss of audio frames should happen rarely; thus the LOGW should
@@ -342,19 +467,45 @@
void AudioSource::queueInputBuffer_l(MediaBuffer *buffer, int64_t timeUs) {
const size_t bufferSize = buffer->range_length();
const size_t frameSize = mRecord->frameSize();
+#ifdef QCOM_HARDWARE
+ int64_t timestampUs = mPrevSampleTimeUs;
+ int64_t recordDurationUs = 0;
+ if ( mFormat == AUDIO_FORMAT_PCM_16_BIT && mSampleRate){
+ recordDurationUs = ((1000000LL * (bufferSize / (2 * mRecord->channelCount()))) +
+ (mSampleRate >> 1)) / mSampleRate;
+ } else {
+ recordDurationUs = bufferDurationUs(bufferSize);
+ }
+ timestampUs += recordDurationUs;
+#else
const int64_t timestampUs =
mPrevSampleTimeUs +
((1000000LL * (bufferSize / frameSize)) +
(mSampleRate >> 1)) / mSampleRate;
+#endif
if (mNumFramesReceived == 0) {
buffer->meta_data()->setInt64(kKeyAnchorTime, mStartTimeUs);
}
buffer->meta_data()->setInt64(kKeyTime, mPrevSampleTimeUs);
+#ifdef QCOM_HARDWARE
+ if (mFormat == AUDIO_FORMAT_PCM_16_BIT) {
+#endif
buffer->meta_data()->setInt64(kKeyDriftTime, timeUs - mInitialReadTimeUs);
+#ifdef QCOM_HARDWARE
+ } else {
+ int64_t wallClockTimeUs = timeUs - mInitialReadTimeUs;
+ int64_t mediaTimeUs = mStartTimeUs + mPrevSampleTimeUs;
+ buffer->meta_data()->setInt64(kKeyDriftTime, mediaTimeUs - wallClockTimeUs);
+ }
+#endif
mPrevSampleTimeUs = timestampUs;
+#ifdef QCOM_HARDWARE
+ mNumFramesReceived += buffer->range_length() / sizeof(int16_t);
+#else
mNumFramesReceived += bufferSize / frameSize;
+#endif
mBuffersReceived.push_back(buffer);
mFrameAvailableCondition.signal();
}
@@ -382,4 +533,24 @@
return value;
}
+#ifdef QCOM_HARDWARE
+int64_t AudioSource::bufferDurationUs( ssize_t n ) {
+ int64_t dataDurationMs = 0;
+ if (mFormat == AUDIO_FORMAT_AMR_NB) {
+ dataDurationMs = (n/AMR_FRAMESIZE) * 20; //ms
+ }
+ else if (mFormat == AUDIO_FORMAT_EVRC) {
+ dataDurationMs = (n/EVRC_FRAMESIZE) * 20; //ms
+ }
+ else if (mFormat == AUDIO_FORMAT_QCELP) {
+ dataDurationMs = (n/QCELP_FRAMESIZE) * 20; //ms
+ }
+ else if (mFormat == AUDIO_FORMAT_AMR_WB) {
+ dataDurationMs = (n/AMR_WB_FRAMESIZE) * 20; //ms
+ }
+ else
+ CHECK(0);
+ return dataDurationMs*1000LL;
+}
+#endif
} // namespace android
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 130207d..e9223f0 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -1,5 +1,8 @@
/*
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
* Copyright (C) 2009 The Android Open Source Project
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -39,6 +42,16 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/timedtext/TimedTextDriver.h>
#include <media/stagefright/AudioPlayer.h>
+#ifdef QCOM_ENHANCED_AUDIO
+#ifdef LEGACY_LPA
+#include <media/stagefright/LPAPlayerLegacy.h>
+#else
+#include <media/stagefright/LPAPlayer.h>
+#endif
+#ifdef USE_TUNNEL_MODE
+#include <media/stagefright/TunnelPlayer.h>
+#endif
+#endif
#include <media/stagefright/DataSource.h>
#include <media/stagefright/FileSource.h>
#include <media/stagefright/MediaBuffer.h>
@@ -47,6 +60,7 @@
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/OMXCodec.h>
+#include "include/ExtendedUtils.h"
#include <media/stagefright/Utils.h>
#include <gui/IGraphicBufferProducer.h>
@@ -58,6 +72,10 @@
#define USE_SURFACE_ALLOC 1
#define FRAME_DROP_FREQ 0
+#ifdef QCOM_HARDWARE
+#define LPA_MIN_DURATION_USEC_ALLOWED 30000000
+#define LPA_MIN_DURATION_USEC_DEFAULT 60000000
+#endif
namespace android {
@@ -65,6 +83,12 @@
static int64_t kHighWaterMarkUs = 5000000ll; // 5secs
static const size_t kLowWaterMarkBytes = 40000;
static const size_t kHighWaterMarkBytes = 200000;
+static const int64_t kInitFrameDurationUs = 16000;
+static const int64_t kScheduleLagGapUs = 1000;
+static const int64_t kDefaultEventDelayUs = 10000;
+#ifdef QCOM_ENHANCED_AUDIO
+int AwesomePlayer::mTunnelAliveAP = 0;
+#endif
// maximum time in paused state when offloading audio decompression. When elapsed, the AudioPlayer
// is destroyed to allow the audio DSP to power down.
@@ -202,6 +226,7 @@
mVideoBuffer(NULL),
mDecryptHandle(NULL),
mLastVideoTimeUs(-1),
+ mFrameDurationUs(kInitFrameDurationUs),
mTextDriver(NULL),
mOffloadAudio(false),
mAudioTearDown(false) {
@@ -228,6 +253,10 @@
mAudioTearDownEventPending = false;
reset();
+#ifdef QCOM_ENHANCED_AUDIO
+ mIsTunnelAudio = false;
+#endif
+ mLateAVSyncMargin = ExtendedUtils::ShellProp::getMaxAVSyncLateMargin();
}
AwesomePlayer::~AwesomePlayer() {
@@ -237,9 +266,59 @@
reset();
+#ifdef QCOM_ENHANCED_AUDIO
+ // Disable Tunnel Mode Audio
+ if (mIsTunnelAudio) {
+ if (mTunnelAliveAP > 0) {
+ mTunnelAliveAP--;
+ ALOGV("mTunnelAliveAP = %d", mTunnelAliveAP);
+ }
+ }
+ mIsTunnelAudio = false;
+#endif
mClient.disconnect();
}
+void AwesomePlayer::printStats() {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("persist.debug.sf.statistics", value, "0");
+ if (atoi(value) && mVideoSource != NULL) {
+ ALOGE("===========================\n"
+ " videoDimensions(%d x %d)\n"
+ " Total Video Frames Decoded(%lld)\n"
+ " Total Video Frames Rendered(%lld)\n"
+ " Total Playback Duration(%lld ms)\n"
+ " numVideoFramesDropped(%lld)\n"
+ " Average Frames Per Second(%.4f)\n"
+ " Last Seek To Time(%lld ms)\n"
+ " Last Paused Time(%lld ms)\n"
+ " First Frame Latency (%lld ms)\n"
+ " Number of times AV Sync Lost(%u)\n"
+ " Max Video Ahead Time Delta(%u)\n"
+ " Max Video Behind Time Delta(%u)\n"
+ " Max Time Sync Loss(%u)\n"
+ " EOS(%d)\n"
+ " PLAYING(%d)\n"
+ "===========================\n\n",
+ mStats.mVideoWidth,
+ mStats.mVideoHeight,
+ mStats.mNumVideoFramesDecoded,
+ mStats.mTotalFrames,
+ mStats.mTotalTimeUs/1000,
+ mStats.mNumVideoFramesDropped,
+ mStats.mTotalTimeUs > 0 ? ((double)(mStats.mTotalFrames)*1E6)/((double)mStats.mTotalTimeUs) : 0,
+ mStats.mLastSeekToTimeMs,
+ mStats.mLastPausedTimeMs,
+ mStats.mFirstFrameLatencyUs/1000,
+ mStats.mNumTimesSyncLoss,
+ -mStats.mMaxEarlyDelta/1000,
+ mStats.mMaxLateDelta/1000,
+ mStats.mMaxTimeSyncLoss/1000,
+ (mFlags & VIDEO_AT_EOS) > 0,
+ (mFlags & PLAYING) > 0);
+ }
+}
+
void AwesomePlayer::cancelPlayerEvents(bool keepNotifications) {
mQueue.cancelEvent(mVideoEvent->eventID());
mVideoEventPending = false;
@@ -316,12 +395,28 @@
return OK;
}
+void AwesomePlayer::printFileName(int fd) {
+
+ char symName[40] = {0};
+ char fileName[256] = {0};
+
+ snprintf(symName, sizeof(symName), "/proc/%d/fd/%d", getpid(), fd);
+
+ if (readlink( symName, fileName, (sizeof(fileName) - 1)) != -1 ) {
+ ALOGD("printFileName fd(%d) -> %s", fd, fileName);
+ }
+}
+
status_t AwesomePlayer::setDataSource(
int fd, int64_t offset, int64_t length) {
Mutex::Autolock autoLock(mLock);
+ ALOGD("Before reset_l");
reset_l();
+ if(fd)
+ printFileName(fd);
+
sp<DataSource> dataSource = new FileSource(fd, offset, length);
status_t err = dataSource->initCheck();
@@ -567,6 +662,8 @@
mVideoRenderer.clear();
+ modifyFlags(PLAYING, CLEAR);
+ printStats();
if (mVideoSource != NULL) {
shutdownVideoDecoder_l();
}
@@ -588,7 +685,7 @@
mBitrate = -1;
mLastVideoTimeUs = -1;
-
+ mFrameDurationUs = kInitFrameDurationUs;
{
Mutex::Autolock autoLock(mStatsLock);
mStats.mFd = -1;
@@ -602,6 +699,21 @@
mStats.mVideoHeight = -1;
mStats.mFlags = 0;
mStats.mTracks.clear();
+ mStats.mConsecutiveFramesDropped = 0;
+ mStats.mCatchupTimeStart = 0;
+ mStats.mNumTimesSyncLoss = 0;
+ mStats.mMaxEarlyDelta = 0;
+ mStats.mMaxLateDelta = 0;
+ mStats.mMaxTimeSyncLoss = 0;
+ mStats.mTotalFrames = 0;
+ mStats.mLastFrameUs = 0;
+ mStats.mTotalTimeUs = 0;
+ mStats.mVeryFirstFrame = true;
+ mStats.mFirstFrameLatencyUs = 0;
+ mStats.mLastPausedTimeMs = 0;
+ mStats.mLastSeekToTimeMs = 0;
+ mStats.mResumeDelayStartUs = -1;
+ mStats.mSeekDelayStartUs = -1;
}
mWatchForAudioSeekComplete = false;
@@ -929,9 +1041,14 @@
// We don't want to post an error notification at this point,
// the error returned from MediaPlayer::start() will suffice.
-
- status_t err = startAudioPlayer_l(
- false /* sendErrorNotification */);
+ bool sendErrorNotification = false;
+#ifdef QCOM_ENHANCED_AUDIO
+ if(mIsTunnelAudio) {
+ // For tunnel Audio error has to be posted to the client
+ sendErrorNotification = true;
+ }
+#endif
+ status_t err = startAudioPlayer_l(sendErrorNotification);
if ((err != OK) && mOffloadAudio) {
ALOGI("play_l() cannot create offload output, fallback to sw decode");
@@ -983,6 +1100,15 @@
mTimeSource = &mSystemTimeSource;
}
+ {
+ Mutex::Autolock autoLock(mStatsLock);
+ if (mStats.mVeryFirstFrame) {
+ mStats.mFirstFrameLatencyStartUs = getTimeOfDayUs();
+ } else {
+ mStats.mResumeDelayStartUs = getTimeOfDayUs();
+ }
+ }
+
if (mVideoSource != NULL) {
// Kick off video playback
postVideoEvent_l();
@@ -1020,7 +1146,13 @@
uint32_t flags = 0;
int64_t cachedDurationUs;
bool eos;
-
+#ifdef QCOM_ENHANCED_AUDIO
+ sp<MetaData> format = mAudioTrack->getFormat();
+ const char *mime;
+ bool success = format->findCString(kKeyMIMEType, &mime);
+ int tunnelObjectsAlive = 0;
+ CHECK(success);
+#endif
if (mOffloadAudio) {
flags |= AudioPlayer::USE_OFFLOAD;
} else if (mVideoSource == NULL
@@ -1035,8 +1167,89 @@
if (mVideoSource != NULL) {
flags |= AudioPlayer::HAS_VIDEO;
}
+#ifdef QCOM_ENHANCED_AUDIO
+#ifdef USE_TUNNEL_MODE
+ // Create tunnel player if tunnel mode is enabled
+ ALOGW("Trying to create tunnel player mIsTunnelAudio %d, \
+ LPAPlayer::mObjectsAlive %d, \
+ TunnelPlayer::mTunnelObjectsAlive = %d,\
+ (mAudioPlayer == NULL) %d",
+ mIsTunnelAudio, TunnelPlayer::mTunnelObjectsAlive,
+ LPAPlayer::mObjectsAlive,(mAudioPlayer == NULL));
+ if(mIsTunnelAudio && (mAudioPlayer == NULL) &&
+ (LPAPlayer::mObjectsAlive == 0) &&
+ (TunnelPlayer::mTunnelObjectsAlive < TunnelPlayer::getTunnelObjectsAliveMax())) {
+ ALOGD("Tunnel player created for mime %s duration %lld\n",\
+ mime, mDurationUs);
+ bool initCheck = false;
+ if(mVideoSource != NULL) {
+ // The parameter true is to inform tunnel player that
+ // clip is audio video
+ ALOGD("Tunnel for video");
+ mAudioPlayer = new TunnelPlayer(mAudioSink, initCheck,
+ this, true);
+ }
+ else {
+ ALOGD("Tunnel for audio");
+ mAudioPlayer = new TunnelPlayer(mAudioSink, initCheck,
+ this);
+ }
+ if(!initCheck) {
+ ALOGE("deleting Tunnel Player - initCheck failed");
+ delete mAudioPlayer;
+ mAudioPlayer = NULL;
+ }
+ }
+ tunnelObjectsAlive = (TunnelPlayer::mTunnelObjectsAlive);
+#endif
+ int32_t nchannels = 0;
+ if(mAudioTrack != NULL) {
+ sp<MetaData> format = mAudioTrack->getFormat();
+ if(format != NULL) {
+ format->findInt32( kKeyChannelCount, &nchannels );
+ ALOGV("nchannels %d;LPA will be skipped if nchannels is > 2 or nchannels == 0",nchannels);
+ }
+ }
+ char lpaDecode[PROPERTY_VALUE_MAX];
+ uint32_t minDurationForLPA = LPA_MIN_DURATION_USEC_DEFAULT;
+ char minUserDefDuration[PROPERTY_VALUE_MAX];
+ property_get("lpa.decode",lpaDecode,"0");
+ property_get("lpa.min_duration",minUserDefDuration,"LPA_MIN_DURATION_USEC_DEFAULT");
+ minDurationForLPA = atoi(minUserDefDuration);
+ if(minDurationForLPA < LPA_MIN_DURATION_USEC_ALLOWED) {
+ if(mAudioPlayer == NULL) {
+ ALOGE("LPAPlayer::Clip duration setting of less than 30sec not supported, defaulting to 60sec");
+ minDurationForLPA = LPA_MIN_DURATION_USEC_DEFAULT;
+ }
+ }
+ if((strcmp("true",lpaDecode) == 0) && (mAudioPlayer == NULL) &&
+#ifdef USE_ENHANCED_AUDIO
+ (tunnelObjectsAlive < TunnelPlayer::getTunnelObjectsAliveMax()) &&
+#endif
+ (nchannels && (nchannels <= 2)))
+ {
+ ALOGV("LPAPlayer::getObjectsAlive() %d",LPAPlayer::mObjectsAlive);
+ if ( mDurationUs > minDurationForLPA
+ && (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG) || !strcasecmp(mime,MEDIA_MIMETYPE_AUDIO_AAC))
+ && LPAPlayer::mObjectsAlive == 0 && mVideoSource == NULL) {
+ ALOGD("LPAPlayer created, LPA MODE detected mime %s duration %lld", mime, mDurationUs);
+ bool initCheck = false;
+ mAudioPlayer = new LPAPlayer(mAudioSink, initCheck, this);
+ if(!initCheck) {
+ ALOGE("deleting Tunnel Player - initCheck failed");
+ delete mAudioPlayer;
+ mAudioPlayer = NULL;
+ }
+ }
+ }
+ if(mAudioPlayer == NULL) {
+ ALOGV("AudioPlayer created, Non-LPA mode mime %s duration %lld\n", mime, mDurationUs);
+ mAudioPlayer = new AudioPlayer(mAudioSink, flags, this);
+ }
+#else
mAudioPlayer = new AudioPlayer(mAudioSink, flags, this);
+#endif
mAudioPlayer->setSource(mAudioSource);
mTimeSource = mAudioPlayer;
@@ -1077,6 +1290,7 @@
true /* sourceAlreadyStarted */);
if (err != OK) {
+ ALOGE("AudioPlayer start error");
if (sendErrorNotification) {
notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
}
@@ -1267,6 +1481,12 @@
Playback::PAUSE, 0);
}
+ if(!(mFlags & VIDEO_AT_EOS)){
+ Mutex::Autolock autoLock(mStatsLock);
+ mStats.mLastPausedTimeMs = mVideoTimeUs/1000;
+ printStats();
+ }
+
uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder;
if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) {
params |= IMediaPlayerService::kBatteryDataTrackAudio;
@@ -1402,7 +1622,8 @@
status_t AwesomePlayer::seekTo(int64_t timeUs) {
ATRACE_CALL();
- if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
+ if (((timeUs == 0) && (mExtractorFlags & MediaExtractor::CAN_SEEK_TO_ZERO)) ||
+ (mExtractorFlags & MediaExtractor::CAN_SEEK)) {
Mutex::Autolock autoLock(mLock);
return seekTo_l(timeUs);
}
@@ -1425,6 +1646,11 @@
}
mSeeking = SEEK;
+
+ {
+ Mutex::Autolock autoLock(mStatsLock);
+ mStats.mSeekDelayStartUs = getTimeOfDayUs();
+ }
mSeekNotificationSent = false;
mSeekTimeUs = timeUs;
modifyFlags((AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS), CLEAR);
@@ -1507,6 +1733,119 @@
mOffloadAudio = canOffloadStream(meta, (mVideoSource != NULL),
isStreamingHTTP(), streamType);
+#ifdef QCOM_ENHANCED_AUDIO
+ int32_t nchannels = 0;
+ int32_t isADTS = 0;
+ meta->findInt32( kKeyChannelCount, &nchannels );
+ meta->findInt32(kKeyIsADTS, &isADTS);
+ if (isADTS == 1) {
+ ALOGV("Widevine content\n");
+ }
+
+ ALOGV("nchannels %d;LPA will be skipped if nchannels is > 2 or nchannels == 0",
+ nchannels);
+
+#ifdef USE_TUNNEL_MODE
+ char tunnelDecode[PROPERTY_VALUE_MAX];
+ property_get("tunnel.decode",tunnelDecode,"0");
+ // Enable tunnel mode for mp3 and aac and if the clip is not aac adif
+ // and if no other tunnel mode instances aare running.
+ ALOGD("Tunnel Mime Type: %s, object alive = %d, mTunnelAliveAP = %d",\
+ mime, (TunnelPlayer::mTunnelObjectsAlive), mTunnelAliveAP);
+
+ bool sys_prop_enabled = !strcmp("true",tunnelDecode) || atoi(tunnelDecode);
+ ALOGD("maxPossible tunnels = %d", TunnelPlayer::getTunnelObjectsAliveMax());
+ //widevine will fallback to software decoder
+ if (sys_prop_enabled && (TunnelPlayer::mTunnelObjectsAlive < TunnelPlayer::getTunnelObjectsAliveMax()) &&
+ (mTunnelAliveAP < TunnelPlayer::getTunnelObjectsAliveMax()) && (isADTS == 0) &&
+ mAudioSink->realtime() &&
+ inSupportedTunnelFormats(mime)) {
+
+ if (mVideoSource != NULL) {
+ char tunnelAVDecode[PROPERTY_VALUE_MAX];
+ property_get("tunnel.audiovideo.decode",tunnelAVDecode,"0");
+ sys_prop_enabled = !strncmp("true", tunnelAVDecode, 4) || atoi(tunnelAVDecode);
+ if (sys_prop_enabled) {
+ ALOGD("Enable Tunnel Mode for A-V playback");
+ mIsTunnelAudio = true;
+ }
+ }
+ else {
+ ALOGI("Tunnel Mode Audio Enabled");
+ mIsTunnelAudio = true;
+ }
+#ifdef NO_TUNNEL_MODE_FOR_MULTICHANNEL
+ if (nchannels > 2 || nchannels <= 0) {
+ ALOGD("Use tunnel mode only for mono and stereo channels");
+ mIsTunnelAudio = false;
+ }
+#endif
+ }
+ else
+ ALOGD("Normal Audio Playback");
+#endif
+
+ checkTunnelExceptions();
+
+ if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW) ||
+ (mIsTunnelAudio
+#ifdef USE_TUNNEL_MODE
+ && (mTunnelAliveAP < TunnelPlayer::getTunnelObjectsAliveMax())
+#endif
+ )) {
+ ALOGD("Set Audio Track as Audio Source");
+ if(mIsTunnelAudio) {
+ mTunnelAliveAP++;
+ }
+ mAudioSource = mAudioTrack;
+ } else {
+ // For LPA Playback use the decoder without OMX layer
+ char *matchComponentName = NULL;
+ int64_t durationUs;
+ uint32_t flags = 0;
+ char lpaDecode[128];
+ uint32_t minDurationForLPA = LPA_MIN_DURATION_USEC_DEFAULT;
+ char minUserDefDuration[PROPERTY_VALUE_MAX];
+ property_get("lpa.decode",lpaDecode,"0");
+ property_get("lpa.min_duration",minUserDefDuration,"LPA_MIN_DURATION_USEC_DEFAULT");
+ minDurationForLPA = atoi(minUserDefDuration);
+ if(minDurationForLPA < LPA_MIN_DURATION_USEC_ALLOWED) {
+ ALOGE("LPAPlayer::Clip duration setting of less than 30sec not supported, defaulting to 60sec");
+ minDurationForLPA = LPA_MIN_DURATION_USEC_DEFAULT;
+ }
+ if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
+ Mutex::Autolock autoLock(mMiscStateLock);
+ if (mDurationUs < 0 || durationUs > mDurationUs) {
+ mDurationUs = durationUs;
+ }
+ }
+ if ( mDurationUs > minDurationForLPA
+ && (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG) || !strcasecmp(mime,MEDIA_MIMETYPE_AUDIO_AAC))
+ && LPAPlayer::mObjectsAlive == 0 && mVideoSource == NULL && (strcmp("true",lpaDecode) == 0)
+ && (nchannels && (nchannels <= 2)) ) {
+ char nonOMXDecoder[128];
+ if(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
+ ALOGD("matchComponentName is set to MP3Decoder %lld, mime %s",mDurationUs,mime);
+ property_get("use.non-omx.mp3.decoder",nonOMXDecoder,"0");
+ if((strcmp("true",nonOMXDecoder) == 0)) {
+ matchComponentName = (char *) "MP3Decoder";
+ }
+ } else if((!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC))) {
+ ALOGD("matchComponentName is set to AACDecoder %lld, mime %s",mDurationUs,mime);
+ property_get("use.non-omx.aac.decoder",nonOMXDecoder,"0");
+ if((strcmp("true",nonOMXDecoder) == 0)) {
+ matchComponentName = (char *) "AACDecoder";
+ } else {
+ matchComponentName = (char *) "OMX.google.aac.decoder";
+ }
+ }
+ flags |= OMXCodec::kSoftwareCodecsOnly;
+ }
+ mAudioSource = OMXCodec::Create(
+ mClient.interface(), mAudioTrack->getFormat(),
+ false, // createEncoder
+ mAudioTrack, matchComponentName, flags,NULL);
+#else
if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) {
ALOGV("createAudioPlayer: bypass OMX (raw)");
mAudioSource = mAudioTrack;
@@ -1517,12 +1856,15 @@
mClient.interface(), mAudioTrack->getFormat(),
false, // createEncoder
mAudioTrack);
+#endif
if (mOffloadAudio) {
ALOGV("createAudioPlayer: bypass OMX (offload)");
mAudioSource = mAudioTrack;
+#ifndef QCOM_ENHANCED_AUDIO
} else {
mAudioSource = mOmxSource;
+#endif
}
}
@@ -1718,10 +2060,18 @@
mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
Playback::START, videoTimeUs / 1000);
}
+
+ {
+ Mutex::Autolock autoLock(mStatsLock);
+ mStats.mLastSeekToTimeMs = mSeekTimeUs/1000;
+ printStats();
+ }
}
void AwesomePlayer::onVideoEvent() {
ATRACE_CALL();
+ int64_t eventStartTimeUs = mSystemTimeSource.getRealTimeUs();
+ int64_t earlyGapUs = kScheduleLagGapUs; // gap for in case of event scheduling lag
Mutex::Autolock autoLock(mLock);
if (!mVideoEventPending) {
// The event has been cancelled in reset_l() but had already
@@ -1730,6 +2080,14 @@
}
mVideoEventPending = false;
+ {
+ Mutex::Autolock autoLock(mStatsLock);
+ if(!mStats.mVeryFirstFrame && mSeeking == NO_SEEK){
+ mStats.mTotalTimeUs += getTimeOfDayUs() - mStats.mLastFrameUs;
+ }
+ mStats.mLastFrameUs = getTimeOfDayUs();
+ }
+
if (mSeeking != NO_SEEK) {
if (mVideoBuffer) {
mVideoBuffer->release();
@@ -1823,7 +2181,11 @@
int64_t timeUs;
CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
-
+ if ((mLastVideoTimeUs != timeUs)
+ && (mLastVideoTimeUs > 0)
+ && (mSeeking == NO_SEEK)) {
+ mFrameDurationUs = timeUs - mLastVideoTimeUs;
+ }
mLastVideoTimeUs = timeUs;
if (mSeeking == SEEK_VIDEO_ONLY) {
@@ -1863,18 +2225,27 @@
modifyFlags(FIRST_FRAME, CLEAR);
mSinceLastDropped = 0;
mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs;
+
+ {
+ Mutex::Autolock autoLock(mStatsLock);
+ if(mStats.mVeryFirstFrame){
+ logFirstFrame();
+ printStats();
+ mStats.mLastFrameUs = getTimeOfDayUs();
+ }
+ }
}
- int64_t realTimeUs, mediaTimeUs;
+ int64_t realTimeUs, mediaTimeUs, nowUs = 0, latenessUs = 0;
if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL
&& mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) {
mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
}
if (wasSeeking == SEEK_VIDEO_ONLY) {
- int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
+ nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
- int64_t latenessUs = nowUs - timeUs;
+ latenessUs = nowUs - timeUs;
ATRACE_INT("Video Lateness (ms)", latenessUs / 1E3);
@@ -1886,9 +2257,9 @@
if (wasSeeking == NO_SEEK) {
// Let's display the first frame after seeking right away.
- int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
+ nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
- int64_t latenessUs = nowUs - timeUs;
+ latenessUs = nowUs - timeUs;
ATRACE_INT("Video Lateness (ms)", latenessUs / 1E3);
@@ -1916,7 +2287,7 @@
}
}
- if (latenessUs > 40000) {
+ if (latenessUs > mLateAVSyncMargin) {
// We're more than 40ms late.
ALOGV("we're late by %lld us (%.2f secs)",
latenessUs, latenessUs / 1E6);
@@ -1935,6 +2306,11 @@
{
Mutex::Autolock autoLock(mStatsLock);
++mStats.mNumVideoFramesDropped;
+ mStats.mConsecutiveFramesDropped++;
+ if (mStats.mConsecutiveFramesDropped == 1){
+ mStats.mCatchupTimeStart = mTimeSource->getRealTimeUs();
+ }
+ if(!(mFlags & AT_EOS)) logLate(timeUs,nowUs,latenessUs);
}
postVideoEvent_l(0);
@@ -1944,6 +2320,11 @@
if (latenessUs < -10000) {
// We're more than 10ms early.
+ logOnTime(timeUs,nowUs,latenessUs);
+ {
+ Mutex::Autolock autoLock(mStatsLock);
+ mStats.mConsecutiveFramesDropped = 0;
+ }
postVideoEvent_l(10000);
return;
}
@@ -1967,6 +2348,26 @@
if (mFlags & PLAYING) {
notifyIfMediaStarted_l();
}
+ {
+ Mutex::Autolock autoLock(mStatsLock);
+ logOnTime(timeUs,nowUs,latenessUs);
+ mStats.mTotalFrames++;
+ mStats.mConsecutiveFramesDropped = 0;
+ char value[PROPERTY_VALUE_MAX];
+ property_get("persist.debug.sf.statistics", value, "0");
+ if (atoi(value) && mVideoSource != NULL) {
+ if (mStats.mResumeDelayStartUs > 0) {
+ printStats();
+ ALOGE("Resume Latency = %lld us", getTimeOfDayUs() - mStats.mResumeDelayStartUs);
+ mStats.mResumeDelayStartUs = -1;
+ }
+ if (mStats.mSeekDelayStartUs > 0) {
+ printStats();
+ ALOGE("Seek Latency = %lld us", getTimeOfDayUs() - mStats.mSeekDelayStartUs);
+ mStats.mSeekDelayStartUs = -1;
+ }
+ }
+ }
}
mVideoBuffer->release();
@@ -2058,6 +2459,18 @@
return;
}
mAudioStatusEventPending = true;
+
+#ifdef EXYNOS4_ENHANCEMENTS
+ /*
+ * Do not honor delay when audio reached EOS
+ * in order to change immediately time source from AudioPlayer to SystemTime
+ */
+ status_t finalStatus;
+ if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) {
+ delayUs = 0;
+ }
+#endif
+
// Do not honor delay when looping in order to limit audio gap
if (mFlags & (LOOPING | AUTO_LOOPING)) {
delayUs = 0;
@@ -2834,13 +3247,33 @@
if ((ssize_t)i == mStats.mVideoTrackIndex) {
fprintf(out,
- " videoDimensions(%d x %d), "
- "numVideoFramesDecoded(%lld), "
- "numVideoFramesDropped(%lld)\n",
+ " videoDimensions(%d x %d)\n"
+ " Total Video Frames Decoded(%lld)\n"
+ " Total Video Frames Rendered(%lld)\n"
+ " Total Playback Duration(%lld ms)\n"
+ " numVideoFramesDropped(%lld)\n"
+ " Average Frames Per Second(%.4f)\n"
+ " First Frame Latency (%lld ms)\n"
+ " Number of times AV Sync Lost(%u)\n"
+ " Max Video Ahead Time Delta(%u)\n"
+ " Max Video Behind Time Delta(%u)\n"
+ " Max Time Sync Loss(%u)\n"
+ " EOS(%d)\n"
+ " PLAYING(%d)\n",
mStats.mVideoWidth,
mStats.mVideoHeight,
mStats.mNumVideoFramesDecoded,
- mStats.mNumVideoFramesDropped);
+ mStats.mTotalFrames,
+ mStats.mTotalTimeUs/1000,
+ mStats.mNumVideoFramesDropped,
+ ((double)(mStats.mTotalFrames)*1E6)/((double)mStats.mTotalTimeUs),
+ mStats.mFirstFrameLatencyUs/1000,
+ mStats.mNumTimesSyncLoss,
+ -mStats.mMaxEarlyDelta/1000,
+ mStats.mMaxLateDelta/1000,
+ mStats.mMaxTimeSyncLoss/1000,
+ (mFlags & AT_EOS) > 0,
+ (mFlags & PLAYING) > 0);
}
}
@@ -2922,4 +3355,139 @@
beginPrepareAsync_l();
}
+#ifdef QCOM_ENHANCED_AUDIO
+bool AwesomePlayer::inSupportedTunnelFormats(const char * mime) {
+ const char * tunnelFormats [ ] = {
+ MEDIA_MIMETYPE_AUDIO_MPEG,
+ MEDIA_MIMETYPE_AUDIO_AAC,
+#ifdef TUNNEL_MODE_SUPPORTS_AMRWB
+ MEDIA_MIMETYPE_AUDIO_AMR_WB,
+ #ifdef ENABLE_AV_ENHANCEMENTS
+ MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS
+ #endif
+#endif
+ };
+
+ if (!mime) {
+ return false;
+ }
+
+ size_t len = sizeof(tunnelFormats)/sizeof(const char *);
+ for (size_t i = 0; i < len; i++) {
+ const char * tf = tunnelFormats[i];
+ if (!strncasecmp(mime, tf, strlen(tf))) {
+ if (strlen(mime) == strlen(tf)) { //to prevent a substring match
+ ALOGD("Tunnel playback supported for %s", tf);
+ return true;
+ }
+ }
+ }
+
+ ALOGW("Tunnel playback unsupported for %s", mime);
+ return false;
+}
+
+void AwesomePlayer::checkTunnelExceptions()
+{
+ /* exception 1: No streaming */
+ if (isStreamingHTTP()) {
+ ALOGV("Streaming, force disable tunnel mode playback");
+ mIsTunnelAudio = false;
+ return;
+ }
+
+ CHECK(mAudioTrack != NULL);
+
+ /*
+ * exception 2: No AAC-LD content,
+ * hint given by setting kKeyTunnelException in the track meta
+ */
+ int32_t exception = 0;
+ if (mAudioTrack->getFormat()->findInt32(kKeyTunnelException, &exception) &&
+ exception) {
+ ALOGV("kKeyTunnelException set, disable tunnel mode");
+ mIsTunnelAudio = false;
+ return;
+ }
+
+ /* exception 3: use tunnel player only for AUDIO_STREAM_MUSIC */
+ if (mAudioSink->streamType() != AUDIO_STREAM_MUSIC ) {
+ ALOGV("Use tunnel player only for AUDIO_STREAM_MUSIC");
+ mIsTunnelAudio = false;
+ return;
+ }
+
+ /* below exceptions are only for av content */
+ if (mVideoTrack == NULL) return;
+
+ /* exception 3: No avi having video + mp3 */
+ if (mExtractor == NULL) return;
+
+ sp<MetaData> metaData = mExtractor->getMetaData();
+ const char * container;
+
+ /*only proceed for avi content.*/
+ if (!metaData->findCString(kKeyMIMEType, &container) ||
+ strcmp(container, MEDIA_MIMETYPE_CONTAINER_AVI)) {
+ return;
+ }
+
+ const char * mime;
+ metaData = mAudioTrack->getFormat();
+ /*disable for av content having mp3*/
+ if (metaData->findCString(kKeyMIMEType, &mime) &&
+ !strcmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
+ ALOGV("Clip has AVI extractor and mp3 content, disable tunnel mode");
+ mIsTunnelAudio = false;
+ return;
+ }
+
+ return;
+}
+#endif
+
+inline void AwesomePlayer::logFirstFrame() {
+ mStats.mFirstFrameLatencyUs = getTimeOfDayUs()-mStats.mFirstFrameLatencyStartUs;
+ mStats.mVeryFirstFrame = false;
+}
+
+inline void AwesomePlayer::logCatchUp(int64_t ts, int64_t clock, int64_t delta)
+{
+ if (mStats.mConsecutiveFramesDropped > 0) {
+ mStats.mNumTimesSyncLoss++;
+ if (mStats.mMaxTimeSyncLoss < (clock - mStats.mCatchupTimeStart) && clock > 0 && ts > 0) {
+ mStats.mMaxTimeSyncLoss = clock - mStats.mCatchupTimeStart;
+ }
+ }
+}
+
+inline void AwesomePlayer::logLate(int64_t ts, int64_t clock, int64_t delta)
+{
+ if (mStats.mMaxLateDelta < delta && clock > 0 && ts > 0) {
+ mStats.mMaxLateDelta = delta;
+ }
+}
+
+inline void AwesomePlayer::logOnTime(int64_t ts, int64_t clock, int64_t delta)
+{
+ bool needLogLate = false;
+ logCatchUp(ts, clock, delta);
+ if (delta <= 0) {
+ if ((-delta) > (-mStats.mMaxEarlyDelta) && clock > 0 && ts > 0) {
+ mStats.mMaxEarlyDelta = delta;
+ }
+ }
+ else {
+ needLogLate = true;
+ }
+
+ if(needLogLate) logLate(ts, clock, delta);
+}
+
+inline int64_t AwesomePlayer::getTimeOfDayUs() {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+
+ return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
+}
} // namespace android
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 3017fe7..d054a14 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -30,6 +30,13 @@
#include <gui/Surface.h>
#include <utils/String8.h>
#include <cutils/properties.h>
+#ifdef QCOM_HARDWARE
+#include "include/ExtendedUtils.h"
+#endif
+
+#ifdef USE_TI_CUSTOM_DOMX
+#include <OMX_TI_IVCommon.h>
+#endif
namespace android {
@@ -96,11 +103,20 @@
}
if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV420SP)) {
+#ifdef USE_SAMSUNG_COLORFORMAT
+ static const int OMX_SEC_COLOR_FormatNV12LPhysicalAddress = 0x7F000002;
+ return OMX_SEC_COLOR_FormatNV12LPhysicalAddress;
+#else
return OMX_COLOR_FormatYUV420SemiPlanar;
+#endif
}
if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV422I)) {
+#if defined(TARGET_OMAP3) && defined(OMAP_ENHANCEMENT)
+ return OMX_COLOR_FormatCbYCrY;
+#else
return OMX_COLOR_FormatYCbYCr;
+#endif
}
if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_RGB565)) {
@@ -340,11 +356,13 @@
ALOGV("Supported frame rates: %s", supportedFrameRates);
char buf[4];
snprintf(buf, 4, "%d", frameRate);
+#ifndef HTC_3D_SUPPORT // HTC uses invalid frame rates intentionally on the 3D camera
if (strstr(supportedFrameRates, buf) == NULL) {
ALOGE("Requested frame rate (%d) is not supported: %s",
frameRate, supportedFrameRates);
return BAD_VALUE;
}
+#endif
// The frame rate is supported, set the camera to the requested value.
params->setPreviewFrameRate(frameRate);
@@ -442,11 +460,13 @@
// Check the actual video frame rate against the target/requested
// video frame rate.
+#ifndef HTC_3D_SUPPORT // HTC uses invalid frame rates intentionally on the 3D camera
if (frameRate != -1 && (frameRateActual - frameRate) != 0) {
ALOGE("Failed to set preview frame rate to %d fps. The actual "
"frame rate is %d", frameRate, frameRateActual);
return UNKNOWN_ERROR;
}
+#endif
// Good now.
mVideoFrameRate = frameRateActual;
@@ -563,6 +583,11 @@
mMeta->setInt32(kKeyStride, mVideoSize.width);
mMeta->setInt32(kKeySliceHeight, mVideoSize.height);
mMeta->setInt32(kKeyFrameRate, mVideoFrameRate);
+
+#ifdef QCOM_HARDWARE
+ ExtendedUtils::HFR::setHFRIfEnabled(params, mMeta);
+#endif
+
return OK;
}
@@ -813,6 +838,10 @@
void CameraSource::dataCallbackTimestamp(int64_t timestampUs,
int32_t msgType, const sp<IMemory> &data) {
ALOGV("dataCallbackTimestamp: timestamp %lld us", timestampUs);
+ if (!mStarted) {
+ ALOGD("Stop recording issued. Return here.");
+ return;
+ }
Mutex::Autolock autoLock(mLock);
if (!mStarted || (mNumFramesReceived == 0 && timestampUs < mStartTimeUs)) {
ALOGV("Drop frame at %lld/%lld us", timestampUs, mStartTimeUs);
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
old mode 100644
new mode 100755
index 97987e2..32dafb2
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -32,6 +32,9 @@
#include "include/OggExtractor.h"
#include "include/WAVExtractor.h"
#include "include/WVMExtractor.h"
+#ifdef QCOM_HARDWARE
+#include "include/ExtendedExtractor.h"
+#endif
#include "matroska/MatroskaExtractor.h"
@@ -169,6 +172,9 @@
RegisterSniffer_l(SniffAAC);
RegisterSniffer_l(SniffMPEG2PS);
RegisterSniffer_l(SniffWVM);
+#ifdef QCOM_HARDWARE
+ RegisterSniffer_l(ExtendedExtractor::Sniff);
+#endif
char value[PROPERTY_VALUE_MAX];
if (property_get("drm.service.enabled", value, NULL)
diff --git a/media/libstagefright/ExtendedCodec.cpp b/media/libstagefright/ExtendedCodec.cpp
new file mode 100644
index 0000000..8cde8bd
--- /dev/null
+++ b/media/libstagefright/ExtendedCodec.cpp
@@ -0,0 +1,1077 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ExtendedCodec"
+#include <utils/Log.h>
+#include <cutils/properties.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/ExtendedCodec.h>
+#include <media/stagefright/OMXCodec.h>
+
+#ifdef ENABLE_AV_ENHANCEMENTS
+
+#include <QCMetaData.h>
+#include <QCMediaDefs.h>
+#include <OMX_QCOMExtns.h>
+#include <OMX_Component.h>
+#include <QOMX_AudioExtensions.h>
+#include "include/ExtendedUtils.h"
+
+namespace android {
+enum MetaKeyType{
+ INT32, INT64, STRING, DATA, CSD
+};
+
+struct MetaKeyEntry{
+ int MetaKey;
+ const char* MsgKey;
+ MetaKeyType KeyType;
+};
+
+static const MetaKeyEntry MetaKeyTable[] {
+ {kKeyBitRate , "bitrate" , INT32},
+ {kKeyAacCodecSpecificData , "aac-codec-specific-data", CSD},
+ {kKeyRawCodecSpecificData , "raw-codec-specific-data", CSD},
+ {kKeyDivXVersion , "divx-version" , INT32}, // int32_t
+ {kKeyDivXDrm , "divx-drm" , DATA}, // void *
+ {kKeyWMAEncodeOpt , "wma-encode-opt" , INT32}, // int32_t
+ {kKeyWMABlockAlign , "wma-block-align" , INT32}, // int32_t
+ {kKeyWMAVersion , "wma-version" , INT32}, // int32_t
+ {kKeyWMAAdvEncOpt1 , "wma-adv-enc-opt1" , INT32}, // int16_t
+ {kKeyWMAAdvEncOpt2 , "wma-adv-enc-opt2" , INT32}, // int32_t
+ {kKeyWMAFormatTag , "wma-format-tag" , INT32}, // int32_t
+ {kKeyWMABitspersample , "wma-bits-per-sample" , INT32}, // int32_t
+ {kKeyWMAVirPktSize , "wma-vir-pkt-size" , INT32}, // int32_t
+ {kKeyWMAChannelMask , "wma-channel-mask" , INT32}, // int32_t
+
+ {kKeyFileFormat , "file-format" , STRING}, // cstring
+
+ {kkeyAacFormatAdif , "aac-format-adif" , INT32}, // bool (int32_t)
+ {kkeyAacFormatLtp , "aac-format-ltp" , INT32},
+
+ //DTS subtype
+ {kKeyDTSSubtype , "dts-subtype" , INT32}, //int32_t
+
+ //Extractor sets this
+ {kKeyUseArbitraryMode , "use-arbitrary-mode" , INT32}, //bool (int32_t)
+ {kKeySmoothStreaming , "smooth-streaming" , INT32}, //bool (int32_t)
+ {kKeyHFR , "hfr" , INT32}, // int32_t
+
+ {kKeySampleRate , "sample-rate" , INT32},
+ {kKeyChannelCount , "channel-count" , INT32},
+};
+
+const char* ExtendedCodec::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";
+}
+
+status_t ExtendedCodec::convertMetaDataToMessage(
+ 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);
+ sp<ABuffer> buffer = new ABuffer(size);
+ memcpy(buffer->data(), data, size);
+ if (MetaKeyTable[i].KeyType == CSD) {
+ buffer->meta()->setInt32("csd", true);
+ buffer->meta()->setInt64("timeUs", 0);
+ }
+ format->get()->setBuffer(MetaKeyTable[i].MsgKey, buffer);
+ }
+ }
+ return OK;
+}
+
+uint32_t ExtendedCodec::getComponentQuirks(
+ const MediaCodecList *list, size_t index) {
+ uint32_t quirks = 0;
+
+ if (list->codecHasQuirk(
+ index, "requires-wma-pro-component")) {
+ quirks |= kRequiresWMAProComponent;
+ }
+ return quirks;
+}
+
+const char* ExtendedCodec::overrideComponentName(
+ uint32_t quirks, const sp<MetaData> &meta) {
+ const char* componentName = NULL;
+ if(quirks & kRequiresWMAProComponent)
+ {
+ int32_t version = 0;
+ if (meta->findInt32(kKeyWMAVersion, &version)) {
+ if(version==kTypeWMA) {
+ componentName = "OMX.qcom.audio.decoder.wma";
+ } else if(version==kTypeWMAPro) {
+ componentName = "OMX.qcom.audio.decoder.wma10Pro";
+ } else if(version==kTypeWMALossLess) {
+ componentName = "OMX.qcom.audio.decoder.wmaLossLess";
+ }
+ }
+ }
+ return componentName;
+}
+
+void ExtendedCodec::overrideComponentName(
+ uint32_t quirks, const sp<AMessage> &msg, AString* componentName) {
+ if(quirks & kRequiresWMAProComponent)
+ {
+ int32_t version = 0;
+ if (msg->findInt32(getMsgKey(kKeyWMAVersion), &version)) {
+ if(version==kTypeWMA) {
+ componentName->setTo("OMX.qcom.audio.decoder.wma");
+ } else if(version==kTypeWMAPro) {
+ componentName->setTo("OMX.qcom.audio.decoder.wma10Pro");
+ } else if(version==kTypeWMALossLess) {
+ componentName->setTo("OMX.qcom.audio.decoder.wmaLossLess");
+ }
+ }
+ }
+}
+
+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;
+}
+
+status_t ExtendedCodec::setDIVXFormat(
+ const sp<AMessage> &msg, const char* mime, sp<IOMX> OMXhandle,
+ IOMX::node_id nodeID, int port_index) {
+ status_t err = OK;
+
+ if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX, mime) ||
+ !strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX4, mime) ||
+ !strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX311, mime)) {
+ ALOGV("Setting the QOMX_VIDEO_PARAM_DIVXTYPE params ");
+ QOMX_VIDEO_PARAM_DIVXTYPE paramDivX;
+ InitOMXParams(¶mDivX);
+ paramDivX.nPortIndex = port_index;
+ int32_t DivxVersion = 0;
+ CHECK(msg->findInt32(getMsgKey(kKeyDivXVersion),&DivxVersion));
+ ALOGV("Divx Version Type %d\n",DivxVersion);
+
+ if(DivxVersion == kTypeDivXVer_4) {
+ paramDivX.eFormat = QOMX_VIDEO_DIVXFormat4;
+ } else if(DivxVersion == kTypeDivXVer_5) {
+ paramDivX.eFormat = QOMX_VIDEO_DIVXFormat5;
+ } else if(DivxVersion == kTypeDivXVer_6) {
+ paramDivX.eFormat = QOMX_VIDEO_DIVXFormat6;
+ } else if(DivxVersion == kTypeDivXVer_3_11 ) {
+ paramDivX.eFormat = QOMX_VIDEO_DIVXFormat311;
+ } else {
+ paramDivX.eFormat = QOMX_VIDEO_DIVXFormatUnused;
+ }
+ paramDivX.eProfile = (QOMX_VIDEO_DIVXPROFILETYPE)0; //Not used for now.
+
+ err = OMXhandle->setParameter(nodeID,
+ (OMX_INDEXTYPE)OMX_QcomIndexParamVideoDivx,
+ ¶mDivX, sizeof(paramDivX));
+ }
+
+ return err;
+}
+
+void ExtendedCodec::getRawCodecSpecificData(
+ const sp<MetaData> &meta, const void* &data, size_t &size) {
+ uint32_t type = 0;
+ size = 0;
+ if (meta->findData(kKeyRawCodecSpecificData, &type, &data, &size)) {
+ ALOGV("OMXCodec::configureCodec found kKeyRawCodecSpecificData of size %d\n", size);
+ }
+}
+
+sp<ABuffer> ExtendedCodec::getRawCodecSpecificData(
+ const sp<AMessage> &msg) {
+ sp<ABuffer> buffer;
+ if (msg->findBuffer(getMsgKey(kKeyRawCodecSpecificData), &buffer)) {
+ ALOGV("ACodec found kKeyRawCodecSpecificData of size %d\n", buffer->size());
+ return buffer;
+ }
+ return NULL;
+}
+
+void ExtendedCodec::getAacCodecSpecificData(
+ const sp<MetaData> &meta, const void* &data, size_t &size) {
+ uint32_t type = 0;
+ size = 0;
+ if (meta->findData(kKeyAacCodecSpecificData, &type, &data, &size)) {
+ ALOGV("OMXCodec::configureCodec found kKeyAacCodecSpecificData of size %d\n", size);
+ }
+}
+
+sp<ABuffer> ExtendedCodec::getAacCodecSpecificData(
+ const sp<AMessage> &msg) {
+ sp<ABuffer> buffer;
+ if (msg->findBuffer(getMsgKey(kKeyAacCodecSpecificData), &buffer)) {
+ ALOGV("ACodec found kKeyAacCodecSpecificData of size %d\n", buffer->size());
+ return buffer;
+ }
+ return NULL;
+}
+
+status_t ExtendedCodec::setAudioFormat(
+ const sp<MetaData> &meta, const char* mime, sp<IOMX> OMXhandle,
+ IOMX::node_id nodeID, bool isEncoder ) {
+ sp<AMessage> msg = new AMessage();
+ msg->clear();
+ convertMetaDataToMessage(meta, &msg);
+ return setAudioFormat(msg, mime, OMXhandle, nodeID, isEncoder);
+}
+
+status_t ExtendedCodec::setAudioFormat(
+ const sp<AMessage> &msg, const char* mime, sp<IOMX> OMXhandle,
+ IOMX::node_id nodeID, bool isEncoder ) {
+ ALOGV("setAudioFormat called");
+ status_t err = OK;
+
+ if ((!strcasecmp(MEDIA_MIMETYPE_AUDIO_AC3, mime)) ||
+ (!strcasecmp(MEDIA_MIMETYPE_AUDIO_EAC3, mime))){
+ int32_t numChannels, sampleRate;
+ /* Commenting follwoing call as AC3 soft decoder does not
+ need it and it causes issue with playback*/
+ //setAC3Format(numChannels, sampleRate, OMXhandle, nodeID);
+ CHECK(msg->findInt32("channel-count", &numChannels));
+ CHECK(msg->findInt32("sample-rate", &sampleRate));
+ } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_EVRC, mime)) {
+ int32_t numChannels, sampleRate;
+ CHECK(msg->findInt32("channel-count", &numChannels));
+ CHECK(msg->findInt32("sample-rate", &sampleRate));
+ setEVRCFormat(numChannels, sampleRate, OMXhandle, nodeID, isEncoder );
+ } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_QCELP, mime)) {
+ int32_t numChannels, sampleRate;
+ CHECK(msg->findInt32("channel-count", &numChannels));
+ CHECK(msg->findInt32("sample-rate", &sampleRate));
+ setQCELPFormat(numChannels, sampleRate, OMXhandle, nodeID, isEncoder);
+ } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_WMA, mime)) {
+ err = setWMAFormat(msg, OMXhandle, nodeID, isEncoder);
+ }
+ return err;
+}
+
+status_t ExtendedCodec::setVideoInputFormat(
+ const char *mime, OMX_VIDEO_CODINGTYPE *compressionFormat) {
+ status_t retVal = OK;
+ if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX, mime)){
+ *compressionFormat= (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingDivx;
+ } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX4, mime)){
+ *compressionFormat= (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingDivx;
+ } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX311, mime)){
+ *compressionFormat= (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingDivx;
+ } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_WMV, mime)){
+ *compressionFormat = OMX_VIDEO_CodingWMV;
+ } else if (!strcasecmp(MEDIA_MIMETYPE_CONTAINER_MPEG2, mime)){
+ *compressionFormat = OMX_VIDEO_CodingMPEG2;
+ } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)){
+ *compressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingHevc;
+ } else {
+ retVal = BAD_VALUE;
+ }
+
+ return retVal;
+}
+
+status_t ExtendedCodec::setVideoOutputFormat(
+ const char *mime, OMX_VIDEO_CODINGTYPE *compressionFormat) {
+ status_t retVal = OK;
+ if(!strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX, mime)) {
+ *compressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingDivx;
+ } else if(!strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX311, mime)) {
+ *compressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingDivx;
+ } else if(!strcasecmp(MEDIA_MIMETYPE_VIDEO_DIVX4, mime)) {
+ *compressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingDivx;
+ } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_WMV, mime)){
+ *compressionFormat = OMX_VIDEO_CodingWMV;
+ } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)){
+ *compressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingHevc;
+ } else {
+ retVal = BAD_VALUE;
+ }
+ return retVal;
+}
+
+status_t ExtendedCodec::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 kQCMimeToRole[] = {
+ { MEDIA_MIMETYPE_AUDIO_EVRC,
+ "audio_decoder.evrchw", "audio_encoder.evrc" },
+ { MEDIA_MIMETYPE_AUDIO_QCELP,
+ "audio_decoder,qcelp13Hw", "audio_encoder.qcelp13" },
+ { 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.vc1", NULL },
+ { MEDIA_MIMETYPE_AUDIO_AC3,
+ "audio_decoder.ac3", NULL },
+ { MEDIA_MIMETYPE_AUDIO_WMA,
+ "audio_decoder.wma" , NULL },
+ };
+
+ static const size_t kNumMimeToRole =
+ sizeof(kQCMimeToRole) / sizeof(kQCMimeToRole[0]);
+
+ size_t i;
+ for (i = 0; i < kNumMimeToRole; ++i) {
+ if (!strcasecmp(mime, kQCMimeToRole[i].mime)) {
+ break;
+ }
+ }
+
+ if (i == kNumMimeToRole) {
+ return ERROR_UNSUPPORTED;
+ }
+
+ const char *role =
+ isEncoder ? kQCMimeToRole[i].encoderRole
+ : kQCMimeToRole[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;
+}
+
+status_t ExtendedCodec::getSupportedAudioFormatInfo(
+ const AString* mime,
+ sp<IOMX> OMXhandle,
+ IOMX::node_id nodeID,
+ int portIndex,
+ int* channelCount) {
+ status_t retVal = OK;
+ if (!strcmp(mime->c_str(),MEDIA_MIMETYPE_AUDIO_QCELP)) {
+ OMX_AUDIO_PARAM_QCELP13TYPE params;
+ InitOMXParams(¶ms);
+ params.nPortIndex = portIndex;
+ CHECK_EQ(OMXhandle->getParameter(
+ nodeID, OMX_IndexParamAudioQcelp13, ¶ms, sizeof(params)), (status_t)OK);
+ *channelCount = params.nChannels;
+ } else if(!strcmp(mime->c_str(), MEDIA_MIMETYPE_AUDIO_EVRC)) {
+ OMX_AUDIO_PARAM_EVRCTYPE params;
+ InitOMXParams(¶ms);
+ params.nPortIndex = portIndex;
+ CHECK_EQ(OMXhandle->getParameter(
+ nodeID, OMX_IndexParamAudioEvrc, ¶ms, sizeof(params)), (status_t)OK);
+ *channelCount = params.nChannels;
+ } else {
+ retVal = BAD_VALUE;
+ }
+ return retVal;
+}
+
+status_t ExtendedCodec::handleSupportedAudioFormats(int format, AString* mime) {
+ ALOGV("checkQCFormats called");
+ status_t retVal = OK;
+ if (format == OMX_AUDIO_CodingQCELP13 ) {
+ *mime = MEDIA_MIMETYPE_AUDIO_QCELP;
+ } else if(format == OMX_AUDIO_CodingEVRC ) {
+ *mime = MEDIA_MIMETYPE_AUDIO_EVRC;
+ } else {
+ retVal = BAD_VALUE;
+ }
+ return retVal;
+}
+
+void ExtendedCodec::configureFramePackingFormat(
+ const sp<AMessage> &msg, sp<IOMX> OMXhandle, IOMX::node_id nodeID,
+ const char* componentName) {
+ //ignore non QC components
+ if (strncmp(componentName, "OMX.qcom.", 9)) {
+ return;
+ }
+
+ int32_t arbitraryMode = 0;
+ bool success = msg->findInt32(getMsgKey(kKeyUseArbitraryMode), &arbitraryMode);
+ bool useFrameByFrameMode = true; //default option
+ if (success && arbitraryMode) {
+ useFrameByFrameMode = false;
+ }
+
+ if (useFrameByFrameMode) {
+ ALOGI("Enable frame by frame mode");
+ OMX_QCOM_PARAM_PORTDEFINITIONTYPE portFmt;
+ portFmt.nPortIndex = kPortIndexInput;
+ portFmt.nFramePackingFormat = OMX_QCOM_FramePacking_OnlyOneCompleteFrame;
+ status_t err = OMXhandle->setParameter(
+ nodeID, (OMX_INDEXTYPE)OMX_QcomIndexPortDefn, (void *)&portFmt, sizeof(portFmt));
+ if(err != OK) {
+ ALOGW("Failed to set frame packing format on component");
+ }
+ } else {
+ ALOGI("Decoder should be in arbitrary mode");
+ }
+}
+
+void ExtendedCodec::configureFramePackingFormat(
+ const sp<MetaData> &meta, sp<IOMX> OMXhandle, IOMX::node_id nodeID,
+ const char* componentName) {
+ sp<AMessage> msg = new AMessage();
+ msg->clear();
+ convertMetaDataToMessage(meta, &msg);
+ configureFramePackingFormat(msg, OMXhandle, nodeID, componentName);
+}
+
+void ExtendedCodec::configureVideoDecoder(
+ const sp<AMessage> &msg, const char* mime, sp<IOMX> OMXhandle,
+ const uint32_t flags, IOMX::node_id nodeID, const char* componentName ) {
+ if (strncmp(componentName, "OMX.qcom.", 9)) {
+ //do nothing for non QC component
+ return;
+ }
+
+ setDIVXFormat(msg, mime, OMXhandle, nodeID, kPortIndexOutput);
+ AString fileFormat;
+ const char *fileFormatCStr = NULL;
+ bool success = msg->findString(getMsgKey(kKeyFileFormat), &fileFormat);
+ if (success) {
+ fileFormatCStr = fileFormat.c_str();
+ }
+
+ // Enable timestamp reordering for AVI file type, mpeg4 and vc1 codec types
+ if (!strcmp(componentName, "OMX.qcom.video.decoder.vc1") ||
+ !strcmp(componentName, "OMX.qcom.video.decoder.mpeg4") ||
+ (fileFormatCStr!= NULL && !strncmp(fileFormatCStr, "video/avi", 9))) {
+ ALOGI("Enabling timestamp reordering");
+ QOMX_INDEXTIMESTAMPREORDER reorder;
+ InitOMXParams(&reorder);
+ reorder.nPortIndex = kPortIndexOutput;
+ reorder.bEnable = OMX_TRUE;
+ status_t err = OMXhandle->setParameter(nodeID,
+ (OMX_INDEXTYPE)OMX_QcomIndexParamEnableTimeStampReorder,
+ (void *)&reorder, sizeof(reorder));
+
+ if(err != OK) {
+ ALOGW("Failed to enable timestamp reordering");
+ }
+ }
+
+ // Enable Sync-frame decode mode for thumbnails
+ if (flags & OMXCodec::kClientNeedsFramebuffer) {
+ ALOGV("Enabling thumbnail mode.");
+ QOMX_ENABLETYPE enableType;
+ OMX_INDEXTYPE indexType;
+
+ status_t err = OMXhandle->getExtensionIndex(
+ nodeID, OMX_QCOM_INDEX_PARAM_VIDEO_SYNCFRAMEDECODINGMODE,
+ &indexType);
+ if(err != OK) {
+ ALOGW("Failed to get extension for SYNCFRAMEDECODINGMODE");
+ return;
+ }
+
+ enableType.bEnable = OMX_TRUE;
+ err = OMXhandle->setParameter(nodeID,indexType,
+ (void *)&enableType, sizeof(enableType));
+ if(err != OK) {
+ ALOGW("Failed to get extension for SYNCFRAMEDECODINGMODE");
+ return;
+ }
+ ALOGI("Thumbnail mode enabled.");
+ }
+
+}
+
+void ExtendedCodec::configureVideoDecoder(
+ const sp<MetaData> &meta, const char* mime, sp<IOMX> OMXhandle,
+ const uint32_t flags, IOMX::node_id nodeID, const char* componentName ) {
+ sp<AMessage> msg = new AMessage();
+ msg->clear();
+ convertMetaDataToMessage(meta, &msg);
+ configureVideoDecoder(msg, mime, OMXhandle, flags, nodeID, componentName);
+}
+
+void ExtendedCodec::enableSmoothStreaming(
+ const sp<IOMX> &omx, IOMX::node_id nodeID, bool* isEnabled,
+ const char* componentName) {
+ *isEnabled = false;
+
+ if (!ExtendedUtils::ShellProp::isSmoothStreamingEnabled()) {
+ return;
+ }
+
+ //ignore non QC components
+ if (strncmp(componentName, "OMX.qcom.", 9)) {
+ return;
+ }
+ status_t err = omx->setParameter(
+ nodeID,
+ (OMX_INDEXTYPE)OMX_QcomIndexParamEnableSmoothStreaming,
+ &err, sizeof(status_t));
+ if (err != OK) {
+ ALOGE("Failed to enable Smoothstreaming!");
+ return;
+ }
+ *isEnabled = true;
+ ALOGI("Smoothstreaming Enabled");
+ return;
+}
+
+//private methods
+void ExtendedCodec::setEVRCFormat(
+ int32_t numChannels, int32_t sampleRate, sp<IOMX> OMXhandle,
+ IOMX::node_id nodeID, bool isEncoder ) {
+ ALOGV("setEVRCFormat called");
+
+ if (isEncoder) {
+ CHECK(numChannels == 1);
+ //////////////// input port ////////////////////
+ //handle->setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
+ //////////////// output port ////////////////////
+ // format
+ OMX_AUDIO_PARAM_PORTFORMATTYPE format;
+ format.nPortIndex = kPortIndexOutput;
+ format.nIndex = 0;
+ status_t err = OMX_ErrorNone;
+ while (OMX_ErrorNone == err) {
+ CHECK_EQ(OMXhandle->getParameter(nodeID, OMX_IndexParamAudioPortFormat,
+ &format, sizeof(format)), (status_t)OK);
+ if (format.eEncoding == OMX_AUDIO_CodingEVRC) {
+ break;
+ }
+ format.nIndex++;
+ }
+ CHECK_EQ((status_t)OK, err);
+ CHECK_EQ(OMXhandle->setParameter(nodeID, OMX_IndexParamAudioPortFormat,
+ &format, sizeof(format)), (status_t)OK);
+
+ // port definition
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ InitOMXParams(&def);
+ def.nPortIndex = kPortIndexOutput;
+ def.format.audio.cMIMEType = NULL;
+ CHECK_EQ(OMXhandle->getParameter(nodeID, OMX_IndexParamPortDefinition,
+ &def, sizeof(def)), (status_t)OK);
+ def.format.audio.bFlagErrorConcealment = OMX_TRUE;
+ def.format.audio.eEncoding = OMX_AUDIO_CodingEVRC;
+ CHECK_EQ(OMXhandle->setParameter(nodeID, OMX_IndexParamPortDefinition,
+ &def, sizeof(def)), (status_t)OK);
+
+ // profile
+ OMX_AUDIO_PARAM_EVRCTYPE profile;
+ InitOMXParams(&profile);
+ profile.nPortIndex = kPortIndexOutput;
+ CHECK_EQ(OMXhandle->getParameter(nodeID, OMX_IndexParamAudioEvrc,
+ &profile, sizeof(profile)), (status_t)OK);
+ profile.nChannels = numChannels;
+ CHECK_EQ(OMXhandle->setParameter(nodeID, OMX_IndexParamAudioEvrc,
+ &profile, sizeof(profile)), (status_t)OK);
+ }
+ else{
+ ALOGI("EVRC decoder \n");
+ }
+}
+
+void ExtendedCodec::setQCELPFormat(
+ int32_t numChannels, int32_t sampleRate, sp<IOMX> OMXhandle,
+ IOMX::node_id nodeID, bool isEncoder ) {
+
+ if (isEncoder) {
+ CHECK(numChannels == 1);
+ //////////////// input port ////////////////////
+ //handle->setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
+ //////////////// output port ////////////////////
+ // format
+ OMX_AUDIO_PARAM_PORTFORMATTYPE format;
+ format.nPortIndex = kPortIndexOutput;
+ format.nIndex = 0;
+ status_t err = OMX_ErrorNone;
+ while (OMX_ErrorNone == err) {
+ CHECK_EQ(OMXhandle->getParameter(nodeID, OMX_IndexParamAudioPortFormat,
+ &format, sizeof(format)), (status_t)OK);
+ if (format.eEncoding == OMX_AUDIO_CodingQCELP13) {
+ break;
+ }
+ format.nIndex++;
+ }
+ CHECK_EQ((status_t)OK, err);
+ CHECK_EQ(OMXhandle->setParameter(nodeID, OMX_IndexParamAudioPortFormat,
+ &format, sizeof(format)), (status_t)OK);
+
+ // port definition
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ InitOMXParams(&def);
+ def.nPortIndex = kPortIndexOutput;
+ def.format.audio.cMIMEType = NULL;
+ CHECK_EQ(OMXhandle->getParameter(nodeID, OMX_IndexParamPortDefinition,
+ &def, sizeof(def)), (status_t)OK);
+ def.format.audio.bFlagErrorConcealment = OMX_TRUE;
+ def.format.audio.eEncoding = OMX_AUDIO_CodingQCELP13;
+ CHECK_EQ(OMXhandle->setParameter(nodeID, OMX_IndexParamPortDefinition,
+ &def, sizeof(def)), (status_t)OK);
+
+ // profile
+ OMX_AUDIO_PARAM_QCELP13TYPE profile;
+ InitOMXParams(&profile);
+ profile.nPortIndex = kPortIndexOutput;
+ CHECK_EQ(OMXhandle->getParameter(nodeID, OMX_IndexParamAudioQcelp13,
+ &profile, sizeof(profile)), (status_t)OK);
+ profile.nChannels = numChannels;
+ CHECK_EQ(OMXhandle->setParameter(nodeID, OMX_IndexParamAudioQcelp13,
+ &profile, sizeof(profile)), (status_t)OK);
+ }
+ else {
+ ALOGI("QCELP decoder \n");
+ }
+}
+
+status_t ExtendedCodec::setWMAFormat(
+ const sp<MetaData> &meta, sp<IOMX> OMXhandle,
+ IOMX::node_id nodeID, bool isEncoder ) {
+ sp<AMessage> msg = new AMessage();
+ msg->clear();
+ convertMetaDataToMessage(meta, &msg);
+ return setWMAFormat(msg, OMXhandle, nodeID, isEncoder);
+}
+
+status_t ExtendedCodec::setWMAFormat(
+ const sp<AMessage> &msg, sp<IOMX> OMXhandle,
+ IOMX::node_id nodeID, bool isEncoder ) {
+ ALOGV("setWMAFormat Called");
+
+ if (isEncoder) {
+ ALOGE("WMA encoding not supported");
+ return OK;
+ } else {
+ int32_t version;
+ OMX_AUDIO_PARAM_WMATYPE paramWMA;
+ QOMX_AUDIO_PARAM_WMA10PROTYPE paramWMA10;
+ CHECK(msg->findInt32(getMsgKey(kKeyWMAVersion), &version));
+ int32_t numChannels;
+ int32_t bitRate;
+ int32_t sampleRate;
+ int32_t encodeOptions;
+ int32_t blockAlign;
+ int32_t bitspersample;
+ int32_t formattag;
+ int32_t advencopt1;
+ int32_t advencopt2;
+ int32_t VirtualPktSize;
+ if(version==kTypeWMAPro || version==kTypeWMALossLess) {
+ CHECK(msg->findInt32(getMsgKey(kKeyWMABitspersample), &bitspersample));
+ CHECK(msg->findInt32(getMsgKey(kKeyWMAFormatTag), &formattag));
+ CHECK(msg->findInt32(getMsgKey(kKeyWMAAdvEncOpt1), &advencopt1));
+ CHECK(msg->findInt32(getMsgKey(kKeyWMAAdvEncOpt2), &advencopt2));
+ CHECK(msg->findInt32(getMsgKey(kKeyWMAVirPktSize), &VirtualPktSize));
+ }
+ if(version==kTypeWMA) {
+ InitOMXParams(¶mWMA);
+ paramWMA.nPortIndex = kPortIndexInput;
+ } else if(version==kTypeWMAPro || version==kTypeWMALossLess) {
+ InitOMXParams(¶mWMA10);
+ paramWMA10.nPortIndex = kPortIndexInput;
+ }
+ CHECK(msg->findInt32("channel-count", &numChannels));
+ CHECK(msg->findInt32("sample-rate", &sampleRate));
+ CHECK(msg->findInt32(getMsgKey(kKeyBitRate), &bitRate));
+ CHECK(msg->findInt32(getMsgKey(kKeyWMAEncodeOpt), &encodeOptions));
+ CHECK(msg->findInt32(getMsgKey(kKeyWMABlockAlign), &blockAlign));
+ ALOGV("Channels: %d, SampleRate: %d, BitRate; %d"
+ "EncodeOptions: %d, blockAlign: %d", numChannels,
+ sampleRate, bitRate, encodeOptions, blockAlign);
+ if(sampleRate>48000 || numChannels>2)
+ {
+ ALOGE("Unsupported samplerate/channels");
+ return ERROR_UNSUPPORTED;
+ }
+ if(version==kTypeWMAPro || version==kTypeWMALossLess)
+ {
+ ALOGV("Bitspersample: %d, wmaformattag: %d,"
+ "advencopt1: %d, advencopt2: %d VirtualPktSize %d", bitspersample,
+ formattag, advencopt1, advencopt2, VirtualPktSize);
+ }
+ status_t err = OK;
+ OMX_INDEXTYPE index;
+ if(version==kTypeWMA) {
+ err = OMXhandle->getParameter(
+ nodeID, OMX_IndexParamAudioWma, ¶mWMA, sizeof(paramWMA));
+ } else if(version==kTypeWMAPro || version==kTypeWMALossLess) {
+ OMXhandle->getExtensionIndex(nodeID,"OMX.Qualcomm.index.audio.wma10Pro",&index);
+ err = OMXhandle->getParameter(
+ nodeID, index, ¶mWMA10, sizeof(paramWMA10));
+ }
+ CHECK_EQ(err, (status_t)OK);
+ if(version==kTypeWMA) {
+ paramWMA.nChannels = numChannels;
+ paramWMA.nSamplingRate = sampleRate;
+ paramWMA.nEncodeOptions = encodeOptions;
+ paramWMA.nBitRate = bitRate;
+ paramWMA.nBlockAlign = blockAlign;
+ } else if(version==kTypeWMAPro || version==kTypeWMALossLess) {
+ paramWMA10.nChannels = numChannels;
+ paramWMA10.nSamplingRate = sampleRate;
+ paramWMA10.nEncodeOptions = encodeOptions;
+ paramWMA10.nBitRate = bitRate;
+ paramWMA10.nBlockAlign = blockAlign;
+ }
+ if(version==kTypeWMAPro || version==kTypeWMALossLess) {
+ paramWMA10.advancedEncodeOpt = advencopt1;
+ paramWMA10.advancedEncodeOpt2 = advencopt2;
+ paramWMA10.formatTag = formattag;
+ paramWMA10.validBitsPerSample = bitspersample;
+ paramWMA10.nVirtualPktSize = VirtualPktSize;
+ }
+ if(version==kTypeWMA) {
+ err = OMXhandle->setParameter(
+ nodeID, OMX_IndexParamAudioWma, ¶mWMA, sizeof(paramWMA));
+ } else if(version==kTypeWMAPro || version==kTypeWMALossLess) {
+ err = OMXhandle->setParameter(
+ nodeID, index, ¶mWMA10, sizeof(paramWMA10));
+ }
+ return err;
+ }
+ return OK;
+}
+
+void ExtendedCodec::setAC3Format(
+ int32_t numChannels, int32_t sampleRate, sp<IOMX> OMXhandle,
+ IOMX::node_id nodeID) {
+ QOMX_AUDIO_PARAM_AC3TYPE profileAC3;
+ QOMX_AUDIO_PARAM_AC3PP profileAC3PP;
+ OMX_INDEXTYPE indexTypeAC3;
+ OMX_INDEXTYPE indexTypeAC3PP;
+ OMX_PARAM_PORTDEFINITIONTYPE portParam;
+
+ //configure input port
+ ALOGV("setAC3Format samplerate %d, numChannels %d", sampleRate, numChannels);
+ InitOMXParams(&portParam);
+ portParam.nPortIndex = 0;
+ status_t err = OMXhandle->getParameter(
+ nodeID, OMX_IndexParamPortDefinition, &portParam, sizeof(portParam));
+ CHECK_EQ(err, (status_t)OK);
+ err = OMXhandle->setParameter(
+ nodeID, OMX_IndexParamPortDefinition, &portParam, sizeof(portParam));
+ CHECK_EQ(err, (status_t)OK);
+
+ //configure output port
+ portParam.nPortIndex = 1;
+ err = OMXhandle->getParameter(
+ nodeID, OMX_IndexParamPortDefinition, &portParam, sizeof(portParam));
+ CHECK_EQ(err, (status_t)OK);
+ err = OMXhandle->setParameter(
+ nodeID, OMX_IndexParamPortDefinition, &portParam, sizeof(portParam));
+ CHECK_EQ(err, (status_t)OK);
+
+ err = OMXhandle->getExtensionIndex(nodeID, OMX_QCOM_INDEX_PARAM_AC3TYPE, &indexTypeAC3);
+
+ InitOMXParams(&profileAC3);
+ profileAC3.nPortIndex = kPortIndexInput;
+ err = OMXhandle->getParameter(nodeID, indexTypeAC3, &profileAC3, sizeof(profileAC3));
+ CHECK_EQ(err,(status_t)OK);
+
+ profileAC3.nSamplingRate = sampleRate;
+ profileAC3.nChannels = 2;
+ profileAC3.eChannelConfig = OMX_AUDIO_AC3_CHANNEL_CONFIG_2_0;
+
+ ALOGV("numChannels = %d, profileAC3.nChannels = %d", numChannels, profileAC3.nChannels);
+
+ err = OMXhandle->setParameter(nodeID, indexTypeAC3, &profileAC3, sizeof(profileAC3));
+ CHECK_EQ(err,(status_t)OK);
+
+ //for output port
+ OMX_AUDIO_PARAM_PCMMODETYPE profilePcm;
+ InitOMXParams(&profilePcm);
+ profilePcm.nPortIndex = kPortIndexOutput;
+ err = OMXhandle->getParameter(
+ nodeID, OMX_IndexParamAudioPcm, &profilePcm, sizeof(profilePcm));
+ CHECK_EQ(err, (status_t)OK);
+
+ profilePcm.nSamplingRate = sampleRate;
+ err = OMXhandle->setParameter(
+ nodeID, OMX_IndexParamAudioPcm, &profilePcm, sizeof(profilePcm));
+ CHECK_EQ(err, (status_t)OK);
+ OMXhandle->getExtensionIndex(nodeID, OMX_QCOM_INDEX_PARAM_AC3PP, &indexTypeAC3PP);
+
+ InitOMXParams(&profileAC3PP);
+ profileAC3PP.nPortIndex = kPortIndexInput;
+ err = OMXhandle->getParameter(
+ nodeID, indexTypeAC3PP, &profileAC3PP, sizeof(profileAC3PP));
+ CHECK_EQ(err, (status_t)OK);
+
+ int i;
+ int channel_routing[6] = {0};
+
+ for (i=0; i<6; i++) {
+ channel_routing[i] = -1;
+ }
+ for (i=0; i<6; i++) {
+ profileAC3PP.eChannelRouting[i] = (OMX_AUDIO_AC3_CHANNEL_ROUTING)channel_routing[i];
+ }
+
+ profileAC3PP.eChannelRouting[0] = OMX_AUDIO_AC3_CHANNEL_LEFT;
+ profileAC3PP.eChannelRouting[1] = OMX_AUDIO_AC3_CHANNEL_RIGHT;
+ err = OMXhandle->setParameter(nodeID, indexTypeAC3PP, &profileAC3PP, sizeof(profileAC3PP));
+ CHECK_EQ(err, (status_t)OK);
+}
+
+bool ExtendedCodec::useHWAACDecoder(const char *mime) {
+ char value[PROPERTY_VALUE_MAX] = {0};
+ int aaccodectype = 0;
+ aaccodectype = property_get("media.aaccodectype", value, NULL);
+ if (aaccodectype && !strncmp("0", value, 1) &&
+ !strncmp(mime, MEDIA_MIMETYPE_AUDIO_AAC,sizeof(MEDIA_MIMETYPE_AUDIO_AAC))) {
+ ALOGI("Using Hardware AAC Decoder");
+ return true;
+ }
+ return false;
+}
+
+} //namespace android
+
+#else //ENABLE_AV_ENHANCEMENTS
+
+namespace android {
+ status_t ExtendedCodec::convertMetaDataToMessage(
+ const sp<MetaData> &meta, sp<AMessage> *format) {
+ return OK;
+ }
+
+ uint32_t ExtendedCodec::getComponentQuirks (
+ const MediaCodecList *list, size_t index) {
+ return 0;
+ }
+
+ status_t ExtendedCodec::setDIVXFormat(
+ const sp<AMessage> &msg, const char* mime,
+ sp<IOMX> OMXhandle,IOMX::node_id nodeID, int port_index) {
+ return OK;
+ }
+
+ status_t ExtendedCodec::setAudioFormat(
+ const sp<MetaData> &meta, const char* mime,
+ sp<IOMX> OMXhandle,IOMX::node_id nodeID,
+ bool isEncoder) {
+ return OK;
+ }
+
+ status_t ExtendedCodec::setAudioFormat(
+ const sp<AMessage> &msg, const char* mime,
+ sp<IOMX> OMXhandle,IOMX::node_id nodeID,
+ bool isEncoder) {
+ return OK;
+ }
+
+ status_t ExtendedCodec::setVideoInputFormat(
+ const char *mime,
+ OMX_VIDEO_CODINGTYPE *compressionFormat) {
+ return OK;
+ }
+
+ status_t ExtendedCodec::setVideoOutputFormat(
+ const char *mime,
+ OMX_VIDEO_CODINGTYPE *compressionFormat) {
+ return OK;
+ }
+
+ status_t ExtendedCodec::getSupportedAudioFormatInfo(
+ const AString* mime,
+ sp<IOMX> OMXhandle,
+ IOMX::node_id nodeID,
+ int portIndex,
+ int* channelCount) {
+ return OK;
+ }
+
+ status_t ExtendedCodec::handleSupportedAudioFormats(
+ int format, AString* meta) {
+ return UNKNOWN_ERROR;
+ }
+
+ const char* ExtendedCodec::overrideComponentName (
+ uint32_t quirks, const sp<MetaData> &meta) {
+ return NULL;
+ }
+
+ void ExtendedCodec::overrideComponentName(
+ uint32_t quirks, const sp<AMessage> &msg,
+ AString* componentName){
+ }
+
+ void ExtendedCodec::getRawCodecSpecificData(
+ const sp<MetaData> &meta, const void* &data, size_t &size) {
+ size = 0;
+ }
+
+ sp<ABuffer> ExtendedCodec::getRawCodecSpecificData(
+ const sp<AMessage> &msg){
+ return NULL;
+ }
+
+ void ExtendedCodec::getAacCodecSpecificData(
+ const sp<MetaData> &meta,
+ const void* &data,
+ size_t& size){
+ return;
+ }
+
+ sp<ABuffer> ExtendedCodec::getAacCodecSpecificData(
+ const sp<AMessage> &msg){
+ return NULL;
+ }
+
+
+ status_t ExtendedCodec::setSupportedRole(
+ const sp<IOMX> &omx, IOMX::node_id node,
+ bool isEncoder, const char *mime) {
+ return OK;
+ }
+
+ status_t ExtendedCodec::setWMAFormat(
+ const sp<MetaData> &meta, sp<IOMX> OMXhandle,
+ IOMX::node_id nodeID, bool isEncoder) {
+ return OK;
+ }
+
+ status_t ExtendedCodec::setWMAFormat(
+ const sp<AMessage> &msg, sp<IOMX> OMXhandle,
+ IOMX::node_id nodeID, bool isEncoder) {
+ return OK;
+ }
+
+ void ExtendedCodec::setEVRCFormat(
+ int32_t numChannels, int32_t sampleRate,
+ sp<IOMX> OMXhandle, IOMX::node_id nodeID,
+ bool isEncoder) {
+ }
+
+ void ExtendedCodec::setQCELPFormat(
+ int32_t numChannels, int32_t sampleRate,
+ sp<IOMX> OMXhandle, IOMX::node_id nodeID,
+ bool isEncoder) {
+ }
+
+ void ExtendedCodec::setAC3Format(
+ int32_t numChannels, int32_t sampleRate,
+ sp<IOMX> OMXhandle, IOMX::node_id nodeID) {
+ }
+
+ void ExtendedCodec::configureFramePackingFormat(
+ const sp<AMessage> &msg, sp<IOMX> OMXhandle,
+ IOMX::node_id nodeID, const char* componentName){
+ }
+
+ void ExtendedCodec::configureFramePackingFormat(
+ const sp<MetaData> &meta, sp<IOMX> OMXhandle,
+ IOMX::node_id nodeID, const char* componentName) {
+ }
+
+ void ExtendedCodec::configureVideoDecoder(
+ const sp<MetaData> &meta, const char* mime, sp<IOMX> OMXhandle,
+ const uint32_t flags, IOMX::node_id nodeID, const char* componentName) {
+ }
+
+ void ExtendedCodec::configureVideoDecoder(
+ const sp<AMessage> &msg, const char* mime, sp<IOMX> OMXhandle,
+ const uint32_t flags, IOMX::node_id nodeID, const char* componentName) {
+ }
+
+ bool ExtendedCodec::useHWAACDecoder(const char *mime) {
+ return false;
+ }
+
+ void ExtendedCodec::enableSmoothStreaming(
+ const sp<IOMX> &omx, IOMX::node_id nodeID, bool* isEnabled,
+ const char* componentName) {
+ *isEnabled = false;
+ return;
+ }
+
+} //namespace android
+
+#endif //ENABLE_AV_ENHANCEMENTS
diff --git a/media/libstagefright/ExtendedExtractor.cpp b/media/libstagefright/ExtendedExtractor.cpp
new file mode 100644
index 0000000..952f542
--- /dev/null
+++ b/media/libstagefright/ExtendedExtractor.cpp
@@ -0,0 +1,143 @@
+/*Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ExtendedExtractor"
+#include <utils/Log.h>
+#include <dlfcn.h> // for dlopen/dlclose
+#include "include/ExtendedExtractor.h"
+
+#ifdef ENABLE_AV_ENHANCEMENTS
+
+namespace android {
+
+static const char* EXTENDED_EXTRACTOR_LIB = "libExtendedExtractor.so";
+static const char* EXTENDED_EXTRACTOR_CREATE = "CreateExtractor";
+static const char* EXTENDED_EXTRACTOR_SNIFF = "SniffExtendedExtractor";
+
+typedef MediaExtractor* (*ExtendedExtractorCreate)
+ (const sp<DataSource> &source, const char* mime);
+
+typedef bool (*ExtendedExtractorSniff)
+ (const sp<DataSource> &source, String8 *mimeType,
+ float *confidence,sp<AMessage> *meta);
+
+static void* loadExtendedExtractorLib() {
+ static void* extendedExtractorLib = NULL;
+ static bool alreadyTriedToLoadLib = false;
+
+ if(!alreadyTriedToLoadLib) {
+ alreadyTriedToLoadLib = true;
+
+ extendedExtractorLib = ::dlopen(EXTENDED_EXTRACTOR_LIB, RTLD_LAZY);
+
+ if(extendedExtractorLib == NULL) {
+ ALOGV("Failed to load %s, dlerror = %s \n",
+ EXTENDED_EXTRACTOR_LIB, dlerror());
+ }
+ }
+
+ return extendedExtractorLib;
+}
+
+MediaExtractor* ExtendedExtractor::Create (
+ const sp<DataSource> &source, const char *mime) {
+ static ExtendedExtractorCreate create = NULL;
+ static bool alreadyTriedToFindCreateFunction = false;
+ MediaExtractor* extractor = NULL;
+
+ if (!alreadyTriedToFindCreateFunction) {
+ void *extendedExtractorLib = loadExtendedExtractorLib();
+
+ if (extendedExtractorLib != NULL) {
+ create = (ExtendedExtractorCreate) dlsym (
+ extendedExtractorLib, EXTENDED_EXTRACTOR_CREATE);
+ alreadyTriedToFindCreateFunction = true;
+ }
+ }
+
+ if (create == NULL) {
+ ALOGE ("Failed to find symbol : %s, dlerror = %s",
+ EXTENDED_EXTRACTOR_CREATE, dlerror());
+ return NULL;
+ }
+
+ extractor = create (source, mime);
+ if (extractor == NULL) {
+ ALOGE("Failed to instantiate extractor \n");
+ }
+
+ return extractor;
+}
+
+bool ExtendedExtractor::Sniff (
+ const sp<DataSource> &source, String8 *mimeType,
+ float *confidence,sp<AMessage> *meta) {
+ void *extendedExtractorLib = loadExtendedExtractorLib();
+ bool retVal = false;
+
+ if (extendedExtractorLib != NULL) {
+ ExtendedExtractorSniff sniff = (ExtendedExtractorSniff) dlsym (
+ extendedExtractorLib, EXTENDED_EXTRACTOR_SNIFF);
+
+ if (sniff == NULL) {
+ ALOGE ("Failed to find symbol : %s, dlerror = %s",
+ EXTENDED_EXTRACTOR_SNIFF, dlerror());
+ return retVal;
+ }
+
+ retVal = sniff (source, mimeType, confidence, meta);
+
+ if(!retVal) {
+ ALOGV("Sniff Failed");
+ }
+ }
+ return retVal;
+}
+
+} // namespace android
+
+#else //ENABLE_AV_ENHANCEMENTS
+
+namespace android {
+
+MediaExtractor* ExtendedExtractor::Create (
+ const sp<DataSource> &source, const char *mime) {
+ return NULL;
+}
+bool ExtendedExtractor::Sniff (
+ const sp<DataSource> &source, String8 *mimeType,
+ float *confidence,sp<AMessage> *meta) {
+ *confidence = 0.0;
+ return false;
+}
+
+} // namespace android
+
+#endif //ENABLE_AV_ENHANCEMENTS
+
diff --git a/media/libstagefright/ExtendedMediaDefs.cpp b/media/libstagefright/ExtendedMediaDefs.cpp
new file mode 100644
index 0000000..209db2b
--- /dev/null
+++ b/media/libstagefright/ExtendedMediaDefs.cpp
@@ -0,0 +1,66 @@
+/*Copyright (c) 2012 - 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <QCMediaDefs.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_AUDIO_WMA = "audio/x-ms-wma";
+const char *MEDIA_MIMETYPE_CONTAINER_ASF = "video/x-ms-asf";
+const char *MEDIA_MIMETYPE_VIDEO_DIVX = "video/divx";
+const char *MEDIA_MIMETYPE_AUDIO_AC3 = "audio/ac3";
+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_EAC3 = "audio/eac3";
+const char *MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS = "audio/amr-wb-plus";
+const char *MEDIA_MIMETYPE_VIDEO_HEVC = "video/hevc";
+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
+
+} // namespace android
diff --git a/media/libstagefright/ExtendedUtils.cpp b/media/libstagefright/ExtendedUtils.cpp
new file mode 100644
index 0000000..1799784
--- /dev/null
+++ b/media/libstagefright/ExtendedUtils.cpp
@@ -0,0 +1,649 @@
+/*Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ExtendedUtils"
+#include <utils/Log.h>
+
+#include <utils/Errors.h>
+#include <sys/types.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/OMXCodec.h>
+#include <cutils/properties.h>
+#include <media/stagefright/MediaExtractor.h>
+
+#include "include/ExtendedUtils.h"
+
+static const int64_t kDefaultAVSyncLateMargin = 40000;
+static const int64_t kMaxAVSyncLateMargin = 250000;
+
+#ifdef ENABLE_AV_ENHANCEMENTS
+
+#include <QCMetaData.h>
+#include <QCMediaDefs.h>
+
+#include "include/ExtendedExtractor.h"
+#include "include/avc_utils.h"
+
+namespace android {
+
+void ExtendedUtils::HFR::setHFRIfEnabled(
+ const CameraParameters& params,
+ sp<MetaData> &meta) {
+ const char *hfr_str = params.get("video-hfr");
+ int32_t hfr = -1;
+ if ( hfr_str != NULL ) {
+ hfr = atoi(hfr_str);
+ }
+ if (hfr < 0) {
+ ALOGW("Invalid hfr value(%d) set from app. Disabling HFR.", hfr);
+ hfr = 0;
+ }
+
+ meta->setInt32(kKeyHFR, hfr);
+}
+
+status_t ExtendedUtils::HFR::reCalculateFileDuration(
+ sp<MetaData> &meta, sp<MetaData> &enc_meta,
+ int64_t &maxFileDurationUs, int32_t frameRate,
+ video_encoder videoEncoder) {
+ status_t retVal = OK;
+ int32_t hfr = 0;
+
+ if (!meta->findInt32(kKeyHFR, &hfr)) {
+ ALOGW("hfr not found, default to 0");
+ }
+
+ if (hfr && frameRate) {
+ maxFileDurationUs = maxFileDurationUs * (hfr/frameRate);
+ }
+
+ enc_meta->setInt32(kKeyHFR, hfr);
+ int32_t width = 0, height = 0;
+
+ CHECK(meta->findInt32(kKeyWidth, &width));
+ CHECK(meta->findInt32(kKeyHeight, &height));
+
+ char mDeviceName[100];
+ property_get("ro.board.platform",mDeviceName,"0");
+ if (!strncmp(mDeviceName, "msm7627a", 8)) {
+ if (hfr && (width * height > 432*240)) {
+ ALOGE("HFR mode is supported only upto WQVGA resolution");
+ return INVALID_OPERATION;
+ }
+ } else if (!strncmp(mDeviceName, "msm8974", 7) ||
+ !strncmp(mDeviceName, "msm8610", 7)) {
+ if (hfr && (width * height > 1920*1088)) {
+ ALOGE("HFR mode is supported only upto 1080p resolution");
+ return INVALID_OPERATION;
+ }
+ } else {
+ if (hfr && ((videoEncoder != VIDEO_ENCODER_H264) || (width * height > 800*480))) {
+ ALOGE("HFR mode is supported only upto WVGA and H264 codec.");
+ return INVALID_OPERATION;
+ }
+ }
+ return retVal;
+}
+
+void ExtendedUtils::HFR::reCalculateTimeStamp(
+ sp<MetaData> &meta, int64_t ×tampUs) {
+ int32_t frameRate = 0, hfr = 0;
+ if (!(meta->findInt32(kKeyFrameRate, &frameRate))) {
+ return;
+ }
+
+ if (!(meta->findInt32(kKeyHFR, &hfr))) {
+ return;
+ }
+
+ if (hfr && frameRate) {
+ timestampUs = (hfr * timestampUs) / frameRate;
+ }
+}
+
+void ExtendedUtils::HFR::reCalculateHFRParams(
+ const sp<MetaData> &meta, int32_t &frameRate,
+ int32_t &bitRate) {
+ int32_t hfr = 0;
+ if (!(meta->findInt32(kKeyHFR, &hfr))) {
+ return;
+ }
+
+ if (hfr && frameRate) {
+ bitRate = (hfr * bitRate) / frameRate;
+ frameRate = hfr;
+ }
+}
+
+void ExtendedUtils::HFR::copyHFRParams(
+ const sp<MetaData> &inputFormat,
+ sp<MetaData> &outputFormat) {
+ int32_t frameRate = 0, hfr = 0;
+ inputFormat->findInt32(kKeyHFR, &hfr);
+ inputFormat->findInt32(kKeyFrameRate, &frameRate);
+ outputFormat->setInt32(kKeyHFR, hfr);
+ outputFormat->setInt32(kKeyFrameRate, frameRate);
+}
+
+bool ExtendedUtils::ShellProp::isAudioDisabled() {
+ bool retVal = false;
+ char disableAudio[PROPERTY_VALUE_MAX];
+ property_get("persist.debug.sf.noaudio", disableAudio, "0");
+ if (atoi(disableAudio) == 1) {
+ retVal = true;
+ }
+ return retVal;
+}
+
+void ExtendedUtils::ShellProp::setEncoderProfile(
+ video_encoder &videoEncoder, int32_t &videoEncoderProfile) {
+ char value[PROPERTY_VALUE_MAX];
+ bool customProfile = false;
+ if (!property_get("encoder.video.profile", value, NULL) > 0) {
+ return;
+ }
+
+ switch (videoEncoder) {
+ case VIDEO_ENCODER_H264:
+ if (strncmp("base", value, 4) == 0) {
+ videoEncoderProfile = OMX_VIDEO_AVCProfileBaseline;
+ ALOGI("H264 Baseline Profile");
+ } else if (strncmp("main", value, 4) == 0) {
+ videoEncoderProfile = OMX_VIDEO_AVCProfileMain;
+ ALOGI("H264 Main Profile");
+ } else if (strncmp("high", value, 4) == 0) {
+ videoEncoderProfile = OMX_VIDEO_AVCProfileHigh;
+ ALOGI("H264 High Profile");
+ } else {
+ ALOGW("Unsupported H264 Profile");
+ }
+ break;
+ case VIDEO_ENCODER_MPEG_4_SP:
+ if (strncmp("simple", value, 5) == 0 ) {
+ videoEncoderProfile = OMX_VIDEO_MPEG4ProfileSimple;
+ ALOGI("MPEG4 Simple profile");
+ } else if (strncmp("asp", value, 3) == 0 ) {
+ videoEncoderProfile = OMX_VIDEO_MPEG4ProfileAdvancedSimple;
+ ALOGI("MPEG4 Advanced Simple Profile");
+ } else {
+ ALOGW("Unsupported MPEG4 Profile");
+ }
+ break;
+ default:
+ ALOGW("No custom profile support for other codecs");
+ break;
+ }
+}
+
+int64_t ExtendedUtils::ShellProp::getMaxAVSyncLateMargin() {
+ char lateMarginMs[PROPERTY_VALUE_MAX] = {0};
+ property_get("media.sf.set.late.margin", lateMarginMs, "0");
+ int64_t newLateMarginUs = atoi(lateMarginMs)*1000;
+ int64_t maxLateMarginUs = newLateMarginUs;
+
+ if (newLateMarginUs > kDefaultAVSyncLateMargin
+ || newLateMarginUs < kDefaultAVSyncLateMargin) {
+ maxLateMarginUs = kDefaultAVSyncLateMargin;
+ }
+
+ ALOGI("AV Sync late margin : Intended=%lldms Using=%lldms",
+ maxLateMarginUs/1000, newLateMarginUs/1000);
+ return maxLateMarginUs;
+}
+
+bool ExtendedUtils::ShellProp::isSmoothStreamingEnabled() {
+ char prop[PROPERTY_VALUE_MAX] = {0};
+ property_get("mm.enable.smoothstreaming", prop, "0");
+ if (!strncmp(prop, "true", 4) || atoi(prop)) {
+ return true;
+ }
+ return false;
+}
+
+void ExtendedUtils::setBFrames(
+ OMX_VIDEO_PARAM_MPEG4TYPE &mpeg4type, int32_t &numBFrames,
+ const char* componentName) {
+ //ignore non QC components
+ if (strncmp(componentName, "OMX.qcom.", 9)) {
+ return;
+ }
+ if (mpeg4type.eProfile > OMX_VIDEO_MPEG4ProfileSimple) {
+ mpeg4type.nAllowedPictureTypes |= OMX_VIDEO_PictureTypeB;
+ mpeg4type.nBFrames = 1;
+ mpeg4type.nPFrames /= (mpeg4type.nBFrames + 1);
+ numBFrames = mpeg4type.nBFrames;
+ }
+ return;
+}
+
+void ExtendedUtils::setBFrames(
+ OMX_VIDEO_PARAM_AVCTYPE &h264type, int32_t &numBFrames,
+ int32_t iFramesInterval, int32_t frameRate, const char* componentName) {
+ //ignore non QC components
+ if (strncmp(componentName, "OMX.qcom.", 9)) {
+ return;
+ }
+ OMX_U32 val = 0;
+ if (iFramesInterval < 0) {
+ val = 0xFFFFFFFF;
+ } else if (iFramesInterval == 0) {
+ val = 0;
+ } else {
+ val = frameRate * iFramesInterval - 1;
+ CHECK(val > 1);
+ }
+
+ h264type.nPFrames = val;
+
+ if (h264type.nPFrames == 0) {
+ h264type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI;
+ }
+
+ if (h264type.eProfile > OMX_VIDEO_AVCProfileBaseline) {
+ h264type.nAllowedPictureTypes |= OMX_VIDEO_PictureTypeB;
+ h264type.nBFrames = 1;
+ h264type.nPFrames /= (h264type.nBFrames + 1);
+ //enable CABAC as default entropy mode for Hihg/Main profiles
+ h264type.bEntropyCodingCABAC = OMX_TRUE;
+ h264type.nCabacInitIdc = 0;
+ numBFrames = h264type.nBFrames;
+ }
+ return;
+}
+
+/*
+QCOM HW AAC encoder allowed bitrates
+------------------------------------------------------------------------------------------------------------------
+Bitrate limit |AAC-LC(Mono) | AAC-LC(Stereo) |AAC+(Mono) | AAC+(Stereo) | eAAC+ |
+Minimum |Min(24000,0.5 * f_s) |Min(24000,f_s) | 24000 |24000 | 24000 |
+Maximum |Min(192000,6 * f_s) |Min(192000,12 * f_s) | Min(192000,6 * f_s) | Min(192000,12 * f_s) | Min(192000,12 * f_s) |
+------------------------------------------------------------------------------------------------------------------
+*/
+bool ExtendedUtils::UseQCHWAACEncoder(audio_encoder Encoder,int32_t Channel,int32_t BitRate,int32_t SampleRate)
+{
+ bool ret = false;
+ int minBiteRate = -1;
+ int maxBiteRate = -1;
+ char propValue[PROPERTY_VALUE_MAX] = {0};
+
+ property_get("qcom.hw.aac.encoder",propValue,NULL);
+ if (!strncmp(propValue,"true",sizeof("true"))) {
+ //check for QCOM's HW AAC encoder only when qcom.aac.encoder = true;
+ ALOGV("qcom.aac.encoder enabled, check AAC encoder(%d) allowed bitrates",Encoder);
+ switch (Encoder) {
+ case AUDIO_ENCODER_AAC:// for AAC-LC format
+ if (Channel == 1) {//mono
+ minBiteRate = MIN_BITERATE_AAC<(SampleRate/2)?MIN_BITERATE_AAC:(SampleRate/2);
+ maxBiteRate = MAX_BITERATE_AAC<(SampleRate*6)?MAX_BITERATE_AAC:(SampleRate*6);
+ } else if (Channel == 2) {//stereo
+ minBiteRate = MIN_BITERATE_AAC<SampleRate?MIN_BITERATE_AAC:SampleRate;
+ maxBiteRate = MAX_BITERATE_AAC<(SampleRate*12)?MAX_BITERATE_AAC:(SampleRate*12);
+ }
+ break;
+ case AUDIO_ENCODER_HE_AAC:// for AAC+ format
+ if (Channel == 1) {//mono
+ minBiteRate = MIN_BITERATE_AAC;
+ maxBiteRate = MAX_BITERATE_AAC<(SampleRate*6)?MAX_BITERATE_AAC:(SampleRate*6);
+ } else if (Channel == 2) {//stereo
+ minBiteRate = MIN_BITERATE_AAC;
+ maxBiteRate = MAX_BITERATE_AAC<(SampleRate*12)?MAX_BITERATE_AAC:(SampleRate*12);
+ }
+ break;
+ default:
+ ALOGV("encoder:%d not supported by QCOM HW AAC encoder",Encoder);
+
+ }
+
+ //return true only when 1. minBiteRate and maxBiteRate are updated(not -1) 2. minBiteRate <= SampleRate <= maxBiteRate
+ if (SampleRate >= minBiteRate && SampleRate <= maxBiteRate) {
+ ret = true;
+ }
+ }
+
+ return ret;
+}
+
+
+//- returns NULL if we dont really need a new extractor (or cannot),
+// valid extractor is returned otherwise
+//- caller needs to check for NULL
+// ----------------------------------------
+// defaultExt - the existing extractor
+// source - file source
+// mime - container mime
+// ----------------------------------------
+// Note: defaultExt will be deleted in this function if the new parser is selected
+
+sp<MediaExtractor> ExtendedUtils::MediaExtractor_CreateIfNeeded(sp<MediaExtractor> defaultExt,
+ const sp<DataSource> &source,
+ const char *mime) {
+ bool bCheckExtendedExtractor = false;
+ bool videoTrackFound = false;
+ bool audioTrackFound = false;
+ bool amrwbAudio = false;
+ int numOfTrack = 0;
+
+ if (defaultExt != NULL) {
+ for (size_t trackItt = 0; trackItt < defaultExt->countTracks(); ++trackItt) {
+ ++numOfTrack;
+ sp<MetaData> meta = defaultExt->getTrackMetaData(trackItt);
+ const char *_mime;
+ CHECK(meta->findCString(kKeyMIMEType, &_mime));
+
+ String8 mime = String8(_mime);
+
+ if (!strncasecmp(mime.string(), "audio/", 6)) {
+ audioTrackFound = true;
+
+ amrwbAudio = !strncasecmp(mime.string(),
+ MEDIA_MIMETYPE_AUDIO_AMR_WB,
+ strlen(MEDIA_MIMETYPE_AUDIO_AMR_WB));
+ if (amrwbAudio) {
+ break;
+ }
+ }else if(!strncasecmp(mime.string(), "video/", 6)) {
+ videoTrackFound = true;
+ }
+ }
+
+ if(amrwbAudio) {
+ bCheckExtendedExtractor = true;
+ }else if (numOfTrack == 0) {
+ bCheckExtendedExtractor = true;
+ } else if(numOfTrack == 1) {
+ if((videoTrackFound) ||
+ (!videoTrackFound && !audioTrackFound)){
+ bCheckExtendedExtractor = true;
+ }
+ } else if (numOfTrack >= 2){
+ if(videoTrackFound && audioTrackFound) {
+ if(amrwbAudio) {
+ bCheckExtendedExtractor = true;
+ }
+ } else {
+ bCheckExtendedExtractor = true;
+ }
+ }
+ } else {
+ bCheckExtendedExtractor = true;
+ }
+
+ if (!bCheckExtendedExtractor) {
+ ALOGD("extended extractor not needed, return default");
+ return defaultExt;
+ }
+
+ //Create Extended Extractor only if default extractor is not selected
+ ALOGD("Try creating ExtendedExtractor");
+ sp<MediaExtractor> retExtExtractor = ExtendedExtractor::Create(source, mime);
+
+ if (retExtExtractor == NULL) {
+ ALOGD("Couldn't create the extended extractor, return default one");
+ return defaultExt;
+ }
+
+ if (defaultExt == NULL) {
+ ALOGD("default extractor is NULL, return extended extractor");
+ return retExtExtractor;
+ }
+
+ //bCheckExtendedExtractor is true which means default extractor was found
+ //but we want to give preference to extended extractor based on certain
+ //conditions.
+
+ //needed to prevent a leak in case both extractors are valid
+ //but we still dont want to use the extended one. we need
+ //to delete the new one
+ bool bUseDefaultExtractor = true;
+
+ for (size_t trackItt = 0; (trackItt < retExtExtractor->countTracks()); ++trackItt) {
+ sp<MetaData> meta = retExtExtractor->getTrackMetaData(trackItt);
+ const char *mime;
+ bool success = meta->findCString(kKeyMIMEType, &mime);
+ if ((success == true) &&
+ (!strncasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS,
+ strlen(MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS)) ||
+ !strncasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC,
+ strlen(MEDIA_MIMETYPE_VIDEO_HEVC)) )) {
+
+ ALOGD("Discarding default extractor and using the extended one");
+ bUseDefaultExtractor = false;
+ break;
+ }
+ }
+
+ if (bUseDefaultExtractor) {
+ ALOGD("using default extractor inspite of having a new extractor");
+ retExtExtractor.clear();
+ return defaultExt;
+ } else {
+ defaultExt.clear();
+ return retExtExtractor;
+ }
+
+}
+
+
+void ExtendedUtils::helper_addMediaCodec(Vector<MediaCodecList::CodecInfo> &mCodecInfos,
+ KeyedVector<AString, size_t> &mTypes,
+ bool encoder, const char *name,
+ const char *type, uint32_t quirks) {
+ mCodecInfos.push();
+ MediaCodecList::CodecInfo *info = &mCodecInfos.editItemAt(mCodecInfos.size() - 1);
+ info->mName = name;
+ info->mIsEncoder = encoder;
+ ssize_t index = mTypes.indexOfKey(type);
+ uint32_t bit = mTypes.valueAt(index);
+ info->mTypes |= 1ul << bit;
+ info->mQuirks = quirks;
+}
+
+uint32_t ExtendedUtils::helper_getCodecSpecificQuirks(KeyedVector<AString, size_t> &mCodecQuirks,
+ Vector<AString> quirks) {
+ size_t i = 0, numQuirks = quirks.size();
+ uint32_t bit = 0, value = 0;
+ for (i = 0; i < numQuirks; i++)
+ {
+ ssize_t index = mCodecQuirks.indexOfKey(quirks.itemAt(i));
+ bit = mCodecQuirks.valueAt(index);
+ value |= 1ul << bit;
+ }
+ return value;
+}
+
+bool ExtendedUtils::isAVCProfileSupported(int32_t profile){
+ if(profile == OMX_VIDEO_AVCProfileMain || profile == OMX_VIDEO_AVCProfileHigh || profile == OMX_VIDEO_AVCProfileBaseline){
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void ExtendedUtils::updateNativeWindowBufferGeometry(ANativeWindow* anw,
+ OMX_U32 width, OMX_U32 height, OMX_COLOR_FORMATTYPE colorFormat) {
+#if UPDATE_BUFFER_GEOMETRY_AVAILABLE
+ if (anw != NULL) {
+ ALOGI("Calling native window update buffer geometry [%lu x %lu]",
+ width, height);
+ status_t err = anw->perform(
+ anw, NATIVE_WINDOW_UPDATE_BUFFERS_GEOMETRY,
+ width, height, colorFormat);
+ if (err != OK) {
+ ALOGE("UPDATE_BUFFER_GEOMETRY failed %d", err);
+ }
+ }
+#endif
+}
+
+bool ExtendedUtils::checkIsThumbNailMode(const uint32_t flags, char* componentName) {
+ bool isInThumbnailMode = false;
+ if ((flags & OMXCodec::kClientNeedsFramebuffer) && !strncmp(componentName, "OMX.qcom.", 9)) {
+ isInThumbnailMode = true;
+ }
+ return isInThumbnailMode;
+}
+
+void ExtendedUtils::setArbitraryModeIfInterlaced(
+ const uint8_t *ptr, const sp<MetaData> &meta) {
+
+ if (ptr == NULL) {
+ return;
+ }
+ uint16_t spsSize = (((uint16_t)ptr[6]) << 8) + (uint16_t)(ptr[7]);
+ int32_t width = 0, height = 0, isInterlaced = 0;
+ const uint8_t *spsStart = &ptr[8];
+
+ sp<ABuffer> seqParamSet = new ABuffer(spsSize);
+ memcpy(seqParamSet->data(), spsStart, spsSize);
+ FindAVCDimensions(seqParamSet, &width, &height, NULL, NULL, &isInterlaced);
+
+ ALOGV("height is %d, width is %d, isInterlaced is %d\n", height, width, isInterlaced);
+ if (isInterlaced) {
+ meta->setInt32(kKeyUseArbitraryMode, 1);
+ meta->setInt32(kKeyInterlace, 1);
+ }
+ return;
+}
+
+int32_t ExtendedUtils::checkIsInterlace(sp<MetaData> &meta) {
+ int32_t isInterlaceFormat = 0;
+
+ if(meta->findInt32(kKeyInterlace, &isInterlaceFormat)) {
+ ALOGI("interlace format detected");
+ }
+
+ return isInterlaceFormat;
+}
+
+}
+#else //ENABLE_AV_ENHANCEMENTS
+
+namespace android {
+
+void ExtendedUtils::HFR::setHFRIfEnabled(
+ const CameraParameters& params, sp<MetaData> &meta) {
+}
+
+status_t ExtendedUtils::HFR::reCalculateFileDuration(
+ sp<MetaData> &meta, sp<MetaData> &enc_meta,
+ int64_t &maxFileDurationUs, int32_t frameRate,
+ video_encoder videoEncoder) {
+ return OK;
+}
+
+void ExtendedUtils::HFR::reCalculateTimeStamp(
+ sp<MetaData> &meta, int64_t ×tampUs) {
+}
+
+void ExtendedUtils::HFR::reCalculateHFRParams(
+ const sp<MetaData> &meta, int32_t &frameRate,
+ int32_t &bitrate) {
+}
+
+void ExtendedUtils::HFR::copyHFRParams(
+ const sp<MetaData> &inputFormat,
+ sp<MetaData> &outputFormat) {
+}
+
+bool ExtendedUtils::ShellProp::isAudioDisabled() {
+ return false;
+}
+
+void ExtendedUtils::ShellProp::setEncoderProfile(
+ video_encoder &videoEncoder, int32_t &videoEncoderProfile) {
+}
+
+int64_t ExtendedUtils::ShellProp::getMaxAVSyncLateMargin() {
+ return kDefaultAVSyncLateMargin;
+}
+
+bool ExtendedUtils::ShellProp::isSmoothStreamingEnabled() {
+ return false;
+}
+
+void ExtendedUtils::setBFrames(
+ OMX_VIDEO_PARAM_MPEG4TYPE &mpeg4type, int32_t &numBFrames,
+ const char* componentName) {
+}
+
+void ExtendedUtils::setBFrames(
+ OMX_VIDEO_PARAM_AVCTYPE &h264type, int32_t &numBFrames,
+ int32_t iFramesInterval, int32_t frameRate,
+ const char* componentName) {
+}
+
+bool ExtendedUtils::UseQCHWAACEncoder(audio_encoder Encoder,int32_t Channel,
+ int32_t BitRate,int32_t SampleRate) {
+ return false;
+}
+
+sp<MediaExtractor> ExtendedUtils::MediaExtractor_CreateIfNeeded(sp<MediaExtractor> defaultExt,
+ const sp<DataSource> &source,
+ const char *mime) {
+ return defaultExt;
+}
+
+void ExtendedUtils::helper_addMediaCodec(Vector<MediaCodecList::CodecInfo> &mCodecInfos,
+ KeyedVector<AString, size_t> &mTypes,
+ bool encoder, const char *name,
+ const char *type, uint32_t quirks) {
+}
+
+uint32_t ExtendedUtils::helper_getCodecSpecificQuirks(KeyedVector<AString, size_t> &mCodecQuirks,
+ Vector<AString> quirks) {
+ return 0;
+}
+
+bool ExtendedUtils::isAVCProfileSupported(int32_t profile){
+ return false;
+}
+
+void ExtendedUtils::updateNativeWindowBufferGeometry(ANativeWindow* anw,
+ OMX_U32 width, OMX_U32 height, OMX_COLOR_FORMATTYPE colorFormat) {
+}
+
+bool ExtendedUtils::checkIsThumbNailMode(const uint32_t flags, char* componentName) {
+ return false;
+}
+
+void ExtendedUtils::setArbitraryModeIfInterlaced(
+ const uint8_t *ptr, const sp<MetaData> &meta) {
+}
+
+int32_t ExtendedUtils::checkIsInterlace(sp<MetaData> &meta) {
+ return false;
+}
+
+}
+#endif //ENABLE_AV_ENHANCEMENTS
diff --git a/media/libstagefright/ExtendedWriter.cpp b/media/libstagefright/ExtendedWriter.cpp
new file mode 100644
index 0000000..db5bb4a
--- /dev/null
+++ b/media/libstagefright/ExtendedWriter.cpp
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2012 - 2013, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution.
+ *
+ * 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 <media/stagefright/ExtendedWriter.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/mediarecorder.h>
+#include <system/audio.h>
+
+#include <sys/prctl.h>
+#include <sys/resource.h>
+
+#include <arpa/inet.h>
+#include <QCMediaDefs.h>
+
+#undef LOG_TAG
+#define LOG_TAG "ExtendedWriter"
+
+namespace android {
+
+ExtendedWriter::ExtendedWriter(const char *filename)
+ : mFile(fopen(filename, "wb")),
+ mInitCheck(mFile != NULL ? OK : NO_INIT),
+ mStarted(false),
+ mPaused(false),
+ mResumed(false),
+ mOffset(0) {
+}
+
+ExtendedWriter::ExtendedWriter(int fd)
+ : mFile(fdopen(fd, "wb")),
+ mInitCheck(mFile != NULL ? OK : NO_INIT),
+ mStarted(false),
+ mPaused(false),
+ mResumed(false),
+ mOffset(0) {
+}
+
+ExtendedWriter::~ExtendedWriter() {
+ if (mStarted) {
+ stop();
+ }
+
+ if (mFile != NULL) {
+ fclose(mFile);
+ mFile = NULL;
+ }
+}
+
+status_t ExtendedWriter::initCheck() const {
+ return mInitCheck;
+}
+
+status_t ExtendedWriter::addSource(const sp<MediaSource> &source) {
+ if (mInitCheck != OK) {
+ ALOGE("Init Check not OK, return");
+ return mInitCheck;
+ }
+
+ if (mSource != NULL) {
+ ALOGE("A source already exists, return");
+ return UNKNOWN_ERROR;
+ }
+
+ sp<MetaData> meta = source->getFormat();
+
+ const char *mime;
+ CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+ if ( !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) {
+ mFormat = AUDIO_FORMAT_QCELP;
+ } else if ( !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_EVRC)) {
+ mFormat = AUDIO_FORMAT_EVRC;
+ }
+ else {
+ return UNKNOWN_ERROR;
+ }
+
+ int32_t channelCount;
+ int32_t sampleRate;
+ CHECK(meta->findInt32(kKeyChannelCount, &channelCount));
+ CHECK_EQ(channelCount, 1);
+ CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
+ CHECK_EQ(sampleRate, 8000);
+
+ mSource = source;
+
+ return OK;
+}
+
+status_t ExtendedWriter::start(MetaData *params) {
+ if (mInitCheck != OK) {
+ ALOGE("Init Check not OK, return");
+ return mInitCheck;
+ }
+
+ if (mSource == NULL) {
+ ALOGE("NULL Source");
+ return UNKNOWN_ERROR;
+ }
+
+ if (mStarted && mPaused) {
+ mPaused = false;
+ mResumed = true;
+ return OK;
+ } else if (mStarted) {
+ ALOGE("Already startd, return");
+ return OK;
+ }
+
+ //space for header;
+ size_t headerSize = sizeof( struct QCPEVRCHeader );
+ uint8_t * header = (uint8_t *)malloc(headerSize);
+ memset( header, '?', headerSize);
+ fwrite( header, 1, headerSize, mFile );
+ mOffset += headerSize;
+ delete header;
+
+ status_t err = mSource->start();
+
+ if (err != OK) {
+ return err;
+ }
+
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+ mReachedEOS = false;
+ mDone = false;
+
+ pthread_create(&mThread, &attr, ThreadWrapper, this);
+ pthread_attr_destroy(&attr);
+
+ mStarted = true;
+
+ return OK;
+}
+
+status_t ExtendedWriter::pause() {
+ if (!mStarted) {
+ return OK;
+ }
+ mPaused = true;
+ return OK;
+}
+
+status_t ExtendedWriter::stop() {
+ if (!mStarted) {
+ return OK;
+ }
+
+ mDone = true;
+
+ void *dummy;
+ pthread_join(mThread, &dummy);
+
+ status_t err = (status_t) dummy;
+ {
+ status_t status = mSource->stop();
+ if (err == OK &&
+ (status != OK && status != ERROR_END_OF_STREAM)) {
+ err = status;
+ }
+ }
+
+ mStarted = false;
+ return err;
+}
+
+bool ExtendedWriter::exceedsFileSizeLimit() {
+ if (mMaxFileSizeLimitBytes == 0) {
+ return false;
+ }
+ return mEstimatedSizeBytes >= mMaxFileSizeLimitBytes;
+}
+
+bool ExtendedWriter::exceedsFileDurationLimit() {
+ if (mMaxFileDurationLimitUs == 0) {
+ return false;
+ }
+ return mEstimatedDurationUs >= mMaxFileDurationLimitUs;
+}
+
+// static
+void *ExtendedWriter::ThreadWrapper(void *me) {
+ return (void *) static_cast<ExtendedWriter *>(me)->threadFunc();
+}
+
+status_t ExtendedWriter::threadFunc() {
+ mEstimatedDurationUs = 0;
+ mEstimatedSizeBytes = 0;
+ bool stoppedPrematurely = true;
+ int64_t previousPausedDurationUs = 0;
+ int64_t maxTimestampUs = 0;
+ status_t err = OK;
+
+ pid_t tid = gettid();
+ androidSetThreadPriority(tid, ANDROID_PRIORITY_AUDIO);
+ prctl(PR_SET_NAME, (unsigned long)"ExtendedWriter", 0, 0, 0);
+ while (!mDone) {
+ MediaBuffer *buffer;
+ err = mSource->read(&buffer);
+
+ if (err != OK) {
+ break;
+ }
+
+ if (mPaused) {
+ buffer->release();
+ buffer = NULL;
+ continue;
+ }
+
+ mEstimatedSizeBytes += buffer->range_length();
+ if (exceedsFileSizeLimit()) {
+ buffer->release();
+ buffer = NULL;
+ notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
+ break;
+ }
+
+ int64_t timestampUs;
+ CHECK(buffer->meta_data()->findInt64(kKeyTime, ×tampUs));
+ if (timestampUs > mEstimatedDurationUs) {
+ mEstimatedDurationUs = timestampUs;
+ }
+ if (mResumed) {
+ previousPausedDurationUs += (timestampUs - maxTimestampUs - 20000);
+ mResumed = false;
+ }
+ timestampUs -= previousPausedDurationUs;
+ ALOGV("time stamp: %lld, previous paused duration: %lld",
+ timestampUs, previousPausedDurationUs);
+ if (timestampUs > maxTimestampUs) {
+ maxTimestampUs = timestampUs;
+ }
+
+ if (exceedsFileDurationLimit()) {
+ buffer->release();
+ buffer = NULL;
+ notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0);
+ break;
+ }
+ ssize_t n = fwrite(
+ (const uint8_t *)buffer->data() + buffer->range_offset(),
+ 1,
+ buffer->range_length(),
+ mFile);
+ mOffset += n;
+
+ if (n < (ssize_t)buffer->range_length()) {
+ buffer->release();
+ buffer = NULL;
+
+ break;
+ }
+
+ // XXX: How to tell it is stopped prematurely?
+ if (stoppedPrematurely) {
+ stoppedPrematurely = false;
+ }
+
+ buffer->release();
+ buffer = NULL;
+ }
+
+ if (stoppedPrematurely) {
+ notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS, UNKNOWN_ERROR);
+ }
+
+ if ( mFormat == AUDIO_FORMAT_QCELP ) {
+ writeQCPHeader( );
+ }
+ else if ( mFormat == AUDIO_FORMAT_EVRC ) {
+ writeEVRCHeader( );
+ }
+
+ fflush(mFile);
+ fclose(mFile);
+ mFile = NULL;
+ mReachedEOS = true;
+ if (err == ERROR_END_OF_STREAM || (err == -ETIMEDOUT)) {
+ return OK;
+ }
+ return err;
+}
+
+bool ExtendedWriter::reachedEOS() {
+ return mReachedEOS;
+}
+
+status_t ExtendedWriter::writeQCPHeader() {
+ /* Common part */
+ struct QCPEVRCHeader header = {
+ {'R', 'I', 'F', 'F'}, 0, {'Q', 'L', 'C', 'M'}, /* Riff */
+ {'f', 'm', 't', ' '}, 150, 1, 0, 0, 0, 0,{0}, 0, {0},0,0,160,8000,16,0,{0},{0},{0}, /* Fmt */
+ {'v','r','a','t'}, 0, 0, 0, /* Vrat */
+ {'d','a','t','a'},0 /* Data */
+ };
+
+ fseeko(mFile, 0, SEEK_SET);
+ header.s_riff = (mOffset - 8);
+ header.data1 = (0x5E7F6D41);
+ header.data2 = (0xB115);
+ header.data3 = (0x11D0);
+ header.data4[0] = 0xBA;
+ header.data4[1] = 0x91;
+ header.data4[2] = 0x00;
+ header.data4[3] = 0x80;
+ header.data4[4] = 0x5F;
+ header.data4[5] = 0xB4;
+ header.data4[6] = 0xB9;
+ header.data4[7] = 0x7E;
+ header.ver = (0x0002);
+ memcpy(header.name, "Qcelp 13K", 9);
+ header.abps = (13000);
+ header.bytes_per_pkt = (35);
+ header.vr_num_of_rates = 5;
+ header.vr_bytes_per_pkt[0] = (0x0422);
+ header.vr_bytes_per_pkt[1] = (0x0310);
+ header.vr_bytes_per_pkt[2] = (0x0207);
+ header.vr_bytes_per_pkt[3] = (0x0103);
+ header.s_vrat = (0x00000008);
+ header.v_rate = (0x00000001);
+ header.size_in_pkts = (mOffset - sizeof( struct QCPEVRCHeader ))/ header.bytes_per_pkt;
+ header.s_data = mOffset - sizeof( struct QCPEVRCHeader );
+ fwrite( &header, 1, sizeof( struct QCPEVRCHeader ), mFile );
+ return OK;
+}
+
+status_t ExtendedWriter::writeEVRCHeader() {
+ /* Common part */
+ struct QCPEVRCHeader header = {
+ {'R', 'I', 'F', 'F'}, 0, {'Q', 'L', 'C', 'M'}, /* Riff */
+ {'f', 'm', 't', ' '}, 150, 1, 0, 0, 0, 0,{0}, 0, {0},0,0,160,8000,16,0,{0},{0},{0}, /* Fmt */
+ {'v','r','a','t'}, 0, 0, 0, /* Vrat */
+ {'d','a','t','a'},0 /* Data */
+ };
+
+ fseeko(mFile, 0, SEEK_SET);
+ header.s_riff = (mOffset - 8);
+ header.data1 = (0xe689d48d);
+ header.data2 = (0x9076);
+ header.data3 = (0x46b5);
+ header.data4[0] = 0x91;
+ header.data4[1] = 0xef;
+ header.data4[2] = 0x73;
+ header.data4[3] = 0x6a;
+ header.data4[4] = 0x51;
+ header.data4[5] = 0x00;
+ header.data4[6] = 0xce;
+ header.data4[7] = 0xb4;
+ header.ver = (0x0001);
+ memcpy(header.name, "TIA IS-127 Enhanced Variable Rate Codec, Speech Service Option 3", 64);
+ header.abps = (9600);
+ header.bytes_per_pkt = (23);
+ header.vr_num_of_rates = 4;
+ header.vr_bytes_per_pkt[0] = (0x0416);
+ header.vr_bytes_per_pkt[1] = (0x030a);
+ header.vr_bytes_per_pkt[2] = (0x0200);
+ header.vr_bytes_per_pkt[3] = (0x0102);
+ header.s_vrat = (0x00000008);
+ header.v_rate = (0x00000001);
+ header.size_in_pkts = (mOffset - sizeof( struct QCPEVRCHeader )) / header.bytes_per_pkt;
+ header.s_data = mOffset - sizeof( struct QCPEVRCHeader );
+ fwrite( &header, 1, sizeof( struct QCPEVRCHeader ), mFile );
+ return OK;
+}
+
+
+} // namespace android
diff --git a/media/libstagefright/FLACExtractor.cpp b/media/libstagefright/FLACExtractor.cpp
index 098fcf9..1fb58c1 100644
--- a/media/libstagefright/FLACExtractor.cpp
+++ b/media/libstagefright/FLACExtractor.cpp
@@ -822,12 +822,14 @@
{
// 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/LPAPlayer.cpp b/media/libstagefright/LPAPlayer.cpp
new file mode 100755
index 0000000..9941313
--- /dev/null
+++ b/media/libstagefright/LPAPlayer.cpp
@@ -0,0 +1,841 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution. Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * 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 "LPAPlayer"
+
+#include <utils/Log.h>
+#include <utils/threads.h>
+
+#include <signal.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/poll.h>
+#include <sys/eventfd.h>
+#include <binder/IPCThreadState.h>
+#include <media/AudioTrack.h>
+
+#include <media/stagefright/LPAPlayerLegacy.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MediaErrors.h>
+
+#include <hardware_legacy/power.h>
+
+#include <linux/unistd.h>
+
+#include "include/AwesomePlayer.h"
+#include <powermanager/PowerManager.h>
+
+static const char mName[] = "LPAPlayer";
+
+#define MEM_BUFFER_SIZE 524288
+#define MEM_BUFFER_COUNT 2
+
+#define PCM_FORMAT 2
+#define NUM_FDS 2
+namespace android {
+int LPAPlayer::mObjectsAlive = 0;
+bool LPAPlayer::mLpaInProgress = false;
+
+LPAPlayer::LPAPlayer(
+ const sp<MediaPlayerBase::AudioSink> &audioSink, bool &initCheck,
+ AwesomePlayer *observer)
+ :AudioPlayer(audioSink,0, observer),
+mPositionTimeMediaUs(-1),
+mPositionTimeRealUs(-1),
+mInternalSeeking(false),
+mStarted(false),
+mA2DPEnabled(false),
+mSampleRate(0),
+mLatencyUs(0),
+mFrameSize(0),
+mNumFramesPlayed(0),
+mNumFramesPlayedSysTimeUs(0),
+mInputBuffer(NULL),
+mSeeking(false),
+mReachedEOS(false),
+mReachedOutputEOS(false),
+mFinalStatus(OK),
+mSeekTimeUs(0),
+mPauseTime(0),
+mIsFirstBuffer(false),
+mFirstBufferResult(OK),
+mFirstBuffer(NULL),
+mAudioSink(audioSink),
+mObserver(observer),
+mTrackType(TRACK_NONE){
+ ALOGV("LPAPlayer::LPAPlayer() ctor");
+ mObjectsAlive++;
+ mLpaInProgress = true;
+ mTimeStarted = 0;
+ mTimePlayed = 0;
+ numChannels =0;
+ mPaused = false;
+ mIsA2DPEnabled = false;
+ mAudioFlinger = NULL;
+ AudioFlingerClient = NULL;
+ /* Initialize Suspend/Resume related variables */
+ mQueue.start();
+ mQueueStarted = true;
+ mPauseEvent = new TimedEvent(this, &LPAPlayer::onPauseTimeOut);
+ mPauseEventPending = false;
+ getAudioFlinger();
+ ALOGV("Registering client with AudioFlinger");
+ mAudioFlinger->registerClient(AudioFlingerClient);
+
+ mIsAudioRouted = false;
+
+ initCheck = true;
+
+}
+
+LPAPlayer::~LPAPlayer() {
+ ALOGV("LPAPlayer::~LPAPlayer()");
+ if (mQueueStarted) {
+ mQueue.stop();
+ }
+
+ reset();
+#if 0
+ if (mAudioFlinger != NULL) {
+ mAudioFlinger->deregisterClient(AudioFlingerClient);
+ }
+#endif
+ mObjectsAlive--;
+ mLpaInProgress = false;
+
+}
+
+void LPAPlayer::getAudioFlinger() {
+ Mutex::Autolock _l(AudioFlingerLock);
+
+ if ( mAudioFlinger.get() == 0 ) {
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder;
+ do {
+ binder = sm->getService(String16("media.audio_flinger"));
+ if ( binder != 0 )
+ break;
+ ALOGW("AudioFlinger not published, waiting...");
+ usleep(500000); // 0.5 s
+ } while ( true );
+ if ( AudioFlingerClient == NULL ) {
+ AudioFlingerClient = new AudioFlingerLPAdecodeClient(this);
+ }
+
+ binder->linkToDeath(AudioFlingerClient);
+ mAudioFlinger = interface_cast<IAudioFlinger>(binder);
+ }
+ ALOGE_IF(mAudioFlinger==0, "no AudioFlinger!?");
+}
+
+LPAPlayer::AudioFlingerLPAdecodeClient::AudioFlingerLPAdecodeClient(void *obj)
+{
+ ALOGV("LPAPlayer::AudioFlingerLPAdecodeClient::AudioFlingerLPAdecodeClient");
+ pBaseClass = (LPAPlayer*)obj;
+}
+
+void LPAPlayer::AudioFlingerLPAdecodeClient::binderDied(const wp<IBinder>& who) {
+ Mutex::Autolock _l(pBaseClass->AudioFlingerLock);
+
+ pBaseClass->mAudioFlinger.clear();
+ ALOGW("AudioFlinger server died!");
+}
+
+void LPAPlayer::AudioFlingerLPAdecodeClient::ioConfigChanged(int event, audio_io_handle_t ioHandle, const void *param2) {
+ ALOGV("ioConfigChanged() event %d", event);
+
+#if 0
+ if (event != AudioSystem::A2DP_OUTPUT_STATE) {
+ return;
+ }
+
+ switch ( event ) {
+ case AudioSystem::A2DP_OUTPUT_STATE:
+ {
+ ALOGV("ioConfigChanged() A2DP_OUTPUT_STATE iohandle is %d with A2DPEnabled in %d", ioHandle, pBaseClass->mIsA2DPEnabled);
+ if ( -1 == ioHandle ) {
+ if ( pBaseClass->mIsA2DPEnabled ) {
+ pBaseClass->mIsA2DPEnabled = false;
+ if (pBaseClass->mStarted) {
+ pBaseClass->handleA2DPSwitch();
+ }
+ ALOGV("ioConfigChanged:: A2DP Disabled");
+ }
+ } else {
+ if ( !pBaseClass->mIsA2DPEnabled ) {
+
+ pBaseClass->mIsA2DPEnabled = true;
+ if (pBaseClass->mStarted) {
+ pBaseClass->handleA2DPSwitch();
+ }
+
+ ALOGV("ioConfigChanged:: A2DP Enabled");
+ }
+ }
+ }
+ break;
+ }
+#endif
+ ALOGV("ioConfigChanged Out");
+
+}
+
+void LPAPlayer::handleA2DPSwitch() {
+ pthread_cond_signal(&decoder_cv);
+}
+
+void LPAPlayer::setSource(const sp<MediaSource> &source) {
+ CHECK(mSource == NULL);
+ ALOGV("Setting source from LPA Player");
+ mSource = source;
+}
+
+status_t LPAPlayer::start(bool sourceAlreadyStarted) {
+ CHECK(!mStarted);
+ CHECK(mSource != NULL);
+
+ ALOGV("start: sourceAlreadyStarted %d", sourceAlreadyStarted);
+ //Check if the source is started, start it
+ status_t err;
+ if (!sourceAlreadyStarted) {
+ err = mSource->start();
+
+ if (err != OK) {
+ return err;
+ }
+ }
+
+ //Create decoder and a2dp notification thread and initialize all the
+ //mutexes and coditional variables
+ createThreads();
+ ALOGV("All Threads Created.");
+
+ // We allow an optional INFO_FORMAT_CHANGED at the very beginning
+ // of playback, if there is one, getFormat below will retrieve the
+ // updated format, if there isn't, we'll stash away the valid buffer
+ // of data to be used on the first audio callback.
+
+ CHECK(mFirstBuffer == NULL);
+
+ MediaSource::ReadOptions options;
+ if (mSeeking) {
+ options.setSeekTo(mSeekTimeUs);
+ mSeeking = false;
+ }
+
+ mFirstBufferResult = mSource->read(&mFirstBuffer, &options);
+ if (mFirstBufferResult == INFO_FORMAT_CHANGED) {
+ ALOGV("INFO_FORMAT_CHANGED!!!");
+ CHECK(mFirstBuffer == NULL);
+ mFirstBufferResult = OK;
+ mIsFirstBuffer = false;
+ } else {
+ mIsFirstBuffer = true;
+ }
+
+ sp<MetaData> format = mSource->getFormat();
+ const char *mime;
+
+ bool success = format->findCString(kKeyMIMEType, &mime);
+ CHECK(success);
+ CHECK(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW));
+
+ success = format->findInt32(kKeySampleRate, &mSampleRate);
+ CHECK(success);
+
+ success = format->findInt32(kKeyChannelCount, &numChannels);
+ CHECK(success);
+
+ if(!format->findInt32(kKeyChannelMask, &mChannelMask)) {
+ // log only when there's a risk of ambiguity of channel mask selection
+ ALOGI_IF(numChannels > 2,
+ "source format didn't specify channel mask, using (%d) channel order", numChannels);
+ mChannelMask = CHANNEL_MASK_USE_CHANNEL_ORDER;
+ }
+
+ err = setupAudioSink();
+
+ if (err != OK) {
+ if (mFirstBuffer != NULL) {
+ mFirstBuffer->release();
+ mFirstBuffer = NULL;
+ }
+
+ if (!sourceAlreadyStarted) {
+ mSource->stop();
+ }
+
+ ALOGE("Opening a routing session failed");
+ return err;
+ }
+
+ mIsAudioRouted = true;
+ mStarted = true;
+ mAudioSink->start();
+ mTimeStarted = nanoseconds_to_microseconds(systemTime(SYSTEM_TIME_MONOTONIC));
+ ALOGV("Waking up decoder thread");
+ pthread_cond_signal(&decoder_cv);
+
+ return OK;
+}
+
+status_t LPAPlayer::seekTo(int64_t time_us) {
+ Mutex::Autolock autoLock(mLock);
+ ALOGV("seekTo: time_us %lld", time_us);
+ if ( mReachedEOS ) {
+ mReachedEOS = false;
+ mReachedOutputEOS = false;
+ }
+ mSeeking = true;
+ mSeekTimeUs = time_us;
+ mTimePlayed = time_us;
+ mTimeStarted = 0;
+ ALOGV("In seekTo(), mSeekTimeUs %lld",mSeekTimeUs);
+ mAudioSink->flush();
+ pthread_cond_signal(&decoder_cv);
+ //TODO: Update the mPauseTime
+ return OK;
+}
+
+void LPAPlayer::pause(bool playPendingSamples) {
+ CHECK(mStarted);
+ if (mPaused) {
+ return;
+ }
+ ALOGV("pause: playPendingSamples %d", playPendingSamples);
+ mPaused = true;
+ if (playPendingSamples) {
+ if (!mIsA2DPEnabled) {
+ if (!mPauseEventPending) {
+ ALOGV("Posting an event for Pause timeout");
+ mQueue.postEventWithDelay(mPauseEvent, LPA_PAUSE_TIMEOUT_USEC);
+ mPauseEventPending = true;
+ }
+ if (mAudioSink.get() != NULL)
+ mAudioSink->pause();
+ }
+ else {
+ if (mAudioSink.get() != NULL)
+ mAudioSink->stop();
+
+ }
+ } else {
+ if (!mIsA2DPEnabled) {
+ if(!mPauseEventPending) {
+ ALOGV("Posting an event for Pause timeout");
+ mQueue.postEventWithDelay(mPauseEvent, LPA_PAUSE_TIMEOUT_USEC);
+ mPauseEventPending = true;
+ }
+ if (mAudioSink.get() != NULL)
+ mAudioSink->pause();
+ } else {
+ if (mAudioSink.get() != NULL) {
+ mAudioSink->pause();
+ }
+ }
+ }
+ if(mTimeStarted != 0) {
+ mTimePlayed += (nanoseconds_to_microseconds(systemTime(SYSTEM_TIME_MONOTONIC)) - mTimeStarted);
+ }
+}
+
+status_t LPAPlayer::resume() {
+ ALOGV("resume: mPaused %d",mPaused);
+ if ( mPaused) {
+ CHECK(mStarted);
+ if (!mIsA2DPEnabled) {
+ if(mPauseEventPending) {
+ ALOGV("Resume(): Cancelling the puaseTimeout event");
+ mPauseEventPending = false;
+ mQueue.cancelEvent(mPauseEvent->eventID());
+ }
+
+ }
+
+ setupAudioSink();
+
+ mPaused = false;
+ mIsAudioRouted = true;
+ mAudioSink->start();
+ mTimeStarted = nanoseconds_to_microseconds(systemTime(SYSTEM_TIME_MONOTONIC));
+ pthread_cond_signal(&decoder_cv);
+ }
+ return NO_ERROR;
+}
+
+//static
+size_t LPAPlayer::AudioSinkCallback(
+ MediaPlayerBase::AudioSink *audioSink,
+ void *buffer, size_t size, void *cookie,
+ MediaPlayerBase::AudioSink::cb_event_t event) {
+ if (buffer == NULL && size == AudioTrack::EVENT_UNDERRUN) {
+ LPAPlayer *me = (LPAPlayer *)cookie;
+ me->mReachedEOS = true;
+ me->mReachedOutputEOS = true;
+ ALOGV("postAudioEOS");
+ me->mObserver->postAudioEOS(0);
+ }
+ return 1;
+}
+
+void LPAPlayer::reset() {
+
+ // Close the audiosink after all the threads exited to make sure
+ ALOGV("Reset called!!!!!");
+ mReachedEOS = true;
+ //TODO: Release Wake lock
+
+ // make sure Decoder thread has exited
+ requestAndWaitForDecoderThreadExit();
+ requestAndWaitForA2DPNotificationThreadExit();
+ if (mIsAudioRouted) {
+ mAudioSink->stop();
+ mAudioSink->close();
+ }
+ mAudioSink.clear();
+ // Make sure to release any buffer we hold onto so that the
+ // source is able to stop().
+ if (mFirstBuffer != NULL) {
+ mFirstBuffer->release();
+ mFirstBuffer = NULL;
+ }
+
+ if (mInputBuffer != NULL) {
+ ALOGV("AudioPlayer releasing input buffer.");
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+ }
+
+ mSource->stop();
+
+ // The following hack is necessary to ensure that the OMX
+ // component is completely released by the time we may try
+ // to instantiate it again.
+ wp<MediaSource> tmp = mSource;
+ mSource.clear();
+ while (tmp.promote() != NULL) {
+ usleep(1000);
+ }
+
+ mPositionTimeMediaUs = -1;
+ mPositionTimeRealUs = -1;
+ mSeeking = false;
+ mReachedEOS = false;
+ mReachedOutputEOS = false;
+ mFinalStatus = OK;
+ mStarted = false;
+}
+
+
+bool LPAPlayer::isSeeking() {
+ Mutex::Autolock autoLock(mLock);
+ return mSeeking;
+}
+
+bool LPAPlayer::reachedEOS(status_t *finalStatus) {
+ *finalStatus = OK;
+ Mutex::Autolock autoLock(mLock);
+ *finalStatus = mFinalStatus;
+ return mReachedOutputEOS;
+}
+
+
+void *LPAPlayer::decoderThreadWrapper(void *me) {
+ static_cast<LPAPlayer *>(me)->decoderThreadEntry();
+ return NULL;
+}
+
+
+void LPAPlayer::decoderThreadEntry() {
+
+ pthread_mutex_lock(&decoder_mutex);
+
+ pid_t tid = gettid();
+ androidSetThreadPriority(tid, ANDROID_PRIORITY_AUDIO);
+ prctl(PR_SET_NAME, (unsigned long)"LPA DecodeThread", 0, 0, 0);
+
+ ALOGV("decoderThreadEntry wait for signal \n");
+ if (!mStarted) {
+ pthread_cond_wait(&decoder_cv, &decoder_mutex);
+ }
+ ALOGV("decoderThreadEntry ready to work \n");
+ pthread_mutex_unlock(&decoder_mutex);
+ if (killDecoderThread) {
+ return;
+ }
+ void* local_buf = malloc(MEM_BUFFER_SIZE);
+ int bytesWritten = 0;
+ while (!killDecoderThread) {
+
+ setupAudioSink();
+ if (mTimeStarted == 0) {
+ mTimeStarted = nanoseconds_to_microseconds(systemTime(SYSTEM_TIME_MONOTONIC));
+ }
+
+ if (mReachedEOS || mPaused || !mIsAudioRouted || mIsA2DPEnabled) {
+ ALOGD("DecoderThread taking mutex mReachedEOS %d mPaused %d mIsAudioRouted %d mIsA2DPEnabled %d"
+ , mReachedEOS, mPaused, mIsAudioRouted, mIsA2DPEnabled);
+ pthread_mutex_lock(&decoder_mutex);
+ pthread_cond_wait(&decoder_cv, &decoder_mutex);
+ pthread_mutex_unlock(&decoder_mutex);
+ ALOGD("DecoderThread woken up ");
+ continue;
+ }
+
+ if (!mIsA2DPEnabled) {
+ ALOGV("FillBuffer: MemBuffer size %d", MEM_BUFFER_SIZE);
+ ALOGV("Fillbuffer started");
+ //TODO: Add memset
+ bytesWritten = fillBuffer(local_buf, MEM_BUFFER_SIZE);
+ ALOGV("FillBuffer completed bytesToWrite %d", bytesWritten);
+
+ if(!killDecoderThread) {
+ mAudioSink->write(local_buf, bytesWritten);
+ }
+ }
+ }
+
+ free(local_buf);
+
+ //TODO: Call fillbuffer with different size and write to mAudioSink()
+}
+
+void LPAPlayer::createThreads() {
+
+ //Initialize all the Mutexes and Condition Variables
+ pthread_mutex_init(&decoder_mutex, NULL);
+ pthread_mutex_init(&audio_sink_setup_mutex, NULL);
+ pthread_cond_init (&decoder_cv, NULL);
+
+ // Create 4 threads Effect, decoder, event and A2dp
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+ killDecoderThread = false;
+ killA2DPNotificationThread = false;
+
+ decoderThreadAlive = true;
+
+ ALOGV("Creating decoder Thread");
+ pthread_create(&decoderThread, &attr, decoderThreadWrapper, this);
+
+ pthread_attr_destroy(&attr);
+}
+
+size_t LPAPlayer::fillBuffer(void *data, size_t size) {
+
+ if (mReachedEOS) {
+ return 0;
+ }
+
+ bool postSeekComplete = false;
+
+ size_t size_done = 0;
+ size_t size_remaining = size;
+ while (size_remaining > 0) {
+ MediaSource::ReadOptions options;
+
+ {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mSeeking) {
+ mInternalSeeking = false;
+ }
+ if (mSeeking || mInternalSeeking) {
+ if (mIsFirstBuffer) {
+ if (mFirstBuffer != NULL) {
+ mFirstBuffer->release();
+ mFirstBuffer = NULL;
+ }
+ mIsFirstBuffer = false;
+ }
+
+ options.setSeekTo(mSeekTimeUs);
+
+ if (mInputBuffer != NULL) {
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+ }
+
+ mSeeking = false;
+ if (mObserver && !mInternalSeeking) {
+ ALOGV("fillBuffer: Posting audio seek complete event");
+ postSeekComplete = true;
+ }
+ mInternalSeeking = false;
+ }
+ }
+
+ if (mInputBuffer == NULL) {
+ status_t err;
+
+ if (mIsFirstBuffer) {
+ mInputBuffer = mFirstBuffer;
+ mFirstBuffer = NULL;
+ err = mFirstBufferResult;
+
+ mIsFirstBuffer = false;
+ } else {
+ err = mSource->read(&mInputBuffer, &options);
+ }
+
+ CHECK((err == OK && mInputBuffer != NULL)
+ || (err != OK && mInputBuffer == NULL));
+
+ Mutex::Autolock autoLock(mLock);
+
+ if (err != OK) {
+ mReachedEOS = true;
+ mFinalStatus = err;
+ break;
+ }
+
+ CHECK(mInputBuffer->meta_data()->findInt64(
+ kKeyTime, &mPositionTimeMediaUs));
+ mFrameSize = mAudioSink->frameSize();
+ mPositionTimeRealUs =
+ ((mNumFramesPlayed + size_done / mFrameSize) * 1000000)
+ / mSampleRate;
+ }
+ if (mInputBuffer->range_length() == 0) {
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+
+ continue;
+ }
+
+ size_t copy = size_remaining;
+ if (copy > mInputBuffer->range_length()) {
+ copy = mInputBuffer->range_length();
+ }
+
+ memcpy((char *)data + size_done,
+ (const char *)mInputBuffer->data() + mInputBuffer->range_offset(),
+ copy);
+
+ mInputBuffer->set_range(mInputBuffer->range_offset() + copy,
+ mInputBuffer->range_length() - copy);
+
+ size_done += copy;
+ size_remaining -= copy;
+ }
+
+ if (postSeekComplete) {
+ mObserver->postAudioSeekComplete();
+ }
+
+ return size_done;
+}
+
+int64_t LPAPlayer::getRealTimeUs() {
+ Mutex::Autolock autoLock(mLock);
+ return getRealTimeUsLocked();
+}
+
+
+int64_t LPAPlayer::getRealTimeUsLocked(){
+ //Used for AV sync: irrelevant API for LPA.
+ return 0;
+}
+
+
+int64_t LPAPlayer::getMediaTimeUs() {
+ Mutex::Autolock autoLock(mLock);
+ ALOGV("getMediaTimeUs() mPaused %d mSeekTimeUs %lld", mPaused, mSeekTimeUs);
+ if(mPaused || mTimeStarted == 0) {
+ return mTimePlayed;
+ } else {
+ return nanoseconds_to_microseconds(systemTime(SYSTEM_TIME_MONOTONIC)) - mTimeStarted + mTimePlayed;
+ }
+}
+
+bool LPAPlayer::getMediaTimeMapping(
+ int64_t *realtime_us, int64_t *mediatime_us) {
+ Mutex::Autolock autoLock(mLock);
+
+ *realtime_us = mPositionTimeRealUs;
+ *mediatime_us = mPositionTimeMediaUs;
+
+ return mPositionTimeRealUs != -1 && mPositionTimeMediaUs != -1;
+}
+
+void LPAPlayer::requestAndWaitForDecoderThreadExit() {
+
+ if (!decoderThreadAlive)
+ return;
+ killDecoderThread = true;
+ if (mIsAudioRouted)
+ mAudioSink->flush();
+ pthread_cond_signal(&decoder_cv);
+ pthread_join(decoderThread,NULL);
+ ALOGV("decoder thread killed");
+
+}
+
+void LPAPlayer::requestAndWaitForA2DPNotificationThreadExit() {
+ if (!a2dpNotificationThreadAlive)
+ return;
+ killA2DPNotificationThread = true;
+ pthread_cond_signal(&a2dp_notification_cv);
+ pthread_join(A2DPNotificationThread,NULL);
+ ALOGV("a2dp notification thread killed");
+}
+
+void LPAPlayer::onPauseTimeOut() {
+ ALOGV("onPauseTimeOut");
+ if (!mPauseEventPending) {
+ return;
+ }
+ mPauseEventPending = false;
+ if(!mIsA2DPEnabled) {
+ // 1.) Set seek flags
+ mReachedEOS = false;
+ mReachedOutputEOS = false;
+ mSeekTimeUs = mTimePlayed;
+
+ // 2.) Close routing Session
+ mAudioSink->close();
+ mIsAudioRouted = false;
+ mTrackType = TRACK_NONE;
+ }
+}
+
+status_t LPAPlayer::setupAudioSink()
+{
+ status_t err = NO_ERROR;
+
+ ALOGD("setupAudioSink with A2DP(%d) tracktype(%d)", mIsA2DPEnabled, mTrackType);
+ pthread_mutex_lock(&audio_sink_setup_mutex);
+
+ if(true == mIsA2DPEnabled) {
+ ALOGE("setupAudioSink:dIRECT track --> rEGULAR track");
+
+ if(mTrackType == TRACK_REGULAR) {
+ ALOGD("setupAudioSink:rEGULAR Track already opened");
+ pthread_mutex_unlock(&audio_sink_setup_mutex);
+ return err;
+ }
+
+ if(mTrackType == TRACK_DIRECT) {
+ ALOGD("setupAudioSink:Close dIRECT track");
+ mAudioSink->stop();
+ mAudioSink->close();
+ }
+
+ ALOGD("setupAudioSink:Open rEGULAR track");
+
+ ALOGD("setupAudioSink:mAudiosink->open() mSampleRate %d, numChannels %d, mChannelMask %d, flags %d",
+ mSampleRate, numChannels, mChannelMask, 0);
+
+ err = mAudioSink->open(
+ mSampleRate, numChannels, mChannelMask, AUDIO_FORMAT_PCM_16_BIT,
+ DEFAULT_AUDIOSINK_BUFFERCOUNT,
+ &LPAPlayer::AudioSinkCallback,
+ this,
+ (audio_output_flags_t)0,
+ NULL);
+ if (err != NO_ERROR){
+ ALOGE("setupAudioSink:Audio sink open failed.");
+ }
+
+ ALOGD("setupAudioSink:Start rEGULAR track");
+ mAudioSink->start();
+
+ ALOGD("setupAudioSink:rEGULAR track opened");
+ mTrackType = TRACK_REGULAR;
+
+ } else if (false == mIsA2DPEnabled){
+ ALOGE("setupAudioSink:rEGULAR track --> dIRECT track");
+
+ if(mTrackType == TRACK_DIRECT) {
+ ALOGD("setupAudioSink:Direct Track already opened");
+ pthread_mutex_unlock(&audio_sink_setup_mutex);
+ return err;
+ }
+
+ if(mTrackType == TRACK_REGULAR) {
+ ALOGD("setupAudioSink:Close rEGULAR track");
+ mAudioSink->stop();
+ mAudioSink->close();
+ }
+
+ ALOGD("setupAudioSink:Open dIRECT track");
+
+ ALOGD("setupAudioSink:mAudiosink->open() mSampleRate %d, numChannels %d, mChannelMask %d, flags %d",
+ mSampleRate, numChannels, mChannelMask, (AUDIO_OUTPUT_FLAG_LPA | AUDIO_OUTPUT_FLAG_DIRECT));
+
+ err = mAudioSink->open(
+ mSampleRate, numChannels, mChannelMask, AUDIO_FORMAT_PCM_16_BIT,
+ DEFAULT_AUDIOSINK_BUFFERCOUNT,
+ &LPAPlayer::AudioSinkCallback,
+ this,
+ (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_LPA | AUDIO_OUTPUT_FLAG_DIRECT),
+ NULL);
+ if (err != NO_ERROR){
+ ALOGE("setupAudioSink:Audio sink open failed.");
+ }
+
+ mTrackType = TRACK_DIRECT;
+ ALOGD("setupAudioSink:dIRECT track opened");
+ }
+ pthread_mutex_unlock(&audio_sink_setup_mutex);
+
+ return err;
+
+}
+
+
+size_t LPAPlayer::AudioCallback(
+ MediaPlayerBase::AudioSink *audioSink,
+ void *buffer, size_t size, void *cookie) {
+
+ return (static_cast<LPAPlayer *>(cookie)->AudioCallback(cookie, buffer, size));
+}
+
+size_t LPAPlayer::AudioCallback(void *cookie, void *buffer, size_t size) {
+ size_t size_done = 0;
+ uint32_t numFramesPlayedOut;
+ LPAPlayer *me = (LPAPlayer *)cookie;
+
+ if(me->mReachedOutputEOS)
+ return 0;
+
+ if (buffer == NULL && size == AudioTrack::EVENT_UNDERRUN) {
+ ALOGE("Underrun");
+ return 0;
+ } else {
+ size_done = fillBuffer(buffer, size);
+ ALOGD("RegularTrack:fillbuffersize %d %d", size_done, size);
+ if(mReachedEOS) {
+ me->mReachedOutputEOS = true;
+ me->mObserver->postAudioEOS();
+ ALOGE("postEOSDelayUs ");
+ }
+ return size_done;
+ }
+}
+
+} //namespace android
diff --git a/media/libstagefright/LPAPlayerALSA.cpp b/media/libstagefright/LPAPlayerALSA.cpp
new file mode 100644
index 0000000..b18028c
--- /dev/null
+++ b/media/libstagefright/LPAPlayerALSA.cpp
@@ -0,0 +1,753 @@
+/*
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ * 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_NDDEBUG 0
+//#define LOG_NDEBUG 0
+#define LOG_TAG "LPAPlayerALSA"
+
+#include <utils/Log.h>
+#include <utils/threads.h>
+
+#include <signal.h>
+#include <sys/prctl.h>
+#include <binder/IPCThreadState.h>
+#include <media/AudioTrack.h>
+
+#include <media/stagefright/LPAPlayer.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MediaErrors.h>
+#include "include/AwesomePlayer.h"
+
+static const char mName[] = "LPAPlayer";
+
+#define MEM_METADATA_SIZE 64
+#ifndef LPA_DEFAULT_BUFFER_SIZE
+#define LPA_DEFAULT_BUFFER_SIZE 256
+#endif
+#define MEM_BUFFER_SIZE ((LPA_DEFAULT_BUFFER_SIZE*1024) - MEM_METADATA_SIZE)
+#define MEM_BUFFER_COUNT 4
+#define LPA_BUFFER_TIME 1500000
+
+namespace android {
+int LPAPlayer::mObjectsAlive = 0;
+
+LPAPlayer::LPAPlayer(
+ const sp<MediaPlayerBase::AudioSink> &audioSink, bool &initCheck,
+ AwesomePlayer *observer)
+:AudioPlayer(audioSink, 0, observer),
+mPositionTimeMediaUs(-1),
+mPositionTimeRealUs(-1),
+mInternalSeeking(false),
+mStarted(false),
+mSampleRate(0),
+mLatencyUs(0),
+mFrameSize(0),
+mNumFramesPlayed(0),
+mNumFramesPlayedSysTimeUs(0),
+mInputBuffer(NULL),
+mSeeking(false),
+mReachedEOS(false),
+mReachedOutputEOS(false),
+mFinalStatus(OK),
+mSeekTimeUs(0),
+mPauseTime(0),
+mIsFirstBuffer(false),
+mFirstBufferResult(OK),
+mFirstBuffer(NULL),
+mAudioSink(audioSink),
+mObserver(observer) {
+ ALOGV("LPAPlayer::LPAPlayer() ctor");
+ mObjectsAlive++;
+ mNumOutputChannels =0;
+ mNumInputChannels = 0;
+ mPaused = false;
+ /* Initialize Suspend/Resume related variables */
+ mQueue.start();
+ mQueueStarted = true;
+ mPauseEvent = new TimedEvent(this, &LPAPlayer::onPauseTimeOut);
+ mPauseEventPending = false;
+ ALOGV("Registering client with AudioFlinger");
+
+ mIsAudioRouted = false;
+
+ initCheck = true;
+
+}
+
+LPAPlayer::~LPAPlayer() {
+ ALOGV("LPAPlayer::~LPAPlayer()");
+ if (mQueueStarted) {
+ mQueue.stop();
+ }
+
+ reset();
+
+ mObjectsAlive--;
+}
+
+void LPAPlayer::setSource(const sp<MediaSource> &source) {
+ CHECK(mSource == NULL);
+ ALOGV("Setting source from LPA Player");
+ mSource = source;
+}
+
+status_t LPAPlayer::start(bool sourceAlreadyStarted) {
+ CHECK(!mStarted);
+ CHECK(mSource != NULL);
+
+ ALOGV("start: sourceAlreadyStarted %d", sourceAlreadyStarted);
+ //Check if the source is started, start it
+ status_t err;
+ if (!sourceAlreadyStarted) {
+ err = mSource->start();
+
+ if (err != OK) {
+ return err;
+ }
+ }
+
+ //Create decoder thread and initialize all the
+ //mutexes and coditional variables
+ createThreads();
+ ALOGV("All Threads Created.");
+
+ // We allow an optional INFO_FORMAT_CHANGED at the very beginning
+ // of playback, if there is one, getFormat below will retrieve the
+ // updated format, if there isn't, we'll stash away the valid buffer
+ // of data to be used on the first audio callback.
+
+ CHECK(mFirstBuffer == NULL);
+
+ MediaSource::ReadOptions options;
+ if (mSeeking) {
+ options.setSeekTo(mSeekTimeUs);
+ mSeeking = false;
+ }
+
+ mFirstBufferResult = mSource->read(&mFirstBuffer, &options);
+ if (mFirstBufferResult == INFO_FORMAT_CHANGED) {
+ ALOGV("INFO_FORMAT_CHANGED!!!");
+ CHECK(mFirstBuffer == NULL);
+ mFirstBufferResult = OK;
+ mIsFirstBuffer = false;
+ } else {
+ mIsFirstBuffer = true;
+ }
+
+ sp<MetaData> format = mSource->getFormat();
+ const char *mime;
+
+ bool success = format->findCString(kKeyMIMEType, &mime);
+ CHECK(success);
+ CHECK(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW));
+
+ success = format->findInt32(kKeySampleRate, &mSampleRate);
+ CHECK(success);
+
+ success = format->findInt32(kKeyChannelCount, &mNumInputChannels);
+ CHECK(success);
+
+ // Always produce stereo output
+ mNumOutputChannels = 2;
+
+ if(!format->findInt32(kKeyChannelMask, &mChannelMask)) {
+ // log only when there's a risk of ambiguity of channel mask selection
+ ALOGI_IF(mNumInputChannels > 2,
+ "source format didn't specify channel mask, using (%d) channel order", mNumInputChannels);
+ mChannelMask = CHANNEL_MASK_USE_CHANNEL_ORDER;
+ }
+ audio_output_flags_t flags = (audio_output_flags_t) (AUDIO_OUTPUT_FLAG_LPA |
+ AUDIO_OUTPUT_FLAG_DIRECT);
+ ALOGV("mAudiosink->open() mSampleRate %d, numOutputChannels %d, mChannelMask %d, flags %d",mSampleRate,
+ mNumOutputChannels, mChannelMask, flags);
+ err = mAudioSink->open(
+ mSampleRate, mNumOutputChannels, mChannelMask, AUDIO_FORMAT_PCM_16_BIT,
+ DEFAULT_AUDIOSINK_BUFFERCOUNT,
+ &LPAPlayer::AudioSinkCallback,
+ this,
+ flags,
+ NULL);
+
+ if (err != OK) {
+ if (mFirstBuffer != NULL) {
+ mFirstBuffer->release();
+ mFirstBuffer = NULL;
+ }
+
+ if (!sourceAlreadyStarted) {
+ mSource->stop();
+ }
+
+ ALOGE("Opening a routing session failed");
+ return err;
+ }
+
+ mIsAudioRouted = true;
+ mStarted = true;
+ mAudioSink->start();
+ ALOGV("Waking up decoder thread");
+ mLock.lock();
+ mDecoderCv.signal();
+ mLock.unlock();
+
+ return OK;
+}
+
+status_t LPAPlayer::seekTo(int64_t time_us) {
+ Mutex::Autolock autoLock(mLock);
+ ALOGV("seekTo: time_us %lld", time_us);
+
+ if (seekTooClose(time_us)) {
+ mLock.unlock();
+ mObserver->postAudioSeekComplete();
+ mLock.lock();
+ return OK;
+ }
+
+ mSeeking = true;
+ mSeekTimeUs = time_us;
+ mPauseTime = mSeekTimeUs;
+ ALOGV("In seekTo(), mSeekTimeUs %lld",mSeekTimeUs);
+
+ if (mIsAudioRouted) {
+ mAudioSink->flush();
+ }
+
+ if (mReachedEOS) {
+ mReachedEOS = false;
+ mReachedOutputEOS = false;
+ if(mPaused == false) {
+ ALOGV("Going to signal decoder thread since playback is already going on ");
+ mDecoderCv.signal();
+ ALOGV("Signalled extractor thread.");
+ }
+ }
+ ALOGV("seek done.");
+ return OK;
+}
+
+void LPAPlayer::pause(bool playPendingSamples) {
+ CHECK(mStarted);
+ if (mPaused) {
+ return;
+ }
+ ALOGV("pause: playPendingSamples %d", playPendingSamples);
+ mPaused = true;
+ if (!mPauseEventPending) {
+ ALOGV("Posting an event for Pause timeout");
+ mQueue.postEventWithDelay(mPauseEvent, LPA_PAUSE_TIMEOUT_USEC);
+ mPauseEventPending = true;
+ }
+ mPauseTime = mSeekTimeUs + getTimeStamp();
+
+ if (mAudioSink.get() != NULL) {
+ ALOGV("AudioSink pause");
+ mAudioSink->pause();
+ }
+}
+
+status_t LPAPlayer::resume() {
+ ALOGV("resume: mPaused %d",mPaused);
+ status_t err = NO_ERROR;
+ Mutex::Autolock autoLock(mLock);
+ if ( mPaused) {
+ CHECK(mStarted);
+ if(mPauseEventPending) {
+ ALOGV("Resume(): Cancelling the puaseTimeout event");
+ mPauseEventPending = false;
+ mQueue.cancelEvent(mPauseEvent->eventID());
+ }
+
+ if (!mIsAudioRouted) {
+ audio_output_flags_t flags = (audio_output_flags_t) (AUDIO_OUTPUT_FLAG_LPA |
+ AUDIO_OUTPUT_FLAG_DIRECT);
+ err = mAudioSink->open(
+ mSampleRate, mNumOutputChannels, mChannelMask, AUDIO_FORMAT_PCM_16_BIT,
+ DEFAULT_AUDIOSINK_BUFFERCOUNT,
+ &LPAPlayer::AudioSinkCallback,
+ this,
+ flags,
+ NULL);
+ if (err != NO_ERROR) {
+ ALOGE("Audio sink open failed.");
+ }
+ mIsAudioRouted = true;
+ }
+ mPaused = false;
+ mAudioSink->start();
+ mDecoderCv.signal();
+
+ }
+ return err;
+}
+
+//static
+size_t LPAPlayer::AudioSinkCallback(
+ MediaPlayerBase::AudioSink *audioSink,
+ void *buffer, size_t size, void *cookie,
+ MediaPlayerBase::AudioSink::cb_event_t event) {
+ if (buffer == NULL && size == AudioTrack::EVENT_UNDERRUN) {
+ LPAPlayer *me = (LPAPlayer *)cookie;
+ if(me->mReachedEOS == true) {
+ //in the case of seek all these flags will be reset
+ me->mReachedOutputEOS = true;
+ ALOGV("postAudioEOS mSeeking %d", me->mSeeking);
+ me->mObserver->postAudioEOS(0);
+ }else {
+ ALOGV("postAudioEOS ignored since %d", me->mSeeking);
+ }
+ }
+ return 1;
+}
+
+void LPAPlayer::reset() {
+ ALOGD("Reset");
+
+ Mutex::Autolock _l(mLock); //to sync w/ onpausetimeout
+
+ //cancel any pending onpause timeout events
+ //doesnt matter if the event is really present or not
+ mPauseEventPending = false;
+ mQueue.cancelEvent(mPauseEvent->eventID());
+
+ // Close the audiosink after all the threads exited to make sure
+ mReachedEOS = true;
+
+ // make sure Decoder thread has exited
+ ALOGD("Closing all the threads");
+ requestAndWaitForDecoderThreadExit_l();
+
+ ALOGD("Close the Sink");
+ if (mIsAudioRouted) {
+ mAudioSink->stop();
+ mAudioSink->close();
+ mAudioSink.clear();
+ mIsAudioRouted = false;
+ }
+ // Make sure to release any buffer we hold onto so that the
+ // source is able to stop().
+ if (mFirstBuffer != NULL) {
+ mFirstBuffer->release();
+ mFirstBuffer = NULL;
+ }
+
+ if (mInputBuffer != NULL) {
+ ALOGV("AudioPlayer releasing input buffer.");
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+ }
+
+ mSource->stop();
+
+ // The following hack is necessary to ensure that the OMX
+ // component is completely released by the time we may try
+ // to instantiate it again.
+ wp<MediaSource> tmp = mSource;
+ mSource.clear();
+ while (tmp.promote() != NULL) {
+ usleep(1000);
+ }
+
+ mPositionTimeMediaUs = -1;
+ mPositionTimeRealUs = -1;
+ mSeeking = false;
+ mReachedEOS = false;
+ mReachedOutputEOS = false;
+ mFinalStatus = OK;
+ mStarted = false;
+}
+
+
+bool LPAPlayer::isSeeking() {
+ Mutex::Autolock autoLock(mLock);
+ return mSeeking;
+}
+
+bool LPAPlayer::reachedEOS(status_t *finalStatus) {
+ *finalStatus = OK;
+ Mutex::Autolock autoLock(mLock);
+ *finalStatus = mFinalStatus;
+ return mReachedOutputEOS;
+}
+
+
+void *LPAPlayer::decoderThreadWrapper(void *me) {
+ static_cast<LPAPlayer *>(me)->decoderThreadEntry();
+ return NULL;
+}
+
+
+void LPAPlayer::decoderThreadEntry() {
+
+ mLock.lock();
+ pid_t tid = gettid();
+ androidSetThreadPriority(tid, ANDROID_PRIORITY_AUDIO);
+ prctl(PR_SET_NAME, (unsigned long)"LPA DecodeThread", 0, 0, 0);
+
+ ALOGV("mDecoderThreadEntry wait for signal \n");
+ if (!mStarted) {
+ mDecoderCv.wait(mLock);
+ }
+ ALOGV("decoderThreadEntry ready to work \n");
+ mLock.unlock();
+ if (mKillDecoderThread) {
+ return;
+ }
+ void* local_buf = malloc(MEM_BUFFER_SIZE);
+ if(local_buf == (void*) NULL) {
+ mKillDecoderThread = true;
+ ALOGE("Malloc failed");
+ return;
+ }
+ int *lptr = ((int*)local_buf);
+ int bytesWritten = 0;
+
+ if (!local_buf) {
+ ALOGE("Failed to allocate temporary buffer for mDecoderThread");
+ return;
+ }
+
+ bool lSeeking = false;
+ bool lPaused = false;
+
+ while (!mKillDecoderThread) {
+
+ if (mReachedEOS || mPaused || !mIsAudioRouted) {
+ ALOGV("Going to sleep before write since "
+ "mReachedEOS %d, mPaused %d, mIsAudioRouted %d",
+ mReachedEOS, mPaused, mIsAudioRouted);
+ mDecoderMutex.lock();
+ mDecoderCv.wait(mDecoderMutex);
+ mDecoderMutex.unlock();
+ ALOGV("Woke up from sleep before write since "
+ "mReachedEOS %d, mPaused %d, mIsAudioRouted %d",
+ mReachedEOS, mPaused, mIsAudioRouted);
+ continue;
+ }
+
+ ALOGV("FillBuffer: MemBuffer size %d", MEM_BUFFER_SIZE);
+ ALOGV("Fillbuffer started");
+ if (mNumInputChannels == 1) {
+ bytesWritten = fillBuffer(local_buf, MEM_BUFFER_SIZE/2);
+ CHECK(bytesWritten <= MEM_BUFFER_SIZE/2);
+
+ convertMonoToStereo((int16_t*)local_buf, bytesWritten);
+ bytesWritten *= 2;
+ } else {
+ bytesWritten = fillBuffer(local_buf, MEM_BUFFER_SIZE);
+ CHECK(bytesWritten <= MEM_BUFFER_SIZE);
+ }
+
+ ALOGV("FillBuffer completed bytesToWrite %d", bytesWritten);
+ if(!mKillDecoderThread) {
+ mLock.lock();
+ lPaused = mPaused;
+ mLock.unlock();
+
+ if(lPaused == true) {
+ //write only if player is not in paused state. Sleep on lock
+ // resume is called
+ ALOGV("Going to sleep in decodethreadiwrite since sink is paused");
+ mDecoderMutex.lock();
+ mDecoderCv.wait(mDecoderMutex);
+ ALOGV("Going to unlock n decodethreadwrite since sink "
+ "resumed mPaused %d, mIsAudioRouted %d, mReachedEOS %d",
+ mPaused, mIsAudioRouted, mReachedEOS);
+ mDecoderMutex.unlock();
+ }
+ mLock.lock();
+ lSeeking = mSeeking||mInternalSeeking;
+ mLock.unlock();
+
+ if(lSeeking == false && (mKillDecoderThread == false)){
+ //if we are seeking, ignore write, otherwise write
+ ALOGV("Fillbuffer before seeling flag %d", mSeeking);
+ int lWrittenBytes = mAudioSink->write(local_buf, bytesWritten);
+ ALOGV("Fillbuffer after write, written bytes %d and seek flag %d", lWrittenBytes, mSeeking);
+ } else {
+ ALOGV("Fillbuffer ignored since we seeked after fillBuffer was set %d", mSeeking);
+ }
+ }
+ }
+
+ free(local_buf);
+
+ //TODO: Call fillbuffer with different size and write to mAudioSink()
+}
+
+void LPAPlayer::createThreads() {
+
+ // Create 4 threads Effect, decoder, event and A2dp
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+ mKillDecoderThread = false;
+
+ mDecoderThreadAlive = true;
+
+ ALOGV("Creating decoder Thread");
+ pthread_create(&mDecoderThread, &attr, decoderThreadWrapper, this);
+
+ pthread_attr_destroy(&attr);
+}
+
+size_t LPAPlayer::fillBuffer(void *data, size_t size) {
+
+ if (mReachedEOS) {
+ return 0;
+ }
+
+ if ((data == (void*) NULL) || size > MEM_BUFFER_SIZE) {
+ ALOGE("fillBuffer given wrong buffer");
+ return 0;
+ }
+
+ bool postSeekComplete = false;
+
+ size_t size_done = 0;
+ size_t size_remaining = size;
+ ALOGV("fillBuffer: Clearing seek flag in fill buffer");
+
+ while (size_remaining > 0) {
+ MediaSource::ReadOptions options;
+
+ {
+ Mutex::Autolock autoLock(mLock);
+
+ if(mSeeking) {
+ mInternalSeeking = false;
+ }
+
+ if (mSeeking || mInternalSeeking) {
+ if (mIsFirstBuffer) {
+ if (mFirstBuffer != NULL) {
+ mFirstBuffer->release();
+ mFirstBuffer = NULL;
+ }
+ mIsFirstBuffer = false;
+ }
+
+ options.setSeekTo(mSeekTimeUs);
+
+ if (mInputBuffer != NULL) {
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+ }
+
+ // This is to ignore the data already filled in the output buffer
+ size_done = 0;
+ size_remaining = size;
+
+ mSeeking = false;
+ if (mObserver && !mInternalSeeking) {
+ ALOGV("fillBuffer: Posting audio seek complete event");
+ postSeekComplete = true;
+ }
+ mInternalSeeking = false;
+ ALOGV("fillBuffer: Setting seek flag in fill buffer");
+ }
+ }
+
+ if (mInputBuffer == NULL) {
+ status_t err;
+
+ if (mIsFirstBuffer) {
+ mInputBuffer = mFirstBuffer;
+ mFirstBuffer = NULL;
+ err = mFirstBufferResult;
+
+ mIsFirstBuffer = false;
+ } else {
+ err = mSource->read(&mInputBuffer, &options);
+ }
+
+ CHECK((err == OK && mInputBuffer != NULL)
+ || (err != OK && mInputBuffer == NULL));
+ {
+ Mutex::Autolock autoLock(mLock);
+
+ if (err != OK) {
+ ALOGD("fill buffer - reached eos true");
+ mReachedEOS = true;
+ mFinalStatus = err;
+ break;
+ }
+ }
+
+ CHECK(mInputBuffer->meta_data()->findInt64(
+ kKeyTime, &mPositionTimeMediaUs));
+ mFrameSize = mAudioSink->frameSize();
+ mPositionTimeRealUs =
+ ((mNumFramesPlayed + size_done / mFrameSize) * 1000000)
+ / mSampleRate;
+ }
+ if (mInputBuffer->range_length() == 0) {
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+
+ continue;
+ }
+
+ size_t copy = size_remaining;
+ if (copy > mInputBuffer->range_length()) {
+ copy = mInputBuffer->range_length();
+ } //is size_remaining < range_length impossible?
+
+ memcpy((char *)data + size_done,
+ (const char *)mInputBuffer->data() + mInputBuffer->range_offset(),
+ copy);
+
+ mInputBuffer->set_range(mInputBuffer->range_offset() + copy,
+ mInputBuffer->range_length() - copy);
+
+ size_done += copy;
+ size_remaining -= copy;
+ }
+
+ if (postSeekComplete) {
+ mObserver->postAudioSeekComplete();
+ }
+
+ return size_done;
+}
+
+int64_t LPAPlayer::getRealTimeUs() {
+ Mutex::Autolock autoLock(mLock);
+ return getRealTimeUsLocked();
+}
+
+
+int64_t LPAPlayer::getRealTimeUsLocked(){
+ //Used for AV sync: irrelevant API for LPA.
+ return 0;
+}
+
+int64_t LPAPlayer::getTimeStamp() {
+ uint64_t timestamp = 0;
+ mAudioSink->getTimeStamp(×tamp);
+ ALOGV("timestamp %lld ", timestamp);
+ return timestamp;
+}
+
+int64_t LPAPlayer::getMediaTimeUs_l() {
+ if (mPaused) {
+ return mPauseTime;
+ } else {
+ return (mSeekTimeUs + getTimeStamp());
+ }
+}
+
+int64_t LPAPlayer::getMediaTimeUs() {
+ Mutex::Autolock autoLock(mLock);
+ ALOGV("getMediaTimeUs() mPaused %d mSeekTimeUs %lld mPauseTime %lld", mPaused, mSeekTimeUs, mPauseTime);
+ return getMediaTimeUs_l();
+}
+
+bool LPAPlayer::getMediaTimeMapping(
+ int64_t *realtime_us, int64_t *mediatime_us) {
+ ALOGE("getMediaTimeMapping is invalid for LPA Player");
+ *realtime_us = -1;
+ *mediatime_us = -1;
+ return false;
+}
+
+bool LPAPlayer::seekTooClose(int64_t time_us) {
+ int64_t t1 = getMediaTimeUs_l();
+ /*
+ * empirical
+ * -----------
+ * This constant signifies how much data (in Us) has been rendered by the
+ * DSP in the interval between the moment flush is issued on AudioSink to
+ * after ioctl(PAUSE) returns in Audio HAL. (flush triggers an implicit
+ * pause in audio HAL)
+ *
+ */
+ const int64_t kDeltaUs = 60000LL; /* 60-70ms on msm8974, must be measured for other targets */
+ t1 += kDeltaUs;
+ return (time_us > t1) && ((time_us - t1) <= LPA_BUFFER_TIME);
+}
+
+//lock taken in reset()
+void LPAPlayer::requestAndWaitForDecoderThreadExit_l() {
+
+ if (!mDecoderThreadAlive)
+ return;
+ mKillDecoderThread = true;
+
+ /* Flush the audio sink to unblock the decoder thread
+ if any write to audio HAL is blocked */
+ if (!mReachedOutputEOS && mIsAudioRouted)
+ mAudioSink->flush();
+
+ mDecoderCv.signal();
+ mLock.unlock();
+ pthread_join(mDecoderThread,NULL);
+ mLock.lock();
+ ALOGD("decoder thread killed");
+
+}
+
+void LPAPlayer::onPauseTimeOut() {
+ ALOGV("onPauseTimeOut");
+ Mutex::Autolock autoLock(mLock);
+ if (!mPauseEventPending) {
+ return;
+ }
+ mPauseEventPending = false;
+ // 1.) Set seek flags
+ mReachedEOS = false;
+ mReachedOutputEOS = false;
+ if(mSeeking == false) {
+ mSeekTimeUs += getTimeStamp();
+ mInternalSeeking = true;
+ } else {
+ //do not update seek time if user has already seeked
+ // to a new position
+ // also seek has to be posted back to player,
+ // so do not set mInternalSeeking flag
+ ALOGV("do not update seek time %lld ", mSeekTimeUs);
+ }
+ ALOGV("newseek time = %lld ", mSeekTimeUs);
+ // 2.) Close routing Session
+ mAudioSink->flush();
+ mAudioSink->stop();
+ mAudioSink->close();
+ mIsAudioRouted = false;
+}
+
+//dup each mono frame
+void LPAPlayer::convertMonoToStereo(int16_t *data, size_t size)
+{
+ int i =0;
+ int16_t *start_pointer = data;
+ int monoFrameCount = (size) / (sizeof(int16_t));
+
+ for (i = monoFrameCount; i > 0 ; i--) {
+ int16_t temp_sample = *(start_pointer + i - 1);
+ *(start_pointer + (i*2) - 1) = temp_sample;
+ *(start_pointer + (i*2) - 2) = temp_sample;
+ }
+}
+
+} //namespace android
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 4926c1d..2394b79 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -37,6 +37,10 @@
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
#include <utils/String8.h>
+#ifdef ENABLE_AV_ENHANCEMENTS
+#include <QCMediaDefs.h>
+#include "include/ExtendedUtils.h"
+#endif
namespace android {
@@ -186,6 +190,11 @@
mCachedOffset(0),
mCachedSize(0),
mCache(NULL) {
+ #ifdef DOLBY_UDC
+ #if defined (DEBUG_LOG_DDP_DECODER_EXTRA)
+ ALOGE("@DDP MPEG4DataSource::MPEG4DataSource");
+ #endif
+ #endif //DOLBY_UDC
}
MPEG4DataSource::~MPEG4DataSource() {
@@ -293,9 +302,18 @@
}
static const char *FourCC2MIME(uint32_t fourcc) {
+ #ifdef DOLBY_UDC
+ #if defined (DEBUG_LOG_DDP_DECODER_EXTRA)
+ ALOGE("@DDP FourCC2MIME");
+ #endif
+ #endif //DOLBY_UDC
switch (fourcc) {
case FOURCC('m', 'p', '4', 'a'):
return MEDIA_MIMETYPE_AUDIO_AAC;
+#ifdef QCOM_HARDWARE
+ case FOURCC('.', 'm', 'p', '3'):
+ return MEDIA_MIMETYPE_AUDIO_MPEG;
+#endif
case FOURCC('s', 'a', 'm', 'r'):
return MEDIA_MIMETYPE_AUDIO_AMR_NB;
@@ -314,8 +332,29 @@
case FOURCC('a', 'v', 'c', '1'):
return MEDIA_MIMETYPE_VIDEO_AVC;
+#ifdef ENABLE_AV_ENHANCEMENTS
+ case FOURCC('s', 'q', 'c', 'p'):
+ return MEDIA_MIMETYPE_AUDIO_QCELP;
+ case FOURCC('s', 'e', 'v', 'c'):
+ return MEDIA_MIMETYPE_AUDIO_EVRC;
+ case FOURCC('d', 't', 's', 'c'):
+ case FOURCC('d', 't', 's', 'h'):
+ case FOURCC('d', 't', 's', 'l'):
+ return MEDIA_MIMETYPE_AUDIO_DTS;
+ case FOURCC('d', 't', 's', 'e'):
+ return MEDIA_MIMETYPE_AUDIO_DTS_LBR;
+ case FOURCC('a', 'c', '-', '3'):
+ return MEDIA_MIMETYPE_AUDIO_AC3;
+ case FOURCC('e', 'c', '-', '3'):
+ return MEDIA_MIMETYPE_AUDIO_EAC3;
+#endif
default:
CHECK(!"should not be here.");
+ #ifdef DOLBY_UDC
+ #if defined (DEBUG_LOG_DDP_DECODER_EXTRA)
+ ALOGE("@DDP FourCC2Mime default (not found)");
+ #endif
+ #endif //DOLBY_UDC
return NULL;
}
}
@@ -347,6 +386,11 @@
mFileMetaData(new MetaData),
mFirstSINF(NULL),
mIsDrm(false) {
+ #ifdef DOLBY_UDC
+ #if defined (DEBUG_LOG_DDP_DECODER_EXTRA)
+ ALOGE("@DDP MPEG4Extractor::MPEG4Extractor");
+ #endif
+ #endif //DOLBY_UDC
}
MPEG4Extractor::~MPEG4Extractor() {
@@ -443,14 +487,14 @@
}
} else {
uint32_t sampleIndex;
- uint32_t sampleTime;
+ uint64_t sampleTime;
if (track->sampleTable->findThumbnailSample(&sampleIndex) == OK
&& track->sampleTable->getMetaDataForSample(
sampleIndex, NULL /* offset */, NULL /* size */,
&sampleTime) == OK) {
track->meta->setInt64(
kKeyThumbnailTime,
- ((int64_t)sampleTime * 1000000) / track->timescale);
+ (sampleTime * 1000000) / track->timescale);
}
}
}
@@ -1226,8 +1270,21 @@
case FOURCC('m', 'p', '4', 'a'):
case FOURCC('e', 'n', 'c', 'a'):
+#ifdef QCOM_HARDWARE
+ case FOURCC('.', 'm', 'p', '3'):
+#endif
case FOURCC('s', 'a', 'm', 'r'):
case FOURCC('s', 'a', 'w', 'b'):
+#ifdef QCOM_HARDWARE
+ case FOURCC('s', 'e', 'v', 'c'):
+ case FOURCC('s', 'q', 'c', 'p'):
+ case FOURCC('d', 't', 's', 'c'):
+ case FOURCC('d', 't', 's', 'h'):
+ case FOURCC('d', 't', 's', 'l'):
+ case FOURCC('d', 't', 's', 'e'):
+ case FOURCC('a', 'c', '-', '3'):
+ case FOURCC('e', 'c', '-', '3'):
+#endif
{
uint8_t buffer[8 + 20];
if (chunk_data_size < (ssize_t)sizeof(buffer)) {
@@ -1251,13 +1308,27 @@
mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(chunk_type));
AdjustChannelsAndRate(chunk_type, &num_channels, &sample_rate);
}
+ #ifdef DOLBY_UDC
+ #if defined (DEBUG_LOG_DDP_DECODER_EXTRA)
+ ALOGE("@DDP FourCC:'%s'", FourCC2MIME(chunk_type));
+ #endif
+ #endif //DOLBY_UDC
ALOGV("*** coding='%s' %d channels, size %d, rate %d\n",
chunk, num_channels, sample_size, sample_rate);
mLastTrack->meta->setInt32(kKeyChannelCount, num_channels);
mLastTrack->meta->setInt32(kKeySampleRate, sample_rate);
off64_t stop_offset = *offset + chunk_size;
+#ifdef QCOM_HARDWARE
+ if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_MPEG, FourCC2MIME(chunk_type)) ||
+ !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, FourCC2MIME(chunk_type))) {
+ *offset = stop_offset;
+ } else {
+#endif
*offset = data_offset + sizeof(buffer);
+#ifdef QCOM_HARDWARE
+ }
+#endif
while (*offset < stop_offset) {
status_t err = parseChunk(offset, depth + 1);
if (err != OK) {
@@ -1545,6 +1616,16 @@
break;
}
+#ifdef QCOM_HARDWARE
+ case FOURCC('d', 'd', 't', 's'):
+ case FOURCC('d', 'a', 'c', '3'):
+ case FOURCC('d', 'e', 'c', '3'):
+ {
+ ALOGV("ddts/dac3/dec3 pass from mpeg4 extractor");
+ *offset += chunk_size;
+ break;
+ }
+#endif
case FOURCC('a', 'v', 'c', 'C'):
{
sp<ABuffer> buffer = new ABuffer(chunk_data_size);
@@ -2253,12 +2334,27 @@
return ERROR_MALFORMED;
}
+#ifdef ENABLE_AV_ENHANCEMENTS
+ if (objectTypeIndication == 0xA0) {
+ mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_EVRC);
+ return OK;
+ }
+#endif
if (objectTypeIndication == 0xe1) {
// This isn't MPEG4 audio at all, it's QCELP 14k...
mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_QCELP);
return OK;
}
+#ifdef QCOM_HARDWARE
+ if (objectTypeIndication == 0x6b
+ || objectTypeIndication == 0x69) {
+ // Our software MP3 audio decoder may not be able to handle
+ mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+ ALOGD("objectTypeIndication:0x%x, set mimetype to mpeg ",objectTypeIndication);
+ return OK;
+ }
+#else
if (objectTypeIndication == 0x6b) {
// The media subtype is MP3 audio
// Our software MP3 audio decoder may not be able to handle
@@ -2266,6 +2362,7 @@
ALOGE("MP3 track in MP4/3GPP file is not supported");
return ERROR_UNSUPPORTED;
}
+#endif
const uint8_t *csd;
size_t csd_size;
@@ -2401,6 +2498,11 @@
mBuffer(NULL),
mWantsNALFragments(false),
mSrcBuffer(NULL) {
+ #ifdef DOLBY_UDC
+ #if defined (DEBUG_LOG_DDP_DECODER_EXTRA)
+ ALOGE("@DDP MPEG4Source::MPEG4Source");
+ #endif
+ #endif //DOLBY_UDC
mFormat->findInt32(kKeyCryptoMode, &mCryptoMode);
mDefaultIVSize = 0;
@@ -3100,7 +3202,7 @@
sampleIndex, &syncSampleIndex, findFlags);
}
- uint32_t sampleTime;
+ uint64_t sampleTime;
if (err == OK) {
err = mSampleTable->getMetaDataForSample(
sampleIndex, NULL, NULL, &sampleTime);
@@ -3124,7 +3226,7 @@
}
#if 0
- uint32_t syncSampleTime;
+ uint64_t syncSampleTime;
CHECK_EQ(OK, mSampleTable->getMetaDataForSample(
syncSampleIndex, NULL, NULL, &syncSampleTime));
@@ -3146,7 +3248,7 @@
off64_t offset;
size_t size;
- uint32_t cts;
+ uint64_t cts;
bool isSyncSample;
bool newBuffer = false;
if (mBuffer == NULL) {
@@ -3179,12 +3281,11 @@
return ERROR_IO;
}
-
CHECK(mBuffer != NULL);
mBuffer->set_range(0, size);
mBuffer->meta_data()->clear();
mBuffer->meta_data()->setInt64(
- kKeyTime, ((int64_t)cts * 1000000) / mTimescale);
+ kKeyTime, (cts * 1000000) / mTimescale);
if (targetSampleTimeUs >= 0) {
mBuffer->meta_data()->setInt64(
@@ -3306,7 +3407,7 @@
mBuffer->meta_data()->clear();
mBuffer->meta_data()->setInt64(
- kKeyTime, ((int64_t)cts * 1000000) / mTimescale);
+ kKeyTime, (cts * 1000000) / mTimescale);
if (targetSampleTimeUs >= 0) {
mBuffer->meta_data()->setInt64(
@@ -3612,6 +3713,9 @@
}
if (!memcmp(header, "ftyp3gp", 7) || !memcmp(header, "ftypmp42", 8)
+#ifdef QCOM_HARDWARE
+ || !memcmp(header, "ftyp3g2a", 8) || !memcmp(header, "ftyp3g2b", 8) || !memcmp(header, "ftyp3g2c", 8)
+#endif
|| !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 42885dd..48ad607 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -40,12 +40,15 @@
#include "include/ESDS.h"
+#include "include/ExtendedUtils.h"
+
namespace android {
static const int64_t kMinStreamableFileSizeInBytes = 5 * 1024 * 1024;
static const int64_t kMax32BitFileSize = 0x00ffffffffLL; // 2^32-1 : max FAT32
// filesystem file size
// used by most SD cards
+static const int64_t kMax64BitFileSize = 0x00ffffffffLL; //fat32 max size limited to 4GB
static const uint8_t kNalUnitTypeSeqParamSet = 0x07;
static const uint8_t kNalUnitTypePicParamSet = 0x08;
static const int64_t kInitialDelayTimeUs = 700000LL;
@@ -442,7 +445,8 @@
// A track of type other than video or audio is not supported.
const char *mime;
- source->getFormat()->findCString(kKeyMIMEType, &mime);
+ sp<MetaData> meta = source->getFormat();
+ CHECK(meta->findCString(kKeyMIMEType, &mime));
bool isAudio = !strncasecmp(mime, "audio/", 6);
bool isVideo = !strncasecmp(mime, "video/", 6);
if (!isAudio && !isVideo) {
@@ -510,7 +514,7 @@
// 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;
@@ -569,11 +573,14 @@
mIsFileSizeLimitExplicitlyRequested = true;
}
- int32_t use64BitOffset;
+ int32_t use64BitOffset = 0;
if (param &&
param->findInt32(kKey64BitFileOffset, &use64BitOffset) &&
use64BitOffset) {
mUse32BitOffset = false;
+ if (mMaxFileSizeLimitBytes == 0) {
+ mMaxFileSizeLimitBytes = kMax64BitFileSize;
+ }
}
if (mUse32BitOffset) {
@@ -2144,6 +2151,83 @@
mGotAllCodecSpecificData = true;
continue;
}
+#if defined(OMAP_ENHANCEMENT) && defined(TARGET_OMAP3)
+ else if (mIsAvc && count < 3) {
+ size_t size = buffer->range_length();
+
+ switch (count) {
+ case 1:
+ {
+ CHECK_EQ(mCodecSpecificData, (void *)NULL);
+ mCodecSpecificData = malloc(size + 8);
+ uint8_t *header = (uint8_t *)mCodecSpecificData;
+ header[0] = 1;
+ header[1] = 0x42; // profile
+ header[2] = 0x80;
+ header[3] = 0x1e; // level
+ header[4] = 0xfc | 3;
+ header[5] = 0xe0 | 1;
+ header[6] = size >> 8;
+ header[7] = size & 0xff;
+ memcpy(&header[8],
+ (const uint8_t *)buffer->data() + buffer->range_offset(),
+ size);
+
+ mCodecSpecificDataSize = size + 8;
+ break;
+ }
+
+ case 2:
+ {
+ size_t offset = mCodecSpecificDataSize;
+ mCodecSpecificDataSize += size + 3;
+ mCodecSpecificData = realloc(mCodecSpecificData, mCodecSpecificDataSize);
+ uint8_t *header = (uint8_t *)mCodecSpecificData;
+ header[offset] = 1;
+ header[offset + 1] = size >> 8;
+ header[offset + 2] = size & 0xff;
+ memcpy(&header[offset + 3],
+ (const uint8_t *)buffer->data() + buffer->range_offset(),
+ size);
+ break;
+ }
+ }
+
+ buffer->release();
+ buffer = NULL;
+
+ continue;
+
+ } else if (mCodecSpecificData == NULL && mIsMPEG4) {
+ const uint8_t *data =
+ (const uint8_t *)buffer->data() + buffer->range_offset();
+
+ const size_t size = buffer->range_length();
+
+ size_t offset = 0;
+ while (offset + 3 < size) {
+ if (data[offset] == 0x00 && data[offset + 1] == 0x00
+ && data[offset + 2] == 0x01 && data[offset + 3] == 0xb6) {
+ break;
+ }
+
+ ++offset;
+ }
+
+ // CHECK(offset + 3 < size);
+ if (offset + 3 >= size) {
+ // XXX assume the entire first chunk of data is the codec specific
+ // data.
+ offset = size;
+ }
+
+ mCodecSpecificDataSize = offset;
+ mCodecSpecificData = malloc(offset);
+ memcpy(mCodecSpecificData, data, offset);
+
+ buffer->set_range(buffer->range_offset() + offset, size - offset);
+ }
+#endif
// Make a deep copy of the MediaBuffer and Metadata and release
// the original as soon as we can
@@ -2184,6 +2268,10 @@
meta_data->findInt32(kKeyIsSyncFrame, &isSync);
CHECK(meta_data->findInt64(kKeyTime, ×tampUs));
+ if (!mIsAudio) {
+ ExtendedUtils::HFR::reCalculateTimeStamp(mMeta, timestampUs);
+ }
+
////////////////////////////////////////////////////////////////////////////////
if (mStszTableEntries->count() == 0) {
mFirstSampleTimeRealUs = systemTime() / 1000;
@@ -2202,19 +2290,26 @@
}
timestampUs -= previousPausedDurationUs;
+#ifndef OMAP_ENHANCEMENT
CHECK_GE(timestampUs, 0ll);
+#endif
if (!mIsAudio) {
/*
* Composition time: timestampUs
* Decoding time: decodingTimeUs
* Composition time offset = composition time - decoding time
*/
+ int64_t tmpCttsOffsetTimeUs;
int64_t decodingTimeUs;
CHECK(meta_data->findInt64(kKeyDecodingTime, &decodingTimeUs));
+ ExtendedUtils::HFR::reCalculateTimeStamp(mMeta, decodingTimeUs);
+
decodingTimeUs -= previousPausedDurationUs;
cttsOffsetTimeUs =
- timestampUs + kMaxCttsOffsetTimeUs - decodingTimeUs;
- CHECK_GE(cttsOffsetTimeUs, 0ll);
+ timestampUs - decodingTimeUs;
+ tmpCttsOffsetTimeUs = kMaxCttsOffsetTimeUs;
+ ExtendedUtils::HFR::reCalculateTimeStamp(mMeta, tmpCttsOffsetTimeUs);
+ CHECK_GE(tmpCttsOffsetTimeUs, decodingTimeUs - timestampUs);
timestampUs = decodingTimeUs;
ALOGV("decoding time: %lld and ctts offset time: %lld",
timestampUs, cttsOffsetTimeUs);
diff --git a/media/libstagefright/MediaBuffer.cpp b/media/libstagefright/MediaBuffer.cpp
index 11b80bf..b470e43 100644
--- a/media/libstagefright/MediaBuffer.cpp
+++ b/media/libstagefright/MediaBuffer.cpp
@@ -136,6 +136,7 @@
void MediaBuffer::set_range(size_t offset, size_t length) {
if ((mGraphicBuffer == NULL) && (offset + length > mSize)) {
ALOGE("offset = %d, length = %d, mSize = %d", offset, length, mSize);
+ offset = 0;
}
CHECK((mGraphicBuffer != NULL) || (offset + length <= mSize));
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
old mode 100644
new mode 100755
index c36dd7c..49683f7
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -35,6 +35,9 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
+#ifdef QCOM_HARDWARE
+#include <media/stagefright/ExtendedCodec.h>
+#endif
#include <media/stagefright/NativeWindowWrapper.h>
#include "include/avc_utils.h"
@@ -1415,6 +1418,20 @@
++i;
}
+#ifdef QCOM_HARDWARE
+ sp<ABuffer> extendedCSD = ExtendedCodec::getRawCodecSpecificData(format);
+ if (extendedCSD != NULL) {
+ ALOGV("pushing extended CSD of size %d", extendedCSD->size());
+ mCSD.push_back(extendedCSD);
+ }
+
+ sp<ABuffer> aacCSD = ExtendedCodec::getAacCodecSpecificData(format);
+ if (aacCSD != NULL) {
+ ALOGV("pushing AAC CSD of size %d", aacCSD->size());
+ mCSD.push_back(aacCSD);
+ }
+#endif
+
ALOGV("Found %u pieces of codec specific data.", mCSD.size());
}
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index 6248e90..60e8ea8 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -27,6 +27,9 @@
#include <utils/threads.h>
#include <libexpat/expat.h>
+#ifdef QCOM_HARDWARE
+#include "include/ExtendedUtils.h"
+#endif
namespace android {
@@ -63,7 +66,15 @@
addMediaCodec(true /* encoder */, "AACEncoder", "audio/mp4a-latm");
addMediaCodec(
- false /* encoder */, "OMX.google.raw.decoder", "audio/raw");
+ false /* encoder */, "OMX.google.raw.decoder", "audio/raw");
+
+#ifdef QCOM_HARDWARE
+ Vector<AString> QcomAACQuirks;
+ QcomAACQuirks.push(AString("requires-allocate-on-input-ports"));
+ QcomAACQuirks.push(AString("requires-allocate-on-output-ports"));
+ ExtendedUtils::helper_addMediaCodec(mCodecInfos, mTypes, false, "OMX.qcom.audio.decoder.multiaac",
+ "audio/mp4a-latm", ExtendedUtils::helper_getCodecSpecificQuirks(mCodecQuirks, QcomAACQuirks));
+#endif
}
#if 0
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
old mode 100644
new mode 100755
index 9ab6611..5ebf160
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -39,6 +39,10 @@
#include <media/stagefright/MetaData.h>
#include <utils/String8.h>
+#ifdef QCOM_HARDWARE
+#include "include/ExtendedUtils.h"
+#endif
+
namespace android {
sp<MetaData> MediaExtractor::getMetaData() {
@@ -126,7 +130,11 @@
}
}
+#ifdef QCOM_HARDWARE
+ return ExtendedUtils::MediaExtractor_CreateIfNeeded(ret, source, mime);
+#else
return ret;
+#endif
}
} // namespace android
diff --git a/media/libstagefright/NOTICE b/media/libstagefright/NOTICE
index c5b1efa..1c3f344 100644
--- a/media/libstagefright/NOTICE
+++ b/media/libstagefright/NOTICE
@@ -188,3 +188,31 @@
END OF TERMS AND CONDITIONS
+Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 43736ad..1562574 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1,5 +1,8 @@
/*
* Copyright (C) 2009 The Android Open Source Project
+ * Copyright (c) 2010 - 2013, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,6 +22,9 @@
#include <utils/Log.h>
#include "include/AACEncoder.h"
+#ifdef QCOM_HARDWARE
+#include "include/MP3Decoder.h"
+#endif
#include "include/ESDS.h"
@@ -41,11 +47,50 @@
#include <OMX_Audio.h>
#include <OMX_Component.h>
-
+#ifdef QCOM_HARDWARE
+#include <media/stagefright/ExtendedCodec.h>
+#include "include/ExtendedUtils.h"
+#endif
#include "include/avc_utils.h"
+#ifdef ENABLE_AV_ENHANCEMENTS
+#include <QCMediaDefs.h>
+#include <QCMetaData.h>
+#include <QOMX_AudioExtensions.h>
+#endif
+
+#ifdef USE_SAMSUNG_COLORFORMAT
+#include <sec_format.h>
+#endif
+
+#ifdef USE_TI_CUSTOM_DOMX
+#include <OMX_TI_Video.h>
+#include <OMX_TI_Index.h>
+#include <OMX_TI_IVCommon.h>
+#include <ctype.h>
+#endif
+
namespace android {
+#ifdef USE_SAMSUNG_COLORFORMAT
+static const int OMX_SEC_COLOR_FormatNV12TPhysicalAddress = 0x7F000001;
+static const int OMX_SEC_COLOR_FormatNV12LPhysicalAddress = 0x7F000002;
+static const int OMX_SEC_COLOR_FormatNV12LVirtualAddress = 0x7F000003;
+static const int OMX_SEC_COLOR_FormatNV12Tiled = 0x7FC00002;
+static int calc_plane(int width, int height)
+{
+ int mbX, mbY;
+
+ mbX = (width + 15)/16;
+ mbY = (height + 15)/16;
+
+ /* Alignment for interlaced processing */
+ mbY = (mbY + 1) / 2 * 2;
+
+ return (mbX * 16) * (mbY * 16);
+}
+#endif // USE_SAMSUNG_COLORFORMAT
+
// Treat time out as an error if we have not received any output
// buffers after 3 seconds.
const static int64_t kBufferFilledEventTimeOutNs = 3000000000LL;
@@ -57,6 +102,11 @@
// component in question is buggy or not.
const static uint32_t kMaxColorFormatSupported = 1000;
+#define FACTORY_CREATE(name) \
+static sp<MediaSource> Make##name(const sp<MediaSource> &source) { \
+ return new name(source); \
+}
+
#define FACTORY_CREATE_ENCODER(name) \
static sp<MediaSource> Make##name(const sp<MediaSource> &source, const sp<MetaData> &meta) { \
return new name(source, meta); \
@@ -64,6 +114,9 @@
#define FACTORY_REF(name) { #name, Make##name },
+#ifdef QCOM_HARDWARE
+FACTORY_CREATE(MP3Decoder)
+#endif
FACTORY_CREATE_ENCODER(AACEncoder)
static sp<MediaSource> InstantiateSoftwareEncoder(
@@ -87,8 +140,28 @@
return NULL;
}
+#ifdef QCOM_HARDWARE
+static sp<MediaSource> InstantiateSoftwareDecoder(
+ const char *name, const sp<MediaSource> &source) {
+ struct FactoryInfo {
+ const char *name;
+ sp<MediaSource> (*CreateFunc)(const sp<MediaSource> &);
+ };
+ static const FactoryInfo kFactoryInfo[] = {
+ FACTORY_REF(MP3Decoder)
+ };
+ for (size_t i = 0;
+ i < sizeof(kFactoryInfo) / sizeof(kFactoryInfo[0]); ++i) {
+ if (!strcmp(name, kFactoryInfo[i].name)) {
+ return (*kFactoryInfo[i].CreateFunc)(source);
+ }
+ }
+ return NULL;
+}
+#endif
#undef FACTORY_CREATE_ENCODER
#undef FACTORY_REF
+#undef FACTORY_CREATE
#define CODEC_LOGI(x, ...) ALOGI("[%s] "x, mComponentName, ##__VA_ARGS__)
#define CODEC_LOGV(x, ...) ALOGV("[%s] "x, mComponentName, ##__VA_ARGS__)
@@ -133,7 +206,13 @@
}
static bool IsSoftwareCodec(const char *componentName) {
- if (!strncmp("OMX.google.", componentName, 11)) {
+#ifdef DOLBY_UDC
+ if (!strncmp("OMX.dolby.", componentName, 10)) {
+ return true;
+ }
+#endif // DOLBY_UDC
+ if (!strncmp("OMX.google.", componentName, 11)
+ || !strncmp("OMX.PV.", componentName, 7)) {
return true;
}
@@ -192,6 +271,16 @@
}
size_t index = 0;
+
+#ifdef ENABLE_AV_ENHANCEMENTS
+ if (matchComponentName && !strcmp("OMX.qcom.audio.encoder.aac", matchComponentName)) {
+ matchingCodecs->add();
+ CodecNameAndQuirks *entry = &matchingCodecs->editItemAt(index);
+ entry->mName = String8("OMX.qcom.audio.encoder.aac");
+ entry->mQuirks = 0;
+ return;
+ }
+#endif
for (;;) {
ssize_t matchIndex =
list->findCodecByType(mime, createEncoder, index);
@@ -205,6 +294,7 @@
const char *componentName = list->getCodecName(matchIndex);
// If a specific codec is requested, skip the non-matching ones.
+ ALOGV("matchComponentName %s ",matchComponentName);
if (matchComponentName && strcmp(componentName, matchComponentName)) {
continue;
}
@@ -236,6 +326,23 @@
uint32_t OMXCodec::getComponentQuirks(
const MediaCodecList *list, size_t index) {
uint32_t quirks = 0;
+
+ if (list->codecHasQuirk(
+ index, "needs-flush-before-disable")) {
+ quirks |= kNeedsFlushBeforeDisable;
+ }
+ if (list->codecHasQuirk(
+ index, "requires-flush-complete-emulation")) {
+ quirks |= kRequiresFlushCompleteEmulation;
+ }
+ if (list->codecHasQuirk(
+ index, "supports-multiple-frames-per-input-buffer")) {
+ quirks |= kSupportsMultipleFramesPerInputBuffer;
+ }
+ if (list->codecHasQuirk(
+ index, "requires-larger-encoder-output-buffer")) {
+ quirks |= kRequiresLargerEncoderOutputBuffer;
+ }
if (list->codecHasQuirk(
index, "requires-allocate-on-input-ports")) {
quirks |= kRequiresAllocateBufferOnInputPorts;
@@ -245,9 +352,51 @@
quirks |= kRequiresAllocateBufferOnOutputPorts;
}
if (list->codecHasQuirk(
+ index, "requires-flush-before-shutdown")) {
+ quirks |= kRequiresFlushBeforeShutdown;
+ }
+ if (list->codecHasQuirk(
index, "output-buffers-are-unreadable")) {
quirks |= kOutputBuffersAreUnreadable;
}
+#ifdef QCOM_HARDWARE
+ if (list->codecHasQuirk(
+ index, "requies-loaded-to-idle-after-allocation")) {
+ quirks |= kRequiresLoadedToIdleAfterAllocation;
+ }
+ if (list->codecHasQuirk(
+ index, "requires-global-flush")) {
+ quirks |= kRequiresGlobalFlush;
+ }
+ if (list->codecHasQuirk(
+ index, "defers-output-buffer-allocation")) {
+ quirks |= kDefersOutputBufferAllocation;
+ }
+#ifdef DOLBY_UDC
+ if (list->codecHasQuirk(
+ index, "needs-flush-before-disable")) {
+ quirks |= kNeedsFlushBeforeDisable;
+ }
+ if (list->codecHasQuirk(
+ index, "requires-flush-complete-emulation")) {
+ quirks |= kRequiresFlushCompleteEmulation;
+ }
+#endif // DOLBY_UDC
+#endif
+#ifdef OMAP_ENHANCEMENT
+ if (list->codecHasQuirk(
+ index, "avoid-memcopy-input-recording-frames")) {
+ quirks |= kAvoidMemcopyInputRecordingFrames;
+ }
+ if (list->codecHasQuirk(
+ index, "input-buffer-sizes-are-bogus")) {
+ quirks |= kInputBufferSizesAreBogus;
+ }
+#endif
+
+#ifdef QCOM_HARDWARE
+ quirks |= ExtendedCodec::getComponentQuirks(list,index);
+#endif
return quirks;
}
@@ -259,6 +408,12 @@
if (list == NULL) {
return false;
}
+#ifdef ENABLE_AV_ENHANCEMENTS
+ if (componentName && !strcmp("OMX.qcom.audio.encoder.aac", componentName)) {
+ *quirks = 0;
+ return true;
+ }
+#endif
ssize_t index = list->findCodecByName(componentName);
@@ -293,8 +448,18 @@
CHECK(success);
Vector<CodecNameAndQuirks> matchingCodecs;
- findMatchingCodecs(
+
+#ifdef QCOM_HARDWARE
+ if (ExtendedCodec::useHWAACDecoder(mime)) {
+ findMatchingCodecs(mime, createEncoder,
+ "OMX.qcom.audio.decoder.multiaac", flags, &matchingCodecs);
+ } else {
+#endif
+ findMatchingCodecs(
mime, createEncoder, matchComponentName, flags, &matchingCodecs);
+#ifdef QCOM_HARDWARE
+ }
+#endif
if (matchingCodecs.isEmpty()) {
ALOGV("No matching codecs! (mime: %s, createEncoder: %s, "
@@ -319,15 +484,25 @@
componentName = tmp.c_str();
}
+ sp<MediaSource> softwareCodec;
if (createEncoder) {
- sp<MediaSource> softwareCodec =
- InstantiateSoftwareEncoder(componentName, source, meta);
-
+ softwareCodec = InstantiateSoftwareEncoder(componentName, source, meta);
+#ifdef QCOM_HARDWARE
+ } else {
+ softwareCodec = InstantiateSoftwareDecoder(componentName, source);
+ }
+#endif
if (softwareCodec != NULL) {
ALOGV("Successfully allocated software codec '%s'", componentName);
return softwareCodec;
}
+
+#ifdef QCOM_HARDWARE
+ const char* ext_componentName = ExtendedCodec::overrideComponentName(quirks, meta);
+ if(ext_componentName != NULL) {
+ componentName = ext_componentName;
+#endif
}
ALOGV("Attempting to allocate OMX node '%s'", componentName);
@@ -466,8 +641,18 @@
esds.getCodecSpecificInfo(
&codec_specific_data, &codec_specific_data_size);
+#ifdef QCOM_HARDWARE
+ const char * mime_type;
+ meta->findCString(kKeyMIMEType, &mime_type);
+ if (strncmp(mime_type,
+ MEDIA_MIMETYPE_AUDIO_MPEG,
+ strlen(MEDIA_MIMETYPE_AUDIO_MPEG))) {
+#endif
addCodecSpecificData(
codec_specific_data, codec_specific_data_size);
+#ifdef QCOM_HARDWARE
+ }
+#endif
} else if (meta->findData(kKeyAVCC, &type, &data, &size)) {
// Parse the AVCDecoderConfigurationRecord
@@ -479,6 +664,10 @@
return err;
}
+#ifdef QCOM_HARDWARE
+ ExtendedUtils::setArbitraryModeIfInterlaced((const uint8_t *)data, meta);
+#endif
+
CODEC_LOGI(
"AVC profile = %u (%s), level = %u",
profile, AVCProfileToString(profile), level);
@@ -487,6 +676,18 @@
CHECK(meta->findData(kKeyVorbisBooks, &type, &data, &size));
addCodecSpecificData(data, size);
+#ifdef QCOM_HARDWARE
+#ifdef ENABLE_AV_ENHANCEMENTS
+ } else if (meta->findData(kKeyRawCodecSpecificData, &type, &data, &size)) {
+ ALOGV("OMXCodec::configureCodec found kKeyRawCodecSpecificData of size %d\n", size);
+ addCodecSpecificData(data, size);
+#endif
+ } else {
+ ExtendedCodec::getRawCodecSpecificData(meta, data, size);
+ if (size) {
+ addCodecSpecificData(data, size);
+ }
+#endif
}
}
@@ -517,6 +718,15 @@
CODEC_LOGE("setAACFormat() failed (err = %d)", err);
return err;
}
+#ifdef ENABLE_AV_ENHANCEMENTS
+ uint32_t type;
+ const void *data;
+ size_t size;
+ if (meta->findData(kKeyAacCodecSpecificData, &type, &data, &size)) {
+ ALOGV("OMXCodec:: configureCodec found kKeyAacCodecSpecificData of size %d\n", size);
+ addCodecSpecificData(data, size);
+ }
+#endif
} else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_MPEG, mMIME)) {
int32_t numChannels, sampleRate;
if (meta->findInt32(kKeyChannelCount, &numChannels)
@@ -545,12 +755,29 @@
CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
+#ifdef QCOM_HARDWARE
+ } else {
+ if (mIsEncoder && !mIsVideo) {
+ int32_t numChannels, sampleRate;
+ CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
+ CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
+ setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
+ }
+ status_t err = ExtendedCodec::setAudioFormat(
+ meta, mMIME, mOMX, mNode, mIsEncoder);
+ if(OK != err) {
+ return err;
+ }
+#endif
}
if (!strncasecmp(mMIME, "video/", 6)) {
if (mIsEncoder) {
- setVideoInputFormat(mMIME, meta);
+ status_t err = setVideoInputFormat(mMIME, meta);
+ if (err != OK) {
+ return err;
+ }
} else {
status_t err = setVideoOutputFormat(
mMIME, meta);
@@ -558,6 +785,15 @@
if (err != OK) {
return err;
}
+
+#ifdef QCOM_HARDWARE
+ ExtendedCodec::configureVideoDecoder(
+ meta, mMIME, mOMX, mFlags, mNode, mComponentName);
+ ExtendedCodec::configureFramePackingFormat(
+ meta, mOMX, mNode, mComponentName);
+ ExtendedCodec::enableSmoothStreaming(
+ mOMX, mNode, &mInSmoothStreamingMode, mComponentName);
+#endif
}
}
@@ -671,6 +907,22 @@
index, format.eCompressionFormat, format.eColorFormat);
#endif
+ if (!strcmp("OMX.TI.Video.encoder", mComponentName) ||
+ !strcmp("OMX.TI.720P.Encoder", mComponentName)) {
+ if (portIndex == kPortIndexInput
+ && colorFormat == format.eColorFormat) {
+ // eCompressionFormat does not seem right.
+ found = true;
+ break;
+ }
+ if (portIndex == kPortIndexOutput
+ && compressionFormat == format.eCompressionFormat) {
+ // eColorFormat does not seem right.
+ found = true;
+ break;
+ }
+ }
+
if (format.eCompressionFormat == compressionFormat
&& format.eColorFormat == colorFormat) {
found = true;
@@ -697,6 +949,13 @@
return err;
}
+#ifdef USE_SAMSUNG_COLORFORMAT
+#define ALIGN_TO_8KB(x) ((((x) + (1 << 13) - 1) >> 13) << 13)
+#define ALIGN_TO_32B(x) ((((x) + (1 << 5) - 1) >> 5) << 5)
+#define ALIGN_TO_128B(x) ((((x) + (1 << 7) - 1) >> 7) << 7)
+#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
+#endif
+
static size_t getFrameSize(
OMX_COLOR_FORMATTYPE colorFormat, int32_t width, int32_t height) {
switch (colorFormat) {
@@ -716,8 +975,19 @@
* this part in the future
*/
case OMX_COLOR_FormatAndroidOpaque:
+#ifdef USE_SAMSUNG_COLORFORMAT
+ case OMX_SEC_COLOR_FormatNV12TPhysicalAddress:
+ case OMX_SEC_COLOR_FormatNV12LPhysicalAddress:
+#endif
return (width * height * 3) / 2;
-
+#ifdef USE_SAMSUNG_COLORFORMAT
+ case OMX_SEC_COLOR_FormatNV12LVirtualAddress:
+ return ALIGN((ALIGN(width, 16) * ALIGN(height, 16)), 2048) + ALIGN((ALIGN(width, 16) * ALIGN(height >> 1, 8)), 2048);
+ case OMX_SEC_COLOR_FormatNV12Tiled:
+ static unsigned int frameBufferYSise = ALIGN_TO_8KB(ALIGN_TO_128B(width) * ALIGN_TO_32B(height));
+ static unsigned int frameBufferUVSise = ALIGN_TO_8KB(ALIGN_TO_128B(width) * ALIGN_TO_32B(height/2));
+ return (frameBufferYSise + frameBufferUVSise);
+#endif
default:
CHECK(!"Should not be here. Unsupported color format.");
break;
@@ -761,7 +1031,7 @@
// the incremented index (bug 2897413).
CHECK_EQ(index, portFormat.nIndex);
if (portFormat.eColorFormat == colorFormat) {
- CODEC_LOGV("Found supported color format: %d", portFormat.eColorFormat);
+ CODEC_LOGE("Found supported color format: %d", portFormat.eColorFormat);
return OK; // colorFormat is supported!
}
++index;
@@ -777,7 +1047,7 @@
return UNKNOWN_ERROR;
}
-void OMXCodec::setVideoInputFormat(
+status_t OMXCodec::setVideoInputFormat(
const char *mime, const sp<MetaData>& meta) {
int32_t width, height, frameRate, bitRate, stride, sliceHeight;
@@ -790,6 +1060,10 @@
CHECK(success);
CHECK(stride != 0);
+#ifdef QCOM_HARDWARE
+ ExtendedUtils::HFR::reCalculateHFRParams(meta, frameRate, bitRate);
+#endif
+
OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
compressionFormat = OMX_VIDEO_CodingAVC;
@@ -798,8 +1072,15 @@
} else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
compressionFormat = OMX_VIDEO_CodingH263;
} else {
+#ifdef QCOM_HARDWARE
+ status_t err = ExtendedCodec::setVideoInputFormat(mime, &compressionFormat);
+ if(err != OK) {
+#endif
ALOGE("Not a supported video mime type: %s", mime);
CHECK(!"Should not be here. Not a supported video mime type.");
+#ifdef QCOM_HARDWARE
+ }
+#endif
}
OMX_COLOR_FORMATTYPE colorFormat;
@@ -810,21 +1091,30 @@
OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
//////////////////////// Input port /////////////////////////
- CHECK_EQ(setVideoPortFormatType(
- kPortIndexInput, OMX_VIDEO_CodingUnused,
- colorFormat), (status_t)OK);
+ err = setVideoPortFormatType(
+ kPortIndexInput, OMX_VIDEO_CodingUnused, colorFormat);
+ if(err != OK) {
+ ALOGE("Setting OMX_VIDEO_CodingUnused failed");
+ return err;
+ }
InitOMXParams(&def);
def.nPortIndex = kPortIndexInput;
err = mOMX->getParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
- CHECK_EQ(err, (status_t)OK);
+ if(err != OK) {
+ ALOGE("Getting OMX_IndexParamPortDefinition failed");
+ return err;
+ }
def.nBufferSize = getFrameSize(colorFormat,
stride > 0? stride: -stride, sliceHeight);
- CHECK_EQ((int)def.eDomain, (int)OMX_PortDomainVideo);
+ if((int)def.eDomain != (int)OMX_PortDomainVideo) {
+ ALOGE("Input port: Not a Video Domain!!");
+ return UNKNOWN_ERROR;
+ }
video_def->nFrameWidth = width;
video_def->nFrameHeight = height;
@@ -836,20 +1126,33 @@
err = mOMX->setParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
- CHECK_EQ(err, (status_t)OK);
+ if(err != OK) {
+ ALOGE("Setting Video InPort Definition failed");
+ return err;
+ }
//////////////////////// Output port /////////////////////////
- CHECK_EQ(setVideoPortFormatType(
- kPortIndexOutput, compressionFormat, OMX_COLOR_FormatUnused),
- (status_t)OK);
+ err = setVideoPortFormatType(
+ kPortIndexOutput, compressionFormat, OMX_COLOR_FormatUnused);
+ if(err != OK) {
+ ALOGE("Setting compressionFormat failed");
+ return err;
+ }
+
InitOMXParams(&def);
def.nPortIndex = kPortIndexOutput;
err = mOMX->getParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ if(err != OK) {
+ ALOGE("Getting Video InPort Definition failed");
+ return err;
+ }
- CHECK_EQ(err, (status_t)OK);
- CHECK_EQ((int)def.eDomain, (int)OMX_PortDomainVideo);
+ if((int)def.eDomain != (int)OMX_PortDomainVideo) {
+ ALOGE("Output port: Not a Video Domain");
+ return UNKNOWN_ERROR;
+ }
video_def->nFrameWidth = width;
video_def->nFrameHeight = height;
@@ -864,7 +1167,10 @@
err = mOMX->setParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
- CHECK_EQ(err, (status_t)OK);
+ if(err != OK) {
+ ALOGE("Setting Video OutPort Definition failed");
+ return err;
+ }
/////////////////// Codec-specific ////////////////////////
switch (compressionFormat) {
@@ -888,6 +1194,7 @@
CHECK(!"Support for this compressionFormat to be implemented.");
break;
}
+ return OK;
}
static OMX_U32 setPFramesSpacing(int32_t iFramesInterval, int32_t frameRate) {
@@ -1017,6 +1324,10 @@
h263type.nAllowedPictureTypes =
OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP;
+#ifdef QCOM_HARDWARE
+ ExtendedUtils::HFR::reCalculateHFRParams(meta, frameRate, bitRate);
+#endif
+
h263type.nPFrames = setPFramesSpacing(iFramesInterval, frameRate);
if (h263type.nPFrames == 0) {
h263type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI;
@@ -1068,6 +1379,10 @@
mpeg4type.nAllowedPictureTypes =
OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP;
+#ifdef QCOM_HARDWARE
+ ExtendedUtils::HFR::reCalculateHFRParams(meta, frameRate, bitRate);
+#endif
+
mpeg4type.nPFrames = setPFramesSpacing(iFramesInterval, frameRate);
if (mpeg4type.nPFrames == 0) {
mpeg4type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI;
@@ -1089,6 +1404,9 @@
mpeg4type.eProfile = static_cast<OMX_VIDEO_MPEG4PROFILETYPE>(profileLevel.mProfile);
mpeg4type.eLevel = static_cast<OMX_VIDEO_MPEG4LEVELTYPE>(profileLevel.mLevel);
+#ifdef QCOM_HARDWARE
+ ExtendedUtils::setBFrames(mpeg4type, mNumBFrames, mComponentName);
+#endif
err = mOMX->setParameter(
mNode, OMX_IndexParamVideoMpeg4, &mpeg4type, sizeof(mpeg4type));
CHECK_EQ(err, (status_t)OK);
@@ -1126,8 +1444,21 @@
h264type.eProfile = static_cast<OMX_VIDEO_AVCPROFILETYPE>(profileLevel.mProfile);
h264type.eLevel = static_cast<OMX_VIDEO_AVCLEVELTYPE>(profileLevel.mLevel);
+#ifdef QCOM_HARDWARE
+ ExtendedUtils::HFR::reCalculateHFRParams(meta, frameRate, bitRate);
+#endif
+
// XXX
+#ifdef USE_TI_DUCATI_H264_PROFILE
+ if ((strncmp(mComponentName, "OMX.TI.DUCATI1", 14) != 0)
+ && (h264type.eProfile != OMX_VIDEO_AVCProfileBaseline)) {
+#elif defined (QCOM_HARDWARE)
+ if (ExtendedUtils::isAVCProfileSupported(h264type.eProfile)){
+ ALOGI("Profile type is %d ",h264type.eProfile);
+ } else if (h264type.eProfile != OMX_VIDEO_AVCProfileBaseline) {
+#else
if (h264type.eProfile != OMX_VIDEO_AVCProfileBaseline) {
+#endif
ALOGW("Use baseline profile instead of %d for AVC recording",
h264type.eProfile);
h264type.eProfile = OMX_VIDEO_AVCProfileBaseline;
@@ -1152,6 +1483,10 @@
h264type.nCabacInitIdc = 0;
}
+#ifdef QCOM_HARDWARE
+ ExtendedUtils::setBFrames(
+ h264type, mNumBFrames, iFramesInterval, frameRate, mComponentName);
+#endif
if (h264type.nBFrames != 0) {
h264type.nAllowedPictureTypes |= OMX_VIDEO_PictureTypeB;
}
@@ -1197,8 +1532,16 @@
} else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG2, mime)) {
compressionFormat = OMX_VIDEO_CodingMPEG2;
} else {
+#ifdef QCOM_HARDWARE
+ status_t err = ExtendedCodec::setVideoOutputFormat(mime,&compressionFormat);
+
+ if(err != OK) {
+#endif
ALOGE("Not a supported video mime type: %s", mime);
CHECK(!"Should not be here. Not a supported video mime type.");
+#ifdef QCOM_HARDWARE
+ }
+#endif
}
status_t err = setVideoPortFormatType(
@@ -1221,6 +1564,30 @@
CHECK_EQ(err, (status_t)OK);
CHECK_EQ((int)format.eCompressionFormat, (int)OMX_VIDEO_CodingUnused);
+#if 0
+ CHECK(format.eColorFormat == OMX_COLOR_FormatYUV420Planar
+ || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar
+ || format.eColorFormat == OMX_COLOR_FormatCbYCrY
+ || format.eColorFormat == OMX_TI_COLOR_FormatYUV420PackedSemiPlanar
+ || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar
+ || format.eColorFormat == OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka
+#ifdef USE_SAMSUNG_COLORFORMAT
+ || format.eColorFormat == OMX_SEC_COLOR_FormatNV12TPhysicalAddress
+ || format.eColorFormat == OMX_SEC_COLOR_FormatNV12Tiled
+#endif
+ );
+
+#ifdef USE_SAMSUNG_COLORFORMAT
+ if (!strncmp("OMX.SEC.", mComponentName, 8)) {
+ if (mNativeWindow == NULL)
+ format.eColorFormat = OMX_COLOR_FormatYUV420Planar;
+ else
+ format.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
+ }
+#endif
+
+#endif
+
int32_t colorFormat;
if (meta->findInt32(kKeyColorFormat, &colorFormat)
&& colorFormat != OMX_COLOR_FormatUnused
@@ -1264,7 +1631,11 @@
#if 1
// XXX Need a (much) better heuristic to compute input buffer sizes.
+#ifdef USE_SAMSUNG_COLORFORMAT
+ const size_t X = 64 * 8 * 1024;
+#else
const size_t X = 64 * 1024;
+#endif
if (def.nBufferSize < X) {
def.nBufferSize = X;
}
@@ -1331,6 +1702,9 @@
mState(LOADED),
mInitialBufferSubmit(true),
mSignalledEOS(false),
+#ifdef QCOM_HARDWARE
+ mFinalStatus(OK),
+#endif
mNoMoreOutputData(false),
mOutputPortSettingsHaveChanged(false),
mSeekTimeUs(-1),
@@ -1342,7 +1716,13 @@
mPaused(false),
mNativeWindow(
(!strncmp(componentName, "OMX.google.", 11))
+#ifdef QCOM_HARDWARE
+ ? NULL : nativeWindow),
+ mNumBFrames(0),
+ mInSmoothStreamingMode(false) {
+#else
? NULL : nativeWindow) {
+#endif
mPortStatus[kPortIndexInput] = ENABLED;
mPortStatus[kPortIndexOutput] = ENABLED;
@@ -1370,6 +1750,10 @@
"audio_decoder.amrnb", "audio_encoder.amrnb" },
{ MEDIA_MIMETYPE_AUDIO_AMR_WB,
"audio_decoder.amrwb", "audio_encoder.amrwb" },
+#ifdef ENABLE_AV_ENHANCEMENTS
+ { MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS,
+ "audio_decoder.amrwbplus", "audio_encoder.amrwbplus" },
+#endif
{ MEDIA_MIMETYPE_AUDIO_AAC,
"audio_decoder.aac", "audio_encoder.aac" },
{ MEDIA_MIMETYPE_AUDIO_VORBIS,
@@ -1378,6 +1762,12 @@
"audio_decoder.g711mlaw", "audio_encoder.g711mlaw" },
{ MEDIA_MIMETYPE_AUDIO_G711_ALAW,
"audio_decoder.g711alaw", "audio_encoder.g711alaw" },
+#ifdef ENABLE_AV_ENHANCEMENTS
+ { MEDIA_MIMETYPE_AUDIO_EVRC,
+ "audio_decoder.evrchw", "audio_encoder.evrc" },
+ { MEDIA_MIMETYPE_AUDIO_QCELP,
+ "audio_decoder,qcelp13Hw", "audio_encoder.qcelp13" },
+#endif
{ MEDIA_MIMETYPE_VIDEO_AVC,
"video_decoder.avc", "video_encoder.avc" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4,
@@ -1394,6 +1784,16 @@
"audio_decoder.flac", "audio_encoder.flac" },
{ MEDIA_MIMETYPE_AUDIO_MSGSM,
"audio_decoder.gsm", "audio_encoder.gsm" },
+#ifdef ENABLE_AV_ENHANCEMENTS
+ { MEDIA_MIMETYPE_VIDEO_DIVX,
+ "video_decoder.divx", NULL },
+ { MEDIA_MIMETYPE_AUDIO_AC3,
+ "audio_decoder.ac3", NULL },
+ { MEDIA_MIMETYPE_AUDIO_EAC3,
+ "audio_decoder.eac3", NULL },
+ { MEDIA_MIMETYPE_VIDEO_DIVX311,
+ "video_decoder.divx", NULL },
+#endif
};
static const size_t kNumMimeToRole =
@@ -1407,6 +1807,9 @@
}
if (i == kNumMimeToRole) {
+#ifdef QCOM_HARDWARE
+ ExtendedCodec::setSupportedRole(omx, node, isEncoder, mime);
+#endif
return;
}
@@ -1493,6 +1896,10 @@
return state == LOADED_TO_IDLE
|| state == IDLE_TO_EXECUTING
|| state == EXECUTING_TO_IDLE
+#ifdef QCOM_HARDWARE
+ || state == PAUSING
+ || state == FLUSHING
+#endif
|| state == IDLE_TO_LOADED
|| state == RECONFIGURING;
}
@@ -1713,11 +2120,34 @@
return err;
}
+#ifndef USE_SAMSUNG_COLORFORMAT
err = native_window_set_buffers_geometry(
mNativeWindow.get(),
def.format.video.nFrameWidth,
def.format.video.nFrameHeight,
def.format.video.eColorFormat);
+#else
+ OMX_COLOR_FORMATTYPE eColorFormat;
+
+ switch (def.format.video.eColorFormat) {
+ case OMX_SEC_COLOR_FormatNV12TPhysicalAddress:
+ eColorFormat = (OMX_COLOR_FORMATTYPE)HAL_PIXEL_FORMAT_CUSTOM_YCbCr_420_SP_TILED;
+ break;
+ case OMX_COLOR_FormatYUV420SemiPlanar:
+ eColorFormat = (OMX_COLOR_FORMATTYPE)HAL_PIXEL_FORMAT_YCbCr_420_SP;
+ break;
+ case OMX_COLOR_FormatYUV420Planar:
+ default:
+ eColorFormat = (OMX_COLOR_FORMATTYPE)HAL_PIXEL_FORMAT_YCbCr_420_P;
+ break;
+ }
+
+ err = native_window_set_buffers_geometry(
+ mNativeWindow.get(),
+ def.format.video.nFrameWidth,
+ def.format.video.nFrameHeight,
+ eColorFormat);
+#endif
if (err != 0) {
ALOGE("native_window_set_buffers_geometry failed: %s (%d)",
@@ -1762,8 +2192,10 @@
}
ALOGV("native_window_set_usage usage=0x%lx", usage);
+
err = native_window_set_usage(
mNativeWindow.get(), usage | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP);
+
if (err != 0) {
ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), -err);
return err;
@@ -1778,12 +2210,23 @@
return err;
}
+#ifdef QCOM_HARDWARE
+ //add an extra buffer to display queue to get around dequeue+wait
+ //blocking too long (more than 1 Vsync) in case BufferQeuue is in
+ //sync-mode and advertizes only 1 buffer
+ //NOTE: This is not necessary for 30fps content, but adding a buffer
+ // regardless this root-cause is identified in SF
+ minUndequeuedBufs++;
+ ALOGI("NOTE: Overriding minUndequeuedBufs to %d",minUndequeuedBufs);
+#endif
+
// XXX: Is this the right logic to use? It's not clear to me what the OMX
// buffer counts refer to - how do they account for the renderer holding on
// to buffers?
if (def.nBufferCountActual < def.nBufferCountMin + minUndequeuedBufs) {
OMX_U32 newBufferCount = def.nBufferCountMin + minUndequeuedBufs;
def.nBufferCountActual = newBufferCount;
+ ALOGI("NOTE: Allocating %lu buffers on output port",def.nBufferCountActual);
err = mOMX->setParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
if (err != OK) {
@@ -1801,6 +2244,15 @@
return err;
}
+#ifdef QCOM_HARDWARE
+ err = mNativeWindow.get()->perform(mNativeWindow.get(),
+ NATIVE_WINDOW_SET_BUFFERS_SIZE, def.nBufferSize);
+ if (err != 0) {
+ ALOGE("native_window_set_buffers_size failed: %s (%d)", strerror(-err),
+ -err);
+ return err;
+ }
+#endif
CODEC_LOGV("allocating %lu buffers from a native window of size %lu on "
"output port", def.nBufferCountActual, def.nBufferSize);
@@ -1851,9 +2303,15 @@
cancelEnd = def.nBufferCountActual;
}
- for (OMX_U32 i = cancelStart; i < cancelEnd; i++) {
- BufferInfo *info = &mPortBuffers[kPortIndexOutput].editItemAt(i);
- cancelBufferToNativeWindow(info);
+
+ if (err != 0 &&
+ ((mState == LOADED) || (mState == LOADED_TO_IDLE))) {
+ freeBuffersOnPort(kPortIndexOutput);
+ } else {
+ for (OMX_U32 i = cancelStart; i < cancelEnd; i++) {
+ BufferInfo *info = &mPortBuffers[kPortIndexOutput].editItemAt(i);
+ cancelBufferToNativeWindow(info);
+ }
}
return err;
@@ -2118,6 +2576,14 @@
// Buffer could not be released until empty buffer done is called.
if (info->mMediaBuffer != NULL) {
+#ifdef OMAP_ENHANCEMENT
+ if (mIsEncoder &&
+ (mQuirks & kAvoidMemcopyInputRecordingFrames)) {
+ // If zero-copy mode is enabled this will send the
+ // input buffer back to the upstream source.
+ restorePatchedDataPointer(info);
+ }
+#endif
info->mMediaBuffer->release();
info->mMediaBuffer = NULL;
}
@@ -2547,11 +3013,22 @@
CODEC_LOGV("FLUSH_DONE(%ld)", portIndex);
+#ifdef QCOM_HARDWARE
+ if (portIndex == (OMX_U32) -1) {
+ CHECK_EQ((int)mPortStatus[kPortIndexInput], (int)SHUTTING_DOWN);
+ mPortStatus[kPortIndexInput] = ENABLED;
+ CHECK_EQ((int)mPortStatus[kPortIndexOutput], (int)SHUTTING_DOWN);
+ mPortStatus[kPortIndexOutput] = ENABLED;
+ } else {
+#endif
CHECK_EQ((int)mPortStatus[portIndex], (int)SHUTTING_DOWN);
mPortStatus[portIndex] = ENABLED;
CHECK_EQ(countBuffersWeOwn(mPortBuffers[portIndex]),
mPortBuffers[portIndex].size());
+#ifdef QCOM_HARDWARE
+ }
+#endif
if (mSkipCutBuffer != NULL && mPortStatus[kPortIndexOutput] == ENABLED) {
mSkipCutBuffer->clear();
@@ -2658,14 +3135,34 @@
mPortStatus[kPortIndexInput] = ENABLED;
mPortStatus[kPortIndexOutput] = ENABLED;
- if ((mFlags & kEnableGrallocUsageProtected) &&
- mNativeWindow != NULL) {
- // We push enough 1x1 blank buffers to ensure that one of
- // them has made it to the display. This allows the OMX
- // component teardown to zero out any protected buffers
- // without the risk of scanning out one of those buffers.
- pushBlankBuffersToNativeWindow();
+#ifdef QCOM_HARDWARE
+ if (mNativeWindow != NULL) {
+ /*
+ * reset buffer size field with SurfaceTexture
+ * back to 0. This will ensure proper size
+ * buffers are allocated if the same SurfaceTexture
+ * is re-used in a different decode session
+ */
+ int err =
+ mNativeWindow.get()->perform(mNativeWindow.get(),
+ NATIVE_WINDOW_SET_BUFFERS_SIZE,
+ 0);
+ if (err != 0) {
+ ALOGE("set_buffers_size failed: %s (%d)", strerror(-err),
+ -err);
+ }
+#endif
+
+ if (mFlags & kEnableGrallocUsageProtected) {
+ // We push enough 1x1 blank buffers to ensure that one of
+ // them has made it to the display. This allows the OMX
+ // component teardown to zero out any protected buffers
+ // without the risk of scanning out one of those buffers.
+ pushBlankBuffersToNativeWindow();
+ }
+#ifdef QCOM_HARDWARE
}
+#endif
setState(IDLE_TO_LOADED);
}
@@ -2700,6 +3197,16 @@
break;
}
+#ifdef QCOM_HARDWARE
+ case OMX_StatePause:
+ {
+ CODEC_LOGV("Now paused.");
+ CHECK_EQ((int)mState, (int)PAUSING);
+ setState(PAUSED);
+ break;
+ }
+#endif
+
case OMX_StateInvalid:
{
setState(ERROR);
@@ -2814,8 +3321,18 @@
bool OMXCodec::flushPortAsync(OMX_U32 portIndex) {
CHECK(mState == EXECUTING || mState == RECONFIGURING
+#ifdef QCOM_HARDWARE
+ || mState == EXECUTING_TO_IDLE || mState == FLUSHING);
+#else
|| mState == EXECUTING_TO_IDLE);
+#endif
+#ifdef QCOM_HARDWARE
+ if (portIndex == (OMX_U32) -1 ) {
+ mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
+ mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
+ } else {
+#endif
CODEC_LOGV("flushPortAsync(%ld): we own %d out of %d buffers already.",
portIndex, countBuffersWeOwn(mPortBuffers[portIndex]),
mPortBuffers[portIndex].size());
@@ -2831,6 +3348,9 @@
return false;
}
+#ifdef QCOM_HARDWARE
+ }
+#endif
status_t err =
mOMX->sendCommand(mNode, OMX_CommandFlush, portIndex);
@@ -2864,13 +3384,26 @@
}
void OMXCodec::fillOutputBuffers() {
+#ifdef QCOM_HARDWARE
+ CHECK(mState == EXECUTING || mState == FLUSHING);
+#else
CHECK_EQ((int)mState, (int)EXECUTING);
+#endif
// This is a workaround for some decoders not properly reporting
// end-of-output-stream. If we own all input buffers and also own
// all output buffers and we already signalled end-of-input-stream,
// the end-of-output-stream is implied.
- if (mSignalledEOS
+
+ // NOTE: Thumbnail mode needs a call to fillOutputBuffer in order
+ // to get the decoded frame from the component. Currently,
+ // thumbnail mode calls emptyBuffer with an EOS flag on its first
+ // frame and sets mSignalledEOS to true, so without the check for
+ // !mThumbnailMode, fillOutputBuffer will never be called.
+#ifdef QCOM_HARDWARE
+ if(!ExtendedUtils::checkIsThumbNailMode(mFlags, mComponentName)) {
+#endif
+ if (mSignalledEOS
&& countBuffersWeOwn(mPortBuffers[kPortIndexInput])
== mPortBuffers[kPortIndexInput].size()
&& countBuffersWeOwn(mPortBuffers[kPortIndexOutput])
@@ -2878,8 +3411,11 @@
mNoMoreOutputData = true;
mBufferFilled.signal();
- return;
+ return;
+ }
+#ifdef QCOM_HARDWARE
}
+#endif
Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexOutput];
for (size_t i = 0; i < buffers->size(); ++i) {
@@ -2891,7 +3427,11 @@
}
void OMXCodec::drainInputBuffers() {
+#ifdef QCOM_HARDWARE
+ CHECK(mState == EXECUTING || mState == RECONFIGURING || mState == FLUSHING);
+#else
CHECK(mState == EXECUTING || mState == RECONFIGURING);
+#endif
if (mFlags & kUseSecureInputBuffers) {
Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
@@ -2914,7 +3454,12 @@
break;
}
+#ifdef QCOM_HARDWARE
+ if ((mFlags & kOnlySubmitOneInputBufferAtOneTime)
+ && (i == mNumBFrames)) {
+#else
if (mFlags & kOnlySubmitOneInputBufferAtOneTime) {
+#endif
break;
}
}
@@ -3017,6 +3562,10 @@
size_t offset = 0;
int32_t n = 0;
+#ifdef QCOM_HARDWARE
+ int32_t InterlaceFormatDetected = false;
+ int32_t InterlaceFrameCount = 0;
+#endif
for (;;) {
@@ -3064,6 +3613,11 @@
break;
}
+#ifdef QCOM_HARDWARE
+ sp<MetaData> metaData = mSource->getFormat();
+ InterlaceFormatDetected = ExtendedUtils::checkIsInterlace(metaData);
+#endif
+
if (mFlags & kUseSecureInputBuffers) {
info = findInputBufferByDataPointer(srcBuffer->data());
CHECK(info != NULL);
@@ -3090,6 +3644,23 @@
}
bool releaseBuffer = true;
+#ifdef OMAP_ENHANCEMENT
+ if (mIsEncoder && (mQuirks & kAvoidMemcopyInputRecordingFrames)) {
+ CHECK(mOMXLivesLocally && offset == 0);
+
+ OMX_BUFFERHEADERTYPE *header =
+ (OMX_BUFFERHEADERTYPE *)info->mBuffer;
+
+ CHECK(header->pBuffer == info->mData);
+
+ header->pBuffer =
+ (OMX_U8 *)srcBuffer->data() + srcBuffer->range_offset();
+
+ releaseBuffer = false;
+ info->mMediaBuffer = srcBuffer;
+ } else {
+#endif
+
if (mFlags & kStoreMetaDataInVideoBuffers) {
releaseBuffer = false;
info->mMediaBuffer = srcBuffer;
@@ -3103,13 +3674,53 @@
CHECK(info->mMediaBuffer == NULL);
info->mMediaBuffer = srcBuffer;
} else {
+#ifdef USE_SAMSUNG_COLORFORMAT
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ InitOMXParams(&def);
+ def.nPortIndex = kPortIndexInput;
+
+ status_t err = mOMX->getParameter(mNode, OMX_IndexParamPortDefinition,
+ &def, sizeof(def));
+ CHECK_EQ(err, (status_t)OK);
+
+ if (def.eDomain == OMX_PortDomainVideo) {
+ OMX_VIDEO_PORTDEFINITIONTYPE *videoDef = &def.format.video;
+ switch (videoDef->eColorFormat) {
+ case OMX_SEC_COLOR_FormatNV12LVirtualAddress: {
+ CHECK(srcBuffer->data() != NULL);
+ void *pSharedMem = (void *)(srcBuffer->data());
+ memcpy((uint8_t *)info->mData + offset,
+ (const void *)&pSharedMem, sizeof(void *));
+ break;
+ }
+ default:
+ CHECK(srcBuffer->data() != NULL);
+ memcpy((uint8_t *)info->mData + offset,
+ (const uint8_t *)srcBuffer->data()
+ + srcBuffer->range_offset(),
+ srcBuffer->range_length());
+ break;
+ }
+ } else {
+ CHECK(srcBuffer->data() != NULL);
+ memcpy((uint8_t *)info->mData + offset,
+ (const uint8_t *)srcBuffer->data()
+ + srcBuffer->range_offset(),
+ srcBuffer->range_length());
+ }
+#else
CHECK(srcBuffer->data() != NULL) ;
memcpy((uint8_t *)info->mData + offset,
(const uint8_t *)srcBuffer->data()
+ srcBuffer->range_offset(),
srcBuffer->range_length());
+#endif // USE_SAMSUNG_COLORFORMAT
}
+#ifdef OMAP_ENHANCEMENT
+ }
+#endif
+
int64_t lastBufferTimeUs;
CHECK(srcBuffer->meta_data()->findInt64(kKeyTime, &lastBufferTimeUs));
CHECK(lastBufferTimeUs >= 0);
@@ -3165,8 +3776,29 @@
OMX_U32 flags = OMX_BUFFERFLAG_ENDOFFRAME;
+#ifdef QCOM_HARDWARE
+ if(InterlaceFormatDetected) {
+ InterlaceFrameCount++;
+ }
+#endif
+
if (signalEOS) {
flags |= OMX_BUFFERFLAG_EOS;
+#ifdef QCOM_HARDWARE
+ } else if(ExtendedUtils::checkIsThumbNailMode(mFlags, mComponentName)
+ && (!InterlaceFormatDetected || InterlaceFrameCount>= 2)) {
+ // Because we don't get an EOS after getting the first frame, we
+ // need to notify the component with OMX_BUFFERFLAG_EOS, set
+ // mNoMoreOutputData to false so fillOutputBuffer gets called on
+ // the first output buffer (see comment in fillOutputBuffer), and
+ // mSignalledEOS must be true so drainInputBuffer is not executed
+ // on extra frames. Setting mFinalStatus to ERROR_END_OF_STREAM as
+ // we dont want to return OK and NULL buffer in read.
+ flags |= OMX_BUFFERFLAG_EOS;
+ mNoMoreOutputData = false;
+ mSignalledEOS = true;
+ mFinalStatus = ERROR_END_OF_STREAM;
+#endif
} else {
mNoMoreOutputData = false;
}
@@ -3195,6 +3827,14 @@
return false;
}
+ // This component does not ever signal the EOS flag on output buffers,
+ // Thanks for nothing.
+ if (mSignalledEOS && (!strcmp(mComponentName, "OMX.TI.Video.encoder") ||
+ !strcmp(mComponentName, "OMX.TI.720P.Encoder"))) {
+ mNoMoreOutputData = true;
+ mBufferFilled.signal();
+ }
+
info->mStatus = OWNED_BY_COMPONENT;
return true;
@@ -3265,6 +3905,11 @@
return mBufferFilled.wait(mLock);
}
status_t err = mBufferFilled.waitRelative(mLock, kBufferFilledEventTimeOutNs);
+#ifdef QCOM_HARDWARE
+ if ((err == -ETIMEDOUT) && (mPaused == true)){
+ err = OK;
+ }
+#endif
if (err != OK) {
CODEC_LOGE("Timed out waiting for output buffers: %d/%d",
countBuffersWeOwn(mPortBuffers[kPortIndexInput]),
@@ -3280,6 +3925,9 @@
OMX_PARAM_PORTDEFINITIONTYPE def;
InitOMXParams(&def);
def.nPortIndex = portIndex;
+#ifdef QCOM_HARDWARE
+ def.format.audio.cMIMEType = NULL;
+#endif
status_t err = mOMX->getParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
CHECK_EQ(err, (status_t)OK);
@@ -3612,6 +4260,29 @@
status_t OMXCodec::start(MetaData *meta) {
Mutex::Autolock autoLock(mLock);
+#ifdef QCOM_HARDWARE
+ if (mPaused) {
+ if (!strncmp(mComponentName, "OMX.qcom.", 9)) {
+ while (isIntermediateState(mState)) {
+ mAsyncCompletion.wait(mLock);
+ }
+ CHECK_EQ(mState, (status_t)PAUSED);
+ status_t err = mOMX->sendCommand(mNode,OMX_CommandStateSet, OMX_StateExecuting);
+ CHECK_EQ(err, (status_t)OK);
+ setState(IDLE_TO_EXECUTING);
+ mPaused = false;
+ while (mState != EXECUTING && mState != ERROR) {
+ mAsyncCompletion.wait(mLock);
+ }
+ drainInputBuffers();
+ return mState == ERROR ? UNKNOWN_ERROR : OK;
+ } else { // SW Codec
+ mPaused = false;
+ return OK;
+ }
+ }
+#endif
+
if (mState != LOADED) {
CODEC_LOGE("called start in the unexpected state: %d", mState);
return UNKNOWN_ERROR;
@@ -3722,6 +4393,9 @@
isError = true;
}
+#ifdef QCOM_HARDWARE
+ case PAUSED:
+#endif
case EXECUTING:
{
setState(EXECUTING_TO_IDLE);
@@ -3730,6 +4404,16 @@
CODEC_LOGV("This component requires a flush before transitioning "
"from EXECUTING to IDLE...");
+#ifdef QCOM_HARDWARE
+ //DSP supports flushing of ports simultaneously.
+ //Flushing individual port is not supported.
+ if(mQuirks & kRequiresGlobalFlush) {
+ bool emulateFlushCompletion = !flushPortAsync(kPortIndexBoth);
+ if (emulateFlushCompletion) {
+ onCmdComplete(OMX_CommandFlush, kPortIndexBoth);
+ }
+ } else {
+#endif
bool emulateInputFlushCompletion =
!flushPortAsync(kPortIndexInput);
@@ -3743,6 +4427,9 @@
if (emulateOutputFlushCompletion) {
onCmdComplete(OMX_CommandFlush, kPortIndexOutput);
}
+#ifdef QCOM_HARDWARE
+ }
+#endif
} else {
mPortStatus[kPortIndexInput] = SHUTTING_DOWN;
mPortStatus[kPortIndexOutput] = SHUTTING_DOWN;
@@ -3849,7 +4536,24 @@
mFilledBuffers.clear();
CHECK_EQ((int)mState, (int)EXECUTING);
+#ifdef QCOM_HARDWARE
+ setState(FLUSHING);
+ if(mQuirks & kRequiresGlobalFlush) {
+ bool emulateFlushCompletion = !flushPortAsync(kPortIndexBoth);
+ if (emulateFlushCompletion) {
+ onCmdComplete(OMX_CommandFlush, kPortIndexBoth);
+ }
+ } else {
+ //DSP supports flushing of ports simultaneously.
+ //Flushing individual port is not supported.
+ if(mQuirks & kRequiresGlobalFlush) {
+ bool emulateFlushCompletion = !flushPortAsync(kPortIndexBoth);
+ if (emulateFlushCompletion) {
+ onCmdComplete(OMX_CommandFlush, kPortIndexBoth);
+ }
+ } else {
+#endif
bool emulateInputFlushCompletion = !flushPortAsync(kPortIndexInput);
bool emulateOutputFlushCompletion = !flushPortAsync(kPortIndexOutput);
@@ -3860,6 +4564,10 @@
if (emulateOutputFlushCompletion) {
onCmdComplete(OMX_CommandFlush, kPortIndexOutput);
}
+#ifdef QCOM_HARDWARE
+ }
+ }
+#endif
while (mSeekTimeUs >= 0) {
if ((err = waitForBufferFilled_l()) != OK) {
@@ -3870,6 +4578,15 @@
while (mState != ERROR && !mNoMoreOutputData && mFilledBuffers.empty()) {
if ((err = waitForBufferFilled_l()) != OK) {
+#ifdef QCOM_HARDWARE
+ if ((err == -ETIMEDOUT) && (mPaused == true) && !mIsVideo) {
+ // When the audio playback is paused, the fill buffer maybe timed out
+ // if input data is not available to decode. Hence, considering the
+ // timed out as a valid case.
+ ALOGV("returned OK instead of timedout from read() as mPaused is true");
+ err = OK;
+ }
+#endif
return err;
}
}
@@ -3878,6 +4595,13 @@
return UNKNOWN_ERROR;
}
+#ifdef QCOM_HARDWARE
+ if (seeking) {
+ CHECK_EQ((int)mState, (int)FLUSHING);
+ setState(EXECUTING);
+ }
+#endif
+
if (mFilledBuffers.empty()) {
return mSignalledEOS ? mFinalStatus : ERROR_END_OF_STREAM;
}
@@ -4025,7 +4749,22 @@
if (type == OMX_TI_COLOR_FormatYUV420PackedSemiPlanar) {
return "OMX_TI_COLOR_FormatYUV420PackedSemiPlanar";
- } else if (type == OMX_QCOM_COLOR_FormatYVU420SemiPlanar) {
+ }
+#ifdef USE_SAMSUNG_COLORFORMAT
+ if (type == OMX_SEC_COLOR_FormatNV12TPhysicalAddress) {
+ return "OMX_SEC_COLOR_FormatNV12TPhysicalAddress";
+ }
+ if (type == OMX_SEC_COLOR_FormatNV12LPhysicalAddress) {
+ return "OMX_SEC_COLOR_FormatNV12LPhysicalAddress";
+ }
+ if (type == OMX_SEC_COLOR_FormatNV12LVirtualAddress) {
+ return "OMX_SEC_COLOR_FormatNV12LVirtualAddress";
+ }
+ if (type == OMX_SEC_COLOR_FormatNV12Tiled) {
+ return "OMX_SEC_COLOR_FormatNV12Tiled";
+ }
+#endif // USE_SAMSUNG_COLORFORMAT
+ else if (type == OMX_QCOM_COLOR_FormatYVU420SemiPlanar) {
return "OMX_QCOM_COLOR_FormatYVU420SemiPlanar";
} else if (type < 0 || (size_t)type >= numNames) {
return "UNKNOWN";
@@ -4086,6 +4825,9 @@
"OMX_AUDIO_CodingWMA",
"OMX_AUDIO_CodingRA",
"OMX_AUDIO_CodingMIDI",
+#ifdef DOLBY_UDC
+ "OMX_AUDIO_CodingDDP",
+#endif // DOLBY_UDC
};
size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
@@ -4423,7 +5165,25 @@
mOutputFormat->setInt32(kKeySampleRate, sampleRate);
mOutputFormat->setInt32(kKeyBitRate, bitRate);
} else {
+#ifdef QCOM_HARDWARE
+ AString mimeType;
+ if (OK == ExtendedCodec::handleSupportedAudioFormats(
+ audio_def->eEncoding, &mimeType)) {
+ mOutputFormat->setCString(
+ kKeyMIMEType, mimeType.c_str());
+ int32_t numChannels, sampleRate, bitRate;
+ inputFormat->findInt32(kKeyChannelCount, &numChannels);
+ inputFormat->findInt32(kKeySampleRate, &sampleRate);
+ inputFormat->findInt32(kKeyBitRate, &bitRate);
+ mOutputFormat->setInt32(kKeyChannelCount, numChannels);
+ mOutputFormat->setInt32(kKeySampleRate, sampleRate);
+ mOutputFormat->setInt32(kKeyBitRate, bitRate);
+ } else {
+#endif
CHECK(!"Should not be here. Unknown audio encoding.");
+#ifdef QCOM_HARDWARE
+ }
+#endif
}
break;
}
@@ -4492,8 +5252,19 @@
}
if (mNativeWindow != NULL) {
- initNativeWindowCrop();
+#ifdef QCOM_HARDWARE
+ if (mInSmoothStreamingMode) {
+ ExtendedUtils::updateNativeWindowBufferGeometry(
+ mNativeWindow.get(), video_def->nFrameWidth,
+ video_def->nFrameHeight, video_def->eColorFormat);
+ }
+#endif
+ initNativeWindowCrop();
}
+#ifdef QCOM_HARDWARE
+ } else {
+ ExtendedUtils::HFR::copyHFRParams(inputFormat, mOutputFormat);
+#endif
}
break;
}
@@ -4515,15 +5286,46 @@
}
status_t OMXCodec::pause() {
+ CODEC_LOGV("pause mState=%d", mState);
+
Mutex::Autolock autoLock(mLock);
-
- mPaused = true;
-
- return OK;
+#ifdef QCOM_HARDWARE
+ if (mState != EXECUTING) {
+ return UNKNOWN_ERROR;
+ }
+ while (isIntermediateState(mState)) {
+ mAsyncCompletion.wait(mLock);
+ }
+ if (!strncmp(mComponentName, "OMX.qcom.", 9)) {
+ status_t err = mOMX->sendCommand(mNode,
+ OMX_CommandStateSet, OMX_StatePause);
+ CHECK_EQ(err, (status_t)OK);
+ setState(PAUSING);
+ mPaused = true;
+ while (mState != PAUSED && mState != ERROR) {
+ mAsyncCompletion.wait(mLock);
+ }
+ return mState == ERROR ? UNKNOWN_ERROR : OK;
+ } else {
+#endif
+ mPaused = true;
+ return OK;
+#ifdef QCOM_HARDWARE
+ }
+#endif
}
////////////////////////////////////////////////////////////////////////////////
+#ifdef OMAP_ENHANCEMENT
+void OMXCodec::restorePatchedDataPointer(BufferInfo *info) {
+ CHECK(mIsEncoder && (mQuirks & kAvoidMemcopyInputRecordingFrames));
+ CHECK(mOMXLivesLocally);
+
+ OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)info->mBuffer;
+ header->pBuffer = (OMX_U8 *)info->mData;
+}
+#endif
status_t QueryCodecs(
const sp<IOMX> &omx,
const char *mime, bool queryDecoders, bool hwCodecOnly,
@@ -4603,8 +5405,13 @@
// Color format query
OMX_VIDEO_PARAM_PORTFORMATTYPE portFormat;
InitOMXParams(&portFormat);
+#ifdef OMAP_ENHANCEMENT
+ portFormat.nPortIndex = !isEncoder ? 0 : 1;
+#else
portFormat.nPortIndex = !isEncoder ? 1 : 0;
- for (portFormat.nIndex = 0;; ++portFormat.nIndex) {
+#endif
+ for (OMX_U32 index = 0;;index++) {
+ portFormat.nIndex = index;
err = omx->getParameter(
node, OMX_IndexParamVideoPortFormat,
&portFormat, sizeof(portFormat));
diff --git a/media/libstagefright/SampleIterator.cpp b/media/libstagefright/SampleIterator.cpp
index eae721b..ee5c0d3 100644
--- a/media/libstagefright/SampleIterator.cpp
+++ b/media/libstagefright/SampleIterator.cpp
@@ -286,7 +286,7 @@
}
status_t SampleIterator::findSampleTime(
- uint32_t sampleIndex, uint32_t *time) {
+ uint32_t sampleIndex, uint64_t *time) {
if (sampleIndex >= mTable->mNumSampleSizes) {
return ERROR_OUT_OF_RANGE;
}
@@ -305,9 +305,9 @@
++mTimeToSampleIndex;
}
- *time = mTTSSampleTime + mTTSDuration * (sampleIndex - mTTSSampleIndex);
+ *time = mTTSSampleTime + (uint64_t)mTTSDuration * ((uint64_t)sampleIndex - (uint64_t)mTTSSampleIndex);
- *time += mTable->getCompositionTimeOffset(sampleIndex);
+ *time += (int32_t)mTable->getCompositionTimeOffset(sampleIndex);
return OK;
}
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
index d9858d7..9d86a0f 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/libstagefright/SampleTable.cpp
@@ -360,8 +360,9 @@
return ERROR_IO;
}
- if (U32_AT(header) != 0) {
- // Expected version = 0, flags = 0.
+ if (U32_AT(header) != 0 &&
+ U32_AT(header) != 0x01000000) {
+ // Expected version = 0/1, flags = 0.
return ERROR_MALFORMED;
}
@@ -460,7 +461,7 @@
return OK;
}
-uint32_t abs_difference(uint32_t time1, uint32_t time2) {
+uint64_t abs_difference(uint64_t time1, uint64_t time2) {
return time1 > time2 ? time1 - time2 : time2 - time1;
}
@@ -488,7 +489,7 @@
mSampleTimeEntries = new SampleTimeEntry[mNumSampleSizes];
uint32_t sampleIndex = 0;
- uint32_t sampleTime = 0;
+ uint64_t sampleTime = 0;
for (uint32_t i = 0; i < mTimeToSampleCount; ++i) {
uint32_t n = mTimeToSample[2 * i];
@@ -520,14 +521,14 @@
}
status_t SampleTable::findSampleAtTime(
- uint32_t req_time, uint32_t *sample_index, uint32_t flags) {
+ uint64_t req_time, uint32_t *sample_index, uint32_t flags) {
buildSampleEntriesTable();
uint32_t left = 0;
uint32_t right = mNumSampleSizes;
while (left < right) {
uint32_t center = (left + right) / 2;
- uint32_t centerTime = mSampleTimeEntries[center].mCompositionTime;
+ uint64_t centerTime = mSampleTimeEntries[center].mCompositionTime;
if (req_time < centerTime) {
right = center;
@@ -576,12 +577,12 @@
if (closestIndex > 0) {
// Check left neighbour and pick closest.
- uint32_t absdiff1 =
+ uint64_t absdiff1 =
abs_difference(
mSampleTimeEntries[closestIndex].mCompositionTime,
req_time);
- uint32_t absdiff2 =
+ uint64_t absdiff2 =
abs_difference(
mSampleTimeEntries[closestIndex - 1].mCompositionTime,
req_time);
@@ -656,20 +657,20 @@
return err;
}
- uint32_t sample_time = mSampleIterator->getSampleTime();
+ uint64_t sample_time = mSampleIterator->getSampleTime();
err = mSampleIterator->seekTo(x);
if (err != OK) {
return err;
}
- uint32_t x_time = mSampleIterator->getSampleTime();
+ uint64_t x_time = mSampleIterator->getSampleTime();
err = mSampleIterator->seekTo(y);
if (err != OK) {
return err;
}
- uint32_t y_time = mSampleIterator->getSampleTime();
+ uint64_t y_time = mSampleIterator->getSampleTime();
if (abs_difference(x_time, sample_time)
> abs_difference(y_time, sample_time)) {
@@ -777,7 +778,7 @@
uint32_t sampleIndex,
off64_t *offset,
size_t *size,
- uint32_t *compositionTime,
+ uint64_t *compositionTime,
bool *isSyncSample) {
Mutex::Autolock autoLock(mLock);
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index af8186c..98ba1a4 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -43,6 +43,9 @@
".wav", ".amr", ".midi", ".xmf", ".rtttl", ".rtx", ".ota",
".mkv", ".mka", ".webm", ".ts", ".fl", ".flac", ".mxmf",
".avi", ".mpeg", ".mpg", ".awb", ".mpga"
+#ifdef ENABLE_AV_ENHANCEMENTS
+ ,".qcp", ".ac3", ".dts", ".wmv", ".ec3"
+#endif
};
static const size_t kNumValidExtensions =
sizeof(kValidExtensions) / sizeof(kValidExtensions[0]);
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 19af4fb..0de6249 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -148,8 +148,16 @@
// XXX:
// Once all vendors support OMX_COLOR_FormatYUV420Planar, we can
// remove this check and always set the decoder output color format
+ // skip this check for software decoders
+#ifndef QCOM_HARDWARE
if (isYUV420PlanarSupported(client, trackMeta)) {
format->setInt32(kKeyColorFormat, OMX_COLOR_FormatYUV420Planar);
+#else
+ if (!(flags & OMXCodec::kSoftwareCodecsOnly)) {
+ if (isYUV420PlanarSupported(client, trackMeta)) {
+ format->setInt32(kKeyColorFormat, OMX_COLOR_FormatYUV420Planar);
+ }
+#endif
}
sp<MediaSource> decoder =
@@ -382,7 +390,11 @@
VideoFrame *frame =
extractVideoFrameWithCodecFlags(
+#ifndef QCOM_HARDWARE
&mClient, trackMeta, source, OMXCodec::kPreferSoftwareCodecs,
+#else
+ &mClient, trackMeta, source, OMXCodec::kSoftwareCodecsOnly,
+#endif
timeUs, option);
if (frame == NULL) {
diff --git a/media/libstagefright/TunnelPlayer.cpp b/media/libstagefright/TunnelPlayer.cpp
new file mode 100644
index 0000000..9aacbb6
--- /dev/null
+++ b/media/libstagefright/TunnelPlayer.cpp
@@ -0,0 +1,798 @@
+/*
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ * 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_NDDEBUG 0
+#define LOG_TAG "TunnelPlayer"
+#include <utils/Log.h>
+#include <utils/threads.h>
+
+#include <signal.h>
+#include <sys/prctl.h>
+#include <binder/IPCThreadState.h>
+#include <media/AudioTrack.h>
+
+#include <media/stagefright/TunnelPlayer.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/MediaErrors.h>
+#include "include/AwesomePlayer.h"
+#include <cutils/properties.h>
+
+static const char mName[] = "TunnelPlayer";
+#define MEM_METADATA_SIZE 64
+/*
+ * We need to reserve some space in the
+ * ion buffer (used in HAL) to save the
+ * metadata. so read from the extractor
+ * a somewhat smaller number of bytes.
+ * ideally this number should be bufer_size - sizeof(struct output_metadata_t)
+ */
+#define MEM_BUFFER_SIZE (240*1024 - MEM_METADATA_SIZE)
+#define MEM_BUFFER_COUNT 4
+#define TUNNEL_BUFFER_TIME 1500000
+
+namespace android {
+int TunnelPlayer::mTunnelObjectsAlive = 0;
+
+TunnelPlayer::TunnelPlayer(
+ const sp<MediaPlayerBase::AudioSink> &audioSink, bool &initCheck,
+ AwesomePlayer *observer, bool hasVideo)
+:AudioPlayer(audioSink, 0, observer),
+mPositionTimeMediaUs(-1),
+mPositionTimeRealUs(-1),
+mInternalSeeking(false),
+mStarted(false),
+mSampleRate(0),
+mLatencyUs(0),
+mFrameSize(0),
+mNumFramesPlayed(0),
+mNumFramesPlayedSysTimeUs(0),
+mInputBuffer(NULL),
+mSeeking(false),
+mReachedEOS(false),
+mReachedOutputEOS(false),
+mFinalStatus(OK),
+mSeekTimeUs(0),
+mPauseTime(0),
+mIsFirstBuffer(false),
+mFirstBufferResult(OK),
+mFirstBuffer(NULL),
+mAudioSink(audioSink),
+mObserver(observer) {
+ ALOGD("TunnelPlayer::TunnelPlayer()");
+ mTunnelObjectsAlive++;
+ numChannels = 0;
+ mPaused = false;
+ mFormat = AUDIO_FORMAT_MP3;
+ mQueue.start();
+ mQueueStarted = true;
+ mPauseEvent = new TunnelEvent(this, &TunnelPlayer::onPauseTimeOut);
+ mPauseEventPending = false;
+
+ mSeekTimeUs = 0;
+ mIsAudioRouted = false;
+ mExtractorThreadAlive = false;
+
+ mHasVideo = hasVideo;
+ initCheck = true;
+
+}
+const int TunnelPlayer::getTunnelObjectsAliveMax() {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("tunnel.multiple", value, "0");
+ if (strcmp("true",value) == 0) {
+ return 4;
+ }
+ return 1;
+}
+
+TunnelPlayer::~TunnelPlayer() {
+ ALOGD("TunnelPlayer::~TunnelPlayer()");
+ if (mQueueStarted) {
+ mQueue.stop();
+ }
+
+ reset();
+ mTunnelObjectsAlive--;
+
+}
+
+void TunnelPlayer::setSource(const sp<MediaSource> &source) {
+ CHECK(mSource == NULL);
+ ALOGD("Setting source from Tunnel Player");
+ mSource = source;
+}
+
+status_t TunnelPlayer::start(bool sourceAlreadyStarted) {
+ CHECK(!mStarted);
+ CHECK(mSource != NULL);
+
+ ALOGV("start: sourceAlreadyStarted %d", sourceAlreadyStarted);
+ //Check if the source is started, start it
+ status_t err;
+ if (!sourceAlreadyStarted) {
+ err = mSource->start();
+ if (err != OK) {
+ return err;
+ }
+ }
+
+ //Create extractor thread, read and initialize all the
+ //mutexes and coditional variables
+ createThreads();
+ ALOGV("Thread Created.");
+ // We allow an optional INFO_FORMAT_CHANGED at the very beginning
+ // of playback, if there is one, getFormat below will retrieve the
+ // updated format, if there isn't, we'll stash away the valid buffer
+ // of data to be used on the first audio callback.
+
+ CHECK(mFirstBuffer == NULL);
+
+ MediaSource::ReadOptions options;
+ if (mSeeking) {
+ options.setSeekTo(mSeekTimeUs);
+ mSeeking = false;
+ }
+
+ mFirstBufferResult = mSource->read(&mFirstBuffer, &options);
+ if (mFirstBufferResult == INFO_FORMAT_CHANGED) {
+ ALOGV("INFO_FORMAT_CHANGED!!!");
+ CHECK(mFirstBuffer == NULL);
+ mFirstBufferResult = OK;
+ mIsFirstBuffer = false;
+ } else {
+ mIsFirstBuffer = true;
+ }
+
+ sp<MetaData> format = mSource->getFormat();
+ const char *mime;
+ bool success = format->findCString(kKeyMIMEType, &mime);
+ if (!strcasecmp(mime,MEDIA_MIMETYPE_AUDIO_AAC)) {
+ mFormat = AUDIO_FORMAT_AAC;
+ }
+ else if (!strcasecmp(mime,MEDIA_MIMETYPE_AUDIO_MPEG)) {
+ mFormat = AUDIO_FORMAT_MP3;
+ ALOGD("TunnelPlayer::start AUDIO_FORMAT_MP3");
+ } else {
+ ALOGE("TunnelPlayer::UNSUPPORTED");
+ }
+
+
+ CHECK(success);
+
+ success = format->findInt32(kKeySampleRate, &mSampleRate);
+ CHECK(success);
+
+ success = format->findInt32(kKeyChannelCount, &numChannels);
+ CHECK(success);
+
+ if(!format->findInt32(kKeyChannelMask, &mChannelMask)) {
+ // log only when there's a risk of ambiguity of channel mask selection
+ ALOGI_IF(numChannels > 2,
+ "source format didn't specify channel mask, using (%d) channel order", numChannels);
+ mChannelMask = CHANNEL_MASK_USE_CHANNEL_ORDER;
+ }
+ audio_output_flags_t flags = (audio_output_flags_t) (AUDIO_OUTPUT_FLAG_TUNNEL |
+ AUDIO_OUTPUT_FLAG_DIRECT);
+ ALOGV("mAudiosink->open() mSampleRate %d, numChannels %d, mChannelMask %d, flags %d",mSampleRate, numChannels, mChannelMask, flags);
+ err = mAudioSink->open(
+ mSampleRate, numChannels, mChannelMask, mFormat,
+ DEFAULT_AUDIOSINK_BUFFERCOUNT,
+ &TunnelPlayer::AudioSinkCallback,
+ this,
+ flags,
+ NULL);
+
+ if (err != OK) {
+ if (mFirstBuffer != NULL) {
+ mFirstBuffer->release();
+ mFirstBuffer = NULL;
+ }
+
+ if (!sourceAlreadyStarted) {
+ mSource->stop();
+ }
+
+ ALOGE("Opening a routing session failed");
+ return err;
+ }
+
+ mIsAudioRouted = true;
+ mStarted = true;
+ mAudioSink->start();
+ mLock.lock();
+ ALOGV("Waking up extractor thread");
+ mExtractorCv.signal();
+ mLock.unlock();
+ return OK;
+}
+
+status_t TunnelPlayer::seekTo(int64_t time_us) {
+
+ ALOGD("seekTo: time_us %lld", time_us);
+
+ Mutex::Autolock _l(mLock); //to sync w/ onpausetimeout
+
+ if (seekTooClose(time_us)) {
+ ALOGV("seek time is too close to current playback position");
+ mLock.unlock(); //unlock and post
+ mObserver->postAudioSeekComplete();
+ mLock.lock();
+ return OK;
+ }
+
+ mSeeking = true;
+ mSeekTimeUs = time_us;
+ mPauseTime = mSeekTimeUs;
+ ALOGV("In seekTo(), mSeekTimeUs %lld",mSeekTimeUs);
+
+ if (mIsAudioRouted) {
+ mAudioSink->flush();
+ }
+
+ if (mReachedEOS) {
+ mReachedEOS = false;
+ mReachedOutputEOS = false;
+ if(mPaused == false) {
+ ALOGV("Going to signal extractor thread since playback is already going on ");
+ mExtractorCv.signal();
+ ALOGV("Signalled extractor thread.");
+ }
+ }
+ ALOGV("seek done.");
+ return OK;
+}
+void TunnelPlayer::pause(bool playPendingSamples) {
+ CHECK(mStarted);
+ if (mPaused) {
+ return;
+ }
+ Mutex::Autolock autoLock(mLock);
+ ALOGV("pause: playPendingSamples %d", playPendingSamples);
+ mPaused = true;
+ int64_t playedTime = 0;
+ if(!mPauseEventPending) {
+ ALOGV("Posting an event for Pause timeout");
+ mQueue.postEventWithDelay(mPauseEvent, TUNNEL_PAUSE_TIMEOUT_USEC);
+ mPauseEventPending = true;
+ }
+ getPlayedTimeFromDSP_l(&playedTime);
+ mPauseTime = mSeekTimeUs + playedTime;
+ if (mAudioSink.get() != NULL) {
+ ALOGV("AudioSink pause");
+ mAudioSink->pause();
+ }
+}
+
+status_t TunnelPlayer::resume() {
+ status_t err = NO_ERROR;
+ Mutex::Autolock autoLock(mLock);
+ ALOGV("resume: mPaused %d",mPaused);
+ if ( mPaused) {
+ CHECK(mStarted);
+ if(mPauseEventPending) {
+ ALOGV("Resume(): Cancelling the puaseTimeout event");
+ mPauseEventPending = false;
+ mQueue.cancelEvent(mPauseEvent->eventID());
+ }
+ audio_format_t format;
+
+ if (!mIsAudioRouted) {
+ audio_output_flags_t flags = (audio_output_flags_t) (AUDIO_OUTPUT_FLAG_TUNNEL |
+ AUDIO_OUTPUT_FLAG_DIRECT);
+ err = mAudioSink->open(
+ mSampleRate, numChannels, mChannelMask, mFormat,
+ DEFAULT_AUDIOSINK_BUFFERCOUNT,
+ &TunnelPlayer::AudioSinkCallback,
+ this,
+ flags,
+ NULL);
+ if (err != NO_ERROR) {
+ ALOGE("Audio sink open failed.");
+ }
+ mIsAudioRouted = true;
+ }
+ mPaused = false;
+ ALOGV("Audio sink open succeeded.");
+ mAudioSink->start();
+ ALOGV("Audio sink start succeeded.");
+ mExtractorCv.signal();
+ ALOGV("Audio signalling extractor thread.");
+ }
+ return err;
+}
+
+//static
+size_t TunnelPlayer::AudioSinkCallback(
+ MediaPlayerBase::AudioSink *audioSink,
+ void *buffer, size_t size, void *cookie,
+ MediaPlayerBase::AudioSink::cb_event_t event) {
+ TunnelPlayer *me = (TunnelPlayer *)cookie;
+ if(me != NULL) {
+ ALOGV("postAudioEOS mSeeking %d", me->mSeeking);
+ if (buffer == NULL && size == AudioTrack::EVENT_UNDERRUN) {
+ if(me->mReachedEOS == true) {
+ //in the case of seek all these flags will be reset
+ me->mReachedOutputEOS = true;
+ ALOGV("postAudioEOS mSeeking %d", me->mSeeking);
+ me->mObserver->postAudioEOS(0);
+ }else {
+ ALOGV("postAudioEOS ignored since %d", me->mSeeking);
+ }
+ } else if (size == AudioTrack::EVENT_HW_FAIL) {
+ ALOGV("postAudioEOS in SSR " );
+ me->mReachedOutputEOS = true;
+ me->mReachedEOS = true;
+ me->mKillExtractorThread = true;
+ me->mObserver->postAudioEOS(0);
+ }
+ }
+ return 1;
+}
+
+void TunnelPlayer::reset() {
+ ALOGV("Reset");
+
+ Mutex::Autolock _l(mLock); //to sync w/ onpausetimeout
+
+ //cancel any pending onpause timeout events
+ //doesnt matter if the event is really present or not
+ mPauseEventPending = false;
+ mQueue.cancelEvent(mPauseEvent->eventID());
+
+ mReachedEOS = true;
+
+ // make sure Decoder thread has exited
+ requestAndWaitForExtractorThreadExit_l();
+
+ // Close the audiosink after all the threads exited to make sure
+ if (mIsAudioRouted) {
+ mAudioSink->stop();
+ mAudioSink->close();
+ mIsAudioRouted = false;
+ }
+ //TODO: Release Wake lock
+
+ // Make sure to release any buffer we hold onto so that the
+ // source is able to stop().
+ if (mFirstBuffer != NULL) {
+ mFirstBuffer->release();
+ mFirstBuffer = NULL;
+ }
+
+ if (mInputBuffer != NULL) {
+ ALOGV("AudioPlayer releasing input buffer.");
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+ }
+
+ if (mStarted)
+ mSource->stop();
+
+ mSource.clear();
+
+ mPositionTimeMediaUs = -1;
+ mPositionTimeRealUs = -1;
+ mSeeking = false;
+ mReachedEOS = false;
+ mReachedOutputEOS = false;
+ mFinalStatus = OK;
+ mStarted = false;
+}
+
+
+bool TunnelPlayer::isSeeking() {
+ Mutex::Autolock autoLock(mLock);
+ return mSeeking;
+}
+
+bool TunnelPlayer::reachedEOS(status_t *finalStatus) {
+ *finalStatus = OK;
+ Mutex::Autolock autoLock(mLock);
+ *finalStatus = mFinalStatus;
+ return mReachedOutputEOS;
+}
+
+
+void *TunnelPlayer::extractorThreadWrapper(void *me) {
+ static_cast<TunnelPlayer *>(me)->extractorThreadEntry();
+ return NULL;
+}
+
+
+void TunnelPlayer::extractorThreadEntry() {
+
+ mLock.lock();
+ uint32_t BufferSizeToUse = MEM_BUFFER_SIZE;
+
+ pid_t tid = gettid();
+ androidSetThreadPriority(tid, mHasVideo ? ANDROID_PRIORITY_NORMAL :
+ ANDROID_PRIORITY_AUDIO);
+ prctl(PR_SET_NAME, (unsigned long)"Extractor Thread", 0, 0, 0);
+
+ ALOGV("extractorThreadEntry wait for signal \n");
+ if (!mStarted && !mKillExtractorThread) {
+ mExtractorCv.wait(mLock);
+ }
+ ALOGV("extractorThreadEntry ready to work \n");
+ mLock.unlock();
+ if (mKillExtractorThread) {
+ return;
+ }
+ if(mSource != NULL) {
+ sp<MetaData> format = mSource->getFormat();
+ const char *mime;
+ bool success = format->findCString(kKeyMIMEType, &mime);
+ }
+ void* local_buf = malloc(BufferSizeToUse);
+ int *lptr = ((int*)local_buf);
+ int bytesWritten = 0;
+ bool lSeeking = false;
+ bool lPaused = false;
+ while (!mKillExtractorThread) {
+
+ if (mReachedEOS || mPaused || !mIsAudioRouted) {
+ ALOGV("Going to sleep before write since "
+ "mReachedEOS %d, mPaused %d, mIsAudioRouted %d",
+ mReachedEOS, mPaused, mIsAudioRouted);
+ mExtractorMutex.lock();
+ mExtractorCv.wait(mExtractorMutex);
+ mExtractorMutex.unlock();
+ ALOGV("Woke up from sleep before write since "
+ "mReachedEOS %d, mPaused %d, mIsAudioRouted %d",
+ mReachedEOS, mPaused, mIsAudioRouted);
+ continue;
+ }
+
+ ALOGV("FillBuffer: MemBuffer size %d", BufferSizeToUse);
+ ALOGV("Fillbuffer started");
+ bytesWritten = fillBuffer(local_buf, BufferSizeToUse);
+ ALOGV("FillBuffer completed bytesToWrite %d", bytesWritten);
+ if(!mKillExtractorThread) {
+ mLock.lock();
+ lPaused = mPaused;
+ mLock.unlock();
+
+ if(lPaused == true) {
+ //write only if player is not in paused state. Sleep on lock
+ // resume is called
+ ALOGV("Going to sleep in decodethreadiwrite since sink is paused");
+ mExtractorMutex.lock();
+ mExtractorCv.wait(mExtractorMutex);
+ ALOGV("Going to unlock n decodethreadwrite since sink "
+ "resumed mPaused %d, mIsAudioRouted %d, mReachedEOS %d",
+ mPaused, mIsAudioRouted, mReachedEOS);
+ mExtractorMutex.unlock();
+ }
+ mLock.lock();
+ lSeeking = mSeeking||mInternalSeeking;
+ mLock.unlock();
+
+ if(lSeeking == false && (mKillExtractorThread == false)){
+ //if we are seeking, ignore write, otherwise write
+ ALOGV("Fillbuffer before seek flag %d", mSeeking);
+ int lWrittenBytes = mAudioSink->write(local_buf, bytesWritten);
+ ALOGV("Fillbuffer after write, written bytes %d and seek flag %d", lWrittenBytes, mSeeking);
+ if(lWrittenBytes > 0) {
+ //send EOS only if write was successful, if is_buffer_available
+ // is flushed out (which returns 0 do not SEND EOS
+ ALOGV("Fillbuffer after write and seek flag %d", mSeeking);
+ mLock.lock();
+ lSeeking = mSeeking||mInternalSeeking;
+ mLock.unlock();
+ //ignore posting zero length buffer is seeking is set
+ if(mReachedEOS && bytesWritten && !lSeeking && (mKillExtractorThread == false)) {
+ ALOGV("Fillbuffer after write sent EOS flag %d", lSeeking);
+ mAudioSink->write(local_buf, 0);
+ } else {
+ ALOGV("Not sending EOS buffer sent since seeking %d, "
+ "kill %d and mReachedEOS %d", \
+ lSeeking, mKillExtractorThread, mReachedEOS);
+ }
+ } else {
+ ALOGV("write exited because of flush %d", mSeeking);
+ }
+ } else {
+ ALOGV("Fillbuffer ignored since we seeked after fillBuffer was set %d", mSeeking);
+ }
+ }
+ }
+
+ free(local_buf);
+
+ //TODO: Call fillbuffer with different size and write to mAudioSink()
+}
+void TunnelPlayer::createThreads() {
+
+ // Create extractor Thread
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+ mKillExtractorThread = false;
+
+ mExtractorThreadAlive = true;
+
+ ALOGV("Creating Extractor Thread");
+ pthread_create(&mExtractorThread, &attr, extractorThreadWrapper, this);
+
+ pthread_attr_destroy(&attr);
+}
+size_t TunnelPlayer::fillBuffer(void *data, size_t size) {
+
+ if (mReachedEOS) {
+ return 0;
+ }
+
+ bool postSeekComplete = false;
+
+ size_t size_done = 0;
+ size_t size_remaining = size;
+ //clear the flag since we dont know whether we are seeking or not, yet
+ ALOGV("fillBuffer: Clearing seek flag in fill buffer");
+
+ bool yield = !mIsFirstBuffer;
+
+ while (size_remaining > 0) {
+ MediaSource::ReadOptions options;
+ {
+ Mutex::Autolock autoLock(mLock);
+ if(mSeeking) {
+ mInternalSeeking = false;
+ }
+
+ if (mSeeking || mInternalSeeking) {
+ if (mIsFirstBuffer) {
+ if (mFirstBuffer != NULL) {
+ mFirstBuffer->release();
+ mFirstBuffer = NULL;
+ }
+ mIsFirstBuffer = false;
+ }
+
+ MediaSource::ReadOptions::SeekMode seekMode;
+ seekMode = MediaSource::ReadOptions::SEEK_CLOSEST_SYNC;
+ options.setSeekTo(mSeekTimeUs, seekMode );
+ if (mInputBuffer != NULL) {
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+ }
+
+ // This is to ignore the data already filled in the output buffer
+ size_done = 0;
+ size_remaining = size;
+
+ mSeeking = false;
+ if (mObserver && !mInternalSeeking) {
+ ALOGV("fillBuffer: Posting audio seek complete event");
+ postSeekComplete = true;
+ }
+ mInternalSeeking = false;
+ ALOGV("fillBuffer: Setting seek flag in fill buffer");
+ //set the flag since we know that this buffer is the new positions buffer
+ }
+ }
+ if (mInputBuffer == NULL) {
+ status_t err;
+
+ if (mIsFirstBuffer) {
+ mInputBuffer = mFirstBuffer;
+ mFirstBuffer = NULL;
+ err = mFirstBufferResult;
+
+ mIsFirstBuffer = false;
+ } else {
+ err = mSource->read(&mInputBuffer, &options);
+ }
+
+ CHECK((err == OK && mInputBuffer != NULL)
+ || (err != OK && mInputBuffer == NULL));
+ {
+ Mutex::Autolock autoLock(mLock);
+
+ if (err != OK) {
+ ALOGD("fill buffer - reached eos true");
+ mReachedEOS = true;
+ mFinalStatus = err;
+ break;
+ }
+ }
+
+ }
+ if (mInputBuffer->range_length() == 0) {
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+ continue;
+ }
+
+ size_t copy = size_remaining;
+ if (copy > mInputBuffer->range_length()) {
+ copy = mInputBuffer->range_length();
+ }
+ memcpy((char *)data + size_done,
+ (const char *)mInputBuffer->data() + mInputBuffer->range_offset(),
+ copy);
+
+ mInputBuffer->set_range(mInputBuffer->range_offset() + copy,
+ mInputBuffer->range_length() - copy);
+
+ size_done += copy;
+ size_remaining -= copy;
+
+ if (mHasVideo && yield) {
+ sched_yield();
+ }
+ }
+ if(mReachedEOS)
+ memset((char *)data + size_done, 0x0, size_remaining);
+ ALOGV("fill buffer size_done = %d",size_done);
+
+ if (postSeekComplete) {
+ mObserver->postAudioSeekComplete();
+ }
+
+ return size_done;
+}
+
+int64_t TunnelPlayer::getRealTimeUs() {
+ Mutex::Autolock autoLock(mLock);
+
+ /*
+ * If it so happens that the client (e.g. AwesomePlayer),
+ * queries for the current time before compressed
+ * data from the new position is given to the compressed
+ * driver, we need to return the seek position
+ */
+ if (mSeeking || mInternalSeeking) {
+ ALOGV("Seek yet to be processed, return seek time as current time %lld",
+ mSeekTimeUs);
+ return mSeekTimeUs;
+ }
+
+ getOffsetRealTime_l(&mPositionTimeRealUs);
+ //update media time too
+ mPositionTimeMediaUs = mPositionTimeRealUs;
+ return mPositionTimeRealUs;
+}
+
+void TunnelPlayer::getPlayedTimeFromDSP_l(int64_t* timeStamp ) {
+ ALOGV("going to query timestamp");
+ mAudioSink->getTimeStamp((uint64_t*)timeStamp);
+ ALOGV("timestamp returned from DSP %lld ", (*timeStamp));
+ return;
+}
+
+//offset with pause and seek time
+void TunnelPlayer::getOffsetRealTime_l(int64_t* offsetTime) {
+ if (mPaused) {
+ *offsetTime = mPauseTime;
+ ALOGV("getMediaTimeUs() mPaused %d mSeekTimeUs %lld mPauseTime %lld", mPaused, mSeekTimeUs, mPauseTime );
+ } else {
+ getPlayedTimeFromDSP_l(offsetTime);
+ ALOGV("getMediaTimeUs() mPaused %d mSeekTimeUs %lld mPauseTime %lld, timeStamp %lld", mPaused, mSeekTimeUs, mPauseTime, *offsetTime);
+ *offsetTime = mSeekTimeUs + *offsetTime;
+ }
+}
+
+int64_t TunnelPlayer::getMediaTimeUs() {
+ //essentially there is only one time, the real time
+ return getRealTimeUs();
+}
+
+bool TunnelPlayer::getMediaTimeMapping(
+ int64_t *realtime_us, int64_t *mediatime_us) {
+ Mutex::Autolock autoLock(mLock);
+
+ *realtime_us = mPositionTimeRealUs;
+ *mediatime_us = mPositionTimeMediaUs;
+
+ return mPositionTimeRealUs != -1 && mPositionTimeMediaUs != -1;
+}
+
+//lock has been taken in reset() to sync with onpausetimeout
+void TunnelPlayer::requestAndWaitForExtractorThreadExit_l() {
+
+ ALOGV("requestAndWaitForExtractorThreadExit_l -1");
+
+ if (!mExtractorThreadAlive)
+ return;
+
+ mKillExtractorThread = true;
+
+ ALOGV("requestAndWaitForExtractorThreadExit_l +0");
+ if (mIsAudioRouted && !mReachedOutputEOS) {
+ mAudioSink->flush();
+ }
+
+
+ ALOGV("requestAndWaitForExtractorThreadExit_l +1");
+ mExtractorCv.signal();
+ mLock.unlock();
+ ALOGV("requestAndWaitForExtractorThreadExit_l +2");
+ pthread_join(mExtractorThread,NULL);
+ mLock.lock();
+ ALOGV("requestAndWaitForExtractorThreadExit_l +3");
+
+ ALOGV("Extractor thread killed");
+}
+
+void TunnelPlayer::onPauseTimeOut() {
+ Mutex::Autolock autoLock(mLock);
+ int64_t playedTime = 0;
+ ALOGV("onPauseTimeOut");
+ if (!mPauseEventPending) {
+ return;
+ }
+ mPauseEventPending = false;
+ // 1.) Set seek flags
+ mReachedEOS = false;
+ mReachedOutputEOS = false;
+
+ if(mSeeking == false) {
+ ALOGV("onPauseTimeOut +2");
+ mInternalSeeking = true;
+ ALOGV("onPauseTimeOut +3");
+ getPlayedTimeFromDSP_l(&playedTime);
+ mSeekTimeUs += playedTime;
+ } else {
+ ALOGV("Do not update seek time if it was seeked before onpause timeout");
+ }
+
+ // 2.) Close routing Session
+ ALOGV("onPauseTimeOut +4");
+ mAudioSink->flush();
+ ALOGV("onPauseTimeOut +5");
+ mAudioSink->stop();
+ ALOGV("onPauseTimeOut +6");
+ mAudioSink->close();
+ ALOGV("onPauseTimeOut +7");
+ mIsAudioRouted = false;
+}
+
+/*
+ * Returns true if the seek position is too close to the
+ * current playback position.
+ * Caller must acquire mLock
+ */
+bool TunnelPlayer::seekTooClose(int64_t time_us) {
+ int64_t t1 = -1;
+ /* The time as per DSP just before flush is issued */
+ if (mPositionTimeRealUs == -1) {
+ getOffsetRealTime_l(&mPositionTimeRealUs);
+ }
+
+ t1 = mPositionTimeRealUs;
+ /*
+ * empirical
+ * -----------
+ * This constant signifies how much data (in Us) has been rendered by the
+ * DSP in the interval between the moment flush is issued on AudioSink to
+ * after ioctl(PAUSE) returns in Audio HAL. (flush triggers an implicit
+ * pause in audio HAL)
+ *
+ */
+ const int64_t deltaUs = 60000LL; /* 60-70ms on msm8974 */
+ return (time_us > t1) && ((time_us - t1) <= deltaUs);
+}
+
+} //namespace android
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
old mode 100644
new mode 100755
index 216a329..517465d
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -32,6 +32,9 @@
#include <hardware/audio.h>
#include <media/stagefright/Utils.h>
#include <media/AudioParameter.h>
+#ifdef QCOM_HARDWARE
+#include <media/stagefright/ExtendedCodec.h>
+#endif
namespace android {
@@ -253,6 +256,9 @@
msg->setBuffer("csd-1", buffer);
}
+#ifdef QCOM_HARDWARE
+ ExtendedCodec::convertMetaDataToMessage(meta, &msg);
+#endif
*format = msg;
return OK;
diff --git a/media/libstagefright/WAVEWriter.cpp b/media/libstagefright/WAVEWriter.cpp
new file mode 100644
index 0000000..468765f
--- /dev/null
+++ b/media/libstagefright/WAVEWriter.cpp
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2012 - 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "WAVEWriter"
+#include <utils/Log.h>
+
+#include <media/stagefright/WAVEWriter.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/mediarecorder.h>
+#include <sys/prctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+namespace android {
+
+static struct wav_header hdr;
+
+
+WAVEWriter::WAVEWriter(const char *filename)
+ : mFd(-1),
+ mInitCheck(NO_INIT),
+ mStarted(false),
+ mPaused(false),
+ mResumed(false) {
+
+ mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
+ if (mFd >= 0) {
+ mInitCheck = OK;
+ }
+}
+
+WAVEWriter::WAVEWriter(int fd)
+ : mFd(dup(fd)),
+ mInitCheck(mFd < 0? NO_INIT: OK),
+ mStarted(false),
+ mPaused(false),
+ mResumed(false) {
+}
+
+WAVEWriter::~WAVEWriter() {
+ if (mStarted) {
+ stop();
+ }
+
+ if (mFd != -1) {
+ close(mFd);
+ mFd = -1;
+ }
+}
+
+status_t WAVEWriter::initCheck() const {
+ return mInitCheck;
+}
+
+status_t WAVEWriter::addSource(const sp<MediaSource> &source) {
+ uint32_t count;
+ if (mInitCheck != OK) {
+ ALOGE("Init Check not OK, return");
+ return mInitCheck;
+ }
+
+ if (mSource != NULL) {
+ ALOGE("A source already exists, return");
+ return UNKNOWN_ERROR;
+ }
+
+ sp<MetaData> meta = source->getFormat();
+
+ const char *mime;
+ CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+ int32_t channelCount;
+ int32_t sampleRate;
+ CHECK(meta->findInt32(kKeyChannelCount, &channelCount));
+ CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
+
+ memset(&hdr, 0, sizeof(struct wav_header));
+ hdr.riff_id = ID_RIFF;
+ hdr.riff_fmt = ID_WAVE;
+ hdr.fmt_id = ID_FMT;
+ hdr.fmt_sz = 16;
+ hdr.audio_format = FORMAT_PCM;
+ hdr.num_channels = channelCount;
+ hdr.sample_rate = sampleRate;
+ hdr.bits_per_sample = 16;
+ hdr.byte_rate = (sampleRate * channelCount * hdr.bits_per_sample) / 8;
+ hdr.block_align = ( hdr.bits_per_sample * channelCount ) / 8;
+ hdr.data_id = ID_DATA;
+ hdr.data_sz = 0;
+ hdr.riff_sz = hdr.data_sz + 44 - 8;
+
+ if (write(mFd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
+ ALOGE("Write header error, return ERROR_IO");
+ return -ERROR_IO;
+ }
+
+ mSource = source;
+
+ return OK;
+}
+
+status_t WAVEWriter::start(MetaData *params) {
+ if (mInitCheck != OK) {
+ ALOGE("Init Check not OK, return");
+ return mInitCheck;
+ }
+
+ if (mSource == NULL) {
+ ALOGE("NULL Source");
+ return UNKNOWN_ERROR;
+ }
+
+ if (mStarted && mPaused) {
+ mPaused = false;
+ mResumed = true;
+ return OK;
+ } else if (mStarted) {
+ ALOGE("Already startd, return");
+ return OK;
+ }
+
+ status_t err = mSource->start();
+
+ if (err != OK) {
+ return err;
+ }
+
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+ mReachedEOS = false;
+ mDone = false;
+
+ pthread_create(&mThread, &attr, ThreadWrapper, this);
+ pthread_attr_destroy(&attr);
+
+ mStarted = true;
+
+ return OK;
+}
+
+status_t WAVEWriter::pause() {
+ if (!mStarted) {
+ return OK;
+ }
+ mPaused = true;
+ return OK;
+}
+
+status_t WAVEWriter::stop() {
+ if (!mStarted) {
+ return OK;
+ }
+
+ mDone = true;
+
+ void *dummy;
+ pthread_join(mThread, &dummy);
+
+ status_t err = (status_t) dummy;
+ {
+ status_t status = mSource->stop();
+ if (err == OK &&
+ (status != OK && status != ERROR_END_OF_STREAM)) {
+ err = status;
+ }
+ }
+
+ mStarted = false;
+ return err;
+}
+
+bool WAVEWriter::exceedsFileSizeLimit() {
+ if (mMaxFileSizeLimitBytes == 0) {
+ return false;
+ }
+ return mEstimatedSizeBytes >= mMaxFileSizeLimitBytes;
+}
+
+bool WAVEWriter::exceedsFileDurationLimit() {
+ if (mMaxFileDurationLimitUs == 0) {
+ return false;
+ }
+ return mEstimatedDurationUs >= mMaxFileDurationLimitUs;
+}
+
+// static
+void *WAVEWriter::ThreadWrapper(void *me) {
+ return (void *) static_cast<WAVEWriter *>(me)->threadFunc();
+}
+
+status_t WAVEWriter::threadFunc() {
+ mEstimatedDurationUs = 0;
+ mEstimatedSizeBytes = 0;
+ bool stoppedPrematurely = true;
+ int64_t previousPausedDurationUs = 0;
+ int64_t maxTimestampUs = 0;
+ status_t err = OK;
+
+ prctl(PR_SET_NAME, (unsigned long)"WAVEWriter", 0, 0, 0);
+ hdr.data_sz = 0;
+ while (!mDone) {
+ MediaBuffer *buffer;
+ err = mSource->read(&buffer);
+
+ if (err != OK) {
+ break;
+ }
+
+ if (mPaused) {
+ buffer->release();
+ buffer = NULL;
+ continue;
+ }
+
+ mEstimatedSizeBytes += buffer->range_length();
+ if (exceedsFileSizeLimit()) {
+ buffer->release();
+ buffer = NULL;
+ notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
+ break;
+ }
+
+ int64_t timestampUs;
+ CHECK(buffer->meta_data()->findInt64(kKeyTime, ×tampUs));
+ if (timestampUs > mEstimatedDurationUs) {
+ mEstimatedDurationUs = timestampUs;
+ }
+ if (mResumed) {
+ previousPausedDurationUs += (timestampUs - maxTimestampUs - 20000);
+ mResumed = false;
+ }
+ timestampUs -= previousPausedDurationUs;
+ ALOGV("time stamp: %lld, previous paused duration: %lld",
+ timestampUs, previousPausedDurationUs);
+ if (timestampUs > maxTimestampUs) {
+ maxTimestampUs = timestampUs;
+ }
+
+ if (exceedsFileDurationLimit()) {
+ buffer->release();
+ buffer = NULL;
+ notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0);
+ break;
+ }
+ ssize_t n = write(mFd,
+ (const uint8_t *)buffer->data() + buffer->range_offset(),
+ buffer->range_length());
+
+ hdr.data_sz += (ssize_t)buffer->range_length();
+ hdr.riff_sz = hdr.data_sz + 44 - 8;
+
+ if (n < (ssize_t)buffer->range_length()) {
+ buffer->release();
+ buffer = NULL;
+
+ break;
+ }
+
+ if (stoppedPrematurely) {
+ stoppedPrematurely = false;
+ }
+
+ buffer->release();
+ buffer = NULL;
+ }
+
+ if (stoppedPrematurely) {
+ notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS, UNKNOWN_ERROR);
+ }
+
+ lseek(mFd, 0, SEEK_SET);
+ write(mFd, &hdr, sizeof(hdr));
+ lseek(mFd, 0, SEEK_END);
+
+ close(mFd);
+ mFd = -1;
+ mReachedEOS = true;
+ if (err == ERROR_END_OF_STREAM) {
+ return OK;
+ }
+ return err;
+}
+
+bool WAVEWriter::reachedEOS() {
+ return mReachedEOS;
+}
+
+} // namespace android
diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp
index b822868..1d843f3 100644
--- a/media/libstagefright/avc_utils.cpp
+++ b/media/libstagefright/avc_utils.cpp
@@ -44,7 +44,11 @@
void FindAVCDimensions(
const sp<ABuffer> &seqParamSet,
int32_t *width, int32_t *height,
+#ifdef QCOM_HARDWARE
+ int32_t *sarWidth, int32_t *sarHeight, int32_t *isInterlaced) {
+#else
int32_t *sarWidth, int32_t *sarHeight) {
+#endif
ABitReader br(seqParamSet->data() + 1, seqParamSet->size() - 1);
unsigned profile_idc = br.getBits(8);
@@ -63,7 +67,13 @@
parseUE(&br); // bit_depth_luma_minus8
parseUE(&br); // bit_depth_chroma_minus8
br.skipBits(1); // qpprime_y_zero_transform_bypass_flag
- CHECK_EQ(br.getBits(1), 0u); // seq_scaling_matrix_present_flag
+#ifdef QCOM_HARDWARE
+ bool seq_scaling_matrix_present = (br.getBits(1) != 0u);
+ if (isInterlaced != NULL && seq_scaling_matrix_present) {
+ return;
+ }
+ CHECK_EQ(seq_scaling_matrix_present, false); // seq_scaling_matrix_present_flag
+#endif
}
parseUE(&br); // log2_max_frame_num_minus4
@@ -133,6 +143,12 @@
(frame_crop_top_offset + frame_crop_bottom_offset) * cropUnitY;
}
+#ifdef QCOM_HARDWARE
+ if (isInterlaced != NULL) {
+ *isInterlaced = !frame_mbs_only_flag;
+ }
+#endif
+
if (sarWidth != NULL) {
*sarWidth = 0;
}
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
index 1b20cbb..2f7da48 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
@@ -362,9 +362,13 @@
inInfo->mOwnedByUs = false;
notifyEmptyBufferDone(inHeader);
- if (mDecoderHasData) {
+ if (mDecoderHasData || mInputBufferCount) {
// flush out the decoder's delayed data by calling DecodeFrame
// one more time, with the AACDEC_FLUSH flag set
+
+ // for the use case where the first frame in the buffer is EOS,
+ // decode the header to update the sample rate and channel mode
+ // and flush out the buffer.
INT_PCM *outBuffer =
reinterpret_cast<INT_PCM *>(
outHeader->pBuffer + outHeader->nOffset);
@@ -395,6 +399,9 @@
}
outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+ outHeader->nTimeStamp =
+ mAnchorTimeUs
+ + (mNumSamplesOutput * 1000000ll) / mStreamInfo->sampleRate;
outQueue.erase(outQueue.begin());
outInfo->mOwnedByUs = false;
diff --git a/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp b/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp
index 3320688..78d0b23 100644
--- a/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp
+++ b/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp
@@ -352,7 +352,14 @@
}
size_t frameSize = getFrameSize(mode);
- CHECK_GE(inHeader->nFilledLen, frameSize);
+ if (inHeader->nFilledLen < frameSize) {
+ ALOGE("Filled length vs frameSize %d vs %d. Corrupt clip?",
+ inHeader->nFilledLen, frameSize);
+
+ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+ mSignalledError = true;
+ return;
+ }
int16_t *outPtr = (int16_t *)outHeader->pBuffer;
@@ -429,6 +436,17 @@
}
void SoftAMR::onPortFlushCompleted(OMX_U32 portIndex) {
+ ALOGE("onPortFlushCompleted portindex %d, resetting frame ",portIndex);
+ if(portIndex == 0) {
+#ifdef QCOM_HARDWARE
+ if(mMode == MODE_NARROW)
+ Speech_Decode_Frame_reset(mState);
+ else
+ pvDecoder_AmrWb_Reset(mState, 0);
+#else
+ Speech_Decode_Frame_reset(mState);
+#endif
+ }
}
void SoftAMR::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
diff --git a/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp
index 50b739c..c6300a8 100644
--- a/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp
+++ b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp
@@ -71,7 +71,7 @@
def.eDir = OMX_DirInput;
def.nBufferCountMin = kNumBuffers;
def.nBufferCountActual = def.nBufferCountMin;
- def.nBufferSize = kNumSamplesPerFrame * sizeof(int16_t);
+ def.nBufferSize = kNumSamplesPerFrame * sizeof(int16_t) * 4;
def.bEnabled = OMX_TRUE;
def.bPopulated = OMX_FALSE;
def.eDomain = OMX_PortDomainAudio;
diff --git a/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp
index 9ccb49c..afd2b32 100644
--- a/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp
+++ b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp
@@ -78,7 +78,7 @@
def.eDir = OMX_DirInput;
def.nBufferCountMin = kNumBuffers;
def.nBufferCountActual = def.nBufferCountMin;
- def.nBufferSize = kNumSamplesPerFrame * sizeof(int16_t);
+ def.nBufferSize = kNumSamplesPerFrame * sizeof(int16_t) * 4;
def.bEnabled = OMX_TRUE;
def.bPopulated = OMX_FALSE;
def.eDomain = OMX_PortDomainAudio;
diff --git a/media/libstagefright/codecs/mp3dec/Android.mk b/media/libstagefright/codecs/mp3dec/Android.mk
index 135c715..c27a63d 100644
--- a/media/libstagefright/codecs/mp3dec/Android.mk
+++ b/media/libstagefright/codecs/mp3dec/Android.mk
@@ -42,6 +42,11 @@
src/pvmp3_dct_16.cpp
endif
+ifeq ($(BOARD_USES_QCOM_HARDWARE),true)
+LOCAL_SRC_FILES += \
+ MP3Decoder.cpp
+endif
+
LOCAL_C_INCLUDES := \
frameworks/av/media/libstagefright/include \
$(LOCAL_PATH)/src \
diff --git a/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp b/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp
new file mode 100644
index 0000000..c757589
--- /dev/null
+++ b/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp
@@ -0,0 +1,601 @@
+/*
+ * 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.
+ */
+
+#include "MP3Decoder.h"
+
+#include "include/pvmp3decoder_api.h"
+
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
+
+#include <cutils/log.h>
+
+#define LITERAL_TO_STRING_INTERNAL(x) #x
+#define LITERAL_TO_STRING(x) LITERAL_TO_STRING_INTERNAL(x)
+
+#define CHECK_EQ(x,y) \
+ LOG_ALWAYS_FATAL_IF( \
+ (x) != (y), \
+ __FILE__ ":" LITERAL_TO_STRING(__LINE__) " " #x " != " #y)
+
+#define CHECK(x) \
+ LOG_ALWAYS_FATAL_IF( \
+ !(x), \
+ __FILE__ ":" LITERAL_TO_STRING(__LINE__) " " #x)
+
+
+namespace android {
+
+// Everything must match except for
+// protection, bitrate, padding, private bits, mode extension,
+// copyright bit, original bit and emphasis.
+// Yes ... there are things that must indeed match...
+static const uint32_t kMask = 0xfffe0cc0;
+
+static bool get_mp3_frame_size(
+ uint32_t header, size_t *frame_size,
+ int *out_sampling_rate = NULL, int *out_channels = NULL,
+ int *out_bitrate = NULL) {
+ *frame_size = 0;
+
+ if (out_sampling_rate) {
+ *out_sampling_rate = 0;
+ }
+
+ if (out_channels) {
+ *out_channels = 0;
+ }
+
+ if (out_bitrate) {
+ *out_bitrate = 0;
+ }
+
+ if ((header & 0xffe00000) != 0xffe00000) {
+ return false;
+ }
+
+ unsigned version = (header >> 19) & 3;
+
+ if (version == 0x01) {
+ return false;
+ }
+
+ unsigned layer = (header >> 17) & 3;
+
+ if (layer == 0x00) {
+ return false;
+ }
+
+ unsigned protection = (header >> 16) & 1;
+
+ unsigned bitrate_index = (header >> 12) & 0x0f;
+
+ if (bitrate_index == 0 || bitrate_index == 0x0f) {
+ // Disallow "free" bitrate.
+ return false;
+ }
+
+ unsigned sampling_rate_index = (header >> 10) & 3;
+
+ if (sampling_rate_index == 3) {
+ return false;
+ }
+
+ static const int kSamplingRateV1[] = { 44100, 48000, 32000 };
+ int sampling_rate = kSamplingRateV1[sampling_rate_index];
+ if (version == 2 /* V2 */) {
+ sampling_rate /= 2;
+ } else if (version == 0 /* V2.5 */) {
+ sampling_rate /= 4;
+ }
+
+ unsigned padding = (header >> 9) & 1;
+
+ if (layer == 3) {
+ // layer I
+
+ static const int kBitrateV1[] = {
+ 32, 64, 96, 128, 160, 192, 224, 256,
+ 288, 320, 352, 384, 416, 448
+ };
+
+ static const int kBitrateV2[] = {
+ 32, 48, 56, 64, 80, 96, 112, 128,
+ 144, 160, 176, 192, 224, 256
+ };
+
+ int bitrate =
+ (version == 3 /* V1 */)
+ ? kBitrateV1[bitrate_index - 1]
+ : kBitrateV2[bitrate_index - 1];
+
+ if (out_bitrate) {
+ *out_bitrate = bitrate;
+ }
+
+ *frame_size = (12000 * bitrate / sampling_rate + padding) * 4;
+ } else {
+ // layer II or III
+
+ static const int kBitrateV1L2[] = {
+ 32, 48, 56, 64, 80, 96, 112, 128,
+ 160, 192, 224, 256, 320, 384
+ };
+
+ static const int kBitrateV1L3[] = {
+ 32, 40, 48, 56, 64, 80, 96, 112,
+ 128, 160, 192, 224, 256, 320
+ };
+
+ static const int kBitrateV2[] = {
+ 8, 16, 24, 32, 40, 48, 56, 64,
+ 80, 96, 112, 128, 144, 160
+ };
+
+ int bitrate;
+ if (version == 3 /* V1 */) {
+ bitrate = (layer == 2 /* L2 */)
+ ? kBitrateV1L2[bitrate_index - 1]
+ : kBitrateV1L3[bitrate_index - 1];
+ } else {
+ // V2 (or 2.5)
+
+ bitrate = kBitrateV2[bitrate_index - 1];
+ }
+
+ if (out_bitrate) {
+ *out_bitrate = bitrate;
+ }
+
+ if (version == 3 /* V1 */) {
+ *frame_size = 144000 * bitrate / sampling_rate + padding;
+ } else {
+ // V2 or V2.5
+ *frame_size = 72000 * bitrate / sampling_rate + padding;
+ }
+ }
+
+ if (out_sampling_rate) {
+ *out_sampling_rate = sampling_rate;
+ }
+
+ if (out_channels) {
+ int channel_mode = (header >> 6) & 3;
+
+ *out_channels = (channel_mode == 3) ? 1 : 2;
+ }
+
+ return true;
+}
+
+static bool resync(
+ uint8_t *data, uint32_t size, uint32_t match_header, off_t *out_pos) {
+
+ bool valid = false;
+ off_t pos = 0;
+ *out_pos = 0;
+ do {
+ if (pos + 4 > size) {
+ // Don't scan forever.
+ ALOGV("no dice, no valid sequence of frames found.");
+ break;
+ }
+
+ uint32_t header = U32_AT(data + pos);
+
+ if (match_header != 0 && (header & kMask) != (match_header & kMask)) {
+ ++pos;
+ continue;
+ }
+
+ ALOGV("found possible frame at %ld (header = 0x%08x)", pos, header);
+
+ // We found what looks like a valid frame,
+ valid = true;
+ *out_pos = pos;
+ } while (!valid);
+
+ return valid;
+}
+
+
+MP3Decoder::MP3Decoder(const sp<MediaSource> &source)
+ : mSource(source),
+ mNumChannels(0),
+ mStarted(false),
+ mBufferGroup(NULL),
+ mConfig(new tPVMP3DecoderExternal),
+ mDecoderBuf(NULL),
+ mAnchorTimeUs(0),
+ mNumFramesOutput(0),
+ mInputBuffer(NULL),
+ mPartialBuffer(NULL),
+ mFixedHeader(0) {
+ init();
+}
+
+void MP3Decoder::init() {
+ sp<MetaData> srcFormat = mSource->getFormat();
+
+ int32_t sampleRate;
+ CHECK(srcFormat->findInt32(kKeyChannelCount, &mNumChannels));
+ CHECK(srcFormat->findInt32(kKeySampleRate, &sampleRate));
+
+ mMeta = new MetaData;
+ mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
+ mMeta->setInt32(kKeyChannelCount, mNumChannels);
+ mMeta->setInt32(kKeySampleRate, sampleRate);
+
+ int64_t durationUs;
+ if (srcFormat->findInt64(kKeyDuration, &durationUs)) {
+ mMeta->setInt64(kKeyDuration, durationUs);
+ }
+
+ mMeta->setCString(kKeyDecoderComponent, "MP3Decoder");
+}
+
+MP3Decoder::~MP3Decoder() {
+ if (mStarted) {
+ stop();
+ }
+
+ delete mConfig;
+ mConfig = NULL;
+}
+
+status_t MP3Decoder::start(MetaData *params) {
+ CHECK(!mStarted);
+
+ mBufferGroup = new MediaBufferGroup;
+ mBufferGroup->add_buffer(new MediaBuffer(4608 * 2));
+
+ mConfig->equalizerType = flat;
+ mConfig->crcEnabled = false;
+
+ uint32_t memRequirements = pvmp3_decoderMemRequirements();
+ mDecoderBuf = malloc(memRequirements);
+
+ pvmp3_InitDecoder(mConfig, mDecoderBuf);
+
+ mSource->start();
+
+ mAnchorTimeUs = 0;
+ mNumFramesOutput = 0;
+ mStarted = true;
+
+ return OK;
+}
+
+status_t MP3Decoder::stop() {
+ CHECK(mStarted);
+
+ if (mInputBuffer) {
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+ }
+
+ free(mDecoderBuf);
+ mDecoderBuf = NULL;
+
+ delete mBufferGroup;
+ mBufferGroup = NULL;
+
+ mSource->stop();
+
+ mStarted = false;
+
+ return OK;
+}
+
+sp<MetaData> MP3Decoder::getFormat() {
+ return mMeta;
+}
+
+status_t MP3Decoder::updatePartialFrame() {
+ status_t err = OK;
+ if (mPartialBuffer == NULL) {
+ return err;
+ }
+
+ size_t frameSize = 0;
+ uint32_t partialBufLen = mPartialBuffer->range_length();
+ uint32_t inputBufLen = mInputBuffer->range_length();
+ uint8_t frameHeader[4];
+ uint8_t *frmHdr;
+ uint32_t header;
+
+
+ // Look at the frame size and complete the partial frame
+ // Also check if a vaild header is found after the partial frame
+ if (partialBufLen < 4) { // check if partial frame has the 4 bytes header
+ if (inputBufLen < (4 - partialBufLen)) {
+ // input buffer does not have the frame header bytes
+ // bail out TODO
+ ALOGE("MP3Decoder::updatePartialFrame buffer to small header not found"
+ " partial buffer len %d, input buffer len %d",
+ partialBufLen, inputBufLen);
+ //mPartialBuffer->release();
+ //mPartialBuffer = NULL;
+ return UNKNOWN_ERROR;
+ }
+
+ // copy the header bytes to frameHeader
+ memcpy (frameHeader, mPartialBuffer->data(), partialBufLen);
+ memcpy (frameHeader + partialBufLen, mInputBuffer->data(), (4 - partialBufLen));
+ // get the first 4 bytes of the buffer
+ header = U32_AT((uint8_t *)frameHeader);
+ frmHdr = frameHeader;
+ } else {
+ frmHdr = (uint8_t *)mPartialBuffer->data();
+ }
+
+ // check if its a good frame, and the frame size
+ // get the first 4 bytes of the buffer
+ header = U32_AT(frmHdr);
+ bool curFrame = get_mp3_frame_size(header,&frameSize);
+ if (!curFrame) {
+ ALOGE("MP3Decoder::read - partial frame does not have a vaild header 0x%x",
+ header);
+ return UNKNOWN_ERROR;
+ }
+
+ // check if the following frame is good
+ uint32_t nextFrameOffset = frameSize - partialBufLen;
+ if ((nextFrameOffset + 4) <= inputBufLen) {
+ header = U32_AT((uint8_t *)mInputBuffer->data() + nextFrameOffset);
+ if ((header & 0xffe00000) != 0xffe00000) {
+ // next frame does not have a valid header,
+ // this may not be the next buffer, bail out.
+ ALOGE("MP3Decoder::read - next frame does not have a vaild header 0x%x",
+ header);
+ return UNKNOWN_ERROR;
+ }
+ } else {
+ // next frame header is out of range
+ // assume good header for now
+ ALOGE("MP3Decoder::read - assuming next frame is good");
+ }
+
+ // check if the input buffer has the remaining partial frame
+ if (frameSize > (partialBufLen + inputBufLen)) {
+ // input buffer does not have the remaining partial frame,
+ // discard data here as frame split in 3 buffers not supported
+ ALOGE("MP3Decoder::updatePartialFrame - input buffer does not have the complete frame."
+ " frame size %d, saved partial buffer len %d,"
+ " input buffer len %d", frameSize, partialBufLen, inputBufLen);
+ return UNKNOWN_ERROR;
+ }
+
+ // check if the mPartialBuffer can fit the remaining frame
+ if ((mPartialBuffer->size() - partialBufLen) < (frameSize - partialBufLen)) {
+ // mPartialBuffer is small to hold the reaming frame
+ //TODO
+ ALOGE("MP3Decoder::updatePartialFrame - mPartialBuffer is small, size %d, required &d",
+ (mPartialBuffer->size() - partialBufLen), (frameSize - partialBufLen));
+ return UNKNOWN_ERROR;
+ }
+
+ // done with error checks
+ // copy the partial frames to from a complete frame
+ // Copy the remaining frame from input buffer
+ uint32_t bytesRemaining = frameSize - mPartialBuffer->range_length();
+ memcpy ((uint8_t *)mPartialBuffer->data() + mPartialBuffer->range_length(),
+ (uint8_t *)mInputBuffer->data() + mInputBuffer->range_offset(),
+ bytesRemaining);
+
+ // mark the bytes as consumed from input buffer
+ mInputBuffer->set_range(
+ mInputBuffer->range_offset() + bytesRemaining,
+ mInputBuffer->range_length() - bytesRemaining);
+
+ // set the range and length of mPartialBuffer
+ mPartialBuffer->set_range(0,
+ mPartialBuffer->range_length() + bytesRemaining);
+
+ ALOGE("MP3Decoder::updatePartialFrame - copied the partial frame %d, input buffer length %d",
+ bytesRemaining, mInputBuffer->range_length());
+
+ return err;
+}
+
+status_t MP3Decoder::read(
+ MediaBuffer **out, const ReadOptions *options) {
+ status_t err;
+
+ *out = NULL;
+ bool usedPartialFrame = false;
+ bool seekSource = false;
+
+ int64_t seekTimeUs;
+ ReadOptions::SeekMode mode;
+ if (options && options->getSeekTo(&seekTimeUs, &mode)) {
+ CHECK(seekTimeUs >= 0);
+
+ mNumFramesOutput = 0;
+ seekSource = true;
+
+ if (mInputBuffer) {
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+ }
+
+ if (mPartialBuffer) {
+ mPartialBuffer->release();
+ mPartialBuffer = NULL;
+ }
+
+ // Make sure that the next buffer output does not still
+ // depend on fragments from the last one decoded.
+ pvmp3_InitDecoder(mConfig, mDecoderBuf);
+ } else {
+ seekTimeUs = -1;
+ }
+
+ if (mInputBuffer == NULL) {
+ err = mSource->read(&mInputBuffer, options);
+
+ if (err != OK) {
+ return err;
+ }
+
+ if ((mFixedHeader == 0) && (mInputBuffer->range_length() > 4)) {
+ //save the first 4 bytes as fixed header for the reset of the file
+ mFixedHeader = U32_AT((uint8_t *)mInputBuffer->data());
+ }
+
+ if (seekSource == true) {
+ off_t syncOffset = 0;
+ bool valid = resync((uint8_t *)mInputBuffer->data() + mInputBuffer->range_offset()
+ ,mInputBuffer->range_length(), mFixedHeader, &syncOffset);
+ if (valid) {
+ // consume these bytes, we might find a frame header in next buffer
+ mInputBuffer->set_range(
+ mInputBuffer->range_offset() + syncOffset,
+ mInputBuffer->range_length() - syncOffset);
+ ALOGV("mp3 decoder found a sync point after seek syncOffset %d", syncOffset);
+ } else {
+ ALOGV("NO SYNC POINT found, buffer length %d",mInputBuffer->range_length());
+ }
+ }
+
+ int64_t timeUs;
+ if (mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
+ mAnchorTimeUs = timeUs;
+ mNumFramesOutput = 0;
+ } else {
+ // We must have a new timestamp after seeking.
+ CHECK(seekTimeUs < 0);
+ }
+ // check for partial frame
+ if (mPartialBuffer != NULL) {
+ err = updatePartialFrame();
+ if (err != OK) {
+ // updating partial frame failed, discard the previously
+ // saved partial frame and continue
+ mPartialBuffer->release();
+ mPartialBuffer = NULL;
+ err = OK;
+ }
+ }
+ }
+
+ MediaBuffer *buffer;
+ CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK);
+
+ if (mPartialBuffer != NULL) {
+ mConfig->pInputBuffer =
+ (uint8_t *)mPartialBuffer->data() + mPartialBuffer->range_offset();
+ mConfig->inputBufferCurrentLength = mPartialBuffer->range_length();
+ usedPartialFrame = true;
+ } else {
+ mConfig->pInputBuffer =
+ (uint8_t *)mInputBuffer->data() + mInputBuffer->range_offset();
+ mConfig->inputBufferCurrentLength = mInputBuffer->range_length();
+ }
+
+ mConfig->inputBufferMaxLength = 0;
+ mConfig->inputBufferUsedLength = 0;
+
+ mConfig->outputFrameSize = buffer->size() / sizeof(int16_t);
+ mConfig->pOutputBuffer = static_cast<int16_t *>(buffer->data());
+
+ ERROR_CODE decoderErr;
+ if ((decoderErr = pvmp3_framedecoder(mConfig, mDecoderBuf))
+ != NO_DECODING_ERROR) {
+ ALOGV("mp3 decoder returned error %d", decoderErr);
+
+ if ((decoderErr != NO_ENOUGH_MAIN_DATA_ERROR) &&
+ (decoderErr != SYNCH_LOST_ERROR)) {
+ buffer->release();
+ buffer = NULL;
+
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+ if (mPartialBuffer) {
+ mPartialBuffer->release();
+ mPartialBuffer = NULL;
+ }
+ ALOGE("mp3 decoder returned UNKNOWN_ERROR");
+
+ return UNKNOWN_ERROR;
+ }
+
+ if ((mPartialBuffer == NULL) && (decoderErr == NO_ENOUGH_MAIN_DATA_ERROR)) {
+ // Might be a partial frame, save it
+ mPartialBuffer = new MediaBuffer(mInputBuffer->size());
+ memcpy ((uint8_t *)mPartialBuffer->data(),
+ mConfig->pInputBuffer, mConfig->inputBufferCurrentLength);
+ mPartialBuffer->set_range(0, mConfig->inputBufferCurrentLength);
+ // set output buffer to 0
+ mConfig->outputFrameSize = 0;
+ // consume the copied bytes from input
+ mConfig->inputBufferUsedLength = mConfig->inputBufferCurrentLength;
+ } else if(decoderErr == SYNCH_LOST_ERROR) {
+ // Try to find the mp3 frame header in the current buffer
+ off_t syncOffset = 0;
+ bool valid = resync(mConfig->pInputBuffer, mConfig->inputBufferCurrentLength,
+ mFixedHeader, &syncOffset);
+ if (!valid || !syncOffset) {
+ // consume these bytes, we might find a frame header in next buffer
+ syncOffset = mConfig->inputBufferCurrentLength;
+ }
+ // set output buffer to 0
+ mConfig->outputFrameSize = 0;
+ // consume the junk bytes from input buffer
+ mConfig->inputBufferUsedLength = syncOffset;
+ } else {
+ // This is recoverable, just ignore the current frame and
+ // play silence instead.
+ memset(buffer->data(), 0, mConfig->outputFrameSize * sizeof(int16_t));
+ mConfig->inputBufferUsedLength = mInputBuffer->range_length();
+ }
+ }
+
+ buffer->set_range(
+ 0, mConfig->outputFrameSize * sizeof(int16_t));
+
+ if ((mPartialBuffer != NULL) && usedPartialFrame) {
+ mPartialBuffer->set_range(
+ mPartialBuffer->range_offset() + mConfig->inputBufferUsedLength,
+ mPartialBuffer->range_length() - mConfig->inputBufferUsedLength);
+ mPartialBuffer->release();
+ mPartialBuffer = NULL;
+ } else {
+ mInputBuffer->set_range(
+ mInputBuffer->range_offset() + mConfig->inputBufferUsedLength,
+ mInputBuffer->range_length() - mConfig->inputBufferUsedLength);
+ }
+
+ if (mInputBuffer->range_length() == 0) {
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+ }
+
+ buffer->meta_data()->setInt64(
+ kKeyTime,
+ mAnchorTimeUs
+ + (mNumFramesOutput * 1000000) / mConfig->samplingRate);
+
+ mNumFramesOutput += mConfig->outputFrameSize / mNumChannels;
+
+ *out = buffer;
+
+ return OK;
+}
+
+} // namespace android
diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
index 7c382fb..be42ae5 100644
--- a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
+++ b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
@@ -110,7 +110,7 @@
void SoftMP3::initDecoder() {
mConfig->equalizerType = flat;
mConfig->crcEnabled = false;
-
+ mConfig->samplingRate = mSamplingRate;
uint32_t memRequirements = pvmp3_decoderMemRequirements();
mDecoderBuf = malloc(memRequirements);
@@ -252,10 +252,13 @@
if (decoderErr != NO_ENOUGH_MAIN_DATA_ERROR
&& decoderErr != SIDE_INFO_ERROR) {
ALOGE("mp3 decoder returned error %d", decoderErr);
-
- notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
- mSignalledError = true;
- return;
+ if(decoderErr == SYNCH_LOST_ERROR) {
+ mConfig->outputFrameSize = kOutputBufferSize / sizeof(int16_t);
+ } else {
+ notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
+ mSignalledError = true;
+ return;
+ }
}
if (mConfig->outputFrameSize == 0) {
diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
index 77f21b7..d74a5f4 100644
--- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp
+++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
@@ -94,11 +94,20 @@
CHECK(mCropHeight > 0);
CHECK(mConverter == NULL || mConverter->isValid());
+#ifdef EXYNOS4_ENHANCEMENTS
+ CHECK_EQ(0,
+ native_window_set_usage(
+ mNativeWindow.get(),
+ GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_OFTEN
+ | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP
+ | GRALLOC_USAGE_HW_FIMC1 | GRALLOC_USAGE_HWC_HWOVERLAY));
+#else
CHECK_EQ(0,
native_window_set_usage(
mNativeWindow.get(),
GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_OFTEN
| GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP));
+#endif
CHECK_EQ(0,
native_window_set_scaling_mode(
@@ -200,13 +209,25 @@
const uint8_t *src_uv =
(const uint8_t *)data + mWidth * (mHeight - mCropTop / 2);
- uint8_t *dst_y = (uint8_t *)dst;
+#ifdef EXYNOS4_ENHANCEMENTS
+ void *pYUVBuf[3];
+ CHECK_EQ(0, mapper.unlock(buf->handle));
+ CHECK_EQ(0, mapper.lock(
+ buf->handle, GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_YUV_ADDR, bounds, pYUVBuf));
+
+ size_t dst_c_stride = buf->stride / 2;
+ uint8_t *dst_y = (uint8_t *)pYUVBuf[0];
+ uint8_t *dst_v = (uint8_t *)pYUVBuf[1];
+ uint8_t *dst_u = (uint8_t *)pYUVBuf[2];
+#else
size_t dst_y_size = buf->stride * buf->height;
size_t dst_c_stride = ALIGN(buf->stride / 2, 16);
size_t dst_c_size = dst_c_stride * buf->height / 2;
+ uint8_t *dst_y = (uint8_t *)dst;
uint8_t *dst_v = dst_y + dst_y_size;
uint8_t *dst_u = dst_v + dst_c_size;
+#endif
for (int y = 0; y < mCropHeight; ++y) {
memcpy(dst_y, src_y, mCropWidth);
diff --git a/media/libstagefright/id3/Android.mk b/media/libstagefright/id3/Android.mk
index bf6f7bb..7f0cb6c 100644
--- a/media/libstagefright/id3/Android.mk
+++ b/media/libstagefright/id3/Android.mk
@@ -4,6 +4,10 @@
LOCAL_SRC_FILES := \
ID3.cpp
+ifneq ($(TI_CUSTOM_DOMX_PATH),)
+LOCAL_C_INCLUDES += $(TI_CUSTOM_DOMX_PATH)/omx_core/inc
+endif
+
LOCAL_MODULE := libstagefright_id3
include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 271df8e..61dba35 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -1,4 +1,6 @@
/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -102,6 +104,7 @@
void postAudioEOS(int64_t delayUs = 0ll);
void postAudioSeekComplete();
void postAudioTearDown();
+ void printFileName(int fd);
status_t dump(int fd, const Vector<String16> &args) const;
private:
@@ -204,6 +207,9 @@
bool mWatchForAudioSeekComplete;
bool mWatchForAudioEOS;
+#ifdef QCOM_ENHANCED_AUDIO
+ static int mTunnelAliveAP;
+#endif
sp<TimedEventQueue::Event> mVideoEvent;
bool mVideoEventPending;
@@ -241,6 +247,7 @@
sp<DecryptHandle> mDecryptHandle;
int64_t mLastVideoTimeUs;
+ int64_t mFrameDurationUs;
TimedTextDriver *mTextDriver;
sp<WVMExtractor> mWVMExtractor;
@@ -313,6 +320,17 @@
ASSIGN
};
void modifyFlags(unsigned value, FlagMode mode);
+#ifdef QCOM_ENHANCED_AUDIO
+ void checkTunnelExceptions();
+#endif
+ void logFirstFrame();
+ void logCatchUp(int64_t ts, int64_t clock, int64_t delta);
+ void logLate(int64_t ts, int64_t clock, int64_t delta);
+ void logOnTime(int64_t ts, int64_t clock, int64_t delta);
+ void printStats();
+ int64_t getTimeOfDayUs();
+ bool mStatistics;
+ int64_t mLateAVSyncMargin;
struct TrackStat {
String8 mMIME;
@@ -338,6 +356,23 @@
int32_t mVideoHeight;
uint32_t mFlags;
Vector<TrackStat> mTracks;
+
+ int64_t mConsecutiveFramesDropped;
+ uint32_t mCatchupTimeStart;
+ uint32_t mNumTimesSyncLoss;
+ uint32_t mMaxEarlyDelta;
+ uint32_t mMaxLateDelta;
+ uint32_t mMaxTimeSyncLoss;
+ uint64_t mTotalFrames;
+ int64_t mFirstFrameLatencyStartUs; //first frame latency start
+ int64_t mFirstFrameLatencyUs;
+ int64_t mLastFrameUs;
+ bool mVeryFirstFrame;
+ int64_t mTotalTimeUs;
+ int64_t mLastPausedTimeMs;
+ int64_t mLastSeekToTimeMs;
+ int64_t mResumeDelayStartUs;
+ int64_t mSeekDelayStartUs;
} mStats;
bool mOffloadAudio;
@@ -357,6 +392,11 @@
size_t countTracks() const;
+#ifdef QCOM_ENHANCED_AUDIO
+ bool inSupportedTunnelFormats(const char * mime);
+ //Flag to check if tunnel mode audio is enabled
+ bool mIsTunnelAudio;
+#endif
AwesomePlayer(const AwesomePlayer &);
AwesomePlayer &operator=(const AwesomePlayer &);
};
diff --git a/media/libstagefright/include/ExtendedExtractor.h b/media/libstagefright/include/ExtendedExtractor.h
new file mode 100644
index 0000000..3bce1ff
--- /dev/null
+++ b/media/libstagefright/include/ExtendedExtractor.h
@@ -0,0 +1,49 @@
+/*Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef EXTENDED_EXTRACTOR_
+#define EXTENDED_EXTRACTOR_
+
+#include <media/stagefright/DataSource.h>
+
+namespace android {
+
+class MediaExtractor;
+class ExtendedExtractor
+{
+public:
+ static MediaExtractor* Create (
+ const sp<DataSource> &source, const char *mime);
+ static bool Sniff (
+ const sp<DataSource> &source, String8 *mimeType,
+ float *confidence,sp<AMessage> *meta);
+};
+
+} // namespace android
+
+#endif //EXTENDED_EXTRACTOR_
diff --git a/media/libstagefright/include/ExtendedUtils.h b/media/libstagefright/include/ExtendedUtils.h
new file mode 100644
index 0000000..1c3f3aa
--- /dev/null
+++ b/media/libstagefright/include/ExtendedUtils.h
@@ -0,0 +1,151 @@
+/*Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef QC_UTILS_H_
+#define QC_UTILS_H_
+
+#include <utils/StrongPointer.h>
+#include <media/Metadata.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/MediaCodecList.h>
+
+#include <media/MediaRecorderBase.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <camera/CameraParameters.h>
+#include <OMX_Video.h>
+#include <android/native_window.h>
+
+#define MIN_BITERATE_AAC 24000
+#define MAX_BITERATE_AAC 192000
+
+namespace android {
+
+/*
+ * This class is a placeholder for utility methods for
+ * QC specific changes
+ */
+struct ExtendedUtils {
+
+ /*
+ * This class is a placeholder for set of methods used
+ * to enable HFR (High Frame Rate) Recording
+ *
+ * HFR is a slow-motion recording feature where framerate
+ * is increased at capture, but file is composed to play
+ * back at normal rate, giving a net result of slow-motion.
+ * If HFR factor = N
+ * framerate (at capture and encoder) = N * actual value
+ * timeStamps (at composition) = N * actual value
+ * bitrate = N * actual value
+ * (as the encoder still gets actual timestamps)
+ */
+ struct HFR {
+ // set kKeyHFR when 'video-hfr' paramater is enabled
+ static void setHFRIfEnabled(
+ const CameraParameters& params, sp<MetaData> &meta);
+
+ // recalculate fileduration when hfr is enabled
+ static status_t reCalculateFileDuration(
+ sp<MetaData> &meta, sp<MetaData> &enc_meta,
+ int64_t &maxFileDurationUs, int32_t frameRate,
+ video_encoder videoEncoder);
+
+ // compute timestamp when hfr is enabled
+ static void reCalculateTimeStamp(
+ sp<MetaData> &meta, int64_t ×tampUs);
+
+ // recalculate frameRate and bitrate when hfr is enabled
+ static void reCalculateHFRParams(
+ const sp<MetaData> &meta, int32_t &frameRate,
+ int32_t &bitrate);
+
+ // Copy HFR params (bitrate,framerate) from output to
+ // to input format, if HFR is enabled
+ static void copyHFRParams(
+ const sp<MetaData> &inputFormat,
+ sp<MetaData> &outputFormat);
+ };
+
+ /*
+ * This class is a placeholder for methods to override
+ * default heaviour based on shell properties set
+ */
+ struct ShellProp {
+ // check if shell property to disable audio is set
+ static bool isAudioDisabled();
+
+ //helper function to set encoding profiles
+ static void setEncoderProfile(video_encoder &videoEncoder,
+ int32_t &videoEncoderProfile);
+
+ static bool isSmoothStreamingEnabled();
+
+ static int64_t getMaxAVSyncLateMargin();
+ };
+
+ //set B frames for MPEG4
+ static void setBFrames(OMX_VIDEO_PARAM_MPEG4TYPE &mpeg4type, int32_t &numBFrames,
+ const char* componentName);
+
+ //set B frames for H264
+ static void setBFrames(OMX_VIDEO_PARAM_AVCTYPE &h264type, int32_t &numBFrames,
+ int32_t iFramesInterval, int32_t frameRate, const char* componentName);
+
+ static bool UseQCHWAACEncoder(audio_encoder Encoder, int32_t Channel,
+ int32_t BitRate, int32_t SampleRate);
+
+ static sp<MediaExtractor> MediaExtractor_CreateIfNeeded(
+ sp<MediaExtractor> defaultExt, const sp<DataSource> &source,
+ const char *mime);
+
+ //helper function to add media codecs with specific quirks
+ static void helper_addMediaCodec(Vector<MediaCodecList::CodecInfo> &mCodecInfos,
+ KeyedVector<AString, size_t> &mTypes,
+ bool encoder, const char *name,
+ const char *type, uint32_t quirks);
+
+ //helper function to calculate the value of quirks from strings
+ static uint32_t helper_getCodecSpecificQuirks(KeyedVector<AString, size_t> &mCodecQuirks,
+ Vector<AString> quirks);
+
+ static bool isAVCProfileSupported(int32_t profile);
+
+ //notify stride change to ANW
+ static void updateNativeWindowBufferGeometry(ANativeWindow* anw,
+ OMX_U32 width, OMX_U32 height, OMX_COLOR_FORMATTYPE colorFormat);
+
+ static bool checkIsThumbNailMode(const uint32_t flags, char* componentName);
+
+ static void setArbitraryModeIfInterlaced(
+ const uint8_t *ptr, const sp<MetaData> &meta);
+
+ static int32_t checkIsInterlace(sp<MetaData> &meta);
+};
+
+}
+#endif //QC_UTILS_H_
diff --git a/media/libstagefright/include/MP3Decoder.h b/media/libstagefright/include/MP3Decoder.h
new file mode 100644
index 0000000..8ff570a
--- /dev/null
+++ b/media/libstagefright/include/MP3Decoder.h
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+#ifndef MP3_DECODER_H_
+
+#define MP3_DECODER_H_
+
+#include <media/stagefright/MediaSource.h>
+
+struct tPVMP3DecoderExternal;
+
+namespace android {
+
+struct MediaBufferGroup;
+
+struct MP3Decoder : public MediaSource {
+ MP3Decoder(const sp<MediaSource> &source);
+
+ virtual status_t start(MetaData *params);
+ virtual status_t stop();
+
+ virtual sp<MetaData> getFormat();
+
+ virtual status_t read(
+ MediaBuffer **buffer, const ReadOptions *options);
+
+protected:
+ virtual ~MP3Decoder();
+
+private:
+ sp<MediaSource> mSource;
+ sp<MetaData> mMeta;
+ int32_t mNumChannels;
+
+ bool mStarted;
+
+ MediaBufferGroup *mBufferGroup;
+
+ tPVMP3DecoderExternal *mConfig;
+ void *mDecoderBuf;
+ int64_t mAnchorTimeUs;
+ int64_t mNumFramesOutput;
+ uint32_t mFixedHeader;
+
+ MediaBuffer *mInputBuffer;
+ MediaBuffer *mPartialBuffer;
+
+ void init();
+
+ MP3Decoder(const MP3Decoder &);
+ MP3Decoder &operator=(const MP3Decoder &);
+ status_t updatePartialFrame();
+};
+
+} // namespace android
+
+#endif // MP3_DECODER_H_
diff --git a/media/libstagefright/include/SampleIterator.h b/media/libstagefright/include/SampleIterator.h
index b5a043c..47ea5bf 100644
--- a/media/libstagefright/include/SampleIterator.h
+++ b/media/libstagefright/include/SampleIterator.h
@@ -29,7 +29,7 @@
uint32_t getDescIndex() const { return mChunkDesc; }
off64_t getSampleOffset() const { return mCurrentSampleOffset; }
size_t getSampleSize() const { return mCurrentSampleSize; }
- uint32_t getSampleTime() const { return mCurrentSampleTime; }
+ uint64_t getSampleTime() const { return mCurrentSampleTime; }
status_t getSampleSizeDirect(
uint32_t sampleIndex, size_t *size);
@@ -53,19 +53,19 @@
uint32_t mTimeToSampleIndex;
uint32_t mTTSSampleIndex;
- uint32_t mTTSSampleTime;
+ uint64_t mTTSSampleTime;
uint32_t mTTSCount;
uint32_t mTTSDuration;
uint32_t mCurrentSampleIndex;
off64_t mCurrentSampleOffset;
size_t mCurrentSampleSize;
- uint32_t mCurrentSampleTime;
+ uint64_t mCurrentSampleTime;
void reset();
status_t findChunkRange(uint32_t sampleIndex);
status_t getChunkOffset(uint32_t chunk, off64_t *offset);
- status_t findSampleTime(uint32_t sampleIndex, uint32_t *time);
+ status_t findSampleTime(uint32_t sampleIndex, uint64_t *time);
SampleIterator(const SampleIterator &);
SampleIterator &operator=(const SampleIterator &);
diff --git a/media/libstagefright/include/SampleTable.h b/media/libstagefright/include/SampleTable.h
index 847dff7..d05e7c7 100644
--- a/media/libstagefright/include/SampleTable.h
+++ b/media/libstagefright/include/SampleTable.h
@@ -65,7 +65,7 @@
uint32_t sampleIndex,
off64_t *offset,
size_t *size,
- uint32_t *compositionTime,
+ uint64_t *compositionTime,
bool *isSyncSample = NULL);
enum {
@@ -74,7 +74,7 @@
kFlagClosest
};
status_t findSampleAtTime(
- uint32_t req_time, uint32_t *sample_index, uint32_t flags);
+ uint64_t req_time, uint32_t *sample_index, uint32_t flags);
status_t findSyncSampleNear(
uint32_t start_sample_index, uint32_t *sample_index,
@@ -113,7 +113,7 @@
struct SampleTimeEntry {
uint32_t mSampleIndex;
- uint32_t mCompositionTime;
+ uint64_t mCompositionTime;
};
SampleTimeEntry *mSampleTimeEntries;
diff --git a/media/libstagefright/include/avc_utils.h b/media/libstagefright/include/avc_utils.h
index d517320..205e8ae 100644
--- a/media/libstagefright/include/avc_utils.h
+++ b/media/libstagefright/include/avc_utils.h
@@ -40,8 +40,11 @@
void FindAVCDimensions(
const sp<ABuffer> &seqParamSet,
int32_t *width, int32_t *height,
+#ifdef QCOM_HARDWARE
+ int32_t *sarWidth = NULL, int32_t *sarHeight = NULL, int32_t *isInterlaced = NULL);
+#else
int32_t *sarWidth = NULL, int32_t *sarHeight = NULL);
-
+#endif
unsigned parseUE(ABitReader *br);
status_t getNextNALUnit(
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index 8f9c9c8..0679a1a 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -504,7 +504,9 @@
if (first) {
timeUs = info->mTimestampUs;
- first = false;
+ if(mMode != AAC) {
+ first = false;
+ }
}
if (info->mLength > size) {
diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
index cd912e7..724325f 100644
--- a/media/libstagefright/omx/Android.mk
+++ b/media/libstagefright/omx/Android.mk
@@ -27,6 +27,10 @@
libstagefright_foundation \
libdl
+ifeq ($(BOARD_USES_PROPRIETARY_OMX),SAMSUNG)
+LOCAL_CFLAGS += -DSAMSUNG_OMX
+endif
+
LOCAL_MODULE:= libstagefright_omx
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/omx/OMXMaster.cpp b/media/libstagefright/omx/OMXMaster.cpp
index 6b6d0ab..c544770 100644
--- a/media/libstagefright/omx/OMXMaster.cpp
+++ b/media/libstagefright/omx/OMXMaster.cpp
@@ -45,6 +45,9 @@
void OMXMaster::addVendorPlugin() {
addPlugin("libstagefrighthw.so");
+#ifdef SAMSUNG_OMX
+ addPlugin("libsomxcore.so");
+#endif
}
void OMXMaster::addPlugin(const char *libname) {
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 6c5c857..35fd568 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -764,15 +764,20 @@
OMX_U32 portIndex, OMX::buffer_id buffer) {
Mutex::Autolock autoLock(mLock);
- removeActiveBuffer(portIndex, buffer);
-
OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate);
OMX_ERRORTYPE err = OMX_FreeBuffer(mHandle, portIndex, header);
- delete buffer_meta;
- buffer_meta = NULL;
+ if (err != OMX_ErrorNone) {
+ ALOGW("OMX_FreeBuffer failed w/ err %x, do not remove from active buffer list", err);
+ } else {
+ ALOGI("OMX_FreeBuffer for buffer header %p successful", header);
+ removeActiveBuffer(portIndex, buffer);
+
+ delete buffer_meta;
+ buffer_meta = NULL;
+ }
return StatusFromOMXError(err);
}
diff --git a/media/libstagefright/timedtext/Android.mk b/media/libstagefright/timedtext/Android.mk
index f099bbd..4c6172a 100644
--- a/media/libstagefright/timedtext/Android.mk
+++ b/media/libstagefright/timedtext/Android.mk
@@ -14,6 +14,10 @@
$(TOP)/frameworks/av/include/media/stagefright/timedtext \
$(TOP)/frameworks/av/media/libstagefright
+ifneq ($(TI_CUSTOM_DOMX_PATH),)
+LOCAL_C_INCLUDES += $(TI_CUSTOM_DOMX_PATH)/omx_core/inc
+endif
+
LOCAL_MODULE:= libstagefright_timedtext
include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libstagefright/wifi-display/Android.mk b/media/libstagefright/wifi-display/Android.mk
index f70454a..7b828fa 100644
--- a/media/libstagefright/wifi-display/Android.mk
+++ b/media/libstagefright/wifi-display/Android.mk
@@ -16,9 +16,14 @@
LOCAL_C_INCLUDES:= \
$(TOP)/frameworks/av/media/libstagefright \
- $(TOP)/frameworks/native/include/media/openmax \
$(TOP)/frameworks/av/media/libstagefright/mpeg2ts \
+ifneq ($(TI_CUSTOM_DOMX_PATH),)
+LOCAL_C_INCLUDES += $(TI_CUSTOM_DOMX_PATH)/omx_core/inc
+else
+LOCAL_C_INCLUDES += $(TOP)/frameworks/native/include/media/openmax
+endif
+
LOCAL_SHARED_LIBRARIES:= \
libbinder \
libcutils \
diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
index 05e4018..0057d97 100644
--- a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
+++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
@@ -931,7 +931,11 @@
}
mUsingHDCP = false;
- if (!params->findParameter("wfd_content_protection", &value)) {
+ char val[PROPERTY_VALUE_MAX];
+ if (property_get("persist.sys.wfd.nohdcp", val, NULL)
+ && !strcmp("1", val)) {
+ ALOGI("Content protection has been disabled for WFD sinks");
+ } else if (!params->findParameter("wfd_content_protection", &value)) {
ALOGI("Sink doesn't appear to support content protection.");
} else if (value == "none") {
ALOGI("Sink does not support content protection.");
diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
index 1ac647a..5f84723 100644
--- a/media/mediaserver/Android.mk
+++ b/media/mediaserver/Android.mk
@@ -28,6 +28,11 @@
LOCAL_STATIC_LIBRARIES := \
libregistermsext
+ifeq ($(BOARD_USE_SECTVOUT),true)
+ LOCAL_CFLAGS += -DSECTVOUT
+ LOCAL_SHARED_LIBRARIES += libTVOut
+endif
+
LOCAL_C_INCLUDES := \
frameworks/av/media/libmediaplayerservice \
frameworks/av/services/medialog \
diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp
index d5207d5..efe6e85 100644
--- a/media/mediaserver/main_mediaserver.cpp
+++ b/media/mediaserver/main_mediaserver.cpp
@@ -37,6 +37,12 @@
using namespace android;
+#ifdef SECTVOUT
+namespace android { namespace SecTVOutService {
+void instantiate(void);
+} }
+#endif
+
int main(int argc, char** argv)
{
signal(SIGPIPE, SIG_IGN);
@@ -124,6 +130,9 @@
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
ALOGI("ServiceManager: %p", sm.get());
+#ifdef SECTVOUT
+ SecTVOutService::instantiate();
+#endif
AudioFlinger::instantiate();
MediaPlayerService::instantiate();
CameraService::instantiate();
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 54377f1..cba7af0 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -46,6 +46,14 @@
libdl \
libpowermanager
+# SRS Processing
+ifeq ($(strip $(BOARD_USES_SRS_TRUEMEDIA)),true)
+LOCAL_SHARED_LIBRARIES += libsrsprocessing
+LOCAL_CFLAGS += -DSRS_PROCESSING
+LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/audio-effects
+endif
+# SRS Processing
+
LOCAL_STATIC_LIBRARIES := \
libscheduling_policy \
libcpustats \
@@ -64,6 +72,10 @@
LOCAL_CFLAGS += -DANDROID_SMP=0
endif
+ifeq ($(BOARD_HAVE_PRE_KITKAT_AUDIO_BLOB),true)
+ LOCAL_CFLAGS += -DHAVE_PRE_KITKAT_AUDIO_BLOB
+endif
+
LOCAL_CFLAGS += -fvisibility=hidden
include $(BUILD_SHARED_LIBRARY)
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index acbd19a..f10c8e0 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1,5 +1,6 @@
/*
-**
+** Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+** Not a Contribution.
** Copyright 2007, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
@@ -63,6 +64,11 @@
#include <media/AudioParameter.h>
#include <private/android_filesystem_config.h>
+#ifdef SRS_PROCESSING
+#include "srs_processing.h"
+#include "postpro_patch_ics.h"
+#endif
+
// ----------------------------------------------------------------------------
// Note: the following macro is used for extremely verbose logging message. In
@@ -121,11 +127,13 @@
if (rc) {
goto out;
}
+#if !defined(ICS_AUDIO_BLOB) && !defined(MR0_AUDIO_BLOB)
if ((*dev)->common.version != AUDIO_DEVICE_API_VERSION_CURRENT) {
ALOGE("%s wrong audio hw device version %04x", __func__, (*dev)->common.version);
rc = BAD_VALUE;
goto out;
}
+#endif
return 0;
out:
@@ -146,7 +154,12 @@
mBtNrecIsOff(false),
mIsLowRamDevice(true),
mIsDeviceTypeKnown(false),
+#ifdef QCOM_HARDWARE
+ mGlobalEffectEnableTime(0),
+ mAllChainsLocked(false)
+#else
mGlobalEffectEnableTime(0)
+#endif
{
getpid_cached = getpid();
char value[PROPERTY_VALUE_MAX];
@@ -178,6 +191,11 @@
Mutex::Autolock _l(mLock);
/* TODO: move all this work into an Init() function */
+#ifdef QCOM_HARDWARE
+ mLPASessionId = -2; // -2 is invalid session ID
+ mIsEffectConfigChanged = false;
+ mLPAEffectChain = NULL;
+#endif
char val_str[PROPERTY_VALUE_MAX] = { 0 };
if (property_get("ro.audio.flinger_standbytime_ms", val_str, NULL) >= 0) {
uint32_t int_val;
@@ -237,6 +255,13 @@
if ((dev->get_supported_devices != NULL) &&
(dev->get_supported_devices(dev) & devices) == devices)
return audioHwDevice;
+#ifdef ICS_AUDIO_BLOB
+ else if (dev->get_supported_devices == NULL && i != 0 &&
+ devices == 0x80)
+ // Reasonably safe assumption: A non-primary HAL without
+ // get_supported_devices is a locally-built A2DP binary
+ return audioHwDevice;
+#endif
}
} else {
// check a match for the requested module handle
@@ -558,9 +583,126 @@
return trackHandle;
}
+#ifdef QCOM_HARDWARE
+sp<IDirectTrack> AudioFlinger::createDirectTrack(
+ pid_t pid,
+ uint32_t sampleRate,
+ audio_channel_mask_t channelMask,
+ audio_io_handle_t output,
+ int *sessionId,
+ IDirectTrackClient *client,
+ audio_stream_type_t streamType,
+ status_t *status)
+{
+ *status = NO_ERROR;
+ status_t lStatus = NO_ERROR;
+ sp<IDirectTrack> track = NULL;
+ DirectAudioTrack* directTrack = NULL;
+ Mutex::Autolock _l(mLock);
+
+ ALOGV("createDirectTrack() sessionId: %d sampleRate %d channelMask %d",
+ *sessionId, sampleRate, channelMask);
+ AudioSessionDescriptor *desc = mDirectAudioTracks.valueFor(output);
+ if(desc == NULL) {
+ ALOGE("Error: Invalid output (%d) to create direct audio track", output);
+ lStatus = BAD_VALUE;
+ goto Exit;
+ }
+ desc->mStreamType = streamType;
+ if (desc->flag & AUDIO_OUTPUT_FLAG_LPA) {
+ if (sessionId != NULL && *sessionId != AUDIO_SESSION_OUTPUT_MIX) {
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+ sp<PlaybackThread> t = mPlaybackThreads.valueAt(i);
+ // Check if the session ID is already associated with a track
+ uint32_t sessions = t->hasAudioSession(*sessionId);
+
+ // check if an effect with same session ID is waiting for a ssession to be created
+ ALOGV("check if an effect with same session ID is waiting for a ssession to be created");
+ if ((mLPAEffectChain == NULL) && (sessions & PlaybackThread::EFFECT_SESSION)) {
+ // Clear reference to previous effect chain if any
+ t->mLock.lock();
+ ALOGV("getting the LPA effect chain and setting LPA flag to true.");
+ mLPAEffectChain = t->getEffectChain_l(*sessionId);
+ t->mLock.unlock();
+ }
+ }
+ mLPASessionId = *sessionId;
+ if (mLPAEffectChain != NULL) {
+ mLPAEffectChain->setLPAFlag(true);
+ // For LPA, the volume will be applied in DSP. No need for volume
+ // control in the Effect chain, so setting it to unity.
+ uint32_t volume = 0x1000000; // Equals to 1.0 in 8.24 format
+ mLPAEffectChain->setVolume_l(&volume,&volume);
+ } else {
+ ALOGW("There was no effectChain created for the sessionId(%d)", mLPASessionId);
+ }
+ mLPASampleRate = sampleRate;
+ mLPANumChannels = popcount(channelMask);
+ } else {
+ if(sessionId != NULL) {
+ ALOGE("Error: Invalid sessionID (%d) for direct audio track", *sessionId);
+ }
+ }
+ }
+ mLock.unlock();
+ directTrack = new DirectAudioTrack(this, output, desc, client, desc->flag);
+ desc->trackRefPtr = dynamic_cast<void *>(directTrack);
+ mLock.lock();
+ if (directTrack != 0) {
+ track = dynamic_cast<IDirectTrack *>(directTrack);
+ AudioEventObserver* obv = dynamic_cast<AudioEventObserver *>(directTrack);
+ ALOGE("setting observer mOutputDesc track %p, obv %p", track.get(), obv);
+ desc->stream->set_observer(desc->stream, reinterpret_cast<void *>(obv));
+ } else {
+ lStatus = BAD_VALUE;
+ }
+Exit:
+ if(lStatus) {
+ if (track != NULL) {
+ track.clear();
+ }
+ *status = lStatus;
+ }
+ return track;
+}
+
+void AudioFlinger::deleteEffectSession()
+{
+ ALOGV("deleteSession");
+ // -2 is invalid session ID
+ mLPASessionId = -2;
+ if (mLPAEffectChain != NULL) {
+ mLPAEffectChain->lock();
+ mLPAEffectChain->setLPAFlag(false);
+ size_t i, numEffects = mLPAEffectChain->getNumEffects();
+ for(i = 0; i < numEffects; i++) {
+ sp<EffectModule> effect = mLPAEffectChain->getEffectFromIndex_l(i);
+ effect->setInBuffer(mLPAEffectChain->inBuffer());
+ if (i == numEffects-1) {
+ effect->setOutBuffer(mLPAEffectChain->outBuffer());
+ } else {
+ effect->setOutBuffer(mLPAEffectChain->inBuffer());
+ }
+ effect->configure();
+ }
+ mLPAEffectChain->unlock();
+ mLPAEffectChain.clear();
+ mLPAEffectChain = NULL;
+ }
+}
+#endif
+
uint32_t AudioFlinger::sampleRate(audio_io_handle_t output) const
{
Mutex::Autolock _l(mLock);
+#ifdef QCOM_HARDWARE
+ if (!mDirectAudioTracks.isEmpty()) {
+ AudioSessionDescriptor *desc = mDirectAudioTracks.valueFor(output);
+ if(desc != NULL) {
+ return desc->stream->common.get_sample_rate(&desc->stream->common);
+ }
+ }
+#endif
PlaybackThread *thread = checkPlaybackThread_l(output);
if (thread == NULL) {
ALOGW("sampleRate() unknown thread %d", output);
@@ -572,6 +714,12 @@
int AudioFlinger::channelCount(audio_io_handle_t output) const
{
Mutex::Autolock _l(mLock);
+#ifdef QCOM_HARDWARE
+ AudioSessionDescriptor *desc = mDirectAudioTracks.valueFor(output);
+ if(desc != NULL) {
+ return desc->stream->common.get_channels(&desc->stream->common);
+ }
+#endif
PlaybackThread *thread = checkPlaybackThread_l(output);
if (thread == NULL) {
ALOGW("channelCount() unknown thread %d", output);
@@ -594,6 +742,12 @@
size_t AudioFlinger::frameCount(audio_io_handle_t output) const
{
Mutex::Autolock _l(mLock);
+#ifdef QCOM_HARDWARE
+ AudioSessionDescriptor *desc = mDirectAudioTracks.valueFor(output);
+ if(desc != NULL) {
+ return desc->stream->common.get_buffer_size(&desc->stream->common);
+ }
+#endif
PlaybackThread *thread = checkPlaybackThread_l(output);
if (thread == NULL) {
ALOGW("frameCount() unknown thread %d", output);
@@ -607,6 +761,15 @@
uint32_t AudioFlinger::latency(audio_io_handle_t output) const
{
Mutex::Autolock _l(mLock);
+#ifdef QCOM_HARDWARE
+ if (!mDirectAudioTracks.isEmpty()) {
+ AudioSessionDescriptor *desc = mDirectAudioTracks.valueFor(output);
+ if (desc != NULL) {
+ return desc->stream->get_latency(desc->stream);
+ }
+ }
+#endif
+
PlaybackThread *thread = checkPlaybackThread_l(output);
if (thread == NULL) {
ALOGW("latency(): no playback thread found for output handle %d", output);
@@ -737,6 +900,7 @@
Mutex::Autolock _l(mLock);
mMasterMute = muted;
+#ifndef ICS_AUDIO_BLOB
// Set master mute in the HALs which support it.
for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
AutoMutex lock(mHardwareLock);
@@ -755,6 +919,7 @@
// mute will simply ignore the setting.
for (size_t i = 0; i < mPlaybackThreads.size(); i++)
mPlaybackThreads.valueAt(i)->setMasterMute(muted);
+#endif
return NO_ERROR;
}
@@ -795,10 +960,33 @@
}
AutoMutex lock(mLock);
+#ifdef QCOM_HARDWARE
+ ALOGV("setStreamVolume stream %d, output %d, value %f",stream, output, value);
+ AudioSessionDescriptor *desc = NULL;
+ if (!mDirectAudioTracks.isEmpty()) {
+ desc = mDirectAudioTracks.valueFor(output);
+ if (desc != NULL) {
+ ALOGV("setStreamVolume for mAudioTracks size %d desc %p",mDirectAudioTracks.size(),desc);
+ if (desc->mStreamType == stream) {
+ mStreamTypes[stream].volume = value;
+ desc->mVolumeScale = value;
+ desc->stream->set_volume(desc->stream,
+ desc->mVolumeLeft * mStreamTypes[stream].volume,
+ desc->mVolumeRight* mStreamTypes[stream].volume);
+ return NO_ERROR;
+ }
+ }
+ }
+#endif
PlaybackThread *thread = NULL;
if (output) {
thread = checkPlaybackThread_l(output);
if (thread == NULL) {
+#ifdef QCOM_HARDWARE
+ if (desc != NULL) {
+ return NO_ERROR;
+ }
+#endif
return BAD_VALUE;
}
}
@@ -881,6 +1069,11 @@
// ioHandle == 0 means the parameters are global to the audio hardware interface
if (ioHandle == 0) {
Mutex::Autolock _l(mLock);
+#ifdef SRS_PROCESSING
+ POSTPRO_PATCH_ICS_PARAMS_SET(keyValuePairs);
+ if (!mDirectAudioTracks.isEmpty())
+ audioConfigChanged_l(AudioSystem::EFFECT_CONFIG_CHANGED, 0, NULL);
+#endif
status_t final_result = NO_ERROR;
{
AutoMutex lock(mHardwareLock);
@@ -928,6 +1121,33 @@
return final_result;
}
+#ifdef QCOM_HARDWARE
+ AudioSessionDescriptor *desc = NULL;
+ if (!mDirectAudioTracks.isEmpty()) {
+ desc = mDirectAudioTracks.valueFor(ioHandle);
+ if (desc != NULL) {
+ ALOGV("setParameters for mAudioTracks size %d desc %p",mDirectAudioTracks.size(),desc);
+ desc->stream->common.set_parameters(&desc->stream->common, keyValuePairs.string());
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 key = String8(AudioParameter::keyRouting);
+ int device;
+ if (param.getInt(key, device) == NO_ERROR) {
+ mDirectDevice = device;
+#ifdef SRS_PROCESSING
+ ALOGV("setParameters:: routing change to device %d", device);
+ POSTPRO_PATCH_ICS_OUTPROC_MIX_ROUTE(desc->trackRefPtr, param, device);
+ if(desc->flag & AUDIO_OUTPUT_FLAG_TUNNEL)
+ audioConfigChanged_l(AudioSystem::EFFECT_CONFIG_CHANGED, 0, NULL);
+#endif
+ if(mLPAEffectChain != NULL){
+ mLPAEffectChain->setDevice_l(device);
+ audioConfigChanged_l(AudioSystem::EFFECT_CONFIG_CHANGED, 0, NULL);
+ }
+ }
+ }
+ }
+#endif
+
// hold a strong ref on thread in case closeOutput() or closeInput() is called
// and the thread is exited once the lock is released
sp<ThreadBase> thread;
@@ -964,6 +1184,9 @@
if (ioHandle == 0) {
String8 out_s8;
+#ifdef SRS_PROCESSING
+ POSTPRO_PATCH_ICS_PARAMS_GET(keys, out_s8);
+#endif
for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
char *s;
{
@@ -1007,7 +1230,11 @@
config.format = format;
audio_hw_device_t *dev = mPrimaryHardwareDev->hwDevice();
+#ifndef ICS_AUDIO_BLOB
size_t size = dev->get_input_buffer_size(dev, &config);
+#else
+ size_t size = dev->get_input_buffer_size(dev, sampleRate, format, popcount(channelMask));
+#endif
mHardwareStatus = AUDIO_HW_IDLE;
return size;
}
@@ -1088,6 +1315,23 @@
}
}
+#ifdef QCOM_HARDWARE
+status_t AudioFlinger::deregisterClient(const sp<IAudioFlingerClient>& client)
+{
+ ALOGV("deregisterClient() %p, tid %d, calling tid %d", client.get(), gettid(), IPCThreadState::self()->getCallingPid());
+ Mutex::Autolock _l(mLock);
+
+ pid_t pid = IPCThreadState::self()->getCallingPid();
+ int index = mNotificationClients.indexOfKey(pid);
+ if (index >= 0) {
+ mNotificationClients.removeItemsAt(index);
+ return true;
+ }
+
+ return false;
+}
+#endif
+
void AudioFlinger::removeNotificationClient(pid_t pid)
{
Mutex::Autolock _l(mLock);
@@ -1118,11 +1362,33 @@
// audioConfigChanged_l() must be called with AudioFlinger::mLock held
void AudioFlinger::audioConfigChanged_l(int event, audio_io_handle_t ioHandle, const void *param2)
{
- size_t size = mNotificationClients.size();
- for (size_t i = 0; i < size; i++) {
- mNotificationClients.valueAt(i)->audioFlingerClient()->ioConfigChanged(event, ioHandle,
- param2);
+#ifdef QCOM_HARDWARE
+ ALOGV("AudioFlinger::audioConfigChanged_l: event %d", event);
+ if (event == AudioSystem::EFFECT_CONFIG_CHANGED) {
+ mIsEffectConfigChanged = true;
}
+ if (!mNotificationClients.isEmpty()){
+#endif
+ size_t size = mNotificationClients.size();
+ for (size_t i = 0; i < size; i++) {
+ mNotificationClients.valueAt(i)->audioFlingerClient()->ioConfigChanged(event, ioHandle,
+ param2);
+ }
+#ifdef QCOM_HARDWARE
+ }
+ if ((!mDirectAudioTracks.isEmpty())&& (event == AudioSystem::EFFECT_CONFIG_CHANGED)){
+ size_t dsize = mDirectAudioTracks.size();
+ for(size_t i = 0; i < dsize; i++) {
+ AudioSessionDescriptor *desc = mDirectAudioTracks.valueAt(i);
+ if(desc && ((DirectAudioTrack*)desc->trackRefPtr)) {
+ ALOGV("signalling directAudioTrack ");
+ ((DirectAudioTrack*)desc->trackRefPtr)->signalEffect();
+ } else{
+ ALOGV("not found track to signal directAudioTrack ");
+ }
+ }
+ }
+#endif
}
// removeClient_l() must be called with AudioFlinger::mLock held
@@ -1243,6 +1509,10 @@
RecordThread *thread;
size_t inFrameCount;
int lSessionId;
+#ifdef QCOM_HARDWARE
+ size_t inputBufferSize = 0;
+ uint32_t channelCount = popcount(channelMask);
+#endif
// check calling permissions
if (!recordingAllowed()) {
@@ -1251,11 +1521,21 @@
goto Exit;
}
+#ifdef QCOM_HARDWARE
+ // Check that audio input stream accepts requested audio parameters
+ inputBufferSize = getInputBufferSize(sampleRate, format, channelCount);
+ if (inputBufferSize == 0) {
+ lStatus = BAD_VALUE;
+ ALOGE("Bad audio input parameters: sampling rate %u, format %d, channels %d", sampleRate, format, channelCount);
+ goto Exit;
+ }
+#else
if (format != AUDIO_FORMAT_PCM_16_BIT) {
ALOGE("openRecord() invalid format %d", format);
lStatus = BAD_VALUE;
goto Exit;
}
+#endif
// add client to list
{ // scope for mLock
@@ -1286,6 +1566,32 @@
*sessionId = lSessionId;
}
}
+
+#ifdef QCOM_HARDWARE
+ // frameCount must be a multiple of input buffer size
+ // Change for Codec type
+ uint8_t channelCount = popcount(channelMask);
+ if (*flags & IAudioFlinger::TRACK_VOICE_COMMUNICATION) {
+ inFrameCount = inputBufferSize/channelCount/sizeof(short);
+ } else {
+ if ((format == AUDIO_FORMAT_PCM_16_BIT) ||
+ (format == AUDIO_FORMAT_PCM_8_BIT)) {
+ inFrameCount = inputBufferSize/channelCount/sizeof(short);
+ } else if (format == AUDIO_FORMAT_AMR_NB) {
+ inFrameCount = inputBufferSize/channelCount/AMR_FRAMESIZE;
+ } else if (format == AUDIO_FORMAT_EVRC) {
+ inFrameCount = inputBufferSize/channelCount/EVRC_FRAMESIZE;
+ } else if (format == AUDIO_FORMAT_QCELP) {
+ inFrameCount = inputBufferSize/channelCount/QCELP_FRAMESIZE;
+ } else if (format == AUDIO_FORMAT_AAC) {
+ inFrameCount = inputBufferSize/AAC_FRAMESIZE;
+ } else if (format == AUDIO_FORMAT_AMR_WB) {
+ inFrameCount = inputBufferSize/channelCount/AMR_WB_FRAMESIZE;
+ }
+ }
+ frameCount = ((frameCount - 1)/inFrameCount + 1) * inFrameCount;
+#endif
+
// create new record track.
// The record track uses one track in mHardwareMixerThread by convention.
// TODO: the uid should be passed in as a parameter to openRecord
@@ -1362,6 +1668,7 @@
{ // scope for auto-lock pattern
AutoMutex lock(mHardwareLock);
+#if !defined(ICS_AUDIO_BLOB) && !defined(MR0_AUDIO_BLOB)
if (0 == mAudioHwDevs.size()) {
mHardwareStatus = AUDIO_HW_GET_MASTER_VOLUME;
if (NULL != dev->get_master_volume) {
@@ -1379,6 +1686,7 @@
}
}
}
+#endif
mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
if ((NULL != dev->set_master_volume) &&
@@ -1387,12 +1695,14 @@
AudioHwDevice::AHWD_CAN_SET_MASTER_VOLUME);
}
+#if !defined(ICS_AUDIO_BLOB) && !defined(MR0_AUDIO_BLOB)
mHardwareStatus = AUDIO_HW_SET_MASTER_MUTE;
if ((NULL != dev->set_master_mute) &&
(OK == dev->set_master_mute(dev, mMasterMute))) {
flags = static_cast<AudioHwDevice::Flags>(flags |
AudioHwDevice::AHWD_CAN_SET_MASTER_MUTE);
}
+#endif
mHardwareStatus = AUDIO_HW_IDLE;
}
@@ -1442,6 +1752,20 @@
// ----------------------------------------------------------------------------
+#ifdef HAVE_PRE_KITKAT_AUDIO_BLOB
+audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module,
+ audio_devices_t *pDevices,
+ uint32_t *pSamplingRate,
+ audio_format_t *pFormat,
+ audio_channel_mask_t *pChannelMask,
+ uint32_t *pLatencyMs,
+ audio_output_flags_t flags)
+{
+ return openOutput(module, pDevices, pSamplingRate, pFormat, pChannelMask,
+ pLatencyMs, flags, NULL);
+}
+#endif
+
audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_t module,
audio_devices_t *pDevices,
uint32_t *pSamplingRate,
@@ -1456,9 +1780,11 @@
config.sample_rate = (pSamplingRate != NULL) ? *pSamplingRate : 0;
config.channel_mask = (pChannelMask != NULL) ? *pChannelMask : 0;
config.format = (pFormat != NULL) ? *pFormat : AUDIO_FORMAT_DEFAULT;
+#ifndef HAVE_PRE_KITKAT_AUDIO_BLOB
if (offloadInfo) {
config.offload_info = *offloadInfo;
}
+#endif
audio_stream_out_t *outStream = NULL;
AudioHwDevice *outHwDev;
@@ -1470,8 +1796,10 @@
config.format,
config.channel_mask,
flags);
+#ifndef HAVE_PRE_KITKAT_AUDIO_BLOB
ALOGV("openOutput(), offloadInfo %p version 0x%04x",
offloadInfo, offloadInfo == NULL ? -1 : offloadInfo->version );
+#endif
if (pDevices == NULL || *pDevices == 0) {
return 0;
@@ -1488,12 +1816,24 @@
mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
- status_t status = hwDevHal->open_output_stream(hwDevHal,
+ status_t status;
+#ifndef ICS_AUDIO_BLOB
+ status = hwDevHal->open_output_stream(hwDevHal,
id,
*pDevices,
(audio_output_flags_t)flags,
&config,
&outStream);
+#else
+ status = hwDevHal->open_output_stream(hwDevHal,
+ *pDevices,
+ (int *)&config.format,
+ &config.channel_mask,
+ &config.sample_rate,
+ &outStream);
+ uint32_t newflags = flags | AUDIO_OUTPUT_FLAG_PRIMARY;
+ flags = (audio_output_flags_t)newflags;
+#endif
mHardwareStatus = AUDIO_HW_IDLE;
ALOGV("openOutput() openOutputStream returned output %p, SamplingRate %d, Format %#08x, "
@@ -1506,10 +1846,23 @@
if (status == NO_ERROR && outStream != NULL) {
AudioStreamOut *output = new AudioStreamOut(outHwDev, outStream, flags);
-
if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
thread = new OffloadThread(this, output, id, *pDevices);
ALOGV("openOutput() created offload output: ID %d thread %p", id, thread);
+#ifdef QCOM_HARDWARE
+ }
+ if (flags & AUDIO_OUTPUT_FLAG_LPA || flags & AUDIO_OUTPUT_FLAG_TUNNEL ) {
+ AudioSessionDescriptor *desc = new AudioSessionDescriptor(hwDevHal, outStream, flags);
+ desc->mActive = true;
+ //TODO: no stream type
+ //desc->mStreamType = streamType;
+ desc->mVolumeLeft = 1.0;
+ desc->mVolumeRight = 1.0;
+ desc->device = *pDevices;
+ desc->trackRefPtr = NULL;
+ mDirectAudioTracks.add(id, desc);
+ mDirectDevice = desc->device;
+#endif
} else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT) ||
(config.format != AUDIO_FORMAT_PCM_16_BIT) ||
(config.channel_mask != AUDIO_CHANNEL_OUT_STEREO)) {
@@ -1519,7 +1872,9 @@
thread = new MixerThread(this, output, id, *pDevices);
ALOGV("openOutput() created mixer output: ID %d thread %p", id, thread);
}
- mPlaybackThreads.add(id, thread);
+ if (thread != NULL) {
+ mPlaybackThreads.add(id, thread);
+ }
if (pSamplingRate != NULL) {
*pSamplingRate = config.sample_rate;
@@ -1530,18 +1885,30 @@
if (pChannelMask != NULL) {
*pChannelMask = config.channel_mask;
}
- if (pLatencyMs != NULL) {
- *pLatencyMs = thread->latency();
+ if (thread != NULL) {
+ if (pLatencyMs != NULL) *pLatencyMs = thread->latency();
+ // notify client processes of the new output creation
+ thread->audioConfigChanged_l(AudioSystem::OUTPUT_OPENED);
}
+#ifdef QCOM_HARDWARE
+ else {
+ *pLatencyMs = 0;
+ if ((flags & AUDIO_OUTPUT_FLAG_LPA) || (flags & AUDIO_OUTPUT_FLAG_TUNNEL)) {
+ AudioSessionDescriptor *desc = mDirectAudioTracks.valueFor(id);
+ *pLatencyMs = desc->stream->get_latency(desc->stream);
+ }
+ }
+#endif
- // notify client processes of the new output creation
- thread->audioConfigChanged_l(AudioSystem::OUTPUT_OPENED);
// the first primary output opened designates the primary hw device
if ((mPrimaryHardwareDev == NULL) && (flags & AUDIO_OUTPUT_FLAG_PRIMARY)) {
ALOGI("Using module %d has the primary audio interface", module);
mPrimaryHardwareDev = outHwDev;
-
+#ifdef SRS_PROCESSING
+ SRS_Processing::RawDataSet(NULL, "qdsp hook", &mPrimaryHardwareDev,
+ sizeof(&mPrimaryHardwareDev));
+#endif
AutoMutex lock(mHardwareLock);
mHardwareStatus = AUDIO_HW_SET_MODE;
hwDevHal->set_mode(hwDevHal, mMode);
@@ -1584,6 +1951,22 @@
{
// keep strong reference on the playback thread so that
// it is not destroyed while exit() is executed
+#ifdef QCOM_HARDWARE
+ AudioSessionDescriptor *desc = mDirectAudioTracks.valueFor(output);
+ if (desc) {
+ ALOGV("Closing DirectTrack output %d", output);
+ desc->mActive = false;
+ desc->stream->common.standby(&desc->stream->common);
+ desc->hwDev->close_output_stream(desc->hwDev, desc->stream);
+ desc->trackRefPtr = NULL;
+ desc->stream = NULL;
+ mDirectAudioTracks.removeItem(output);
+ audioConfigChanged_l(AudioSystem::OUTPUT_CLOSED, output, NULL);
+ delete desc;
+ return NO_ERROR;
+ }
+#endif
+
sp<PlaybackThread> thread;
{
Mutex::Autolock _l(mLock);
@@ -1700,8 +2083,16 @@
audio_hw_device_t *inHwHal = inHwDev->hwDevice();
audio_io_handle_t id = nextUniqueId();
+#ifndef ICS_AUDIO_BLOB
status = inHwHal->open_input_stream(inHwHal, id, *pDevices, &config,
&inStream);
+#else
+ status = inHwHal->open_input_stream(inHwHal, *pDevices,
+ (int *)&config.format,
+ &config.channel_mask,
+ &config.sample_rate, (audio_in_acoustics_t)0,
+ &inStream);
+#endif
ALOGV("openInput() openInputStream returned input %p, SamplingRate %d, Format %d, Channels %x, "
"status %d",
inStream,
@@ -1716,10 +2107,18 @@
if (status == BAD_VALUE &&
reqFormat == config.format && config.format == AUDIO_FORMAT_PCM_16_BIT &&
(config.sample_rate <= 2 * reqSamplingRate) &&
- (popcount(config.channel_mask) <= FCC_2) && (popcount(reqChannels) <= FCC_2)) {
+ (getInputChannelCount(config.channel_mask) <= FCC_2) && (getInputChannelCount(reqChannels) <= FCC_2)) {
ALOGV("openInput() reopening with proposed sampling rate and channel mask");
inStream = NULL;
+#ifndef ICS_AUDIO_BLOB
status = inHwHal->open_input_stream(inHwHal, id, *pDevices, &config, &inStream);
+#else
+ status = inHwHal->open_input_stream(inHwHal, *pDevices,
+ (int *)&config.format,
+ &config.channel_mask,
+ &config.sample_rate, (audio_in_acoustics_t)0,
+ &inStream);
+#endif
}
if (status == NO_ERROR && inStream != NULL) {
@@ -2525,8 +2924,6 @@
}
#endif
-// ----------------------------------------------------------------------------
-
status_t AudioFlinger::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 53e238e..c0c9b99 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -1,5 +1,6 @@
/*
-**
+** Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+** Not a Contribution.
** Copyright 2007, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
@@ -28,6 +29,10 @@
#include <media/IAudioFlinger.h>
#include <media/IAudioFlingerClient.h>
+#ifdef QCOM_HARDWARE
+#include <media/IDirectTrack.h>
+#include <media/IDirectTrackClient.h>
+#endif
#include <media/IAudioTrack.h>
#include <media/IAudioRecord.h>
#include <media/AudioSystem.h>
@@ -54,7 +59,7 @@
#include "AudioWatchdog.h"
#include <powermanager/IPowerManager.h>
-
+#include <utils/List.h>
#include <media/nbaio/NBLog.h>
#include <private/media/AudioTrackShared.h>
@@ -86,6 +91,14 @@
#define INCLUDING_FROM_AUDIOFLINGER_H
+static uint32_t getInputChannelCount(uint32_t channels) {
+ // only mono, stereo, and 5.1 are supported for input sources
+#ifdef QCOM_HARDWARE
+ return popcount((channels)&(AUDIO_CHANNEL_IN_STEREO|AUDIO_CHANNEL_IN_MONO|AUDIO_CHANNEL_IN_5POINT1));
+#else
+ return popcount(channels);
+#endif
+}
class AudioFlinger :
public BinderService<AudioFlinger>,
public BnAudioFlinger
@@ -111,7 +124,18 @@
String8& name,
int clientUid,
status_t *status);
-
+#ifdef QCOM_HARDWARE
+ virtual sp<IDirectTrack> createDirectTrack(
+ pid_t pid,
+ uint32_t sampleRate,
+ audio_channel_mask_t channelMask,
+ audio_io_handle_t output,
+ int *sessionId,
+ IDirectTrackClient* client,
+ audio_stream_type_t streamType,
+ status_t *status);
+ virtual void deleteEffectSession();
+#endif
virtual sp<IAudioRecord> openRecord(
audio_io_handle_t input,
uint32_t sampleRate,
@@ -152,10 +176,22 @@
virtual String8 getParameters(audio_io_handle_t ioHandle, const String8& keys) const;
virtual void registerClient(const sp<IAudioFlingerClient>& client);
-
+#ifdef QCOM_HARDWARE
+ virtual status_t deregisterClient(const sp<IAudioFlingerClient>& client);
+#endif
virtual size_t getInputBufferSize(uint32_t sampleRate, audio_format_t format,
audio_channel_mask_t channelMask) const;
+#ifdef HAVE_PRE_KITKAT_AUDIO_BLOB
+ virtual audio_io_handle_t openOutput(audio_module_handle_t module,
+ audio_devices_t *pDevices,
+ uint32_t *pSamplingRate,
+ audio_format_t *pFormat,
+ audio_channel_mask_t *pChannelMask,
+ uint32_t *pLatencyMs,
+ audio_output_flags_t flags);
+#endif
+
virtual audio_io_handle_t openOutput(audio_module_handle_t module,
audio_devices_t *pDevices,
uint32_t *pSamplingRate,
@@ -230,6 +266,14 @@
Parcel* reply,
uint32_t flags);
+#ifdef QCOM_HARDWARE
+ bool applyEffectsOn(void *token,
+ int16_t *buffer1,
+ int16_t *buffer2,
+ int size,
+ bool force);
+#endif
+
// end of IAudioFlinger interface
sp<NBLog::Writer> newWriter_l(size_t size, const char *name);
@@ -375,6 +419,9 @@
class EffectModule;
class EffectHandle;
class EffectChain;
+#ifdef QCOM_HARDWARE
+ struct AudioSessionDescriptor;
+#endif
struct AudioStreamOut;
struct AudioStreamIn;
@@ -464,7 +511,118 @@
sp<PlaybackThread> getEffectThread_l(int sessionId, int EffectId);
+#ifdef QCOM_HARDWARE
+ // server side of the client's IAudioTrack
+ class DirectAudioTrack : public android::BnDirectTrack,
+ public AudioEventObserver
+ {
+ public:
+ DirectAudioTrack(const sp<AudioFlinger>& audioFlinger,
+ int output, AudioSessionDescriptor *outputDesc,
+ IDirectTrackClient* client, audio_output_flags_t outflag);
+ virtual ~DirectAudioTrack();
+ virtual status_t start();
+ virtual void stop();
+ virtual void flush();
+ virtual void mute(bool);
+ virtual void pause();
+ virtual ssize_t write(const void *buffer, size_t bytes);
+ virtual void setVolume(float left, float right);
+ virtual int64_t getTimeStamp();
+ virtual void postEOS(int64_t delayUs);
+ void signalEffect();
+ virtual status_t onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
+ private:
+
+ IDirectTrackClient* mClient;
+ AudioSessionDescriptor *mOutputDesc;
+ int mOutput;
+ bool mIsPaused;
+ audio_output_flags_t mFlag;
+
+ class BufferInfo {
+ public:
+ BufferInfo(void *buf1, void *buf2, int32_t nSize) :
+ localBuf(buf1), dspBuf(buf2), memBufsize(nSize)
+ {}
+
+ void *localBuf;
+ void *dspBuf;
+ uint32_t memBufsize;
+ uint32_t bytesToWrite;
+ };
+ List<BufferInfo> mBufPool;
+ List<BufferInfo> mEffectsPool;
+ void *mEffectsThreadScratchBuffer;
+
+ void allocateBufPool();
+ void deallocateBufPool();
+
+ //******Effects*************
+ static void *EffectsThreadWrapper(void *me);
+ void EffectsThreadEntry();
+ // make sure the Effects thread also exited
+ void requestAndWaitForEffectsThreadExit();
+ void createEffectThread();
+ Condition mEffectCv;
+ Mutex mEffectLock;
+ pthread_t mEffectsThread;
+ bool mKillEffectsThread;
+ bool mEffectsThreadAlive;
+ bool mEffectConfigChanged;
+
+ //Structure to recieve the Effect notification from the flinger.
+ class AudioFlingerDirectTrackClient: public IBinder::DeathRecipient, public BnAudioFlingerClient {
+ public:
+ AudioFlingerDirectTrackClient(void *obj);
+
+ DirectAudioTrack *pBaseClass;
+ // DeathRecipient
+ virtual void binderDied(const wp<IBinder>& who);
+
+ // IAudioFlingerClient
+
+ // indicate a change in the configuration of an output or input: keeps the cached
+ // values for output/input parameters upto date in client process
+ virtual void ioConfigChanged(int event, audio_io_handle_t ioHandle, const void *param2);
+
+ friend class DirectAudioTrack;
+ };
+ // helper function to obtain AudioFlinger service handle
+ sp<AudioFlinger> mAudioFlinger;
+ sp<AudioFlingerDirectTrackClient> mAudioFlingerClient;
+
+ void clearPowerManager();
+
+ class PMDeathRecipient : public IBinder::DeathRecipient {
+ public:
+ PMDeathRecipient(void *obj){parentClass = (DirectAudioTrack *)obj;}
+ virtual ~PMDeathRecipient() {}
+
+ // IBinder::DeathRecipient
+ virtual void binderDied(const wp<IBinder>& who);
+
+ private:
+ DirectAudioTrack *parentClass;
+ PMDeathRecipient(const PMDeathRecipient&);
+ PMDeathRecipient& operator = (const PMDeathRecipient&);
+
+ friend class DirectAudioTrack;
+ };
+
+ friend class PMDeathRecipient;
+
+ Mutex pmLock;
+ void acquireWakeLock();
+ void releaseWakeLock();
+
+ sp<IPowerManager> mPowerManager;
+ sp<IBinder> mWakeLockToken;
+ sp<PMDeathRecipient> mDeathRecipient;
+ };
+#endif
void removeClient_l(pid_t pid);
void removeNotificationClient(pid_t pid);
@@ -526,6 +684,22 @@
AudioStreamIn(AudioHwDevice *dev, audio_stream_in_t *in) :
audioHwDev(dev), stream(in) {}
};
+#ifdef QCOM_HARDWARE
+ struct AudioSessionDescriptor {
+ bool mActive;
+ int mStreamType;
+ float mVolumeLeft;
+ float mVolumeRight;
+ float mVolumeScale;
+ audio_hw_device_t *hwDev;
+ audio_stream_out_t *stream;
+ audio_output_flags_t flag;
+ void *trackRefPtr;
+ audio_devices_t device;
+ AudioSessionDescriptor(audio_hw_device_t *dev, audio_stream_out_t *out, audio_output_flags_t outflag) :
+ hwDev(dev), stream(out), flag(outflag) {}
+ };
+#endif
// for mAudioSessionRefs only
struct AudioSessionRef {
@@ -590,10 +764,20 @@
volatile int32_t mNextUniqueId; // updated by android_atomic_inc
audio_mode_t mMode;
bool mBtNrecIsOff;
-
+#ifdef QCOM_HARDWARE
+ DefaultKeyedVector<audio_io_handle_t, AudioSessionDescriptor *> mDirectAudioTracks;
// protected by mLock
+ volatile bool mIsEffectConfigChanged;
+#endif
Vector<AudioSessionRef*> mAudioSessionRefs;
-
+#ifdef QCOM_HARDWARE
+ sp<EffectChain> mLPAEffectChain;
+ int mLPASessionId;
+ audio_devices_t mDirectDevice;//device for directTrack,used for effects
+ int mLPASampleRate;
+ int mLPANumChannels;
+ volatile bool mAllChainsLocked;
+#endif
float masterVolume_l() const;
bool masterMute_l() const;
audio_module_handle_t loadHwModule_l(const char *name);
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index 07dc6dd..32d2892 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -561,7 +561,11 @@
(value == 48000 && devSampleRate == 44100))) {
quality = AudioResampler::LOW_QUALITY;
} else {
+#ifdef QCOM_HARDWARE
+ quality = AudioResampler::VERY_HIGH_QUALITY;
+#else
quality = AudioResampler::DEFAULT_QUALITY;
+#endif
}
resampler = AudioResampler::create(
format,
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
index 35e816b..4cb6df5 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audioflinger/AudioPolicyService.cpp
@@ -418,12 +418,15 @@
return BAD_VALUE;
}
Mutex::Autolock _l(mLock);
+#ifndef ICS_AUDIO_BLOB
if (mpAudioPolicy->set_stream_volume_index_for_device) {
return mpAudioPolicy->set_stream_volume_index_for_device(mpAudioPolicy,
stream,
index,
device);
- } else {
+ } else
+#endif
+ {
return mpAudioPolicy->set_stream_volume_index(mpAudioPolicy, stream, index);
}
}
@@ -439,12 +442,15 @@
return BAD_VALUE;
}
Mutex::Autolock _l(mLock);
+#ifndef ICS_AUDIO_BLOB
if (mpAudioPolicy->get_stream_volume_index_for_device) {
return mpAudioPolicy->get_stream_volume_index_for_device(mpAudioPolicy,
stream,
index,
device);
- } else {
+ } else
+#endif
+ {
return mpAudioPolicy->get_stream_volume_index(mpAudioPolicy, stream, index);
}
}
@@ -515,15 +521,19 @@
bool AudioPolicyService::isStreamActiveRemotely(audio_stream_type_t stream, uint32_t inPastMs) const
{
+#if !defined(ICS_AUDIO_BLOB) && !defined(MR1_AUDIO_BLOB)
if (mpAudioPolicy == NULL) {
return 0;
}
Mutex::Autolock _l(mLock);
return mpAudioPolicy->is_stream_active_remotely(mpAudioPolicy, stream, inPastMs);
+#endif
+ return 0;
}
bool AudioPolicyService::isSourceActive(audio_source_t source) const
{
+#ifndef ICS_AUDIO_BLOB
if (mpAudioPolicy == NULL) {
return false;
}
@@ -532,6 +542,9 @@
}
Mutex::Autolock _l(mLock);
return mpAudioPolicy->is_source_active(mpAudioPolicy, source);
+#else
+ return false;
+#endif
}
status_t AudioPolicyService::queryDefaultPreProcessing(int audioSession,
@@ -1020,7 +1033,9 @@
} else {
data2->mKeyValuePairs = param2.toString();
}
- command->mTime = command2->mTime;
+ if (!strcmp(data2->mKeyValuePairs.string(), data->mKeyValuePairs.string())){
+ 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;
@@ -1137,6 +1152,9 @@
bool AudioPolicyService::isOffloadSupported(const audio_offload_info_t& info)
{
+#ifdef HAVE_PRE_KITKAT_AUDIO_BLOB
+ return false;
+#endif
if (mpAudioPolicy == NULL) {
ALOGV("mpAudioPolicy == NULL");
return false;
diff --git a/services/audioflinger/AudioResampler.cpp b/services/audioflinger/AudioResampler.cpp
index 2c3c719..48c189c 100644
--- a/services/audioflinger/AudioResampler.cpp
+++ b/services/audioflinger/AudioResampler.cpp
@@ -52,6 +52,7 @@
static const int kPreInterpShift = kNumPhaseBits - kNumInterpBits;
void init() {}
+ void reset();
void resampleMono16(int32_t* out, size_t outFrameCount,
AudioBufferProvider* provider);
void resampleStereo16(int32_t* out, size_t outFrameCount,
@@ -294,6 +295,14 @@
}
}
+void AudioResamplerOrder1::reset() {
+ mInputIndex = 0;
+ mPhaseFraction = 0;
+ mBuffer.frameCount = 0;
+ mX0L = 0;
+ mX0R = 0;
+}
+
void AudioResamplerOrder1::resampleStereo16(int32_t* out, size_t outFrameCount,
AudioBufferProvider* provider) {
diff --git a/services/audioflinger/AudioResamplerCubic.cpp b/services/audioflinger/AudioResamplerCubic.cpp
index 18e59e9..ff4e473 100644
--- a/services/audioflinger/AudioResamplerCubic.cpp
+++ b/services/audioflinger/AudioResamplerCubic.cpp
@@ -32,6 +32,14 @@
memset(&right, 0, sizeof(state));
}
+void AudioResamplerCubic::reset(){
+ mInputIndex = 0;
+ mPhaseFraction = 0;
+ mBuffer.frameCount = 0;
+ memset(&left, 0, sizeof(state));
+ memset(&right, 0, sizeof(state));
+}
+
void AudioResamplerCubic::resample(int32_t* out, size_t outFrameCount,
AudioBufferProvider* provider) {
diff --git a/services/audioflinger/AudioResamplerCubic.h b/services/audioflinger/AudioResamplerCubic.h
index 203b933..5ec38ee 100644
--- a/services/audioflinger/AudioResamplerCubic.h
+++ b/services/audioflinger/AudioResamplerCubic.h
@@ -43,6 +43,7 @@
int32_t a, b, c, y0, y1, y2, y3;
} state;
void init();
+ void reset ();
void resampleMono16(int32_t* out, size_t outFrameCount,
AudioBufferProvider* provider);
void resampleStereo16(int32_t* out, size_t outFrameCount,
diff --git a/services/audioflinger/AudioResamplerSinc.cpp b/services/audioflinger/AudioResamplerSinc.cpp
index 207f26b..60cfef7 100644
--- a/services/audioflinger/AudioResamplerSinc.cpp
+++ b/services/audioflinger/AudioResamplerSinc.cpp
@@ -497,6 +497,15 @@
mRingFull = mImpulse + (numCoefs+1)*mChannelCount;
}
+void AudioResamplerSinc::reset(){
+ mInputIndex = 0;
+ mPhaseFraction = 0;
+ mBuffer.frameCount = 0;
+ const Constants& c(*mConstants);
+ const size_t stateSize = (2*c.halfNumCoefs) * mChannelCount * 2;
+ memset(mState, 0, sizeof(int16_t)*stateSize);
+}
+
void AudioResamplerSinc::setVolume(int16_t left, int16_t right) {
AudioResampler::setVolume(left, right);
mVolumeSIMD[0] = int32_t(left)<<16;
diff --git a/services/audioflinger/AudioResamplerSinc.h b/services/audioflinger/AudioResamplerSinc.h
index 1ea4474..636586f 100644
--- a/services/audioflinger/AudioResamplerSinc.h
+++ b/services/audioflinger/AudioResamplerSinc.h
@@ -44,6 +44,8 @@
private:
void init();
+ void reset();
+
virtual void setVolume(int16_t left, int16_t right);
template<int CHANNELS>
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index a8a5169..a8f0511 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -1,5 +1,6 @@
/*
-**
+** Copyright (c) 2013, The Linux Foundation. All rights reserved.
+** Not a Contribution.
** Copyright 2012, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
@@ -29,6 +30,11 @@
#include "AudioFlinger.h"
#include "ServiceUtilities.h"
+#ifdef SRS_PROCESSING
+#include "srs_processing.h"
+#include "postpro_patch_ics.h"
+#endif
+
// ----------------------------------------------------------------------------
// Note: the following macro is used for extremely verbose logging message. In
@@ -66,7 +72,11 @@
mStatus(NO_INIT), mState(IDLE),
// mMaxDisableWaitCnt is set by configure() and not used before then
// mDisableWaitCnt is set by process() and updateState() and not used before then
+#ifdef QCOM_HARDWARE
+ mSuspended(false), mIsForLPA(false)
+#else
mSuspended(false)
+#endif
{
ALOGV("Constructor %p", this);
int lStatus;
@@ -301,12 +311,20 @@
(*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_RESET, 0, NULL, 0, NULL);
}
+#ifdef QCOM_HARDWARE
+status_t AudioFlinger::EffectModule::configure(bool isForLPA, int sampleRate, int channelCount, int frameCount)
+#else
status_t AudioFlinger::EffectModule::configure()
+#endif
{
status_t status;
+ status_t cmdStatus = 0;
sp<ThreadBase> thread;
uint32_t size;
audio_channel_mask_t channelMask;
+#ifdef QCOM_HARDWARE
+ uint32_t channels;
+#endif
if (mEffectInterface == NULL) {
status = NO_INIT;
@@ -321,6 +339,26 @@
// TODO: handle configuration of effects replacing track process
channelMask = thread->channelMask();
+#ifdef QCOM_HARDWARE
+ if(popcount(channelMask) > 2) {
+ ALOGE("Error: Trying to apply effect on %d channel content",popcount(channelMask));
+ return INVALID_OPERATION;
+ }
+ mIsForLPA = isForLPA;
+ if(isForLPA) {
+ if (channelCount == 1) {
+ channels = AUDIO_CHANNEL_OUT_MONO;
+ } else {
+ channels = AUDIO_CHANNEL_OUT_STEREO;
+ }
+ } else {
+ if (thread->channelCount() == 1) {
+ channels = AUDIO_CHANNEL_OUT_MONO;
+ } else {
+ channels = AUDIO_CHANNEL_OUT_STEREO;
+ }
+ }
+#endif
if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_MONO;
@@ -330,7 +368,15 @@
mConfig.outputCfg.channels = channelMask;
mConfig.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
mConfig.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
- mConfig.inputCfg.samplingRate = thread->sampleRate();
+#ifdef QCOM_HARDWARE
+ if(isForLPA){
+ mConfig.inputCfg.samplingRate = sampleRate;
+ } else {
+#endif
+ mConfig.inputCfg.samplingRate = thread->sampleRate();
+#ifdef QCOM_HARDWARE
+ }
+#endif
mConfig.outputCfg.samplingRate = mConfig.inputCfg.samplingRate;
mConfig.inputCfg.bufferProvider.cookie = NULL;
mConfig.inputCfg.bufferProvider.getBuffer = NULL;
@@ -355,13 +401,20 @@
}
mConfig.inputCfg.mask = EFFECT_CONFIG_ALL;
mConfig.outputCfg.mask = EFFECT_CONFIG_ALL;
- mConfig.inputCfg.buffer.frameCount = thread->frameCount();
+#ifdef QCOM_HARDWARE
+ if(isForLPA) {
+ mConfig.inputCfg.buffer.frameCount = frameCount;
+ } else {
+#endif
+ mConfig.inputCfg.buffer.frameCount = thread->frameCount();
+#ifdef QCOM_HARDWARE
+ }
+#endif
mConfig.outputCfg.buffer.frameCount = mConfig.inputCfg.buffer.frameCount;
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,
@@ -412,7 +465,7 @@
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,
@@ -440,7 +493,7 @@
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,
@@ -553,10 +606,15 @@
// must be called with EffectModule::mLock held
status_t AudioFlinger::EffectModule::setEnabled_l(bool enabled)
{
-
+#ifdef QCOM_HARDWARE
+ bool effectStateChanged = false;
+#endif
ALOGV("setEnabled %p enabled %d", this, enabled);
if (enabled != isEnabled()) {
+#ifdef QCOM_HARDWARE
+ effectStateChanged = true;
+#endif
status_t status = AudioSystem::setEffectEnabled(mId, enabled);
if (enabled && status != NO_ERROR) {
return status;
@@ -594,6 +652,19 @@
}
}
}
+#ifdef QCOM_HARDWARE
+ /*
+ Send notification event to LPA Player when an effect for
+ LPA output is enabled or disabled.
+ */
+ sp<EffectChain> chain = mChain.promote();
+ if (effectStateChanged && chain->isForLPATrack()) {
+ sp<ThreadBase> thread = mThread.promote();
+ unlock();//Acquire locks in certain sequence to avoid deadlock
+ thread->effectConfigChanged();
+ lock();
+ }
+#endif
return NO_ERROR;
}
@@ -645,7 +716,7 @@
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);
@@ -680,7 +751,7 @@
}
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;
@@ -702,7 +773,7 @@
}
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,
@@ -1137,6 +1208,17 @@
return disable();
}
+#ifdef QCOM_HARDWARE
+ if(mEffect->isOnLPA() &&
+ ((cmdCode == EFFECT_CMD_SET_PARAM) || (cmdCode == EFFECT_CMD_SET_PARAM_DEFERRED) ||
+ (cmdCode == EFFECT_CMD_SET_PARAM_COMMIT) || (cmdCode == EFFECT_CMD_SET_DEVICE) ||
+ (cmdCode == EFFECT_CMD_SET_VOLUME) || (cmdCode == EFFECT_CMD_SET_AUDIO_MODE)) ) {
+ // Notify Direct track for the change in Effect module
+ // TODO: check if it is required to send mLPAHandle
+ ALOGV("Notifying Direct Track for the change in effect config %d", cmdCode);
+ mClient->audioFlinger()->audioConfigChanged_l(AudioSystem::EFFECT_CONFIG_CHANGED, 0, NULL);
+ }
+#endif
return mEffect->command(cmdCode, cmdSize, pCmdData, replySize, pReplyData);
}
@@ -1204,7 +1286,11 @@
int sessionId)
: mThread(thread), mSessionId(sessionId), mActiveTrackCnt(0), mTrackCnt(0), mTailBufferCount(0),
mOwnInBuffer(false), mVolumeCtrlIdx(-1), mLeftVolume(UINT_MAX), mRightVolume(UINT_MAX),
+#ifdef QCOM_HARDWARE
+ mNewLeftVolume(UINT_MAX), mNewRightVolume(UINT_MAX), mIsForLPATrack(false)
+#else
mNewLeftVolume(UINT_MAX), mNewRightVolume(UINT_MAX)
+#endif
{
mStrategy = AudioSystem::getStrategyForStream(AUDIO_STREAM_MUSIC);
if (thread == NULL) {
@@ -1250,6 +1336,20 @@
return 0;
}
+#ifdef QCOM_HARDWARE
+sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromIndex_l(int idx)
+{
+ sp<EffectModule> effect = NULL;
+ if(idx < 0 || idx >= mEffects.size()) {
+ ALOGE("EffectChain::getEffectFromIndex_l: invalid index %d", idx);
+ }
+ if(mEffects.size() > 0){
+ effect = mEffects[idx];
+ }
+ return effect;
+}
+#endif
+
// getEffectFromType_l() must be called with ThreadBase::mLock held
sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromType_l(
const effect_uuid_t *type)
@@ -1315,7 +1415,11 @@
}
size_t size = mEffects.size();
+#ifdef QCOM_HARDWARE
+ if (doProcess || isForLPATrack()) {
+#else
if (doProcess) {
+#endif
for (size_t i = 0; i < size; i++) {
mEffects[i]->process();
}
@@ -1780,6 +1884,7 @@
}
}
+
bool AudioFlinger::EffectChain::isNonOffloadableEnabled()
{
Mutex::Autolock _l(mLock);
@@ -1792,4 +1897,181 @@
return false;
}
+#ifdef QCOM_HARDWARE
+#define DEAFULT_FRAME_COUNT 1200
+bool AudioFlinger::applyEffectsOn(void *token, int16_t *inBuffer,
+ int16_t *outBuffer, int size, bool force)
+{
+ ALOGV("applyEffectsOn: inBuf %p outBuf %p size %d token %p", inBuffer, outBuffer, size, token);
+ // This might be the first buffer to apply effects after effect config change
+ // should not skip effects processing
+ mIsEffectConfigChanged = false;
+
+ volatile size_t numEffects = 0;
+#ifdef SRS_PROCESSING
+ POSTPRO_PATCH_ICS_OUTPROC_DIRECT_SAMPLES(token, AUDIO_FORMAT_PCM_16_BIT, outBuffer, size, mLPASampleRate, mLPANumChannels);
+#endif
+
+ if(mLPAEffectChain != NULL) {
+ numEffects = mLPAEffectChain->getNumEffects();
+ }
+
+ if( numEffects > 0) {
+ size_t i = 0;
+ int16_t *pIn = inBuffer;
+ int16_t *pOut = outBuffer;
+
+ int frameCount = size / (sizeof(int16_t) * mLPANumChannels);
+
+ while(frameCount > 0) {
+ if(mLPAEffectChain == NULL) {
+ ALOGV("LPA Effect Chain is removed - No effects processing !!");
+ numEffects = 0;
+ break;
+ }
+ mLPAEffectChain->lock();
+
+ numEffects = mLPAEffectChain->getNumEffects();
+ if(!numEffects) {
+ ALOGV("applyEffectsOn: All the effects are removed - nothing to process");
+ mLPAEffectChain->unlock();
+ break;
+ }
+
+ int outFrameCount = (frameCount > DEAFULT_FRAME_COUNT ? DEAFULT_FRAME_COUNT: frameCount);
+ bool isEffectEnabled = false;
+ for(i = 0; i < numEffects; i++) {
+ // If effect configuration is changed while applying effects do not process further
+ if(mIsEffectConfigChanged && !force) {
+ mLPAEffectChain->unlock();
+ ALOGV("applyEffectsOn: mIsEffectConfigChanged is set - no further processing %d",frameCount);
+ return false;
+ }
+ sp<EffectModule> effect = mLPAEffectChain->getEffectFromIndex_l(i);
+ if(effect == NULL) {
+ ALOGE("getEffectFromIndex_l(%d) returned NULL ptr", i);
+ mLPAEffectChain->unlock();
+ return false;
+ }
+ if(i == 0) {
+ // For the first set input and output buffers different
+ isEffectEnabled = effect->isProcessEnabled();
+ effect->setInBuffer(pIn);
+ effect->setOutBuffer(pOut);
+ } else {
+ // For the remaining use previous effect's output buffer as input buffer
+ effect->setInBuffer(pOut);
+ effect->setOutBuffer(pOut);
+ }
+ // true indicates that it is being applied on LPA output
+ effect->configure(true, mLPASampleRate, mLPANumChannels, outFrameCount);
+ }
+
+ if(isEffectEnabled) {
+ // Clear the output buffer
+ memset(pOut, 0, (outFrameCount * mLPANumChannels * sizeof(int16_t)));
+ } else {
+ // Copy input buffer content to the output buffer
+ memcpy(pOut, pIn, (outFrameCount * mLPANumChannels * sizeof(int16_t)));
+ }
+
+ mLPAEffectChain->process_l();
+
+ mLPAEffectChain->unlock();
+
+ // Update input and output buffer pointers
+ pIn += (outFrameCount * mLPANumChannels);
+ pOut += (outFrameCount * mLPANumChannels);
+ frameCount -= outFrameCount;
+ }
+ }
+
+ if (!numEffects && !force) {
+ ALOGV("applyEffectsOn: There are no effects to be applied");
+ if(inBuffer != outBuffer) {
+ // No effect applied so just copy input buffer to output buffer
+ memcpy(outBuffer, inBuffer, size);
+ }
+ }
+ return true;
+}
+
+void *AudioFlinger::DirectAudioTrack::EffectsThreadWrapper(void *me) {
+ static_cast<DirectAudioTrack *>(me)->EffectsThreadEntry();
+ return NULL;
+}
+
+void AudioFlinger::DirectAudioTrack::EffectsThreadEntry() {
+ while(1) {
+ mEffectLock.lock();
+ if (!mEffectConfigChanged && !mKillEffectsThread) {
+ mEffectCv.wait(mEffectLock);
+ }
+ if(mKillEffectsThread) {
+ mEffectLock.unlock();
+ break;
+ }
+ if (mEffectConfigChanged) {
+ mEffectConfigChanged = false;
+ if (mFlag & AUDIO_OUTPUT_FLAG_LPA) {
+ for ( List<BufferInfo>::iterator it = mEffectsPool.begin();
+ it != mEffectsPool.end(); it++) {
+ ALOGV("ete: calling applyEffectsOn buff %x",it->localBuf);
+ bool isEffectsApplied = mAudioFlinger->applyEffectsOn(
+ static_cast<void *>(this),
+ (int16_t *)it->localBuf,
+ (int16_t *)mEffectsThreadScratchBuffer,
+ it->bytesToWrite,
+ false);
+ if (isEffectsApplied == true){
+ ALOGV("ete:dsp updated for local buf %x",it->localBuf);
+ memcpy(it->dspBuf, mEffectsThreadScratchBuffer, it->bytesToWrite);
+ }
+ else
+ ALOGV("ete:dsp updated for local buf %x SKIPPED",it->localBuf);
+
+ if (mEffectConfigChanged) {
+ ALOGE("ete:effects changed, abort effects application");
+ break;
+ }
+ }
+#ifdef SRS_PROCESSING
+ } else if (mFlag & AUDIO_OUTPUT_FLAG_TUNNEL) {
+ ALOGV("applying effects for TUNNEL");
+ char buffer[2];
+ //dummy buffer to ensure the SRS processing takes place
+ // The API mandates Sample rate and channel mode. Hence
+ // defaulted the sample rate channel mode to 48000 and 2 respectively
+ POSTPRO_PATCH_ICS_OUTPROC_DIRECT_SAMPLES(static_cast<void *>(this),
+ AUDIO_FORMAT_PCM_16_BIT,
+ (int16_t*)buffer, 2, 48000, 2);
+#endif
+ }
+ }
+ mEffectLock.unlock();
+ }
+ ALOGV("Effects thread is dead");
+ mEffectsThreadAlive = false;
+}
+
+void AudioFlinger::DirectAudioTrack::requestAndWaitForEffectsThreadExit() {
+ if (!mEffectsThreadAlive)
+ return;
+ mKillEffectsThread = true;
+ mEffectCv.signal();
+ pthread_join(mEffectsThread,NULL);
+ ALOGV("effects thread killed");
+}
+
+void AudioFlinger::DirectAudioTrack::createEffectThread() {
+ //Create the effects thread
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+ mEffectsThreadAlive = true;
+ ALOGV("Creating Effects Thread");
+ pthread_create(&mEffectsThread, &attr, EffectsThreadWrapper, this);
+}
+#endif
+
}; // namespace android
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index b717857..5ad312b 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -1,5 +1,6 @@
/*
-**
+** Copyright (c) 2013, The Linux Foundation. All rights reserved.
+** Not a Contribution.
** Copyright 2012, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
@@ -68,7 +69,14 @@
void *pReplyData);
void reset_l();
+#ifdef QCOM_HARDWARE
+ status_t configure(bool isForLPA = false,
+ int sampleRate = 0,
+ int channelCount = 0,
+ int frameCount = 0);
+#else
status_t configure();
+#endif
status_t init();
effect_state state() const {
return mState;
@@ -119,6 +127,10 @@
{ return (mDescriptor.flags & EFFECT_FLAG_OFFLOAD_SUPPORTED) != 0; }
status_t setOffloaded(bool offloaded, audio_io_handle_t io);
bool isOffloaded() const;
+#ifdef QCOM_HARDWARE
+ bool isOnLPA() { return mIsForLPA;}
+ void setLPAFlag(bool isForLPA) {mIsForLPA = isForLPA; }
+#endif
void dump(int fd, const Vector<String16>& args);
@@ -153,6 +165,9 @@
uint32_t mDisableWaitCnt; // current process() calls count during disable period.
bool mSuspended; // effect is suspended: temporarily disabled by framework
bool mOffloaded; // effect is currently offloaded to the audio DSP
+#ifdef QCOM_HARDWARE
+ bool mIsForLPA;
+#endif
};
// The EffectHandle class implements the IEffect interface. It provides resources
@@ -262,12 +277,18 @@
status_t addEffect_l(const sp<EffectModule>& handle);
size_t removeEffect_l(const sp<EffectModule>& handle);
+#ifdef QCOM_HARDWARE
+ size_t getNumEffects() { return mEffects.size(); }
+#endif
int sessionId() const { return mSessionId; }
void setSessionId(int sessionId) { mSessionId = sessionId; }
sp<EffectModule> getEffectFromDesc_l(effect_descriptor_t *descriptor);
sp<EffectModule> getEffectFromId_l(int id);
+#ifdef QCOM_HARDWARE
+ sp<EffectModule> getEffectFromIndex_l(int idx);
+#endif
sp<EffectModule> getEffectFromType_l(const effect_uuid_t *type);
bool setVolume_l(uint32_t *left, uint32_t *right);
void setDevice_l(audio_devices_t device);
@@ -317,6 +338,10 @@
void dump(int fd, const Vector<String16>& args);
+#ifdef QCOM_HARDWARE
+ bool isForLPATrack() {return mIsForLPATrack; }
+ void setLPAFlag(bool flag) {mIsForLPATrack = flag;}
+#endif
protected:
friend class AudioFlinger; // for mThread, mEffects
@@ -365,6 +390,9 @@
uint32_t mNewLeftVolume; // new volume on left channel
uint32_t mNewRightVolume; // new volume on right channel
uint32_t mStrategy; // strategy for this effect chain
+#ifdef QCOM_HARDWARE
+ bool mIsForLPATrack;
+#endif
// mSuspendedEffects lists all effects currently suspended in the chain.
// Use effect type UUID timelow field as key. There is no real risk of identical
// timeLow fields among effect type UUIDs.
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index 57de568..8e20d5a 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -28,6 +28,9 @@
audio_format_t format,
audio_channel_mask_t channelMask,
size_t frameCount,
+#ifdef QCOM_HARDWARE
+ uint32_t flags,
+#endif
int sessionId,
int uid);
virtual ~RecordTrack();
@@ -58,6 +61,9 @@
int64_t pts = kInvalidPTS);
// releaseBuffer() not overridden
+#ifdef QCOM_HARDWARE
+ track_flags_t mFlags;
+#endif
bool mOverflow; // overflow on most recent attempt to fill client buffer
AudioRecordServerProxy* mAudioRecordServerProxy;
};
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 3d657b3..045cc29 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1,5 +1,6 @@
/*
-**
+** Copyright (c) 2013, The Linux Foundation. All rights reserved.
+** Not a Contribution.
** Copyright 2012, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
@@ -64,6 +65,11 @@
#include <cpustats/ThreadCpuUsage.h>
#endif
+#ifdef SRS_PROCESSING
+#include "srs_processing.h"
+#include "postpro_patch_ics.h"
+#endif
+
// ----------------------------------------------------------------------------
// Note: the following macro is used for extremely verbose logging message. In
@@ -79,6 +85,11 @@
#define ALOGVV(a...) do { } while(0)
#endif
+#ifdef QCOM_HARDWARE
+#define DIRECT_TRACK_EOS 1
+#define DIRECT_TRACK_HW_FAIL 6
+static const char lockName[] = "DirectTrack";
+#endif
namespace android {
// retry counts for buffer fill timeout
@@ -341,6 +352,13 @@
return status;
}
+#ifdef QCOM_HARDWARE
+void AudioFlinger::ThreadBase::effectConfigChanged() {
+ ALOGV("New effect is being added to LPA chain, Notifying LPA Direct Track");
+ mAudioFlinger->audioConfigChanged_l(AudioSystem::EFFECT_CONFIG_CHANGED, 0, NULL);
+}
+#endif
+
void AudioFlinger::ThreadBase::sendIoConfigEvent(int event, int param)
{
Mutex::Autolock _l(mLock);
@@ -794,6 +812,21 @@
addEffectChain_l(chain);
chain->setStrategy(getStrategyForSession_l(sessionId));
chainCreated = true;
+#ifdef QCOM_HARDWARE
+ if(sessionId == mAudioFlinger->mLPASessionId) {
+ // Clear reference to previous effect chain if any
+ if(mAudioFlinger->mLPAEffectChain.get()) {
+ mAudioFlinger->mLPAEffectChain.clear();
+ }
+ ALOGV("New EffectChain is created for LPA session ID %d", sessionId);
+ mAudioFlinger->mLPAEffectChain = chain;
+ chain->setLPAFlag(true);
+ // For LPA, the volume will be applied in DSP. No need for volume
+ // control in the Effect chain, so setting it to unity.
+ uint32_t volume = 0x1000000; // Equals to 1.0 in 8.24 format
+ chain->setVolume_l(&volume,&volume);
+ }
+#endif
} else {
effect = chain->getEffectFromDesc_l(desc);
}
@@ -822,7 +855,11 @@
}
effectCreated = true;
+#ifdef QCOM_HARDWARE
+ effect->setDevice(mAudioFlinger->mLPASessionId == sessionId ? mAudioFlinger->mDirectDevice:mOutDevice);
+#else
effect->setDevice(mOutDevice);
+#endif
effect->setDevice(mInDevice);
effect->setMode(mAudioFlinger->getMode());
effect->setAudioSource(mAudioSource);
@@ -937,8 +974,20 @@
Vector< sp<AudioFlinger::EffectChain> >& effectChains)
{
effectChains = mEffectChains;
+#ifdef QCOM_HARDWARE
+ mAudioFlinger->mAllChainsLocked = true;
+#endif
for (size_t i = 0; i < mEffectChains.size(); i++) {
- mEffectChains[i]->lock();
+#ifdef QCOM_HARDWARE
+ if (mEffectChains[i] != mAudioFlinger->mLPAEffectChain) {
+#else
+ mEffectChains[i]->lock();
+#endif
+#ifdef QCOM_HARDWARE
+ } else {
+ mAudioFlinger-> mAllChainsLocked = false;
+ }
+#endif
}
}
@@ -946,7 +995,10 @@
const Vector< sp<AudioFlinger::EffectChain> >& effectChains)
{
for (size_t i = 0; i < effectChains.size(); i++) {
- effectChains[i]->unlock();
+#ifdef QCOM_HARDWARE
+ if (mAudioFlinger->mAllChainsLocked || effectChains[i] != mAudioFlinger->mLPAEffectChain)
+#endif
+ effectChains[i]->unlock();
}
}
@@ -1248,7 +1300,10 @@
// This is probably too conservative, but legacy application code may depend on it.
// If you change this calculation, also review the start threshold which is related.
uint32_t latencyMs = mOutput->stream->get_latency(mOutput->stream);
- uint32_t minBufCount = latencyMs / ((1000 * mNormalFrameCount) / mSampleRate);
+ uint32_t minBufCount = 0;
+ if (mSampleRate) {
+ minBufCount = latencyMs / ((1000 * mNormalFrameCount) / mSampleRate);
+ }
if (minBufCount < 2) {
minBufCount = 2;
}
@@ -1260,7 +1315,17 @@
}
if (mType == DIRECT) {
+#ifdef QCOM_HARDWARE
+ if (((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_PCM)
+ ||((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AMR_NB)
+ ||((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AMR_WB)
+ ||((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_EVRC)
+ ||((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_EVRCB)
+ ||((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_EVRCWB)
+ ||((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_EVRCNW)) {
+#else
if ((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_PCM) {
+#endif
if (sampleRate != mSampleRate || format != mFormat || channelMask != mChannelMask) {
ALOGE("createTrack_l() Bad parameter: sampleRate %u format %d, channelMask 0x%08x "
"for output %p with format %d",
@@ -2153,6 +2218,13 @@
standbyTime = systemTime();
+#ifdef SRS_PROCESSING
+if (mType == MIXER) {
+ POSTPRO_PATCH_ICS_OUTPROC_MIX_INIT(this, gettid());
+ } else if (mType == DUPLICATING) {
+ POSTPRO_PATCH_ICS_OUTPROC_DUPE_INIT(this, gettid());
+ }
+#endif
// MIXER
nsecs_t lastWarning = 0;
@@ -2314,8 +2386,14 @@
// only process effects if we're going to write
if (sleepTime == 0 && mType != OFFLOAD) {
for (size_t i = 0; i < effectChains.size(); i ++) {
- effectChains[i]->process_l();
- }
+#ifdef QCOM_HARDWARE
+ if (effectChains[i] != mAudioFlinger->mLPAEffectChain) {
+#endif
+ effectChains[i]->process_l();
+#ifdef QCOM_HARDWARE
+ }
+#endif
+ }
}
}
// Process effect chains for offloaded thread even if no audio
@@ -2334,6 +2412,15 @@
if (!waitingAsyncCallback()) {
// sleepTime == 0 means we must write to audio hardware
if (sleepTime == 0) {
+#ifdef SRS_PROCESSING
+ if (mType == MIXER) {
+ POSTPRO_PATCH_ICS_OUTPROC_MIX_SAMPLES(this, mFormat, mMixBuffer,
+ mixBufferSize, mSampleRate, mChannelCount);
+ } else if (mType == DUPLICATING) {
+ POSTPRO_PATCH_ICS_OUTPROC_DUPE_SAMPLES(this, mFormat, mMixBuffer,
+ mixBufferSize, mSampleRate, mChannelCount);
+ }
+#endif
if (mBytesRemaining) {
ssize_t ret = threadLoop_write();
if (ret < 0) {
@@ -2395,6 +2482,13 @@
}
}
+#ifdef SRS_PROCESSING
+ if (mType == MIXER) {
+ POSTPRO_PATCH_ICS_OUTPROC_MIX_EXIT(this, gettid());
+ } else if (mType == DUPLICATING) {
+ POSTPRO_PATCH_ICS_OUTPROC_DUPE_EXIT(this, gettid());
+ }
+#endif
releaseWakeLock();
mWakeLockUids.clear();
mActiveTracksGeneration++;
@@ -2636,7 +2730,10 @@
{
if (mFastMixer != NULL) {
MonoPipe *pipe = (MonoPipe *)mPipeSink.get();
- latency += (pipe->getAvgFrames() * 1000) / mSampleRate;
+ if(mSampleRate)
+ latency += (pipe->getAvgFrames() * 1000) / mSampleRate;
+ else
+ ALOGW("SampleRate is 0");
}
return latency;
}
@@ -2754,11 +2851,13 @@
int64_t pts;
status_t status = INVALID_OPERATION;
+#ifndef ICS_AUDIO_BLOB
if (mNormalSink != 0) {
status = mNormalSink->getNextWriteTimestamp(&pts);
} else {
status = mOutputSink->getNextWriteTimestamp(&pts);
}
+#endif
if (status != NO_ERROR) {
pts = AudioBufferProvider::kInvalidPTS;
@@ -3024,7 +3123,12 @@
desiredFrames = mNormalFrameCount;
} else {
// +1 for rounding and +1 for additional sample needed for interpolation
- desiredFrames = (mNormalFrameCount * sr) / mSampleRate + 1 + 1;
+ if (mSampleRate) {
+ desiredFrames = (mNormalFrameCount * sr) / mSampleRate + 1 + 1;
+ } else {
+ desiredFrames = 2;
+ ALOGW("SampleRate is 0");
+ }
// add frames already consumed but not yet released by the resampler
// because cblk->framesReady() will include these frames
desiredFrames += mAudioMixer->getUnreleasedFrames(track->name());
@@ -3350,6 +3454,9 @@
AudioParameter param = AudioParameter(keyValuePair);
int value;
+#ifdef SRS_PROCESSING
+ POSTPRO_PATCH_ICS_OUTPROC_MIX_ROUTE(this, param, value);
+#endif
if (param.getInt(String8(AudioParameter::keySamplingRate), value) == NO_ERROR) {
reconfig = true;
}
@@ -3655,7 +3762,8 @@
size_t audioHALFrames = (latency_l() * mSampleRate) / 1000;
size_t framesWritten = mBytesWritten / mFrameSize;
if (mStandby || !last ||
- track->presentationComplete(framesWritten, audioHALFrames)) {
+ track->presentationComplete(framesWritten, audioHALFrames) ||
+ track->isTerminated()) {
if (track->isStopped()) {
track->reset();
}
@@ -3936,7 +4044,8 @@
: DirectOutputThread(audioFlinger, output, id, device, OFFLOAD),
mHwPaused(false),
mFlushPending(false),
- mPausedBytesRemaining(0)
+ mPausedBytesRemaining(0),
+ mPreviousTrack(NULL)
{
//FIXME: mStandby should be set to true by ThreadBase constructor
mStandby = true;
@@ -4282,7 +4391,10 @@
{
Mutex::Autolock _l(mLock);
// FIXME explain this formula
- size_t frameCount = (3 * mNormalFrameCount * mSampleRate) / thread->sampleRate();
+ int sampleRate = thread->sampleRate();
+ size_t frameCount = 0;
+ if (sampleRate)
+ frameCount = (3 * mNormalFrameCount * mSampleRate) / thread->sampleRate();
OutputTrack *outputTrack = new OutputTrack(thread,
this,
mSampleRate,
@@ -4380,7 +4492,7 @@
ThreadBase(audioFlinger, id, outDevice, inDevice, RECORD),
mInput(input), mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpInBuffer(NULL),
// mRsmpInIndex and mBufferSize set by readInputParameters()
- mReqChannelCount(popcount(channelMask)),
+ mReqChannelCount(getInputChannelCount(channelMask)),
mReqSampleRate(sampleRate)
// mBytesRead is only meaningful while active, and so is cleared in start()
// (but might be better to also clear here for dump?)
@@ -4529,8 +4641,29 @@
}
}
}
- if (framesOut && mFrameCount == mRsmpInIndex) {
+ if (framesOut && (mFrameCount == mRsmpInIndex)) {
void *readInto;
+#ifdef QCOM_HARDWARE
+ int InputBytes;
+ /*Fix me: How does framesOut become 0 in this condition */
+ if (( framesOut != mFrameCount) &&
+ ((mFormat != AUDIO_FORMAT_PCM_16_BIT)&&
+ (!(mActiveTrack->mFlags & TRACK_VOICE_COMMUNICATION)))) {
+ readInto = buffer.raw;
+ InputBytes = buffer.frameCount * mFrameSize;
+ } else if (framesOut == mFrameCount &&
+ (mChannelCount == mReqChannelCount ||
+ ((mFormat != AUDIO_FORMAT_PCM_16_BIT) &&
+ (!(mActiveTrack->mFlags & TRACK_VOICE_COMMUNICATION))))) {
+ readInto = buffer.raw;
+ InputBytes = mBufferSize;
+ framesOut = 0;
+ } else {
+ readInto = mRsmpInBuffer;
+ mRsmpInIndex = 0;
+ InputBytes = mBufferSize;
+ }
+#else
if (framesOut == mFrameCount && mChannelCount == mReqChannelCount) {
readInto = buffer.raw;
framesOut = 0;
@@ -4538,8 +4671,13 @@
readInto = mRsmpInBuffer;
mRsmpInIndex = 0;
}
+#endif
mBytesRead = mInput->stream->read(mInput->stream, readInto,
+#ifdef QCOM_HARDWARE
+ InputBytes);
+#else
mBufferSize);
+#endif
if (mBytesRead <= 0) {
if ((mBytesRead < 0) && (mActiveTrack->mState == TrackBase::ACTIVE))
{
@@ -4720,7 +4858,10 @@
// If you change this calculation, also review the start threshold which is related.
uint32_t latencyMs = 50; // FIXME mInput->stream->get_latency(mInput->stream);
size_t mNormalFrameCount = 2048; // FIXME
- uint32_t minBufCount = latencyMs / ((1000 * mNormalFrameCount) / mSampleRate);
+ uint32_t minBufCount = 0;
+ if (mSampleRate) {
+ minBufCount = latencyMs / ((1000 * mNormalFrameCount) / mSampleRate);
+ }
if (minBufCount < 2) {
minBufCount = 2;
}
@@ -4737,7 +4878,11 @@
Mutex::Autolock _l(mLock);
track = new RecordTrack(this, client, sampleRate,
+#ifdef QCOM_HARDWARE
+ format, channelMask, frameCount, *flags, sessionId, uid);
+#else
format, channelMask, frameCount, sessionId, uid);
+#endif
if (track->getCblk() == 0) {
ALOGE("createRecordTrack_l() no control block");
@@ -5078,7 +5223,7 @@
}
}
if (param.getInt(String8(AudioParameter::keyChannels), value) == NO_ERROR) {
- reqChannelCount = popcount(value);
+ reqChannelCount = getInputChannelCount(value);
reconfig = true;
}
if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) {
@@ -5142,7 +5287,7 @@
reqFormat == AUDIO_FORMAT_PCM_16_BIT &&
(mInput->stream->common.get_sample_rate(&mInput->stream->common)
<= (2 * reqSamplingRate)) &&
- popcount(mInput->stream->common.get_channels(&mInput->stream->common))
+ getInputChannelCount(mInput->stream->common.get_channels(&mInput->stream->common))
<= FCC_2 &&
(reqChannelCount <= FCC_2)) {
status = NO_ERROR;
@@ -5211,11 +5356,13 @@
mSampleRate = mInput->stream->common.get_sample_rate(&mInput->stream->common);
mChannelMask = mInput->stream->common.get_channels(&mInput->stream->common);
- mChannelCount = popcount(mChannelMask);
+ mChannelCount = (uint16_t)getInputChannelCount(mChannelMask);
mFormat = mInput->stream->common.get_format(&mInput->stream->common);
+#ifndef QCOM_HARDWARE
if (mFormat != AUDIO_FORMAT_PCM_16_BIT) {
ALOGE("HAL format %d not supported; must be AUDIO_FORMAT_PCM_16_BIT", mFormat);
}
+#endif
mFrameSize = audio_stream_frame_size(&mInput->stream->common);
mBufferSize = mInput->stream->common.get_buffer_size(&mInput->stream->common);
mFrameCount = mBufferSize / mFrameSize;
@@ -5335,4 +5482,321 @@
return 0;
}
+#ifdef QCOM_HARDWARE
+// ----------------------------------------------------------------------------
+
+AudioFlinger::DirectAudioTrack::DirectAudioTrack(const sp<AudioFlinger>& audioFlinger,
+ int output, AudioSessionDescriptor *outputDesc,
+ IDirectTrackClient* client, audio_output_flags_t outflag)
+ : BnDirectTrack(), mIsPaused(false), mAudioFlinger(audioFlinger), mOutput(output), mOutputDesc(outputDesc),
+ mClient(client), mEffectConfigChanged(false), mKillEffectsThread(false), mFlag(outflag),
+ mEffectsThreadScratchBuffer(NULL)
+{
+#ifdef SRS_PROCESSING
+ ALOGD("SRS_Processing - DirectAudioTrack - OutNotify_Init: %p TID %d\n", this, gettid());
+ POSTPRO_PATCH_ICS_OUTPROC_DIRECT_INIT(this, gettid());
+ SRS_Processing::ProcessOutRoute(SRS_Processing::AUTO, this, outputDesc->device);
+#endif
+ if (mFlag & AUDIO_OUTPUT_FLAG_LPA) {
+ ALOGV("create effects thread for LPA");
+ createEffectThread();
+ allocateBufPool();
+#ifdef SRS_PROCESSING
+ } else if (mFlag & AUDIO_OUTPUT_FLAG_TUNNEL) {
+ ALOGV("create effects thread for TUNNEL");
+ createEffectThread();
+#endif
+ }
+ outputDesc->mVolumeScale = 1.0;
+ mDeathRecipient = new PMDeathRecipient(this);
+ acquireWakeLock();
+}
+
+void AudioFlinger::DirectAudioTrack::signalEffect() {
+ if (mFlag & AUDIO_OUTPUT_FLAG_LPA){
+ mEffectConfigChanged = true;
+ mEffectCv.signal();
+ }
+#ifdef SRS_PROCESSING
+ if (mFlag & AUDIO_OUTPUT_FLAG_TUNNEL){
+ mEffectConfigChanged = true;
+ mEffectCv.signal();
+ }
+#endif
+}
+
+AudioFlinger::DirectAudioTrack::~DirectAudioTrack() {
+#ifdef SRS_PROCESSING
+ ALOGD("SRS_Processing - DirectAudioTrack - OutNotify_Init: %p TID %d\n", this, gettid());
+ POSTPRO_PATCH_ICS_OUTPROC_DIRECT_EXIT(this, gettid());
+#endif
+ if (mFlag & AUDIO_OUTPUT_FLAG_LPA) {
+ requestAndWaitForEffectsThreadExit();
+ mAudioFlinger->deleteEffectSession();
+ deallocateBufPool();
+#ifdef SRS_PROCESSING
+ } else if (mFlag & AUDIO_OUTPUT_FLAG_TUNNEL) {
+ requestAndWaitForEffectsThreadExit();
+ mAudioFlinger->deleteEffectSession();
+#endif
+ }
+ AudioSystem::releaseOutput(mOutput);
+ releaseWakeLock();
+
+ {
+ Mutex::Autolock _l(pmLock);
+ if (mPowerManager != 0) {
+ sp<IBinder> binder = mPowerManager->asBinder();
+ binder->unlinkToDeath(mDeathRecipient);
+ }
+ }
+}
+
+status_t AudioFlinger::DirectAudioTrack::start() {
+ AudioSystem::startOutput(mOutput, (audio_stream_type_t)mOutputDesc->mStreamType);
+ if(mIsPaused) {
+ mIsPaused = false;
+ mOutputDesc->stream->start(mOutputDesc->stream);
+ }
+ mOutputDesc->mActive = true;
+ mOutputDesc->stream->set_volume(mOutputDesc->stream,
+ mOutputDesc->mVolumeLeft * mOutputDesc->mVolumeScale,
+ mOutputDesc->mVolumeRight* mOutputDesc->mVolumeScale);
+ return NO_ERROR;
+}
+
+void AudioFlinger::DirectAudioTrack::stop() {
+ ALOGV("DirectAudioTrack::stop");
+ mOutputDesc->mActive = false;
+ mOutputDesc->stream->stop(mOutputDesc->stream);
+ AudioSystem::stopOutput(mOutput, (audio_stream_type_t)mOutputDesc->mStreamType);
+}
+
+void AudioFlinger::DirectAudioTrack::pause() {
+ if(!mIsPaused) {
+ mIsPaused = true;
+ mOutputDesc->stream->pause(mOutputDesc->stream);
+ mOutputDesc->mActive = false;
+ AudioSystem::stopOutput(mOutput, (audio_stream_type_t)mOutputDesc->mStreamType);
+ }
+}
+
+ssize_t AudioFlinger::DirectAudioTrack::write(const void *buffer, size_t size) {
+ ALOGV("Writing to AudioSessionOut");
+ int isAvail = 0;
+ mOutputDesc->stream->is_buffer_available(mOutputDesc->stream, &isAvail);
+ if (!isAvail) {
+ return 0;
+ }
+
+ if (mFlag & AUDIO_OUTPUT_FLAG_LPA) {
+ mEffectLock.lock();
+ List<BufferInfo>::iterator it = mEffectsPool.begin();
+ BufferInfo buf = *it;
+ mEffectsPool.erase(it);
+ memcpy((char *) buf.localBuf, (char *)buffer, size);
+ buf.bytesToWrite = size;
+ mEffectsPool.push_back(buf);
+ mAudioFlinger->applyEffectsOn(static_cast<void *>(this),
+ (int16_t*)buf.localBuf, (int16_t*)buffer, (int)size, true);
+ mEffectLock.unlock();
+ }
+ ALOGV("out of Writing to AudioSessionOut");
+ return mOutputDesc->stream->write(mOutputDesc->stream, buffer, size);
+}
+
+void AudioFlinger::DirectAudioTrack::flush() {
+ if (mFlag & AUDIO_OUTPUT_FLAG_LPA) {
+ mEffectLock.lock();
+ mEffectsPool.clear();
+ mEffectsPool = mBufPool;
+ mEffectLock.unlock();
+ }
+ mOutputDesc->stream->flush(mOutputDesc->stream);
+}
+
+void AudioFlinger::DirectAudioTrack::mute(bool muted) {
+}
+
+void AudioFlinger::DirectAudioTrack::setVolume(float left, float right) {
+ ALOGV("DirectAudioTrack::setVolume left: %f, right: %f", left, right);
+ if(mOutputDesc) {
+ mOutputDesc->mVolumeLeft = left;
+ mOutputDesc->mVolumeRight = right;
+ if(mOutputDesc->mActive && mOutputDesc->stream) {
+ mOutputDesc->stream->set_volume(mOutputDesc->stream,
+ left * mOutputDesc->mVolumeScale,
+ right* mOutputDesc->mVolumeScale);
+ } else {
+ ALOGD("stream is not active, so cache and send when stream is active");
+ }
+ } else {
+ ALOGD("output descriptor is not valid to set the volume");
+ }
+}
+
+int64_t AudioFlinger::DirectAudioTrack::getTimeStamp() {
+ int64_t time;
+ mOutputDesc->stream->get_next_write_timestamp(mOutputDesc->stream, &time);
+ ALOGV("Timestamp %lld",time);
+ return time;
+}
+
+void AudioFlinger::DirectAudioTrack::postEOS(int64_t delayUs) {
+ if (delayUs == 0 ) {
+ ALOGV("Notify Audio Track of EOS event");
+ mClient->notify(DIRECT_TRACK_EOS);
+ } else {
+ ALOGV("Notify Audio Track of hardware failure event");
+ mClient->notify(DIRECT_TRACK_HW_FAIL);
+ }
+}
+
+void AudioFlinger::DirectAudioTrack::allocateBufPool() {
+ void *dsp_buf = NULL;
+ void *local_buf = NULL;
+
+ //1. get the ion buffer information
+ struct buf_info* buf = NULL;
+ mOutputDesc->stream->get_buffer_info(mOutputDesc->stream, &buf);
+ ALOGV("get buffer info %p",buf);
+ if (!buf) {
+ ALOGV("buffer is NULL");
+ return;
+ }
+ int nSize = buf->bufsize;
+ int bufferCount = buf->nBufs;
+
+ //2. allocate the buffer pool, allocate local buffers
+ for (int i = 0; i < bufferCount; i++) {
+ dsp_buf = (void *)buf->buffers[i];
+ local_buf = malloc(nSize);
+ memset(local_buf, 0, nSize);
+ // Store this information for internal mapping / maintanence
+ BufferInfo buf(local_buf, dsp_buf, nSize);
+ buf.bytesToWrite = 0;
+ mBufPool.push_back(buf);
+ mEffectsPool.push_back(buf);
+
+ ALOGV("The MEM that is allocated buffer is %x, size %d",(unsigned int)dsp_buf,nSize);
+ }
+
+ mEffectsThreadScratchBuffer = malloc(nSize);
+ ALOGV("effectsThreadScratchBuffer = %x",mEffectsThreadScratchBuffer);
+
+ free(buf);
+}
+
+void AudioFlinger::DirectAudioTrack::deallocateBufPool() {
+
+ //1. Deallocate the local memory
+ //2. Remove all the buffers from bufpool
+ mEffectLock.lock();
+ while (!mBufPool.empty()) {
+ List<BufferInfo>::iterator it = mBufPool.begin();
+ BufferInfo &memBuffer = *it;
+ // free the local buffer corresponding to mem buffer
+ if (memBuffer.localBuf) {
+ free(memBuffer.localBuf);
+ memBuffer.localBuf = NULL;
+ }
+ ALOGV("Removing from bufpool");
+ mBufPool.erase(it);
+ }
+ mEffectsPool.clear();
+ mEffectLock.unlock();
+
+ free(mEffectsThreadScratchBuffer);
+ mEffectsThreadScratchBuffer = NULL;
+}
+
+status_t AudioFlinger::DirectAudioTrack::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ return BnDirectTrack::onTransact(code, data, reply, flags);
+}
+
+AudioFlinger::DirectAudioTrack::AudioFlingerDirectTrackClient::AudioFlingerDirectTrackClient(void *obj)
+{
+ ALOGV("AudioFlinger::DirectAudioTrack::AudioFlingerDirectTrackClient");
+ pBaseClass = (DirectAudioTrack*)obj;
+}
+
+void AudioFlinger::DirectAudioTrack::AudioFlingerDirectTrackClient::binderDied(const wp<IBinder>& who) {
+ pBaseClass->mAudioFlinger.clear();
+ ALOGW("AudioFlinger server died!");
+}
+
+void AudioFlinger::DirectAudioTrack::AudioFlingerDirectTrackClient
+ ::ioConfigChanged(int event, audio_io_handle_t ioHandle, const void *param2) {
+ ALOGV("ioConfigChanged() event %d", event);
+ if (event == AudioSystem::EFFECT_CONFIG_CHANGED) {
+ ALOGV("Received notification for change in effect module");
+ // Seek to current media time - flush the decoded buffers with the driver
+ pBaseClass->mEffectConfigChanged = true;
+ // Signal effects thread to re-apply effects
+ ALOGV("Signalling Effects Thread");
+ pBaseClass->mEffectCv.signal();
+
+ }
+ ALOGV("ioConfigChanged Out");
+}
+
+void AudioFlinger::DirectAudioTrack::acquireWakeLock()
+{
+ Mutex::Autolock _l(pmLock);
+
+ if (mPowerManager == 0) {
+ // use checkService() to avoid blocking if power service is not up yet
+ sp<IBinder> binder =
+ defaultServiceManager()->checkService(String16("power"));
+ if (binder == 0) {
+ ALOGW("Thread %s cannot connect to the power manager service", lockName);
+ } else {
+ mPowerManager = interface_cast<IPowerManager>(binder);
+ binder->linkToDeath(mDeathRecipient);
+ }
+ }
+ if (mPowerManager != 0 && mWakeLockToken == 0) {
+ sp<IBinder> binder = new BBinder();
+ status_t status = mPowerManager->acquireWakeLock(POWERMANAGER_PARTIAL_WAKE_LOCK,
+ binder,
+ String16(lockName),
+ String16("media"));
+ if (status == NO_ERROR) {
+ mWakeLockToken = binder;
+ }
+ ALOGV("acquireWakeLock() status %d", status);
+ }
+}
+
+void AudioFlinger::DirectAudioTrack::releaseWakeLock()
+{
+ Mutex::Autolock _l(pmLock);
+
+ if (mWakeLockToken != 0) {
+ ALOGV("releaseWakeLock()");
+ if (mPowerManager != 0) {
+ mPowerManager->releaseWakeLock(mWakeLockToken, 0);
+ }
+ mWakeLockToken.clear();
+ }
+}
+
+void AudioFlinger::DirectAudioTrack::clearPowerManager()
+{
+ releaseWakeLock();
+ Mutex::Autolock _l(pmLock);
+ mPowerManager.clear();
+}
+
+void AudioFlinger::DirectAudioTrack::PMDeathRecipient::binderDied(const wp<IBinder>& who)
+{
+ parentClass->clearPowerManager();
+ ALOGW("power manager service died !!!");
+}
+
+// ----------------------------------------------------------------------------
+#endif
+
}; // namespace android
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 207f1eb..8036a28 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -1,5 +1,6 @@
/*
-**
+** Copyright (c) 2013, The Linux Foundation. All rights reserved.
+** Not a Contribution.
** Copyright 2012, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
@@ -137,6 +138,9 @@
virtual status_t setParameters(const String8& keyValuePairs);
virtual String8 getParameters(const String8& keys) = 0;
virtual void audioConfigChanged_l(int event, int param = 0) = 0;
+#ifdef QCOM_HARDWARE
+ void effectConfigChanged();
+#endif
void sendIoConfigEvent(int event, int param = 0);
void sendIoConfigEvent_l(int event, int param = 0);
void sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio);
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index cd201d9..ab83955 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -43,6 +43,9 @@
audio_format_t format,
audio_channel_mask_t channelMask,
size_t frameCount,
+#ifdef QCOM_HARDWARE
+ uint32_t flags,
+#endif
const sp<IMemory>& sharedBuffer,
int sessionId,
int uid,
@@ -132,7 +135,9 @@
// 8-bit PCM samples are stored as 16-bit
const size_t mFrameCount;// size of track buffer given at createTrack() or
// openRecord(), and then adjusted as needed
-
+#ifdef QCOM_HARDWARE
+ uint32_t mFlags;
+#endif
const int mSessionId;
int mUid;
Vector < sp<SyncEvent> >mSyncEvents;
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index d6b9908..59b611a 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -66,6 +66,9 @@
audio_format_t format,
audio_channel_mask_t channelMask,
size_t frameCount,
+#ifdef QCOM_HARDWARE
+ uint32_t flags,
+#endif
const sp<IMemory>& sharedBuffer,
int sessionId,
int clientUid,
@@ -80,9 +83,17 @@
mFormat(format),
mChannelMask(channelMask),
mChannelCount(popcount(channelMask)),
+#ifdef QCOM_HARDWARE
+ mFrameSize((audio_is_linear_pcm(format) || audio_is_supported_compressed(format)) ?
+ ((flags & IAudioFlinger::TRACK_VOICE_COMMUNICATION)? mChannelCount * sizeof(int16_t) : mChannelCount * audio_bytes_per_sample(format)) : sizeof(int8_t)),
+#else
mFrameSize(audio_is_linear_pcm(format) ?
mChannelCount * audio_bytes_per_sample(format) : sizeof(int8_t)),
+#endif
mFrameCount(frameCount),
+#ifdef QCOM_HARDWARE
+ mFlags(0),
+#endif
mSessionId(sessionId),
mIsOut(isOut),
mServerProxy(NULL),
@@ -109,7 +120,31 @@
// ALOGD("Creating track with %d buffers @ %d bytes", bufferCount, bufferSize);
size_t size = sizeof(audio_track_cblk_t);
+#ifdef QCOM_HARDWARE
+ uint8_t channelCount = popcount(channelMask);
+ size_t bufferSize = 0;
+ if (flags & IAudioFlinger::TRACK_VOICE_COMMUNICATION) {
+ bufferSize = roundup(frameCount) * channelCount * mFrameSize;
+ } else {
+ if ( (format == AUDIO_FORMAT_PCM_16_BIT) ||
+ (format == AUDIO_FORMAT_PCM_8_BIT)) {
+ bufferSize = frameCount * channelCount * sizeof(int16_t);
+ } else if (format == AUDIO_FORMAT_AMR_NB) {
+ bufferSize = frameCount * channelCount * AMR_FRAMESIZE; // full rate frame size
+ } else if (format == AUDIO_FORMAT_EVRC) {
+ bufferSize = frameCount * channelCount * EVRC_FRAMESIZE; // full rate frame size
+ } else if (format == AUDIO_FORMAT_QCELP) {
+ bufferSize = frameCount * channelCount * QCELP_FRAMESIZE; // full rate frame size
+ } else if (format == AUDIO_FORMAT_AAC) {
+ bufferSize = frameCount * AAC_FRAMESIZE; // full rate frame size
+ } else if (format == AUDIO_FORMAT_AMR_WB) {
+ bufferSize = frameCount * channelCount * AMR_WB_FRAMESIZE; // full rate frame size
+ }
+ }
+#else
size_t bufferSize = (sharedBuffer == 0 ? roundup(frameCount) : frameCount) * mFrameSize;
+#endif
+
if (sharedBuffer == 0) {
size += bufferSize;
}
@@ -137,7 +172,33 @@
mCblk->frameCount_ = frameCount;
if (sharedBuffer == 0) {
mBuffer = (char*)mCblk + sizeof(audio_track_cblk_t);
+#ifdef QCOM_HARDWARE
+ if (flags & IAudioFlinger::TRACK_VOICE_COMMUNICATION) {
+ memset(mBuffer, 0, bufferSize);
+ } else {
+ if ((format == AUDIO_FORMAT_PCM_16_BIT) ||
+ (format == AUDIO_FORMAT_PCM_8_BIT)) {
+ memset(mBuffer, 0, bufferSize);
+ } else if (format == AUDIO_FORMAT_AMR_NB) {
+ // full rate frame size
+ memset(mBuffer, 0, frameCount * channelCount * AMR_FRAMESIZE);
+ } else if (format == AUDIO_FORMAT_EVRC) {
+ // full rate frame size
+ memset(mBuffer, 0, frameCount * channelCount * EVRC_FRAMESIZE);
+ } else if (format == AUDIO_FORMAT_QCELP) {
+ // full rate frame size
+ memset(mBuffer, 0, frameCount * channelCount * QCELP_FRAMESIZE);
+ } else if (format == AUDIO_FORMAT_AAC) {
+ // full rate frame size
+ memset(mBuffer, 0, frameCount * AAC_FRAMESIZE);
+ } else if (format == AUDIO_FORMAT_AMR_WB) {
+ // full rate frame size
+ memset(mBuffer, 0, frameCount * channelCount * AMR_WB_FRAMESIZE);
+ }
+ }
+#else
memset(mBuffer, 0, bufferSize);
+#endif
} else {
mBuffer = sharedBuffer->pointer();
#if 0
@@ -328,8 +389,14 @@
int sessionId,
int uid,
IAudioFlinger::track_flags_t flags)
+#ifdef QCOM_HARDWARE
+ : TrackBase(thread, client, sampleRate, format, channelMask, frameCount,
+ ((audio_stream_type_t)streamType == AUDIO_STREAM_VOICE_CALL)? IAudioFlinger::TRACK_VOICE_COMMUNICATION:0x0,
+ sharedBuffer, sessionId, uid, true /*isOut*/),
+#else
: TrackBase(thread, client, sampleRate, format, channelMask, frameCount, sharedBuffer,
sessionId, uid, true /*isOut*/),
+#endif
mFillingUpStatus(FS_INVALID),
// mRetryCount initialized later when needed
mSharedBuffer(sharedBuffer),
@@ -1756,13 +1823,24 @@
audio_format_t format,
audio_channel_mask_t channelMask,
size_t frameCount,
+#ifdef QCOM_HARDWARE
+ uint32_t flags,
+#endif
int sessionId,
int uid)
+#ifdef QCOM_HARDWARE
+ : TrackBase(thread, client, sampleRate, format, channelMask, frameCount,
+ flags, 0 /*sharedBuffer*/, sessionId, uid, false /*isOut*/),
+#else
: TrackBase(thread, client, sampleRate, format,
channelMask, frameCount, 0 /*sharedBuffer*/, sessionId, uid, false /*isOut*/),
+#endif
mOverflow(false)
{
ALOGV("RecordTrack constructor");
+#ifdef QCOM_HARDWARE
+ mFlags = flags;
+#endif
if (mCblk != NULL) {
mAudioRecordServerProxy = new AudioRecordServerProxy(mCblk, mBuffer, frameCount,
mFrameSize);
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index 51ba698..9fc4c40 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -58,6 +58,18 @@
LOCAL_CFLAGS += -Wall -Wextra
+ifeq ($(BOARD_USES_QCOM_LEGACY_CAM_PARAMS),true)
+ LOCAL_CFLAGS += -DQCOM_LEGACY_CAM_PARAMS
+endif
+
+ifeq ($(BOARD_HAVE_HTC_FFC),true)
+ LOCAL_CFLAGS += -DBOARD_HAVE_HTC_FFC
+endif
+
+ifeq ($(BOARD_HTC_3D_SUPPORT),true)
+ LOCAL_CFLAGS += -DHTC_3D_SUPPORT
+endif
+
LOCAL_MODULE:= libcameraservice
include $(BUILD_SHARED_LIBRARY)
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 5957d97..243ff9f 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -21,6 +21,8 @@
#include <stdio.h>
#include <sys/types.h>
#include <pthread.h>
+#include <unistd.h>
+#include <fcntl.h>
#include <binder/AppOpsManager.h>
#include <binder/IPCThreadState.h>
@@ -37,6 +39,7 @@
#include <utils/Log.h>
#include <utils/String16.h>
+#include <system/camera.h>
#include "CameraService.h"
#include "api1/CameraClient.h"
#include "api1/Camera2Client.h"
@@ -85,6 +88,24 @@
// ----------------------------------------------------------------------------
+#if defined(BOARD_HAVE_HTC_FFC)
+#define HTC_SWITCH_CAMERA_FILE_PATH "/sys/android_camera2/htcwc"
+static void htcCameraSwitch(int cameraId)
+{
+ char buffer[16];
+ int fd;
+
+ if (access(HTC_SWITCH_CAMERA_FILE_PATH, W_OK) == 0) {
+ snprintf(buffer, sizeof(buffer), "%d", cameraId);
+
+ fd = open(HTC_SWITCH_CAMERA_FILE_PATH, O_WRONLY);
+ write(fd, buffer, strlen(buffer));
+ close(fd);
+ }
+}
+#endif
+
+
// This is ugly and only safe if we never re-create the CameraService, but
// should be ok for now.
static CameraService *gCameraService;
@@ -365,6 +386,10 @@
String8 clientName8(clientPackageName);
int callingPid = getCallingPid();
+#if defined(BOARD_HAVE_HTC_FFC)
+ htcCameraSwitch(cameraId);
+#endif
+
if (mClient[cameraId] != 0) {
client = mClient[cameraId].promote();
if (client != 0) {
@@ -891,8 +916,18 @@
LOG1("CameraService::loadSound ref=%d", mSoundRef);
if (mSoundRef++) return;
- mSoundPlayer[SOUND_SHUTTER] = newMediaPlayer("/system/media/audio/ui/camera_click.ogg");
- mSoundPlayer[SOUND_RECORDING] = newMediaPlayer("/system/media/audio/ui/VideoRecord.ogg");
+ char value[PROPERTY_VALUE_MAX];
+ property_get("persist.camera.shutter.disable", value, "0");
+ int disableSound = atoi(value);
+
+ if(!disableSound) {
+ mSoundPlayer[SOUND_SHUTTER] = newMediaPlayer("/system/media/audio/ui/camera_click.ogg");
+ mSoundPlayer[SOUND_RECORDING] = newMediaPlayer("/system/media/audio/ui/VideoRecord.ogg");
+ }
+ else {
+ mSoundPlayer[SOUND_SHUTTER] = NULL;
+ mSoundPlayer[SOUND_RECORDING] = NULL;
+ }
}
void CameraService::releaseSound() {
@@ -936,6 +971,7 @@
LOG1("Client::Client E (pid %d, id %d)", callingPid, cameraId);
mRemoteCallback = cameraClient;
+ mLongshotEnabled = false;
cameraService->setCameraBusy(cameraId);
cameraService->loadSound();
@@ -970,6 +1006,9 @@
mServicePid = servicePid;
mOpsActive = false;
mDestructionStarted = false;
+#ifdef QCOM_HARDWARE
+ mBurstCnt = 0;
+#endif
}
CameraService::BasicClient::~BasicClient() {
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index ad6a582..1864fbb 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -35,7 +35,11 @@
#include <camera/ICameraServiceListener.h>
/* This needs to be increased if we can have more cameras */
+#ifdef OMAP_ENHANCEMENT
+#define MAX_CAMERAS 3
+#else
#define MAX_CAMERAS 2
+#endif
namespace android {
@@ -172,6 +176,9 @@
pid_t mClientPid;
uid_t mClientUid; // immutable after constructor
pid_t mServicePid; // immutable after constructor
+#ifdef QCOM_HARDWARE
+ int mBurstCnt;
+#endif
// - The app-side Binder interface to receive callbacks from us
sp<IBinder> mRemoteBinder; // immutable after constructor
@@ -260,11 +267,11 @@
virtual void notifyError();
- // Initialized in constructor
// - The app-side Binder interface to receive callbacks from us
sp<ICameraClient> mRemoteCallback;
+ bool mLongshotEnabled;
}; // class Client
class ProClient : public BnProCameraUser, public BasicClient {
diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp
index bd6805d..d63eb3c 100644
--- a/services/camera/libcameraservice/api1/CameraClient.cpp
+++ b/services/camera/libcameraservice/api1/CameraClient.cpp
@@ -88,8 +88,14 @@
(void *)mCameraId);
// Enable zoom, error, focus, and metadata messages by default
- enableMsgType(CAMERA_MSG_ERROR | CAMERA_MSG_ZOOM | CAMERA_MSG_FOCUS |
- CAMERA_MSG_PREVIEW_METADATA | CAMERA_MSG_FOCUS_MOVE);
+ enableMsgType(CAMERA_MSG_ERROR | CAMERA_MSG_ZOOM | CAMERA_MSG_FOCUS
+#ifndef QCOM_HARDWARE
+ | CAMERA_MSG_PREVIEW_METADATA
+#endif
+#ifndef OMAP_ICS_CAMERA
+ | CAMERA_MSG_FOCUS_MOVE
+#endif
+ );
LOG1("CameraClient::initialize X (pid %d, id %d)", callingPid, mCameraId);
return OK;
@@ -252,7 +258,9 @@
if (mPreviewWindow != 0) {
disconnectWindow(mPreviewWindow);
mPreviewWindow = 0;
+#ifndef NO_UPDATE_PREVIEW
mHardware->setPreviewWindow(mPreviewWindow);
+#endif
}
mHardware.clear();
@@ -350,6 +358,9 @@
// start preview mode
status_t CameraClient::startPreview() {
+#ifdef QCOM_HARDWARE
+ enableMsgType(CAMERA_MSG_PREVIEW_METADATA);
+#endif
LOG1("startPreview (pid %d)", getCallingPid());
return startCameraMode(CAMERA_PREVIEW_MODE);
}
@@ -400,6 +411,11 @@
native_window_set_buffers_transform(mPreviewWindow.get(),
mOrientation);
}
+
+#if defined(OMAP_ICS_CAMERA) || defined(OMAP_ENHANCEMENT_BURST_CAPTURE)
+ disableMsgType(CAMERA_MSG_COMPRESSED_BURST_IMAGE);
+#endif
+
mHardware->setPreviewWindow(mPreviewWindow);
result = mHardware->startPreview();
@@ -436,11 +452,35 @@
// stop preview mode
void CameraClient::stopPreview() {
LOG1("stopPreview (pid %d)", getCallingPid());
+#ifdef QCOM_HARDWARE
+ disableMsgType(CAMERA_MSG_PREVIEW_METADATA);
+#endif
Mutex::Autolock lock(mLock);
if (checkPidAndHardware() != NO_ERROR) return;
+#ifdef OMAP_ENHANCEMENT
+ // According to framework documentation, preview needs
+ // to be started for image capture. This will make sure
+ // that image capture related messages get disabled if
+ // not done already in their respective handlers.
+ // If these messages come when in the midddle of
+ // stopping preview we will deadlock the system in
+ // lockIfMessageWanted().
+ disableMsgType(CAMERA_MSG_POSTVIEW_FRAME);
+#endif
disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
+#ifdef QCOM_HARDWARE
+ //Disable picture related message types
+ ALOGI("stopPreview: Disable picture related messages");
+ int picMsgType = 0;
+ picMsgType = (CAMERA_MSG_SHUTTER |
+ CAMERA_MSG_POSTVIEW_FRAME |
+ CAMERA_MSG_RAW_IMAGE |
+ CAMERA_MSG_RAW_IMAGE_NOTIFY |
+ CAMERA_MSG_COMPRESSED_IMAGE);
+ disableMsgType(picMsgType);
+#endif
mHardware->stopPreview();
mPreviewBuffer.clear();
@@ -453,6 +493,17 @@
if (checkPidAndHardware() != NO_ERROR) return;
disableMsgType(CAMERA_MSG_VIDEO_FRAME);
+#ifdef QCOM_HARDWARE
+ //Disable picture related message types
+ ALOGI("stopRecording: Disable picture related messages");
+ int picMsgType = 0;
+ picMsgType = (CAMERA_MSG_SHUTTER |
+ CAMERA_MSG_POSTVIEW_FRAME |
+ CAMERA_MSG_RAW_IMAGE |
+ CAMERA_MSG_RAW_IMAGE_NOTIFY |
+ CAMERA_MSG_COMPRESSED_IMAGE);
+ disableMsgType(picMsgType);
+#endif
mHardware->stopRecording();
mCameraService->playSound(CameraService::SOUND_RECORDING);
@@ -534,9 +585,24 @@
CAMERA_MSG_POSTVIEW_FRAME |
CAMERA_MSG_RAW_IMAGE |
CAMERA_MSG_RAW_IMAGE_NOTIFY |
+#if defined(OMAP_ICS_CAMERA) || defined(OMAP_ENHANCEMENT_BURST_CAPTURE)
+ CAMERA_MSG_RAW_BURST |
+#endif
CAMERA_MSG_COMPRESSED_IMAGE);
+#if defined(OMAP_ICS_CAMERA) || defined(OMAP_ENHANCEMENT_BURST_CAPTURE)
+ picMsgType |= CAMERA_MSG_COMPRESSED_BURST_IMAGE;
+#endif
+#ifdef QCOM_HARDWARE
+ disableMsgType(CAMERA_MSG_PREVIEW_METADATA);
+#endif
enableMsgType(picMsgType);
+#ifdef QCOM_HARDWARE
+ mBurstCnt = mHardware->getParameters().getInt("num-snaps-per-shutter");
+ if(mBurstCnt <= 0)
+ mBurstCnt = 1;
+ LOG1("mBurstCnt = %d", mBurstCnt);
+#endif
return mHardware->takePicture();
}
@@ -630,6 +696,22 @@
} else if (cmd == CAMERA_CMD_PING) {
// If mHardware is 0, checkPidAndHardware will return error.
return OK;
+#ifdef QCOM_HARDWARE
+ } 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);
+#endif
}
return mHardware->sendCommand(cmd, arg1, arg2);
@@ -651,6 +733,14 @@
bool CameraClient::lockIfMessageWanted(int32_t msgType) {
int sleepCount = 0;
while (mMsgEnabled & msgType) {
+#ifdef QCOM_HARDWARE
+ if ((msgType == CAMERA_MSG_PREVIEW_FRAME) &&
+ (mMsgEnabled & CAMERA_MSG_COMPRESSED_IMAGE)) {
+ LOG1("lockIfMessageWanted(%d): Don't try to acquire mlock if "
+ "both Preview and Compressed are enabled", msgType);
+ return false;
+ }
+#endif
if (mLock.tryLock() == NO_ERROR) {
if (sleepCount > 0) {
LOG1("lockIfMessageWanted(%d): waited for %d ms",
@@ -694,6 +784,12 @@
int32_t ext2, void* user) {
LOG2("notifyCallback(%d)", msgType);
+ // Ignore CAF_RESTART callbacks from Samsung's camera driver
+ if (msgType == CAMERA_MSG_FOCUS && ext1 == 4) {
+ LOG2("Ignore CAF_RESTART callback");
+ return;
+ }
+
Mutex* lock = getClientLockFromCookie(user);
if (lock == NULL) return;
Mutex::Autolock alock(*lock);
@@ -747,6 +843,11 @@
case CAMERA_MSG_COMPRESSED_IMAGE:
client->handleCompressedPicture(dataPtr);
break;
+#if defined(OMAP_ICS_CAMERA) || defined(OMAP_ENHANCEMENT_BURST_CAPTURE)
+ case CAMERA_MSG_COMPRESSED_BURST_IMAGE:
+ client->handleCompressedBurstPicture(dataPtr);
+ break;
+#endif
default:
client->handleGenericData(msgType, dataPtr, metadata);
break;
@@ -788,7 +889,9 @@
c->notifyCallback(CAMERA_MSG_SHUTTER, 0, 0);
if (!lockIfMessageWanted(CAMERA_MSG_SHUTTER)) return;
}
- disableMsgType(CAMERA_MSG_SHUTTER);
+ if ( !mLongshotEnabled ) {
+ disableMsgType(CAMERA_MSG_SHUTTER);
+ }
mLock.unlock();
}
@@ -867,7 +970,17 @@
// picture callback - compressed picture ready
void CameraClient::handleCompressedPicture(const sp<IMemory>& mem) {
- disableMsgType(CAMERA_MSG_COMPRESSED_IMAGE);
+#ifdef QCOM_HARDWARE
+ if (mBurstCnt)
+ mBurstCnt--;
+
+ if (!mBurstCnt && !mLongshotEnabled) {
+ LOG1("handleCompressedPicture mBurstCnt = %d", mBurstCnt);
+#endif
+ disableMsgType(CAMERA_MSG_COMPRESSED_IMAGE);
+#ifdef QCOM_HARDWARE
+ }
+#endif
sp<ICameraClient> c = mRemoteCallback;
mLock.unlock();
@@ -876,6 +989,20 @@
}
}
+#if defined(OMAP_ICS_CAMERA) || defined(OMAP_ENHANCEMENT_BURST_CAPTURE)
+// burst picture callback - compressed picture ready
+void CameraClient::handleCompressedBurstPicture(const sp<IMemory>& mem) {
+ // Don't disable this message type yet. In this mode takePicture() will
+ // get called only once. When burst finishes this message will get automatically
+ // disabled in the respective call for restarting the preview.
+
+ sp<ICameraClient> c = mCameraClient;
+ mLock.unlock();
+ if (c != 0) {
+ c->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE, mem, NULL);
+ }
+}
+#endif
void CameraClient::handleGenericNotify(int32_t msgType,
int32_t ext1, int32_t ext2) {
diff --git a/services/camera/libcameraservice/api1/CameraClient.h b/services/camera/libcameraservice/api1/CameraClient.h
index 4b89564..f460763 100644
--- a/services/camera/libcameraservice/api1/CameraClient.h
+++ b/services/camera/libcameraservice/api1/CameraClient.h
@@ -105,6 +105,9 @@
void handlePostview(const sp<IMemory>& mem);
void handleRawPicture(const sp<IMemory>& mem);
void handleCompressedPicture(const sp<IMemory>& mem);
+#if defined(OMAP_ICS_CAMERA) || defined(OMAP_ENHANCEMENT_BURST_CAPTURE)
+ void handleCompressedBurstPicture(const sp<IMemory>& mem);
+#endif
void handleGenericNotify(int32_t msgType, int32_t ext1, int32_t ext2);
void handleGenericData(int32_t msgType, const sp<IMemory>& dataPtr,
camera_frame_metadata_t *metadata);
diff --git a/services/camera/libcameraservice/device1/CameraHardwareInterface.h b/services/camera/libcameraservice/device1/CameraHardwareInterface.h
index 87b2807..2bdf827 100644
--- a/services/camera/libcameraservice/device1/CameraHardwareInterface.h
+++ b/services/camera/libcameraservice/device1/CameraHardwareInterface.h
@@ -451,13 +451,17 @@
ALOGV("%s", __FUNCTION__);
CameraHardwareInterface *__this =
static_cast<CameraHardwareInterface *>(user);
- sp<CameraHeapMemory> mem(static_cast<CameraHeapMemory *>(data->handle));
- if (index >= mem->mNumBufs) {
+ if (data != NULL) {
+ sp<CameraHeapMemory> mem(static_cast<CameraHeapMemory *>(data->handle));
+ if (index >= mem->mNumBufs) {
ALOGE("%s: invalid buffer index %d, max allowed is %d", __FUNCTION__,
index, mem->mNumBufs);
return;
+ }
+ __this->mDataCb(msg_type, mem->mBuffers[index], metadata, __this->mCbUser);
+ } else {
+ __this->mDataCb(msg_type, NULL, metadata, __this->mCbUser);
}
- __this->mDataCb(msg_type, mem->mBuffers[index], metadata, __this->mCbUser);
}
static void __data_cb_timestamp(nsecs_t timestamp, int32_t msg_type,
@@ -636,6 +640,9 @@
static int __set_usage(struct preview_stream_ops* w, int usage)
{
+#ifdef HTC_3D_SUPPORT
+ usage |= GRALLOC_USAGE_PRIVATE_0;
+#endif
ANativeWindow *a = anw(w);
return native_window_set_usage(a, usage);
}
@@ -654,6 +661,14 @@
return a->query(a, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, count);
}
+#ifdef HTC_3D_SUPPORT
+ static int __set_3d_mode(
+ const struct preview_stream_ops *w, int r1, int r2, int r3)
+ {
+ return 0;
+ }
+#endif
+
void initHalPreviewWindow()
{
mHalPreviewWindow.nw.cancel_buffer = __cancel_buffer;
@@ -661,6 +676,9 @@
mHalPreviewWindow.nw.dequeue_buffer = __dequeue_buffer;
mHalPreviewWindow.nw.enqueue_buffer = __enqueue_buffer;
mHalPreviewWindow.nw.set_buffer_count = __set_buffer_count;
+#ifdef HTC_3D_SUPPORT
+ mHalPreviewWindow.nw.set_3d_mode = __set_3d_mode;
+#endif
mHalPreviewWindow.nw.set_buffers_geometry = __set_buffers_geometry;
mHalPreviewWindow.nw.set_crop = __set_crop;
mHalPreviewWindow.nw.set_timestamp = __set_timestamp;