LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/common_audio - wav_header.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 106 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 12 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
       3             :  *
       4             :  *  Use of this source code is governed by a BSD-style license
       5             :  *  that can be found in the LICENSE file in the root of the source
       6             :  *  tree. An additional intellectual property rights grant can be found
       7             :  *  in the file PATENTS.  All contributing project authors may
       8             :  *  be found in the AUTHORS file in the root of the source tree.
       9             :  */
      10             : 
      11             : // Based on the WAV file format documentation at
      12             : // https://ccrma.stanford.edu/courses/422/projects/WaveFormat/ and
      13             : // http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html
      14             : 
      15             : #include "webrtc/common_audio/wav_header.h"
      16             : 
      17             : #include <algorithm>
      18             : #include <cstring>
      19             : #include <limits>
      20             : #include <string>
      21             : 
      22             : #include "webrtc/base/checks.h"
      23             : #include "webrtc/common_audio/include/audio_util.h"
      24             : 
      25             : namespace webrtc {
      26             : namespace {
      27             : 
      28             : struct ChunkHeader {
      29             :   uint32_t ID;
      30             :   uint32_t Size;
      31             : };
      32             : static_assert(sizeof(ChunkHeader) == 8, "ChunkHeader size");
      33             : 
      34             : // We can't nest this definition in WavHeader, because VS2013 gives an error
      35             : // on sizeof(WavHeader::fmt): "error C2070: 'unknown': illegal sizeof operand".
      36             : struct FmtSubchunk {
      37             :   ChunkHeader header;
      38             :   uint16_t AudioFormat;
      39             :   uint16_t NumChannels;
      40             :   uint32_t SampleRate;
      41             :   uint32_t ByteRate;
      42             :   uint16_t BlockAlign;
      43             :   uint16_t BitsPerSample;
      44             : };
      45             : static_assert(sizeof(FmtSubchunk) == 24, "FmtSubchunk size");
      46             : const uint32_t kFmtSubchunkSize = sizeof(FmtSubchunk) - sizeof(ChunkHeader);
      47             : 
      48             : struct WavHeader {
      49             :   struct {
      50             :     ChunkHeader header;
      51             :     uint32_t Format;
      52             :   } riff;
      53             :   FmtSubchunk fmt;
      54             :   struct {
      55             :     ChunkHeader header;
      56             :   } data;
      57             : };
      58             : static_assert(sizeof(WavHeader) == kWavHeaderSize, "no padding in header");
      59             : 
      60             : }  // namespace
      61             : 
      62           0 : bool CheckWavParameters(size_t num_channels,
      63             :                         int sample_rate,
      64             :                         WavFormat format,
      65             :                         size_t bytes_per_sample,
      66             :                         size_t num_samples) {
      67             :   // num_channels, sample_rate, and bytes_per_sample must be positive, must fit
      68             :   // in their respective fields, and their product must fit in the 32-bit
      69             :   // ByteRate field.
      70           0 :   if (num_channels == 0 || sample_rate <= 0 || bytes_per_sample == 0)
      71           0 :     return false;
      72           0 :   if (static_cast<uint64_t>(sample_rate) > std::numeric_limits<uint32_t>::max())
      73           0 :     return false;
      74           0 :   if (num_channels > std::numeric_limits<uint16_t>::max())
      75           0 :     return false;
      76           0 :   if (static_cast<uint64_t>(bytes_per_sample) * 8 >
      77           0 :       std::numeric_limits<uint16_t>::max())
      78           0 :     return false;
      79           0 :   if (static_cast<uint64_t>(sample_rate) * num_channels * bytes_per_sample >
      80           0 :       std::numeric_limits<uint32_t>::max())
      81           0 :     return false;
      82             : 
      83             :   // format and bytes_per_sample must agree.
      84           0 :   switch (format) {
      85             :     case kWavFormatPcm:
      86             :       // Other values may be OK, but for now we're conservative:
      87           0 :       if (bytes_per_sample != 1 && bytes_per_sample != 2)
      88           0 :         return false;
      89           0 :       break;
      90             :     case kWavFormatALaw:
      91             :     case kWavFormatMuLaw:
      92           0 :       if (bytes_per_sample != 1)
      93           0 :         return false;
      94           0 :       break;
      95             :     default:
      96           0 :       return false;
      97             :   }
      98             : 
      99             :   // The number of bytes in the file, not counting the first ChunkHeader, must
     100             :   // be less than 2^32; otherwise, the ChunkSize field overflows.
     101           0 :   const size_t header_size = kWavHeaderSize - sizeof(ChunkHeader);
     102             :   const size_t max_samples =
     103           0 :       (std::numeric_limits<uint32_t>::max() - header_size) / bytes_per_sample;
     104           0 :   if (num_samples > max_samples)
     105           0 :     return false;
     106             : 
     107             :   // Each channel must have the same number of samples.
     108           0 :   if (num_samples % num_channels != 0)
     109           0 :     return false;
     110             : 
     111           0 :   return true;
     112             : }
     113             : 
     114             : #ifdef WEBRTC_ARCH_LITTLE_ENDIAN
     115           0 : static inline void WriteLE16(uint16_t* f, uint16_t x) { *f = x; }
     116           0 : static inline void WriteLE32(uint32_t* f, uint32_t x) { *f = x; }
     117           0 : static inline void WriteFourCC(uint32_t* f, char a, char b, char c, char d) {
     118           0 :   *f = static_cast<uint32_t>(a)
     119           0 :       | static_cast<uint32_t>(b) << 8
     120           0 :       | static_cast<uint32_t>(c) << 16
     121           0 :       | static_cast<uint32_t>(d) << 24;
     122           0 : }
     123             : 
     124           0 : static inline uint16_t ReadLE16(uint16_t x) { return x; }
     125           0 : static inline uint32_t ReadLE32(uint32_t x) { return x; }
     126           0 : static inline std::string ReadFourCC(uint32_t x) {
     127           0 :   return std::string(reinterpret_cast<char*>(&x), 4);
     128             : }
     129             : #else
     130             : static inline void WriteLE16(uint16_t* f, uint16_t x) {
     131             :   *f = ((x << 8) & 0xff00)  | ( ( x >> 8) & 0x00ff);
     132             : }
     133             : 
     134             : static inline void WriteLE32(uint32_t* f, uint32_t x) {
     135             :     *f = ( (x & 0x000000ff) << 24 )
     136             :       | ((x & 0x0000ff00) << 8)
     137             :       | ((x & 0x00ff0000) >> 8)
     138             :       | ((x & 0xff000000) >> 24 );
     139             : }
     140             : 
     141             : static inline void WriteFourCC(uint32_t* f, char a, char b, char c, char d) {
     142             :     *f = (static_cast<uint32_t>(a) << 24 )
     143             :       |  (static_cast<uint32_t>(b) << 16)
     144             :       |  (static_cast<uint32_t>(c) << 8)
     145             :       |  (static_cast<uint32_t>(d) );
     146             : }
     147             : 
     148             : static inline uint16_t ReadLE16(uint16_t x) {
     149             :   return  (( x & 0x00ff) << 8 )| ((x & 0xff00)>>8);
     150             : }
     151             : 
     152             : static inline uint32_t ReadLE32(uint32_t x) {
     153             :   return   ( (x & 0x000000ff) << 24 )
     154             :          | ( (x & 0x0000ff00) << 8 )
     155             :          | ( (x & 0x00ff0000) >> 8)
     156             :          | ( (x & 0xff000000) >> 24 );
     157             : }
     158             : 
     159             : static inline std::string ReadFourCC(uint32_t x) {
     160             :   x = ReadLE32(x);
     161             :   return std::string(reinterpret_cast<char*>(&x), 4);
     162             : }
     163             : #endif
     164             : 
     165           0 : static inline uint32_t RiffChunkSize(size_t bytes_in_payload) {
     166             :   return static_cast<uint32_t>(
     167           0 :       bytes_in_payload + kWavHeaderSize - sizeof(ChunkHeader));
     168             : }
     169             : 
     170           0 : static inline uint32_t ByteRate(size_t num_channels, int sample_rate,
     171             :                                 size_t bytes_per_sample) {
     172           0 :   return static_cast<uint32_t>(num_channels * sample_rate * bytes_per_sample);
     173             : }
     174             : 
     175           0 : static inline uint16_t BlockAlign(size_t num_channels,
     176             :                                   size_t bytes_per_sample) {
     177           0 :   return static_cast<uint16_t>(num_channels * bytes_per_sample);
     178             : }
     179             : 
     180           0 : void WriteWavHeader(uint8_t* buf,
     181             :                     size_t num_channels,
     182             :                     int sample_rate,
     183             :                     WavFormat format,
     184             :                     size_t bytes_per_sample,
     185             :                     size_t num_samples) {
     186           0 :   RTC_CHECK(CheckWavParameters(num_channels, sample_rate, format,
     187           0 :                                bytes_per_sample, num_samples));
     188             : 
     189             :   WavHeader header;
     190           0 :   const size_t bytes_in_payload = bytes_per_sample * num_samples;
     191             : 
     192           0 :   WriteFourCC(&header.riff.header.ID, 'R', 'I', 'F', 'F');
     193           0 :   WriteLE32(&header.riff.header.Size, RiffChunkSize(bytes_in_payload));
     194           0 :   WriteFourCC(&header.riff.Format, 'W', 'A', 'V', 'E');
     195             : 
     196           0 :   WriteFourCC(&header.fmt.header.ID, 'f', 'm', 't', ' ');
     197           0 :   WriteLE32(&header.fmt.header.Size, kFmtSubchunkSize);
     198           0 :   WriteLE16(&header.fmt.AudioFormat, format);
     199           0 :   WriteLE16(&header.fmt.NumChannels, static_cast<uint16_t>(num_channels));
     200           0 :   WriteLE32(&header.fmt.SampleRate, sample_rate);
     201           0 :   WriteLE32(&header.fmt.ByteRate, ByteRate(num_channels, sample_rate,
     202           0 :                                            bytes_per_sample));
     203           0 :   WriteLE16(&header.fmt.BlockAlign, BlockAlign(num_channels, bytes_per_sample));
     204           0 :   WriteLE16(&header.fmt.BitsPerSample,
     205           0 :             static_cast<uint16_t>(8 * bytes_per_sample));
     206             : 
     207           0 :   WriteFourCC(&header.data.header.ID, 'd', 'a', 't', 'a');
     208           0 :   WriteLE32(&header.data.header.Size, static_cast<uint32_t>(bytes_in_payload));
     209             : 
     210             :   // Do an extra copy rather than writing everything to buf directly, since buf
     211             :   // might not be correctly aligned.
     212           0 :   memcpy(buf, &header, kWavHeaderSize);
     213           0 : }
     214             : 
     215           0 : bool ReadWavHeader(ReadableWav* readable,
     216             :                    size_t* num_channels,
     217             :                    int* sample_rate,
     218             :                    WavFormat* format,
     219             :                    size_t* bytes_per_sample,
     220             :                    size_t* num_samples) {
     221             :   WavHeader header;
     222           0 :   if (readable->Read(&header, kWavHeaderSize - sizeof(header.data)) !=
     223             :       kWavHeaderSize - sizeof(header.data))
     224           0 :     return false;
     225             : 
     226           0 :   const uint32_t fmt_size = ReadLE32(header.fmt.header.Size);
     227           0 :   if (fmt_size != kFmtSubchunkSize) {
     228             :     // There is an optional two-byte extension field permitted to be present
     229             :     // with PCM, but which must be zero.
     230             :     int16_t ext_size;
     231           0 :     if (kFmtSubchunkSize + sizeof(ext_size) != fmt_size)
     232           0 :       return false;
     233           0 :     if (readable->Read(&ext_size, sizeof(ext_size)) != sizeof(ext_size))
     234           0 :       return false;
     235           0 :     if (ext_size != 0)
     236           0 :       return false;
     237             :   }
     238           0 :   if (readable->Read(&header.data, sizeof(header.data)) != sizeof(header.data))
     239           0 :     return false;
     240             : 
     241             :   // Parse needed fields.
     242           0 :   *format = static_cast<WavFormat>(ReadLE16(header.fmt.AudioFormat));
     243           0 :   *num_channels = ReadLE16(header.fmt.NumChannels);
     244           0 :   *sample_rate = ReadLE32(header.fmt.SampleRate);
     245           0 :   *bytes_per_sample = ReadLE16(header.fmt.BitsPerSample) / 8;
     246           0 :   const size_t bytes_in_payload = ReadLE32(header.data.header.Size);
     247           0 :   if (*bytes_per_sample == 0)
     248           0 :     return false;
     249           0 :   *num_samples = bytes_in_payload / *bytes_per_sample;
     250             : 
     251             :   // Sanity check remaining fields.
     252           0 :   if (ReadFourCC(header.riff.header.ID) != "RIFF")
     253           0 :     return false;
     254           0 :   if (ReadFourCC(header.riff.Format) != "WAVE")
     255           0 :     return false;
     256           0 :   if (ReadFourCC(header.fmt.header.ID) != "fmt ")
     257           0 :     return false;
     258           0 :   if (ReadFourCC(header.data.header.ID) != "data")
     259           0 :     return false;
     260             : 
     261           0 :   if (ReadLE32(header.riff.header.Size) < RiffChunkSize(bytes_in_payload))
     262           0 :     return false;
     263           0 :   if (ReadLE32(header.fmt.ByteRate) !=
     264           0 :       ByteRate(*num_channels, *sample_rate, *bytes_per_sample))
     265           0 :     return false;
     266           0 :   if (ReadLE16(header.fmt.BlockAlign) !=
     267           0 :       BlockAlign(*num_channels, *bytes_per_sample))
     268           0 :     return false;
     269             : 
     270           0 :   return CheckWavParameters(*num_channels, *sample_rate, *format,
     271           0 :                             *bytes_per_sample, *num_samples);
     272             : }
     273             : 
     274             : 
     275             : }  // namespace webrtc

Generated by: LCOV version 1.13