This source file includes following definitions.
- GetUIntMkvSize
 
- GetUIntSize
 
- MasterElementSize
 
- IntElementSize
 
- DoubleElementSize
 
- StringElementSize
 
- SerializeInt
 
- SerializeDouble
 
- WriteElementId
 
- WriteUInt
 
- WriteMasterElement
 
- WriteIntElement
 
- WriteDoubleElement
 
- WriteStringElement
 
- AddVideoTrack
 
- AddAudioTrack
 
- AddTextTrack
 
- Finish
 
- AddTrackInternal
 
- GetTracksSize
 
- GetTracksPayloadSize
 
- WriteTracks
 
- audio_sampling_frequency_
 
- GetSize
 
- GetVideoPayloadSize
 
- GetAudioPayloadSize
 
- GetPayloadSize
 
- Write
 
#include "media/formats/webm/tracks_builder.h"
#include "base/logging.h"
#include "media/formats/webm/webm_constants.h"
namespace media {
static int GetUIntMkvSize(uint64 value) {
  if (value < 0x07FULL)
    return 1;
  if (value < 0x03FFFULL)
    return 2;
  if (value < 0x01FFFFFULL)
    return 3;
  if (value < 0x0FFFFFFFULL)
    return 4;
  if (value < 0x07FFFFFFFFULL)
    return 5;
  if (value < 0x03FFFFFFFFFFULL)
    return 6;
  if (value < 0x01FFFFFFFFFFFFULL)
    return 7;
  return 8;
}
static int GetUIntSize(uint64 value) {
  if (value < 0x0100ULL)
    return 1;
  if (value < 0x010000ULL)
    return 2;
  if (value < 0x01000000ULL)
    return 3;
  if (value < 0x0100000000ULL)
    return 4;
  if (value < 0x010000000000ULL)
    return 5;
  if (value < 0x01000000000000ULL)
    return 6;
  if (value < 0x0100000000000000ULL)
    return 7;
  return 8;
}
static int MasterElementSize(int element_id, int payload_size) {
  return GetUIntSize(element_id) + GetUIntMkvSize(payload_size) + payload_size;
}
static int IntElementSize(int element_id, int value) {
  return GetUIntSize(element_id) + 1 + GetUIntSize(value);
}
static int DoubleElementSize(int element_id) {
  return GetUIntSize(element_id) + 1 + 8;
}
static int StringElementSize(int element_id, const std::string& value) {
 return GetUIntSize(element_id) +
        GetUIntMkvSize(value.length()) +
        value.length();
}
static void SerializeInt(uint8** buf_ptr, int* buf_size_ptr,
                         int64 value, int size) {
  uint8*& buf = *buf_ptr;
  int& buf_size = *buf_size_ptr;
  for (int idx = 1; idx <= size; ++idx) {
    *buf++ = static_cast<uint8>(value >> ((size - idx) * 8));
    --buf_size;
  }
}
static void SerializeDouble(uint8** buf_ptr, int* buf_size_ptr,
                            double value) {
  
  union {
    double src;
    int64 dst;
  } tmp;
  tmp.src = value;
  
  SerializeInt(buf_ptr, buf_size_ptr, tmp.dst, 8);
}
static void WriteElementId(uint8** buf, int* buf_size, int element_id) {
  SerializeInt(buf, buf_size, element_id, GetUIntSize(element_id));
}
static void WriteUInt(uint8** buf, int* buf_size, uint64 value) {
  const int size = GetUIntMkvSize(value);
  value |= (1ULL << (size * 7));  
  SerializeInt(buf, buf_size, value, size);
}
static void WriteMasterElement(uint8** buf, int* buf_size,
                               int element_id, int payload_size) {
  WriteElementId(buf, buf_size, element_id);
  WriteUInt(buf, buf_size, payload_size);
}
static void WriteIntElement(uint8** buf, int* buf_size,
                            int element_id, int value) {
  WriteElementId(buf, buf_size, element_id);
  const int size = GetUIntSize(value);
  WriteUInt(buf, buf_size, size);
  SerializeInt(buf, buf_size, value, size);
}
static void WriteDoubleElement(uint8** buf, int* buf_size,
                               int element_id, double value) {
  WriteElementId(buf, buf_size, element_id);
  WriteUInt(buf, buf_size, 8);
  SerializeDouble(buf, buf_size, value);
}
static void WriteStringElement(uint8** buf_ptr, int* buf_size_ptr,
                               int element_id, const std::string& value) {
  uint8*& buf = *buf_ptr;
  int& buf_size = *buf_size_ptr;
  WriteElementId(&buf, &buf_size, element_id);
  const uint64 size = value.length();
  WriteUInt(&buf, &buf_size, size);
  memcpy(buf, value.data(), size);
  buf += size;
  buf_size -= size;
}
TracksBuilder::TracksBuilder(bool allow_invalid_values)
    : allow_invalid_values_(allow_invalid_values) {}
TracksBuilder::TracksBuilder()
    : allow_invalid_values_(false) {}
TracksBuilder::~TracksBuilder() {}
void TracksBuilder::AddVideoTrack(
    int track_num,
    int track_uid,
    const std::string& codec_id,
    const std::string& name,
    const std::string& language,
    int default_duration,
    int video_pixel_width,
    int video_pixel_height) {
  AddTrackInternal(track_num, kWebMTrackTypeVideo, track_uid, codec_id, name,
                   language, default_duration, video_pixel_width,
                   video_pixel_height, -1, -1);
}
void TracksBuilder::AddAudioTrack(
    int track_num,
    int track_uid,
    const std::string& codec_id,
    const std::string& name,
    const std::string& language,
    int default_duration,
    int audio_channels,
    double audio_sampling_frequency) {
  AddTrackInternal(track_num, kWebMTrackTypeAudio, track_uid, codec_id, name,
                   language, default_duration, -1, -1, audio_channels,
                   audio_sampling_frequency);
}
void TracksBuilder::AddTextTrack(
    int track_num,
    int track_uid,
    const std::string& codec_id,
    const std::string& name,
    const std::string& language) {
  AddTrackInternal(track_num, kWebMTrackTypeSubtitlesOrCaptions, track_uid,
                   codec_id, name, language, -1, -1, -1, -1, -1);
}
std::vector<uint8> TracksBuilder::Finish() {
  
  std::vector<uint8> buffer;
  buffer.resize(GetTracksSize());
  
  WriteTracks(&buffer[0], buffer.size());
  return buffer;
}
void TracksBuilder::AddTrackInternal(
    int track_num,
    int track_type,
    int track_uid,
    const std::string& codec_id,
    const std::string& name,
    const std::string& language,
    int default_duration,
    int video_pixel_width,
    int video_pixel_height,
    int audio_channels,
    double audio_sampling_frequency) {
  tracks_.push_back(Track(track_num, track_type, track_uid, codec_id, name,
                          language, default_duration, video_pixel_width,
                          video_pixel_height, audio_channels,
                          audio_sampling_frequency, allow_invalid_values_));
}
int TracksBuilder::GetTracksSize() const {
  return MasterElementSize(kWebMIdTracks, GetTracksPayloadSize());
}
int TracksBuilder::GetTracksPayloadSize() const {
  int payload_size = 0;
  for (TrackList::const_iterator itr = tracks_.begin();
       itr != tracks_.end(); ++itr) {
    payload_size += itr->GetSize();
  }
  return payload_size;
}
void TracksBuilder::WriteTracks(uint8* buf, int buf_size) const {
  WriteMasterElement(&buf, &buf_size, kWebMIdTracks, GetTracksPayloadSize());
  for (TrackList::const_iterator itr = tracks_.begin();
       itr != tracks_.end(); ++itr) {
    itr->Write(&buf, &buf_size);
  }
}
TracksBuilder::Track::Track(int track_num, int track_type, int track_uid,
                            const std::string& codec_id,
                            const std::string& name,
                            const std::string& language,
                            int default_duration,
                            int video_pixel_width, int video_pixel_height,
                            int audio_channels, double audio_sampling_frequency,
                            bool allow_invalid_values)
    : track_num_(track_num),
      track_type_(track_type),
      track_uid_(track_uid),
      codec_id_(codec_id),
      name_(name),
      language_(language),
      default_duration_(default_duration),
      video_pixel_width_(video_pixel_width),
      video_pixel_height_(video_pixel_height),
      audio_channels_(audio_channels),
      audio_sampling_frequency_(audio_sampling_frequency) {
  if (!allow_invalid_values) {
    CHECK_GT(track_num_, 0);
    CHECK_GT(track_type_, 0);
    CHECK_LT(track_type_, 255);
    CHECK_GT(track_uid_, 0);
    if (track_type != kWebMTrackTypeVideo &&
        track_type != kWebMTrackTypeAudio) {
      CHECK_EQ(default_duration_, -1);
    } else {
      CHECK(default_duration_ == -1 || default_duration_ > 0);
    }
    if (track_type == kWebMTrackTypeVideo) {
      CHECK_GT(video_pixel_width_, 0);
      CHECK_GT(video_pixel_height_, 0);
    } else {
      CHECK_EQ(video_pixel_width_, -1);
      CHECK_EQ(video_pixel_height_, -1);
    }
    if (track_type == kWebMTrackTypeAudio) {
      CHECK_GT(audio_channels_, 0);
      CHECK_GT(audio_sampling_frequency_, 0.0);
    } else {
      CHECK_EQ(audio_channels_, -1);
      CHECK_EQ(audio_sampling_frequency_, -1.0);
    }
  }
}
int TracksBuilder::Track::GetSize() const {
  return MasterElementSize(kWebMIdTrackEntry, GetPayloadSize());
}
int TracksBuilder::Track::GetVideoPayloadSize() const {
  int payload_size = 0;
  if (video_pixel_width_ >= 0)
    payload_size += IntElementSize(kWebMIdPixelWidth, video_pixel_width_);
  if (video_pixel_height_ >= 0)
    payload_size += IntElementSize(kWebMIdPixelHeight, video_pixel_height_);
  return payload_size;
}
int TracksBuilder::Track::GetAudioPayloadSize() const {
  int payload_size = 0;
  if (audio_channels_ >= 0)
    payload_size += IntElementSize(kWebMIdChannels, audio_channels_);
  if (audio_sampling_frequency_ >= 0)
    payload_size += DoubleElementSize(kWebMIdSamplingFrequency);
  return payload_size;
}
int TracksBuilder::Track::GetPayloadSize() const {
  int size = 0;
  size += IntElementSize(kWebMIdTrackNumber, track_num_);
  size += IntElementSize(kWebMIdTrackType, track_type_);
  size += IntElementSize(kWebMIdTrackUID, track_uid_);
  if (default_duration_ >= 0)
    size += IntElementSize(kWebMIdDefaultDuration, default_duration_);
  if (!codec_id_.empty())
    size += StringElementSize(kWebMIdCodecID, codec_id_);
  if (!name_.empty())
    size += StringElementSize(kWebMIdName, name_);
  if (!language_.empty())
    size += StringElementSize(kWebMIdLanguage, language_);
  if (GetVideoPayloadSize() > 0) {
    size += MasterElementSize(kWebMIdVideo, GetVideoPayloadSize());
  }
  if (GetAudioPayloadSize() > 0) {
    size += MasterElementSize(kWebMIdAudio, GetAudioPayloadSize());
  }
  return size;
}
void TracksBuilder::Track::Write(uint8** buf, int* buf_size) const {
  WriteMasterElement(buf, buf_size, kWebMIdTrackEntry, GetPayloadSize());
  WriteIntElement(buf, buf_size, kWebMIdTrackNumber, track_num_);
  WriteIntElement(buf, buf_size, kWebMIdTrackType, track_type_);
  WriteIntElement(buf, buf_size, kWebMIdTrackUID, track_uid_);
  if (default_duration_ >= 0)
    WriteIntElement(buf, buf_size, kWebMIdDefaultDuration, default_duration_);
  if (!codec_id_.empty())
    WriteStringElement(buf, buf_size, kWebMIdCodecID, codec_id_);
  if (!name_.empty())
    WriteStringElement(buf, buf_size, kWebMIdName, name_);
  if (!language_.empty())
    WriteStringElement(buf, buf_size, kWebMIdLanguage, language_);
  if (GetVideoPayloadSize() > 0) {
    WriteMasterElement(buf, buf_size, kWebMIdVideo, GetVideoPayloadSize());
    if (video_pixel_width_ >= 0)
      WriteIntElement(buf, buf_size, kWebMIdPixelWidth, video_pixel_width_);
    if (video_pixel_height_ >= 0)
      WriteIntElement(buf, buf_size, kWebMIdPixelHeight, video_pixel_height_);
  }
  if (GetAudioPayloadSize() > 0) {
    WriteMasterElement(buf, buf_size, kWebMIdAudio, GetAudioPayloadSize());
    if (audio_channels_ >= 0)
      WriteIntElement(buf, buf_size, kWebMIdChannels, audio_channels_);
    if (audio_sampling_frequency_ >= 0) {
      WriteDoubleElement(buf, buf_size, kWebMIdSamplingFrequency,
          audio_sampling_frequency_);
    }
  }
}
}