Home | History | Annotate | Download | only in webm
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "media/formats/webm/tracks_builder.h"
      6 
      7 #include "base/logging.h"
      8 #include "media/formats/webm/webm_constants.h"
      9 
     10 namespace media {
     11 
     12 // Returns size of an integer, formatted using Matroska serialization.
     13 static int GetUIntMkvSize(uint64 value) {
     14   if (value < 0x07FULL)
     15     return 1;
     16   if (value < 0x03FFFULL)
     17     return 2;
     18   if (value < 0x01FFFFFULL)
     19     return 3;
     20   if (value < 0x0FFFFFFFULL)
     21     return 4;
     22   if (value < 0x07FFFFFFFFULL)
     23     return 5;
     24   if (value < 0x03FFFFFFFFFFULL)
     25     return 6;
     26   if (value < 0x01FFFFFFFFFFFFULL)
     27     return 7;
     28   return 8;
     29 }
     30 
     31 // Returns the minimium size required to serialize an integer value.
     32 static int GetUIntSize(uint64 value) {
     33   if (value < 0x0100ULL)
     34     return 1;
     35   if (value < 0x010000ULL)
     36     return 2;
     37   if (value < 0x01000000ULL)
     38     return 3;
     39   if (value < 0x0100000000ULL)
     40     return 4;
     41   if (value < 0x010000000000ULL)
     42     return 5;
     43   if (value < 0x01000000000000ULL)
     44     return 6;
     45   if (value < 0x0100000000000000ULL)
     46     return 7;
     47   return 8;
     48 }
     49 
     50 static int MasterElementSize(int element_id, int payload_size) {
     51   return GetUIntSize(element_id) + GetUIntMkvSize(payload_size) + payload_size;
     52 }
     53 
     54 static int UIntElementSize(int element_id, uint64 value) {
     55   return GetUIntSize(element_id) + 1 + GetUIntSize(value);
     56 }
     57 
     58 static int DoubleElementSize(int element_id) {
     59   return GetUIntSize(element_id) + 1 + 8;
     60 }
     61 
     62 static int StringElementSize(int element_id, const std::string& value) {
     63  return GetUIntSize(element_id) +
     64         GetUIntMkvSize(value.length()) +
     65         value.length();
     66 }
     67 
     68 static void SerializeInt(uint8** buf_ptr, int* buf_size_ptr,
     69                          int64 value, int size) {
     70   uint8*& buf = *buf_ptr;
     71   int& buf_size = *buf_size_ptr;
     72 
     73   for (int idx = 1; idx <= size; ++idx) {
     74     *buf++ = static_cast<uint8>(value >> ((size - idx) * 8));
     75     --buf_size;
     76   }
     77 }
     78 
     79 static void SerializeDouble(uint8** buf_ptr, int* buf_size_ptr,
     80                             double value) {
     81   // Use a union to convert |value| to native endian integer bit pattern.
     82   union {
     83     double src;
     84     int64 dst;
     85   } tmp;
     86   tmp.src = value;
     87 
     88   // Write the bytes from native endian |tmp.dst| to big-endian form in |buf|.
     89   SerializeInt(buf_ptr, buf_size_ptr, tmp.dst, 8);
     90 }
     91 
     92 static void WriteElementId(uint8** buf, int* buf_size, int element_id) {
     93   SerializeInt(buf, buf_size, element_id, GetUIntSize(element_id));
     94 }
     95 
     96 static void WriteUInt(uint8** buf, int* buf_size, uint64 value) {
     97   const int size = GetUIntMkvSize(value);
     98   value |= (1ULL << (size * 7));  // Matroska formatting
     99   SerializeInt(buf, buf_size, value, size);
    100 }
    101 
    102 static void WriteMasterElement(uint8** buf, int* buf_size,
    103                                int element_id, int payload_size) {
    104   WriteElementId(buf, buf_size, element_id);
    105   WriteUInt(buf, buf_size, payload_size);
    106 }
    107 
    108 static void WriteUIntElement(uint8** buf,
    109                              int* buf_size,
    110                              int element_id,
    111                              uint64 value) {
    112   WriteElementId(buf, buf_size, element_id);
    113 
    114   const int size = GetUIntSize(value);
    115   WriteUInt(buf, buf_size, size);
    116 
    117   SerializeInt(buf, buf_size, value, size);
    118 }
    119 
    120 static void WriteDoubleElement(uint8** buf, int* buf_size,
    121                                int element_id, double value) {
    122   WriteElementId(buf, buf_size, element_id);
    123   WriteUInt(buf, buf_size, 8);
    124   SerializeDouble(buf, buf_size, value);
    125 }
    126 
    127 static void WriteStringElement(uint8** buf_ptr, int* buf_size_ptr,
    128                                int element_id, const std::string& value) {
    129   uint8*& buf = *buf_ptr;
    130   int& buf_size = *buf_size_ptr;
    131 
    132   WriteElementId(&buf, &buf_size, element_id);
    133 
    134   const uint64 size = value.length();
    135   WriteUInt(&buf, &buf_size, size);
    136 
    137   memcpy(buf, value.data(), size);
    138   buf += size;
    139   buf_size -= size;
    140 }
    141 
    142 TracksBuilder::TracksBuilder(bool allow_invalid_values)
    143     : allow_invalid_values_(allow_invalid_values) {}
    144 TracksBuilder::TracksBuilder()
    145     : allow_invalid_values_(false) {}
    146 TracksBuilder::~TracksBuilder() {}
    147 
    148 void TracksBuilder::AddVideoTrack(int track_num,
    149                                   uint64 track_uid,
    150                                   const std::string& codec_id,
    151                                   const std::string& name,
    152                                   const std::string& language,
    153                                   int default_duration,
    154                                   int video_pixel_width,
    155                                   int video_pixel_height) {
    156   AddTrackInternal(track_num, kWebMTrackTypeVideo, track_uid, codec_id, name,
    157                    language, default_duration, video_pixel_width,
    158                    video_pixel_height, -1, -1);
    159 }
    160 
    161 void TracksBuilder::AddAudioTrack(int track_num,
    162                                   uint64 track_uid,
    163                                   const std::string& codec_id,
    164                                   const std::string& name,
    165                                   const std::string& language,
    166                                   int default_duration,
    167                                   int audio_channels,
    168                                   double audio_sampling_frequency) {
    169   AddTrackInternal(track_num, kWebMTrackTypeAudio, track_uid, codec_id, name,
    170                    language, default_duration, -1, -1, audio_channels,
    171                    audio_sampling_frequency);
    172 }
    173 
    174 void TracksBuilder::AddTextTrack(int track_num,
    175                                  uint64 track_uid,
    176                                  const std::string& codec_id,
    177                                  const std::string& name,
    178                                  const std::string& language) {
    179   AddTrackInternal(track_num, kWebMTrackTypeSubtitlesOrCaptions, track_uid,
    180                    codec_id, name, language, -1, -1, -1, -1, -1);
    181 }
    182 
    183 std::vector<uint8> TracksBuilder::Finish() {
    184   // Allocate the storage
    185   std::vector<uint8> buffer;
    186   buffer.resize(GetTracksSize());
    187 
    188   // Populate the storage with a tracks header
    189   WriteTracks(&buffer[0], buffer.size());
    190 
    191   return buffer;
    192 }
    193 
    194 void TracksBuilder::AddTrackInternal(int track_num,
    195                                      int track_type,
    196                                      uint64 track_uid,
    197                                      const std::string& codec_id,
    198                                      const std::string& name,
    199                                      const std::string& language,
    200                                      int default_duration,
    201                                      int video_pixel_width,
    202                                      int video_pixel_height,
    203                                      int audio_channels,
    204                                      double audio_sampling_frequency) {
    205   tracks_.push_back(Track(track_num, track_type, track_uid, codec_id, name,
    206                           language, default_duration, video_pixel_width,
    207                           video_pixel_height, audio_channels,
    208                           audio_sampling_frequency, allow_invalid_values_));
    209 }
    210 
    211 int TracksBuilder::GetTracksSize() const {
    212   return MasterElementSize(kWebMIdTracks, GetTracksPayloadSize());
    213 }
    214 
    215 int TracksBuilder::GetTracksPayloadSize() const {
    216   int payload_size = 0;
    217 
    218   for (TrackList::const_iterator itr = tracks_.begin();
    219        itr != tracks_.end(); ++itr) {
    220     payload_size += itr->GetSize();
    221   }
    222 
    223   return payload_size;
    224 }
    225 
    226 void TracksBuilder::WriteTracks(uint8* buf, int buf_size) const {
    227   WriteMasterElement(&buf, &buf_size, kWebMIdTracks, GetTracksPayloadSize());
    228 
    229   for (TrackList::const_iterator itr = tracks_.begin();
    230        itr != tracks_.end(); ++itr) {
    231     itr->Write(&buf, &buf_size);
    232   }
    233 }
    234 
    235 TracksBuilder::Track::Track(int track_num,
    236                             int track_type,
    237                             uint64 track_uid,
    238                             const std::string& codec_id,
    239                             const std::string& name,
    240                             const std::string& language,
    241                             int default_duration,
    242                             int video_pixel_width,
    243                             int video_pixel_height,
    244                             int audio_channels,
    245                             double audio_sampling_frequency,
    246                             bool allow_invalid_values)
    247     : track_num_(track_num),
    248       track_type_(track_type),
    249       track_uid_(track_uid),
    250       codec_id_(codec_id),
    251       name_(name),
    252       language_(language),
    253       default_duration_(default_duration),
    254       video_pixel_width_(video_pixel_width),
    255       video_pixel_height_(video_pixel_height),
    256       audio_channels_(audio_channels),
    257       audio_sampling_frequency_(audio_sampling_frequency) {
    258   if (!allow_invalid_values) {
    259     CHECK_GT(track_num_, 0);
    260     CHECK_GT(track_type_, 0);
    261     CHECK_LT(track_type_, 255);
    262     CHECK_GT(track_uid_, 0);
    263     if (track_type != kWebMTrackTypeVideo &&
    264         track_type != kWebMTrackTypeAudio) {
    265       CHECK_EQ(default_duration_, -1);
    266     } else {
    267       CHECK(default_duration_ == -1 || default_duration_ > 0);
    268     }
    269 
    270     if (track_type == kWebMTrackTypeVideo) {
    271       CHECK_GT(video_pixel_width_, 0);
    272       CHECK_GT(video_pixel_height_, 0);
    273     } else {
    274       CHECK_EQ(video_pixel_width_, -1);
    275       CHECK_EQ(video_pixel_height_, -1);
    276     }
    277 
    278     if (track_type == kWebMTrackTypeAudio) {
    279       CHECK_GT(audio_channels_, 0);
    280       CHECK_GT(audio_sampling_frequency_, 0.0);
    281     } else {
    282       CHECK_EQ(audio_channels_, -1);
    283       CHECK_EQ(audio_sampling_frequency_, -1.0);
    284     }
    285   }
    286 }
    287 
    288 int TracksBuilder::Track::GetSize() const {
    289   return MasterElementSize(kWebMIdTrackEntry, GetPayloadSize());
    290 }
    291 
    292 int TracksBuilder::Track::GetVideoPayloadSize() const {
    293   int payload_size = 0;
    294 
    295   if (video_pixel_width_ >= 0)
    296     payload_size += UIntElementSize(kWebMIdPixelWidth, video_pixel_width_);
    297   if (video_pixel_height_ >= 0)
    298     payload_size += UIntElementSize(kWebMIdPixelHeight, video_pixel_height_);
    299 
    300   return payload_size;
    301 }
    302 
    303 int TracksBuilder::Track::GetAudioPayloadSize() const {
    304   int payload_size = 0;
    305 
    306   if (audio_channels_ >= 0)
    307     payload_size += UIntElementSize(kWebMIdChannels, audio_channels_);
    308   if (audio_sampling_frequency_ >= 0)
    309     payload_size += DoubleElementSize(kWebMIdSamplingFrequency);
    310 
    311   return payload_size;
    312 }
    313 
    314 int TracksBuilder::Track::GetPayloadSize() const {
    315   int size = 0;
    316 
    317   size += UIntElementSize(kWebMIdTrackNumber, track_num_);
    318   size += UIntElementSize(kWebMIdTrackType, track_type_);
    319   size += UIntElementSize(kWebMIdTrackUID, track_uid_);
    320 
    321   if (default_duration_ >= 0)
    322     size += UIntElementSize(kWebMIdDefaultDuration, default_duration_);
    323 
    324   if (!codec_id_.empty())
    325     size += StringElementSize(kWebMIdCodecID, codec_id_);
    326 
    327   if (!name_.empty())
    328     size += StringElementSize(kWebMIdName, name_);
    329 
    330   if (!language_.empty())
    331     size += StringElementSize(kWebMIdLanguage, language_);
    332 
    333   if (GetVideoPayloadSize() > 0) {
    334     size += MasterElementSize(kWebMIdVideo, GetVideoPayloadSize());
    335   }
    336 
    337   if (GetAudioPayloadSize() > 0) {
    338     size += MasterElementSize(kWebMIdAudio, GetAudioPayloadSize());
    339   }
    340 
    341   return size;
    342 }
    343 
    344 void TracksBuilder::Track::Write(uint8** buf, int* buf_size) const {
    345   WriteMasterElement(buf, buf_size, kWebMIdTrackEntry, GetPayloadSize());
    346 
    347   WriteUIntElement(buf, buf_size, kWebMIdTrackNumber, track_num_);
    348   WriteUIntElement(buf, buf_size, kWebMIdTrackType, track_type_);
    349   WriteUIntElement(buf, buf_size, kWebMIdTrackUID, track_uid_);
    350 
    351   if (default_duration_ >= 0)
    352     WriteUIntElement(buf, buf_size, kWebMIdDefaultDuration, default_duration_);
    353 
    354   if (!codec_id_.empty())
    355     WriteStringElement(buf, buf_size, kWebMIdCodecID, codec_id_);
    356 
    357   if (!name_.empty())
    358     WriteStringElement(buf, buf_size, kWebMIdName, name_);
    359 
    360   if (!language_.empty())
    361     WriteStringElement(buf, buf_size, kWebMIdLanguage, language_);
    362 
    363   if (GetVideoPayloadSize() > 0) {
    364     WriteMasterElement(buf, buf_size, kWebMIdVideo, GetVideoPayloadSize());
    365 
    366     if (video_pixel_width_ >= 0)
    367       WriteUIntElement(buf, buf_size, kWebMIdPixelWidth, video_pixel_width_);
    368 
    369     if (video_pixel_height_ >= 0)
    370       WriteUIntElement(buf, buf_size, kWebMIdPixelHeight, video_pixel_height_);
    371   }
    372 
    373   if (GetAudioPayloadSize() > 0) {
    374     WriteMasterElement(buf, buf_size, kWebMIdAudio, GetAudioPayloadSize());
    375 
    376     if (audio_channels_ >= 0)
    377       WriteUIntElement(buf, buf_size, kWebMIdChannels, audio_channels_);
    378 
    379     if (audio_sampling_frequency_ >= 0) {
    380       WriteDoubleElement(buf, buf_size, kWebMIdSamplingFrequency,
    381           audio_sampling_frequency_);
    382     }
    383   }
    384 }
    385 
    386 }  // namespace media
    387