LCOV - code coverage report
Current view: top level - dom/media/flac - FlacFrameParser.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 112 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: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       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 "FlacFrameParser.h"
       8             : #include "mp4_demuxer/ByteReader.h"
       9             : #include "nsTArray.h"
      10             : #include "OggCodecState.h"
      11             : #include "OpusParser.h"
      12             : #include "VideoUtils.h"
      13             : 
      14             : using mp4_demuxer::ByteReader;
      15             : 
      16             : namespace mozilla
      17             : {
      18             : 
      19             : #define OGG_FLAC_METADATA_TYPE_STREAMINFO 0x7F
      20             : #define FLAC_STREAMINFO_SIZE   34
      21             : 
      22             : #define BITMASK(x) ((1ULL << x)-1)
      23             : 
      24             : enum
      25             : {
      26             :   FLAC_METADATA_TYPE_STREAMINFO = 0,
      27             :   FLAC_METADATA_TYPE_PADDING,
      28             :   FLAC_METADATA_TYPE_APPLICATION,
      29             :   FLAC_METADATA_TYPE_SEEKTABLE,
      30             :   FLAC_METADATA_TYPE_VORBIS_COMMENT,
      31             :   FLAC_METADATA_TYPE_CUESHEET,
      32             :   FLAC_METADATA_TYPE_PICTURE,
      33             :   FLAC_METADATA_TYPE_INVALID = 127
      34             : };
      35             : 
      36           0 : FlacFrameParser::FlacFrameParser()
      37             :   : mMinBlockSize(0)
      38             :   , mMaxBlockSize(0)
      39             :   , mMinFrameSize(0)
      40             :   , mMaxFrameSize(0)
      41             :   , mNumFrames(0)
      42             :   , mFullMetadata(false)
      43           0 :   , mPacketCount(0)
      44             : {
      45           0 : }
      46             : 
      47           0 : FlacFrameParser::~FlacFrameParser()
      48             : {
      49           0 : }
      50             : 
      51             : uint32_t
      52           0 : FlacFrameParser::HeaderBlockLength(const uint8_t* aPacket) const
      53             : {
      54           0 :   uint32_t extra = 4;
      55           0 :   if (aPacket[0] == 'f') {
      56             :     // This must be the first block read, which contains the fLaC signature.
      57           0 :     aPacket += 4;
      58           0 :     extra += 4;
      59             :   }
      60           0 :   return (BigEndian::readUint32(aPacket) & BITMASK(24)) + extra;
      61             : }
      62             : 
      63             : bool
      64           0 : FlacFrameParser::DecodeHeaderBlock(const uint8_t* aPacket, size_t aLength)
      65             : {
      66           0 :   if (aLength < 4 || aPacket[0] == 0xff) {
      67             :     // Not a header block.
      68           0 :     return false;
      69             :   }
      70           0 :   ByteReader br(aPacket, aLength);
      71             : 
      72           0 :   mPacketCount++;
      73             : 
      74           0 :   if (aPacket[0] == 'f') {
      75           0 :     if (mPacketCount != 1 || memcmp(br.Read(4), "fLaC", 4) ||
      76           0 :         br.Remaining() != FLAC_STREAMINFO_SIZE + 4) {
      77           0 :       return false;
      78             :     }
      79           0 :     aPacket += 4;
      80           0 :     aLength -= 4;
      81             :   }
      82           0 :   uint8_t blockHeader = br.ReadU8();
      83             :   // blockType is a misnomer as it could indicate here either a packet type
      84             :   // should it points to the start of a Flac in Ogg metadata, or an actual
      85             :   // block type as per the flac specification.
      86           0 :   uint32_t blockType = blockHeader & 0x7f;
      87           0 :   bool lastBlock = blockHeader & 0x80;
      88             : 
      89           0 :   if (blockType == OGG_FLAC_METADATA_TYPE_STREAMINFO) {
      90           0 :     if (mPacketCount != 1 || memcmp(br.Read(4), "FLAC", 4) ||
      91           0 :         br.Remaining() != FLAC_STREAMINFO_SIZE + 12) {
      92           0 :       return false;
      93             :     }
      94           0 :     uint32_t major = br.ReadU8();
      95           0 :     if (major != 1) {
      96             :       // unsupported version;
      97           0 :       return false;
      98             :     }
      99           0 :     br.ReadU8(); // minor version
     100           0 :     mNumHeaders = Some(uint32_t(br.ReadU16()));
     101           0 :     br.Read(4); // fLaC
     102           0 :     blockType = br.ReadU8() & BITMASK(7);
     103             :     // First METADATA_BLOCK_STREAMINFO
     104           0 :     if (blockType != FLAC_METADATA_TYPE_STREAMINFO) {
     105             :       // First block must be a stream info.
     106           0 :       return false;
     107             :     }
     108             :   }
     109             : 
     110           0 :   uint32_t blockDataSize = br.ReadU24();
     111           0 :   const uint8_t* blockDataStart = br.Peek(blockDataSize);
     112           0 :   if (!blockDataStart) {
     113             :     // Incomplete block.
     114           0 :     return false;
     115             :   }
     116             : 
     117           0 :   switch (blockType) {
     118             :     case FLAC_METADATA_TYPE_STREAMINFO:
     119             :     {
     120           0 :       if (mPacketCount != 1 || blockDataSize != FLAC_STREAMINFO_SIZE) {
     121             :         // STREAMINFO must be the first metadata block found, and its size
     122             :         // is constant.
     123           0 :         return false;
     124             :       }
     125             : 
     126           0 :       mMinBlockSize = br.ReadU16();
     127           0 :       mMaxBlockSize = br.ReadU16();
     128           0 :       mMinFrameSize = br.ReadU24();
     129           0 :       mMaxFrameSize = br.ReadU24();
     130             : 
     131           0 :       uint64_t blob = br.ReadU64();
     132           0 :       uint32_t sampleRate = (blob >> 44) & BITMASK(20);
     133           0 :       if (!sampleRate) {
     134           0 :         return false;
     135             :       }
     136           0 :       uint32_t numChannels = ((blob >> 41) & BITMASK(3)) + 1;
     137           0 :       if (numChannels > FLAC_MAX_CHANNELS) {
     138           0 :         return false;
     139             :       }
     140           0 :       uint32_t bps = ((blob >> 36) & BITMASK(5)) + 1;
     141           0 :       if (bps > 24) {
     142           0 :         return false;
     143             :       }
     144           0 :       mNumFrames = blob & BITMASK(36);
     145             : 
     146           0 :       mInfo.mMimeType = "audio/flac";
     147           0 :       mInfo.mRate = sampleRate;
     148           0 :       mInfo.mChannels = numChannels;
     149           0 :       mInfo.mBitDepth = bps;
     150           0 :       mInfo.mCodecSpecificConfig->AppendElements(blockDataStart, blockDataSize);
     151           0 :       auto duration = FramesToTimeUnit(mNumFrames, sampleRate);
     152           0 :       mInfo.mDuration = duration.IsValid() ? duration : media::TimeUnit::Zero();
     153           0 :       mParser = new OpusParser;
     154           0 :       break;
     155             :     }
     156             :     case FLAC_METADATA_TYPE_VORBIS_COMMENT:
     157             :     {
     158           0 :       if (!mParser) {
     159             :         // We must have seen a valid streaminfo first.
     160           0 :         return false;
     161             :       }
     162           0 :       nsTArray<uint8_t> comments(blockDataSize + 8);
     163           0 :       comments.AppendElements("OpusTags", 8);
     164           0 :       comments.AppendElements(blockDataStart, blockDataSize);
     165           0 :       if (!mParser->DecodeTags(comments.Elements(), comments.Length())) {
     166           0 :         return false;
     167             :       }
     168           0 :       break;
     169             :     }
     170             :     default:
     171           0 :       break;
     172             :   }
     173             : 
     174           0 :   if (mNumHeaders && mPacketCount > mNumHeaders.ref() + 1) {
     175             :     // Received too many header block. assuming invalid.
     176           0 :     return false;
     177             :   }
     178             : 
     179           0 :   if (lastBlock || (mNumHeaders && mNumHeaders.ref() + 1 == mPacketCount)) {
     180           0 :     mFullMetadata = true;
     181             :   }
     182             : 
     183           0 :   return true;
     184             : }
     185             : 
     186             : int64_t
     187           0 : FlacFrameParser::BlockDuration(const uint8_t* aPacket, size_t aLength) const
     188             : {
     189           0 :   if (!mInfo.IsValid()) {
     190           0 :     return -1;
     191             :   }
     192           0 :   if (mMinBlockSize == mMaxBlockSize) {
     193             :     // block size is fixed, use this instead of looking at the frame header.
     194           0 :     return mMinBlockSize;
     195             :   }
     196             :   // TODO
     197           0 :   return 0;
     198             : }
     199             : 
     200             : bool
     201           0 : FlacFrameParser::IsHeaderBlock(const uint8_t* aPacket, size_t aLength) const
     202             : {
     203             :   // Ogg Flac header
     204             :   // The one-byte packet type 0x7F
     205             :   // The four-byte ASCII signature "FLAC", i.e. 0x46, 0x4C, 0x41, 0x43
     206             : 
     207             :   // Flac header:
     208             :   // "fLaC", the FLAC stream marker in ASCII, meaning byte 0 of the stream is 0x66, followed by 0x4C 0x61 0x43
     209             : 
     210             :   // If we detect either a ogg or plain flac header, then it must be valid.
     211           0 :   if (aLength < 4 || aPacket[0] == 0xff) {
     212             :     // A header is at least 4 bytes.
     213           0 :     return false;
     214             :   }
     215           0 :   if (aPacket[0] == 0x7f) {
     216             :     // Ogg packet
     217           0 :     ByteReader br(aPacket + 1, aLength - 1);
     218           0 :     const uint8_t* signature = br.Read(4);
     219           0 :     return signature && !memcmp(signature, "FLAC", 4);
     220             :   }
     221           0 :   ByteReader br(aPacket, aLength - 1);
     222           0 :   const uint8_t* signature = br.Read(4);
     223           0 :   if (signature && !memcmp(signature, "fLaC", 4)) {
     224             :     // Flac start header, must have STREAMINFO as first metadata block;
     225           0 :     if (!br.CanRead8()) {
     226           0 :       return false;
     227             :     }
     228           0 :     uint32_t blockType = br.ReadU8() & 0x7f;
     229           0 :     return blockType == FLAC_METADATA_TYPE_STREAMINFO;
     230             :   }
     231           0 :   char type = aPacket[0] & 0x7f;
     232           0 :   return type >= 1 && type <= 6;
     233             : }
     234             : 
     235             : MetadataTags*
     236           0 : FlacFrameParser::GetTags() const
     237             : {
     238             :   MetadataTags* tags;
     239             : 
     240           0 :   tags = new MetadataTags;
     241           0 :   for (uint32_t i = 0; i < mParser->mTags.Length(); i++) {
     242           0 :     OggCodecState::AddVorbisComment(tags,
     243           0 :                                     mParser->mTags[i].Data(),
     244           0 :                                     mParser->mTags[i].Length());
     245             :   }
     246             : 
     247           0 :   return tags;
     248             : }
     249             : 
     250             : } // namespace mozilla

Generated by: LCOV version 1.13