LCOV - code coverage report
Current view: top level - media/libstagefright/binding - Box.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 83 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 7 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim:set ts=2 sw=2 sts=2 et cindent: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "mp4_demuxer/Box.h"
       8             : #include "mp4_demuxer/Stream.h"
       9             : #include "mozilla/EndianUtils.h"
      10             : #include "mozilla/Unused.h"
      11             : #include <algorithm>
      12             : 
      13             : using namespace mozilla;
      14             : 
      15             : namespace mp4_demuxer {
      16             : 
      17             : // Limit reads to 32MiB max.
      18             : // static
      19             : const uint64_t Box::kMAX_BOX_READ = 32 * 1024 * 1024;
      20             : 
      21             : // Returns the offset from the start of the body of a box of type |aType|
      22             : // to the start of its first child.
      23             : static uint32_t
      24           0 : BoxOffset(AtomType aType)
      25             : {
      26           0 :   const uint32_t FULLBOX_OFFSET = 4;
      27             : 
      28           0 :   if (aType == AtomType("mp4a") || aType == AtomType("enca")) {
      29             :     // AudioSampleEntry; ISO 14496-12, section 8.16
      30           0 :     return 28;
      31           0 :   } else if (aType == AtomType("mp4v") || aType == AtomType("encv")) {
      32             :     // VideoSampleEntry; ISO 14496-12, section 8.16
      33           0 :     return 78;
      34           0 :   } else if (aType == AtomType("stsd")) {
      35             :     // SampleDescriptionBox; ISO 14496-12, section 8.16
      36             :     // This is a FullBox, and contains a |count| member before its child
      37             :     // boxes.
      38           0 :     return FULLBOX_OFFSET + 4;
      39             :   }
      40             : 
      41           0 :   return 0;
      42             : }
      43             : 
      44           0 : Box::Box(BoxContext* aContext, uint64_t aOffset, const Box* aParent)
      45           0 :   : mContext(aContext), mParent(aParent)
      46             : {
      47             :   uint8_t header[8];
      48             : 
      49           0 :   if (aOffset > INT64_MAX - sizeof(header)) {
      50           0 :     return;
      51             :   }
      52             : 
      53           0 :   MediaByteRange headerRange(aOffset, aOffset + sizeof(header));
      54           0 :   if (mParent && !mParent->mRange.Contains(headerRange)) {
      55           0 :     return;
      56             :   }
      57             : 
      58             :   const MediaByteRange* byteRange;
      59           0 :   for (int i = 0; ; i++) {
      60           0 :     if (i == mContext->mByteRanges.Length()) {
      61           0 :       return;
      62             :     }
      63             : 
      64           0 :     byteRange = static_cast<const MediaByteRange*>(&mContext->mByteRanges[i]);
      65           0 :     if (byteRange->Contains(headerRange)) {
      66           0 :       break;
      67             :     }
      68             :   }
      69             : 
      70             :   size_t bytes;
      71           0 :   if (!mContext->mSource->CachedReadAt(aOffset, header, sizeof(header),
      72           0 :                                        &bytes) ||
      73           0 :       bytes != sizeof(header)) {
      74           0 :     return;
      75             :   }
      76             : 
      77           0 :   uint64_t size = BigEndian::readUint32(header);
      78           0 :   if (size == 1) {
      79             :     uint8_t bigLength[8];
      80           0 :     if (aOffset > INT64_MAX - sizeof(header) - sizeof(bigLength)) {
      81           0 :       return;
      82             :     }
      83             :     MediaByteRange bigLengthRange(headerRange.mEnd,
      84           0 :                                   headerRange.mEnd + sizeof(bigLength));
      85           0 :     if ((mParent && !mParent->mRange.Contains(bigLengthRange)) ||
      86           0 :         !byteRange->Contains(bigLengthRange) ||
      87           0 :         !mContext->mSource->CachedReadAt(aOffset + sizeof(header), bigLength,
      88           0 :                                          sizeof(bigLength), &bytes) ||
      89           0 :         bytes != sizeof(bigLength)) {
      90           0 :       return;
      91             :     }
      92           0 :     size = BigEndian::readUint64(bigLength);
      93           0 :     mBodyOffset = bigLengthRange.mEnd;
      94           0 :   } else if (size == 0) {
      95             :     // box extends to end of file.
      96           0 :     size = mContext->mByteRanges.LastInterval().mEnd - aOffset;
      97           0 :     mBodyOffset = headerRange.mEnd;
      98             :   } else {
      99           0 :     mBodyOffset = headerRange.mEnd;
     100             :   }
     101             : 
     102           0 :   if (size > INT64_MAX) {
     103           0 :     return;
     104             :   }
     105           0 :   int64_t end = static_cast<int64_t>(aOffset) + static_cast<int64_t>(size);
     106           0 :   if (end < static_cast<int64_t>(aOffset)) {
     107             :     // Overflowed.
     108           0 :     return;
     109             :   }
     110             : 
     111           0 :   mType = BigEndian::readUint32(&header[4]);
     112           0 :   mChildOffset = mBodyOffset + BoxOffset(mType);
     113             : 
     114           0 :   MediaByteRange boxRange(aOffset, end);
     115           0 :   if (mChildOffset > boxRange.mEnd ||
     116           0 :       (mParent && !mParent->mRange.Contains(boxRange)) ||
     117           0 :       !byteRange->Contains(boxRange)) {
     118           0 :     return;
     119             :   }
     120             : 
     121           0 :   mRange = boxRange;
     122             : }
     123             : 
     124           0 : Box::Box()
     125           0 :   : mContext(nullptr)
     126           0 : {}
     127             : 
     128             : Box
     129           0 : Box::Next() const
     130             : {
     131           0 :   MOZ_ASSERT(IsAvailable());
     132           0 :   return Box(mContext, mRange.mEnd, mParent);
     133             : }
     134             : 
     135             : Box
     136           0 : Box::FirstChild() const
     137             : {
     138           0 :   MOZ_ASSERT(IsAvailable());
     139           0 :   if (mChildOffset == mRange.mEnd) {
     140           0 :     return Box();
     141             :   }
     142           0 :   return Box(mContext, mChildOffset, this);
     143             : }
     144             : 
     145             : nsTArray<uint8_t>
     146           0 : Box::Read()
     147             : {
     148           0 :   nsTArray<uint8_t> out;
     149           0 :   Unused << Read(&out, mRange);
     150           0 :   return out;
     151             : }
     152             : 
     153             : bool
     154           0 : Box::Read(nsTArray<uint8_t>* aDest, const MediaByteRange& aRange)
     155             : {
     156             :   int64_t length;
     157           0 :   if (!mContext->mSource->Length(&length)) {
     158             :     // The HTTP server didn't give us a length to work with.
     159             :     // Limit the read to kMAX_BOX_READ max.
     160           0 :     length = std::min(aRange.mEnd - mChildOffset, kMAX_BOX_READ);
     161             :   } else {
     162           0 :     length = aRange.mEnd - mChildOffset;
     163             :   }
     164           0 :   aDest->SetLength(length);
     165             :   size_t bytes;
     166           0 :   if (!mContext->mSource->CachedReadAt(mChildOffset, aDest->Elements(),
     167           0 :                                        aDest->Length(), &bytes) ||
     168           0 :       bytes != aDest->Length()) {
     169             :     // Byte ranges are being reported incorrectly
     170           0 :     NS_WARNING("Read failed in mp4_demuxer::Box::Read()");
     171           0 :     aDest->Clear();
     172           0 :     return false;
     173             :   }
     174           0 :   return true;
     175             : }
     176             : }

Generated by: LCOV version 1.13