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

          Line data    Source code
       1             : /* This Source Code Form is subject to the terms of the Mozilla Public
       2             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       3             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       4             : 
       5             : #include "mozilla/ArrayUtils.h"
       6             : #include "mozilla/EndianUtils.h"
       7             : #include "mp4_demuxer/AnnexB.h"
       8             : #include "mp4_demuxer/ByteReader.h"
       9             : #include "mp4_demuxer/ByteWriter.h"
      10             : #include "MediaData.h"
      11             : #include "nsAutoPtr.h"
      12             : 
      13             : using namespace mozilla;
      14             : 
      15             : namespace mp4_demuxer
      16             : {
      17             : 
      18             : static const uint8_t kAnnexBDelimiter[] = { 0, 0, 0, 1 };
      19             : 
      20             : bool
      21           0 : AnnexB::ConvertSampleToAnnexB(mozilla::MediaRawData* aSample, bool aAddSPS)
      22             : {
      23           0 :   MOZ_ASSERT(aSample);
      24             : 
      25           0 :   if (!IsAVCC(aSample)) {
      26           0 :     return true;
      27             :   }
      28           0 :   MOZ_ASSERT(aSample->Data());
      29             : 
      30           0 :   if (!ConvertSampleTo4BytesAVCC(aSample)) {
      31           0 :     return false;
      32             :   }
      33             : 
      34           0 :   if (aSample->Size() < 4) {
      35             :     // Nothing to do, it's corrupted anyway.
      36           0 :     return true;
      37             :   }
      38             : 
      39           0 :   ByteReader reader(aSample->Data(), aSample->Size());
      40             : 
      41           0 :   nsTArray<uint8_t> tmp;
      42           0 :   ByteWriter writer(tmp);
      43             : 
      44           0 :   while (reader.Remaining() >= 4) {
      45           0 :     uint32_t nalLen = reader.ReadU32();
      46           0 :     const uint8_t* p = reader.Read(nalLen);
      47             : 
      48           0 :     if (!writer.Write(kAnnexBDelimiter, ArrayLength(kAnnexBDelimiter))) {
      49           0 :       return false;
      50             :     }
      51           0 :     if (!p) {
      52           0 :       break;
      53             :     }
      54           0 :     if (!writer.Write(p, nalLen)) {
      55           0 :       return false;
      56             :     }
      57             :   }
      58             : 
      59           0 :   nsAutoPtr<MediaRawDataWriter> samplewriter(aSample->CreateWriter());
      60             : 
      61           0 :   if (!samplewriter->Replace(tmp.Elements(), tmp.Length())) {
      62           0 :     return false;
      63             :   }
      64             : 
      65             :   // Prepend the Annex B NAL with SPS and PPS tables to keyframes.
      66           0 :   if (aAddSPS && aSample->mKeyframe) {
      67             :     RefPtr<MediaByteBuffer> annexB =
      68           0 :       ConvertExtraDataToAnnexB(aSample->mExtraData);
      69           0 :     if (!samplewriter->Prepend(annexB->Elements(), annexB->Length())) {
      70           0 :       return false;
      71             :     }
      72             : 
      73             :     // Prepending the NAL with SPS/PPS will mess up the encryption subsample
      74             :     // offsets. So we need to account for the extra bytes by increasing
      75             :     // the length of the first clear data subsample. Otherwise decryption
      76             :     // will fail.
      77           0 :     if (aSample->mCrypto.mValid) {
      78           0 :       MOZ_ASSERT(samplewriter->mCrypto.mPlainSizes.Length() > 0);
      79           0 :       samplewriter->mCrypto.mPlainSizes[0] += annexB->Length();
      80             :     }
      81             :   }
      82             : 
      83           0 :   return true;
      84             : }
      85             : 
      86             : already_AddRefed<mozilla::MediaByteBuffer>
      87           0 : AnnexB::ConvertExtraDataToAnnexB(const mozilla::MediaByteBuffer* aExtraData)
      88             : {
      89             :   // AVCC 6 byte header looks like:
      90             :   //     +------+------+------+------+------+------+------+------+
      91             :   // [0] |   0  |   0  |   0  |   0  |   0  |   0  |   0  |   1  |
      92             :   //     +------+------+------+------+------+------+------+------+
      93             :   // [1] | profile                                               |
      94             :   //     +------+------+------+------+------+------+------+------+
      95             :   // [2] | compatiblity                                          |
      96             :   //     +------+------+------+------+------+------+------+------+
      97             :   // [3] | level                                                 |
      98             :   //     +------+------+------+------+------+------+------+------+
      99             :   // [4] | unused                                  | nalLenSiz-1 |
     100             :   //     +------+------+------+------+------+------+------+------+
     101             :   // [5] | unused             | numSps                           |
     102             :   //     +------+------+------+------+------+------+------+------+
     103             : 
     104           0 :   RefPtr<mozilla::MediaByteBuffer> annexB = new mozilla::MediaByteBuffer;
     105             : 
     106           0 :   ByteReader reader(*aExtraData);
     107           0 :   const uint8_t* ptr = reader.Read(5);
     108           0 :   if (ptr && ptr[0] == 1) {
     109             :     // Append SPS then PPS
     110           0 :     ConvertSPSOrPPS(reader, reader.ReadU8() & 31, annexB);
     111           0 :     ConvertSPSOrPPS(reader, reader.ReadU8(), annexB);
     112             : 
     113             :     // MP4Box adds extra bytes that we ignore. I don't know what they do.
     114             :   }
     115             : 
     116           0 :   return annexB.forget();
     117             : }
     118             : 
     119             : void
     120           0 : AnnexB::ConvertSPSOrPPS(ByteReader& aReader, uint8_t aCount,
     121             :                         mozilla::MediaByteBuffer* aAnnexB)
     122             : {
     123           0 :   for (int i = 0; i < aCount; i++) {
     124           0 :     uint16_t length = aReader.ReadU16();
     125             : 
     126           0 :     const uint8_t* ptr = aReader.Read(length);
     127           0 :     if (!ptr) {
     128           0 :       MOZ_ASSERT(false);
     129             :       return;
     130             :     }
     131           0 :     aAnnexB->AppendElements(kAnnexBDelimiter, ArrayLength(kAnnexBDelimiter));
     132           0 :     aAnnexB->AppendElements(ptr, length);
     133             :   }
     134           0 : }
     135             : 
     136             : static bool
     137           0 : FindStartCodeInternal(ByteReader& aBr) {
     138           0 :   size_t offset = aBr.Offset();
     139             : 
     140           0 :   for (uint32_t i = 0; i < aBr.Align() && aBr.Remaining() >= 3; i++) {
     141           0 :     if (aBr.PeekU24() == 0x000001) {
     142           0 :       return true;
     143             :     }
     144           0 :     aBr.Read(1);
     145             :   }
     146             : 
     147           0 :   while (aBr.Remaining() >= 6) {
     148           0 :     uint32_t x32 = aBr.PeekU32();
     149           0 :     if ((x32 - 0x01010101) & (~x32) & 0x80808080) {
     150           0 :       if ((x32 >> 8) == 0x000001) {
     151           0 :         return true;
     152             :       }
     153           0 :       if (x32 == 0x000001) {
     154           0 :         aBr.Read(1);
     155           0 :         return true;
     156             :       }
     157           0 :       if ((x32 & 0xff) == 0) {
     158           0 :         const uint8_t* p = aBr.Peek(1);
     159           0 :         if ((x32 & 0xff00) == 0 && p[4] == 1) {
     160           0 :           aBr.Read(2);
     161           0 :           return true;
     162             :         }
     163           0 :         if (p[4] == 0 && p[5] == 1) {
     164           0 :           aBr.Read(3);
     165           0 :           return true;
     166             :         }
     167             :       }
     168             :     }
     169           0 :     aBr.Read(4);
     170             :   }
     171             : 
     172           0 :   while (aBr.Remaining() >= 3) {
     173           0 :     if (aBr.PeekU24() == 0x000001) {
     174           0 :       return true;
     175             :     }
     176           0 :     aBr.Read(1);
     177             :   }
     178             : 
     179             :   // No start code were found; Go back to the beginning.
     180           0 :   aBr.Seek(offset);
     181           0 :   return false;
     182             : }
     183             : 
     184             : static bool
     185           0 : FindStartCode(ByteReader& aBr, size_t& aStartSize)
     186             : {
     187           0 :   if (!FindStartCodeInternal(aBr)) {
     188           0 :     aStartSize = 0;
     189           0 :     return false;
     190             :   }
     191             : 
     192           0 :   aStartSize = 3;
     193           0 :   if (aBr.Offset()) {
     194             :     // Check if it's 4-bytes start code
     195           0 :     aBr.Rewind(1);
     196           0 :     if (aBr.ReadU8() == 0) {
     197           0 :       aStartSize = 4;
     198             :     }
     199             :   }
     200           0 :   aBr.Read(3);
     201           0 :   return true;
     202             : }
     203             : 
     204             : static bool
     205           0 : ParseNALUnits(ByteWriter& aBw, ByteReader& aBr)
     206             : {
     207             :   size_t startSize;
     208             : 
     209           0 :   bool rv = FindStartCode(aBr, startSize);
     210           0 :   if (rv) {
     211           0 :     size_t startOffset = aBr.Offset();
     212           0 :     while (FindStartCode(aBr, startSize)) {
     213           0 :       size_t offset = aBr.Offset();
     214           0 :       size_t sizeNAL = offset - startOffset - startSize;
     215           0 :       aBr.Seek(startOffset);
     216           0 :       if (!aBw.WriteU32(sizeNAL)
     217           0 :           || !aBw.Write(aBr.Read(sizeNAL), sizeNAL)) {
     218           0 :         return false;
     219             :       }
     220           0 :       aBr.Read(startSize);
     221           0 :       startOffset = offset;
     222             :     }
     223             :   }
     224           0 :   size_t sizeNAL = aBr.Remaining();
     225           0 :   if (sizeNAL) {
     226           0 :     if (!aBw.WriteU32(sizeNAL)
     227           0 :         || !aBw.Write(aBr.Read(sizeNAL), sizeNAL)) {
     228           0 :       return false;
     229             :     }
     230             :   }
     231           0 :   return true;
     232             : }
     233             : 
     234             : bool
     235           0 : AnnexB::ConvertSampleToAVCC(mozilla::MediaRawData* aSample)
     236             : {
     237           0 :   if (IsAVCC(aSample)) {
     238           0 :     return ConvertSampleTo4BytesAVCC(aSample);
     239             :   }
     240           0 :   if (!IsAnnexB(aSample)) {
     241             :     // Not AnnexB, nothing to convert.
     242           0 :     return true;
     243             :   }
     244             : 
     245           0 :   nsTArray<uint8_t> nalu;
     246           0 :   ByteWriter writer(nalu);
     247           0 :   ByteReader reader(aSample->Data(), aSample->Size());
     248             : 
     249           0 :   if (!ParseNALUnits(writer, reader)) {
     250           0 :     return false;
     251             :   }
     252           0 :   nsAutoPtr<MediaRawDataWriter> samplewriter(aSample->CreateWriter());
     253           0 :   if (!samplewriter->Replace(nalu.Elements(), nalu.Length())) {
     254           0 :     return false;
     255             :   }
     256             :   // Create the AVCC header.
     257           0 :   RefPtr<mozilla::MediaByteBuffer> extradata = new mozilla::MediaByteBuffer;
     258             :   static const uint8_t kFakeExtraData[] = {
     259             :     1 /* version */,
     260             :     0x64 /* profile (High) */,
     261             :     0 /* profile compat (0) */,
     262             :     40 /* level (40) */,
     263             :     0xfc | 3 /* nal size - 1 */,
     264             :     0xe0 /* num SPS (0) */,
     265             :     0 /* num PPS (0) */
     266             :   };
     267           0 :   if (!extradata->AppendElements(kFakeExtraData, ArrayLength(kFakeExtraData))) {
     268           0 :     return false;
     269             :   }
     270           0 :   aSample->mExtraData = extradata;
     271           0 :   return true;
     272             : }
     273             : 
     274             : bool
     275           0 : AnnexB::ConvertSampleTo4BytesAVCC(mozilla::MediaRawData* aSample)
     276             : {
     277           0 :   MOZ_ASSERT(IsAVCC(aSample));
     278             : 
     279           0 :   int nalLenSize = ((*aSample->mExtraData)[4] & 3) + 1;
     280             : 
     281           0 :   if (nalLenSize == 4) {
     282           0 :     return true;
     283             :   }
     284           0 :   nsTArray<uint8_t> dest;
     285           0 :   ByteWriter writer(dest);
     286           0 :   ByteReader reader(aSample->Data(), aSample->Size());
     287           0 :   while (reader.Remaining() > nalLenSize) {
     288             :     uint32_t nalLen;
     289           0 :     switch (nalLenSize) {
     290           0 :       case 1: nalLen = reader.ReadU8();  break;
     291           0 :       case 2: nalLen = reader.ReadU16(); break;
     292           0 :       case 3: nalLen = reader.ReadU24(); break;
     293           0 :       case 4: nalLen = reader.ReadU32(); break;
     294             :     }
     295           0 :     const uint8_t* p = reader.Read(nalLen);
     296           0 :     if (!p) {
     297           0 :       return true;
     298             :     }
     299           0 :     if (!writer.WriteU32(nalLen)
     300           0 :         || !writer.Write(p, nalLen)) {
     301           0 :       return false;
     302             :     }
     303             :   }
     304           0 :   nsAutoPtr<MediaRawDataWriter> samplewriter(aSample->CreateWriter());
     305           0 :   return samplewriter->Replace(dest.Elements(), dest.Length());
     306             : }
     307             : 
     308             : bool
     309           0 : AnnexB::IsAVCC(const mozilla::MediaRawData* aSample)
     310             : {
     311           0 :   return aSample->Size() >= 3 && aSample->mExtraData &&
     312           0 :     aSample->mExtraData->Length() >= 7 && (*aSample->mExtraData)[0] == 1;
     313             : }
     314             : 
     315             : bool
     316           0 : AnnexB::IsAnnexB(const mozilla::MediaRawData* aSample)
     317             : {
     318           0 :   if (aSample->Size() < 4) {
     319           0 :     return false;
     320             :   }
     321           0 :   uint32_t header = mozilla::BigEndian::readUint32(aSample->Data());
     322           0 :   return header == 0x00000001 || (header >> 8) == 0x000001;
     323             : }
     324             : 
     325             : } // namespace mp4_demuxer

Generated by: LCOV version 1.13