Box definitions for WebVTT

Change-Id: I94d38bef918eed18df7cd312126e2d589aadf9c7
This commit is contained in:
Rintaro Kuroiwa 2015-11-23 15:12:04 -08:00 committed by KongQun Yang
parent c8e3345959
commit 09d1c2ce9f
8 changed files with 594 additions and 29 deletions

View File

@ -53,6 +53,15 @@ bool BufferReader::ReadToVector(std::vector<uint8_t>* vec, size_t count) {
return true; return true;
} }
bool BufferReader::ReadToString(std::string* str, size_t size) {
DCHECK(str);
if (!HasBytes(size))
return false;
str->assign(buf_ + pos_, buf_ + pos_ + size);
pos_ += size;
return true;
}
bool BufferReader::SkipBytes(size_t num_bytes) { bool BufferReader::SkipBytes(size_t num_bytes) {
if (!HasBytes(num_bytes)) if (!HasBytes(num_bytes))
return false; return false;

View File

@ -9,6 +9,7 @@
#include <stdint.h> #include <stdint.h>
#include <string>
#include <vector> #include <vector>
#include "packager/base/compiler_specific.h" #include "packager/base/compiler_specific.h"
@ -53,6 +54,7 @@ class BufferReader {
/// @} /// @}
bool ReadToVector(std::vector<uint8_t>* t, size_t count) WARN_UNUSED_RESULT; bool ReadToVector(std::vector<uint8_t>* t, size_t count) WARN_UNUSED_RESULT;
bool ReadToString(std::string* str, size_t size) WARN_UNUSED_RESULT;
/// Advance the stream by this many bytes. /// Advance the stream by this many bytes.
/// @return false if there are not enough bytes in the buffer, true otherwise. /// @return false if there are not enough bytes in the buffer, true otherwise.

View File

@ -7,6 +7,8 @@
#ifndef MEDIA_FORMATS_MP4_BOX_BUFFER_H_ #ifndef MEDIA_FORMATS_MP4_BOX_BUFFER_H_
#define MEDIA_FORMATS_MP4_BOX_BUFFER_H_ #define MEDIA_FORMATS_MP4_BOX_BUFFER_H_
#include <string>
#include "packager/base/compiler_specific.h" #include "packager/base/compiler_specific.h"
#include "packager/media/base/buffer_writer.h" #include "packager/media/base/buffer_writer.h"
#include "packager/media/formats/mp4/box.h" #include "packager/media/formats/mp4/box.h"
@ -55,6 +57,14 @@ class BoxBuffer {
return writer_->Size(); return writer_->Size();
} }
/// @return In read mode, return the number of bytes left in the box.
/// In write mode, return 0.
size_t BytesLeft() const {
if (reader_)
return reader_->size() - reader_->pos();
return 0;
}
/// @name Read/write integers of various sizes and signedness. /// @name Read/write integers of various sizes and signedness.
/// @{ /// @{
bool ReadWriteUInt8(uint8_t* v) { bool ReadWriteUInt8(uint8_t* v) {
@ -120,9 +130,21 @@ class BoxBuffer {
if (reader_) if (reader_)
return reader_->ReadToVector(vector, count); return reader_->ReadToVector(vector, count);
DCHECK_EQ(vector->size(), count); DCHECK_EQ(vector->size(), count);
writer_->AppendVector(*vector); writer_->AppendArray(vector_as_array(vector), count);
return true; return true;
} }
/// Reads @a size characters from the buffer and sets it to str.
/// Writes @a str to the buffer. Write mode ignores @a size.
bool ReadWriteString(std::string* str, size_t size) {
if (reader_)
return reader_->ReadToString(str, size);
DCHECK_EQ(str->size(), size);
writer_->AppendArray(reinterpret_cast<const uint8_t*>(str->data()),
str->size());
return true;
}
bool ReadWriteFourCC(FourCC* fourcc) { bool ReadWriteFourCC(FourCC* fourcc) {
if (reader_) if (reader_)
return reader_->ReadFourCC(fourcc); return reader_->ReadFourCC(fourcc);

View File

@ -25,6 +25,7 @@ const uint8_t kUnityMatrix[] = {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// Default entries for HandlerReference box. // Default entries for HandlerReference box.
const char kVideoHandlerName[] = "VideoHandler"; const char kVideoHandlerName[] = "VideoHandler";
const char kAudioHandlerName[] = "SoundHandler"; const char kAudioHandlerName[] = "SoundHandler";
const char kTextHandlerName[] = "TextHandler";
// Default values for VideoSampleEntry box. // Default values for VideoSampleEntry box.
const uint32_t kVideoResolution = 0x00480000; // 72 dpi. const uint32_t kVideoResolution = 0x00480000; // 72 dpi.
@ -36,6 +37,10 @@ const char kAvcCompressorName[] = "\012AVC Coding";
const char kHevcCompressorName[] = "\013HEVC Coding"; const char kHevcCompressorName[] = "\013HEVC Coding";
const char kVpcCompressorName[] = "\012VPC Coding"; const char kVpcCompressorName[] = "\012VPC Coding";
// Using negative value as "not set". It is very unlikely that 2^31 cues happen
// at once.
const int kCueSourceIdNotSet = -1;
// Utility functions to check if the 64bit integers can fit in 32bit integer. // Utility functions to check if the 64bit integers can fit in 32bit integer.
bool IsFitIn32Bits(uint64_t a) { bool IsFitIn32Bits(uint64_t a) {
return a <= std::numeric_limits<uint32_t>::max(); return a <= std::numeric_limits<uint32_t>::max();
@ -377,10 +382,20 @@ FourCC SampleDescription::BoxType() const { return FOURCC_STSD; }
bool SampleDescription::ReadWriteInternal(BoxBuffer* buffer) { bool SampleDescription::ReadWriteInternal(BoxBuffer* buffer) {
uint32_t count = 0; uint32_t count = 0;
if (type == kVideo) switch (type) {
count = video_entries.size(); case kVideo:
else count = video_entries.size();
count = audio_entries.size(); break;
case kAudio:
count = audio_entries.size();
break;
case kText:
count = wvtt_entries.size();
break;
default:
NOTIMPLEMENTED() << "SampleDecryption type " << type
<< " is not handled. Skipping.";
}
RCHECK(ReadWriteHeaderInternal(buffer) && RCHECK(ReadWriteHeaderInternal(buffer) &&
buffer->ReadWriteUInt32(&count)); buffer->ReadWriteUInt32(&count));
@ -397,6 +412,9 @@ bool SampleDescription::ReadWriteInternal(BoxBuffer* buffer) {
} else if (type == kAudio) { } else if (type == kAudio) {
RCHECK(reader->ReadAllChildren(&audio_entries)); RCHECK(reader->ReadAllChildren(&audio_entries));
RCHECK(audio_entries.size() == count); RCHECK(audio_entries.size() == count);
} else if (type == kText) {
RCHECK(reader->ReadAllChildren(&wvtt_entries));
RCHECK(wvtt_entries.size() == count);
} }
} else { } else {
DCHECK_LT(0u, count); DCHECK_LT(0u, count);
@ -406,6 +424,9 @@ bool SampleDescription::ReadWriteInternal(BoxBuffer* buffer) {
} else if (type == kAudio) { } else if (type == kAudio) {
for (uint32_t i = 0; i < count; ++i) for (uint32_t i = 0; i < count; ++i)
RCHECK(buffer->ReadWriteChild(&audio_entries[i])); RCHECK(buffer->ReadWriteChild(&audio_entries[i]));
} else if (type == kText) {
for (uint32_t i = 0; i < count; ++i)
RCHECK(buffer->ReadWriteChild(&wvtt_entries[i]));
} else { } else {
NOTIMPLEMENTED(); NOTIMPLEMENTED();
} }
@ -803,6 +824,10 @@ bool HandlerReference::ReadWriteInternal(BoxBuffer* buffer) {
hdlr_type = FOURCC_SOUN; hdlr_type = FOURCC_SOUN;
handler_name.assign(kAudioHandlerName, handler_name.assign(kAudioHandlerName,
kAudioHandlerName + arraysize(kAudioHandlerName)); kAudioHandlerName + arraysize(kAudioHandlerName));
} else if (type == kText) {
hdlr_type = FOURCC_TEXT;
handler_name.assign(kTextHandlerName,
kTextHandlerName + arraysize(kTextHandlerName));
} else { } else {
NOTIMPLEMENTED(); NOTIMPLEMENTED();
return false; return false;
@ -828,9 +853,15 @@ bool HandlerReference::ReadWriteInternal(BoxBuffer* buffer) {
} }
uint32_t HandlerReference::ComputeSizeInternal() { uint32_t HandlerReference::ComputeSizeInternal() {
return HeaderSize() + kFourCCSize + 16 + // 16 bytes Reserved uint32_t box_size = HeaderSize() + kFourCCSize + 16; // 16 bytes Reserved
(type == kVideo ? sizeof(kVideoHandlerName) if (type == kVideo) {
: sizeof(kAudioHandlerName)); box_size += sizeof(kVideoHandlerName);
} else if (type == kAudio) {
box_size += sizeof(kAudioHandlerName);
} else {
box_size += sizeof(kTextHandlerName);
}
return box_size;
} }
CodecConfigurationRecord::CodecConfigurationRecord() : box_type(FOURCC_NULL) {} CodecConfigurationRecord::CodecConfigurationRecord() : box_type(FOURCC_NULL) {}
@ -844,7 +875,7 @@ FourCC CodecConfigurationRecord::BoxType() const {
bool CodecConfigurationRecord::ReadWriteInternal(BoxBuffer* buffer) { bool CodecConfigurationRecord::ReadWriteInternal(BoxBuffer* buffer) {
RCHECK(ReadWriteHeaderInternal(buffer)); RCHECK(ReadWriteHeaderInternal(buffer));
if (buffer->Reading()) { if (buffer->Reading()) {
RCHECK(buffer->ReadWriteVector(&data, buffer->Size() - buffer->Pos())); RCHECK(buffer->ReadWriteVector(&data, buffer->BytesLeft()));
} else { } else {
RCHECK(buffer->ReadWriteVector(&data, data.size())); RCHECK(buffer->ReadWriteVector(&data, data.size()));
} }
@ -996,7 +1027,7 @@ bool ElementaryStreamDescriptor::ReadWriteInternal(BoxBuffer* buffer) {
RCHECK(ReadWriteHeaderInternal(buffer)); RCHECK(ReadWriteHeaderInternal(buffer));
if (buffer->Reading()) { if (buffer->Reading()) {
std::vector<uint8_t> data; std::vector<uint8_t> data;
RCHECK(buffer->ReadWriteVector(&data, buffer->Size() - buffer->Pos())); RCHECK(buffer->ReadWriteVector(&data, buffer->BytesLeft()));
RCHECK(es_descriptor.Parse(data)); RCHECK(es_descriptor.Parse(data));
if (es_descriptor.IsAAC()) { if (es_descriptor.IsAAC()) {
RCHECK(aac_audio_specific_config.Parse( RCHECK(aac_audio_specific_config.Parse(
@ -1104,6 +1135,68 @@ uint32_t AudioSampleEntry::ComputeSizeInternal() {
4; // 4 bytes predefined. 4; // 4 bytes predefined.
} }
WebVTTConfigurationBox::WebVTTConfigurationBox() {}
WebVTTConfigurationBox::~WebVTTConfigurationBox() {}
FourCC WebVTTConfigurationBox::BoxType() const {
return FOURCC_vttC;
}
bool WebVTTConfigurationBox::ReadWriteInternal(BoxBuffer* buffer) {
RCHECK(ReadWriteHeaderInternal(buffer));
return buffer->ReadWriteString(
&config,
buffer->Reading() ? buffer->BytesLeft() : config.size());
}
uint32_t WebVTTConfigurationBox::ComputeSizeInternal() {
return HeaderSize() + config.size();
}
WebVTTSourceLabelBox::WebVTTSourceLabelBox() {}
WebVTTSourceLabelBox::~WebVTTSourceLabelBox() {}
FourCC WebVTTSourceLabelBox::BoxType() const {
return FOURCC_vlab;
}
bool WebVTTSourceLabelBox::ReadWriteInternal(BoxBuffer* buffer) {
RCHECK(ReadWriteHeaderInternal(buffer));
return buffer->ReadWriteString(&source_label, buffer->Reading()
? buffer->BytesLeft()
: source_label.size());
}
uint32_t WebVTTSourceLabelBox::ComputeSizeInternal() {
if (source_label.empty())
return 0;
return HeaderSize() + source_label.size();
}
WVTTSampleEntry::WVTTSampleEntry() {}
WVTTSampleEntry::~WVTTSampleEntry() {}
FourCC WVTTSampleEntry::BoxType() const {
return FOURCC_wvtt;
}
bool WVTTSampleEntry::ReadWriteInternal(BoxBuffer* buffer) {
// TODO(rkuroiwa): Handle the optional MPEG4BitRateBox.
RCHECK(ReadWriteHeaderInternal(buffer) &&
buffer->IgnoreBytes(6) && // reserved for SampleEntry.
buffer->ReadWriteUInt16(&data_reference_index) &&
buffer->PrepareChildren() &&
buffer->ReadWriteChild(&config) &&
buffer->ReadWriteChild(&label));
return true;
}
uint32_t WVTTSampleEntry::ComputeSizeInternal() {
// 6 for the (anonymous) reserved bytes for SampleEntry class.
return HeaderSize() + 6 + sizeof(data_reference_index) +
config.ComputeSize() + label.ComputeSize();
}
MediaHeader::MediaHeader() MediaHeader::MediaHeader()
: creation_time(0), modification_time(0), timescale(0), duration(0) { : creation_time(0), modification_time(0), timescale(0), duration(0) {
language[0] = 0; language[0] = 0;
@ -1192,6 +1285,19 @@ uint32_t SoundMediaHeader::ComputeSizeInternal() {
return HeaderSize() + sizeof(balance) + sizeof(uint16_t); return HeaderSize() + sizeof(balance) + sizeof(uint16_t);
} }
SubtitleMediaHeader::SubtitleMediaHeader() {}
SubtitleMediaHeader::~SubtitleMediaHeader() {}
FourCC SubtitleMediaHeader::BoxType() const { return FOURCC_sthd; }
bool SubtitleMediaHeader::ReadWriteInternal(BoxBuffer* buffer) {
return ReadWriteHeaderInternal(buffer);
}
uint32_t SubtitleMediaHeader::ComputeSizeInternal() {
return HeaderSize();
}
DataEntryUrl::DataEntryUrl() { DataEntryUrl::DataEntryUrl() {
const uint32_t kDataEntryUrlFlags = 1; const uint32_t kDataEntryUrlFlags = 1;
flags = kDataEntryUrlFlags; flags = kDataEntryUrlFlags;
@ -1260,12 +1366,19 @@ bool MediaInformation::ReadWriteInternal(BoxBuffer* buffer) {
buffer->PrepareChildren() && buffer->PrepareChildren() &&
buffer->ReadWriteChild(&dinf) && buffer->ReadWriteChild(&dinf) &&
buffer->ReadWriteChild(&sample_table)); buffer->ReadWriteChild(&sample_table));
if (sample_table.description.type == kVideo) switch (sample_table.description.type) {
RCHECK(buffer->ReadWriteChild(&vmhd)); case kVideo:
else if (sample_table.description.type == kAudio) RCHECK(buffer->ReadWriteChild(&vmhd));
RCHECK(buffer->ReadWriteChild(&smhd)); break;
else case kAudio:
NOTIMPLEMENTED(); RCHECK(buffer->ReadWriteChild(&smhd));
break;
case kText:
RCHECK(buffer->ReadWriteChild(&sthd));
break;
default:
NOTIMPLEMENTED();
}
// Hint is not supported for now. // Hint is not supported for now.
return true; return true;
} }
@ -1273,10 +1386,19 @@ bool MediaInformation::ReadWriteInternal(BoxBuffer* buffer) {
uint32_t MediaInformation::ComputeSizeInternal() { uint32_t MediaInformation::ComputeSizeInternal() {
uint32_t box_size = uint32_t box_size =
HeaderSize() + dinf.ComputeSize() + sample_table.ComputeSize(); HeaderSize() + dinf.ComputeSize() + sample_table.ComputeSize();
if (sample_table.description.type == kVideo) switch (sample_table.description.type) {
box_size += vmhd.ComputeSize(); case kVideo:
else if (sample_table.description.type == kAudio) box_size += vmhd.ComputeSize();
box_size += smhd.ComputeSize(); break;
case kAudio:
box_size += smhd.ComputeSize();
break;
case kText:
box_size += sthd.ComputeSize();
break;
default:
NOTIMPLEMENTED();
}
return box_size; return box_size;
} }
@ -1912,6 +2034,154 @@ uint32_t MediaData::ComputeSizeInternal() {
return HeaderSize() + data_size; return HeaderSize() + data_size;
} }
CueSourceIDBox::CueSourceIDBox() : source_id(kCueSourceIdNotSet) {}
CueSourceIDBox::~CueSourceIDBox() {}
FourCC CueSourceIDBox::BoxType() const { return FOURCC_vsid; }
bool CueSourceIDBox::ReadWriteInternal(BoxBuffer* buffer) {
RCHECK(ReadWriteHeaderInternal(buffer) && buffer->ReadWriteInt32(&source_id));
return true;
}
uint32_t CueSourceIDBox::ComputeSizeInternal() {
if (source_id == kCueSourceIdNotSet)
return 0;
return HeaderSize() + sizeof(source_id);
}
CueTimeBox::CueTimeBox() {}
CueTimeBox::~CueTimeBox() {}
FourCC CueTimeBox::BoxType() const {
return FOURCC_ctim;
}
bool CueTimeBox::ReadWriteInternal(BoxBuffer* buffer) {
RCHECK(ReadWriteHeaderInternal(buffer));
return buffer->ReadWriteString(
&cue_current_time,
buffer->Reading() ? buffer->BytesLeft() : cue_current_time.size());
}
uint32_t CueTimeBox::ComputeSizeInternal() {
if (cue_current_time.empty())
return 0;
return HeaderSize() + cue_current_time.size();
}
CueIDBox::CueIDBox() {}
CueIDBox::~CueIDBox() {}
FourCC CueIDBox::BoxType() const {
return FOURCC_iden;
}
bool CueIDBox::ReadWriteInternal(BoxBuffer* buffer) {
RCHECK(ReadWriteHeaderInternal(buffer));
return buffer->ReadWriteString(
&cue_id, buffer->Reading() ? buffer->BytesLeft() : cue_id.size());
}
uint32_t CueIDBox::ComputeSizeInternal() {
if (cue_id.empty())
return 0;
return HeaderSize() + cue_id.size();
}
CueSettingsBox::CueSettingsBox() {}
CueSettingsBox::~CueSettingsBox() {}
FourCC CueSettingsBox::BoxType() const {
return FOURCC_sttg;
}
bool CueSettingsBox::ReadWriteInternal(BoxBuffer* buffer) {
RCHECK(ReadWriteHeaderInternal(buffer));
return buffer->ReadWriteString(
&settings, buffer->Reading() ? buffer->BytesLeft() : settings.size());
}
uint32_t CueSettingsBox::ComputeSizeInternal() {
if (settings.empty())
return 0;
return HeaderSize() + settings.size();
}
CuePayloadBox::CuePayloadBox() {}
CuePayloadBox::~CuePayloadBox() {}
FourCC CuePayloadBox::BoxType() const {
return FOURCC_payl;
}
bool CuePayloadBox::ReadWriteInternal(BoxBuffer* buffer) {
RCHECK(ReadWriteHeaderInternal(buffer));
return buffer->ReadWriteString(
&cue_text, buffer->Reading() ? buffer->BytesLeft() : cue_text.size());
}
uint32_t CuePayloadBox::ComputeSizeInternal() {
return HeaderSize() + cue_text.size();
}
VTTEmptyCueBox::VTTEmptyCueBox() {}
VTTEmptyCueBox::~VTTEmptyCueBox() {}
FourCC VTTEmptyCueBox::BoxType() const {
return FOURCC_vtte;
}
bool VTTEmptyCueBox::ReadWriteInternal(BoxBuffer* buffer) {
return ReadWriteHeaderInternal(buffer);
}
uint32_t VTTEmptyCueBox::ComputeSizeInternal() {
return HeaderSize();
}
VTTAdditionalTextBox::VTTAdditionalTextBox() {}
VTTAdditionalTextBox::~VTTAdditionalTextBox() {}
FourCC VTTAdditionalTextBox::BoxType() const {
return FOURCC_vtta;
}
bool VTTAdditionalTextBox::ReadWriteInternal(BoxBuffer* buffer) {
RCHECK(ReadWriteHeaderInternal(buffer));
return buffer->ReadWriteString(
&cue_additional_text,
buffer->Reading() ? buffer->BytesLeft() : cue_additional_text.size());
}
uint32_t VTTAdditionalTextBox::ComputeSizeInternal() {
return HeaderSize() + cue_additional_text.size();
}
VTTCueBox::VTTCueBox() {}
VTTCueBox::~VTTCueBox() {}
FourCC VTTCueBox::BoxType() const {
return FOURCC_vttc;
}
bool VTTCueBox::ReadWriteInternal(BoxBuffer* buffer) {
RCHECK(ReadWriteHeaderInternal(buffer) &&
buffer->PrepareChildren() &&
buffer->ReadWriteChild(&cue_source_id) &&
buffer->ReadWriteChild(&cue_id) &&
buffer->ReadWriteChild(&cue_time) &&
buffer->ReadWriteChild(&cue_settings) &&
buffer->ReadWriteChild(&cue_payload));
return true;
}
uint32_t VTTCueBox::ComputeSizeInternal() {
return HeaderSize() + cue_source_id.ComputeSize() + cue_id.ComputeSize() +
cue_time.ComputeSize() + cue_settings.ComputeSize() +
cue_payload.ComputeSize();
}
} // namespace mp4 } // namespace mp4
} // namespace media } // namespace media
} // namespace edash_packager } // namespace edash_packager

View File

@ -23,7 +23,8 @@ enum TrackType {
kInvalid = 0, kInvalid = 0,
kVideo, kVideo,
kAudio, kAudio,
kHint kHint,
kText,
}; };
class BoxBuffer; class BoxBuffer;
@ -233,12 +234,33 @@ struct AudioSampleEntry : Box {
DTSSpecific ddts; DTSSpecific ddts;
}; };
struct WebVTTConfigurationBox : Box {
DECLARE_BOX_METHODS(WebVTTConfigurationBox);
std::string config;
};
struct WebVTTSourceLabelBox : Box {
DECLARE_BOX_METHODS(WebVTTSourceLabelBox);
std::string source_label;
};
struct WVTTSampleEntry : Box {
DECLARE_BOX_METHODS(WVTTSampleEntry);
uint16_t data_reference_index;
WebVTTConfigurationBox config;
WebVTTSourceLabelBox label;
// Optional MPEG4BitRateBox.
};
struct SampleDescription : FullBox { struct SampleDescription : FullBox {
DECLARE_BOX_METHODS(SampleDescription); DECLARE_BOX_METHODS(SampleDescription);
TrackType type; TrackType type;
std::vector<VideoSampleEntry> video_entries; std::vector<VideoSampleEntry> video_entries;
std::vector<AudioSampleEntry> audio_entries; std::vector<AudioSampleEntry> audio_entries;
std::vector<WVTTSampleEntry> wvtt_entries;
}; };
struct DecodingTime { struct DecodingTime {
@ -358,6 +380,10 @@ struct SoundMediaHeader : FullBox {
uint16_t balance; uint16_t balance;
}; };
struct SubtitleMediaHeader : FullBox {
DECLARE_BOX_METHODS(SubtitleMediaHeader);
};
struct DataEntryUrl : FullBox { struct DataEntryUrl : FullBox {
DECLARE_BOX_METHODS(DataEntryUrl); DECLARE_BOX_METHODS(DataEntryUrl);
@ -385,6 +411,7 @@ struct MediaInformation : Box {
// Exactly one specific meida header shall be present, vmhd, smhd, hmhd, nmhd. // Exactly one specific meida header shall be present, vmhd, smhd, hmhd, nmhd.
VideoMediaHeader vmhd; VideoMediaHeader vmhd;
SoundMediaHeader smhd; SoundMediaHeader smhd;
SubtitleMediaHeader sthd;
}; };
struct Media : Box { struct Media : Box {
@ -591,6 +618,50 @@ struct MediaData : Box {
uint32_t data_size; uint32_t data_size;
}; };
struct CueSourceIDBox : Box {
DECLARE_BOX_METHODS(CueSourceIDBox);
int32_t source_id;
};
struct CueTimeBox : Box {
DECLARE_BOX_METHODS(CueTimeBox);
std::string cue_current_time;
};
struct CueIDBox : Box {
DECLARE_BOX_METHODS(CueIDBox);
std::string cue_id;
};
struct CueSettingsBox : Box {
DECLARE_BOX_METHODS(CueSettingsBox);
std::string settings;
};
struct CuePayloadBox : Box {
DECLARE_BOX_METHODS(CuePayloadBox);
std::string cue_text;
};
struct VTTEmptyCueBox : Box {
DECLARE_BOX_METHODS(VTTEmptyCueBox);
};
struct VTTAdditionalTextBox : Box {
DECLARE_BOX_METHODS(VTTAdditionalTextBox);
std::string cue_additional_text;
};
struct VTTCueBox : Box {
DECLARE_BOX_METHODS(VTTCueBox);
CueSourceIDBox cue_source_id;
CueIDBox cue_id;
CueTimeBox cue_time;
CueSettingsBox cue_settings;
CuePayloadBox cue_payload;
};
#undef DECLARE_BOX #undef DECLARE_BOX
} // namespace mp4 } // namespace mp4

View File

@ -209,6 +209,21 @@ inline bool operator==(const AudioSampleEntry& lhs,
lhs.ddts == rhs.ddts; lhs.ddts == rhs.ddts;
} }
inline bool operator==(const WebVTTConfigurationBox& lhs,
const WebVTTConfigurationBox& rhs) {
return lhs.config == rhs.config;
}
inline bool operator==(const WebVTTSourceLabelBox& lhs,
const WebVTTSourceLabelBox& rhs) {
return lhs.source_label == rhs.source_label;
}
inline bool operator==(const WVTTSampleEntry& lhs,
const WVTTSampleEntry& rhs) {
return lhs.config == rhs.config && lhs.label == rhs.label;
}
inline bool operator==(const MediaHeader& lhs, const MediaHeader& rhs) { inline bool operator==(const MediaHeader& lhs, const MediaHeader& rhs) {
return lhs.creation_time == rhs.creation_time && return lhs.creation_time == rhs.creation_time &&
lhs.modification_time == rhs.modification_time && lhs.modification_time == rhs.modification_time &&
@ -229,6 +244,11 @@ inline bool operator==(const SoundMediaHeader& lhs,
return lhs.balance == rhs.balance; return lhs.balance == rhs.balance;
} }
inline bool operator==(const SubtitleMediaHeader& lhs,
const SubtitleMediaHeader& rhs) {
return true;
}
inline bool operator==(const DataEntryUrl& lhs, const DataEntryUrl& rhs) { inline bool operator==(const DataEntryUrl& lhs, const DataEntryUrl& rhs) {
return lhs.flags == rhs.flags && lhs.location == rhs.location; return lhs.flags == rhs.flags && lhs.location == rhs.location;
} }
@ -366,6 +386,47 @@ inline bool operator==(const SegmentIndex& lhs, const SegmentIndex& rhs) {
lhs.references == rhs.references; lhs.references == rhs.references;
} }
inline bool operator==(const CueSourceIDBox& lhs,
const CueSourceIDBox& rhs) {
return lhs.source_id == rhs.source_id;
}
inline bool operator==(const CueTimeBox& lhs,
const CueTimeBox& rhs) {
return lhs.cue_current_time == rhs.cue_current_time;
}
inline bool operator==(const CueIDBox& lhs,
const CueIDBox& rhs) {
return lhs.cue_id == rhs.cue_id;
}
inline bool operator==(const CueSettingsBox& lhs,
const CueSettingsBox& rhs) {
return lhs.settings == rhs.settings;
}
inline bool operator==(const CuePayloadBox& lhs,
const CuePayloadBox& rhs) {
return lhs.cue_text == rhs.cue_text;
}
inline bool operator==(const VTTEmptyCueBox& lhs, const VTTEmptyCueBox& rhs) {
return true;
}
inline bool operator==(const VTTAdditionalTextBox& lhs,
const VTTAdditionalTextBox& rhs) {
return lhs.cue_additional_text == rhs.cue_additional_text;
}
inline bool operator==(const VTTCueBox& lhs,
const VTTCueBox& rhs) {
return lhs.cue_source_id == rhs.cue_source_id && lhs.cue_id == rhs.cue_id &&
lhs.cue_time == rhs.cue_time && lhs.cue_settings == rhs.cue_settings &&
lhs.cue_payload == rhs.cue_payload;
}
} // namespace mp4 } // namespace mp4
} // namespace media } // namespace media
} // namespace edash_packager } // namespace edash_packager

View File

@ -335,6 +335,33 @@ class BoxDefinitionsTestGeneral : public testing::Test {
void Modify(AudioSampleEntry* enca) { enca->channelcount = 2; } void Modify(AudioSampleEntry* enca) { enca->channelcount = 2; }
void Fill(WebVTTConfigurationBox* vttc) {
vttc->config = "WEBVTT";
}
void Modify(WebVTTConfigurationBox* vttc) {
vttc->config = "WEBVTT\n"
"Region: id=someting width=40\% lines=3";
}
void Fill(WebVTTSourceLabelBox* vlab) {
vlab->source_label = "some_label";
}
void Modify(WebVTTSourceLabelBox* vlab) {
vlab->source_label = "another_label";
}
void Fill(WVTTSampleEntry* wvtt) {
Fill(&wvtt->config);
Fill(&wvtt->label);
}
void Modify(WVTTSampleEntry* wvtt) {
Modify(&wvtt->config);
Modify(&wvtt->label);
}
void Fill(SampleDescription* stsd) { void Fill(SampleDescription* stsd) {
stsd->type = kSampleDescriptionTrackType; stsd->type = kSampleDescriptionTrackType;
stsd->video_entries.resize(1); stsd->video_entries.resize(1);
@ -475,6 +502,9 @@ class BoxDefinitionsTestGeneral : public testing::Test {
void Modify(SoundMediaHeader* smhd) { smhd->balance /= 2; } void Modify(SoundMediaHeader* smhd) { smhd->balance /= 2; }
void Fill(SubtitleMediaHeader* sthd) {}
void Modify(SubtitleMediaHeader* sthd) {}
void Fill(DataEntryUrl* url) { void Fill(DataEntryUrl* url) {
url->flags = 2; url->flags = 2;
url->location.assign(kData8, kData8 + arraysize(kData8)); url->location.assign(kData8, kData8 + arraysize(kData8));
@ -718,6 +748,73 @@ class BoxDefinitionsTestGeneral : public testing::Test {
sidx->version = 1; sidx->version = 1;
} }
void Fill(CueSourceIDBox* vsid) {
vsid->source_id = 5;
}
void Modify(CueSourceIDBox* vsid) {
vsid->source_id = 100;
}
void Fill(CueTimeBox* ctim) {
ctim->cue_current_time = "00:19:00.000";
}
void Modify(CueTimeBox* ctim) {
ctim->cue_current_time = "00:20:01.291";
}
void Fill(CueIDBox* iden) {
iden->cue_id = "some_id";
}
void Modify(CueIDBox* iden) {
iden->cue_id = "another_id";
}
void Fill(CueSettingsBox* sttg) {
sttg->settings = "align:left";
}
void Modify(CueSettingsBox* sttg) {
sttg->settings = "align:right";
}
void Fill(CuePayloadBox* payl) {
payl->cue_text = "hello";
}
void Modify(CuePayloadBox* payl) {
payl->cue_text = "hi";
}
void Fill(VTTEmptyCueBox* vtte) {}
void Modify(VTTEmptyCueBox* vtte) {}
void Fill(VTTAdditionalTextBox* vtta) {
vtta->cue_additional_text = "NOTE some comment";
}
void Modify(VTTAdditionalTextBox* vtta) {
vtta->cue_additional_text = "NOTE another comment";
}
void Fill(VTTCueBox* vttc) {
Fill(&vttc->cue_source_id);
Fill(&vttc->cue_id);
Fill(&vttc->cue_time);
Fill(&vttc->cue_settings);
Fill(&vttc->cue_payload);
}
void Modify(VTTCueBox* vttc) {
Modify(&vttc->cue_source_id);
Modify(&vttc->cue_id);
Modify(&vttc->cue_time);
Modify(&vttc->cue_settings);
Modify(&vttc->cue_payload);
}
bool IsOptional(const SampleAuxiliaryInformationOffset* box) { return true; } bool IsOptional(const SampleAuxiliaryInformationOffset* box) { return true; }
bool IsOptional(const SampleAuxiliaryInformationSize* box) { return true; } bool IsOptional(const SampleAuxiliaryInformationSize* box) { return true; }
bool IsOptional(const ProtectionSchemeInfo* box) { return true; } bool IsOptional(const ProtectionSchemeInfo* box) { return true; }
@ -726,12 +823,18 @@ class BoxDefinitionsTestGeneral : public testing::Test {
bool IsOptional(const CodecConfigurationRecord* box) { return true; } bool IsOptional(const CodecConfigurationRecord* box) { return true; }
bool IsOptional(const PixelAspectRatio* box) { return true; } bool IsOptional(const PixelAspectRatio* box) { return true; }
bool IsOptional(const ElementaryStreamDescriptor* box) { return true; } bool IsOptional(const ElementaryStreamDescriptor* box) { return true; }
// Recommended, but optional.
bool IsOptional(const WebVTTSourceLabelBox* box) { return true; }
bool IsOptional(const CompositionTimeToSample* box) { return true; } bool IsOptional(const CompositionTimeToSample* box) { return true; }
bool IsOptional(const SyncSample* box) { return true; } bool IsOptional(const SyncSample* box) { return true; }
bool IsOptional(const MovieExtendsHeader* box) { return true; } bool IsOptional(const MovieExtendsHeader* box) { return true; }
bool IsOptional(const MovieExtends* box) { return true; } bool IsOptional(const MovieExtends* box) { return true; }
bool IsOptional(const SampleToGroup* box) { return true; } bool IsOptional(const SampleToGroup* box) { return true; }
bool IsOptional(const SampleGroupDescription* box) { return true; } bool IsOptional(const SampleGroupDescription* box) { return true; }
bool IsOptional(const CueSourceIDBox* box) { return true; }
bool IsOptional(const CueIDBox* box) { return true; }
bool IsOptional(const CueTimeBox* box) { return true; }
bool IsOptional(const CueSettingsBox* box) { return true; }
protected: protected:
scoped_ptr<BufferWriter> buffer_; scoped_ptr<BufferWriter> buffer_;
@ -758,6 +861,9 @@ typedef testing::Types<
VideoSampleEntry, VideoSampleEntry,
ElementaryStreamDescriptor, ElementaryStreamDescriptor,
AudioSampleEntry, AudioSampleEntry,
WebVTTConfigurationBox,
WebVTTSourceLabelBox,
WVTTSampleEntry,
SampleDescription, SampleDescription,
DecodingTimeToSample, DecodingTimeToSample,
CompositionTimeToSample, CompositionTimeToSample,
@ -771,6 +877,7 @@ typedef testing::Types<
MediaHeader, MediaHeader,
VideoMediaHeader, VideoMediaHeader,
SoundMediaHeader, SoundMediaHeader,
SubtitleMediaHeader,
DataEntryUrl, DataEntryUrl,
DataReference, DataReference,
DataInformation, DataInformation,
@ -783,17 +890,25 @@ typedef testing::Types<
Movie, Movie,
TrackFragmentDecodeTime, TrackFragmentDecodeTime,
MovieFragmentHeader, MovieFragmentHeader,
TrackFragmentHeader, TrackFragmentHeader> Boxes;
TrackFragmentRun,
TrackFragment,
MovieFragment,
SegmentIndex> Boxes;
// GTEST support a maximum of 50 types in the template list, so we have to // GTEST support a maximum of 50 types in the template list, so we have to
// break it into two groups. // break it into two groups.
typedef testing::Types< typedef testing::Types<
TrackFragmentRun,
TrackFragment,
MovieFragment,
SegmentIndex,
SampleToGroup, SampleToGroup,
SampleGroupDescription> Boxes2; SampleGroupDescription,
CueSourceIDBox,
CueTimeBox,
CueIDBox,
CueSettingsBox,
CuePayloadBox,
VTTEmptyCueBox,
VTTAdditionalTextBox,
VTTCueBox> Boxes2;
TYPED_TEST_CASE_P(BoxDefinitionsTestGeneral); TYPED_TEST_CASE_P(BoxDefinitionsTestGeneral);

View File

@ -11,6 +11,7 @@ namespace edash_packager {
namespace media { namespace media {
namespace mp4 { namespace mp4 {
// TODO(rkuroiwa): Make these case sensitive. e.g. FOURCC_avc1.
enum FourCC { enum FourCC {
FOURCC_NULL = 0, FOURCC_NULL = 0,
FOURCC_AVC1 = 0x61766331, FOURCC_AVC1 = 0x61766331,
@ -88,7 +89,9 @@ enum FourCC {
FOURCC_STTS = 0x73747473, FOURCC_STTS = 0x73747473,
FOURCC_STYP = 0x73747970, FOURCC_STYP = 0x73747970,
FOURCC_STZ2 = 0x73747a32, FOURCC_STZ2 = 0x73747a32,
FOURCC_SUBT = 0x73756274,
FOURCC_TENC = 0x74656e63, FOURCC_TENC = 0x74656e63,
FOURCC_TEXT = 0x74657874,
FOURCC_TFDT = 0x74666474, FOURCC_TFDT = 0x74666474,
FOURCC_TFHD = 0x74666864, FOURCC_TFHD = 0x74666864,
FOURCC_TKHD = 0x746b6864, FOURCC_TKHD = 0x746b6864,
@ -97,8 +100,8 @@ enum FourCC {
FOURCC_TREX = 0x74726578, FOURCC_TREX = 0x74726578,
FOURCC_TRUN = 0x7472756e, FOURCC_TRUN = 0x7472756e,
FOURCC_UDTA = 0x75647461, FOURCC_UDTA = 0x75647461,
FOURCC_URL = 0x75726c20, FOURCC_URL = 0x75726c20,
FOURCC_URN = 0x75726e20, FOURCC_URN = 0x75726e20,
FOURCC_UUID = 0x75756964, FOURCC_UUID = 0x75756964,
FOURCC_VIDE = 0x76696465, FOURCC_VIDE = 0x76696465,
FOURCC_VMHD = 0x766d6864, FOURCC_VMHD = 0x766d6864,
@ -107,6 +110,18 @@ enum FourCC {
FOURCC_VP10 = 0x76703130, FOURCC_VP10 = 0x76703130,
FOURCC_VPCC = 0x76706343, FOURCC_VPCC = 0x76706343,
FOURCC_WIDE = 0x77696465, FOURCC_WIDE = 0x77696465,
FOURCC_ctim = 0x6374696d,
FOURCC_iden = 0x6964656e,
FOURCC_payl = 0x7061796c,
FOURCC_sthd = 0x73746864,
FOURCC_sttg = 0x73747467,
FOURCC_vlab = 0x766c6162,
FOURCC_vsid = 0x76736964,
FOURCC_vttC = 0x76747443,
FOURCC_vtta = 0x76747461,
FOURCC_vttc = 0x76747463,
FOURCC_vtte = 0x76747465,
FOURCC_wvtt = 0x77767474,
}; };
const inline std::string FourCCToString(FourCC fourcc) { const inline std::string FourCCToString(FourCC fourcc) {