Bug 1309163: P3. Add PPS decoder. r=rillian
authorJean-Yves Avenard <jyavenard@mozilla.com>
Mon, 24 Oct 2016 23:04:09 +1100
changeset 325346 8930cf031f641559e69435b251eac3d134443c64
parent 325345 99d76c84603d08dcccbd85630c5a62aebc909694
child 325347 566e418afd5ee713b09eb447d807769ea924b8c1
push id24
push usermaklebus@msu.edu
push dateTue, 20 Dec 2016 03:11:33 +0000
reviewersrillian
bugs1309163
milestone53.0a1
Bug 1309163: P3. Add PPS decoder. r=rillian Currently, only decode the first PPS found. MozReview-Commit-ID: APzyvUdeSXR
media/libstagefright/binding/H264.cpp
media/libstagefright/binding/include/mp4_demuxer/H264.h
--- a/media/libstagefright/binding/H264.cpp
+++ b/media/libstagefright/binding/H264.cpp
@@ -6,33 +6,143 @@
 #include "mozilla/PodOperations.h"
 #include "mp4_demuxer/AnnexB.h"
 #include "mp4_demuxer/BitReader.h"
 #include "mp4_demuxer/ByteReader.h"
 #include "mp4_demuxer/ByteWriter.h"
 #include "mp4_demuxer/H264.h"
 #include <media/stagefright/foundation/ABitReader.h>
 #include <limits>
+#include <cmath>
 
 using namespace mozilla;
 
-namespace mp4_demuxer
+namespace mp4_demuxer {
+
+// Default scaling lists (per spec).
+// ITU H264:
+// Table 7-2 – Assignment of mnemonic names to scaling list indices and
+// specification of fall-back rule
+static const uint8_t Default_4x4_Intra[16] = {
+    6, 13, 13, 20,
+   20, 20, 28, 28,
+   28, 28, 32, 32,
+   32, 37, 37, 42
+};
+
+static const uint8_t Default_4x4_Inter[16] = {
+   10, 14, 14, 20,
+   20, 20, 24, 24,
+   24, 24, 27, 27,
+   27, 30, 30, 34
+};
+
+static const uint8_t Default_8x8_Intra[64] = {
+    6, 10, 10, 13, 11, 13, 16, 16,
+   16, 16, 18, 18, 18, 18, 18, 23,
+   23, 23, 23, 23, 23, 25, 25, 25,
+   25, 25, 25, 25, 27, 27, 27, 27,
+   27, 27, 27, 27, 29, 29, 29, 29,
+   29, 29, 29, 31, 31, 31, 31, 31,
+   31, 33, 33, 33, 33, 33, 36, 36,
+   36, 36, 38, 38, 38, 40, 40, 42
+};
+
+static const uint8_t Default_8x8_Inter[64] = {
+    9, 13, 13, 15, 13, 15, 17, 17,
+   17, 17, 19, 19, 19, 19, 19, 21,
+   21, 21, 21, 21, 21, 22, 22, 22,
+   22, 22, 22, 22, 24, 24, 24, 24,
+   24, 24, 24, 24, 25, 25, 25, 25,
+   25, 25, 25, 27, 27, 27, 27, 27,
+   27, 28, 28, 28, 28, 28, 30, 30,
+   30, 30, 32, 32, 32, 33, 33, 35
+};
+
+namespace detail {
+static void
+scaling_list(BitReader& aBr, uint8_t* aScalingList, int aSizeOfScalingList,
+             const uint8_t* aDefaultList, const uint8_t* aFallbackList)
 {
+  int32_t lastScale = 8;
+  int32_t nextScale = 8;
+  int32_t deltaScale;
+
+  // (pic|seq)_scaling_list_present_flag[i]
+  if (!aBr.ReadBit()) {
+    if (aFallbackList) {
+      memcpy(aScalingList, aFallbackList, aSizeOfScalingList);
+    }
+    return;
+  }
+
+  for (int i = 0; i < aSizeOfScalingList; i++) {
+    if (nextScale != 0) {
+      deltaScale = aBr.ReadSE();
+      nextScale = (lastScale + deltaScale + 256) % 256;
+      if (!i && !nextScale) {
+        memcpy(aScalingList, aDefaultList, aSizeOfScalingList);
+        return;
+      }
+    }
+    aScalingList[i] = (nextScale == 0) ? lastScale : nextScale;
+    lastScale = aScalingList[i];
+  }
+}
+} // namespace detail.
+
+template <size_t N>
+static void
+scaling_list(BitReader& aBr, uint8_t (&aScalingList)[N],
+             const uint8_t (&aDefaultList)[N], const uint8_t (&aFallbackList)[N])
+{
+  detail::scaling_list(aBr, aScalingList, N, aDefaultList, aFallbackList);
+}
+
+template <size_t N>
+static void
+scaling_list(BitReader& aBr, uint8_t (&aScalingList)[N], const uint8_t (&aDefaultList)[N])
+{
+  detail::scaling_list(aBr, aScalingList, N, aDefaultList, nullptr);
+}
 
 SPSData::SPSData()
 {
   PodZero(this);
   // Default values when they aren't defined as per ITU-T H.264 (2014/02).
   chroma_format_idc = 1;
   video_format = 5;
   colour_primaries = 2;
   transfer_characteristics = 2;
   sample_ratio = 1.0;
+  memset(scaling_matrix4x4, 16, sizeof(scaling_matrix4x4));
+  memset(scaling_matrix8x8, 16, sizeof(scaling_matrix8x8));
 }
 
+PPSData::PPSData()
+{
+  PodZero(this);
+  memset(scaling_matrix4x4, 16, sizeof(scaling_matrix4x4));
+  memset(scaling_matrix8x8, 16, sizeof(scaling_matrix8x8));
+}
+
+const uint8_t H264::ZZ_SCAN[16] = { 0,  1,  4,  8,
+                                    5,  2,  3,  6,
+                                    9, 12, 13, 10,
+                                    7, 11, 14, 15 };
+
+const uint8_t H264::ZZ_SCAN8[64] = {  0,  1,  8, 16,  9,  2,  3, 10,
+                                     17, 24, 32, 25, 18, 11,  4,  5,
+                                     12, 19, 26, 33, 40, 48, 41, 34,
+                                     27, 20, 13,  6,  7, 14, 21, 28,
+                                     35, 42, 49, 56, 57, 50, 43, 36,
+                                     29, 22, 15, 23, 30, 37, 44, 51,
+                                     58, 59, 52, 45, 38, 31, 39, 46,
+                                     53, 60, 61, 54, 47, 55, 62, 63 };
+
 /* static */ already_AddRefed<mozilla::MediaByteBuffer>
 H264::DecodeNALUnit(const mozilla::MediaByteBuffer* aNAL)
 {
   MOZ_ASSERT(aNAL);
 
   if (aNAL->Length() < 4) {
     return nullptr;
   }
@@ -86,59 +196,70 @@ ConditionDimension(float aValue)
 /* static */ bool
 H264::DecodeSPS(const mozilla::MediaByteBuffer* aSPS, SPSData& aDest)
 {
   if (!aSPS) {
     return false;
   }
   BitReader br(aSPS);
 
-  int32_t lastScale;
-  int32_t nextScale;
-  int32_t deltaScale;
-
   aDest.profile_idc = br.ReadBits(8);
   aDest.constraint_set0_flag = br.ReadBit();
   aDest.constraint_set1_flag = br.ReadBit();
   aDest.constraint_set2_flag = br.ReadBit();
   aDest.constraint_set3_flag = br.ReadBit();
   aDest.constraint_set4_flag = br.ReadBit();
   aDest.constraint_set5_flag = br.ReadBit();
   br.ReadBits(2); // reserved_zero_2bits
   aDest.level_idc = br.ReadBits(8);
   aDest.seq_parameter_set_id = br.ReadUE();
   if (aDest.profile_idc == 100 || aDest.profile_idc == 110 ||
       aDest.profile_idc == 122 || aDest.profile_idc == 244 ||
       aDest.profile_idc == 44 || aDest.profile_idc == 83 ||
-     aDest.profile_idc == 86 || aDest.profile_idc == 118 ||
+      aDest.profile_idc == 86 || aDest.profile_idc == 118 ||
       aDest.profile_idc == 128 || aDest.profile_idc == 138 ||
       aDest.profile_idc == 139 || aDest.profile_idc == 134) {
     if ((aDest.chroma_format_idc = br.ReadUE()) == 3) {
       aDest.separate_colour_plane_flag = br.ReadBit();
     }
-    br.ReadUE();  // bit_depth_luma_minus8
-    br.ReadUE();  // bit_depth_chroma_minus8
-    br.ReadBit(); // qpprime_y_zero_transform_bypass_flag
-    if (br.ReadBit()) { // seq_scaling_matrix_present_flag
-      for (int idx = 0; idx < ((aDest.chroma_format_idc != 3) ? 8 : 12); ++idx) {
-        if (br.ReadBit()) { // Scaling list present
-          lastScale = nextScale = 8;
-          int sl_n = (idx < 6) ? 16 : 64;
-          for (int sl_i = 0; sl_i < sl_n; sl_i++) {
-            if (nextScale) {
-              deltaScale = br.ReadSE();
-              nextScale = (lastScale + deltaScale + 256) % 256;
-            }
-            lastScale = (nextScale == 0) ? lastScale : nextScale;
-          }
-        }
+    br.ReadUE();        // bit_depth_luma_minus8
+    br.ReadUE();        // bit_depth_chroma_minus8
+    br.ReadBit();       // qpprime_y_zero_transform_bypass_flag
+    aDest.seq_scaling_matrix_present_flag = br.ReadBit();
+    if (aDest.seq_scaling_matrix_present_flag) {
+      scaling_list(br, aDest.scaling_matrix4x4[0], Default_4x4_Intra,
+                   Default_4x4_Intra);
+      scaling_list(br, aDest.scaling_matrix4x4[1], Default_4x4_Intra,
+                   aDest.scaling_matrix4x4[0]);
+      scaling_list(br, aDest.scaling_matrix4x4[2], Default_4x4_Intra,
+                   aDest.scaling_matrix4x4[1]);
+      scaling_list(br, aDest.scaling_matrix4x4[3], Default_4x4_Inter,
+                   Default_4x4_Inter);
+      scaling_list(br, aDest.scaling_matrix4x4[4], Default_4x4_Inter,
+                   aDest.scaling_matrix4x4[3]);
+      scaling_list(br, aDest.scaling_matrix4x4[5], Default_4x4_Inter,
+                   aDest.scaling_matrix4x4[4]);
+
+      scaling_list(br, aDest.scaling_matrix8x8[0], Default_8x8_Intra,
+                   Default_8x8_Intra);
+      scaling_list(br, aDest.scaling_matrix8x8[1], Default_8x8_Inter,
+                   Default_8x8_Inter);
+      if (aDest.chroma_format_idc == 3) {
+        scaling_list(br, aDest.scaling_matrix8x8[2], Default_8x8_Intra,
+                     aDest.scaling_matrix8x8[0]);
+        scaling_list(br, aDest.scaling_matrix8x8[3], Default_8x8_Inter,
+                     aDest.scaling_matrix8x8[1]);
+        scaling_list(br, aDest.scaling_matrix8x8[4], Default_8x8_Intra,
+                     aDest.scaling_matrix8x8[2]);
+        scaling_list(br, aDest.scaling_matrix8x8[5], Default_8x8_Inter,
+                     aDest.scaling_matrix8x8[3]);
       }
     }
   } else if (aDest.profile_idc == 183) {
-      aDest.chroma_format_idc = 0;
+    aDest.chroma_format_idc = 0;
   } else {
     // default value if chroma_format_idc isn't set.
     aDest.chroma_format_idc = 1;
   }
   aDest.log2_max_frame_num = br.ReadUE() + 4;
   aDest.pic_order_cnt_type = br.ReadUE();
   if (aDest.pic_order_cnt_type == 0) {
     aDest.log2_max_pic_order_cnt_lsb = br.ReadUE() + 4;
@@ -235,17 +356,17 @@ H264::DecodeSPS(const mozilla::MediaByte
 H264::vui_parameters(BitReader& aBr, SPSData& aDest)
 {
   aDest.aspect_ratio_info_present_flag = aBr.ReadBit();
   if (aDest.aspect_ratio_info_present_flag) {
     aDest.aspect_ratio_idc = aBr.ReadBits(8);
     aDest.sar_width = aDest.sar_height = 0;
 
     // From E.2.1 VUI parameters semantics (ITU-T H.264 02/2014)
-    switch (aDest.aspect_ratio_idc)  {
+    switch (aDest.aspect_ratio_idc) {
       case 0:
         // Unspecified
         break;
       case 1:
         /*
           1:1
          7680x4320 16:9 frame without horizontal overscan
          3840x2160 16:9 frame without horizontal overscan
@@ -363,17 +484,17 @@ H264::vui_parameters(BitReader& aBr, SPS
         /*
           2:1
          960x1080 16:9 frame without horizontal overscan
          */
         aDest.sample_ratio = 2.0 / 1.0;
         break;
       case 255:
         /* Extended_SAR */
-        aDest.sar_width  = aBr.ReadBits(16);
+        aDest.sar_width = aBr.ReadBits(16);
         aDest.sar_height = aBr.ReadBits(16);
         if (aDest.sar_width && aDest.sar_height) {
           aDest.sample_ratio = float(aDest.sar_width) / float(aDest.sar_height);
         }
         break;
       default:
         break;
     }
@@ -396,46 +517,49 @@ H264::vui_parameters(BitReader& aBr, SPS
 
   aDest.chroma_loc_info_present_flag = aBr.ReadBit();
   if (aDest.chroma_loc_info_present_flag) {
     aDest.chroma_sample_loc_type_top_field = aBr.ReadUE();
     aDest.chroma_sample_loc_type_bottom_field = aBr.ReadUE();
   }
 
   aDest.timing_info_present_flag = aBr.ReadBit();
-  if (aDest.timing_info_present_flag ) {
+  if (aDest.timing_info_present_flag) {
     aDest.num_units_in_tick = aBr.ReadBits(32);
     aDest.time_scale = aBr.ReadBits(32);
     aDest.fixed_frame_rate_flag = aBr.ReadBit();
   }
 }
 
 /* static */ bool
-H264::DecodeSPSFromExtraData(const mozilla::MediaByteBuffer* aExtraData, SPSData& aDest)
+H264::DecodeSPSFromExtraData(const mozilla::MediaByteBuffer* aExtraData,
+                             SPSData& aDest)
 {
   if (!AnnexB::HasSPS(aExtraData)) {
     return false;
   }
   ByteReader reader(aExtraData);
 
   if (!reader.Read(5)) {
     return false;
   }
 
-  if (!(reader.ReadU8() & 0x1f)) {
+  uint8_t numSps = reader.ReadU8() & 0x1f;
+  if (!numSps) {
     // No SPS.
     return false;
   }
+  NS_ASSERTION(numSps == 1, "More than one SPS in extradata");
+
   uint16_t length = reader.ReadU16();
 
   if ((reader.PeekU8() & 0x1f) != 7) {
     // Not a SPS NAL type.
     return false;
   }
-
   const uint8_t* ptr = reader.Read(length);
   if (!ptr) {
     return false;
   }
 
   RefPtr<mozilla::MediaByteBuffer> rawNAL = new mozilla::MediaByteBuffer;
   rawNAL->AppendElements(ptr, length);
 
@@ -450,32 +574,214 @@ H264::DecodeSPSFromExtraData(const mozil
 
 /* static */ bool
 H264::EnsureSPSIsSane(SPSData& aSPS)
 {
   bool valid = true;
   static const float default_aspect = 4.0f / 3.0f;
   if (aSPS.sample_ratio <= 0.0f || aSPS.sample_ratio > 6.0f) {
     if (aSPS.pic_width && aSPS.pic_height) {
-      aSPS.sample_ratio =
-        (float) aSPS.pic_width / (float) aSPS.pic_height;
+      aSPS.sample_ratio = (float)aSPS.pic_width / (float)aSPS.pic_height;
     } else {
       aSPS.sample_ratio = default_aspect;
     }
     aSPS.display_width = aSPS.pic_width;
     aSPS.display_height = aSPS.pic_height;
     valid = false;
   }
   if (aSPS.max_num_ref_frames > 16) {
     aSPS.max_num_ref_frames = 16;
     valid = false;
   }
   return valid;
 }
 
+/* static */ bool
+H264::DecodePPSFromExtraData(const mozilla::MediaByteBuffer* aExtraData,
+                             const SPSData& aSPS, PPSData& aDest)
+{
+  if (!AnnexB::HasPPS(aExtraData)) {
+    return false;
+  }
+  ByteReader reader(aExtraData);
+
+  if (!reader.Read(5)) {
+    return false;
+  }
+
+  uint8_t numSps = reader.ReadU8() & 0x1f;
+  if (!numSps) {
+    // No SPS.
+    return false;
+  }
+  NS_ASSERTION(numSps == 1, "More than one SPS in extradata");
+  for (uint8_t i = 0; i < numSps; i++) {
+    uint16_t length = reader.ReadU16();
+
+    if ((reader.PeekU8() & 0x1f) != 7) {
+      // Not a SPS NAL type.
+      return false;
+    }
+    const uint8_t* ptr = reader.Read(length);
+    if (!ptr) {
+      return false;
+    }
+  }
+  uint8_t numPps = reader.ReadU8();
+  if (!numPps) {
+    // No PPs.
+    return false;
+  }
+  NS_ASSERTION(numPps == 1, "More than one PPS in extradata");
+  uint16_t length = reader.ReadU16();
+
+  if ((reader.PeekU8() & 0x1f) != 8) {
+    // Not a PPS NAL type.
+    return false;
+  }
+  const uint8_t* ptr = reader.Read(length);
+  if (!ptr) {
+    return false;
+  }
+
+  RefPtr<mozilla::MediaByteBuffer> rawNAL = new mozilla::MediaByteBuffer;
+  rawNAL->AppendElements(ptr, length);
+
+  RefPtr<mozilla::MediaByteBuffer> pps = DecodeNALUnit(rawNAL);
+
+  if (!pps) {
+    return false;
+  }
+
+  return DecodePPS(pps, aSPS, aDest);
+}
+
+/* static */ bool
+H264::DecodePPS(const mozilla::MediaByteBuffer* aPPS,const SPSData& aSPS,
+                PPSData& aDest)
+{
+  if (!aPPS) {
+    return false;
+  }
+
+  memcpy(aDest.scaling_matrix4x4, aSPS.scaling_matrix4x4,
+         sizeof(aDest.scaling_matrix4x4));
+  memcpy(aDest.scaling_matrix8x8, aSPS.scaling_matrix8x8,
+         sizeof(aDest.scaling_matrix8x8));
+
+  BitReader br(aPPS);
+
+  aDest.pic_parameter_set_id = br.ReadUE();
+  aDest.seq_parameter_set_id = br.ReadUE();
+  aDest.entropy_coding_mode_flag = br.ReadBit();
+  aDest.bottom_field_pic_order_in_frame_present_flag = br.ReadBit();
+  aDest.num_slice_groups_minus1 = br.ReadUE();
+  if (aDest.num_slice_groups_minus1 > 0) {
+    aDest.slice_group_map_type = br.ReadUE();
+    switch (aDest.slice_group_map_type) {
+      case 0:
+        for (uint8_t iGroup = 0; iGroup <= aDest.num_slice_groups_minus1;
+             iGroup++) {
+          aDest.run_length_minus1[iGroup] = br.ReadUE();
+        }
+        break;
+      case 2:
+        for (uint8_t iGroup = 0; iGroup < aDest.num_slice_groups_minus1;
+             iGroup++) {
+          aDest.top_left[iGroup] = br.ReadUE();
+          aDest.bottom_right[iGroup] = br.ReadUE();
+        }
+        break;
+      case 3:
+      case 4:
+      case 5:
+        aDest.slice_group_change_direction_flag = br.ReadBit();
+        aDest.slice_group_change_rate_minus1 = br.ReadUE();
+        break;
+      case 6:
+        aDest.pic_size_in_map_units_minus1 = br.ReadUE();
+        for (uint32_t i = 0; i <= aDest.pic_size_in_map_units_minus1; i++) {
+          /* slice_group_id[ i ] identifies a slice group of the i-th slice group map
+            unit in raster scan order. The length of the slice_group_id[i] syntax
+            element is Ceil(Log2(num_slice_groups_minus1+1)) bits. The value of
+            slice_group_id[i] shall be in the range of 0 to num_slice_groups_minus1,
+            inclusive. */
+          br.ReadBits(std::ceil(std::log2(aDest.num_slice_groups_minus1 + 1)));
+        }
+        break;
+      default:
+        return false;
+    }
+  }
+  aDest.num_ref_idx_l0_default_active_minus1 = br.ReadUE();
+  aDest.num_ref_idx_l1_default_active_minus1 = br.ReadUE();
+  if (aDest.num_ref_idx_l0_default_active_minus1 > 32 ||
+      aDest.num_ref_idx_l1_default_active_minus1 > 32) {
+    // reference overflow.
+    return false;
+  }
+  aDest.weighted_pred_flag = br.ReadBit();
+  aDest.weighted_bipred_idc = br.ReadBits(2);
+  aDest.pic_init_qp_minus26 = br.ReadSE();
+  aDest.pic_init_qs_minus26 = br.ReadSE();
+  aDest.chroma_qp_index_offset = br.ReadSE();
+  aDest.deblocking_filter_control_present_flag = br.ReadBit();
+  aDest.constrained_intra_pred_flag = br.ReadBit();
+  aDest.redundant_pic_cnt_present_flag = br.ReadBit();
+  if (br.BitsLeft()) {
+    aDest.transform_8x8_mode_flag = br.ReadBit();
+    if (br.ReadBit()) { // pic_scaling_matrix_present_flag
+      if (aSPS.seq_scaling_matrix_present_flag) {
+        scaling_list(br, aDest.scaling_matrix4x4[0], Default_4x4_Intra);
+        scaling_list(br, aDest.scaling_matrix4x4[1], Default_4x4_Intra,
+                     aDest.scaling_matrix4x4[0]);
+        scaling_list(br, aDest.scaling_matrix4x4[2], Default_4x4_Intra,
+                     aDest.scaling_matrix4x4[1]);
+        scaling_list(br, aDest.scaling_matrix4x4[3], Default_4x4_Inter);
+      } else {
+        scaling_list(br, aDest.scaling_matrix4x4[0], Default_4x4_Intra,
+                     Default_4x4_Intra);
+        scaling_list(br, aDest.scaling_matrix4x4[1], Default_4x4_Intra,
+                     aDest.scaling_matrix4x4[0]);
+        scaling_list(br, aDest.scaling_matrix4x4[2], Default_4x4_Intra,
+                     aDest.scaling_matrix4x4[1]);
+        scaling_list(br, aDest.scaling_matrix4x4[3], Default_4x4_Inter,
+                     Default_4x4_Inter);
+      }
+      scaling_list(br, aDest.scaling_matrix4x4[4], Default_4x4_Inter,
+                   aDest.scaling_matrix4x4[3]);
+      scaling_list(br, aDest.scaling_matrix4x4[5], Default_4x4_Inter,
+                   aDest.scaling_matrix4x4[4]);
+      if (aDest.transform_8x8_mode_flag) {
+        if (aSPS.seq_scaling_matrix_present_flag) {
+          scaling_list(br, aDest.scaling_matrix8x8[0], Default_8x8_Intra);
+          scaling_list(br, aDest.scaling_matrix8x8[1], Default_8x8_Inter);
+        } else {
+          scaling_list(br, aDest.scaling_matrix8x8[0], Default_8x8_Intra,
+                       Default_8x8_Intra);
+          scaling_list(br, aDest.scaling_matrix8x8[1], Default_8x8_Inter,
+                       Default_8x8_Inter);
+        }
+        if (aSPS.chroma_format_idc == 3) {
+          scaling_list(br, aDest.scaling_matrix8x8[2], Default_8x8_Intra,
+                       aDest.scaling_matrix8x8[0]);
+          scaling_list(br, aDest.scaling_matrix8x8[3], Default_8x8_Inter,
+                       aDest.scaling_matrix8x8[1]);
+          scaling_list(br, aDest.scaling_matrix8x8[4], Default_8x8_Intra,
+                       aDest.scaling_matrix8x8[2]);
+          scaling_list(br, aDest.scaling_matrix8x8[5], Default_8x8_Inter,
+                       aDest.scaling_matrix8x8[3]);
+        }
+      }
+    }
+    aDest.second_chroma_qp_index_offset = br.ReadSE();
+  }
+  return true;
+}
+
 /* static */ uint32_t
 H264::ComputeMaxRefFrames(const mozilla::MediaByteBuffer* aExtraData)
 {
   uint32_t maxRefFrames = 4;
   // Retrieve video dimensions from H264 SPS NAL.
   SPSData spsdata;
   if (DecodeSPSFromExtraData(aExtraData, spsdata)) {
     // max_num_ref_frames determines the size of the sliding window
--- a/media/libstagefright/binding/include/mp4_demuxer/H264.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/H264.h
@@ -2,18 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MP4_DEMUXER_H264_H_
 #define MP4_DEMUXER_H264_H_
 
 #include "mp4_demuxer/DecoderData.h"
 
-namespace mp4_demuxer
-{
+namespace mp4_demuxer {
 
 class BitReader;
 
 struct SPSData
 {
   /* Decoded Members */
   /*
     pic_width is the decoded width according to:
@@ -90,16 +89,28 @@ struct SPSData
     it shall be inferred to be equal to 0. When separate_colour_plane_flag is
     equal to 1, the primary coded picture consists of three separate components,
     each of which consists of coded samples of one colour plane (Y, Cb or Cr)
     that each use the monochrome coding syntax. In this case, each colour plane
     is associated with a specific colour_plane_id value.
    */
   bool separate_colour_plane_flag;
 
+/*
+   seq_scaling_matrix_present_flag equal to 1 specifies that the flags
+   seq_scaling_list_present_flag[ i ] for i = 0..7 or
+   i = 0..11 are present. seq_scaling_matrix_present_flag equal to 0 specifies
+   that these flags are not present and the sequence-level scaling list
+   specified by Flat_4x4_16 shall be inferred for i = 0..5 and the
+   sequence-level scaling list specified by Flat_8x8_16 shall be inferred for
+   i = 6..11. When seq_scaling_matrix_present_flag is not present, it shall be
+   inferred to be equal to 0.
+   */
+  bool seq_scaling_matrix_present_flag;
+
   /*
     log2_max_frame_num_minus4 specifies the value of the variable
     MaxFrameNum that is used in frame_num related derivations as
     follows:
 
      MaxFrameNum = 2( log2_max_frame_num_minus4 + 4 ). The value of
     log2_max_frame_num_minus4 shall be in the range of 0 to 12, inclusive.
    */
@@ -203,17 +214,17 @@ struct SPSData
 
   /*
     frame_cropping_flag equal to 1 specifies that the frame cropping
     offset parameters follow next in the sequence parameter
     set. frame_cropping_flag equal to 0 specifies that the frame
     cropping offset parameters are not present.
    */
   bool frame_cropping_flag;
-  uint32_t frame_crop_left_offset;;
+  uint32_t frame_crop_left_offset;
   uint32_t frame_crop_right_offset;
   uint32_t frame_crop_top_offset;
   uint32_t frame_crop_bottom_offset;
 
   // VUI Parameters
 
   /*
     vui_parameters_present_flag equal to 1 specifies that the
@@ -320,53 +331,259 @@ struct SPSData
   bool chroma_loc_info_present_flag;
   uint32_t chroma_sample_loc_type_top_field;
   uint32_t chroma_sample_loc_type_bottom_field;
   bool timing_info_present_flag;
   uint32_t num_units_in_tick;
   uint32_t time_scale;
   bool fixed_frame_rate_flag;
 
+  bool scaling_matrix_present;
+  uint8_t scaling_matrix4x4[6][16];
+  uint8_t scaling_matrix8x8[6][64];
+
   SPSData();
 };
 
+struct PPSData
+{
+  /*
+    H264 decoding parameters according to ITU-T H.264 (T-REC-H.264-201402-I/en)
+   http://www.itu.int/rec/T-REC-H.264-201402-I/en
+   7.3.2.2 Picture parameter set RBSP syntax
+  */
+  /* pic_parameter_set_id identifies the picture parameter set that is referred
+      to in the slice header. The value of pic_parameter_set_id shall be in the
+      range of 0 to 255, inclusive. */
+  uint8_t pic_parameter_set_id;
+
+  /* seq_parameter_set_id refers to the active sequence parameter set. The value
+    of seq_parameter_set_id shall be in the range of 0 to 31, inclusive. */
+  uint8_t seq_parameter_set_id;
+
+  /* entropy_coding_mode_flag selects the entropy decoding method to be applied
+    for the syntax elements for which two descriptors appear in the syntax tables
+    as follows:
+    – If entropy_coding_mode_flag is equal to 0, the method specified by the
+      left descriptor in the syntax table is applied (Exp-Golomb coded, see
+      clause 9.1 or CAVLC, see clause 9.2).
+    – Otherwise (entropy_coding_mode_flag is equal to 1), the method specified
+      by the right descriptor in the syntax table is applied (CABAC, see clause
+      9.3) */
+  bool entropy_coding_mode_flag;
+
+  /* bottom_field_pic_order_in_frame_present_flag equal to 1 specifies that the
+    syntax  elements delta_pic_order_cnt_bottom (when pic_order_cnt_type is
+    equal to 0) or delta_pic_order_cnt[ 1 ] (when pic_order_cnt_type is equal to
+    1), which are related to picture order counts for the bottom field of a
+    coded frame, are present in the slice headers for coded frames as specified
+    in clause 7.3.3. bottom_field_pic_order_in_frame_present_flag equal to 0
+    specifies that the syntax elements delta_pic_order_cnt_bottom and
+    delta_pic_order_cnt[ 1 ] are not present inthe slice headers. */
+  bool bottom_field_pic_order_in_frame_present_flag;
+
+  /* num_slice_groups_minus1 plus 1 specifies the number of slice groups for a
+    picture. When num_slice_groups_minus1 is equal to 0, all slices of the
+    picture belong to the same slice group. The allowed range of
+    num_slice_groups_minus1 is specified in Annex A. */
+  uint8_t num_slice_groups_minus1;
+
+  /* slice_group_map_type specifies how the mapping of slice group map units to
+    slice groups is coded. The value of slice_group_map_type shall be in the
+    range of 0 to 6, inclusive. */
+  uint8_t slice_group_map_type;
+
+  /* run_length_minus1[i] is used to specify the number of consecutive slice
+    group map units to be assigned to the i-th slice group in raster scan order
+    of slice group map units. The value of run_length_minus1[ i ] shall be in
+    the range of 0 to PicSizeInMapUnits − 1, inclusive. */
+  uint32_t run_length_minus1[8];
+
+  /* top_left[i] and bottom_right[i] specify the top-left and bottom-right
+    corners of a rectangle, respectively. top_left[i] and bottom_right[i] are
+    slice group map unit positions in a raster scan of the picture for the slice
+    group map units. For each rectangle i, all of the following constraints
+    shall be obeyed by the values of the syntax elements top_left[i] and
+    bottom_right[i]:
+      – top_left[ i ] shall be less than or equal to bottom_right[i] and
+        bottom_right[i] shall be less than PicSizeInMapUnits.
+      – (top_left[i] % PicWidthInMbs) shall be less than or equal to the value
+        of (bottom_right[i] % PicWidthInMbs). */
+  uint32_t top_left[8];
+  uint32_t bottom_right[8];
+
+  /* slice_group_change_direction_flag is used with slice_group_map_type to
+    specify the refined map type when slice_group_map_type is 3, 4, or 5. */
+  bool slice_group_change_direction_flag;
+
+  /* slice_group_change_rate_minus1 is used to specify the variable
+    SliceGroupChangeRate. SliceGroupChangeRate specifies the multiple in number
+    of slice group map units by which the size of a slice group can change from
+    one picture to the next. The value of slice_group_change_rate_minus1 shall
+    be in the range of 0 to PicSizeInMapUnits − 1, inclusive.
+    The SliceGroupChangeRate variable is specified as follows:
+      SliceGroupChangeRate = slice_group_change_rate_minus1 + 1 */
+  uint32_t slice_group_change_rate_minus1;
+
+  /* pic_size_in_map_units_minus1 is used to specify the number of slice group
+    map units in the picture. pic_size_in_map_units_minus1 shall be equal to
+    PicSizeInMapUnits − 1. */
+  uint32_t pic_size_in_map_units_minus1;
+
+  /* num_ref_idx_l0_default_active_minus1 specifies how
+    num_ref_idx_l0_active_minus1 is inferred for P, SP, and B slices
+    with num_ref_idx_active_override_flag equal to 0. The value of
+    num_ref_idx_l0_default_active_minus1 shall be in the
+    range of 0 to 31, inclusive. */
+  uint8_t num_ref_idx_l0_default_active_minus1;
+
+  /* num_ref_idx_l1_default_active_minus1 specifies how
+    num_ref_idx_l1_active_minus1 is inferred for B slices with
+    num_ref_idx_active_override_flag equal to 0. The value of
+    num_ref_idx_l1_default_active_minus1 shall be in the range
+    of 0 to 31, inclusive. */
+  uint8_t num_ref_idx_l1_default_active_minus1;
+
+  /* weighted_pred_flag equal to 0 specifies that the default weighted
+    prediction shall be applied to P and SP slices.
+    weighted_pred_flag equal to 1 specifies that explicit weighted prediction
+    shall be applied to P and SP slices.weighted_pred_flag 1 */
+  bool weighted_pred_flag;
+
+  /* weighted_bipred_idc equal to 0 specifies that the default weighted
+     prediction shall be applied to B slices.
+     weighted_bipred_idc equal to 1 specifies that explicit weighted prediction
+     shall be applied to B slices. weighted_bipred_idc equal to 2 specifies that
+     implicit weighted prediction shall be applied to B slices. The value of
+     weighted_bipred_idc shall be in the range of 0 to 2, inclusive. */
+  uint8_t weighted_bipred_idc;
+
+  /* pic_init_qp_minus26 specifies the initial value minus 26 of SliceQP Y for
+     each slice. The initial value is modified at the slice layer when a
+     non-zero value of slice_qp_delta is decoded, and is modified further when a
+     non-zero value of mb_qp_delta is decoded at the macroblock layer.
+     The value of pic_init_qp_minus26 shall be in the range of
+     −(26 + QpBdOffset Y ) to +25, inclusive. */
+  int8_t pic_init_qp_minus26;
+
+  /* pic_init_qs_minus26 specifies the initial value minus 26 of SliceQS Y for
+    all macroblocks in SP or SI slices. The initial value is modified at the
+    slice layer when a non-zero value of slice_qs_delta is decoded.
+    The value of pic_init_qs_minus26 shall be in the range of −26 to +25,
+    inclusive. */
+  int8_t pic_init_qs_minus26;
+
+  /* chroma_qp_index_offset specifies the offset that shall be added to QP Y and
+    QS Y for addressing the table of QP C values for the Cb chroma component.
+    The value of chroma_qp_index_offset shall be in the range of −12 to +12,
+    inclusive. */
+  int8_t chroma_qp_index_offset;
+
+  /* deblocking_filter_control_present_flag equal to 1 specifies that a set of
+    syntax elements controlling the characteristics of the deblocking filter is
+    present in the slice header. deblocking_filter_control_present_flag equal to
+    0 specifies that the set of syntax elements controlling the characteristics
+    of the deblocking filter is not present in the slice headers and their
+    inferred values are in effect. */
+  bool deblocking_filter_control_present_flag;
+
+  /* constrained_intra_pred_flag equal to 0 specifies that intra prediction
+    allows usage of residual data and decoded samples of neighbouring
+    macroblocks coded using Inter macroblock prediction modes for the prediction
+    of macroblocks coded using Intra macroblock prediction modes.
+    constrained_intra_pred_flag equal to 1 specifies constrained intra
+    prediction, in which case prediction of macroblocks coded using Intra
+    macroblock prediction modes only uses residual data and decoded samples from
+    I or SI macroblock types. */
+  bool constrained_intra_pred_flag;
+
+  /* redundant_pic_cnt_present_flag equal to 0 specifies that the
+    redundant_pic_cnt syntax element is not present in slice headers, coded
+    slice data partition B NAL units, and coded slice data partition C NAL units
+    that refer (either directly or by association with a corresponding coded
+    slice data partition A NAL unit) to the picture parameter set.
+    redundant_pic_cnt_present_flag equal to 1 specifies that the
+    redundant_pic_cnt syntax element is present in all slice headers, coded
+    slice data partition B NAL units, and coded slice data partition C NAL units
+    that refer (either directly or by association with a corresponding coded
+    slice data partition A NAL unit) to the picture parameter set. */
+  bool redundant_pic_cnt_present_flag;
+
+  /* transform_8x8_mode_flag equal to 1 specifies that the 8x8 transform
+    decoding process may be in use (see clause 8.5).
+    transform_8x8_mode_flag equal to 0 specifies that the 8x8 transform decoding
+    process is not in use. When transform_8x8_mode_flag is not present, it shall
+    be inferred to be 0. */
+  bool transform_8x8_mode_flag;
+
+  /* second_chroma_qp_index_offset specifies the offset that shall be added to
+    QP Y and QS Y for addressing the table of QP C values for the Cr chroma
+    component.
+    The value of second_chroma_qp_index_offset shall be in the range of
+    −12 to +12, inclusive.
+    When second_chroma_qp_index_offset is not present, it shall be inferred to
+    be equal to chroma_qp_index_offset. */
+  int8_t second_chroma_qp_index_offset;
+
+  uint8_t scaling_matrix4x4[6][16];
+  uint8_t scaling_matrix8x8[6][64];
+
+  PPSData();
+};
+
 class H264
 {
 public:
-  static bool DecodeSPSFromExtraData(const mozilla::MediaByteBuffer* aExtraData, SPSData& aDest);
+  static bool DecodeSPSFromExtraData(const mozilla::MediaByteBuffer* aExtraData,
+                                     SPSData& aDest);
 
   /* Extract RAW BYTE SEQUENCE PAYLOAD from NAL content.
      Returns nullptr if invalid content.
      This is compliant to ITU H.264 7.3.1 Syntax in tabular form NAL unit syntax
    */
-  static already_AddRefed<mozilla::MediaByteBuffer> DecodeNALUnit(const mozilla::MediaByteBuffer* aNAL);
-
-  /* Decode SPS NAL RBSP and fill SPSData structure */
-  static bool DecodeSPS(const mozilla::MediaByteBuffer* aSPS, SPSData& aDest);
+  static already_AddRefed<mozilla::MediaByteBuffer> DecodeNALUnit(
+    const mozilla::MediaByteBuffer* aNAL);
 
   // Ensure that SPS data makes sense, Return true if SPS data was, and false
   // otherwise. If false, then content will be adjusted accordingly.
   static bool EnsureSPSIsSane(SPSData& aSPS);
 
+  static bool DecodePPSFromExtraData(const mozilla::MediaByteBuffer* aExtraData,
+                                     const SPSData& aSPS, PPSData& aDest);
+
   // If the given aExtraData is valid, return the aExtraData.max_num_ref_frames
   // clamped to be in the range of [4, 16]; otherwise return 4.
-  static uint32_t ComputeMaxRefFrames(const mozilla::MediaByteBuffer* aExtraData);
+  static uint32_t ComputeMaxRefFrames(
+    const mozilla::MediaByteBuffer* aExtraData);
 
   enum class FrameType
   {
     I_FRAME,
     OTHER,
     INVALID,
   };
 
   // Returns the frame type. Returns I_FRAME if the sample is an IDR
   // (Instantaneous Decoding Refresh) Picture.
   static FrameType GetFrameType(const mozilla::MediaRawData* aSample);
 
+  // ZigZag index taBles.
+  // Some hardware requires the tables to be in zigzag order.
+  // Use ZZ_SCAN table for the scaling_matrix4x4.
+  // Use ZZ_SCAN8 table for the scaling_matrix8x8.
+  // e.g. dest_scaling_matrix4x4[i,j] = scaling_matrix4x4[ZZ_SCAN(i,j)]
+  static const uint8_t ZZ_SCAN[16];
+  static const uint8_t ZZ_SCAN8[64];
+
 private:
+  /* Decode SPS NAL RBSP and fill SPSData structure */
+  static bool DecodeSPS(const mozilla::MediaByteBuffer* aSPS, SPSData& aDest);
+  /* Decode PPS NAL RBSP and fill PPSData structure */
+  static bool DecodePPS(const mozilla::MediaByteBuffer* aPPS, const SPSData& aSPS,
+                        PPSData& aDest);
   static void vui_parameters(BitReader& aBr, SPSData& aDest);
   // Read HRD parameters, all data is ignored.
   static void hrd_parameters(BitReader& aBr);
 };
 
 } // namespace mp4_demuxer
 
 #endif // MP4_DEMUXER_H264_H_