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:
parent
593f513c83
commit
5c07ff6b1c
|
@ -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',
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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',
|
||||||
|
|
|
@ -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() {}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
|
@ -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_
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue