Rotation support

- We only support 0, 90, 180, and 270 degree clockwise rotation

- Some players are known to ignore composition matrix in the MP4 file,
  although this is part of the MP4 file standard.
  Both QT and YT are supporting the rotation

The original patch (65a73f4e8c79d05c0d9001b660325748d4ecf37b) was not merged.
The only change I made is to reuse the same kKeyRotation in MetaData.h;
and thus do not neeed to use kKeyRotationDegree.

Change-Id: Ib328716d4842201c4adf57e4ddfe1f1ac1ae4d8a
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/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 6a25dc5..9da5f01 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -345,6 +345,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) {
@@ -599,6 +610,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)) {
@@ -1255,6 +1271,9 @@
     if (mTrackEveryTimeDurationUs > 0) {
         (*meta)->setInt64(kKeyTrackTimeStatus, mTrackEveryTimeDurationUs);
     }
+    if (mRotationDegrees != 0) {
+        (*meta)->setInt32(kKeyRotation, mRotationDegrees);
+    }
 }
 
 status_t StagefrightRecorder::startMPEG4Recording() {
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index d11d7e0..36a15a8 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -93,6 +93,7 @@
     int64_t mMaxFileSizeBytes;
     int64_t mMaxFileDurationUs;
     int64_t mTrackEveryTimeDurationUs;
+    int32_t mRotationDegrees;  // Clockwise
 
     bool mCaptureTimeLapse;
     int64_t mTimeBetweenTimeLapseFrameCaptureUs;
@@ -146,6 +147,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/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index b3ed845..17a40b0 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);
@@ -520,6 +521,59 @@
     LOGD("Writer thread stopped");
 }
 
+/*
+ * 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;
@@ -585,15 +639,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); // matrix
         writeInt32(0);             // predefined
         writeInt32(0);             // predefined
         writeInt32(0);             // predefined
@@ -886,7 +932,8 @@
       mCodecSpecificData(NULL),
       mCodecSpecificDataSize(0),
       mGotAllCodecSpecificData(false),
-      mReachedEOS(false) {
+      mReachedEOS(false),
+      mRotation(0) {
     getCodecSpecificDataFromInputFormatIfPossible();
 
     const char *mime;
@@ -1179,6 +1226,11 @@
         startTimeUs = 0;
     }
 
+    int32_t rotationDegrees;
+    if (!mIsAudio && params && params->findInt32(kKeyRotation, &rotationDegrees)) {
+        mRotation = rotationDegrees;
+    }
+
     mIsRealTimeRecording = true;
     {
         int32_t isNotRealTime;
@@ -2075,15 +2127,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);       // matrix
 
         if (mIsAudio) {
             mOwner->writeInt32(0);