am f0ad5484: Merge "In the absence of width/height information in the sdp, extract the dimensions from the avc codec specific data." into gingerbread

Merge commit 'f0ad54846168f07fc1fd7f18cde93deea1559f86' into gingerbread-plus-aosp

* commit 'f0ad54846168f07fc1fd7f18cde93deea1559f86':
  In the absence of width/height information in the sdp, extract the dimensions from the avc codec specific data.
diff --git a/media/libstagefright/mpeg2ts/ABitReader.h b/include/media/stagefright/foundation/ABitReader.h
similarity index 100%
rename from media/libstagefright/mpeg2ts/ABitReader.h
rename to include/media/stagefright/foundation/ABitReader.h
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index b8b2f3f..86fa668 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -39,6 +39,7 @@
         TimedEventQueue.cpp               \
         Utils.cpp                         \
         WAVExtractor.cpp                  \
+        avc_utils.cpp                     \
         string.cpp
 
 LOCAL_C_INCLUDES:= \
diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp
new file mode 100644
index 0000000..511ae12
--- /dev/null
+++ b/media/libstagefright/avc_utils.cpp
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+#include "include/avc_utils.h"
+
+#include <media/stagefright/foundation/ABitReader.h>
+#include <media/stagefright/foundation/ADebug.h>
+
+namespace android {
+
+static unsigned parseUE(ABitReader *br) {
+    unsigned numZeroes = 0;
+    while (br->getBits(1) == 0) {
+        ++numZeroes;
+    }
+
+    unsigned x = br->getBits(numZeroes);
+
+    return x + (1u << numZeroes) - 1;
+}
+
+// Determine video dimensions from the sequence parameterset.
+void FindAVCDimensions(
+        const sp<ABuffer> &seqParamSet, int32_t *width, int32_t *height) {
+    ABitReader br(seqParamSet->data() + 1, seqParamSet->size() - 1);
+
+    unsigned profile_idc = br.getBits(8);
+    br.skipBits(16);
+    parseUE(&br);  // seq_parameter_set_id
+
+    if (profile_idc == 100 || profile_idc == 110
+            || profile_idc == 122 || profile_idc == 244
+            || profile_idc == 44 || profile_idc == 83 || profile_idc == 86) {
+        unsigned chroma_format_idc = parseUE(&br);
+        if (chroma_format_idc == 3) {
+            br.skipBits(1);  // residual_colour_transform_flag
+        }
+        parseUE(&br);  // bit_depth_luma_minus8
+        parseUE(&br);  // bit_depth_chroma_minus8
+        br.skipBits(1);  // qpprime_y_zero_transform_bypass_flag
+        CHECK_EQ(br.getBits(1), 0u);  // seq_scaling_matrix_present_flag
+    }
+
+    parseUE(&br);  // log2_max_frame_num_minus4
+    unsigned pic_order_cnt_type = parseUE(&br);
+
+    if (pic_order_cnt_type == 0) {
+        parseUE(&br);  // log2_max_pic_order_cnt_lsb_minus4
+    } else if (pic_order_cnt_type == 1) {
+        // offset_for_non_ref_pic, offset_for_top_to_bottom_field and
+        // offset_for_ref_frame are technically se(v), but since we are
+        // just skipping over them the midpoint does not matter.
+
+        br.getBits(1);  // delta_pic_order_always_zero_flag
+        parseUE(&br);  // offset_for_non_ref_pic
+        parseUE(&br);  // offset_for_top_to_bottom_field
+
+        unsigned num_ref_frames_in_pic_order_cnt_cycle = parseUE(&br);
+        for (unsigned i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; ++i) {
+            parseUE(&br);  // offset_for_ref_frame
+        }
+    }
+
+    parseUE(&br);  // num_ref_frames
+    br.getBits(1);  // gaps_in_frame_num_value_allowed_flag
+
+    unsigned pic_width_in_mbs_minus1 = parseUE(&br);
+    unsigned pic_height_in_map_units_minus1 = parseUE(&br);
+    unsigned frame_mbs_only_flag = br.getBits(1);
+
+    *width = pic_width_in_mbs_minus1 * 16 + 16;
+
+    *height = (2 - frame_mbs_only_flag)
+        * (pic_height_in_map_units_minus1 * 16 + 16);
+}
+
+}  // namespace android
+
diff --git a/media/libstagefright/mpeg2ts/ABitReader.cpp b/media/libstagefright/foundation/ABitReader.cpp
similarity index 100%
rename from media/libstagefright/mpeg2ts/ABitReader.cpp
rename to media/libstagefright/foundation/ABitReader.cpp
diff --git a/media/libstagefright/foundation/Android.mk b/media/libstagefright/foundation/Android.mk
index 35eea7e..f6a8a52 100644
--- a/media/libstagefright/foundation/Android.mk
+++ b/media/libstagefright/foundation/Android.mk
@@ -3,6 +3,7 @@
 
 LOCAL_SRC_FILES:=               \
     AAtomizer.cpp               \
+    ABitReader.cpp              \
     ABuffer.cpp                 \
     ADebug.cpp                  \
     AHandler.cpp                \
diff --git a/media/libstagefright/include/avc_utils.h b/media/libstagefright/include/avc_utils.h
new file mode 100644
index 0000000..cc405b5
--- /dev/null
+++ b/media/libstagefright/include/avc_utils.h
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+#ifndef AVC_UTILS_H_
+
+#define AVC_UTILS_H_
+
+#include <media/stagefright/foundation/ABuffer.h>
+
+namespace android {
+
+void FindAVCDimensions(
+        const sp<ABuffer> &seqParamSet, int32_t *width, int32_t *height);
+
+}  // namespace android
+
+#endif  // AVC_UTILS_H_
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index d05975d..26a0fb3 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -16,9 +16,10 @@
 
 #include "ATSParser.h"
 
-#include "ABitReader.h"
 #include "AnotherPacketSource.h"
+#include "include/avc_utils.h"
 
+#include <media/stagefright/foundation/ABitReader.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -473,60 +474,6 @@
     }
 }
 
-static unsigned parseUE(ABitReader *br) {
-    unsigned numZeroes = 0;
-    while (br->getBits(1) == 0) {
-        ++numZeroes;
-    }
-
-    unsigned x = br->getBits(numZeroes);
-
-    return x + (1u << numZeroes) - 1;
-}
-
-// Determine video dimensions from the sequence parameterset.
-static void FindDimensions(
-        const sp<ABuffer> seqParamSet, int32_t *width, int32_t *height) {
-    ABitReader br(seqParamSet->data() + 1, seqParamSet->size() - 1);
-
-    unsigned profile_idc = br.getBits(8);
-    br.skipBits(16);
-    parseUE(&br);  // seq_parameter_set_id
-
-    if (profile_idc == 100 || profile_idc == 110
-            || profile_idc == 122 || profile_idc == 144) {
-        TRESPASS();
-    }
-
-    parseUE(&br);  // log2_max_frame_num_minus4
-    unsigned pic_order_cnt_type = parseUE(&br);
-
-    if (pic_order_cnt_type == 0) {
-        parseUE(&br);  // log2_max_pic_order_cnt_lsb_minus4
-    } else if (pic_order_cnt_type == 1) {
-        br.getBits(1);  // delta_pic_order_always_zero_flag
-        parseUE(&br);  // offset_for_non_ref_pic
-        parseUE(&br);  // offset_for_top_to_bottom_field
-
-        unsigned num_ref_frames_in_pic_order_cnt_cycle = parseUE(&br);
-        for (unsigned i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; ++i) {
-            parseUE(&br);  // offset_for_ref_frame
-        }
-    }
-
-    parseUE(&br);  // num_ref_frames
-    br.getBits(1);  // gaps_in_frame_num_value_allowed_flag
-
-    unsigned pic_width_in_mbs_minus1 = parseUE(&br);
-    unsigned pic_height_in_map_units_minus1 = parseUE(&br);
-    unsigned frame_mbs_only_flag = br.getBits(1);
-
-    *width = pic_width_in_mbs_minus1 * 16 + 16;
-
-    *height = (2 - frame_mbs_only_flag)
-        * (pic_height_in_map_units_minus1 * 16 + 16);
-}
-
 static sp<ABuffer> MakeAVCCodecSpecificData(
         const sp<ABuffer> &buffer, int32_t *width, int32_t *height) {
     const uint8_t *data = buffer->data();
@@ -537,7 +484,7 @@
         return NULL;
     }
 
-    FindDimensions(seqParamSet, width, height);
+    FindAVCDimensions(seqParamSet, width, height);
 
     size_t stopOffset;
     sp<ABuffer> picParamSet = FindNAL(data, size, 8, &stopOffset);
diff --git a/media/libstagefright/mpeg2ts/Android.mk b/media/libstagefright/mpeg2ts/Android.mk
index b6772eb..3544b4c 100644
--- a/media/libstagefright/mpeg2ts/Android.mk
+++ b/media/libstagefright/mpeg2ts/Android.mk
@@ -3,7 +3,6 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=                 \
-        ABitReader.cpp            \
         AnotherPacketSource.cpp   \
         ATSParser.cpp             \
         MPEG2TSExtractor.cpp      \
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index b2d697b..353c746 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -18,6 +18,8 @@
 
 #include "ASessionDescription.h"
 
+#include "avc_utils.h"
+
 #include <ctype.h>
 
 #include <media/stagefright/foundation/ABuffer.h>
@@ -96,7 +98,11 @@
     return buffer;
 }
 
-static sp<ABuffer> MakeAVCCodecSpecificData(const char *params) {
+static sp<ABuffer> MakeAVCCodecSpecificData(
+        const char *params, int32_t *width, int32_t *height) {
+    *width = 0;
+    *height = 0;
+
     AString val;
     if (!GetAttribute(params, "profile-level-id", &val)) {
         return NULL;
@@ -178,6 +184,11 @@
         memcpy(out, nal->data(), nal->size());
 
         out += nal->size();
+
+        if (i == 0) {
+            FindAVCDimensions(nal, width, height);
+            LOG(INFO) << "dimensions " << *width << "x" << *height;
+        }
     }
 
     *out++ = numPicParameterSets;
@@ -193,7 +204,7 @@
         out += nal->size();
     }
 
-    hexdump(csd->data(), csd->size());
+    // hexdump(csd->data(), csd->size());
 
     return csd;
 }
@@ -230,7 +241,7 @@
     csd->data()[sizeof(kStaticESDS)] = (x >> 8) & 0xff;
     csd->data()[sizeof(kStaticESDS) + 1] = x & 0xff;
 
-    hexdump(csd->data(), csd->size());
+    // hexdump(csd->data(), csd->size());
 
     return csd;
 }
@@ -260,22 +271,32 @@
 
         int32_t width, height;
         if (!sessionDesc->getDimensions(index, PT, &width, &height)) {
-            // TODO: extract dimensions from sequence parameter set.
+            width = -1;
+            height = -1;
+        }
+
+        int32_t encWidth, encHeight;
+        sp<ABuffer> codecSpecificData =
+            MakeAVCCodecSpecificData(params.c_str(), &encWidth, &encHeight);
+
+        if (codecSpecificData != NULL) {
+            if (width < 0) {
+                // If no explicit width/height given in the sdp, use the dimensions
+                // extracted from the first sequence parameter set.
+                width = encWidth;
+                height = encHeight;
+            }
+
+            mFormat->setData(
+                    kKeyAVCC, 0,
+                    codecSpecificData->data(), codecSpecificData->size());
+        } else if (width < 0) {
             mInitCheck = ERROR_UNSUPPORTED;
             return;
         }
 
         mFormat->setInt32(kKeyWidth, width);
         mFormat->setInt32(kKeyHeight, height);
-
-        sp<ABuffer> codecSpecificData =
-            MakeAVCCodecSpecificData(params.c_str());
-
-        if (codecSpecificData != NULL) {
-            mFormat->setData(
-                    kKeyAVCC, 0,
-                    codecSpecificData->data(), codecSpecificData->size());
-        }
     } else if (!strncmp(desc.c_str(), "H263-2000/", 10)
             || !strncmp(desc.c_str(), "H263-1998/", 10)) {
         mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);