Bug 1412183 - use BufferReader instead of ByteReader in H264 parser. r=kinetik
authorAlfredo.Yang <ayang@mozilla.com>
Wed, 25 Oct 2017 15:26:45 +0800
changeset 389000 71bad9dae18b61365159407c4f1544df4dcd444d
parent 388999 f042748e5f838cda6cacac1b9387e0dd3003dc97
child 389001 cce51f29025fe0ad00e9359eec8270cc94be168c
push id32777
push userarchaeopteryx@coole-files.de
push dateMon, 30 Oct 2017 22:44:45 +0000
treeherdermozilla-central@dd0f265a1300 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskinetik
bugs1412183
milestone58.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1412183 - use BufferReader instead of ByteReader in H264 parser. r=kinetik MozReview-Commit-ID: KhwWj1Nr85E
media/libstagefright/binding/H264.cpp
media/libstagefright/binding/include/mp4_demuxer/BufferReader.h
--- a/media/libstagefright/binding/H264.cpp
+++ b/media/libstagefright/binding/H264.cpp
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * 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/. */
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/PodOperations.h"
 #include "mp4_demuxer/AnnexB.h"
 #include "mp4_demuxer/BitReader.h"
-#include "mp4_demuxer/ByteReader.h"
+#include "mp4_demuxer/BufferReader.h"
 #include "mp4_demuxer/ByteWriter.h"
 #include "mp4_demuxer/H264.h"
 #include <media/stagefright/foundation/ABitReader.h>
 #include <limits>
 #include <cmath>
 
 #define READSE(var, min, max)                                                  \
   {                                                                            \
@@ -272,100 +272,120 @@ public:
   explicit SPSNALIterator(const mozilla::MediaByteBuffer* aExtraData)
     : mExtraDataPtr(aExtraData->Elements())
     , mReader(aExtraData)
   {
     if (!mReader.Read(5)) {
       return;
     }
 
-    mNumSPS = mReader.ReadU8() & 0x1f;
+    auto res = mReader.ReadU8();
+    mNumSPS = res.isOk() ? res.unwrap() & 0x1f : 0;
     if (mNumSPS == 0) {
       return;
     }
     mValid = true;
   }
 
   SPSNALIterator& operator++()
   {
     if (mEOS || !mValid) {
       return *this;
     }
     if (--mNumSPS == 0) {
       mEOS = true;
     }
-    uint16_t length = mReader.ReadU16();
+    auto res = mReader.ReadU16();
+    uint16_t length = res.isOk() ? res.unwrap() : 0;
     if (length == 0 || !mReader.Read(length)) {
       mEOS = true;
     }
     return *this;
   }
 
   explicit operator bool() const
   {
     return mValid && !mEOS;
   }
 
   SPSNAL operator*() const
   {
     MOZ_ASSERT(bool(*this));
-    ByteReader reader(mExtraDataPtr + mReader.Offset(), mReader.Remaining());
-    uint16_t length = reader.ReadU16();
+    BufferReader reader(mExtraDataPtr + mReader.Offset(), mReader.Remaining());
+
+    auto res = reader.ReadU16();
+    uint16_t length = res.isOk() ? res.unwrap() : 0;
     const uint8_t* ptr = reader.Read(length);
-    if (!ptr) {
+    if (!ptr || !length) {
       return SPSNAL();
     }
     return SPSNAL(ptr, length);
   }
 
 private:
   const uint8_t* mExtraDataPtr;
-  ByteReader mReader;
+  BufferReader mReader;
   bool mValid = false;
   bool mEOS = false;
   uint8_t mNumSPS = 0;
 };
 
 /* static */ already_AddRefed<mozilla::MediaByteBuffer>
 H264::DecodeNALUnit(const uint8_t* aNAL, size_t aLength)
 {
   MOZ_ASSERT(aNAL);
 
   if (aLength < 4) {
     return nullptr;
   }
 
   RefPtr<mozilla::MediaByteBuffer> rbsp = new mozilla::MediaByteBuffer;
-  ByteReader reader(aNAL, aLength);
-  uint8_t nal_unit_type = reader.ReadU8() & 0x1f;
+  BufferReader reader(aNAL, aLength);
+  auto res = reader.ReadU8();
+  if (res.isErr()) {
+    return nullptr;
+  }
+  uint8_t nal_unit_type = res.unwrap() & 0x1f;
   uint32_t nalUnitHeaderBytes = 1;
   if (nal_unit_type == H264_NAL_PREFIX ||
       nal_unit_type == H264_NAL_SLICE_EXT ||
       nal_unit_type == H264_NAL_SLICE_EXT_DVC) {
     bool svc_extension_flag = false;
     bool avc_3d_extension_flag = false;
     if (nal_unit_type != H264_NAL_SLICE_EXT_DVC) {
-      svc_extension_flag = reader.PeekU8() & 0x80;
+      res = reader.PeekU8();
+      if (res.isErr()) {
+        return nullptr;
+      }
+      svc_extension_flag = res.unwrap() & 0x80;
     } else {
-      avc_3d_extension_flag = reader.PeekU8() & 0x80;
+      res = reader.PeekU8();
+      if (res.isErr()) {
+        return nullptr;
+      }
+      avc_3d_extension_flag = res.unwrap() & 0x80;
     }
     if (svc_extension_flag) {
       nalUnitHeaderBytes += 3;
     } else if (avc_3d_extension_flag) {
       nalUnitHeaderBytes += 2;
     } else {
       nalUnitHeaderBytes += 3;
     }
   }
   if (!reader.Read(nalUnitHeaderBytes - 1)) {
     return nullptr;
   }
   uint32_t lastbytes = 0xffff;
   while (reader.Remaining()) {
-    uint8_t byte = reader.ReadU8();
+    auto res = reader.ReadU8();
+    if (res.isErr()) {
+      return nullptr;
+    }
+    uint8_t byte = res.unwrap();
     if ((lastbytes & 0xffff) == 0 && byte == 0x03) {
       // reset last two bytes, to detect the 0x000003 sequence again.
       lastbytes = 0xffff;
     } else {
       rbsp->AppendElement(byte);
     }
     lastbytes = (lastbytes << 8) | byte;
   }
@@ -783,25 +803,25 @@ H264::GetFrameType(const mozilla::MediaR
   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());
+  BufferReader reader(aSample->Data(), aSample->Size());
 
   while (reader.Remaining() >= nalLenSize) {
-    uint32_t nalLen;
+    uint32_t nalLen = 0;
     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;
+      case 1: Unused << reader.ReadU8().map([&] (uint8_t x) mutable { return nalLen = x; }); break;
+      case 2: Unused << reader.ReadU16().map([&] (uint16_t x) mutable { return nalLen = x; }); break;
+      case 3: Unused << reader.ReadU24().map([&] (uint32_t x) mutable { return nalLen = x; }); break;
+      case 4: Unused << reader.ReadU32().map([&] (uint32_t x) mutable { return nalLen = x; }); break;
     }
     if (!nalLen) {
       continue;
     }
     const uint8_t* p = reader.Read(nalLen);
     if (!p) {
       return FrameType::INVALID;
     }
@@ -846,31 +866,31 @@ H264::ExtractExtraData(const mozilla::Me
     if (aSample->mCrypto.mPlainSizes.Length() == 0 ||
         aSample->mCrypto.mPlainSizes[0] > sampleSize) {
       // This is invalid content.
       return nullptr;
     }
     sampleSize = aSample->mCrypto.mPlainSizes[0];
   }
 
-  ByteReader reader(aSample->Data(), sampleSize);
+  BufferReader reader(aSample->Data(), sampleSize);
 
   nsTArray<SPSData> SPSTable;
   // If we encounter SPS with the same id but different content, we will stop
   // attempting to detect duplicates.
   bool checkDuplicate = true;
 
   // Find SPS and PPS NALUs in AVCC data
   while (reader.Remaining() > nalLenSize) {
-    uint32_t nalLen;
+    uint32_t nalLen = 0;
     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;
+      case 1: Unused << reader.ReadU8().map([&] (uint8_t x) mutable { return nalLen = x; }); break;
+      case 2: Unused << reader.ReadU16().map([&] (uint16_t x) mutable { return nalLen = x; }); break;
+      case 3: Unused << reader.ReadU24().map([&] (uint32_t x) mutable { return nalLen = x; }); break;
+      case 4: Unused << reader.ReadU32().map([&] (uint32_t x) mutable { return nalLen = x; }); break;
     }
     const uint8_t* p = reader.Read(nalLen);
     if (!p) {
       return extradata.forget();
     }
     uint8_t nalType = *p & 0x1f;
 
     if (nalType == H264_NAL_SPS) {
@@ -941,22 +961,23 @@ H264::HasSPS(const mozilla::MediaByteBuf
 
 /* static */ uint8_t
 H264::NumSPS(const mozilla::MediaByteBuffer* aExtraData)
 {
   if (!aExtraData) {
     return 0;
   }
 
-  ByteReader reader(aExtraData);
+  BufferReader reader(aExtraData);
   const uint8_t* ptr = reader.Read(5);
-  if (!ptr || !reader.CanRead8()) {
+  auto res = reader.ReadU8();
+  if (!ptr || res.isErr()) {
     return 0;
   }
-  return reader.ReadU8() & 0x1f;
+  return res.unwrap() & 0x1f;
 }
 
 /* static */ bool
 H264::CompareExtraData(const mozilla::MediaByteBuffer* aExtraData1,
                        const mozilla::MediaByteBuffer* aExtraData2)
 {
   if (aExtraData1 == aExtraData2) {
     return true;
@@ -977,57 +998,51 @@ H264::CompareExtraData(const mozilla::Me
       return false;
     }
     ++it1;
     ++it2;
   }
   return true;
 }
 
-static inline bool
-ReadSEIInt(ByteReader& aBr, uint32_t& aOutput)
+static inline Result<Ok, nsresult>
+ReadSEIInt(BufferReader& aBr, uint32_t& aOutput)
 {
   uint8_t tmpByte;
 
   aOutput = 0;
-  if (!aBr.CanRead8()) {
-    return false;
-  }
-  tmpByte = aBr.ReadU8();
+  MOZ_TRY_VAR(tmpByte, aBr.ReadU8());
   while (tmpByte == 0xFF) {
     aOutput += 255;
-    if (!aBr.CanRead8()) {
-      return false;
-    }
-    tmpByte = aBr.ReadU8();
+    MOZ_TRY_VAR(tmpByte, aBr.ReadU8());
   }
   aOutput += tmpByte;   // this is the last byte
-  return true;
+  return Ok();
 }
 
 /* static */ bool
 H264::DecodeRecoverySEI(const mozilla::MediaByteBuffer* aSEI,
                         SEIRecoveryData& aDest)
 {
   if (!aSEI) {
     return false;
   }
   // sei_rbsp() as per 7.3.2.3 Supplemental enhancement information RBSP syntax
-  ByteReader br(aSEI);
+  BufferReader br(aSEI);
 
   do {
     // sei_message() as per
     // 7.3.2.3.1 Supplemental enhancement information message syntax
     uint32_t payloadType = 0;
-    if (!ReadSEIInt(br, payloadType)) {
+    if (ReadSEIInt(br, payloadType).isErr()) {
       return false;
     }
 
     uint32_t payloadSize = 0;
-    if (!ReadSEIInt(br, payloadSize)) {
+    if (ReadSEIInt(br, payloadSize).isErr()) {
       return false;
     }
 
     // sei_payload(payloadType, payloadSize) as per
     // D.1 SEI payload syntax.
     const uint8_t* p = br.Read(payloadSize);
     if (!p) {
       return false;
@@ -1040,17 +1055,17 @@ H264::DecodeRecoverySEI(const mozilla::M
       // D.1.7 Recovery point SEI message syntax
       BitReader br(p, payloadSize * 8);
       aDest.recovery_frame_cnt = br.ReadUE();
       aDest.exact_match_flag = br.ReadBit();
       aDest.broken_link_flag = br.ReadBit();
       aDest.changing_slice_group_idc = br.ReadBits(2);
       return true;
     }
-  } while(br.CanRead8() && br.PeekU8() != 0x80); // more_rbsp_data() msg[offset] != 0x80
+  } while(br.PeekU8().isOk() && br.PeekU8().unwrap() != 0x80); // more_rbsp_data() msg[offset] != 0x80
   // ignore the trailing bits rbsp_trailing_bits();
   return false;
 }
 
 #undef READUE
 #undef READSE
 
 } // namespace mp4_demuxer
--- a/media/libstagefright/binding/include/mp4_demuxer/BufferReader.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/BufferReader.h
@@ -173,22 +173,22 @@ public:
     if (aCount < rewind) {
       rewind = aCount;
     }
     mRemaining += rewind;
     mPtr -= rewind;
     return mPtr;
   }
 
-  uint8_t PeekU8() const
+  mozilla::Result<uint8_t, nsresult> PeekU8() const
   {
     auto ptr = Peek(1);
     if (!ptr) {
       NS_WARNING("Failed to peek data");
-      return 0;
+      return mozilla::Err(NS_ERROR_FAILURE);
     }
     return *ptr;
   }
 
   mozilla::Result<uint16_t, nsresult> PeekU16() const
   {
     auto ptr = Peek(2);
     if (!ptr) {