Bug 1411525 - use BufferReader in flac/ogg parser. r?kinetik draft
authorAlfredo.Yang <ayang@mozilla.com>
Thu, 19 Oct 2017 10:16:32 +0800
changeset 686570 ebcaa3d35f7f895742f3ab16d7139dec136ef178
parent 685608 a124f4901430f6db74cfc7fe3b07957a1c691b40
child 686573 3c3be72f4c9800b8a07f75050ccd40eb59e1f5bc
push id86214
push userbmo:ayang@mozilla.com
push dateThu, 26 Oct 2017 01:24:08 +0000
reviewerskinetik
bugs1411525
milestone58.0a1
Bug 1411525 - use BufferReader in flac/ogg parser. r?kinetik MozReview-Commit-ID: 5chnxLnpqmY
dom/media/flac/FlacDemuxer.cpp
dom/media/flac/FlacFrameParser.cpp
dom/media/flac/FlacFrameParser.h
dom/media/ogg/OggCodecState.cpp
media/libstagefright/binding/include/mp4_demuxer/BufferReader.h
--- a/dom/media/flac/FlacDemuxer.cpp
+++ b/dom/media/flac/FlacDemuxer.cpp
@@ -417,27 +417,28 @@ public:
       mFirstFrame = mFrame;
     }
     return mFrame.IsValid();
   }
 
   // Convenience methods to external FlacFrameParser ones.
   bool IsHeaderBlock(const uint8_t* aPacket, size_t aLength) const
   {
-    return mParser.IsHeaderBlock(aPacket, aLength);
+    auto res = mParser.IsHeaderBlock(aPacket, aLength);
+    return res.isOk() ? res.unwrap() : false;
   }
 
   uint32_t HeaderBlockLength(const uint8_t* aPacket) const
   {
     return mParser.HeaderBlockLength(aPacket);
   }
 
   bool DecodeHeaderBlock(const uint8_t* aPacket, size_t aLength)
   {
-    return mParser.DecodeHeaderBlock(aPacket, aLength);
+    return mParser.DecodeHeaderBlock(aPacket, aLength).isOk();
   }
 
   bool HasFullMetadata() const { return mParser.HasFullMetadata(); }
 
   AudioInfo Info() const { return mParser.mInfo; }
 
   // Return a hash table with tag metadata.
   MetadataTags* GetTags() const { return mParser.GetTags(); }
--- a/dom/media/flac/FlacFrameParser.cpp
+++ b/dom/media/flac/FlacFrameParser.cpp
@@ -1,22 +1,23 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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 "FlacFrameParser.h"
-#include "mp4_demuxer/ByteReader.h"
 #include "nsTArray.h"
 #include "OggCodecState.h"
 #include "OpusParser.h"
 #include "VideoUtils.h"
+#include "mp4_demuxer/BufferReader.h"
+#include "mozilla/ResultExtensions.h"
 
-using mp4_demuxer::ByteReader;
+using mp4_demuxer::BufferReader;
 
 namespace mozilla
 {
 
 #define OGG_FLAC_METADATA_TYPE_STREAMINFO 0x7F
 #define FLAC_STREAMINFO_SIZE   34
 
 #define BITMASK(x) ((1ULL << x)-1)
@@ -55,94 +56,101 @@ FlacFrameParser::HeaderBlockLength(const
   if (aPacket[0] == 'f') {
     // This must be the first block read, which contains the fLaC signature.
     aPacket += 4;
     extra += 4;
   }
   return (BigEndian::readUint32(aPacket) & BITMASK(24)) + extra;
 }
 
-bool
+Result<Ok, nsresult>
 FlacFrameParser::DecodeHeaderBlock(const uint8_t* aPacket, size_t aLength)
 {
   if (aLength < 4 || aPacket[0] == 0xff) {
     // Not a header block.
-    return false;
+    return Err(NS_ERROR_FAILURE);
   }
-  ByteReader br(aPacket, aLength);
+  BufferReader br(aPacket, aLength);
 
   mPacketCount++;
 
   if (aPacket[0] == 'f') {
     if (mPacketCount != 1 || memcmp(br.Read(4), "fLaC", 4) ||
         br.Remaining() != FLAC_STREAMINFO_SIZE + 4) {
-      return false;
+      return Err(NS_ERROR_FAILURE);
     }
   }
-  uint8_t blockHeader = br.ReadU8();
+  uint8_t blockHeader;
+  MOZ_TRY_VAR(blockHeader, br.ReadU8());
   // blockType is a misnomer as it could indicate here either a packet type
   // should it points to the start of a Flac in Ogg metadata, or an actual
   // block type as per the flac specification.
   uint32_t blockType = blockHeader & 0x7f;
   bool lastBlock = blockHeader & 0x80;
 
   if (blockType == OGG_FLAC_METADATA_TYPE_STREAMINFO) {
     if (mPacketCount != 1 || memcmp(br.Read(4), "FLAC", 4) ||
         br.Remaining() != FLAC_STREAMINFO_SIZE + 12) {
-      return false;
+      return Err(NS_ERROR_FAILURE);
     }
-    uint32_t major = br.ReadU8();
+    uint32_t major;
+    MOZ_TRY_VAR(major, br.ReadU8());
     if (major != 1) {
       // unsupported version;
-      return false;
+      return Err(NS_ERROR_FAILURE);
     }
-    br.ReadU8(); // minor version
-    mNumHeaders = Some(uint32_t(br.ReadU16()));
+    MOZ_TRY(br.ReadU8()); // minor version
+    uint32_t header;
+    MOZ_TRY_VAR(header, br.ReadU16());
+    mNumHeaders = Some(header);
     br.Read(4); // fLaC
-    blockType = br.ReadU8() & BITMASK(7);
+    MOZ_TRY_VAR(blockType, br.ReadU8());
+    blockType &= BITMASK(7);
     // First METADATA_BLOCK_STREAMINFO
     if (blockType != FLAC_METADATA_TYPE_STREAMINFO) {
       // First block must be a stream info.
-      return false;
+      return Err(NS_ERROR_FAILURE);
     }
   }
 
-  uint32_t blockDataSize = br.ReadU24();
+  uint32_t blockDataSize;
+  MOZ_TRY_VAR(blockDataSize, br.ReadU24());
   const uint8_t* blockDataStart = br.Peek(blockDataSize);
   if (!blockDataStart) {
     // Incomplete block.
-    return false;
+    return Err(NS_ERROR_FAILURE);
   }
 
   switch (blockType) {
     case FLAC_METADATA_TYPE_STREAMINFO:
     {
       if (mPacketCount != 1 || blockDataSize != FLAC_STREAMINFO_SIZE) {
         // STREAMINFO must be the first metadata block found, and its size
         // is constant.
-        return false;
+        return Err(NS_ERROR_FAILURE);
       }
 
-      mMinBlockSize = br.ReadU16();
-      mMaxBlockSize = br.ReadU16();
-      mMinFrameSize = br.ReadU24();
-      mMaxFrameSize = br.ReadU24();
+      MOZ_TRY_VAR(mMinBlockSize, br.ReadU16());
+      MOZ_TRY_VAR(mMaxBlockSize, br.ReadU16());
+      MOZ_TRY_VAR(mMinFrameSize, br.ReadU24());
+      MOZ_TRY_VAR(mMaxFrameSize, br.ReadU24());
 
-      uint64_t blob = br.ReadU64();
+      uint64_t blob;
+      MOZ_TRY_VAR(blob, br.ReadU64());
       uint32_t sampleRate = (blob >> 44) & BITMASK(20);
       if (!sampleRate) {
-        return false;
+        return Err(NS_ERROR_FAILURE);
       }
       uint32_t numChannels = ((blob >> 41) & BITMASK(3)) + 1;
       if (numChannels > FLAC_MAX_CHANNELS) {
-        return false;
+        return Err(NS_ERROR_FAILURE);
       }
       uint32_t bps = ((blob >> 36) & BITMASK(5)) + 1;
       if (bps > 24) {
-        return false;
+        return Err(NS_ERROR_FAILURE);
       }
       mNumFrames = blob & BITMASK(36);
 
       mInfo.mMimeType = "audio/flac";
       mInfo.mRate = sampleRate;
       mInfo.mChannels = numChannels;
       mInfo.mBitDepth = bps;
       mInfo.mCodecSpecificConfig->AppendElements(blockDataStart, blockDataSize);
@@ -150,85 +158,84 @@ FlacFrameParser::DecodeHeaderBlock(const
       mInfo.mDuration = duration.IsValid() ? duration : media::TimeUnit::Zero();
       mParser = new OpusParser;
       break;
     }
     case FLAC_METADATA_TYPE_VORBIS_COMMENT:
     {
       if (!mParser) {
         // We must have seen a valid streaminfo first.
-        return false;
+        return Err(NS_ERROR_FAILURE);
       }
       nsTArray<uint8_t> comments(blockDataSize + 8);
       comments.AppendElements("OpusTags", 8);
       comments.AppendElements(blockDataStart, blockDataSize);
       if (!mParser->DecodeTags(comments.Elements(), comments.Length())) {
-        return false;
+        return Err(NS_ERROR_FAILURE);
       }
       break;
     }
     default:
       break;
   }
 
   if (mNumHeaders && mPacketCount > mNumHeaders.ref() + 1) {
     // Received too many header block. assuming invalid.
-    return false;
+    return Err(NS_ERROR_FAILURE);
   }
 
   if (lastBlock || (mNumHeaders && mNumHeaders.ref() + 1 == mPacketCount)) {
     mFullMetadata = true;
   }
 
-  return true;
+  return Ok();
 }
 
 int64_t
 FlacFrameParser::BlockDuration(const uint8_t* aPacket, size_t aLength) const
 {
   if (!mInfo.IsValid()) {
     return -1;
   }
   if (mMinBlockSize == mMaxBlockSize) {
     // block size is fixed, use this instead of looking at the frame header.
     return mMinBlockSize;
   }
   // TODO
   return 0;
 }
 
-bool
+Result<bool, nsresult>
 FlacFrameParser::IsHeaderBlock(const uint8_t* aPacket, size_t aLength) const
 {
   // Ogg Flac header
   // The one-byte packet type 0x7F
   // The four-byte ASCII signature "FLAC", i.e. 0x46, 0x4C, 0x41, 0x43
 
   // Flac header:
   // "fLaC", the FLAC stream marker in ASCII, meaning byte 0 of the stream is 0x66, followed by 0x4C 0x61 0x43
 
   // If we detect either a ogg or plain flac header, then it must be valid.
   if (aLength < 4 || aPacket[0] == 0xff) {
     // A header is at least 4 bytes.
     return false;
   }
   if (aPacket[0] == 0x7f) {
     // Ogg packet
-    ByteReader br(aPacket + 1, aLength - 1);
+    BufferReader br(aPacket + 1, aLength - 1);
     const uint8_t* signature = br.Read(4);
     return signature && !memcmp(signature, "FLAC", 4);
   }
-  ByteReader br(aPacket, aLength - 1);
+  BufferReader br(aPacket, aLength - 1);
   const uint8_t* signature = br.Read(4);
   if (signature && !memcmp(signature, "fLaC", 4)) {
     // Flac start header, must have STREAMINFO as first metadata block;
-    if (!br.CanRead8()) {
-      return false;
-    }
-    uint32_t blockType = br.ReadU8() & 0x7f;
+    uint32_t blockType;
+    MOZ_TRY_VAR(blockType, br.ReadU8());
+    blockType &= 0x7f;
     return blockType == FLAC_METADATA_TYPE_STREAMINFO;
   }
   char type = aPacket[0] & 0x7f;
   return type >= 1 && type <= 6;
 }
 
 MetadataTags*
 FlacFrameParser::GetTags() const
--- a/dom/media/flac/FlacFrameParser.h
+++ b/dom/media/flac/FlacFrameParser.h
@@ -3,16 +3,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/. */
 
 #ifndef FLAC_FRAME_PARSER_H_
 #define FLAC_FRAME_PARSER_H_
 
 #include "mozilla/Maybe.h"
+#include "mozilla/Result.h"
 #include "nsAutoPtr.h"
 #include "MediaDecoder.h" // For MetadataTags
 #include "MediaInfo.h"
 #include "MediaResource.h"
 
 namespace mozilla
 {
 
@@ -31,22 +32,22 @@ class OpusParser;
 // (https://xiph.org/flac/format.html#frame_header)
 
 class FlacFrameParser
 {
 public:
   FlacFrameParser();
   ~FlacFrameParser();
 
-  bool IsHeaderBlock(const uint8_t* aPacket, size_t aLength) const;
+  Result<bool, nsresult> IsHeaderBlock(const uint8_t* aPacket, size_t aLength) const;
   // Return the length of the block header (METADATA_BLOCK_HEADER+
   // METADATA_BLOCK_DATA), aPacket must point to at least 4
   // bytes and to a valid block header start (as determined by IsHeaderBlock).
   uint32_t HeaderBlockLength(const uint8_t* aPacket) const;
-  bool DecodeHeaderBlock(const uint8_t* aPacket, size_t aLength);
+  Result<Ok, nsresult> DecodeHeaderBlock(const uint8_t* aPacket, size_t aLength);
   bool HasFullMetadata() const { return mFullMetadata; }
   // Return the duration in frames found in the block. -1 if error
   // such as invalid packet.
   int64_t BlockDuration(const uint8_t* aPacket, size_t aLength) const;
 
   // Return a hash table with tag metadata.
   MetadataTags* GetTags() const;
 
--- a/dom/media/ogg/OggCodecState.cpp
+++ b/dom/media/ogg/OggCodecState.cpp
@@ -1312,17 +1312,17 @@ OpusState::PacketOutAsMediaRawData()
 FlacState::FlacState(ogg_page* aBosPage)
   : OggCodecState(aBosPage, true)
 {
 }
 
 bool
 FlacState::DecodeHeader(OggPacketPtr aPacket)
 {
-  if (!mParser.DecodeHeaderBlock(aPacket->packet, aPacket->bytes)) {
+  if (mParser.DecodeHeaderBlock(aPacket->packet, aPacket->bytes).isErr()) {
     return false;
   }
   if (mParser.HasFullMetadata()) {
     mDoneReadingHeaders = true;
   }
   return true;
 }
 
@@ -1344,17 +1344,18 @@ int64_t
 FlacState::PacketDuration(ogg_packet* aPacket)
 {
   return mParser.BlockDuration(aPacket->packet, aPacket->bytes);
 }
 
 bool
 FlacState::IsHeader(ogg_packet* aPacket)
 {
-  return mParser.IsHeaderBlock(aPacket->packet, aPacket->bytes);
+  auto res = mParser.IsHeaderBlock(aPacket->packet, aPacket->bytes);
+  return res.isOk() ? res.unwrap() : false;
 }
 
 nsresult
 FlacState::PageIn(ogg_page* aPage)
 {
   if (!mActive) {
     return NS_OK;
   }
--- a/media/libstagefright/binding/include/mp4_demuxer/BufferReader.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/BufferReader.h
@@ -48,110 +48,110 @@ public:
 
   size_t Offset() const
   {
     return mLength - mRemaining;
   }
 
   size_t Remaining() const { return mRemaining; }
 
-  Result<uint8_t, nsresult> ReadU8()
+  mozilla::Result<uint8_t, nsresult> ReadU8()
   {
     auto ptr = Read(1);
     if (!ptr) {
       NS_WARNING("Failed to read data");
       return mozilla::Err(NS_ERROR_FAILURE);
     }
     return *ptr;
   }
 
-  Result<uint16_t, nsresult> ReadU16()
+  mozilla::Result<uint16_t, nsresult> ReadU16()
   {
     auto ptr = Read(2);
     if (!ptr) {
       NS_WARNING("Failed to read data");
       return mozilla::Err(NS_ERROR_FAILURE);
     }
     return mozilla::BigEndian::readUint16(ptr);
   }
 
-  Result<int16_t, nsresult> ReadLE16()
+  mozilla::Result<int16_t, nsresult> ReadLE16()
   {
     auto ptr = Read(2);
     if (!ptr) {
       NS_WARNING("Failed to read data");
       return mozilla::Err(NS_ERROR_FAILURE);
     }
     return mozilla::LittleEndian::readInt16(ptr);
   }
 
-  Result<uint32_t, nsresult> ReadU24()
+  mozilla::Result<uint32_t, nsresult> ReadU24()
   {
     auto ptr = Read(3);
     if (!ptr) {
       NS_WARNING("Failed to read data");
       return mozilla::Err(NS_ERROR_FAILURE);
     }
     return ptr[0] << 16 | ptr[1] << 8 | ptr[2];
   }
 
-  Result<int32_t, nsresult> Read24()
+  mozilla::Result<int32_t, nsresult> Read24()
   {
     auto res = ReadU24();
     if (res.isErr()) {
       return mozilla::Err(NS_ERROR_FAILURE);
     }
     return (int32_t)res.unwrap();
   }
 
-  Result<int32_t, nsresult> ReadLE24()
+  mozilla::Result<int32_t, nsresult> ReadLE24()
   {
     auto ptr = Read(3);
     if (!ptr) {
       NS_WARNING("Failed to read data");
       return mozilla::Err(NS_ERROR_FAILURE);
     }
     int32_t result = int32_t(ptr[2] << 16 | ptr[1] << 8 | ptr[0]);
     if (result & 0x00800000u) {
       result -= 0x1000000;
     }
     return result;
   }
 
-  Result<uint32_t, nsresult> ReadU32()
+  mozilla::Result<uint32_t, nsresult> ReadU32()
   {
     auto ptr = Read(4);
     if (!ptr) {
       NS_WARNING("Failed to read data");
       return mozilla::Err(NS_ERROR_FAILURE);
     }
     return mozilla::BigEndian::readUint32(ptr);
   }
 
-  Result<int32_t, nsresult> Read32()
+  mozilla::Result<int32_t, nsresult> Read32()
   {
     auto ptr = Read(4);
     if (!ptr) {
       NS_WARNING("Failed to read data");
       return mozilla::Err(NS_ERROR_FAILURE);
     }
     return mozilla::BigEndian::readInt32(ptr);
   }
 
-  Result<uint64_t, nsresult> ReadU64()
+  mozilla::Result<uint64_t, nsresult> ReadU64()
   {
     auto ptr = Read(8);
     if (!ptr) {
       NS_WARNING("Failed to read data");
       return mozilla::Err(NS_ERROR_FAILURE);
     }
     return mozilla::BigEndian::readUint64(ptr);
   }
 
-  Result<int64_t, nsresult> Read64()
+  mozilla::Result<int64_t, nsresult> Read64()
   {
     auto ptr = Read(8);
     if (!ptr) {
       NS_WARNING("Failed to read data");
       return mozilla::Err(NS_ERROR_FAILURE);
     }
     return mozilla::BigEndian::readInt64(ptr);
   }