diff options
author | ST-Ericsson <void@stericsson.com> | 2012-04-20 13:39:45 +0200 |
---|---|---|
committer | Patrik Ryd <patrik.ryd@linaro.org> | 2012-05-09 19:13:01 +0200 |
commit | 7fcc59be0ba1d2d9404278903694b966a3a30629 (patch) | |
tree | d2e8b6e8538c9f4e3312cd2eede89fe19ce64fd7 | |
parent | 681fc12b00cabc77d8ae9b539a286c50408d7cc1 (diff) | |
download | base-7fcc59be0ba1d2d9404278903694b966a3a30629.tar.gz |
Adding multimedia extension
More specifically:
- Add support for ST-Ericsson native pixel formats and conversion to
and from these formats.
- The Khronos headers are out of date and Mali extensions are missing from
the extension headers. GLES2/gl2ext.h has been updated with the missing ARM
extensions.
- ST-Ericsson audio support for multimedia.
- ST-Ericsson video support for multimedia.
- Support for FM Audio in framework.
Signed-off-by: Patrik Ryd <patrik.ryd@stericsson.com>
(cherry picked from commit b5650a283cd3b95f9d4eb1b39dc031f1e2dc82da)
Change-Id: I5c899aaaa567cf6c40508e3eaad871518d370e11
Signed-off-by: Patrik Ryd <patrik.ryd@linaro.org>
65 files changed, 1421 insertions, 200 deletions
diff --git a/api/current.txt b/api/current.txt index 506ab35d11cb..cc8706a3e68d 100644 --- a/api/current.txt +++ b/api/current.txt @@ -10860,6 +10860,7 @@ package android.media { public final class MediaRecorder.AudioSource { field public static final int CAMCORDER = 5; // 0x5 field public static final int DEFAULT = 0; // 0x0 + field public static final int FM_RADIO_RX = 8; // 0x8 field public static final int MIC = 1; // 0x1 field public static final int VOICE_CALL = 4; // 0x4 field public static final int VOICE_COMMUNICATION = 7; // 0x7 diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 93fd5fb0d449..550722c6a22e 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -24,6 +24,10 @@ ifeq ($(USE_OPENGL_RENDERER),true) LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER endif +ifeq ($(BOARD_HAVE_CODEC_SUPPORT),STERICSSON_CODEC_SUPPORT) + LOCAL_CFLAGS += -DSTERICSSON_CODEC_SUPPORT +endif + LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES LOCAL_SRC_FILES:= \ diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h index 7edf6b4562ff..e0bba334575d 100644 --- a/include/camera/CameraParameters.h +++ b/include/camera/CameraParameters.h @@ -596,9 +596,15 @@ public: // Pixel color formats for KEY_PREVIEW_FORMAT, KEY_PICTURE_FORMAT, // and KEY_VIDEO_FRAME_FORMAT static const char PIXEL_FORMAT_YUV422SP[]; + static const char PIXEL_FORMAT_YUV420P[]; // YV12 static const char PIXEL_FORMAT_YUV420SP[]; // NV21 + static const char PIXEL_FORMAT_YUV420SPNV12[]; // NV12 static const char PIXEL_FORMAT_YUV422I[]; // YUY2 - static const char PIXEL_FORMAT_YUV420P[]; // YV12 + static const char PIXEL_FORMAT_YVU422SP[]; + static const char PIXEL_FORMAT_YVU422P[]; + static const char PIXEL_FORMAT_YVU420SP[]; + static const char PIXEL_FORMAT_YVU420P[]; + static const char PIXEL_FORMAT_YUV420MB[]; static const char PIXEL_FORMAT_RGB565[]; static const char PIXEL_FORMAT_RGBA8888[]; static const char PIXEL_FORMAT_JPEG[]; @@ -656,6 +662,9 @@ public: // To stop continuous focus, applications should change the focus mode to // other modes. static const char FOCUS_MODE_CONTINUOUS_PICTURE[]; + // keys for record stride and slice height + static const char KEY_RECORD_STRIDE[]; + static const char KEY_RECORD_SLICE_HEIGHT[]; private: DefaultKeyedVector<String8,String8> mMap; diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h index a8c76725e7c9..a8db994988fc 100644 --- a/include/gui/SurfaceTexture.h +++ b/include/gui/SurfaceTexture.h @@ -29,7 +29,7 @@ #include <utils/String8.h> #include <utils/Vector.h> #include <utils/threads.h> - +#include <hardware/copybit.h> #define ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID "mSurfaceTexture" namespace android { @@ -47,6 +47,7 @@ public: }; enum { NUM_BUFFER_SLOTS = 32 }; enum { NO_CONNECTED_API = 0 }; + enum { NUM_BLIT_BUFFER_SLOTS = 2 }; struct FrameAvailableListener : public virtual RefBase { // onFrameAvailable() is called from queueBuffer() each time an @@ -139,6 +140,16 @@ public: // target texture belongs is bound to the calling thread. status_t updateTexImage(); + // A surface that uses a non-native format requires conversion of + // its buffers. This conversion can be deferred until the layer + // based on this surface is drawn. + status_t updateTexImage(bool deferConversion); + + // convert() performs the deferred texture conversion as scheduled + // by updateTexImage(bool deferConversion). + // The method returns immediately if no conversion is necessary. + status_t convert(); + // setBufferCountServer set the buffer count. If the client has requested // a buffer count using setBufferCount, the server-buffer count will // take effect once the client sets the count back to zero. @@ -263,6 +274,12 @@ private: EGLImageKHR createImage(EGLDisplay dpy, const sp<GraphicBuffer>& graphicBuffer); + // returns TRUE if buffer needs color format conversion + bool conversionIsNeeded(const sp<GraphicBuffer>& graphicBuffer); + + // converts buffer to a suitable color format + status_t convert(sp<GraphicBuffer> &srcBuf, sp<GraphicBuffer> &dstBuf); + status_t setBufferCountServerLocked(int bufferCount); // computeCurrentTransformMatrix computes the transform matrix for the @@ -508,7 +525,33 @@ private: // with the surface Texture. uint64_t mFrameCounter; - + // mBlitEngine is the handle to the copybit device which will be used in + // case color transform is needed before the EGL image is created. + copybit_device_t* mBlitEngine; + + // mBlitSlots contains several buffers which will + // be rendered alternately in case color transform is needed (instead + // of rendering the buffers in mSlots). + BufferSlot mBlitSlots[NUM_BLIT_BUFFER_SLOTS]; + + // mNextBlitSlot is the index of the blitter buffer (in mBlitSlots) which + // will be used in the next color transform. + int mNextBlitSlot; + + // mConversionSrcSlot designates the slot where source buffer + // for the last deferred updateTexImage is located. + int mConversionSrcSlot; + + // mConversionBltSlot designates the slot where destination buffer + // for the last deferred updateTexImage is located. + int mConversionBltSlot; + + // mNeedsConversion indicates that a format conversion is necessary + // before the layer based on this surface is drawn. + // This flag is set whenever updateTexImage() with deferred conversion + // is called. It is cleared once the layer is drawn, + // or when updateTexImage() w/o deferred conversion is called. + bool mNeedsConversion; }; // ---------------------------------------------------------------------------- diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h index 6a15f6ec90a6..95d539efec8c 100644 --- a/include/media/AudioSystem.h +++ b/include/media/AudioSystem.h @@ -110,7 +110,6 @@ public: static int newAudioSessionId(); static void acquireAudioSessionId(int audioSession); static void releaseAudioSessionId(int audioSession); - // types of io configuration change events received with ioConfigChanged() enum io_config_event { OUTPUT_OPENED, @@ -163,7 +162,8 @@ public: uint32_t format = AUDIO_FORMAT_DEFAULT, uint32_t channels = AUDIO_CHANNEL_IN_MONO, audio_in_acoustics_t acoustics = (audio_in_acoustics_t)0, - int sessionId = 0); + int sessionId = 0, + audio_input_clients *inputClientId = NULL); static status_t startInput(audio_io_handle_t input); static status_t stopInput(audio_io_handle_t input); static void releaseInput(audio_io_handle_t input); diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h index 1c401e2b276b..62516c6c54a0 100644 --- a/include/media/AudioTrack.h +++ b/include/media/AudioTrack.h @@ -451,7 +451,6 @@ private: status_t setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCount); audio_io_handle_t getOutput_l(); status_t restoreTrack_l(audio_track_cblk_t*& cblk, bool fromStart); - sp<IAudioTrack> mAudioTrack; sp<IMemory> mCblkMemory; sp<AudioTrackThread> mAudioTrackThread; diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h index 9e3cb7f3c383..4e72448d330a 100644 --- a/include/media/IAudioFlinger.h +++ b/include/media/IAudioFlinger.h @@ -126,8 +126,9 @@ public: uint32_t *pSamplingRate, uint32_t *pFormat, uint32_t *pChannels, - uint32_t acoustics) = 0; - virtual status_t closeInput(int input) = 0; + uint32_t acoustics, + uint32_t *pInputClientId = NULL) = 0; + virtual status_t closeInput(int input, uint32_t* inputClientId = NULL) = 0; virtual status_t setStreamOutput(uint32_t stream, int output) = 0; @@ -159,6 +160,7 @@ public: int *enabled) = 0; virtual status_t moveEffects(int session, int srcOutput, int dstOutput) = 0; + virtual size_t readInput(uint32_t *input, uint32_t inputClientId, void *buffer, uint32_t bytes, uint32_t *pOverwrittenBytes) = 0; }; diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h index 9807cbe56430..1607bc5cdddf 100644 --- a/include/media/IAudioPolicyService.h +++ b/include/media/IAudioPolicyService.h @@ -66,7 +66,8 @@ public: uint32_t format = AUDIO_FORMAT_DEFAULT, uint32_t channels = 0, audio_in_acoustics_t acoustics = (audio_in_acoustics_t)0, - int audioSession = 0) = 0; + int audioSession = 0, + audio_input_clients *inputClientId = NULL) = 0; virtual status_t startInput(audio_io_handle_t input) = 0; virtual status_t stopInput(audio_io_handle_t input) = 0; virtual void releaseInput(audio_io_handle_t input) = 0; diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h index 0b79324db69d..ae5937d469aa 100644 --- a/include/media/stagefright/AudioPlayer.h +++ b/include/media/stagefright/AudioPlayer.h @@ -101,7 +101,6 @@ private: static size_t AudioSinkCallback( MediaPlayerBase::AudioSink *audioSink, void *data, size_t size, void *me); - size_t fillBuffer(void *data, size_t size); int64_t getRealTimeUsLocked() const; diff --git a/include/media/stagefright/ColorConverter.h b/include/media/stagefright/ColorConverter.h index 85ba9206835c..0f9e40051872 100644 --- a/include/media/stagefright/ColorConverter.h +++ b/include/media/stagefright/ColorConverter.h @@ -73,6 +73,9 @@ private: status_t convertQCOMYUV420SemiPlanar( const BitmapParams &src, const BitmapParams &dst); + status_t convertSTEYUV420PackedSemiPlanarMB( + const BitmapParams &src, const BitmapParams &dst); + status_t convertYUV420SemiPlanar( const BitmapParams &src, const BitmapParams &dst); diff --git a/include/media/stagefright/FMRadioDataSource.h b/include/media/stagefright/FMRadioDataSource.h new file mode 100644 index 000000000000..96735550d846 --- /dev/null +++ b/include/media/stagefright/FMRadioDataSource.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Copyright (C) 2010 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. + * + * Author: Andreas Gustafsson (andreas.a.gustafsson@stericsson.com) + * for ST-Ericsson + */ + +#ifndef FMRADIO_DATA_SOURCE_H_ + +#define FMRADIO_DATA_SOURCE_H_ + +#include <stdio.h> + +#include <media/stagefright/DataSource.h> +#include <media/stagefright/MediaErrors.h> +#include <utils/threads.h> +#include <hardware_legacy/AudioHardwareInterface.h> +#include <media/AudioSystem.h> +#include <system/audio.h> +#include <hardware_legacy/AudioSystemLegacy.h> + +namespace android { + +class FMRadioDataSource : public DataSource { +public: + FMRadioDataSource(); + + virtual status_t initCheck() const; + + virtual ssize_t readAt(off64_t offset, void *data, size_t size); + + virtual status_t getSize(off64_t *size); + + virtual uint32_t getBufferSize(); + + virtual uint32_t getNumChannels(); + + virtual uint32_t getSampleRate(); + + virtual uint32_t getFormat(); + +protected: + virtual ~FMRadioDataSource(); + +private: + android_audio_legacy::AudioStreamIn *mStream; + sp<IAudioFlinger> mAudioFlinger; + FMRadioDataSource(const FMRadioDataSource &); + FMRadioDataSource &operator=(const FMRadioDataSource &); + audio_input_clients mInputClientId; + uint32_t mFormat; + uint32_t mChannels; + uint32_t mSampleRate; + uint32_t mOverwrittenBytes; + uint32_t mFlags; +}; + +} // namespace android + +#endif // FMRADIO_DATA_SOURCE_H_ diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h index 2eb259e8b590..a533ed43e1a7 100644 --- a/include/media/stagefright/MediaDefs.h +++ b/include/media/stagefright/MediaDefs.h @@ -26,8 +26,10 @@ extern const char *MEDIA_MIMETYPE_VIDEO_VPX; extern const char *MEDIA_MIMETYPE_VIDEO_AVC; extern const char *MEDIA_MIMETYPE_VIDEO_MPEG4; extern const char *MEDIA_MIMETYPE_VIDEO_H263; +extern const char *MEDIA_MIMETYPE_VIDEO_H263_SW; extern const char *MEDIA_MIMETYPE_VIDEO_MPEG2; extern const char *MEDIA_MIMETYPE_VIDEO_RAW; +extern const char *MEDIA_MIMETYPE_VIDEO_VC1; extern const char *MEDIA_MIMETYPE_AUDIO_AMR_NB; extern const char *MEDIA_MIMETYPE_AUDIO_AMR_WB; diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h index 84f8282f64b7..5ebba96c9b57 100644 --- a/include/media/stagefright/OMXCodec.h +++ b/include/media/stagefright/OMXCodec.h @@ -140,6 +140,7 @@ private: kAvoidMemcopyInputRecordingFrames = 2048, kRequiresLargerEncoderOutputBuffer = 4096, kOutputBuffersAreUnreadable = 8192, + kRequiresStoreMetaDataBeforeIdle = 16384, }; enum BufferStatus { diff --git a/include/media/stagefright/foundation/ABitReader.h b/include/media/stagefright/foundation/ABitReader.h index 5510b12aee8c..7a4270d53578 100644 --- a/include/media/stagefright/foundation/ABitReader.h +++ b/include/media/stagefright/foundation/ABitReader.h @@ -31,6 +31,8 @@ struct ABitReader { uint32_t getBits(size_t n); void skipBits(size_t n); + void rewindBits(size_t n); + void putBits(uint32_t x, size_t n); size_t numBitsLeft() const; @@ -39,7 +41,9 @@ struct ABitReader { private: const uint8_t *mData; + const uint8_t *mOriginalData; size_t mSize; + size_t mOriginalSize; uint32_t mReservoir; // left-aligned bits size_t mNumBitsLeft; diff --git a/include/media/stagefright/openmax/OMX_IVCommon.h b/include/media/stagefright/openmax/OMX_IVCommon.h index 8bb4dede8fda..5df525c66782 100644 --- a/include/media/stagefright/openmax/OMX_IVCommon.h +++ b/include/media/stagefright/openmax/OMX_IVCommon.h @@ -159,6 +159,7 @@ typedef enum OMX_COLOR_FORMATTYPE { OMX_COLOR_FormatAndroidOpaque = 0x7F000789, OMX_TI_COLOR_FormatYUV420PackedSemiPlanar = 0x7F000100, OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00, + OMX_STE_COLOR_FormatYUV420PackedSemiPlanarMB = 0x7FA00000, OMX_COLOR_FormatMax = 0x7FFFFFFF } OMX_COLOR_FORMATTYPE; diff --git a/include/ui/PixelFormat.h b/include/ui/PixelFormat.h index 848c5a114907..e22071b541de 100644 --- a/include/ui/PixelFormat.h +++ b/include/ui/PixelFormat.h @@ -72,6 +72,12 @@ enum { // New formats can be added if they're also defined in // pixelflinger/format.h + + // Added Support for YUV42XMBN, + // Required for Copybit CC acceleration + PIXEL_FORMAT_YCBCR42XMBN = HAL_PIXEL_FORMAT_YCBCR42XMBN, + PIXEL_FORMAT_YCbCr_420_SP = HAL_PIXEL_FORMAT_YCbCr_420_SP, + PIXEL_FORMAT_YCbCr_420_P = HAL_PIXEL_FORMAT_YCbCr_420_P, }; typedef int32_t PixelFormat; diff --git a/include/ui/Region.h b/include/ui/Region.h index 6c9a6203e793..9ce8efb5579c 100644 --- a/include/ui/Region.h +++ b/include/ui/Region.h @@ -24,6 +24,8 @@ #include <ui/Rect.h> +#include <hardware/copybit.h> + namespace android { // --------------------------------------------------------------------------- @@ -181,6 +183,26 @@ Region& Region::operator -= (const Region& rhs) { Region& Region::operator += (const Point& pt) { return translateSelf(pt.x, pt.y); } + +// --------------------------------------------------------------------------- + +struct region_iterator : public copybit_region_t { + region_iterator(const Region& region) + : b(region.begin()), e(region.end()) { + this->next = iterate; + } +private: + static int iterate(copybit_region_t const * self, copybit_rect_t* rect) { + region_iterator const* me = static_cast<region_iterator const*>(self); + if (me->b != me->e) { + *reinterpret_cast<Rect*>(rect) = *me->b++; + return 1; + } + return 0; + } + mutable Region::const_iterator b; + Region::const_iterator const e; +}; // --------------------------------------------------------------------------- }; // namespace android diff --git a/libs/camera/Android.mk b/libs/camera/Android.mk index 7286f9295660..63abad2f46eb 100644 --- a/libs/camera/Android.mk +++ b/libs/camera/Android.mk @@ -1,6 +1,10 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) +ifeq ($(BOARD_HAVE_CODEC_SUPPORT),STERICSSON_CODEC_SUPPORT) + LOCAL_CFLAGS += -DSTERICSSON_CODEC_SUPPORT +endif + LOCAL_SRC_FILES:= \ Camera.cpp \ CameraParameters.cpp \ diff --git a/libs/camera/CameraParameters.cpp b/libs/camera/CameraParameters.cpp index c6087b404667..4bd6318e122a 100644 --- a/libs/camera/CameraParameters.cpp +++ b/libs/camera/CameraParameters.cpp @@ -148,9 +148,15 @@ const char CameraParameters::SCENE_MODE_CANDLELIGHT[] = "candlelight"; const char CameraParameters::SCENE_MODE_BARCODE[] = "barcode"; const char CameraParameters::PIXEL_FORMAT_YUV422SP[] = "yuv422sp"; +const char CameraParameters::PIXEL_FORMAT_YUV420P[] = "yuv420p"; const char CameraParameters::PIXEL_FORMAT_YUV420SP[] = "yuv420sp"; +const char CameraParameters::PIXEL_FORMAT_YUV420SPNV12[] = "yuv420spnv12"; const char CameraParameters::PIXEL_FORMAT_YUV422I[] = "yuv422i-yuyv"; -const char CameraParameters::PIXEL_FORMAT_YUV420P[] = "yuv420p"; +const char CameraParameters::PIXEL_FORMAT_YUV420MB[] = "yuv420mb"; +const char CameraParameters::PIXEL_FORMAT_YVU422SP[] = "yvu422sp"; +const char CameraParameters::PIXEL_FORMAT_YVU422P[] = "yvu422p"; +const char CameraParameters::PIXEL_FORMAT_YVU420SP[] = "yvu420sp"; +const char CameraParameters::PIXEL_FORMAT_YVU420P[] = "yvu420p"; const char CameraParameters::PIXEL_FORMAT_RGB565[] = "rgb565"; const char CameraParameters::PIXEL_FORMAT_RGBA8888[] = "rgba8888"; const char CameraParameters::PIXEL_FORMAT_JPEG[] = "jpeg"; @@ -165,6 +171,10 @@ 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"; +// keys for record stride and sliceheight +const char CameraParameters::KEY_RECORD_STRIDE[] = "record-stride"; +const char CameraParameters::KEY_RECORD_SLICE_HEIGHT[] = "record-slice-height"; + CameraParameters::CameraParameters() : mMap() { diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk index 9767568bed35..e79cd913e42a 100644 --- a/libs/gui/Android.mk +++ b/libs/gui/Android.mk @@ -1,6 +1,10 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) +ifeq ($(BOARD_HAVE_CODEC_SUPPORT),STERICSSON_CODEC_SUPPORT) + LOCAL_CFLAGS += -DSTERICSSON_CODEC_SUPPORT +endif + LOCAL_SRC_FILES:= \ ISensorEventConnection.cpp \ ISensorServer.cpp \ diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp index 4772189b7fb4..e32df27f537e 100644 --- a/libs/gui/SurfaceTexture.cpp +++ b/libs/gui/SurfaceTexture.cpp @@ -28,6 +28,7 @@ #include <gui/SurfaceTexture.h> #include <hardware/hardware.h> +#include <ui/PixelFormat.h> #include <surfaceflinger/ISurfaceComposer.h> #include <surfaceflinger/SurfaceComposerClient.h> @@ -138,6 +139,8 @@ SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode, mUseFenceSync(false), #endif mTexTarget(texTarget), + mNextBlitSlot(0), + mNeedsConversion(false), mFrameCounter(0) { // Choose a name using the PID and a process-unique ID. mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId()); @@ -148,11 +151,26 @@ SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode, mNextCrop.makeInvalid(); memcpy(mCurrentTransformMatrix, mtxIdentity, sizeof(mCurrentTransformMatrix)); + + for (int i = 0; i < NUM_BLIT_BUFFER_SLOTS; i++) { + mBlitSlots[i].mEglImage = EGL_NO_IMAGE_KHR; + mBlitSlots[i].mEglDisplay = EGL_NO_DISPLAY; + } + + hw_module_t const* module; + mBlitEngine = 0; + if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) { + copybit_open(module, &mBlitEngine); + } + LOGE_IF(!mBlitEngine, "\nCannot open copybit mBlitEngine=%p", mBlitEngine); } SurfaceTexture::~SurfaceTexture() { ST_LOGV("~SurfaceTexture"); freeAllBuffersLocked(); + if (mBlitEngine) { + copybit_close(mBlitEngine); + } } status_t SurfaceTexture::setBufferCountServerLocked(int bufferCount) { @@ -747,6 +765,11 @@ status_t SurfaceTexture::setScalingMode(int mode) { } status_t SurfaceTexture::updateTexImage() { + return updateTexImage(false); +} + +#define STE_DEFERDBG 0 +status_t SurfaceTexture::updateTexImage(bool deferConversion) { ST_LOGV("updateTexImage"); Mutex::Autolock lock(mMutex); @@ -762,20 +785,99 @@ status_t SurfaceTexture::updateTexImage() { int buf = *front; // Update the GL texture object. - EGLImageKHR image = mSlots[buf].mEglImage; + EGLImageKHR image; EGLDisplay dpy = eglGetCurrentDisplay(); - if (image == EGL_NO_IMAGE_KHR) { - if (mSlots[buf].mGraphicBuffer == 0) { - ST_LOGE("buffer at slot %d is null", buf); - return BAD_VALUE; + sp<GraphicBuffer> graphicBuffer; + if (conversionIsNeeded(mSlots[buf].mGraphicBuffer)) { + mNeedsConversion = deferConversion; + // If color conversion is needed we can't use the graphic buffers + // located in mSlots for the textures (wrong color format). Instead + // color convert it into a buffer in mBlitSlots and use that instead. + image = mBlitSlots[mNextBlitSlot].mEglImage; + + // If there exists an image already, make sure that + // the dimensions match the current source buffer. + // Otherwise, destroy the buffer and let a new one be allocated. + if (image != EGL_NO_IMAGE_KHR && + mSlots[buf].mGraphicBuffer != NULL && + mBlitSlots[mNextBlitSlot].mGraphicBuffer != NULL) { + sp<GraphicBuffer> &srcBuf = mSlots[buf].mGraphicBuffer; + sp<GraphicBuffer> &bltBuf = + mBlitSlots[mNextBlitSlot].mGraphicBuffer; + if (srcBuf->getWidth() != bltBuf->getWidth() || + srcBuf->getHeight() != bltBuf->getHeight()) { + eglDestroyImageKHR(mBlitSlots[mNextBlitSlot].mEglDisplay, + image); + mBlitSlots[mNextBlitSlot].mEglImage = EGL_NO_IMAGE_KHR; + mBlitSlots[mNextBlitSlot].mGraphicBuffer = NULL; + image = EGL_NO_IMAGE_KHR; + } } - image = createImage(dpy, mSlots[buf].mGraphicBuffer); - mSlots[buf].mEglImage = image; - mSlots[buf].mEglDisplay = dpy; if (image == EGL_NO_IMAGE_KHR) { - // NOTE: if dpy was invalid, createImage() is guaranteed to - // fail. so we'd end up here. - return -EINVAL; + sp<GraphicBuffer> &srcBuf = mSlots[buf].mGraphicBuffer; + status_t res = 0; + + sp<GraphicBuffer> blitBuffer( + mGraphicBufferAlloc->createGraphicBuffer( + srcBuf->getWidth(), srcBuf->getHeight(), + PIXEL_FORMAT_RGBA_8888, srcBuf->getUsage(), + &res)); + if (blitBuffer == 0) { + ST_LOGE("updateTexImage: SurfaceComposer::createGraphicBuffer failed"); + return NO_MEMORY; + } + if (res != NO_ERROR) { + ST_LOGW("updateTexImage: SurfaceComposer::createGraphicBuffer error=%#04x", res); + } + mBlitSlots[mNextBlitSlot].mGraphicBuffer = blitBuffer; + + EGLDisplay dpy = eglGetCurrentDisplay(); + image = createImage(dpy, blitBuffer); + mBlitSlots[mNextBlitSlot].mEglImage = image; + mBlitSlots[mNextBlitSlot].mEglDisplay = dpy; + } + + if (deferConversion) { + graphicBuffer = mSlots[buf].mGraphicBuffer; + mConversionSrcSlot = buf; + mConversionBltSlot = mNextBlitSlot; + // At this point graphicBuffer and image do not point + // at matching buffers. This is intentional as this + // surface might end up being taken care of by HWComposer, + // which needs access to the original buffer. + // GL however, is fed an EGLImage that is created from + // a conversion buffer. It will have its + // content updated once the surface is actually drawn + // in Layer::onDraw() + } else { + if (convert(mSlots[buf].mGraphicBuffer, + mBlitSlots[mNextBlitSlot].mGraphicBuffer) != OK) { + LOGE("updateTexImage: convert failed"); + return UNKNOWN_ERROR; + } + graphicBuffer = mBlitSlots[mNextBlitSlot].mGraphicBuffer; + } + // mBlitSlots contains several buffers (NUM_BLIT_BUFFER_SLOTS), + // advance (potentially wrap) the index + mNextBlitSlot = (mNextBlitSlot + 1) % NUM_BLIT_BUFFER_SLOTS; + } else { + mNeedsConversion = false; + image = mSlots[buf].mEglImage; + graphicBuffer = mSlots[buf].mGraphicBuffer; + if (image == EGL_NO_IMAGE_KHR) { + EGLDisplay dpy = eglGetCurrentDisplay(); + if (graphicBuffer == 0) { + ST_LOGE("buffer at slot %d is null", buf); + return BAD_VALUE; + } + image = createImage(dpy, graphicBuffer); + mSlots[buf].mEglImage = image; + mSlots[buf].mEglDisplay = dpy; + if (image == EGL_NO_IMAGE_KHR) { + // NOTE: if dpy was invalid, createImage() is guaranteed to + // fail. so we'd end up here. + return -EINVAL; + } } } @@ -827,7 +929,7 @@ status_t SurfaceTexture::updateTexImage() { // Update the SurfaceTexture state. mCurrentTexture = buf; - mCurrentTextureBuf = mSlots[buf].mGraphicBuffer; + mCurrentTextureBuf = graphicBuffer; mCurrentCrop = mSlots[buf].mCrop; mCurrentTransform = mSlots[buf].mTransform; mCurrentScalingMode = mSlots[buf].mScalingMode; @@ -853,8 +955,12 @@ bool SurfaceTexture::isExternalFormat(uint32_t format) case HAL_PIXEL_FORMAT_YV12: // Legacy/deprecated YUV formats case HAL_PIXEL_FORMAT_YCbCr_422_SP: - case HAL_PIXEL_FORMAT_YCrCb_420_SP: + case HAL_PIXEL_FORMAT_YCbCr_420_SP: case HAL_PIXEL_FORMAT_YCbCr_422_I: + case HAL_PIXEL_FORMAT_YCrCb_422_SP: + case HAL_PIXEL_FORMAT_YCrCb_422_P: + case HAL_PIXEL_FORMAT_YCrCb_420_SP: + case HAL_PIXEL_FORMAT_YCrCb_420_P: return true; } @@ -996,6 +1102,14 @@ void SurfaceTexture::freeAllBuffersLocked() { for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { freeBufferLocked(i); } + for (int i = 0; i < NUM_BLIT_BUFFER_SLOTS; i++) { + mBlitSlots[i].mGraphicBuffer = 0; + if (mBlitSlots[i].mEglImage != EGL_NO_IMAGE_KHR) { + eglDestroyImageKHR(mBlitSlots[i].mEglDisplay, mBlitSlots[i].mEglImage); + mBlitSlots[i].mEglImage = EGL_NO_IMAGE_KHR; + mBlitSlots[i].mEglDisplay = EGL_NO_DISPLAY; + } + } } void SurfaceTexture::freeAllBuffersExceptHeadLocked() { @@ -1200,6 +1314,82 @@ void SurfaceTexture::dump(String8& result, const char* prefix, } } +bool SurfaceTexture::conversionIsNeeded(const sp<GraphicBuffer>& graphicBuffer) { + int fmt = graphicBuffer->getPixelFormat(); + return (fmt == PIXEL_FORMAT_YCBCR42XMBN) || (fmt == PIXEL_FORMAT_YCbCr_420_P); +} + +status_t SurfaceTexture::convert() { + if (!mNeedsConversion) + return NO_ERROR; + + if (mConversionBltSlot < 0 || + mConversionBltSlot >= NUM_BLIT_BUFFER_SLOTS || + mConversionSrcSlot < 0 || + mConversionSrcSlot >= NUM_BUFFER_SLOTS) { + LOGE_IF(STE_DEFERDBG, "%s: Incorrect setup for deferred " + "texture conversion:\n" + "mConversionSrcSlot=%d mConversionBltSlot=%d", __FUNCTION__, + mConversionSrcSlot, mConversionBltSlot); + return BAD_VALUE; + } + + if (mSlots[mConversionSrcSlot].mGraphicBuffer == NULL) { + LOGI_IF(STE_DEFERDBG, "%s: NULL source for deferred texture conversion.", + __FUNCTION__); + return OK; + } + + if (mBlitSlots[mConversionBltSlot].mGraphicBuffer == NULL) { + LOGI_IF(STE_DEFERDBG, "%s: NULL destination for deferred " + "texture conversion.", __FUNCTION__); + return OK; + } + + return convert(mSlots[mConversionSrcSlot].mGraphicBuffer, + mBlitSlots[mConversionBltSlot].mGraphicBuffer); +} + +status_t SurfaceTexture::convert(sp<GraphicBuffer> &srcBuf, sp<GraphicBuffer> &dstBuf) { + copybit_image_t dstImg; + dstImg.w = dstBuf->getWidth(); + dstImg.h = dstBuf->getHeight(); + dstImg.format = dstBuf->getPixelFormat(); + dstImg.handle = (native_handle_t*) dstBuf->getNativeBuffer()->handle; + + copybit_image_t srcImg; + srcImg.w = srcBuf->getWidth(); + srcImg.h = srcBuf->getHeight(); + srcImg.format = srcBuf->getPixelFormat(); + srcImg.base = NULL; + srcImg.handle = (native_handle_t*) srcBuf->getNativeBuffer()->handle; + + copybit_rect_t dstCrop; + dstCrop.l = 0; + dstCrop.t = 0; + dstCrop.r = dstBuf->getWidth(); + dstCrop.b = dstBuf->getHeight(); + + copybit_rect_t srcCrop; + srcCrop.l = 0; + srcCrop.t = 0; + srcCrop.r = srcBuf->getWidth(); + srcCrop.b = srcBuf->getHeight(); + + region_iterator clip(Region(Rect(dstCrop.r, dstCrop.b))); + mBlitEngine->set_parameter(mBlitEngine, COPYBIT_TRANSFORM, 0); + mBlitEngine->set_parameter(mBlitEngine, COPYBIT_PLANE_ALPHA, 0xFF); + mBlitEngine->set_parameter(mBlitEngine, COPYBIT_DITHER, COPYBIT_ENABLE); + + int err = mBlitEngine->stretch( + mBlitEngine, &dstImg, &srcImg, &dstCrop, &srcCrop, &clip); + if (err != 0) { + LOGE("\nError: Blit stretch operation failed (err:%d)\n", err); + return UNKNOWN_ERROR; + } + return OK; +} + static void mtxMul(float out[16], const float a[16], const float b[16]) { out[0] = a[0]*b[0] + a[4]*b[1] + a[8]*b[2] + a[12]*b[3]; out[1] = a[1]*b[0] + a[5]*b[1] + a[9]*b[2] + a[13]*b[3]; diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk index fbabfc420cc5..90d401df1fac 100644 --- a/libs/ui/Android.mk +++ b/libs/ui/Android.mk @@ -40,6 +40,10 @@ include $(BUILD_HOST_STATIC_LIBRARY) include $(CLEAR_VARS) +ifeq ($(BOARD_HAVE_CODEC_SUPPORT),STERICSSON_CODEC_SUPPORT) + LOCAL_CFLAGS += -DSTERICSSON_CODEC_SUPPORT +endif + LOCAL_SRC_FILES:= \ $(commonSources) \ EGLUtils.cpp \ diff --git a/libs/ui/PixelFormat.cpp b/libs/ui/PixelFormat.cpp index ee186c84de9c..ec645dee621b 100644 --- a/libs/ui/PixelFormat.cpp +++ b/libs/ui/PixelFormat.cpp @@ -59,11 +59,21 @@ status_t getPixelFormatInfo(PixelFormat format, PixelFormatInfo* info) // YUV format from the HAL are handled here switch (format) { case HAL_PIXEL_FORMAT_YCbCr_422_SP: + case HAL_PIXEL_FORMAT_YCrCb_422_SP: + case HAL_PIXEL_FORMAT_YCbCr_422_P: case HAL_PIXEL_FORMAT_YCbCr_422_I: + case HAL_PIXEL_FORMAT_CbYCrY_422_I: info->bitsPerPixel = 16; goto done; + case HAL_PIXEL_FORMAT_YCbCr_420_SP: case HAL_PIXEL_FORMAT_YCrCb_420_SP: case HAL_PIXEL_FORMAT_YV12: + case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED: + case HAL_PIXEL_FORMAT_YCrCb_420_SP_TILED: + case HAL_PIXEL_FORMAT_YCbCr_420_P: + case HAL_PIXEL_FORMAT_YCbCr_420_I: + case HAL_PIXEL_FORMAT_CbYCrY_420_I: + case HAL_PIXEL_FORMAT_YCBCR42XMBN: info->bitsPerPixel = 12; done: info->format = format; diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 8d71dcf644d0..b8ed9edb5bbf 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -808,7 +808,8 @@ public class MediaPlayer } /** - * Sets the data source (file-path or http/rtsp URL) to use. + * Sets the data source (file-path or http/rtsp URL) to use. To select FM Radio as the data + * source, set the path to "fmradio://rx". * * @param path the path of the file, or the http/rtsp URL of the stream you want to play * @throws IllegalStateException if it is called in an invalid state diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java index 08e603252c5c..c1f2f62c260b 100644 --- a/media/java/android/media/MediaRecorder.java +++ b/media/java/android/media/MediaRecorder.java @@ -168,6 +168,8 @@ public class MediaRecorder * is applied. */ public static final int VOICE_COMMUNICATION = 7; + /** FM Radio Rx audio source */ + public static final int FM_RADIO_RX = 8; } /** diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk index 7af4a8753576..190f8c3844da 100644 --- a/media/libmedia/Android.mk +++ b/media/libmedia/Android.mk @@ -2,6 +2,14 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) +ifeq ($(BOARD_HAVE_CODEC_SUPPORT),STERICSSON_CODEC_SUPPORT) + LOCAL_CFLAGS += -DSTERICSSON_CODEC_SUPPORT +endif + +ifeq ($(BOARD_HAVE_FMRADIO_SUPPORT),STERICSSON_FMRADIO_SUPPORT) + LOCAL_CFLAGS += -DSTERICSSON_FMRADIO_SUPPORT +endif + LOCAL_SRC_FILES:= \ AudioParameter.cpp LOCAL_MODULE:= libmedia_helper @@ -11,6 +19,14 @@ include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) +ifeq ($(BOARD_HAVE_CODEC_SUPPORT),STERICSSON_CODEC_SUPPORT) + LOCAL_CFLAGS += -DSTERICSSON_CODEC_SUPPORT +endif + +ifeq ($(BOARD_HAVE_FMRADIO_SUPPORT),STERICSSON_FMRADIO_SUPPORT) + LOCAL_CFLAGS += -DSTERICSSON_FMRADIO_SUPPORT +endif + LOCAL_SRC_FILES:= \ AudioTrack.cpp \ IAudioFlinger.cpp \ diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 7b14c183b68e..4ec0483850b0 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -44,7 +44,6 @@ int AudioSystem::gPrevInFormat = AUDIO_FORMAT_PCM_16_BIT; int AudioSystem::gPrevInChannelCount = 1; size_t AudioSystem::gInBuffSize = 0; - // establish binder interface to AudioFlinger service const sp<IAudioFlinger>& AudioSystem::get_audio_flinger() { @@ -626,11 +625,12 @@ audio_io_handle_t AudioSystem::getInput(int inputSource, uint32_t format, uint32_t channels, audio_in_acoustics_t acoustics, - int sessionId) + int sessionId, + audio_input_clients *inputClientId) { const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); if (aps == 0) return 0; - return aps->getInput(inputSource, samplingRate, format, channels, acoustics, sessionId); + return aps->getInput(inputSource, samplingRate, format, channels, acoustics, sessionId, inputClientId); } status_t AudioSystem::startInput(audio_io_handle_t input) diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index d58834b81684..1d1b72238acb 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -69,7 +69,8 @@ enum { QUERY_EFFECT, GET_EFFECT_DESCRIPTOR, CREATE_EFFECT, - MOVE_EFFECTS + MOVE_EFFECTS, + READ_INPUT }; class BpAudioFlinger : public BpInterface<IAudioFlinger> @@ -432,7 +433,8 @@ public: uint32_t *pSamplingRate, uint32_t *pFormat, uint32_t *pChannels, - uint32_t acoustics) + uint32_t acoustics, + uint32_t *pInputClientId) { Parcel data, reply; uint32_t devices = pDevices ? *pDevices : 0; @@ -446,6 +448,7 @@ public: data.writeInt32(format); data.writeInt32(channels); data.writeInt32(acoustics); + data.writeIntPtr((intptr_t)pInputClientId); remote()->transact(OPEN_INPUT, data, &reply); int input = reply.readInt32(); devices = reply.readInt32(); @@ -459,11 +462,12 @@ public: return input; } - virtual status_t closeInput(int input) + virtual status_t closeInput(int input, uint32_t *inputClientId) { Parcel data, reply; data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); data.writeInt32(input); + data.writeIntPtr((intptr_t) inputClientId); remote()->transact(CLOSE_INPUT, data, &reply); return reply.readInt32(); } @@ -516,6 +520,20 @@ public: return reply.readInt32(); } + virtual size_t readInput(uint32_t *input, uint32_t inputClientId, void *buffer, uint32_t bytes, uint32_t *pOverwrittenBytes) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.writeIntPtr((intptr_t) input); + data.writeInt32(inputClientId); + data.writeIntPtr((intptr_t) buffer); + data.writeInt32(bytes); + data.writeIntPtr((intptr_t) pOverwrittenBytes); + remote()->transact(READ_INPUT, data, &reply); + + return reply.readInt32(); + } + virtual int newAudioSessionId() { Parcel data, reply; @@ -882,12 +900,14 @@ status_t BnAudioFlinger::onTransact( uint32_t format = data.readInt32(); uint32_t channels = data.readInt32(); uint32_t acoutics = data.readInt32(); + uint32_t *inputClientId = (uint32_t*) data.readIntPtr(); int input = openInput(&devices, &samplingRate, &format, &channels, - acoutics); + acoutics, + inputClientId); reply->writeInt32(input); reply->writeInt32(devices); reply->writeInt32(samplingRate); @@ -897,7 +917,9 @@ status_t BnAudioFlinger::onTransact( } break; case CLOSE_INPUT: { CHECK_INTERFACE(IAudioFlinger, data, reply); - reply->writeInt32(closeInput(data.readInt32())); + uint32_t input = data.readInt32(); + uint32_t *inputClientId = (uint32_t*) data.readIntPtr(); + reply->writeInt32(closeInput(input, inputClientId)); return NO_ERROR; } break; case SET_STREAM_OUTPUT: { @@ -1010,6 +1032,16 @@ status_t BnAudioFlinger::onTransact( reply->writeInt32(moveEffects(session, srcOutput, dstOutput)); return NO_ERROR; } break; + case READ_INPUT: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + uint32_t* input = (uint32_t*) data.readIntPtr(); + uint32_t inputClientId = data.readInt32(); + void* buffer = (void*) data.readIntPtr(); + uint32_t bytes = data.readInt32(); + uint32_t *pOverwrittenBytes = (uint32_t*) data.readIntPtr(); + reply->writeInt32(readInput(input, inputClientId, buffer, bytes, pOverwrittenBytes)); + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp index 50b4855a8e8d..7dc9e566e586 100644 --- a/media/libmedia/IAudioPolicyService.cpp +++ b/media/libmedia/IAudioPolicyService.cpp @@ -187,7 +187,8 @@ public: uint32_t format, uint32_t channels, audio_in_acoustics_t acoustics, - int audioSession) + int audioSession, + audio_input_clients *inputClientId) { Parcel data, reply; data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); @@ -196,6 +197,7 @@ public: data.writeInt32(static_cast <uint32_t>(format)); data.writeInt32(channels); data.writeInt32(static_cast <uint32_t>(acoustics)); + data.writeIntPtr((intptr_t)inputClientId); data.writeInt32(audioSession); remote()->transact(GET_INPUT, data, &reply); return static_cast <audio_io_handle_t> (reply.readInt32()); @@ -478,13 +480,16 @@ status_t BnAudioPolicyService::onTransact( uint32_t channels = data.readInt32(); audio_in_acoustics_t acoustics = static_cast <audio_in_acoustics_t>(data.readInt32()); + audio_input_clients *inputClientId = + (audio_input_clients*) data.readIntPtr(); int audioSession = data.readInt32(); audio_io_handle_t input = getInput(inputSource, samplingRate, format, channels, acoustics, - audioSession); + audioSession, + inputClientId); reply->writeInt32(static_cast <int>(input)); return NO_ERROR; } break; diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk index a3e2517b37d2..ec89f6fabe0d 100644 --- a/media/libmediaplayerservice/Android.mk +++ b/media/libmediaplayerservice/Android.mk @@ -6,6 +6,10 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) +ifeq ($(BOARD_HAVE_CODEC_SUPPORT),STERICSSON_CODEC_SUPPORT) + LOCAL_CFLAGS += -DSTERICSSON_CODEC_SUPPORT +endif + LOCAL_SRC_FILES:= \ MediaRecorderClient.cpp \ MediaPlayerService.cpp \ diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 011c0b972583..736e7eed5b85 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -1503,7 +1503,7 @@ void MediaPlayerService::AudioOutput::CallbackWrapper( AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info; size_t actualSize = (*me->mCallback)( - me, buffer->raw, buffer->size, me->mCallbackCookie); + me, buffer->raw, buffer->size, me->mCallbackCookie); if (actualSize == 0 && buffer->size > 0) { // We've reached EOS but the audio track is not stopped yet, diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h index b04fddb59a8b..fc46eab07c89 100644 --- a/media/libmediaplayerservice/MediaPlayerService.h +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -85,7 +85,6 @@ class MediaPlayerService : public BnMediaPlayerService uint32_t sampleRate, int channelCount, int format, int bufferCount, AudioCallback cb, void *cookie); - virtual void start(); virtual ssize_t write(const void* buffer, size_t size); virtual void stop(); diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index e57878575b76..ff45d48a547e 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -6,6 +6,11 @@ include frameworks/base/media/libstagefright/codecs/common/Config.mk ifeq ($(BOARD_HAVE_CODEC_SUPPORT),SAMSUNG_CODEC_SUPPORT) LOCAL_CFLAGS += -DSAMSUNG_CODEC_SUPPORT endif + +ifeq ($(BOARD_HAVE_CODEC_SUPPORT),STERICSSON_CODEC_SUPPORT) + LOCAL_CFLAGS += -DSTERICSSON_CODEC_SUPPORT +endif + LOCAL_SRC_FILES:= \ ACodec.cpp \ AACExtractor.cpp \ @@ -40,6 +45,7 @@ LOCAL_SRC_FILES:= \ OMXClient.cpp \ OMXCodec.cpp \ OggExtractor.cpp \ + PCMExtractor.cpp \ SampleIterator.cpp \ SampleTable.cpp \ StagefrightMediaScanner.cpp \ diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index bc45f83d3d96..1b4f79f89d69 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -40,6 +40,7 @@ #include <media/stagefright/AudioPlayer.h> #include <media/stagefright/DataSource.h> #include <media/stagefright/FileSource.h> +#include <media/stagefright/FMRadioDataSource.h> #include <media/stagefright/MediaBuffer.h> #include <media/stagefright/MediaDefs.h> #include <media/stagefright/MediaExtractor.h> @@ -1943,6 +1944,7 @@ status_t AwesomePlayer::prepareAsync_l() { status_t AwesomePlayer::finishSetDataSource_l() { sp<DataSource> dataSource; + char *mime = NULL; bool isWidevineStreaming = false; if (!strncasecmp("widevine://", mUri.string(), 11)) { isWidevineStreaming = true; @@ -2081,6 +2083,15 @@ status_t AwesomePlayer::finishSetDataSource_l() { return UNKNOWN_ERROR; } } + } else if (!strncasecmp("fmradio://rx", mUri.string(), 12)) { + + mime = (char*) MEDIA_MIMETYPE_AUDIO_RAW; + // HACK: Removed the line below since it causes problems. Add it back if you want FM-Radio. + //dataSource = new FMRadioDataSource(); + status_t err = dataSource->initCheck(); + if (err != OK) { + return err; + } } else { dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders); } @@ -2107,8 +2118,7 @@ status_t AwesomePlayer::finishSetDataSource_l() { mWVMExtractor->setAdaptiveStreamingMode(true); extractor = mWVMExtractor; } else { - extractor = MediaExtractor::Create( - dataSource, sniffedMIME.empty() ? NULL : sniffedMIME.c_str()); + extractor = MediaExtractor::Create(dataSource, mime); if (extractor == NULL) { return UNKNOWN_ERROR; diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp index 57989c5e4a4a..11502ebf2994 100755..100644 --- a/media/libstagefright/CameraSource.cpp +++ b/media/libstagefright/CameraSource.cpp @@ -111,6 +111,10 @@ static int32_t getColorFormat(const char* colorFormat) { return OMX_TI_COLOR_FormatYUV420PackedSemiPlanar; } + if (!strcmp(colorFormat, CameraParameters::PIXEL_FORMAT_YUV420MB)) { + return OMX_STE_COLOR_FormatYUV420PackedSemiPlanarMB; + } + LOGE("Uknown color format (%s), please add it to " "CameraSource::getColorFormat", colorFormat); @@ -535,13 +539,16 @@ status_t CameraSource::initWithCameraAccess( // XXX: query camera for the stride and slice height // when the capability becomes available. + int stride = newCameraParams.getInt(CameraParameters::KEY_RECORD_STRIDE); + int sliceHeight = newCameraParams.getInt(CameraParameters::KEY_RECORD_SLICE_HEIGHT); + mMeta = new MetaData; mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW); mMeta->setInt32(kKeyColorFormat, mColorFormat); mMeta->setInt32(kKeyWidth, mVideoSize.width); mMeta->setInt32(kKeyHeight, mVideoSize.height); - mMeta->setInt32(kKeyStride, mVideoSize.width); - mMeta->setInt32(kKeySliceHeight, mVideoSize.height); + mMeta->setInt32(kKeyStride, stride != -1 ? stride : mVideoSize.width); + mMeta->setInt32(kKeySliceHeight, sliceHeight != -1 ? sliceHeight : mVideoSize.height); mMeta->setInt32(kKeyFrameRate, mVideoFrameRate); return OK; } diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp index 43539bb8d2ac..8f8257136b6d 100644 --- a/media/libstagefright/DataSource.cpp +++ b/media/libstagefright/DataSource.cpp @@ -20,6 +20,7 @@ #include "include/WAVExtractor.h" #include "include/OggExtractor.h" #include "include/MPEG2PSExtractor.h" +#include "include/PCMExtractor.h" #include "include/MPEG2TSExtractor.h" #include "include/NuCachedSource2.h" #include "include/HTTPBase.h" @@ -32,6 +33,7 @@ #include <media/stagefright/foundation/AMessage.h> #include <media/stagefright/DataSource.h> #include <media/stagefright/FileSource.h> +#include <media/stagefright/FMRadioDataSource.h> #include <media/stagefright/MediaErrors.h> #include <utils/String8.h> diff --git a/media/libstagefright/FMRadioDataSource.cpp b/media/libstagefright/FMRadioDataSource.cpp new file mode 100644 index 000000000000..09780f26e6e8 --- /dev/null +++ b/media/libstagefright/FMRadioDataSource.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Copyright (C) 2010 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. + * + * Author: Andreas Gustafsson (andreas.a.gustafsson@stericsson.com) + * for ST-Ericsson + */ + +#define LOG_TAG "FMRadioDataSource" +#include <utils/Log.h> + +#include <media/stagefright/FMRadioDataSource.h> +#include <media/stagefright/MediaDebug.h> +#include <media/AudioSystem.h> +#include <media/IAudioPolicyService.h> +#include <binder/IServiceManager.h> +#include <media/AudioSystem.h> +#include <media/mediarecorder.h> +#include <media/IAudioFlinger.h> +#include <system/audio.h> + + +namespace android { + +FMRadioDataSource::FMRadioDataSource() { + + mFormat = android_audio_legacy::AudioSystem::PCM_16_BIT; + mChannels = android_audio_legacy::AudioSystem::CHANNEL_IN_STEREO; + mSampleRate = 48000; + mFlags = 0; + mOverwrittenBytes = 0; + mInputClientId = AUDIO_INPUT_CLIENT_PLAYBACK; + int inputSource = AUDIO_SOURCE_FM_RADIO_RX; + + mStream = (android_audio_legacy::AudioStreamIn*) AudioSystem::getInput(inputSource,mSampleRate, mFormat, mChannels, + (audio_in_acoustics_t)mFlags,0,&mInputClientId); + if (mStream != NULL) { + AudioSystem::startInput((audio_io_handle_t) mStream); + } +} + +FMRadioDataSource::~FMRadioDataSource() { + + if (mStream != NULL) { + AudioSystem::stopInput((audio_io_handle_t) mStream); + AudioSystem::releaseInput((audio_io_handle_t) mStream); + } +} + +status_t FMRadioDataSource::initCheck() const { + return mStream != NULL ? OK : NO_INIT; +} + +ssize_t FMRadioDataSource::readAt(off64_t offset, void *data, size_t size) { + if(mStream != NULL) { + const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); + return af->readInput((uint32_t*)mStream, mInputClientId, data, size, &mOverwrittenBytes); + } + return 0; +} + +status_t FMRadioDataSource::getSize(off64_t *size) { + *size = 0; + return OK; +} + +uint32_t FMRadioDataSource::getBufferSize() { + return mStream->bufferSize(); +} + +uint32_t FMRadioDataSource::getNumChannels() { + return android_audio_legacy::AudioSystem::popCount(mChannels); +} + +uint32_t FMRadioDataSource::getSampleRate() { + return mSampleRate; +} + +uint32_t FMRadioDataSource::getFormat() { + if (mFormat == android_audio_legacy::AudioSystem::PCM_16_BIT) { + return 16; + } else if (mFormat == android_audio_legacy::AudioSystem::PCM_8_BIT) { + return 8; + } + return 0; +} + +} // namespace android diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index 46d87df66889..46d87df66889 100755..100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp index 444e823295a3..43e305c8c62f 100644 --- a/media/libstagefright/MediaDefs.cpp +++ b/media/libstagefright/MediaDefs.cpp @@ -24,8 +24,10 @@ const char *MEDIA_MIMETYPE_VIDEO_VPX = "video/x-vnd.on2.vp8"; const char *MEDIA_MIMETYPE_VIDEO_AVC = "video/avc"; const char *MEDIA_MIMETYPE_VIDEO_MPEG4 = "video/mp4v-es"; const char *MEDIA_MIMETYPE_VIDEO_H263 = "video/3gpp"; +const char *MEDIA_MIMETYPE_VIDEO_H263_SW = "video/3gpp-sw"; const char *MEDIA_MIMETYPE_VIDEO_MPEG2 = "video/mpeg2"; const char *MEDIA_MIMETYPE_VIDEO_RAW = "video/raw"; +const char *MEDIA_MIMETYPE_VIDEO_VC1 = "video/vc1"; const char *MEDIA_MIMETYPE_AUDIO_AMR_NB = "audio/3gpp"; const char *MEDIA_MIMETYPE_AUDIO_AMR_WB = "audio/amr-wb"; diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp index 374ecf703613..93fe491e2083 100644 --- a/media/libstagefright/MediaExtractor.cpp +++ b/media/libstagefright/MediaExtractor.cpp @@ -24,6 +24,7 @@ #include "include/WAVExtractor.h" #include "include/OggExtractor.h" #include "include/MPEG2PSExtractor.h" +#include "include/PCMExtractor.h" #include "include/MPEG2TSExtractor.h" #include "include/DRMExtractor.h" #include "include/WVMExtractor.h" @@ -115,6 +116,8 @@ sp<MediaExtractor> MediaExtractor::Create( ret = new AACExtractor(source); } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2PS)) { ret = new MPEG2PSExtractor(source); + } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) { + ret = new PCMExtractor(source); } if (ret != NULL) { diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index c080b6c31f2a..33e85a9a06ff 100755..100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -117,6 +117,7 @@ static sp<MediaSource> InstantiateSoftwareEncoder( static const CodecInfo kDecoderInfo[] = { { MEDIA_MIMETYPE_IMAGE_JPEG, "OMX.TI.JPEG.decode" }, + { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.ST.mp3.decoder" }, // { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.TI.MP3.decode" }, { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.google.mp3.decoder" }, { MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II, "OMX.Nvidia.mp2.decoder" }, @@ -126,11 +127,13 @@ static const CodecInfo kDecoderInfo[] = { // { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.Nvidia.amrwb.decoder" }, { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.TI.WBAMR.decode" }, { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.google.amrwb.decoder" }, + { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.ST.aac.decoder" }, // { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.Nvidia.aac.decoder" }, { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.decode" }, { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.google.aac.decoder" }, { MEDIA_MIMETYPE_AUDIO_G711_ALAW, "OMX.google.g711.alaw.decoder" }, { MEDIA_MIMETYPE_AUDIO_G711_MLAW, "OMX.google.g711.mlaw.decoder" }, + { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.ST.VFM.MPEG4Dec" }, { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.DUCATI1.VIDEO.DECODER" }, { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.Nvidia.mp4.decode" }, { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.7x30.video.decoder.mpeg4" }, @@ -138,12 +141,15 @@ static const CodecInfo kDecoderInfo[] = { { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.Video.Decoder" }, { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.SEC.MPEG4.Decoder" }, { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.google.mpeg4.decoder" }, + { MEDIA_MIMETYPE_VIDEO_H263, "OMX.ST.VFM.MPEG4Dec" }, { MEDIA_MIMETYPE_VIDEO_H263, "OMX.TI.DUCATI1.VIDEO.DECODER" }, { MEDIA_MIMETYPE_VIDEO_H263, "OMX.Nvidia.h263.decode" }, { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.7x30.video.decoder.h263" }, { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.decoder.h263" }, { MEDIA_MIMETYPE_VIDEO_H263, "OMX.SEC.H263.Decoder" }, { MEDIA_MIMETYPE_VIDEO_H263, "OMX.google.h263.decoder" }, + { MEDIA_MIMETYPE_VIDEO_H263_SW, "OMX.ST.VFM.MPEG4HostDec" }, + { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.ST.VFM.H264Dec" }, { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.DUCATI1.VIDEO.DECODER" }, { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.Nvidia.h264.decode" }, { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.7x30.video.decoder.avc" }, @@ -155,6 +161,7 @@ static const CodecInfo kDecoderInfo[] = { { MEDIA_MIMETYPE_AUDIO_VORBIS, "OMX.google.vorbis.decoder" }, { MEDIA_MIMETYPE_VIDEO_VPX, "OMX.google.vpx.decoder" }, { MEDIA_MIMETYPE_VIDEO_MPEG2, "OMX.Nvidia.mpeg2v.decode" }, + { MEDIA_MIMETYPE_VIDEO_VC1, "OMX.ST.VFM.VC1Dec" }, }; static const CodecInfo kEncoderInfo[] = { @@ -164,6 +171,7 @@ static const CodecInfo kEncoderInfo[] = { { MEDIA_MIMETYPE_AUDIO_AMR_WB, "AMRWBEncoder" }, { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.encode" }, { MEDIA_MIMETYPE_AUDIO_AAC, "AACEncoder" }, + { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.ST.VFM.MPEG4Enc" }, { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.DUCATI1.VIDEO.MPEG4E" }, { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.7x30.video.encoder.mpeg4" }, { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.video.encoder.mpeg4" }, @@ -171,6 +179,7 @@ static const CodecInfo kEncoderInfo[] = { { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.Nvidia.mp4.encoder" }, { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.SEC.MPEG4.Encoder" }, { MEDIA_MIMETYPE_VIDEO_MPEG4, "M4vH263Encoder" }, + { MEDIA_MIMETYPE_VIDEO_H263, "OMX.ST.VFM.MPEG4Enc" }, { MEDIA_MIMETYPE_VIDEO_H263, "OMX.TI.DUCATI1.VIDEO.MPEG4E" }, { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.7x30.video.encoder.h263" }, { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.encoder.h263" }, @@ -178,6 +187,7 @@ static const CodecInfo kEncoderInfo[] = { { MEDIA_MIMETYPE_VIDEO_H263, "OMX.Nvidia.h263.encoder" }, { MEDIA_MIMETYPE_VIDEO_H263, "OMX.SEC.H263.Encoder" }, { MEDIA_MIMETYPE_VIDEO_H263, "M4vH263Encoder" }, + { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.ST.VFM.H264Enc" }, { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.DUCATI1.VIDEO.H264E" }, { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.7x30.video.encoder.avc" }, { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.video.encoder.avc" }, @@ -292,6 +302,18 @@ static int CompareSoftwareCodecsFirst( return 0; } +static uint32_t OmxToHALFormat(OMX_COLOR_FORMATTYPE omxValue) { + switch (omxValue) { + case OMX_STE_COLOR_FormatYUV420PackedSemiPlanarMB: + return HAL_PIXEL_FORMAT_YCBCR42XMBN; + case OMX_COLOR_FormatYUV420Planar: + return HAL_PIXEL_FORMAT_YCbCr_420_P; + default: + LOGI("Unknown OMX pixel format (0x%X), passing it on unchanged", omxValue); + return omxValue; + } +} + // static uint32_t OMXCodec::getComponentQuirks( const char *componentName, bool isEncoder) { @@ -376,6 +398,17 @@ uint32_t OMXCodec::getComponentQuirks( quirks |= kOutputBuffersAreUnreadable; } + if (!isEncoder && !strncmp(componentName, "OMX.ST.VFM.", 11)) { + quirks |= kRequiresAllocateBufferOnInputPorts; + quirks |= kRequiresAllocateBufferOnOutputPorts; + } + + if (!strncmp(componentName, "OMX.ST.VFM.MPEG4Enc", 19) || + !strncmp(componentName, "OMX.ST.VFM.H264Enc", 18)) { + quirks |= kRequiresAllocateBufferOnOutputPorts; + quirks |= kRequiresStoreMetaDataBeforeIdle; + } + return quirks; } @@ -901,6 +934,7 @@ static size_t getFrameSize( case OMX_COLOR_FormatYUV420Planar: case OMX_COLOR_FormatYUV420SemiPlanar: case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar: + case OMX_STE_COLOR_FormatYUV420PackedSemiPlanarMB: /* * FIXME: For the Opaque color format, the frame size does not * need to be (w*h*3)/2. It just needs to @@ -1432,7 +1466,7 @@ status_t OMXCodec::setVideoOutputFormat( || 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_STE_COLOR_FormatYUV420PackedSemiPlanarMB #ifdef SAMSUNG_CODEC_SUPPORT || format.eColorFormat == OMX_SEC_COLOR_FormatNV12TPhysicalAddress || format.eColorFormat == OMX_SEC_COLOR_FormatNV12Tiled @@ -1590,6 +1624,8 @@ void OMXCodec::setComponentRole( "video_decoder.mpeg4", "video_encoder.mpeg4" }, { MEDIA_MIMETYPE_VIDEO_H263, "video_decoder.h263", "video_encoder.h263" }, + { MEDIA_MIMETYPE_VIDEO_VC1, + "video_decoder.vc1", "video_encoder.vc1" }, }; static const size_t kNumMimeToRole = @@ -1659,6 +1695,15 @@ status_t OMXCodec::init() { CHECK_EQ((int)mState, (int)LOADED); status_t err; + if ((mQuirks & kRequiresStoreMetaDataBeforeIdle) + && (mFlags & kStoreMetaDataInVideoBuffers)) { + err = mOMX->storeMetaDataInBuffers(mNode, kPortIndexInput, OMX_TRUE); + if (err != OK) { + LOGE("Storing meta data in video buffers is not supported"); + return err; + } + } + if (!(mQuirks & kRequiresLoadedToIdleAfterAllocation)) { err = mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle); CHECK_EQ(err, (status_t)OK); @@ -1714,7 +1759,8 @@ status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) { } status_t err = OK; - if ((mFlags & kStoreMetaDataInVideoBuffers) + if (!(mQuirks & kRequiresStoreMetaDataBeforeIdle) + && (mFlags & kStoreMetaDataInVideoBuffers) && portIndex == kPortIndexInput) { err = mOMX->storeMetaDataInBuffers(mNode, kPortIndexInput, OMX_TRUE); if (err != OK) { @@ -1891,8 +1937,8 @@ status_t OMXCodec::allocateOutputBuffersFromNativeWindow() { mNativeWindow.get(), def.format.video.nFrameWidth, def.format.video.nFrameHeight, - def.format.video.eColorFormat); -#else + OmxToHALFormat(def.format.video.eColorFormat)); +#else /* SAMSUNG_CODEC_SUPPORT */ OMX_COLOR_FORMATTYPE eColorFormat; switch (def.format.video.eColorFormat) { @@ -4272,6 +4318,7 @@ static const char *videoCompressionFormatString(OMX_VIDEO_CODINGTYPE type) { "OMX_VIDEO_CodingRV", "OMX_VIDEO_CodingAVC", "OMX_VIDEO_CodingMJPEG", + "OMX_VIDEO_CodingVC1", }; size_t numNames = sizeof(kNames) / sizeof(kNames[0]); diff --git a/media/libstagefright/PCMExtractor.cpp b/media/libstagefright/PCMExtractor.cpp new file mode 100644 index 000000000000..d85af33e63f7 --- /dev/null +++ b/media/libstagefright/PCMExtractor.cpp @@ -0,0 +1,276 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Copyright (C) 2010 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. + * + * Author: Andreas Gustafsson (andreas.a.gustafsson@stericsson.com) + * for ST-Ericsson + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "PCMExtractor" +#include <utils/Log.h> + +#include "include/PCMExtractor.h" + +#include <media/stagefright/DataSource.h> +#include <media/stagefright/MediaBufferGroup.h> +#include <media/stagefright/MediaDebug.h> +#include <media/stagefright/MediaDefs.h> +#include <media/stagefright/MediaErrors.h> +#include <media/stagefright/MetaData.h> +#include <utils/String8.h> + +namespace android { + +static const uint16_t kDefaultNumChannels = 2; +static const uint32_t kDefaultSampleRate = 48000; +static const uint16_t kDefaultFormat = 16; + +struct PCMSource : public MediaSource { + PCMSource( + const sp<DataSource> &dataSource, + const sp<MetaData> &meta, + int32_t bitsPerSample, + off_t offset, size_t size); + + virtual status_t start(MetaData *params = NULL); + virtual status_t stop(); + virtual sp<MetaData> getFormat(); + + virtual status_t read( + MediaBuffer **buffer, const ReadOptions *options = NULL); + +protected: + virtual ~PCMSource(); + +private: + static const size_t kMaxFrameSize; + + sp<DataSource> mDataSource; + sp<MetaData> mMeta; + int32_t mSampleRate; + int32_t mNumChannels; + int32_t mBitsPerSample; + off_t mOffset; + size_t mSize; + bool mStarted; + MediaBufferGroup *mGroup; + off_t mCurrentPos; + uint32_t mBufferSize; + + PCMSource(const PCMSource &); + PCMSource &operator=(const PCMSource &); +}; + +PCMExtractor::PCMExtractor(const sp<DataSource> &source) + : mDataSource(source), + mValidFormat(false) { + mInitCheck = init(); +} + +PCMExtractor::~PCMExtractor() { +} + +sp<MetaData> PCMExtractor::getMetaData() { + sp<MetaData> meta = new MetaData; + + if (mInitCheck != OK) { + return meta; + } + + meta->setCString(kKeyMIMEType, "audio/raw"); + + return meta; +} + +size_t PCMExtractor::countTracks() { + return mInitCheck == OK ? 1 : 0; +} + +sp<MediaSource> PCMExtractor::getTrack(size_t index) { + if (mInitCheck != OK || index > 0) { + return NULL; + } + + return new PCMSource( + mDataSource, mTrackMeta, + mBitsPerSample, mDataOffset, mDataSize); +} + +sp<MetaData> PCMExtractor::getTrackMetaData( + size_t index, uint32_t flags) { + if (mInitCheck != OK || index > 0) { + return NULL; + } + + return mTrackMeta; +} + +status_t PCMExtractor::init() { + mNumChannels = kDefaultNumChannels; + mSampleRate = kDefaultSampleRate; + mBitsPerSample = kDefaultFormat; + mDataOffset = 0; + mDataSize = 0; + mValidFormat = true; + mTrackMeta = new MetaData;mTrackMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW); + mTrackMeta->setInt32(kKeyChannelCount, mNumChannels); + mTrackMeta->setInt32(kKeySampleRate, mSampleRate); + return OK; +} + +const size_t PCMSource::kMaxFrameSize = 4800; + +PCMSource::PCMSource( + const sp<DataSource> &dataSource, + const sp<MetaData> &meta, + int32_t bitsPerSample, + off_t offset, size_t size) + : mDataSource(dataSource), + mMeta(meta), + mSampleRate(0), + mNumChannels(0), + mBitsPerSample(bitsPerSample), + mOffset(offset), + mSize(size), + mStarted(false), + mGroup(NULL), + mBufferSize(0) { + CHECK(mMeta->findInt32(kKeySampleRate, &mSampleRate)); + CHECK(mMeta->findInt32(kKeyChannelCount, &mNumChannels)); +} + +PCMSource::~PCMSource() { + if (mStarted) { + stop(); + } +} + +status_t PCMSource::start(MetaData *params) { + CHECK(!mStarted); + + mBufferSize = kMaxFrameSize; + mGroup = new MediaBufferGroup; + mGroup->add_buffer(new MediaBuffer(mBufferSize)); + + if (mBitsPerSample == 8) { + // As a temporary buffer for 8->16 bit conversion. + mGroup->add_buffer(new MediaBuffer(mBufferSize)); + } + + mCurrentPos = mOffset; + + mStarted = true; + return OK; +} + +status_t PCMSource::stop() { + + CHECK(mStarted); + delete mGroup; + mGroup = NULL; + + mStarted = false; + return OK; +} + +sp<MetaData> PCMSource::getFormat() { + return mMeta; +} + +status_t PCMSource::read( + MediaBuffer **out, const ReadOptions *options) { + *out = NULL; + int64_t seekTimeUs; + ReadOptions::SeekMode seek = ReadOptions::SEEK_CLOSEST_SYNC; + if (options != NULL && options->getSeekTo(&seekTimeUs,&seek)) { + int64_t pos = (seekTimeUs * mSampleRate) / 1000000 * mNumChannels * 2; + if (pos > mSize) { + pos = mSize; + } + mCurrentPos = pos + mOffset; + } + + MediaBuffer *buffer; + status_t err = mGroup->acquire_buffer(&buffer); + if (err != OK) { + return err; + } + + ssize_t n = mDataSource->readAt( + mCurrentPos, buffer->data(), mBufferSize); + if (n <= 0) { + buffer->release(); + buffer = NULL; + return ERROR_END_OF_STREAM; + } + + mCurrentPos += n; + + buffer->set_range(0, n); + + if (mBitsPerSample == 8) { + // Convert 8-bit unsigned samples to 16-bit signed. + + MediaBuffer *tmp; + CHECK_EQ(mGroup->acquire_buffer(&tmp), OK); + + // The new buffer holds the sample number of samples, but each + // one is 2 bytes wide. + tmp->set_range(0, 2 * n); + + int16_t *dst = (int16_t *)tmp->data(); + const uint8_t *src = (const uint8_t *)buffer->data(); + while (n-- > 0) { + *dst++ = ((int16_t)(*src) - 128) * 256; + ++src; + } + + buffer->release(); + buffer = tmp; + } else if (mBitsPerSample == 24) { + // Convert 24-bit signed samples to 16-bit signed. + + const uint8_t *src = + (const uint8_t *)buffer->data() + buffer->range_offset(); + int16_t *dst = (int16_t *)src; + + size_t numSamples = buffer->range_length() / 3; + for (size_t i = 0; i < numSamples; ++i) { + int32_t x = (int32_t)(src[0] | src[1] << 8 | src[2] << 16); + x = (x << 8) >> 8; // sign extension + + x = x >> 8; + *dst++ = (int16_t)x; + src += 3; + } + + buffer->set_range(buffer->range_offset(), 2 * numSamples); + } + + size_t bytesPerSample = mBitsPerSample >> 3; + + buffer->meta_data()->setInt64( + kKeyTime, + 1000000LL * (mCurrentPos - mOffset) + / (mNumChannels * bytesPerSample) / mSampleRate); + + + *out = buffer; + + return OK; +} + +} // namespace android diff --git a/media/libstagefright/colorconversion/Android.mk b/media/libstagefright/colorconversion/Android.mk index 62ba40f449bc..89ed50f2b454 100644 --- a/media/libstagefright/colorconversion/Android.mk +++ b/media/libstagefright/colorconversion/Android.mk @@ -1,6 +1,10 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) +ifeq ($(BOARD_HAVE_CODEC_SUPPORT),STERICSSON_CODEC_SUPPORT) + LOCAL_CFLAGS += -DSTERICSSON_CODEC_SUPPORT +endif + LOCAL_SRC_FILES:= \ ColorConverter.cpp \ SoftwareRenderer.cpp diff --git a/media/libstagefright/colorconversion/ColorConverter.cpp b/media/libstagefright/colorconversion/ColorConverter.cpp index 5cc3f78804ab..70ef74eba1c7 100644 --- a/media/libstagefright/colorconversion/ColorConverter.cpp +++ b/media/libstagefright/colorconversion/ColorConverter.cpp @@ -47,6 +47,7 @@ bool ColorConverter::isValid() const { case OMX_QCOM_COLOR_FormatYVU420SemiPlanar: case OMX_COLOR_FormatYUV420SemiPlanar: case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar: + case OMX_STE_COLOR_FormatYUV420PackedSemiPlanarMB: return true; default: @@ -122,6 +123,10 @@ status_t ColorConverter::convert( err = convertTIYUV420PackedSemiPlanar(src, dst); break; + case OMX_STE_COLOR_FormatYUV420PackedSemiPlanarMB: + err = convertSTEYUV420PackedSemiPlanarMB(src, dst); + break; + default: { CHECK(!"Should not be here. Unknown color conversion."); @@ -493,6 +498,143 @@ status_t ColorConverter::convertTIYUV420PackedSemiPlanar( return OK; } +status_t ColorConverter::convertSTEYUV420PackedSemiPlanarMB( + const BitmapParams &src, const BitmapParams &dst) { + + if (!((dst.mWidth & 1) == 0 + && src.mCropLeft == 0 + && src.mCropTop == 0 + && src.cropWidth() == dst.cropWidth() + && src.cropHeight() == dst.cropHeight())) { + return ERROR_UNSUPPORTED; + } + + OMX_U32 mx = src.mWidth / 16; + OMX_U32 my = src.mHeight / 16; + OMX_U32 lx, ly; + OMX_U32 *pChroma, *pLuma = (OMX_U32 *)src.mBits; + + pChroma = (OMX_U32 *)src.mBits + mx * my * 64; + for (ly = 0; ly < my; ly++) { + for (lx = 0; lx < mx; lx++) { + OMX_U32 col, row, lumaWord, chromaWord1 = 0, rgbWord, i; + OMX_U8 y[4], cb[4], cr[4], r[4], g[4], b[4]; + OMX_U32 *dstBuf, *locBuf; + OMX_U32 *pBurstLuma = 0, *pBurstChroma = 0; + OMX_U32 *pWordLuma = 0, *pWordChroma = 0; + OMX_U8 nbOfBlock; + + dstBuf = ((OMX_U32 *)dst.mBits) + (ly * 16) * dst.mWidth / 2; + dstBuf += (lx * 16) / 2; + + pBurstLuma = pLuma; + pBurstChroma = pChroma; + + for (col = 0; col < 2; col++) { + // conversion of a macroblock + for (nbOfBlock = 0; nbOfBlock < 2; nbOfBlock++) { + locBuf = dstBuf + 4 * col + 2 * nbOfBlock; + OMX_U32 dstRowOrigo = ly * 16 * dst.mWidth; + + switch (nbOfBlock) { + case 0: + pWordLuma = pBurstLuma; + pWordChroma = pBurstChroma; + break; + case 1: + pWordLuma = pBurstLuma + 1; + pWordChroma = pBurstChroma + 1; + break; + } + for (row = 0; row < 16; row++) { + + // Check for cropping on the y axis + if (ly * 16 + row >= dst.mHeight) { + break; + } + + lumaWord = *pWordLuma; + pWordLuma += 2; + if (row % 2 == 0) { + chromaWord1 = *pWordChroma; + pWordChroma += 2; + } + + y[3] = ((lumaWord >> 24) & 0xff); + y[2] = ((lumaWord >> 16) & 0xff); + y[1] = ((lumaWord >> 8) & 0xff); + y[0] = ((lumaWord >> 0) & 0xff); + + cb[0] = cb[1] = ((chromaWord1 >> 0) & 0xff); + cb[2] = cb[3] = ((chromaWord1 >> 16) & 0xff); + cr[0] = cr[1] = ((chromaWord1 >> 8) & 0xff); + cr[2] = cr[3] = ((chromaWord1 >> 24) & 0xff); + + for (i = 0; i < 4; i++) { + + int32_t rW,gW,bW; + + rW = 298 * y[i] + 408 * cr[i] - 57059; + gW = 298 * y[i] - 100 * cb[i] - 208 * cr[i] + 34713; + bW = 298 * y[i] + 516 * cb[i] - 70887; + + if (rW < 0) { + r[i] = 0; + } else if (rW >= 65536) { + r[i] = 255; + } else { + r[i] = (rW >> 8); + } + if (gW < 0) { + g[i] = 0; + } else if (gW >= 65536) { + g[i] = 255; + } else { + g[i] = (gW >> 8); + } + if (bW < 0) { + b[i] = 0; + } else if (bW >= 65536) { + b[i] = 255; + } else { + b[i] = (bW >> 8); + } + r[i] >>= 3; + g[i] >>= 2; + b[i] >>= 3; + } + for (i = 0; i < 4; i += 2) { + + // Check for cropping on the x axis + OMX_U32 rowPos = (locBuf - (OMX_U32 *)dst.mBits) * 2 - dstRowOrigo; + if (rowPos >= dst.mWidth) { + locBuf++; + continue; + } + + rgbWord = (r[i + 1] << 27) + + (g[i + 1] << 21) + + (b[i + 1] << 16) + + (r[i] << 11) + + (g[i] << 5) + + (b[i] << 0); + *locBuf++ = rgbWord; + } + locBuf += dst.mWidth / 2 - 2; + dstRowOrigo += dst.mWidth; + } //end of for 16 loop + } //end of 2 block loop + pBurstLuma += 32; + pBurstChroma += 16; + } // end of 2 col loop + pLuma += 64; + pChroma += 32; + } + } + + return OK; +} + uint8_t *ColorConverter::initClip() { static const signed kClipMin = -278; static const signed kClipMax = 535; diff --git a/media/libstagefright/foundation/ABitReader.cpp b/media/libstagefright/foundation/ABitReader.cpp index 5499c32bbaba..5d317862cc1f 100644 --- a/media/libstagefright/foundation/ABitReader.cpp +++ b/media/libstagefright/foundation/ABitReader.cpp @@ -22,7 +22,9 @@ namespace android { ABitReader::ABitReader(const uint8_t *data, size_t size) : mData(data), + mOriginalData(data), mSize(size), + mOriginalSize(size), mReservoir(0), mNumBitsLeft(0) { } @@ -78,6 +80,19 @@ void ABitReader::skipBits(size_t n) { } } +void ABitReader::rewindBits(size_t n) { + CHECK_GE(mOriginalSize * 8 - numBitsLeft(), n); + + size_t bitsLeft = numBitsLeft(); + + mData = mOriginalData; + mSize = mOriginalSize; + mReservoir = 0; + mNumBitsLeft = 0; + + skipBits(mOriginalSize * 8 - bitsLeft - n); +} + void ABitReader::putBits(uint32_t x, size_t n) { CHECK_LE(n, 32u); diff --git a/media/libstagefright/foundation/Android.mk b/media/libstagefright/foundation/Android.mk index d5025a13ed86..648f945334c7 100644 --- a/media/libstagefright/foundation/Android.mk +++ b/media/libstagefright/foundation/Android.mk @@ -1,6 +1,10 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) +ifeq ($(BOARD_HAVE_CODEC_SUPPORT),STERICSSON_CODEC_SUPPORT) + LOCAL_CFLAGS += -DSTERICSSON_CODEC_SUPPORT +endif + LOCAL_SRC_FILES:= \ AAtomizer.cpp \ ABitReader.cpp \ diff --git a/media/libstagefright/include/PCMExtractor.h b/media/libstagefright/include/PCMExtractor.h new file mode 100644 index 000000000000..eec72326283e --- /dev/null +++ b/media/libstagefright/include/PCMExtractor.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Copyright (C) 2010 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. + * + * Author: Andreas Gustafsson (andreas.a.gustafsson@stericsson.com) + * for ST-Ericsson + */ + +#ifndef PCM_EXTRACTOR_H_ + +#define PCM_EXTRACTOR_H_ + +#include <media/stagefright/MediaSource.h> +#include <media/stagefright/MediaExtractor.h> + +using namespace android; + +namespace android { + +class DataSource; +class String8; + +class PCMExtractor : public MediaExtractor { +public: + // Extractor assumes ownership of "source". + PCMExtractor(const sp<DataSource> &source); + + virtual size_t countTracks(); + virtual sp<MediaSource> getTrack(size_t index); + virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags); + + virtual sp<MetaData> getMetaData(); + +protected: + virtual ~PCMExtractor(); + +private: + sp<DataSource> mDataSource; + status_t mInitCheck; + bool mValidFormat; + uint16_t mNumChannels; + uint32_t mSampleRate; + uint16_t mBitsPerSample; + off_t mDataOffset; + size_t mDataSize; + sp<MetaData> mTrackMeta; + + status_t init(); + + PCMExtractor(const PCMExtractor &); + PCMExtractor &operator=(const PCMExtractor &); +}; + +} // namespace android + +#endif // PCM_EXTRACTOR_H_ diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk index d844f3dfe6b6..0452a4d8bdaf 100644 --- a/media/libstagefright/omx/Android.mk +++ b/media/libstagefright/omx/Android.mk @@ -1,6 +1,10 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) +ifeq ($(BOARD_HAVE_CODEC_SUPPORT),STERICSSON_CODEC_SUPPORT) + LOCAL_CFLAGS += -DSTERICSSON_CODEC_SUPPORT +endif + LOCAL_C_INCLUDES += $(JNI_H_INCLUDE) LOCAL_SRC_FILES:= \ diff --git a/media/libstagefright/omx/SoftOMXPlugin.cpp b/media/libstagefright/omx/SoftOMXPlugin.cpp index 1e33f05f0ce1..edc21693af7d 100644 --- a/media/libstagefright/omx/SoftOMXPlugin.cpp +++ b/media/libstagefright/omx/SoftOMXPlugin.cpp @@ -34,6 +34,7 @@ static const struct { const char *mRole; } kComponents[] = { + { "OMX.ST.aac.decoder", "ste_aacdec", "audio_decoder.aac" }, { "OMX.google.aac.decoder", "aacdec", "audio_decoder.aac" }, { "OMX.google.amrnb.decoder", "amrdec", "audio_decoder.amrnb" }, { "OMX.google.amrwb.decoder", "amrdec", "audio_decoder.amrwb" }, @@ -42,6 +43,7 @@ static const struct { { "OMX.google.g711.mlaw.decoder", "g711dec", "audio_decoder.g711mlaw" }, { "OMX.google.h263.decoder", "mpeg4dec", "video_decoder.h263" }, { "OMX.google.mpeg4.decoder", "mpeg4dec", "video_decoder.mpeg4" }, + { "OMX.ST.mp3.decoder", "ste_mp3dec", "audio_decoder.mp3" }, { "OMX.google.mp3.decoder", "mp3dec", "audio_decoder.mp3" }, { "OMX.google.vorbis.decoder", "vorbisdec", "audio_decoder.vorbis" }, { "OMX.google.vpx.decoder", "vpxdec", "video_decoder.vpx" }, diff --git a/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp b/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp index 11d9c220959c..43751a3550fc 100644 --- a/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp +++ b/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp @@ -201,13 +201,33 @@ static status_t parseAudioSpecificConfig(ABitReader *bits, sp<ABuffer> *asc) { CHECK_EQ(parseAudioObjectType(bits, &extensionAudioObjectType), (status_t)OK); - sbrPresent = bits->getBits(1); - - if (sbrPresent == 1) { - unsigned extensionSamplingFreqIndex = bits->getBits(4); - if (extensionSamplingFreqIndex == 0x0f) { - /* unsigned extensionSamplingFrequency = */bits->getBits(24); + if (extensionAudioObjectType == 5) { + sbrPresent = bits->getBits(1); + if (sbrPresent == 1) { + unsigned extensionSamplingFreqIndex = bits->getBits(4); + if (extensionSamplingFreqIndex == 0x0f) { + /* unsigned extensionSamplingFrequency = */bits->getBits(24); + } + if (bits->numBitsLeft() >= 12) { + syncExtensionType = bits->getBits(11); + if (syncExtensionType == 0x548) { + /* unsigned psPresent */bits->getBits(1); + } else { + // Rewind bitstream so that the reading of second + // syncExtensionType has no effect + bits->rewindBits(11); + } + } + } + } else if (extensionAudioObjectType == 22) { + sbrPresent = bits->getBits(1); + if (sbrPresent == 1) { + unsigned extensionSamplingFreqIndex = bits->getBits(4); + if (extensionSamplingFreqIndex == 0x0f) { + /* unsigned extensionSamplingFrequency = */bits->getBits(24); + } } + /* unsigned extensionChannelConfiguration = */bits->getBits(4); } size_t numBitsInExtension = @@ -223,7 +243,7 @@ static status_t parseAudioSpecificConfig(ABitReader *bits, sp<ABuffer> *asc) { bits->skipBits(8 - (numBitsInExtension & 7)); } } else { - bits->putBits(syncExtensionType, 11); + bits->rewindBits(11); } } @@ -335,11 +355,14 @@ static status_t parseStreamMuxConfig( break; } + status_t parseResult = OK; *otherDataPresent = bits->getBits(1); *otherDataLenBits = 0; if (*otherDataPresent) { if (audioMuxVersion == 1) { TRESPASS(); // XXX to be implemented + } else if (bits->numBitsLeft() < 9) { + parseResult = ERROR_MALFORMED; } else { *otherDataLenBits = 0; @@ -349,13 +372,45 @@ static status_t parseStreamMuxConfig( otherDataLenEsc = bits->getBits(1); unsigned otherDataLenTmp = bits->getBits(8); (*otherDataLenBits) += otherDataLenTmp; - } while (otherDataLenEsc); + } while (otherDataLenEsc && bits->numBitsLeft() >= 9); + + if (otherDataLenEsc) { + parseResult = ERROR_MALFORMED; + } + } + } + + if (parseResult == OK && bits->numBitsLeft() >= 1) { + unsigned crcCheckPresent = bits->getBits(1); + if (crcCheckPresent && bits->numBitsLeft() >= 8) { + /* unsigned crcCheckSum = */bits->getBits(8); + } else if (crcCheckPresent && bits->numBitsLeft() < 8) { + parseResult = ERROR_MALFORMED; + } + } else { + parseResult = ERROR_MALFORMED; + } + + // Verify that only bits are left for byte aligning and that + // any remaining bits are 0 + if (bits->numBitsLeft() / 8 > 0) { + parseResult = ERROR_MALFORMED; + } else { + unsigned remainder = bits->getBits(bits->numBitsLeft()); + if (remainder != 0) { + parseResult = ERROR_MALFORMED; } } - unsigned crcCheckPresent = bits->getBits(1); - if (crcCheckPresent) { - /* unsigned crcCheckSum = */bits->getBits(8); + // Check if config string parsing has failed (then probably due to a + // malformed AudioSpecificConfig) and if so, assume most common + // configuration for the variables after AudioSpecificConfig. + if (parseResult != OK) { + LOGW("LATM config string parsing has failed, assuming most common case " + "of frameLengthType=0, otherDataPresent=0, and otherDataLenBits=0"); + *frameLengthType = 0; + *otherDataPresent = 0; + *otherDataLenBits = 0; } return OK; diff --git a/media/libstagefright/rtsp/Android.mk b/media/libstagefright/rtsp/Android.mk index 823034787fbb..d97a8bf84465 100644 --- a/media/libstagefright/rtsp/Android.mk +++ b/media/libstagefright/rtsp/Android.mk @@ -2,6 +2,10 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) +ifeq ($(BOARD_HAVE_CODEC_SUPPORT),STERICSSON_CODEC_SUPPORT) + LOCAL_CFLAGS += -DSTERICSSON_CODEC_SUPPORT +endif + LOCAL_SRC_FILES:= \ AAMRAssembler.cpp \ AAVCAssembler.cpp \ @@ -35,6 +39,10 @@ include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) +ifeq ($(BOARD_HAVE_CODEC_SUPPORT),STERICSSON_CODEC_SUPPORT) + LOCAL_CFLAGS += -DSTERICSSON_CODEC_SUPPORT +endif + LOCAL_SRC_FILES:= \ rtp_test.cpp diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h index ca1186337829..142fa0513612 100644 --- a/opengl/include/EGL/eglext.h +++ b/opengl/include/EGL/eglext.h @@ -236,18 +236,6 @@ struct ANativeWindowBuffer; /* EGL_NV_system_time */ -#ifndef EGL_NV_system_time -#define EGL_NV_system_time 1 -typedef khronos_int64_t EGLint64NV; -typedef khronos_uint64_t EGLuint64NV; -#ifdef EGL_EGLEXT_PROTOTYPES -EGLAPI EGLuint64NV EGLAPIENTRY eglGetSystemTimeFrequencyNV(void); -EGLAPI EGLuint64NV EGLAPIENTRY eglGetSystemTimeNV(void); -#endif -typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMEFREQUENCYNVPROC)(void); -typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMENVPROC)(void); -#endif - /* EGL_ANDROID_blob_cache */ diff --git a/opengl/include/GLES2/gl2ext.h b/opengl/include/GLES2/gl2ext.h index 9db4e252c559..28c7aef71288 100644 --- a/opengl/include/GLES2/gl2ext.h +++ b/opengl/include/GLES2/gl2ext.h @@ -188,6 +188,18 @@ typedef void* GLeglImageOES; #endif /*------------------------------------------------------------------------* + * ARM extension tokens + *------------------------------------------------------------------------*/ + +/* GL_ARM_mali_shader_binary */ +#ifndef GL_ARM_mali_shader_binary +#define GL_MALI_SHADER_BINARY_ARM 0x8F60 +#endif + +/* GL_ARM_rgba8 */ +/* No new tokens introduced by this extension. */ + +/*------------------------------------------------------------------------* * EXT extension tokens *------------------------------------------------------------------------*/ @@ -603,6 +615,20 @@ typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERDATAAMDPROC) (GLuint monito #endif /*------------------------------------------------------------------------* + * ARM extension functions + *------------------------------------------------------------------------*/ + +/* GL_ARM_mali_shader_binary */ +#ifndef GL_ARM_mali_shader_binary +#define GL_ARM_mali_shader_binary 1 +#endif + +/* GL_ARM_rgba8 */ +#ifndef GL_ARM_rgba8 +#define GL_ARM_rgba8 1 +#endif + +/*------------------------------------------------------------------------* * EXT extension functions *------------------------------------------------------------------------*/ diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp index e5004e1e5033..84949bb5ab57 100644 --- a/opengl/libs/EGL/eglApi.cpp +++ b/opengl/libs/EGL/eglApi.cpp @@ -49,27 +49,23 @@ using namespace android; // ---------------------------------------------------------------------------- -#define EGL_VERSION_HW_ANDROID 0x3143 - -#ifdef TARGET_BOARD_SNOWBALL static char const * const sVendorString = "Android"; static char const * const sVersionString = "1.4 Android META-EGL"; static char const * const sClientApiString = "OpenGL ES"; static char const * const sExtensionString = - "EGL_KHR_image " - "EGL_KHR_image_base " - "EGL_KHR_image_pixmap " - "EGL_KHR_gl_texture_2D_image " - "EGL_KHR_gl_texture_cubemap_image " - "EGL_KHR_gl_renderbuffer_image " - "EGL_KHR_fence_sync " - "EGL_ANDROID_image_native_buffer " - "EGL_ANDROID_swap_rectangle " -#ifndef TARGET_BOARD_SNOWBALL - "EGL_NV_system_time " -#endif - ; -#endif + "EGL_KHR_image " + "EGL_KHR_image_base " + "EGL_KHR_image_pixmap " + "EGL_KHR_gl_texture_2D_image " + "EGL_KHR_gl_texture_cubemap_image " + "EGL_KHR_gl_renderbuffer_image " + "EGL_KHR_fence_sync " + "EGL_ANDROID_image_native_buffer " + "EGL_ANDROID_swap_rectangle " + /* "EGL_NV_system_time "*/ + ; + +#define EGL_VERSION_HW_ANDROID 0x3143 struct extention_map_t { const char* name; @@ -85,12 +81,6 @@ static const extention_map_t sExtentionMap[] = { (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR }, { "eglDestroyImageKHR", (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR }, -#ifndef TARGET_BOARD_SNOWBALL - { "eglGetSystemTimeFrequencyNV", - (__eglMustCastToProperFunctionPointerType)&eglGetSystemTimeFrequencyNV }, - { "eglGetSystemTimeNV", - (__eglMustCastToProperFunctionPointerType)&eglGetSystemTimeNV }, -#endif }; // accesses protected by sExtensionMapMutex @@ -993,13 +983,10 @@ const char* eglQueryString(EGLDisplay dpy, EGLint name) case EGL_VERSION: return dp->getVersionString(); case EGL_EXTENSIONS: -#ifdef TARGET_BOARD_SNOWBALL if (NULL != dp->disp[IMPL_HARDWARE].queryString.extensions) return dp->disp[IMPL_HARDWARE].queryString.extensions; else return sExtensionString; -#endif - return dp->getExtensionString(); case EGL_CLIENT_APIS: return dp->getClientApiString(); case EGL_VERSION_HW_ANDROID: { @@ -1472,47 +1459,3 @@ EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute /* ANDROID extensions entry-point go here */ -#ifndef TARGET_BOARD_SNOWBALL -// ---------------------------------------------------------------------------- -// NVIDIA extensions -// ---------------------------------------------------------------------------- -EGLuint64NV eglGetSystemTimeFrequencyNV() -{ - clearError(); - - if (egl_init_drivers() == EGL_FALSE) { - return setError(EGL_BAD_PARAMETER, EGL_FALSE); - } - - EGLuint64NV ret = 0; - egl_connection_t* const cnx = &gEGLImpl[IMPL_HARDWARE]; - - if (cnx->dso) { - if (cnx->egl.eglGetSystemTimeFrequencyNV) { - return cnx->egl.eglGetSystemTimeFrequencyNV(); - } - } - - return setErrorQuiet(EGL_BAD_DISPLAY, 0); -} - -EGLuint64NV eglGetSystemTimeNV() -{ - clearError(); - - if (egl_init_drivers() == EGL_FALSE) { - return setError(EGL_BAD_PARAMETER, EGL_FALSE); - } - - EGLuint64NV ret = 0; - egl_connection_t* const cnx = &gEGLImpl[IMPL_HARDWARE]; - - if (cnx->dso) { - if (cnx->egl.eglGetSystemTimeNV) { - return cnx->egl.eglGetSystemTimeNV(); - } - } - - return setErrorQuiet(EGL_BAD_DISPLAY, 0); -} -#endif diff --git a/opengl/libs/EGL/egl_entries.in b/opengl/libs/EGL/egl_entries.in index 9ebdecf8fd21..68acd77354ba 100644 --- a/opengl/libs/EGL/egl_entries.in +++ b/opengl/libs/EGL/egl_entries.in @@ -63,9 +63,5 @@ EGL_ENTRY(EGLBoolean, eglGetSyncAttribKHR, EGLDisplay, EGLSyncKHR, EGLint, EGL_ENTRY(EGLBoolean, eglSetSwapRectangleANDROID, EGLDisplay, EGLSurface, EGLint, EGLint, EGLint, EGLint) EGL_ENTRY(EGLClientBuffer, eglGetRenderBufferANDROID, EGLDisplay, EGLSurface) -#ifndef TARGET_BOARD_SNOWBALL /* NVIDIA extensions */ -EGL_ENTRY(EGLuint64NV, eglGetSystemTimeFrequencyNV, void) -EGL_ENTRY(EGLuint64NV, eglGetSystemTimeNV, void) -#endif diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk index fa4959298fb9..652338879ec4 100644 --- a/services/audioflinger/Android.mk +++ b/services/audioflinger/Android.mk @@ -2,6 +2,10 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) +ifeq ($(BOARD_HAVE_FMRADIO_SUPPORT),STERICSSON_FMRADIO_SUPPORT) + LOCAL_CFLAGS += -DSTERICSSON_FMRADIO_SUPPORT +endif + LOCAL_SRC_FILES:= \ AudioFlinger.cpp \ AudioMixer.cpp.arm \ diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index ce701ca297c9..59ef55b9c14f 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -242,6 +242,7 @@ AudioFlinger::~AudioFlinger() audio_hw_device_close(dev); } mAudioHwDevs.clear(); + delete mInputFMStream; } audio_hw_device_t* AudioFlinger::findSuitableHwDev_l(uint32_t devices) @@ -249,8 +250,8 @@ audio_hw_device_t* AudioFlinger::findSuitableHwDev_l(uint32_t devices) /* first matching HW device is returned */ for (size_t i = 0; i < mAudioHwDevs.size(); i++) { audio_hw_device_t *dev = mAudioHwDevs[i]; - if ((dev->get_supported_devices(dev) & devices) == devices) - return dev; + if ((dev->get_supported_devices(dev) & devices) == devices) + return dev; } return NULL; } @@ -863,6 +864,11 @@ unsigned int AudioFlinger::getInputFramesLost(int ioHandle) return 0; } +size_t AudioFlinger::readInput(uint32_t *input, uint32_t inputClientId, void *buffer, uint32_t bytes, uint32_t *pOverwrittenBytes) +{ + return mInputFMStream->stream->read(mInputFMStream->stream, buffer, (size_t)bytes); +} + status_t AudioFlinger::setVoiceVolume(float value) { status_t ret = initCheck(); @@ -5062,7 +5068,8 @@ int AudioFlinger::openInput(uint32_t *pDevices, uint32_t *pSamplingRate, uint32_t *pFormat, uint32_t *pChannels, - uint32_t acoustics) + uint32_t acoustics, + uint32_t *pInputClientId) { status_t status; RecordThread *thread = NULL; @@ -5089,13 +5096,14 @@ int AudioFlinger::openInput(uint32_t *pDevices, &channels, &samplingRate, (audio_in_acoustics_t)acoustics, &inStream); - LOGV("openInput() openInputStream returned input %p, SamplingRate %d, Format %d, Channels %x, acoustics %x, status %d", + LOGV("openInput() openInputStream returned input %p, SamplingRate %d, Format %d, Channels %x, acoustics %x, status %d, pInputClientId=%p", inStream, samplingRate, format, channels, acoustics, - status); + status, + pInputClientId); // If the input could not be opened with the requested parameters and we can handle the conversion internally, // try to open again with the proposed parameters. The AudioFlinger can resample the input and do mono to stereo @@ -5111,8 +5119,13 @@ int AudioFlinger::openInput(uint32_t *pDevices, &inStream); } - if (inStream != NULL) { - AudioStreamIn *input = new AudioStreamIn(inHwDev, inStream); + if (inStream == NULL) { + return 0; + } + + AudioStreamIn *input = new AudioStreamIn(inHwDev, inStream); + + if (inStream != NULL && pInputClientId == NULL) { int id = nextUniqueId(); // Start record thread @@ -5136,38 +5149,48 @@ int AudioFlinger::openInput(uint32_t *pDevices, // notify client processes of the new input creation thread->audioConfigChanged_l(AudioSystem::INPUT_OPENED); return id; + } else if (pInputClientId != NULL && *pInputClientId == AUDIO_INPUT_CLIENT_PLAYBACK) { + mInputFMStream = input; + return (int)input; } return 0; } -status_t AudioFlinger::closeInput(int input) +status_t AudioFlinger::closeInput(int input, uint32_t *inputClientId) { // keep strong reference on the record thread so that // it is not destroyed while exit() is executed - sp <RecordThread> thread; - { - Mutex::Autolock _l(mLock); - thread = checkRecordThread_l(input); - if (thread == NULL) { - return BAD_VALUE; + if (inputClientId == NULL) { + sp <RecordThread> thread; + { + Mutex::Autolock _l(mLock); + thread = checkRecordThread_l(input); + if (thread == NULL) { + return BAD_VALUE; + } + + LOGV("closeInput() %d", input); + void *param2 = 0; + audioConfigChanged_l(AudioSystem::INPUT_CLOSED, input, param2); + mRecordThreads.removeItem(input); } + thread->exit(); - LOGV("closeInput() %d", input); - void *param2 = 0; - audioConfigChanged_l(AudioSystem::INPUT_CLOSED, input, param2); - mRecordThreads.removeItem(input); + AudioStreamIn *in = thread->clearInput(); + // from now on thread->mInput is NULL + in->hwDev->close_input_stream(in->hwDev, in->stream); + delete in; + } else if (inputClientId != NULL && *inputClientId == AUDIO_INPUT_CLIENT_PLAYBACK) { + AudioStreamIn *in = (AudioStreamIn *)input; + in->hwDev->close_input_stream(in->hwDev, in->stream); + delete in; } - thread->exit(); - - AudioStreamIn *in = thread->clearInput(); - // from now on thread->mInput is NULL - in->hwDev->close_input_stream(in->hwDev, in->stream); - delete in; return NO_ERROR; } + status_t AudioFlinger::setStreamOutput(uint32_t stream, int output) { Mutex::Autolock _l(mLock); diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index 9bd2c7f49302..243bd329a0d9 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -137,9 +137,12 @@ public: uint32_t *pSamplingRate, uint32_t *pFormat, uint32_t *pChannels, - uint32_t acoustics); + uint32_t acoustics, + uint32_t *pInputClientId = NULL); - virtual status_t closeInput(int input); + virtual status_t closeInput(int input, uint32_t *inputClientId = NULL); + + virtual size_t readInput(uint32_t *input, uint32_t inputClientId, void *buffer, uint32_t bytes, uint32_t *pOverwrittenBytes); virtual status_t setStreamOutput(uint32_t stream, int output); @@ -1390,6 +1393,7 @@ private: mutable Mutex mHardwareLock; audio_hw_device_t* mPrimaryHardwareDev; + AudioStreamIn* mInputFMStream; Vector<audio_hw_device_t*> mAudioHwDevs; mutable int mHardwareStatus; diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp index 8da5ca14dd74..15cefc059d5b 100644 --- a/services/audioflinger/AudioPolicyService.cpp +++ b/services/audioflinger/AudioPolicyService.cpp @@ -306,14 +306,15 @@ audio_io_handle_t AudioPolicyService::getInput(int inputSource, uint32_t format, uint32_t channels, audio_in_acoustics_t acoustics, - int audioSession) + int audioSession, + audio_input_clients *inputClientId) { if (mpAudioPolicy == NULL) { return 0; } Mutex::Autolock _l(mLock); audio_io_handle_t input = mpAudioPolicy->get_input(mpAudioPolicy, inputSource, samplingRate, - format, channels, acoustics); + format, channels, acoustics, inputClientId); if (input == 0) { return input; @@ -1411,7 +1412,8 @@ static audio_io_handle_t aps_open_input(void *service, uint32_t *pSamplingRate, uint32_t *pFormat, uint32_t *pChannels, - uint32_t acoustics) + uint32_t acoustics, + uint32_t *inputClientId) { sp<IAudioFlinger> af = AudioSystem::get_audio_flinger(); if (af == NULL) { @@ -1420,16 +1422,16 @@ static audio_io_handle_t aps_open_input(void *service, } return af->openInput(pDevices, pSamplingRate, pFormat, pChannels, - acoustics); + acoustics, inputClientId); } -static int aps_close_input(void *service, audio_io_handle_t input) +static int aps_close_input(void *service, audio_io_handle_t input, uint32_t *inputClientId = NULL) { sp<IAudioFlinger> af = AudioSystem::get_audio_flinger(); if (af == NULL) return PERMISSION_DENIED; - return af->closeInput(input); + return af->closeInput(input, inputClientId); } static int aps_set_stream_output(void *service, audio_stream_type_t stream, diff --git a/services/audioflinger/AudioPolicyService.h b/services/audioflinger/AudioPolicyService.h index d898a530cc8c..68448508453a 100644 --- a/services/audioflinger/AudioPolicyService.h +++ b/services/audioflinger/AudioPolicyService.h @@ -82,7 +82,8 @@ public: uint32_t channels = 0, audio_in_acoustics_t acoustics = (audio_in_acoustics_t)0, - int audioSession = 0); + int audioSession = 0, + audio_input_clients *inputClientId = NULL); virtual status_t startInput(audio_io_handle_t input); virtual status_t stopInput(audio_io_handle_t input); virtual void releaseInput(audio_io_handle_t input); diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk index f1cb50e01d5f..5a084b2ae9d7 100644 --- a/services/surfaceflinger/Android.mk +++ b/services/surfaceflinger/Android.mk @@ -38,6 +38,10 @@ ifeq ($(BOARD_HAVE_CODEC_SUPPORT),SAMSUNG_CODEC_SUPPORT) LOCAL_CFLAGS += -DSAMSUNG_CODEC_SUPPORT endif +ifeq ($(BOARD_HAVE_CODEC_SUPPORT),STERICSSON_CODEC_SUPPORT) + LOCAL_CFLAGS += -DSTERICSSON_CODEC_SUPPORT +endif + LOCAL_SHARED_LIBRARIES := \ libcutils \ libhardware \ diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp index f94d32149b0f..56c8083a7b1e 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp +++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp @@ -379,6 +379,8 @@ void DisplayHardware::flip(const Region& dirty) const if (mHwc->initCheck() == NO_ERROR) { mHwc->commit(); } else { + // Make sure the swapbuffer call is done in sync + mNativeWindow->compositionComplete(); eglSwapBuffers(dpy, surface); } checkEGLErrors("eglSwapBuffers"); diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index be9b2265c7db..186c90cbbd46 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -89,6 +89,7 @@ status_t HWComposer::createWorkList(size_t numLayers) { free(mList); size_t size = sizeof(hwc_layer_list) + numLayers*sizeof(hwc_layer_t); mList = (hwc_layer_list_t*)malloc(size); + memset(mList, 0, size); mCapacity = numLayers; } mList->flags = HWC_GEOMETRY_CHANGED; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 673fda920a68..c4ec78a5e828 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -244,6 +244,16 @@ void Layer::setPerFrameData(hwc_layer_t* hwcl) { void Layer::onDraw(const Region& clip) const { + // Convert the texture to a native format if need be. + // convert() returns immediately if no conversion is necessary. + if (mSurfaceTexture != NULL) { + status_t res = mSurfaceTexture->convert(); + if (res != NO_ERROR) { + LOGE("Layer::onDraw: texture conversion failed. " + "Texture content for this layer will not be initialized."); + } + } + if (CC_UNLIKELY(mActiveBuffer == 0)) { // the texture has not been created yet, this Layer has // in fact never been drawn into. This happens frequently with @@ -404,7 +414,7 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) mFlinger->signalEvent(); } - if (mSurfaceTexture->updateTexImage() < NO_ERROR) { + if (mSurfaceTexture->updateTexImage(true) < NO_ERROR) { // something happened! recomputeVisibleRegions = true; return; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 0da75c4cacc6..1015e54f2e58 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -436,7 +436,6 @@ bool SurfaceFlinger::threadLoop() // inform the h/w that we're done compositing logger.log(GraphicLog::SF_COMPOSITION_COMPLETE, index); - hw.compositionComplete(); logger.log(GraphicLog::SF_SWAP_BUFFERS, index); postFramebuffer(); @@ -444,7 +443,6 @@ bool SurfaceFlinger::threadLoop() logger.log(GraphicLog::SF_REPAINT_DONE, index); } else { // pretend we did the post - hw.compositionComplete(); usleep(16667); // 60 fps period } return true; @@ -816,8 +814,6 @@ void SurfaceFlinger::handleRepaint() // set the frame buffer const DisplayHardware& hw(graphicPlane(0).displayHardware()); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); uint32_t flags = hw.getFlags(); if ((flags & DisplayHardware::SWAP_RECTANGLE) || @@ -858,8 +854,11 @@ void SurfaceFlinger::handleRepaint() mDirtyRegion.clear(); } +static bool checkDrawingWithGL(hwc_layer_t* const layers, size_t layerCount); + void SurfaceFlinger::setupHardwareComposer(Region& dirtyInOut) { + bool useGL = true; const DisplayHardware& hw(graphicPlane(0).displayHardware()); HWComposer& hwc(hw.getHwComposer()); hwc_layer_t* const cur(hwc.getLayers()); @@ -891,6 +890,22 @@ void SurfaceFlinger::setupHardwareComposer(Region& dirtyInOut) status_t err = hwc.prepare(); LOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err)); + /* + * Check if GL will be used + */ + useGL = checkDrawingWithGL(cur, count); + + if (!useGL) { + return; + } + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + if (UNLIKELY(!mWormholeRegion.isEmpty())) { + // should never happen unless the window manager has a bug + // draw something... + drawWormhole(); + } + if (err == NO_ERROR) { // what's happening here is tricky. // we want to clear all the layers with the CLEAR_FB flags @@ -958,20 +973,28 @@ void SurfaceFlinger::setupHardwareComposer(Region& dirtyInOut) } } +static bool checkDrawingWithGL(hwc_layer_t* const layers, size_t layerCount) +{ + bool useGL = false; + if (layers) { + for (size_t i=0 ; i<layerCount ; i++) { + if (layers[i].compositionType == HWC_FRAMEBUFFER) { + useGL = true; + } + } + } + return useGL; +} + void SurfaceFlinger::composeSurfaces(const Region& dirty) { const DisplayHardware& hw(graphicPlane(0).displayHardware()); HWComposer& hwc(hw.getHwComposer()); const size_t fbLayerCount = hwc.getLayerCount(HWC_FRAMEBUFFER); - if (UNLIKELY(fbLayerCount && !mWormholeRegion.isEmpty())) { - // should never happen unless the window manager has a bug - // draw something... - drawWormhole(); - } /* - * and then, render the layers targeted at the framebuffer + * render the layers targeted at the framebuffer */ hwc_layer_t* const cur(hwc.getLayers()); const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ); @@ -1778,24 +1801,14 @@ status_t SurfaceFlinger::renderScreenToTextureLocked(DisplayID dpy, GLuint name, tname; glGenTextures(1, &tname); glBindTexture(GL_TEXTURE_2D, tname); -#ifdef TARGET_BOARD_SNOWBALL glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, hw_w, hw_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); -#else - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, - hw_w, hw_h, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); -#endif if (glGetError() != GL_NO_ERROR) { while ( glGetError() != GL_NO_ERROR ) ; GLint tw = (2 << (31 - clz(hw_w))); GLint th = (2 << (31 - clz(hw_h))); -#ifdef TARGET_BOARD_SNOWBALL glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tw, th, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); -#else - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, - tw, th, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); -#endif u = GLfloat(hw_w) / tw; v = GLfloat(hw_h) / th; } @@ -2367,8 +2380,6 @@ status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy, glDeleteRenderbuffersOES(1, &tname); glDeleteFramebuffersOES(1, &name); - hw.compositionComplete(); - // LOGD("screenshot: result = %s", result<0 ? strerror(result) : "OK"); return result; @@ -2586,9 +2597,9 @@ sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t w, uint32_t h if (err == NO_MEMORY) { GraphicBuffer::dumpAllocationsToSystemLog(); } - LOGE("GraphicBufferAlloc::createGraphicBuffer(w=%d, h=%d) " + LOGE("GraphicBufferAlloc::createGraphicBuffer(w=%d, h=%d, format=%#x) " "failed (%s), handle=%p", - w, h, strerror(-err), graphicBuffer->handle); + w, h, format, strerror(-err), graphicBuffer->handle); return 0; } return graphicBuffer; |