Index: media/formats/webm/tracks_builder.cc |
diff --git a/media/formats/webm/tracks_builder.cc b/media/formats/webm/tracks_builder.cc |
index 5a49ce05f4f49b6a2b8fdd4dbd593a8ddd33057e..fb402c4729c7f478c002273b1a7952233ef540ff 100644 |
--- a/media/formats/webm/tracks_builder.cc |
+++ b/media/formats/webm/tracks_builder.cc |
@@ -4,6 +4,7 @@ |
#include "media/formats/webm/tracks_builder.h" |
+#include "base/logging.h" |
#include "media/formats/webm/webm_constants.h" |
namespace media { |
@@ -54,6 +55,10 @@ 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()) + |
@@ -71,6 +76,19 @@ static void SerializeInt(uint8** buf_ptr, int* buf_size_ptr, |
} |
} |
+static void SerializeDouble(uint8** buf_ptr, int* buf_size_ptr, |
+ double value) { |
+ // Use a union to convert |value| to native endian integer bit pattern. |
+ union { |
+ double src; |
+ int64 dst; |
+ } tmp; |
+ tmp.src = value; |
+ |
+ // Write the bytes from native endian |tmp.dst| to big-endian form in |buf|. |
+ 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)); |
} |
@@ -97,6 +115,13 @@ static void WriteIntElement(uint8** buf, int* buf_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; |
@@ -112,18 +137,48 @@ static void WriteStringElement(uint8** buf_ptr, int* buf_size_ptr, |
buf_size -= size; |
} |
-TracksBuilder::TracksBuilder() {} |
+TracksBuilder::TracksBuilder(bool allow_invalid_values) |
+ : allow_invalid_values_(allow_invalid_values) {} |
+TracksBuilder::TracksBuilder() |
+ : allow_invalid_values_(false) {} |
TracksBuilder::~TracksBuilder() {} |
-void TracksBuilder::AddTrack( |
+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_type, |
int track_uid, |
const std::string& codec_id, |
const std::string& name, |
const std::string& language) { |
- tracks_.push_back(Track(track_num, track_type, track_uid, codec_id, name, |
- language)); |
+ AddTrackInternal(track_num, kWebMTrackTypeSubtitlesOrCaptions, track_uid, |
+ codec_id, name, language, -1, -1, -1, -1, -1); |
} |
std::vector<uint8> TracksBuilder::Finish() { |
@@ -137,6 +192,24 @@ std::vector<uint8> TracksBuilder::Finish() { |
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()); |
} |
@@ -164,19 +237,78 @@ void TracksBuilder::WriteTracks(uint8* buf, int buf_size) const { |
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) |
+ 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) { |
+ 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; |
@@ -184,6 +316,9 @@ int TracksBuilder::Track::GetPayloadSize() const { |
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_); |
@@ -193,6 +328,14 @@ int TracksBuilder::Track::GetPayloadSize() const { |
if (!language_.empty()) |
size += StringElementSize(kWebMIdLanguage, language_); |
+ if (GetVideoPayloadSize() > 0) { |
+ size += MasterElementSize(kWebMIdVideo, GetVideoPayloadSize()); |
+ } |
+ |
+ if (GetAudioPayloadSize() > 0) { |
+ size += MasterElementSize(kWebMIdAudio, GetAudioPayloadSize()); |
+ } |
+ |
return size; |
} |
@@ -203,6 +346,9 @@ void TracksBuilder::Track::Write(uint8** buf, int* buf_size) const { |
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_); |
@@ -211,6 +357,28 @@ void TracksBuilder::Track::Write(uint8** buf, int* buf_size) const { |
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_); |
+ } |
+ } |
} |
} // namespace media |