Merge "Visualizer: Fix the conversion from 8-bit sample to 16-bit sample." into gingerbread
diff --git a/include/camera/Camera.h b/include/camera/Camera.h
index e6d84ba..e734c38 100644
--- a/include/camera/Camera.h
+++ b/include/camera/Camera.h
@@ -105,8 +105,8 @@
 };
 
 enum {
-    CAMERA_FACING_BACK = 0,
-    CAMERA_FACING_FRONT = 1 /* The camera faces to the user */
+    CAMERA_FACING_BACK = 0, /* The facing of the camera is opposite to that of the screen. */
+    CAMERA_FACING_FRONT = 1 /* The facing of the camera is the same as that of the screen. */
 };
 
 struct CameraInfo {
@@ -122,10 +122,12 @@
      * camera image needs to be rotated clockwise so it shows correctly on
      * the display in its natural orientation. It should be 0, 90, 180, or 270.
      *
-     * For example, suppose a device has a naturally tall screen, but the camera
-     * sensor is mounted in landscape. If the top side of the camera sensor is
-     * aligned with the right edge of the display in natural orientation, the
-     * value should be 90.
+     * For example, suppose a device has a naturally tall screen. The
+     * back-facing camera sensor is mounted in landscape. You are looking at
+     * the screen. If the top side of the camera sensor is aligned with the
+     * right edge of the screen in natural orientation, the value should be
+     * 90. If the top side of a front-facing camera sensor is aligned with
+     * the right of the screen, the value should be 270.
      */
     int orientation;
 };
diff --git a/include/camera/CameraHardwareInterface.h b/include/camera/CameraHardwareInterface.h
index 6a66e3c..35c5aa1 100644
--- a/include/camera/CameraHardwareInterface.h
+++ b/include/camera/CameraHardwareInterface.h
@@ -190,7 +190,9 @@
      */
     virtual status_t    cancelPicture() = 0;
 
-    /** Set the camera parameters. */
+    /**
+     * Set the camera parameters. This returns BAD_VALUE if any parameter is
+     * invalid or not supported. */
     virtual status_t    setParameters(const CameraParameters& params) = 0;
 
     /** Return the camera parameters. */
diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h
index 53039a0..4e770fd 100644
--- a/include/camera/CameraParameters.h
+++ b/include/camera/CameraParameters.h
@@ -142,16 +142,23 @@
     // the best.
     // Example value: "90". Read/write.
     static const char KEY_JPEG_QUALITY[];
-    // The orientation of the device in degrees. For example, suppose the
-    // natural position of the device is landscape. If the user takes a picture
-    // in landscape mode in 2048x1536 resolution, the rotation will be set to
-    // "0". If the user rotates the phone 90 degrees clockwise, the rotation
-    // should be set to "90".
-    // The camera driver can set orientation in the EXIF header without rotating
-    // the picture. Or the driver can rotate the picture and the EXIF thumbnail.
-    // If the Jpeg picture is rotated, the orientation in the EXIF header should
-    // be missing or 1 (row #0 is top and column #0 is left side). The driver
-    // should not set default value for this parameter.
+    // The rotation angle in degrees relative to the orientation of the camera.
+    // This affects the pictures returned from CAMERA_MSG_COMPRESSED_IMAGE. The
+    // camera driver may set orientation in the EXIF header without rotating the
+    // picture. Or the driver may rotate the picture and the EXIF thumbnail. If
+    // the Jpeg picture is rotated, the orientation in the EXIF header will be
+    // missing or 1 (row #0 is top and column #0 is left side).
+    //
+    // Note that the JPEG pictures of front-facing cameras are not mirrored
+    // as in preview display.
+    //
+    // For example, suppose the natural orientation of the device is portrait.
+    // The device is rotated 270 degrees clockwise, so the device orientation is
+    // 270. Suppose a back-facing camera sensor is mounted in landscape and the
+    // top side of the camera sensor is aligned with the right edge of the
+    // display in natural orientation. So the camera orientation is 90. The
+    // rotation should be set to 0 (270 + 90).
+    //
     // Example value: "0" or "90" or "180" or "270". Write only.
     static const char KEY_ROTATION[];
     // GPS latitude coordinate. GPSLatitude and GPSLatitudeRef will be stored in
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index 2f61cbe..f794766 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -115,7 +115,8 @@
             const char *componentName,
             OMX_COLOR_FORMATTYPE colorFormat,
             size_t encodedWidth, size_t encodedHeight,
-            size_t displayWidth, size_t displayHeight) = 0;
+            size_t displayWidth, size_t displayHeight,
+            int32_t rotationDegrees) = 0;
 
     // Note: These methods are _not_ virtual, it exists as a wrapper around
     // the virtual "createRenderer" method above facilitating extraction
@@ -125,14 +126,16 @@
             const char *componentName,
             OMX_COLOR_FORMATTYPE colorFormat,
             size_t encodedWidth, size_t encodedHeight,
-            size_t displayWidth, size_t displayHeight);
+            size_t displayWidth, size_t displayHeight,
+            int32_t rotationDegrees);
 
     sp<IOMXRenderer> createRendererFromJavaSurface(
             JNIEnv *env, jobject javaSurface,
             const char *componentName,
             OMX_COLOR_FORMATTYPE colorFormat,
             size_t encodedWidth, size_t encodedHeight,
-            size_t displayWidth, size_t displayHeight);
+            size_t displayWidth, size_t displayHeight,
+            int32_t rotationDegrees);
 };
 
 struct omx_message {
diff --git a/include/media/stagefright/HardwareAPI.h b/include/media/stagefright/HardwareAPI.h
index 221c679..63f11d1 100644
--- a/include/media/stagefright/HardwareAPI.h
+++ b/include/media/stagefright/HardwareAPI.h
@@ -32,6 +32,14 @@
         size_t displayWidth, size_t displayHeight,
         size_t decodedWidth, size_t decodedHeight);
 
+extern android::VideoRenderer *createRendererWithRotation(
+        const android::sp<android::ISurface> &surface,
+        const char *componentName,
+        OMX_COLOR_FORMATTYPE colorFormat,
+        size_t displayWidth, size_t displayHeight,
+        size_t decodedWidth, size_t decodedHeight,
+        int32_t rotationDegrees);
+
 extern android::OMXPluginBase *createOMXPlugin();
 
 #endif  // HARDWARE_API_H_
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index bb469e5..7bf07eb 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -154,6 +154,7 @@
     bool exceedsFileDurationLimit();
     bool isFileStreamable() const;
     void trackProgressStatus(const Track* track, int64_t timeUs, status_t err = OK);
+    void writeCompositionMatrix(int32_t degrees);
 
     MPEG4Writer(const MPEG4Writer &);
     MPEG4Writer &operator=(const MPEG4Writer &);
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index d2bd9f2..29bfc4a 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -32,6 +32,7 @@
     kKeyMIMEType          = 'mime',  // cstring
     kKeyWidth             = 'widt',  // int32_t
     kKeyHeight            = 'heig',  // int32_t
+    kKeyRotation          = 'rotA',  // int32_t (angle in degrees)
     kKeyIFramesInterval   = 'ifiv',  // int32_t
     kKeyStride            = 'strd',  // int32_t
     kKeySliceHeight       = 'slht',  // int32_t
@@ -90,6 +91,7 @@
     // Track authoring progress status
     // kKeyTrackTimeStatus is used to track progress in elapsed time
     kKeyTrackTimeStatus   = 'tktm',  // int64_t
+    kKeyRotationDegree    = 'rdge',  // int32_t (clockwise, in degree)
 
     kKeyNotRealTime       = 'ntrt',  // bool (int32_t)
 
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 1d94160..fed6761 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -109,6 +109,7 @@
         kAvoidMemcopyInputRecordingFrames     = 2048,
         kRequiresLargerEncoderOutputBuffer    = 4096,
         kOutputBuffersAreUnreadable           = 8192,
+        kStoreMetaDataInInputVideoBuffers     = 16384,
     };
 
     struct BufferInfo {
diff --git a/include/private/media/VideoFrame.h b/include/private/media/VideoFrame.h
index 9c35274..3aff0c6 100644
--- a/include/private/media/VideoFrame.h
+++ b/include/private/media/VideoFrame.h
@@ -120,6 +120,7 @@
     uint32_t mDisplayHeight;
     uint32_t mSize;            // Number of bytes in mData
     uint8_t* mData;            // Actual binary data
+    int32_t  mRotationAngle;   // rotation angle, clockwise
 };
 
 }; // namespace android
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index f3804b8..ae6c2bf 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -38,11 +38,13 @@
         const char *componentName,
         OMX_COLOR_FORMATTYPE colorFormat,
         size_t encodedWidth, size_t encodedHeight,
-        size_t displayWidth, size_t displayHeight) {
+        size_t displayWidth, size_t displayHeight,
+        int32_t rotationDegrees) {
     return createRenderer(
             surface->getISurface(),
             componentName, colorFormat, encodedWidth, encodedHeight,
-            displayWidth, displayHeight);
+            displayWidth, displayHeight,
+            rotationDegrees);
 }
 
 sp<IOMXRenderer> IOMX::createRendererFromJavaSurface(
@@ -50,7 +52,8 @@
         const char *componentName,
         OMX_COLOR_FORMATTYPE colorFormat,
         size_t encodedWidth, size_t encodedHeight,
-        size_t displayWidth, size_t displayHeight) {
+        size_t displayWidth, size_t displayHeight,
+        int32_t rotationDegrees) {
     jclass surfaceClass = env->FindClass("android/view/Surface");
     if (surfaceClass == NULL) {
         LOGE("Can't find android/view/Surface");
@@ -67,7 +70,8 @@
 
     return createRenderer(
             surface, componentName, colorFormat, encodedWidth,
-            encodedHeight, displayWidth, displayHeight);
+            encodedHeight, displayWidth, displayHeight,
+            rotationDegrees);
 }
 
 class BpOMX : public BpInterface<IOMX> {
@@ -349,7 +353,8 @@
             const char *componentName,
             OMX_COLOR_FORMATTYPE colorFormat,
             size_t encodedWidth, size_t encodedHeight,
-            size_t displayWidth, size_t displayHeight) {
+            size_t displayWidth, size_t displayHeight,
+            int32_t rotationDegrees) {
         Parcel data, reply;
         data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
 
@@ -360,6 +365,7 @@
         data.writeInt32(encodedHeight);
         data.writeInt32(displayWidth);
         data.writeInt32(displayHeight);
+        data.writeInt32(rotationDegrees);
 
         remote()->transact(CREATE_RENDERER, data, &reply);
 
@@ -682,11 +688,13 @@
             size_t encodedHeight = (size_t)data.readInt32();
             size_t displayWidth = (size_t)data.readInt32();
             size_t displayHeight = (size_t)data.readInt32();
+            int32_t rotationDegrees = data.readInt32();
 
             sp<IOMXRenderer> renderer =
                 createRenderer(isurface, componentName, colorFormat,
                                encodedWidth, encodedHeight,
-                               displayWidth, displayHeight);
+                               displayWidth, displayHeight,
+                               rotationDegrees);
 
             reply->writeStrongBinder(renderer->asBinder());
 
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index ca229fa..39fce81 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -253,6 +253,8 @@
     frameCopy->mDisplayWidth = frame->mDisplayWidth;
     frameCopy->mDisplayHeight = frame->mDisplayHeight;
     frameCopy->mSize = frame->mSize;
+    frameCopy->mRotationAngle = frame->mRotationAngle;
+    LOGV("rotation: %d", frameCopy->mRotationAngle);
     frameCopy->mData = (uint8_t *)frameCopy + sizeof(VideoFrame);
     memcpy(frameCopy->mData, frame->mData, frame->mSize);
     delete frame;  // Fix memory leakage
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index d37d83d..553648d 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -340,6 +340,17 @@
     return OK;
 }
 
+// Always rotate clockwise, and only support 0, 90, 180 and 270 for now.
+status_t StagefrightRecorder::setParamVideoRotation(int32_t degrees) {
+    LOGV("setParamVideoRotation: %d", degrees);
+    if (degrees < 0 || degrees % 90 != 0) {
+        LOGE("Unsupported video rotation angle: %d", degrees);
+        return BAD_VALUE;
+    }
+    mRotationDegrees = degrees % 360;
+    return OK;
+}
+
 status_t StagefrightRecorder::setParamMaxFileDurationUs(int64_t timeUs) {
     LOGV("setParamMaxFileDurationUs: %lld us", timeUs);
     if (timeUs <= 0) {
@@ -532,6 +543,11 @@
         if (safe_strtoi32(value.string(), &video_bitrate)) {
             return setParamVideoEncodingBitRate(video_bitrate);
         }
+    } else if (key == "video-param-rotation-angle-degrees") {
+        int32_t degrees;
+        if (safe_strtoi32(value.string(), &degrees)) {
+            return setParamVideoRotation(degrees);
+        }
     } else if (key == "video-param-i-frames-interval") {
         int32_t seconds;
         if (safe_strtoi32(value.string(), &seconds)) {
@@ -1105,6 +1121,9 @@
     if (mTrackEveryTimeDurationUs > 0) {
         meta->setInt64(kKeyTrackTimeStatus, mTrackEveryTimeDurationUs);
     }
+    if (mRotationDegrees != 0) {
+        meta->setInt32(kKeyRotationDegree, mRotationDegrees);
+    }
     writer->setListener(mListener);
     mWriter = writer;
     return mWriter->start(meta.get());
@@ -1187,6 +1206,7 @@
     mMaxFileDurationUs = 0;
     mMaxFileSizeBytes = 0;
     mTrackEveryTimeDurationUs = 0;
+    mRotationDegrees = 0;
     mEncoderProfiles = MediaProfiles::getInstance();
 
     mOutputFd = -1;
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index ad0dfa0..e42df2e 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -91,6 +91,7 @@
     int64_t mMaxFileSizeBytes;
     int64_t mMaxFileDurationUs;
     int64_t mTrackEveryTimeDurationUs;
+    int32_t mRotationDegrees;  // Clockwise
 
     String8 mParams;
     int mOutputFd;
@@ -120,6 +121,7 @@
     status_t setParamVideoEncoderLevel(int32_t level);
     status_t setParamVideoCameraId(int32_t cameraId);
     status_t setParamVideoTimeScale(int32_t timeScale);
+    status_t setParamVideoRotation(int32_t degrees);
     status_t setParamTrackTimeStatus(int64_t timeDurationUs);
     status_t setParamInterleaveDuration(int32_t durationUs);
     status_t setParam64BitFileOffset(bool use64BitFileOffset);
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 064a00c..66eb7ee 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -103,12 +103,14 @@
             OMX_COLOR_FORMATTYPE colorFormat,
             const sp<ISurface> &surface,
             size_t displayWidth, size_t displayHeight,
-            size_t decodedWidth, size_t decodedHeight)
+            size_t decodedWidth, size_t decodedHeight,
+            int32_t rotationDegrees)
         : mTarget(NULL),
           mLibHandle(NULL) {
             init(previewOnly, componentName,
                  colorFormat, surface, displayWidth,
-                 displayHeight, decodedWidth, decodedHeight);
+                 displayHeight, decodedWidth, decodedHeight,
+                 rotationDegrees);
     }
 
     virtual void render(MediaBuffer *buffer) {
@@ -141,7 +143,8 @@
             OMX_COLOR_FORMATTYPE colorFormat,
             const sp<ISurface> &surface,
             size_t displayWidth, size_t displayHeight,
-            size_t decodedWidth, size_t decodedHeight);
+            size_t decodedWidth, size_t decodedHeight,
+            int32_t rotationDegrees);
 
     AwesomeLocalRenderer(const AwesomeLocalRenderer &);
     AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);;
@@ -153,7 +156,8 @@
         OMX_COLOR_FORMATTYPE colorFormat,
         const sp<ISurface> &surface,
         size_t displayWidth, size_t displayHeight,
-        size_t decodedWidth, size_t decodedHeight) {
+        size_t decodedWidth, size_t decodedHeight,
+        int32_t rotationDegrees) {
     if (!previewOnly) {
         // We will stick to the vanilla software-color-converting renderer
         // for "previewOnly" mode, to avoid unneccessarily switching overlays
@@ -162,6 +166,14 @@
         mLibHandle = dlopen("libstagefrighthw.so", RTLD_NOW);
 
         if (mLibHandle) {
+            typedef VideoRenderer *(*CreateRendererWithRotationFunc)(
+                    const sp<ISurface> &surface,
+                    const char *componentName,
+                    OMX_COLOR_FORMATTYPE colorFormat,
+                    size_t displayWidth, size_t displayHeight,
+                    size_t decodedWidth, size_t decodedHeight,
+                    int32_t rotationDegrees);
+
             typedef VideoRenderer *(*CreateRendererFunc)(
                     const sp<ISurface> &surface,
                     const char *componentName,
@@ -169,17 +181,36 @@
                     size_t displayWidth, size_t displayHeight,
                     size_t decodedWidth, size_t decodedHeight);
 
-            CreateRendererFunc func =
-                (CreateRendererFunc)dlsym(
+            CreateRendererWithRotationFunc funcWithRotation =
+                (CreateRendererWithRotationFunc)dlsym(
                         mLibHandle,
-                        "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20"
-                        "OMX_COLOR_FORMATTYPEjjjj");
+                        "_Z26createRendererWithRotationRKN7android2spINS_8"
+                        "ISurfaceEEEPKc20OMX_COLOR_FORMATTYPEjjjji");
 
-            if (func) {
+            if (funcWithRotation) {
                 mTarget =
-                    (*func)(surface, componentName, colorFormat,
-                        displayWidth, displayHeight,
-                        decodedWidth, decodedHeight);
+                    (*funcWithRotation)(
+                            surface, componentName, colorFormat,
+                            displayWidth, displayHeight,
+                            decodedWidth, decodedHeight,
+                            rotationDegrees);
+            } else {
+                if (rotationDegrees != 0) {
+                    LOGW("renderer does not support rotation.");
+                }
+
+                CreateRendererFunc func =
+                    (CreateRendererFunc)dlsym(
+                            mLibHandle,
+                            "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20"
+                            "OMX_COLOR_FORMATTYPEjjjj");
+
+                if (func) {
+                    mTarget =
+                        (*func)(surface, componentName, colorFormat,
+                            displayWidth, displayHeight,
+                            decodedWidth, decodedHeight);
+                }
             }
         }
     }
@@ -187,7 +218,7 @@
     if (mTarget == NULL) {
         mTarget = new SoftwareRenderer(
                 colorFormat, surface, displayWidth, displayHeight,
-                decodedWidth, decodedHeight);
+                decodedWidth, decodedHeight, rotationDegrees);
     }
 }
 
@@ -785,6 +816,12 @@
         CHECK(meta->findInt32(kKeyWidth, &decodedWidth));
         CHECK(meta->findInt32(kKeyHeight, &decodedHeight));
 
+        int32_t rotationDegrees;
+        if (!mVideoTrack->getFormat()->findInt32(
+                    kKeyRotation, &rotationDegrees)) {
+            rotationDegrees = 0;
+        }
+
         mVideoRenderer.clear();
 
         // Must ensure that mVideoRenderer's destructor is actually executed
@@ -800,7 +837,8 @@
                         mISurface, component,
                         (OMX_COLOR_FORMATTYPE)format,
                         decodedWidth, decodedHeight,
-                        mVideoWidth, mVideoHeight));
+                        mVideoWidth, mVideoHeight,
+                        rotationDegrees));
         } else {
             // Other decoders are instantiated locally and as a consequence
             // allocate their buffers in local address space.
@@ -810,7 +848,7 @@
                 (OMX_COLOR_FORMATTYPE)format,
                 mISurface,
                 mVideoWidth, mVideoHeight,
-                decodedWidth, decodedHeight);
+                decodedWidth, decodedHeight, rotationDegrees);
         }
     }
 }
@@ -1625,7 +1663,22 @@
         if (mVideoWidth < 0 || mVideoHeight < 0) {
             notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
         } else {
-            notifyListener_l(MEDIA_SET_VIDEO_SIZE, mVideoWidth, mVideoHeight);
+            int32_t rotationDegrees;
+            if (!mVideoTrack->getFormat()->findInt32(
+                        kKeyRotation, &rotationDegrees)) {
+                rotationDegrees = 0;
+            }
+
+#if 1
+            if (rotationDegrees == 90 || rotationDegrees == 270) {
+                notifyListener_l(
+                        MEDIA_SET_VIDEO_SIZE, mVideoHeight, mVideoWidth);
+            } else
+#endif
+            {
+                notifyListener_l(
+                        MEDIA_SET_VIDEO_SIZE, mVideoWidth, mVideoHeight);
+            }
         }
 
         notifyListener_l(MEDIA_PREPARED);
@@ -1757,7 +1810,8 @@
                     state->mVideoWidth,
                     state->mVideoHeight,
                     state->mDecodedWidth,
-                    state->mDecodedHeight);
+                    state->mDecodedHeight,
+                    0);
 
         mVideoRendererIsPreview = true;
 
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index f404708..2154f2f 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -27,11 +27,11 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/DataSource.h>
 #include "include/ESDS.h"
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
@@ -579,52 +579,9 @@
 
         case FOURCC('t', 'k', 'h', 'd'):
         {
-            if (chunk_data_size < 4) {
-                return ERROR_MALFORMED;
-            }
-
-            uint8_t version;
-            if (mDataSource->readAt(data_offset, &version, 1) < 1) {
-                return ERROR_IO;
-            }
-
-            uint64_t ctime, mtime, duration;
-            int32_t id;
-            uint32_t width, height;
-
-            if (version == 1) {
-                if (chunk_data_size != 36 + 60) {
-                    return ERROR_MALFORMED;
-                }
-
-                uint8_t buffer[36 + 60];
-                if (mDataSource->readAt(
-                            data_offset, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
-                    return ERROR_IO;
-                }
-
-                ctime = U64_AT(&buffer[4]);
-                mtime = U64_AT(&buffer[12]);
-                id = U32_AT(&buffer[20]);
-                duration = U64_AT(&buffer[28]);
-                width = U32_AT(&buffer[88]);
-                height = U32_AT(&buffer[92]);
-            } else if (version == 0) {
-                if (chunk_data_size != 24 + 60) {
-                    return ERROR_MALFORMED;
-                }
-
-                uint8_t buffer[24 + 60];
-                if (mDataSource->readAt(
-                            data_offset, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
-                    return ERROR_IO;
-                }
-                ctime = U32_AT(&buffer[4]);
-                mtime = U32_AT(&buffer[8]);
-                id = U32_AT(&buffer[12]);
-                duration = U32_AT(&buffer[20]);
-                width = U32_AT(&buffer[76]);
-                height = U32_AT(&buffer[80]);
+            status_t err;
+            if ((err = parseTrackHeader(data_offset, chunk_data_size)) != OK) {
+                return err;
             }
 
             *offset += chunk_size;
@@ -1073,6 +1030,89 @@
     return OK;
 }
 
+status_t MPEG4Extractor::parseTrackHeader(
+        off_t data_offset, off_t data_size) {
+    if (data_size < 4) {
+        return ERROR_MALFORMED;
+    }
+
+    uint8_t version;
+    if (mDataSource->readAt(data_offset, &version, 1) < 1) {
+        return ERROR_IO;
+    }
+
+    size_t dynSize = (version == 1) ? 36 : 24;
+
+    uint8_t buffer[36 + 60];
+
+    if (data_size != (off_t)dynSize + 60) {
+        return ERROR_MALFORMED;
+    }
+
+    if (mDataSource->readAt(
+                data_offset, buffer, data_size) < (ssize_t)data_size) {
+        return ERROR_IO;
+    }
+
+    uint64_t ctime, mtime, duration;
+    int32_t id;
+
+    if (version == 1) {
+        ctime = U64_AT(&buffer[4]);
+        mtime = U64_AT(&buffer[12]);
+        id = U32_AT(&buffer[20]);
+        duration = U64_AT(&buffer[28]);
+    } else if (version == 0) {
+        ctime = U32_AT(&buffer[4]);
+        mtime = U32_AT(&buffer[8]);
+        id = U32_AT(&buffer[12]);
+        duration = U32_AT(&buffer[20]);
+    }
+
+    size_t matrixOffset = dynSize + 16;
+    int32_t a00 = U32_AT(&buffer[matrixOffset]);
+    int32_t a01 = U32_AT(&buffer[matrixOffset + 4]);
+    int32_t dx = U32_AT(&buffer[matrixOffset + 8]);
+    int32_t a10 = U32_AT(&buffer[matrixOffset + 12]);
+    int32_t a11 = U32_AT(&buffer[matrixOffset + 16]);
+    int32_t dy = U32_AT(&buffer[matrixOffset + 20]);
+
+#if 0
+    LOGI("x' = %.2f * x + %.2f * y + %.2f",
+         a00 / 65536.0f, a01 / 65536.0f, dx / 65536.0f);
+    LOGI("y' = %.2f * x + %.2f * y + %.2f",
+         a10 / 65536.0f, a11 / 65536.0f, dy / 65536.0f);
+#endif
+
+    uint32_t rotationDegrees;
+
+    static const int32_t kFixedOne = 0x10000;
+    if (a00 == kFixedOne && a01 == 0 && a10 == 0 && a11 == kFixedOne) {
+        // Identity, no rotation
+        rotationDegrees = 0;
+    } else if (a00 == 0 && a01 == kFixedOne && a10 == -kFixedOne && a11 == 0) {
+        rotationDegrees = 90;
+    } else if (a00 == 0 && a01 == -kFixedOne && a10 == kFixedOne && a11 == 0) {
+        rotationDegrees = 270;
+    } else if (a00 == -kFixedOne && a01 == 0 && a10 == 0 && a11 == -kFixedOne) {
+        rotationDegrees = 180;
+    } else {
+        LOGW("We only support 0,90,180,270 degree rotation matrices");
+        rotationDegrees = 0;
+    }
+
+    if (rotationDegrees != 0) {
+        mLastTrack->meta->setInt32(kKeyRotation, rotationDegrees);
+    }
+
+#if 0
+    uint32_t width = U32_AT(&buffer[dynSize + 52]);
+    uint32_t height = U32_AT(&buffer[dynSize + 56]);
+#endif
+
+    return OK;
+}
+
 status_t MPEG4Extractor::parseMetaData(off_t offset, size_t size) {
     if (size < 4) {
         return ERROR_MALFORMED;
@@ -1386,7 +1426,7 @@
         const uint8_t *ptr = (const uint8_t *)data;
 
         CHECK(size >= 7);
-        CHECK_EQ(ptr[0], 1);  // configurationVersion == 1
+        CHECK_EQ((unsigned)ptr[0], 1u);  // configurationVersion == 1
 
         // The number of bytes used to encode the length of a NAL unit.
         mNALLengthSize = 1 + (ptr[4] & 3);
@@ -1534,7 +1574,7 @@
         }
 
         uint32_t sampleTime;
-        CHECK_EQ(OK, mSampleTable->getMetaDataForSample(
+        CHECK_EQ((status_t)OK, mSampleTable->getMetaDataForSample(
                     sampleIndex, NULL, NULL, &sampleTime));
 
         if (mode == ReadOptions::SEEK_CLOSEST) {
@@ -1581,7 +1621,7 @@
         err = mGroup->acquire_buffer(&mBuffer);
 
         if (err != OK) {
-            CHECK_EQ(mBuffer, NULL);
+            CHECK(mBuffer == NULL);
             return err;
         }
     }
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index a15c274..cbb1604 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -202,6 +202,7 @@
 
     // Simple validation on the codec specific data
     status_t checkCodecSpecificData() const;
+    int32_t mRotation;
 
     void updateTrackSizeEstimate();
     void addOneStscTableEntry(size_t chunkId, size_t sampleId);
@@ -519,6 +520,58 @@
     pthread_join(mThread, &dummy);
 }
 
+/*
+ * MP4 file standard defines a composition matrix:
+ * | a  b  u |
+ * | c  d  v |
+ * | x  y  w |
+ *
+ * the element in the matrix is stored in the following
+ * order: {a, b, u, c, d, v, x, y, w},
+ * where a, b, c, d, x, and y is in 16.16 format, while
+ * u, v and w is in 2.30 format.
+ */
+void MPEG4Writer::writeCompositionMatrix(int degrees) {
+    LOGV("writeCompositionMatrix");
+    uint32_t a = 0x00010000;
+    uint32_t b = 0;
+    uint32_t c = 0;
+    uint32_t d = 0x00010000;
+    switch (degrees) {
+        case 0:
+            break;
+        case 90:
+            a = 0;
+            b = 0x00010000;
+            c = 0xFFFF0000;
+            d = 0;
+            break;
+        case 180:
+            a = 0xFFFF0000;
+            d = 0xFFFF0000;
+            break;
+        case 270:
+            a = 0;
+            b = 0xFFFF0000;
+            c = 0x00010000;
+            d = 0;
+            break;
+        default:
+            CHECK(!"Should never reach this unknown rotation");
+            break;
+    }
+
+    writeInt32(a);           // a
+    writeInt32(b);           // b
+    writeInt32(0);           // u
+    writeInt32(c);           // c
+    writeInt32(d);           // d
+    writeInt32(0);           // v
+    writeInt32(0);           // x
+    writeInt32(0);           // y
+    writeInt32(0x40000000);  // w
+}
+
 status_t MPEG4Writer::stop() {
     if (mFile == NULL) {
         return OK;
@@ -584,15 +637,7 @@
         writeInt16(0);             // reserved
         writeInt32(0);             // reserved
         writeInt32(0);             // reserved
-        writeInt32(0x10000);       // matrix
-        writeInt32(0);
-        writeInt32(0);
-        writeInt32(0);
-        writeInt32(0x10000);
-        writeInt32(0);
-        writeInt32(0);
-        writeInt32(0);
-        writeInt32(0x40000000);
+        writeCompositionMatrix(0);
         writeInt32(0);             // predefined
         writeInt32(0);             // predefined
         writeInt32(0);             // predefined
@@ -885,7 +930,8 @@
       mCodecSpecificData(NULL),
       mCodecSpecificDataSize(0),
       mGotAllCodecSpecificData(false),
-      mReachedEOS(false) {
+      mReachedEOS(false),
+      mRotation(0) {
     getCodecSpecificDataFromInputFormatIfPossible();
 
     const char *mime;
@@ -1178,6 +1224,11 @@
         startTimeUs = 0;
     }
 
+    int32_t rotationDegrees;
+    if (!mIsAudio && params && params->findInt32(kKeyRotationDegree, &rotationDegrees)) {
+        mRotation = rotationDegrees;
+    }
+
     mIsRealTimeRecording = true;
     {
         int32_t isNotRealTime;
@@ -2071,15 +2122,7 @@
         mOwner->writeInt16(mIsAudio ? 0x100 : 0);  // volume
         mOwner->writeInt16(0);             // reserved
 
-        mOwner->writeInt32(0x10000);       // matrix
-        mOwner->writeInt32(0);
-        mOwner->writeInt32(0);
-        mOwner->writeInt32(0);
-        mOwner->writeInt32(0x10000);
-        mOwner->writeInt32(0);
-        mOwner->writeInt32(0);
-        mOwner->writeInt32(0);
-        mOwner->writeInt32(0x40000000);
+        mOwner->writeCompositionMatrix(mRotation);
 
         if (mIsAudio) {
             mOwner->writeInt32(0);
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 9a49a9b..980da77 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -412,6 +412,13 @@
         quirks |= kOutputBuffersAreUnreadable;
     }
 
+    if (!strncmp(componentName, "OMX.SEC.", 8) && isEncoder) {
+        // These input buffers contain meta data (for instance,
+        // information helps locate the actual YUV data, or
+        // the physical address of the YUV data).
+        quirks |= kStoreMetaDataInInputVideoBuffers;
+    }
+
     return quirks;
 }
 
@@ -1695,7 +1702,15 @@
                      "an EMPTY_BUFFER_DONE.", buffer);
             }
 
-            buffers->editItemAt(i).mOwnedByComponent = false;
+            {
+                BufferInfo *info = &buffers->editItemAt(i);
+                info->mOwnedByComponent = false;
+                if (info->mMediaBuffer != NULL) {
+                    // It is time to release the media buffers storing meta data
+                    info->mMediaBuffer->release();
+                    info->mMediaBuffer = NULL;
+                }
+            }
 
             if (mPortStatus[kPortIndexInput] == DISABLING) {
                 CODEC_LOGV("Port is disabled, freeing buffer %p", buffer);
@@ -2202,6 +2217,7 @@
             CHECK_EQ(info->mMediaBuffer->refcount(), 0);
 
             info->mMediaBuffer->release();
+            info->mMediaBuffer = NULL;
         }
 
         buffers->removeAt(i);
@@ -2434,11 +2450,19 @@
             break;
         }
 
+        // Do not release the media buffer if it stores meta data
+        // instead of YUV data. The release is delayed until
+        // EMPTY_BUFFER_DONE callback is received.
+        bool releaseBuffer = true;
         if (mIsEncoder && (mQuirks & kAvoidMemcopyInputRecordingFrames)) {
             CHECK(mOMXLivesLocally && offset == 0);
             OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *) info->mBuffer;
             header->pBuffer = (OMX_U8 *) srcBuffer->data() + srcBuffer->range_offset();
         } else {
+            if (mQuirks & kStoreMetaDataInInputVideoBuffers) {
+                releaseBuffer = false;
+                info->mMediaBuffer = srcBuffer;
+            }
             memcpy((uint8_t *)info->mData + offset,
                     (const uint8_t *)srcBuffer->data() + srcBuffer->range_offset(),
                     srcBuffer->range_length());
@@ -2454,8 +2478,10 @@
 
         offset += srcBuffer->range_length();
 
-        srcBuffer->release();
-        srcBuffer = NULL;
+        if (releaseBuffer) {
+            srcBuffer->release();
+            srcBuffer = NULL;
+        }
 
         ++n;
 
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index a800a93..9b2dec9 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -191,6 +191,11 @@
     CHECK(meta->findInt32(kKeyWidth, &width));
     CHECK(meta->findInt32(kKeyHeight, &height));
 
+    int32_t rotationAngle;
+    if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) {
+        rotationAngle = 0;  // By default, no rotation
+    }
+
     VideoFrame *frame = new VideoFrame;
     frame->mWidth = width;
     frame->mHeight = height;
@@ -198,6 +203,7 @@
     frame->mDisplayHeight = height;
     frame->mSize = width * height * 2;
     frame->mData = new uint8_t[frame->mSize];
+    frame->mRotationAngle = rotationAngle;
 
     int32_t srcFormat;
     CHECK(meta->findInt32(kKeyColorFormat, &srcFormat));
diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
index a6dbf69..86ad85b 100644
--- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp
+++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
@@ -30,7 +30,8 @@
         OMX_COLOR_FORMATTYPE colorFormat,
         const sp<ISurface> &surface,
         size_t displayWidth, size_t displayHeight,
-        size_t decodedWidth, size_t decodedHeight)
+        size_t decodedWidth, size_t decodedHeight,
+        int32_t rotationDegrees)
     : mColorFormat(colorFormat),
       mConverter(colorFormat, OMX_COLOR_Format16bitRGB565),
       mISurface(surface),
@@ -56,10 +57,20 @@
     CHECK(mMemoryHeap->heapID() >= 0);
     CHECK(mConverter.isValid());
 
+    uint32_t orientation;
+    switch (rotationDegrees) {
+        case 0: orientation = ISurface::BufferHeap::ROT_0; break;
+        case 90: orientation = ISurface::BufferHeap::ROT_90; break;
+        case 180: orientation = ISurface::BufferHeap::ROT_180; break;
+        case 270: orientation = ISurface::BufferHeap::ROT_270; break;
+        default: orientation = ISurface::BufferHeap::ROT_0; break;
+    }
+
     ISurface::BufferHeap bufferHeap(
             mDisplayWidth, mDisplayHeight,
             mDecodedWidth, mDecodedHeight,
             PIXEL_FORMAT_RGB_565,
+            orientation, 0,
             mMemoryHeap);
 
     status_t err = mISurface->registerBuffers(bufferHeap);
diff --git a/media/libstagefright/include/MPEG4Extractor.h b/media/libstagefright/include/MPEG4Extractor.h
index 1c9cc7e..2610b0e 100644
--- a/media/libstagefright/include/MPEG4Extractor.h
+++ b/media/libstagefright/include/MPEG4Extractor.h
@@ -71,6 +71,8 @@
 
     static status_t verifyTrack(Track *track);
 
+    status_t parseTrackHeader(off_t data_offset, off_t data_size);
+
     MPEG4Extractor(const MPEG4Extractor &);
     MPEG4Extractor &operator=(const MPEG4Extractor &);
 };
diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h
index c99da59..72ab5aa 100644
--- a/media/libstagefright/include/OMX.h
+++ b/media/libstagefright/include/OMX.h
@@ -92,7 +92,8 @@
             const char *componentName,
             OMX_COLOR_FORMATTYPE colorFormat,
             size_t encodedWidth, size_t encodedHeight,
-            size_t displayWidth, size_t displayHeight);
+            size_t displayWidth, size_t displayHeight,
+            int32_t rotationDegrees);
 
     virtual void binderDied(const wp<IBinder> &the_late_who);
 
diff --git a/media/libstagefright/include/SoftwareRenderer.h b/media/libstagefright/include/SoftwareRenderer.h
index 9eed089..25c9df7 100644
--- a/media/libstagefright/include/SoftwareRenderer.h
+++ b/media/libstagefright/include/SoftwareRenderer.h
@@ -33,7 +33,8 @@
             OMX_COLOR_FORMATTYPE colorFormat,
             const sp<ISurface> &surface,
             size_t displayWidth, size_t displayHeight,
-            size_t decodedWidth, size_t decodedHeight);
+            size_t decodedWidth, size_t decodedHeight,
+            int32_t rotationDegrees = 0);
 
     virtual ~SoftwareRenderer();
 
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index c927da1..63af26a 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -459,7 +459,8 @@
         const char *componentName,
         OMX_COLOR_FORMATTYPE colorFormat,
         size_t encodedWidth, size_t encodedHeight,
-        size_t displayWidth, size_t displayHeight) {
+        size_t displayWidth, size_t displayHeight,
+        int32_t rotationDegrees) {
     Mutex::Autolock autoLock(mLock);
 
     VideoRenderer *impl = NULL;
@@ -467,6 +468,14 @@
     void *libHandle = dlopen("libstagefrighthw.so", RTLD_NOW);
 
     if (libHandle) {
+        typedef VideoRenderer *(*CreateRendererWithRotationFunc)(
+                const sp<ISurface> &surface,
+                const char *componentName,
+                OMX_COLOR_FORMATTYPE colorFormat,
+                size_t displayWidth, size_t displayHeight,
+                size_t decodedWidth, size_t decodedHeight,
+                int32_t rotationDegrees);
+
         typedef VideoRenderer *(*CreateRendererFunc)(
                 const sp<ISurface> &surface,
                 const char *componentName,
@@ -474,22 +483,35 @@
                 size_t displayWidth, size_t displayHeight,
                 size_t decodedWidth, size_t decodedHeight);
 
-        CreateRendererFunc func =
-            (CreateRendererFunc)dlsym(
+        CreateRendererWithRotationFunc funcWithRotation =
+            (CreateRendererWithRotationFunc)dlsym(
                     libHandle,
-                    "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20"
-                    "OMX_COLOR_FORMATTYPEjjjj");
+                    "_Z26createRendererWithRotationRKN7android2spINS_8"
+                    "ISurfaceEEEPKc20OMX_COLOR_FORMATTYPEjjjji");
 
-        if (func) {
-            impl = (*func)(surface, componentName, colorFormat,
-                    displayWidth, displayHeight, encodedWidth, encodedHeight);
+        if (funcWithRotation) {
+            impl = (*funcWithRotation)(
+                    surface, componentName, colorFormat,
+                    displayWidth, displayHeight, encodedWidth, encodedHeight,
+                    rotationDegrees);
+        } else {
+            CreateRendererFunc func =
+                (CreateRendererFunc)dlsym(
+                        libHandle,
+                        "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20"
+                        "OMX_COLOR_FORMATTYPEjjjj");
 
-            if (impl) {
-                impl = new SharedVideoRenderer(libHandle, impl);
-                libHandle = NULL;
+            if (func) {
+                impl = (*func)(surface, componentName, colorFormat,
+                        displayWidth, displayHeight, encodedWidth, encodedHeight);
             }
         }
 
+        if (impl) {
+            impl = new SharedVideoRenderer(libHandle, impl);
+            libHandle = NULL;
+        }
+
         if (libHandle) {
             dlclose(libHandle);
             libHandle = NULL;