Home | History | Annotate | Download | only in webm
      1 // Copyright (c) 2013 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/webm/tracks_builder.h"
      6 
      7 #include "media/webm/webm_constants.h"
      8 
      9 namespace media {
     10 
     11 // Returns size of an integer, formatted using Matroska serialization.
     12 static int GetUIntMkvSize(uint64 value) {
     13   if (value < 0x07FULL)
     14     return 1;
     15   if (value < 0x03FFFULL)
     16     return 2;
     17   if (value < 0x01FFFFFULL)
     18     return 3;
     19   if (value < 0x0FFFFFFFULL)
     20     return 4;
     21   if (value < 0x07FFFFFFFFULL)
     22     return 5;
     23   if (value < 0x03FFFFFFFFFFULL)
     24     return 6;
     25   if (value < 0x01FFFFFFFFFFFFULL)
     26     return 7;
     27   return 8;
     28 }
     29 
     30 // Returns the minimium size required to serialize an integer value.
     31 static int GetUIntSize(uint64 value) {
     32   if (value < 0x0100ULL)
     33     return 1;
     34   if (value < 0x010000ULL)
     35     return 2;
     36   if (value < 0x01000000ULL)
     37     return 3;
     38   if (value < 0x0100000000ULL)
     39     return 4;
     40   if (value < 0x010000000000ULL)
     41     return 5;
     42   if (value < 0x01000000000000ULL)
     43     return 6;
     44   if (value < 0x0100000000000000ULL)
     45     return 7;
     46   return 8;
     47 }
     48 
     49 static int MasterElementSize(int element_id, int payload_size) {
     50   return GetUIntSize(element_id) + GetUIntMkvSize(payload_size) + payload_size;
     51 }
     52 
     53 static int IntElementSize(int element_id, int value) {
     54   return GetUIntSize(element_id) + 1 + GetUIntSize(value);
     55 }
     56 
     57 static int StringElementSize(int element_id, const std::string& value) {
     58  return GetUIntSize(element_id) +
     59         GetUIntMkvSize(value.length()) +
     60         value.length();
     61 }
     62 
     63 static void SerializeInt(uint8** buf_ptr, int* buf_size_ptr,
     64                          int64 value, int size) {
     65   uint8*& buf = *buf_ptr;
     66   int& buf_size = *buf_size_ptr;
     67 
     68   for (int idx = 1; idx <= size; ++idx) {
     69     *buf++ = static_cast<uint8>(value >> ((size - idx) * 8));
     70     --buf_size;
     71   }
     72 }
     73 
     74 static void WriteElementId(uint8** buf, int* buf_size, int element_id) {
     75   SerializeInt(buf, buf_size, element_id, GetUIntSize(element_id));
     76 }
     77 
     78 static void WriteUInt(uint8** buf, int* buf_size, uint64 value) {
     79   const int size = GetUIntMkvSize(value);
     80   value |= (1ULL << (size * 7));  // Matroska formatting
     81   SerializeInt(buf, buf_size, value, size);
     82 }
     83 
     84 static void WriteMasterElement(uint8** buf, int* buf_size,
     85                                int element_id, int payload_size) {
     86   WriteElementId(buf, buf_size, element_id);
     87   WriteUInt(buf, buf_size, payload_size);
     88 }
     89 
     90 static void WriteIntElement(uint8** buf, int* buf_size,
     91                             int element_id, int value) {
     92   WriteElementId(buf, buf_size, element_id);
     93 
     94   const int size = GetUIntSize(value);
     95   WriteUInt(buf, buf_size, size);
     96 
     97   SerializeInt(buf, buf_size, value, size);
     98 }
     99 
    100 static void WriteStringElement(uint8** buf_ptr, int* buf_size_ptr,
    101                                int element_id, const std::string& value) {
    102   uint8*& buf = *buf_ptr;
    103   int& buf_size = *buf_size_ptr;
    104 
    105   WriteElementId(&buf, &buf_size, element_id);
    106 
    107   const uint64 size = value.length();
    108   WriteUInt(&buf, &buf_size, size);
    109 
    110   memcpy(buf, value.data(), size);
    111   buf += size;
    112   buf_size -= size;
    113 }
    114 
    115 TracksBuilder::TracksBuilder() {}
    116 TracksBuilder::~TracksBuilder() {}
    117 
    118 void TracksBuilder::AddTrack(
    119     int track_num,
    120     int track_type,
    121     int track_uid,
    122     const std::string& codec_id,
    123     const std::string& name,
    124     const std::string& language) {
    125   tracks_.push_back(Track(track_num, track_type, track_uid, codec_id, name,
    126                           language));
    127 }
    128 
    129 std::vector<uint8> TracksBuilder::Finish() {
    130   // Allocate the storage
    131   std::vector<uint8> buffer;
    132   buffer.resize(GetTracksSize());
    133 
    134   // Populate the storage with a tracks header
    135   WriteTracks(&buffer[0], buffer.size());
    136 
    137   return buffer;
    138 }
    139 
    140 int TracksBuilder::GetTracksSize() const {
    141   return MasterElementSize(kWebMIdTracks, GetTracksPayloadSize());
    142 }
    143 
    144 int TracksBuilder::GetTracksPayloadSize() const {
    145   int payload_size = 0;
    146 
    147   for (TrackList::const_iterator itr = tracks_.begin();
    148        itr != tracks_.end(); ++itr) {
    149     payload_size += itr->GetSize();
    150   }
    151 
    152   return payload_size;
    153 }
    154 
    155 void TracksBuilder::WriteTracks(uint8* buf, int buf_size) const {
    156   WriteMasterElement(&buf, &buf_size, kWebMIdTracks, GetTracksPayloadSize());
    157 
    158   for (TrackList::const_iterator itr = tracks_.begin();
    159        itr != tracks_.end(); ++itr) {
    160     itr->Write(&buf, &buf_size);
    161   }
    162 }
    163 
    164 TracksBuilder::Track::Track(int track_num, int track_type, int track_uid,
    165                             const std::string& codec_id,
    166                             const std::string& name,
    167                             const std::string& language)
    168     : track_num_(track_num),
    169       track_type_(track_type),
    170       track_uid_(track_uid),
    171       codec_id_(codec_id),
    172       name_(name),
    173       language_(language) {
    174 }
    175 
    176 int TracksBuilder::Track::GetSize() const {
    177   return MasterElementSize(kWebMIdTrackEntry, GetPayloadSize());
    178 }
    179 
    180 int TracksBuilder::Track::GetPayloadSize() const {
    181   int size = 0;
    182 
    183   size += IntElementSize(kWebMIdTrackNumber, track_num_);
    184   size += IntElementSize(kWebMIdTrackType, track_type_);
    185   size += IntElementSize(kWebMIdTrackUID, track_uid_);
    186 
    187   if (!codec_id_.empty())
    188     size += StringElementSize(kWebMIdCodecID, codec_id_);
    189 
    190   if (!name_.empty())
    191     size += StringElementSize(kWebMIdName, name_);
    192 
    193   if (!language_.empty())
    194     size += StringElementSize(kWebMIdLanguage, language_);
    195 
    196   return size;
    197 }
    198 
    199 void TracksBuilder::Track::Write(uint8** buf, int* buf_size) const {
    200   WriteMasterElement(buf, buf_size, kWebMIdTrackEntry, GetPayloadSize());
    201 
    202   WriteIntElement(buf, buf_size, kWebMIdTrackNumber, track_num_);
    203   WriteIntElement(buf, buf_size, kWebMIdTrackType, track_type_);
    204   WriteIntElement(buf, buf_size, kWebMIdTrackUID, track_uid_);
    205 
    206   if (!codec_id_.empty())
    207     WriteStringElement(buf, buf_size, kWebMIdCodecID, codec_id_);
    208 
    209   if (!name_.empty())
    210     WriteStringElement(buf, buf_size, kWebMIdName, name_);
    211 
    212   if (!language_.empty())
    213     WriteStringElement(buf, buf_size, kWebMIdLanguage, language_);
    214 }
    215 
    216 }  // namespace media
    217