Bug 1300296: P1. Add method to determine if an H264 frame is an I-Frame. r?jesup draft
authorJean-Yves Avenard <jyavenard@mozilla.com>
Sun, 04 Sep 2016 21:28:24 +1000
changeset 411033 2a75d7f650ff7f37bb06e02c3054d3797e9aaa51
parent 410870 91c2b9d5c1354ca79e5b174591dbb03b32b15bbf
child 411034 09594036eca55b7ca44c8951dde74b1a96ce5bff
push id28822
push userbmo:jyavenard@mozilla.com
push dateWed, 07 Sep 2016 14:02:29 +0000
reviewersjesup
bugs1300296, 14496
milestone51.0a1
Bug 1300296: P1. Add method to determine if an H264 frame is an I-Frame. r?jesup We do so by checking the frame data for NAL of type 5 as per ISO IEC 14496-2. MozReview-Commit-ID: JFeLysrZ6aG
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
@@ -483,9 +483,46 @@ H264::ComputeMaxRefFrames(const mozilla:
     // pts frames ordering. Use a minimum of 4 to ensure proper playback of
     // non compliant videos.
     maxRefFrames =
       std::min(std::max(maxRefFrames, spsdata.max_num_ref_frames + 1), 16u);
   }
   return maxRefFrames;
 }
 
+/* static */ H264::FrameType
+H264::GetFrameType(const mozilla::MediaRawData* aSample)
+{
+  if (!AnnexB::IsAVCC(aSample)) {
+    // We must have a valid AVCC frame with extradata.
+    return FrameType::INVALID;
+  }
+  MOZ_ASSERT(aSample->Data());
+
+  int nalLenSize = ((*aSample->mExtraData)[4] & 3) + 1;
+
+  ByteReader reader(aSample->Data(), aSample->Size());
+
+  while (reader.Remaining() >= nalLenSize) {
+    uint32_t nalLen;
+    switch (nalLenSize) {
+      case 1: nalLen = reader.ReadU8();  break;
+      case 2: nalLen = reader.ReadU16(); break;
+      case 3: nalLen = reader.ReadU24(); break;
+      case 4: nalLen = reader.ReadU32(); break;
+    }
+    if (!nalLen) {
+      continue;
+    }
+    const uint8_t* p = reader.Read(nalLen);
+    if (!p) {
+      return FrameType::INVALID;
+    }
+    if ((p[0] & 0x1f) == 5) {
+      // IDR NAL.
+      return FrameType::I_FRAME;
+    }
+  }
+
+  return FrameType::OTHER;
+}
+
 } // namespace mp4_demuxer
--- a/media/libstagefright/binding/include/mp4_demuxer/H264.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/H264.h
@@ -345,16 +345,27 @@ public:
   // 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);
 
   // 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);
 
+  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);
+
 private:
   static void vui_parameters(BitReader& aBr, SPSData& aDest);
   // Read HRD parameters, all data is ignored.
   static void hrd_parameters(BitReader& aBr);
 };
 
 } // namespace mp4_demuxer