Move and rename webvtt fragmenter to webvtt sample converter

- The class should be used to generate samples from the demuxer.

Change-Id: If7f245e5809de8773c0b1cf08673ae62dfeffe09
This commit is contained in:
Rintaro Kuroiwa 2017-02-13 14:25:34 -08:00
parent 593f513c83
commit 5c07ff6b1c
9 changed files with 196 additions and 179 deletions

View File

@ -46,15 +46,12 @@
'sync_sample_iterator.h', 'sync_sample_iterator.h',
'track_run_iterator.cc', 'track_run_iterator.cc',
'track_run_iterator.h', 'track_run_iterator.h',
'webvtt_fragmenter.cc',
'webvtt_fragmenter.h',
], ],
'dependencies': [ 'dependencies': [
'../../../third_party/boringssl/boringssl.gyp:boringssl', '../../../third_party/boringssl/boringssl.gyp:boringssl',
'../../base/media_base.gyp:media_base', '../../base/media_base.gyp:media_base',
'../../codecs/codecs.gyp:codecs', '../../codecs/codecs.gyp:codecs',
'../../event/media_event.gyp:media_event', '../../event/media_event.gyp:media_event',
'../../formats/webvtt/webvtt.gyp:webvtt',
], ],
}, },
{ {
@ -69,7 +66,6 @@
'mp4_media_parser_unittest.cc', 'mp4_media_parser_unittest.cc',
'sync_sample_iterator_unittest.cc', 'sync_sample_iterator_unittest.cc',
'track_run_iterator_unittest.cc', 'track_run_iterator_unittest.cc',
'webvtt_fragmenter_unittest.cc',
], ],
'dependencies': [ 'dependencies': [
'../../../testing/gtest.gyp:gtest', '../../../testing/gtest.gyp:gtest',

View File

@ -0,0 +1,60 @@
#include "packager/media/formats/webvtt/cue.h"
#include "packager/base/strings/string_util.h"
namespace shaka {
namespace media {
Cue::Cue() : start_time(0), duration(0) {}
Cue::~Cue() {}
// Mapping:
// comment --> side data (and side data only sample)
// settings --> side data
// start_time --> pts
std::shared_ptr<MediaSample> CueToMediaSample(const Cue& cue) {
const bool kKeyFrame = true;
if (!cue.comment.empty()) {
const std::string comment = base::JoinString(cue.comment, "\n");
return MediaSample::FromMetadata(
reinterpret_cast<const uint8_t*>(comment.data()), comment.size());
}
const std::string payload = base::JoinString(cue.payload, "\n");
std::shared_ptr<MediaSample> media_sample = MediaSample::CopyFrom(
reinterpret_cast<const uint8_t*>(payload.data()), payload.size(),
reinterpret_cast<const uint8_t*>(cue.settings.data()),
cue.settings.size(), !kKeyFrame);
media_sample->set_config_id(cue.identifier);
media_sample->set_pts(cue.start_time);
media_sample->set_duration(cue.duration);
return media_sample;
}
// TODO(rkuroiwa): Cue gets converted to MediaSample in WebVttMediaParser and
// then back to Cue in the muxer. Consider making MediaSample a protobuf or make
// Cue a protobuf and (ab)use MediaSample::data() to store serialized Cue.
Cue MediaSampleToCue(const MediaSample& sample) {
Cue cue;
if (sample.data_size() == 0) {
std::string comment(sample.side_data(),
sample.side_data() + sample.side_data_size());
cue.comment.push_back(comment);
return cue;
}
std::string payload(sample.data(), sample.data() + sample.data_size());
cue.payload.push_back(payload);
cue.identifier.assign(sample.config_id());
cue.start_time = sample.pts();
cue.duration = sample.duration();
if (sample.side_data_size() != 0) {
cue.settings.assign(sample.side_data(),
sample.side_data() + sample.side_data_size());
}
return cue;
}
} // namespace media
} // namespace shaka

View File

@ -0,0 +1,38 @@
#include <stdint.h>
#include <memory>
#include <string>
#include <vector>
#include "packager/media/base/media_sample.h"
namespace shaka {
namespace media {
// If comment is not empty, then this is metadata and other fields must
// be empty.
// Data that can be multiline are vector of strings.
struct Cue {
Cue();
~Cue();
std::string identifier;
uint64_t start_time;
uint64_t duration;
std::string settings;
std::vector<std::string> payload;
std::vector<std::string> comment;
};
/// Convert Cue to MediaSample.
/// @param cue data.
/// @return @a cue converted to a MediaSample.
std::shared_ptr<MediaSample> CueToMediaSample(const Cue& cue);
/// Convert MediaSample to Cue.
/// @param sample to be converted.
/// @return @a sample converted to Cue.
Cue MediaSampleToCue(const MediaSample& sample);
} // namespace media
} // namespace shaka

View File

@ -13,12 +13,17 @@
'target_name': 'webvtt', 'target_name': 'webvtt',
'type': '<(component)', 'type': '<(component)',
'sources': [ 'sources': [
'cue.cc',
'cue.h',
'webvtt_media_parser.cc', 'webvtt_media_parser.cc',
'webvtt_media_parser.h', 'webvtt_media_parser.h',
'webvtt_sample_converter.cc',
'webvtt_sample_converter.h',
], ],
'dependencies': [ 'dependencies': [
'../../../base/base.gyp:base', '../../../base/base.gyp:base',
'../../base/media_base.gyp:media_base', '../../base/media_base.gyp:media_base',
'../../formats/mp4/mp4.gyp:mp4',
], ],
}, },
{ {
@ -26,6 +31,7 @@
'type': '<(gtest_target_type)', 'type': '<(gtest_target_type)',
'sources': [ 'sources': [
'webvtt_media_parser_unittest.cc', 'webvtt_media_parser_unittest.cc',
'webvtt_sample_converter_unittest.cc',
], ],
'dependencies': [ 'dependencies': [
'../../../testing/gmock.gyp:gmock', '../../../testing/gmock.gyp:gmock',

View File

@ -186,57 +186,6 @@ bool ParseTimingAndSettingsLine(const std::string& line,
} // namespace } // namespace
Cue::Cue() : start_time(0), duration(0) {}
Cue::~Cue() {}
// Mapping:
// comment --> side data (and side data only sample)
// settings --> side data
// start_time --> pts
std::shared_ptr<MediaSample> CueToMediaSample(const Cue& cue) {
const bool kKeyFrame = true;
if (!cue.comment.empty()) {
const std::string comment = base::JoinString(cue.comment, "\n");
return MediaSample::FromMetadata(
reinterpret_cast<const uint8_t*>(comment.data()), comment.size());
}
const std::string payload = base::JoinString(cue.payload, "\n");
std::shared_ptr<MediaSample> media_sample = MediaSample::CopyFrom(
reinterpret_cast<const uint8_t*>(payload.data()), payload.size(),
reinterpret_cast<const uint8_t*>(cue.settings.data()),
cue.settings.size(), !kKeyFrame);
media_sample->set_config_id(cue.identifier);
media_sample->set_pts(cue.start_time);
media_sample->set_duration(cue.duration);
return media_sample;
}
// TODO(rkuroiwa): Cue gets converted to MediaSample in WebVttMediaParser and
// then back to Cue in the muxer. Consider making MediaSample a protobuf or make
// Cue a protobuf and (ab)use MediaSample::data() to store serialized Cue.
Cue MediaSampleToCue(const MediaSample& sample) {
Cue cue;
if (sample.data_size() == 0) {
std::string comment(sample.side_data(),
sample.side_data() + sample.side_data_size());
cue.comment.push_back(comment);
return cue;
}
std::string payload(sample.data(), sample.data() + sample.data_size());
cue.payload.push_back(payload);
cue.identifier.assign(sample.config_id());
cue.start_time = sample.pts();
cue.duration = sample.duration();
if (sample.side_data_size() != 0) {
cue.settings.assign(sample.side_data(),
sample.side_data() + sample.side_data_size());
}
return cue;
}
WebVttMediaParser::WebVttMediaParser() : state_(kHeader) {} WebVttMediaParser::WebVttMediaParser() : state_(kHeader) {}
WebVttMediaParser::~WebVttMediaParser() {} WebVttMediaParser::~WebVttMediaParser() {}

View File

@ -13,35 +13,11 @@
#include "packager/base/compiler_specific.h" #include "packager/base/compiler_specific.h"
#include "packager/media/base/media_parser.h" #include "packager/media/base/media_parser.h"
#include "packager/media/formats/webvtt/cue.h"
namespace shaka { namespace shaka {
namespace media { namespace media {
// If comment is not empty, then this is metadata and other fields must
// be empty.
// Data that can be multiline are vector of strings.
struct Cue {
Cue();
~Cue();
std::string identifier;
uint64_t start_time;
uint64_t duration;
std::string settings;
std::vector<std::string> payload;
std::vector<std::string> comment;
};
/// Convert Cue to MediaSample.
/// @param cue data.
/// @return @a cue converted to a MediaSample.
std::shared_ptr<MediaSample> CueToMediaSample(const Cue& cue);
/// Convert MediaSample to Cue.
/// @param sample to be converted.
/// @return @a sample converted to Cue.
Cue MediaSampleToCue(const MediaSample& sample);
// WebVTT parser. // WebVTT parser.
// The input may not be encrypted so decryption_key_source is ignored. // The input may not be encrypted so decryption_key_source is ignored.
class WebVttMediaParser : public MediaParser { class WebVttMediaParser : public MediaParser {

View File

@ -4,7 +4,7 @@
// license that can be found in the LICENSE file or at // license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd // https://developers.google.com/open-source/licenses/bsd
#include "packager/media/formats/mp4/webvtt_fragmenter.h" #include "packager/media/formats/webvtt/webvtt_sample_converter.h"
#include <algorithm> #include <algorithm>
#include <string> #include <string>
@ -18,14 +18,13 @@
namespace shaka { namespace shaka {
namespace media { namespace media {
namespace mp4 {
namespace { namespace {
std::shared_ptr<MediaSample> CreateEmptyCueSample(uint64_t start_time, std::shared_ptr<MediaSample> CreateEmptyCueSample(uint64_t start_time,
uint64_t end_time) { uint64_t end_time) {
DCHECK_GT(end_time, start_time); DCHECK_GT(end_time, start_time);
VTTEmptyCueBox empty_cue_box; mp4::VTTEmptyCueBox empty_cue_box;
std::vector<uint8_t> serialized; std::vector<uint8_t> serialized;
AppendBoxToVector(&empty_cue_box, &serialized); AppendBoxToVector(&empty_cue_box, &serialized);
@ -37,8 +36,8 @@ std::shared_ptr<MediaSample> CreateEmptyCueSample(uint64_t start_time,
return empty_cue_sample; return empty_cue_sample;
} }
VTTCueBox CueBoxFromCue(const Cue& cue) { mp4::VTTCueBox CueBoxFromCue(const Cue& cue) {
VTTCueBox cue_box; mp4::VTTCueBox cue_box;
if (!cue.identifier.empty()) { if (!cue.identifier.empty()) {
cue_box.cue_id.cue_id = cue.identifier; cue_box.cue_id.cue_id = cue.identifier;
} }
@ -77,7 +76,7 @@ std::shared_ptr<MediaSample> CreateVTTCueBoxesSample(
BufferWriter writer; BufferWriter writer;
for (const Cue* cue : cues) { for (const Cue* cue : cues) {
VTTCueBox cue_box = CueBoxFromCue(*cue); mp4::VTTCueBox cue_box = CueBoxFromCue(*cue);
// If there is internal timing, i.e. WebVTT cue timestamp, then // If there is internal timing, i.e. WebVTT cue timestamp, then
// cue_current_time should be populated // cue_current_time should be populated
// "which gives the VTT timestamp associated with the start time of sample." // "which gives the VTT timestamp associated with the start time of sample."
@ -115,7 +114,7 @@ uint64_t GetMinimumPastSweepLine(uint64_t cue_start_time,
} // namespace } // namespace
void AppendBoxToVector(Box* box, std::vector<uint8_t>* output_vector) { void AppendBoxToVector(mp4::Box* box, std::vector<uint8_t>* output_vector) {
BufferWriter writer; BufferWriter writer;
box->Write(&writer); box->Write(&writer);
output_vector->insert(output_vector->end(), output_vector->insert(output_vector->end(),
@ -123,15 +122,15 @@ void AppendBoxToVector(Box* box, std::vector<uint8_t>* output_vector) {
writer.Buffer() + writer.Size()); writer.Buffer() + writer.Size());
} }
WebVttFragmenter::WebVttFragmenter() : next_cue_start_time_(0u) {} WebVttSampleConverter::WebVttSampleConverter() : next_cue_start_time_(0u) {}
WebVttFragmenter::~WebVttFragmenter() {} WebVttSampleConverter::~WebVttSampleConverter() {}
// Note that this |sample| is either a cue or a comment. It does not have any // Note that this |sample| is either a cue or a comment. It does not have any
// info on whether the next cue is overlapping or not. // info on whether the next cue is overlapping or not.
void WebVttFragmenter::PushSample(std::shared_ptr<MediaSample> sample) { void WebVttSampleConverter::PushSample(std::shared_ptr<MediaSample> sample) {
if (sample->data_size() == 0u) { if (sample->data_size() == 0u) {
// A comment. Put it in the buffer and skip. // A comment. Put it in the buffer and skip.
VTTAdditionalTextBox comment; mp4::VTTAdditionalTextBox comment;
comment.cue_additional_text.assign( comment.cue_additional_text.assign(
sample->side_data(), sample->side_data() + sample->side_data_size()); sample->side_data(), sample->side_data() + sample->side_data_size());
additional_texts_.push_back(comment); additional_texts_.push_back(comment);
@ -164,7 +163,7 @@ void WebVttFragmenter::PushSample(std::shared_ptr<MediaSample> sample) {
cues_.erase(cues_.begin(), erase_last_iterator); cues_.erase(cues_.begin(), erase_last_iterator);
} }
void WebVttFragmenter::Flush() { void WebVttSampleConverter::Flush() {
if (cues_.empty()) if (cues_.empty())
return; return;
if (cues_.size() == 1) { if (cues_.size() == 1) {
@ -185,11 +184,11 @@ void WebVttFragmenter::Flush() {
cues_.clear(); cues_.clear();
} }
size_t WebVttFragmenter::ReadySamplesSize() { size_t WebVttSampleConverter::ReadySamplesSize() {
return ready_samples_.size(); return ready_samples_.size();
} }
std::shared_ptr<MediaSample> WebVttFragmenter::PopSample() { std::shared_ptr<MediaSample> WebVttSampleConverter::PopSample() {
CHECK(!ready_samples_.empty()); CHECK(!ready_samples_.empty());
std::shared_ptr<MediaSample> ret = ready_samples_.front(); std::shared_ptr<MediaSample> ret = ready_samples_.front();
ready_samples_.pop_front(); ready_samples_.pop_front();
@ -208,7 +207,7 @@ std::shared_ptr<MediaSample> WebVttFragmenter::PopSample() {
// Change algorithm to create A,B,C samples right away. // Change algorithm to create A,B,C samples right away.
// Note that this requires change to the caller on which cues // Note that this requires change to the caller on which cues
// to remove. // to remove.
bool WebVttFragmenter::HandleAllCuesButLatest() { bool WebVttSampleConverter::HandleAllCuesButLatest() {
DCHECK_GE(cues_.size(), 2u); DCHECK_GE(cues_.size(), 2u);
const Cue& latest_cue = cues_.back(); const Cue& latest_cue = cues_.back();
@ -246,7 +245,7 @@ bool WebVttFragmenter::HandleAllCuesButLatest() {
return processed_cues; return processed_cues;
} }
bool WebVttFragmenter::HandleAllCues() { bool WebVttSampleConverter::HandleAllCues() {
uint64_t latest_time = 0u; uint64_t latest_time = 0u;
for (const Cue& cue : cues_) { for (const Cue& cue : cues_) {
if (cue.start_time + cue.duration > latest_time) if (cue.start_time + cue.duration > latest_time)
@ -259,7 +258,7 @@ bool WebVttFragmenter::HandleAllCues() {
return processed; return processed;
} }
bool WebVttFragmenter::SweepCues(uint64_t sweep_line, bool WebVttSampleConverter::SweepCues(uint64_t sweep_line,
uint64_t sweep_stop_time) { uint64_t sweep_stop_time) {
bool processed_cues = false; bool processed_cues = false;
// This is a sweep line algorithm. For every iteration, it determines active // This is a sweep line algorithm. For every iteration, it determines active
@ -308,6 +307,5 @@ bool WebVttFragmenter::SweepCues(uint64_t sweep_line,
return processed_cues; return processed_cues;
} }
} // namespace mp4
} // namespace media } // namespace media
} // namespace shaka } // namespace shaka

View File

@ -4,24 +4,24 @@
// license that can be found in the LICENSE file or at // license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd // https://developers.google.com/open-source/licenses/bsd
#ifndef PACKAGER_MEDIA_FORMATS_MP4_FRAGMENTER_H_ #ifndef PACKAGER_MEDIA_FORMATS_WEBVTT_WEBVTT_SAMPLE_CONVERTER_H_
#define PACKAGER_MEDIA_FORMATS_MP4_FRAGMENTER_H_ #define PACKAGER_MEDIA_FORMATS_WEBVTT_WEBVTT_SAMPLE_CONVERTER_H_
#include <stdint.h> #include <stdint.h>
#include <list> #include <list>
#include "packager/media/base/status.h" #include "packager/media/base/status.h"
#include "packager/media/formats/mp4/box.h"
#include "packager/media/formats/mp4/box_definitions.h" #include "packager/media/formats/mp4/box_definitions.h"
#include "packager/media/formats/webvtt/webvtt_media_parser.h" #include "packager/media/formats/webvtt/cue.h"
namespace shaka { namespace shaka {
namespace media { namespace media {
namespace mp4 {
/// Appends box to vector. /// Appends box to vector.
/// @param box is the box to be serialized. /// @param box is the box to be serialized.
/// @param output_vector is where the data is appended. /// @param output_vector is where the data is appended.
void AppendBoxToVector(Box* box, std::vector<uint8_t>* output_vector); void AppendBoxToVector(mp4::Box* box, std::vector<uint8_t>* output_vector);
/// According to the spec, when cues overlap, samples must be created.\n /// According to the spec, when cues overlap, samples must be created.\n
/// The example below has 2 WebVTT cues:\n /// The example below has 2 WebVTT cues:\n
@ -51,15 +51,10 @@ void AppendBoxToVector(Box* box, std::vector<uint8_t>* output_vector);
///\n ///\n
/// This class buffers the samples that are passed to AddSample() and creates /// This class buffers the samples that are passed to AddSample() and creates
/// more samples as necessary. /// more samples as necessary.
// TODO(rkuroiwa): Rename this to WebVttSampleConverter, and put this in class WebVttSampleConverter {
// webvtt parser.
// For now, the output (from PopSample()) should still be in ISO-BMFF box form;
// and also to signal that, should have different types for TextStreamInfo. e.g.
// TextStreamInfo::type() returns kIsoBmffStreamText.
class WebVttFragmenter {
public: public:
WebVttFragmenter(); WebVttSampleConverter();
~WebVttFragmenter(); ~WebVttSampleConverter();
/// Add a sample. /// Add a sample.
/// @param sample is the sample to be added. It should contain one VTT cue. /// @param sample is the sample to be added. It should contain one VTT cue.
@ -104,7 +99,7 @@ class WebVttFragmenter {
std::list<Cue> cues_; std::list<Cue> cues_;
// For comment samples. // For comment samples.
std::list<VTTAdditionalTextBox> additional_texts_; std::list<mp4::VTTAdditionalTextBox> additional_texts_;
// Samples that are ready to be processed. // Samples that are ready to be processed.
std::list<std::shared_ptr<MediaSample>> ready_samples_; std::list<std::shared_ptr<MediaSample>> ready_samples_;
@ -114,11 +109,10 @@ class WebVttFragmenter {
// or an empty cue (gap) has to be added. // or an empty cue (gap) has to be added.
uint64_t next_cue_start_time_; uint64_t next_cue_start_time_;
DISALLOW_COPY_AND_ASSIGN(WebVttFragmenter); DISALLOW_COPY_AND_ASSIGN(WebVttSampleConverter);
}; };
} // namespace shaka
} // namespace media } // namespace media
} // namespace edash_packager } // namespace shaka
#endif // PACKAGER_MEDIA_FORMATS_MP4_FRAGMENTER_H_ #endif // PACKAGER_MEDIA_FORMATS_WEBVTT_WEBVTT_SAMPLE_CONVERTER_H_

View File

@ -1,4 +1,4 @@
#include "packager/media/formats/mp4/webvtt_fragmenter.h" #include "packager/media/formats/webvtt/webvtt_sample_converter.h"
#include <gmock/gmock.h> #include <gmock/gmock.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
@ -32,7 +32,7 @@ MATCHER_P3(MatchesStartTimeEndTimeAndData, start_time, end_time, data, "") {
class WebVttFragmenterTest : public ::testing::Test { class WebVttFragmenterTest : public ::testing::Test {
protected: protected:
WebVttFragmenter webvtt_fragmenter_; WebVttSampleConverter webvtt_sample_converter_;
}; };
// Verify that AppednBoxToVector works. // Verify that AppednBoxToVector works.
@ -89,7 +89,7 @@ TEST_F(WebVttFragmenterTest, NoOverlapContiguous) {
sample1->set_dts(0); sample1->set_dts(0);
sample1->set_duration(2000); sample1->set_duration(2000);
webvtt_fragmenter_.PushSample(sample1); webvtt_sample_converter_.PushSample(sample1);
std::shared_ptr<MediaSample> sample2 = std::shared_ptr<MediaSample> sample2 =
MediaSample::CopyFrom(reinterpret_cast<const uint8_t*>(kCueMessage2), MediaSample::CopyFrom(reinterpret_cast<const uint8_t*>(kCueMessage2),
@ -98,22 +98,22 @@ TEST_F(WebVttFragmenterTest, NoOverlapContiguous) {
sample2->set_dts(2000); sample2->set_dts(2000);
sample2->set_duration(1000); sample2->set_duration(1000);
webvtt_fragmenter_.PushSample(sample2); webvtt_sample_converter_.PushSample(sample2);
webvtt_fragmenter_.Flush(); webvtt_sample_converter_.Flush();
EXPECT_EQ(2u, webvtt_fragmenter_.ReadySamplesSize()); EXPECT_EQ(2u, webvtt_sample_converter_.ReadySamplesSize());
VTTCueBox first_cue_data; VTTCueBox first_cue_data;
first_cue_data.cue_payload.cue_text = kCueMessage1; first_cue_data.cue_payload.cue_text = kCueMessage1;
std::vector<uint8_t> expected; std::vector<uint8_t> expected;
AppendBoxToVector(&first_cue_data, &expected); AppendBoxToVector(&first_cue_data, &expected);
EXPECT_THAT(webvtt_fragmenter_.PopSample(), EXPECT_THAT(webvtt_sample_converter_.PopSample(),
MatchesStartTimeEndTimeAndData(0, 2000, expected)); MatchesStartTimeEndTimeAndData(0, 2000, expected));
VTTCueBox second_cue_data; VTTCueBox second_cue_data;
second_cue_data.cue_payload.cue_text = kCueMessage2; second_cue_data.cue_payload.cue_text = kCueMessage2;
expected.clear(); expected.clear();
AppendBoxToVector(&second_cue_data, &expected); AppendBoxToVector(&second_cue_data, &expected);
EXPECT_THAT(webvtt_fragmenter_.PopSample(), EXPECT_THAT(webvtt_sample_converter_.PopSample(),
MatchesStartTimeEndTimeAndData(2000, 3000, expected)); MatchesStartTimeEndTimeAndData(2000, 3000, expected));
} }
@ -126,7 +126,7 @@ TEST_F(WebVttFragmenterTest, Gap) {
sample1->set_dts(0); sample1->set_dts(0);
sample1->set_duration(1000); sample1->set_duration(1000);
webvtt_fragmenter_.PushSample(sample1); webvtt_sample_converter_.PushSample(sample1);
std::shared_ptr<MediaSample> sample2 = std::shared_ptr<MediaSample> sample2 =
MediaSample::CopyFrom(reinterpret_cast<const uint8_t*>(kCueMessage2), MediaSample::CopyFrom(reinterpret_cast<const uint8_t*>(kCueMessage2),
@ -135,30 +135,30 @@ TEST_F(WebVttFragmenterTest, Gap) {
sample2->set_dts(2000); sample2->set_dts(2000);
sample2->set_duration(1000); sample2->set_duration(1000);
webvtt_fragmenter_.PushSample(sample2); webvtt_sample_converter_.PushSample(sample2);
EXPECT_EQ(2u, webvtt_fragmenter_.ReadySamplesSize()); EXPECT_EQ(2u, webvtt_sample_converter_.ReadySamplesSize());
webvtt_fragmenter_.Flush(); webvtt_sample_converter_.Flush();
EXPECT_EQ(3u, webvtt_fragmenter_.ReadySamplesSize()); EXPECT_EQ(3u, webvtt_sample_converter_.ReadySamplesSize());
VTTCueBox first_cue_data; VTTCueBox first_cue_data;
first_cue_data.cue_payload.cue_text = kCueMessage1; first_cue_data.cue_payload.cue_text = kCueMessage1;
std::vector<uint8_t> expected; std::vector<uint8_t> expected;
AppendBoxToVector(&first_cue_data, &expected); AppendBoxToVector(&first_cue_data, &expected);
EXPECT_THAT(webvtt_fragmenter_.PopSample(), EXPECT_THAT(webvtt_sample_converter_.PopSample(),
MatchesStartTimeEndTimeAndData(0, 1000, expected)); MatchesStartTimeEndTimeAndData(0, 1000, expected));
VTTEmptyCueBox empty_cue; VTTEmptyCueBox empty_cue;
expected.clear(); expected.clear();
AppendBoxToVector(&empty_cue, &expected); AppendBoxToVector(&empty_cue, &expected);
EXPECT_THAT(webvtt_fragmenter_.PopSample(), EXPECT_THAT(webvtt_sample_converter_.PopSample(),
MatchesStartTimeEndTimeAndData(1000, 2000, expected)); MatchesStartTimeEndTimeAndData(1000, 2000, expected));
VTTCueBox second_cue_data; VTTCueBox second_cue_data;
second_cue_data.cue_payload.cue_text = kCueMessage2; second_cue_data.cue_payload.cue_text = kCueMessage2;
expected.clear(); expected.clear();
AppendBoxToVector(&second_cue_data, &expected); AppendBoxToVector(&second_cue_data, &expected);
EXPECT_THAT(webvtt_fragmenter_.PopSample(), EXPECT_THAT(webvtt_sample_converter_.PopSample(),
MatchesStartTimeEndTimeAndData(2000, 3000, expected)); MatchesStartTimeEndTimeAndData(2000, 3000, expected));
} }
@ -172,7 +172,7 @@ TEST_F(WebVttFragmenterTest, OverlappingCuesSequential) {
sample1->set_dts(0); sample1->set_dts(0);
sample1->set_duration(2000); sample1->set_duration(2000);
webvtt_fragmenter_.PushSample(sample1); webvtt_sample_converter_.PushSample(sample1);
std::shared_ptr<MediaSample> sample2 = std::shared_ptr<MediaSample> sample2 =
MediaSample::CopyFrom(reinterpret_cast<const uint8_t*>(kCueMessage2), MediaSample::CopyFrom(reinterpret_cast<const uint8_t*>(kCueMessage2),
@ -180,7 +180,7 @@ TEST_F(WebVttFragmenterTest, OverlappingCuesSequential) {
sample2->set_pts(1000); sample2->set_pts(1000);
sample2->set_dts(1000); sample2->set_dts(1000);
sample2->set_duration(2000); sample2->set_duration(2000);
webvtt_fragmenter_.PushSample(sample2); webvtt_sample_converter_.PushSample(sample2);
std::shared_ptr<MediaSample> sample3 = std::shared_ptr<MediaSample> sample3 =
MediaSample::CopyFrom(reinterpret_cast<const uint8_t*>(kCueMessage3), MediaSample::CopyFrom(reinterpret_cast<const uint8_t*>(kCueMessage3),
@ -188,18 +188,18 @@ TEST_F(WebVttFragmenterTest, OverlappingCuesSequential) {
sample3->set_pts(1500); sample3->set_pts(1500);
sample3->set_dts(1500); sample3->set_dts(1500);
sample3->set_duration(4000); sample3->set_duration(4000);
webvtt_fragmenter_.PushSample(sample3); webvtt_sample_converter_.PushSample(sample3);
webvtt_fragmenter_.Flush(); webvtt_sample_converter_.Flush();
// There should be 5 samples for [0,1000], [1000,1500], [1500,2000], // There should be 5 samples for [0,1000], [1000,1500], [1500,2000],
// [2000,3000], and [3000, 5500]. // [2000,3000], and [3000, 5500].
EXPECT_EQ(5u, webvtt_fragmenter_.ReadySamplesSize()); EXPECT_EQ(5u, webvtt_sample_converter_.ReadySamplesSize());
VTTCueBox first_cue_data; VTTCueBox first_cue_data;
first_cue_data.cue_payload.cue_text = kCueMessage1; first_cue_data.cue_payload.cue_text = kCueMessage1;
std::vector<uint8_t> expected; std::vector<uint8_t> expected;
AppendBoxToVector(&first_cue_data, &expected); AppendBoxToVector(&first_cue_data, &expected);
EXPECT_THAT(webvtt_fragmenter_.PopSample(), EXPECT_THAT(webvtt_sample_converter_.PopSample(),
MatchesStartTimeEndTimeAndData(0, 1000, expected)); MatchesStartTimeEndTimeAndData(0, 1000, expected));
VTTCueBox second_cue_data; VTTCueBox second_cue_data;
@ -207,7 +207,7 @@ TEST_F(WebVttFragmenterTest, OverlappingCuesSequential) {
expected.clear(); expected.clear();
AppendBoxToVector(&first_cue_data, &expected); AppendBoxToVector(&first_cue_data, &expected);
AppendBoxToVector(&second_cue_data, &expected); AppendBoxToVector(&second_cue_data, &expected);
EXPECT_THAT(webvtt_fragmenter_.PopSample(), EXPECT_THAT(webvtt_sample_converter_.PopSample(),
MatchesStartTimeEndTimeAndData(1000, 1500, expected)); MatchesStartTimeEndTimeAndData(1000, 1500, expected));
VTTCueBox third_cue_data; VTTCueBox third_cue_data;
@ -216,18 +216,18 @@ TEST_F(WebVttFragmenterTest, OverlappingCuesSequential) {
AppendBoxToVector(&first_cue_data, &expected); AppendBoxToVector(&first_cue_data, &expected);
AppendBoxToVector(&second_cue_data, &expected); AppendBoxToVector(&second_cue_data, &expected);
AppendBoxToVector(&third_cue_data, &expected); AppendBoxToVector(&third_cue_data, &expected);
EXPECT_THAT(webvtt_fragmenter_.PopSample(), EXPECT_THAT(webvtt_sample_converter_.PopSample(),
MatchesStartTimeEndTimeAndData(1500, 2000, expected)); MatchesStartTimeEndTimeAndData(1500, 2000, expected));
expected.clear(); expected.clear();
AppendBoxToVector(&second_cue_data, &expected); AppendBoxToVector(&second_cue_data, &expected);
AppendBoxToVector(&third_cue_data, &expected); AppendBoxToVector(&third_cue_data, &expected);
EXPECT_THAT(webvtt_fragmenter_.PopSample(), EXPECT_THAT(webvtt_sample_converter_.PopSample(),
MatchesStartTimeEndTimeAndData(2000, 3000, expected)); MatchesStartTimeEndTimeAndData(2000, 3000, expected));
expected.clear(); expected.clear();
AppendBoxToVector(&third_cue_data, &expected); AppendBoxToVector(&third_cue_data, &expected);
EXPECT_THAT(webvtt_fragmenter_.PopSample(), EXPECT_THAT(webvtt_sample_converter_.PopSample(),
MatchesStartTimeEndTimeAndData(3000, 5500, expected)); MatchesStartTimeEndTimeAndData(3000, 5500, expected));
} }
@ -239,7 +239,7 @@ TEST_F(WebVttFragmenterTest, OverlappingLongCue) {
sample1->set_dts(0); sample1->set_dts(0);
sample1->set_duration(10000); sample1->set_duration(10000);
webvtt_fragmenter_.PushSample(sample1); webvtt_sample_converter_.PushSample(sample1);
std::shared_ptr<MediaSample> sample2 = std::shared_ptr<MediaSample> sample2 =
MediaSample::CopyFrom(reinterpret_cast<const uint8_t*>(kCueMessage2), MediaSample::CopyFrom(reinterpret_cast<const uint8_t*>(kCueMessage2),
@ -247,7 +247,7 @@ TEST_F(WebVttFragmenterTest, OverlappingLongCue) {
sample2->set_pts(1000); sample2->set_pts(1000);
sample2->set_dts(1000); sample2->set_dts(1000);
sample2->set_duration(5000); sample2->set_duration(5000);
webvtt_fragmenter_.PushSample(sample2); webvtt_sample_converter_.PushSample(sample2);
std::shared_ptr<MediaSample> sample3 = std::shared_ptr<MediaSample> sample3 =
MediaSample::CopyFrom(reinterpret_cast<const uint8_t*>(kCueMessage3), MediaSample::CopyFrom(reinterpret_cast<const uint8_t*>(kCueMessage3),
@ -255,7 +255,7 @@ TEST_F(WebVttFragmenterTest, OverlappingLongCue) {
sample3->set_pts(2000); sample3->set_pts(2000);
sample3->set_dts(2000); sample3->set_dts(2000);
sample3->set_duration(1000); sample3->set_duration(1000);
webvtt_fragmenter_.PushSample(sample3); webvtt_sample_converter_.PushSample(sample3);
std::shared_ptr<MediaSample> sample4 = std::shared_ptr<MediaSample> sample4 =
MediaSample::CopyFrom(reinterpret_cast<const uint8_t*>(kCueMessage4), MediaSample::CopyFrom(reinterpret_cast<const uint8_t*>(kCueMessage4),
@ -263,18 +263,18 @@ TEST_F(WebVttFragmenterTest, OverlappingLongCue) {
sample4->set_pts(8000); sample4->set_pts(8000);
sample4->set_dts(8000); sample4->set_dts(8000);
sample4->set_duration(1000); sample4->set_duration(1000);
webvtt_fragmenter_.PushSample(sample4); webvtt_sample_converter_.PushSample(sample4);
webvtt_fragmenter_.Flush(); webvtt_sample_converter_.Flush();
// There should be 7 samples for [0,1000], [1000,2000], [2000,3000], // There should be 7 samples for [0,1000], [1000,2000], [2000,3000],
// [3000,6000], [6000, 8000], [8000, 9000], [9000, 10000]. // [3000,6000], [6000, 8000], [8000, 9000], [9000, 10000].
EXPECT_EQ(7u, webvtt_fragmenter_.ReadySamplesSize()); EXPECT_EQ(7u, webvtt_sample_converter_.ReadySamplesSize());
VTTCueBox first_long_cue_data; VTTCueBox first_long_cue_data;
first_long_cue_data.cue_payload.cue_text = kCueMessage1; first_long_cue_data.cue_payload.cue_text = kCueMessage1;
std::vector<uint8_t> expected; std::vector<uint8_t> expected;
AppendBoxToVector(&first_long_cue_data, &expected); AppendBoxToVector(&first_long_cue_data, &expected);
EXPECT_THAT(webvtt_fragmenter_.PopSample(), EXPECT_THAT(webvtt_sample_converter_.PopSample(),
MatchesStartTimeEndTimeAndData(0, 1000, expected)); MatchesStartTimeEndTimeAndData(0, 1000, expected));
VTTCueBox second_cue_data; VTTCueBox second_cue_data;
@ -282,7 +282,7 @@ TEST_F(WebVttFragmenterTest, OverlappingLongCue) {
expected.clear(); expected.clear();
AppendBoxToVector(&first_long_cue_data, &expected); AppendBoxToVector(&first_long_cue_data, &expected);
AppendBoxToVector(&second_cue_data, &expected); AppendBoxToVector(&second_cue_data, &expected);
EXPECT_THAT(webvtt_fragmenter_.PopSample(), EXPECT_THAT(webvtt_sample_converter_.PopSample(),
MatchesStartTimeEndTimeAndData(1000, 2000, expected)); MatchesStartTimeEndTimeAndData(1000, 2000, expected));
VTTCueBox third_cue_data; VTTCueBox third_cue_data;
@ -291,18 +291,18 @@ TEST_F(WebVttFragmenterTest, OverlappingLongCue) {
AppendBoxToVector(&first_long_cue_data, &expected); AppendBoxToVector(&first_long_cue_data, &expected);
AppendBoxToVector(&second_cue_data, &expected); AppendBoxToVector(&second_cue_data, &expected);
AppendBoxToVector(&third_cue_data, &expected); AppendBoxToVector(&third_cue_data, &expected);
EXPECT_THAT(webvtt_fragmenter_.PopSample(), EXPECT_THAT(webvtt_sample_converter_.PopSample(),
MatchesStartTimeEndTimeAndData(2000, 3000, expected)); MatchesStartTimeEndTimeAndData(2000, 3000, expected));
expected.clear(); expected.clear();
AppendBoxToVector(&first_long_cue_data, &expected); AppendBoxToVector(&first_long_cue_data, &expected);
AppendBoxToVector(&second_cue_data, &expected); AppendBoxToVector(&second_cue_data, &expected);
EXPECT_THAT(webvtt_fragmenter_.PopSample(), EXPECT_THAT(webvtt_sample_converter_.PopSample(),
MatchesStartTimeEndTimeAndData(3000, 6000, expected)); MatchesStartTimeEndTimeAndData(3000, 6000, expected));
expected.clear(); expected.clear();
AppendBoxToVector(&first_long_cue_data, &expected); AppendBoxToVector(&first_long_cue_data, &expected);
EXPECT_THAT(webvtt_fragmenter_.PopSample(), EXPECT_THAT(webvtt_sample_converter_.PopSample(),
MatchesStartTimeEndTimeAndData(6000, 8000, expected)); MatchesStartTimeEndTimeAndData(6000, 8000, expected));
VTTCueBox fourth_cue_data; VTTCueBox fourth_cue_data;
@ -310,12 +310,12 @@ TEST_F(WebVttFragmenterTest, OverlappingLongCue) {
expected.clear(); expected.clear();
AppendBoxToVector(&first_long_cue_data, &expected); AppendBoxToVector(&first_long_cue_data, &expected);
AppendBoxToVector(&fourth_cue_data, &expected); AppendBoxToVector(&fourth_cue_data, &expected);
EXPECT_THAT(webvtt_fragmenter_.PopSample(), EXPECT_THAT(webvtt_sample_converter_.PopSample(),
MatchesStartTimeEndTimeAndData(8000, 9000, expected)); MatchesStartTimeEndTimeAndData(8000, 9000, expected));
expected.clear(); expected.clear();
AppendBoxToVector(&first_long_cue_data, &expected); AppendBoxToVector(&first_long_cue_data, &expected);
EXPECT_THAT(webvtt_fragmenter_.PopSample(), EXPECT_THAT(webvtt_sample_converter_.PopSample(),
MatchesStartTimeEndTimeAndData(9000, 10000, expected)); MatchesStartTimeEndTimeAndData(9000, 10000, expected));
} }
@ -326,16 +326,16 @@ TEST_F(WebVttFragmenterTest, GapAtBeginning) {
sample1->set_pts(1200); sample1->set_pts(1200);
sample1->set_dts(1200); sample1->set_dts(1200);
sample1->set_duration(2000); sample1->set_duration(2000);
webvtt_fragmenter_.PushSample(sample1); webvtt_sample_converter_.PushSample(sample1);
webvtt_fragmenter_.Flush(); webvtt_sample_converter_.Flush();
EXPECT_EQ(1u, webvtt_fragmenter_.ReadySamplesSize()); EXPECT_EQ(1u, webvtt_sample_converter_.ReadySamplesSize());
VTTCueBox cue_data; VTTCueBox cue_data;
cue_data.cue_payload.cue_text = kCueMessage1; cue_data.cue_payload.cue_text = kCueMessage1;
std::vector<uint8_t> expected; std::vector<uint8_t> expected;
AppendBoxToVector(&cue_data, &expected); AppendBoxToVector(&cue_data, &expected);
EXPECT_THAT(webvtt_fragmenter_.PopSample(), EXPECT_THAT(webvtt_sample_converter_.PopSample(),
MatchesStartTimeEndTimeAndData(1200, 3200, expected)); MatchesStartTimeEndTimeAndData(1200, 3200, expected));
} }
@ -348,7 +348,7 @@ TEST_F(WebVttFragmenterTest, SameStartTime) {
sample1->set_dts(0); sample1->set_dts(0);
sample1->set_duration(2000); sample1->set_duration(2000);
webvtt_fragmenter_.PushSample(sample1); webvtt_sample_converter_.PushSample(sample1);
std::shared_ptr<MediaSample> sample2 = std::shared_ptr<MediaSample> sample2 =
MediaSample::CopyFrom(reinterpret_cast<const uint8_t*>(kCueMessage2), MediaSample::CopyFrom(reinterpret_cast<const uint8_t*>(kCueMessage2),
@ -357,9 +357,9 @@ TEST_F(WebVttFragmenterTest, SameStartTime) {
sample2->set_dts(0); sample2->set_dts(0);
sample2->set_duration(1500); sample2->set_duration(1500);
webvtt_fragmenter_.PushSample(sample2); webvtt_sample_converter_.PushSample(sample2);
webvtt_fragmenter_.Flush(); webvtt_sample_converter_.Flush();
EXPECT_EQ(2u, webvtt_fragmenter_.ReadySamplesSize()); EXPECT_EQ(2u, webvtt_sample_converter_.ReadySamplesSize());
VTTCueBox first_cue_data; VTTCueBox first_cue_data;
first_cue_data.cue_payload.cue_text = kCueMessage1; first_cue_data.cue_payload.cue_text = kCueMessage1;
@ -369,12 +369,12 @@ TEST_F(WebVttFragmenterTest, SameStartTime) {
std::vector<uint8_t> expected; std::vector<uint8_t> expected;
AppendBoxToVector(&first_cue_data, &expected); AppendBoxToVector(&first_cue_data, &expected);
AppendBoxToVector(&second_cue_data, &expected); AppendBoxToVector(&second_cue_data, &expected);
EXPECT_THAT(webvtt_fragmenter_.PopSample(), EXPECT_THAT(webvtt_sample_converter_.PopSample(),
MatchesStartTimeEndTimeAndData(0, 1500, expected)); MatchesStartTimeEndTimeAndData(0, 1500, expected));
expected.clear(); expected.clear();
AppendBoxToVector(&first_cue_data, &expected); AppendBoxToVector(&first_cue_data, &expected);
EXPECT_THAT(webvtt_fragmenter_.PopSample(), EXPECT_THAT(webvtt_sample_converter_.PopSample(),
MatchesStartTimeEndTimeAndData(1500, 2000, expected)); MatchesStartTimeEndTimeAndData(1500, 2000, expected));
} }
@ -387,7 +387,7 @@ TEST_F(WebVttFragmenterTest, MoreCases) {
sample1->set_dts(0); sample1->set_dts(0);
sample1->set_duration(2000); sample1->set_duration(2000);
webvtt_fragmenter_.PushSample(sample1); webvtt_sample_converter_.PushSample(sample1);
std::shared_ptr<MediaSample> sample2 = std::shared_ptr<MediaSample> sample2 =
MediaSample::CopyFrom(reinterpret_cast<const uint8_t*>(kCueMessage2), MediaSample::CopyFrom(reinterpret_cast<const uint8_t*>(kCueMessage2),
@ -396,7 +396,7 @@ TEST_F(WebVttFragmenterTest, MoreCases) {
sample2->set_dts(100); sample2->set_dts(100);
sample2->set_duration(100); sample2->set_duration(100);
webvtt_fragmenter_.PushSample(sample2); webvtt_sample_converter_.PushSample(sample2);
std::shared_ptr<MediaSample> sample3 = std::shared_ptr<MediaSample> sample3 =
MediaSample::CopyFrom(reinterpret_cast<const uint8_t*>(kCueMessage3), MediaSample::CopyFrom(reinterpret_cast<const uint8_t*>(kCueMessage3),
@ -404,7 +404,7 @@ TEST_F(WebVttFragmenterTest, MoreCases) {
sample3->set_pts(1500); sample3->set_pts(1500);
sample3->set_dts(1500); sample3->set_dts(1500);
sample3->set_duration(1000); sample3->set_duration(1000);
webvtt_fragmenter_.PushSample(sample3); webvtt_sample_converter_.PushSample(sample3);
std::shared_ptr<MediaSample> sample4 = std::shared_ptr<MediaSample> sample4 =
MediaSample::CopyFrom(reinterpret_cast<const uint8_t*>(kCueMessage4), MediaSample::CopyFrom(reinterpret_cast<const uint8_t*>(kCueMessage4),
@ -412,10 +412,10 @@ TEST_F(WebVttFragmenterTest, MoreCases) {
sample4->set_pts(1500); sample4->set_pts(1500);
sample4->set_dts(1500); sample4->set_dts(1500);
sample4->set_duration(800); sample4->set_duration(800);
webvtt_fragmenter_.PushSample(sample4); webvtt_sample_converter_.PushSample(sample4);
webvtt_fragmenter_.Flush(); webvtt_sample_converter_.Flush();
EXPECT_EQ(6u, webvtt_fragmenter_.ReadySamplesSize()); EXPECT_EQ(6u, webvtt_sample_converter_.ReadySamplesSize());
VTTCueBox first_cue_data; VTTCueBox first_cue_data;
first_cue_data.cue_payload.cue_text = kCueMessage1; first_cue_data.cue_payload.cue_text = kCueMessage1;
@ -428,36 +428,36 @@ TEST_F(WebVttFragmenterTest, MoreCases) {
std::vector<uint8_t> expected; std::vector<uint8_t> expected;
AppendBoxToVector(&first_cue_data, &expected); AppendBoxToVector(&first_cue_data, &expected);
EXPECT_THAT(webvtt_fragmenter_.PopSample(), EXPECT_THAT(webvtt_sample_converter_.PopSample(),
MatchesStartTimeEndTimeAndData(0, 100, expected)); MatchesStartTimeEndTimeAndData(0, 100, expected));
expected.clear(); expected.clear();
AppendBoxToVector(&first_cue_data, &expected); AppendBoxToVector(&first_cue_data, &expected);
AppendBoxToVector(&second_cue_data, &expected); AppendBoxToVector(&second_cue_data, &expected);
EXPECT_THAT(webvtt_fragmenter_.PopSample(), EXPECT_THAT(webvtt_sample_converter_.PopSample(),
MatchesStartTimeEndTimeAndData(100, 200, expected)); MatchesStartTimeEndTimeAndData(100, 200, expected));
expected.clear(); expected.clear();
AppendBoxToVector(&first_cue_data, &expected); AppendBoxToVector(&first_cue_data, &expected);
EXPECT_THAT(webvtt_fragmenter_.PopSample(), EXPECT_THAT(webvtt_sample_converter_.PopSample(),
MatchesStartTimeEndTimeAndData(200, 1500, expected)); MatchesStartTimeEndTimeAndData(200, 1500, expected));
expected.clear(); expected.clear();
AppendBoxToVector(&first_cue_data, &expected); AppendBoxToVector(&first_cue_data, &expected);
AppendBoxToVector(&third_cue_data, &expected); AppendBoxToVector(&third_cue_data, &expected);
AppendBoxToVector(&fourth_cue_data, &expected); AppendBoxToVector(&fourth_cue_data, &expected);
EXPECT_THAT(webvtt_fragmenter_.PopSample(), EXPECT_THAT(webvtt_sample_converter_.PopSample(),
MatchesStartTimeEndTimeAndData(1500, 2000, expected)); MatchesStartTimeEndTimeAndData(1500, 2000, expected));
expected.clear(); expected.clear();
AppendBoxToVector(&third_cue_data, &expected); AppendBoxToVector(&third_cue_data, &expected);
AppendBoxToVector(&fourth_cue_data, &expected); AppendBoxToVector(&fourth_cue_data, &expected);
EXPECT_THAT(webvtt_fragmenter_.PopSample(), EXPECT_THAT(webvtt_sample_converter_.PopSample(),
MatchesStartTimeEndTimeAndData(2000, 2300, expected)); MatchesStartTimeEndTimeAndData(2000, 2300, expected));
expected.clear(); expected.clear();
AppendBoxToVector(&third_cue_data, &expected); AppendBoxToVector(&third_cue_data, &expected);
EXPECT_THAT(webvtt_fragmenter_.PopSample(), EXPECT_THAT(webvtt_sample_converter_.PopSample(),
MatchesStartTimeEndTimeAndData(2300, 2500, expected)); MatchesStartTimeEndTimeAndData(2300, 2500, expected));
} }