2023-12-01 17:32:19 +00:00
|
|
|
// Copyright 2015 Google LLC. All rights reserved.
|
2015-12-22 00:33:55 +00:00
|
|
|
//
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file or at
|
|
|
|
// https://developers.google.com/open-source/licenses/bsd
|
|
|
|
|
2023-12-01 17:32:19 +00:00
|
|
|
#include <packager/media/formats/webm/segmenter_test_base.h>
|
2015-12-22 00:33:55 +00:00
|
|
|
|
2023-12-01 17:32:19 +00:00
|
|
|
#include <absl/log/check.h>
|
|
|
|
|
|
|
|
#include <packager/file/memory_file.h>
|
|
|
|
#include <packager/media/formats/webm/webm_constants.h>
|
|
|
|
#include <packager/version/version.h>
|
2015-12-22 00:33:55 +00:00
|
|
|
|
2016-05-20 21:19:33 +00:00
|
|
|
namespace shaka {
|
2015-12-22 00:33:55 +00:00
|
|
|
namespace media {
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
// The contents of a frame does not mater.
|
2016-01-07 22:50:40 +00:00
|
|
|
const uint8_t kTestMediaSampleData[] = {0xde, 0xad, 0xbe, 0xef, 0x00};
|
|
|
|
const uint8_t kTestMediaSampleSideData[] = {
|
|
|
|
// First 8 bytes of side_data is the BlockAddID element in big endian.
|
|
|
|
0x12, 0x34, 0x56, 0x78, 0x9a, 0x00, 0x00, 0x00,
|
|
|
|
0x73, 0x69, 0x64, 0x65, 0x00};
|
2015-12-22 00:33:55 +00:00
|
|
|
|
|
|
|
const int kTrackId = 1;
|
2021-08-04 18:56:44 +00:00
|
|
|
const int64_t kDurationInSeconds = 8;
|
2016-07-27 00:51:08 +00:00
|
|
|
const Codec kCodec = kCodecVP8;
|
2015-12-22 00:33:55 +00:00
|
|
|
const std::string kCodecString = "vp8";
|
|
|
|
const std::string kLanguage = "en";
|
|
|
|
const uint16_t kWidth = 100;
|
|
|
|
const uint16_t kHeight = 100;
|
|
|
|
const uint16_t kPixelWidth = 100;
|
|
|
|
const uint16_t kPixelHeight = 100;
|
2024-05-11 00:42:34 +00:00
|
|
|
const uint8_t kColorPrimaries = 0;
|
|
|
|
const uint8_t kMatrixCoefficients = 0;
|
2019-09-23 06:24:33 +00:00
|
|
|
const uint8_t kTransferCharacteristics = 0;
|
2017-05-15 16:22:06 +00:00
|
|
|
const int16_t kTrickPlayFactor = 1;
|
2015-12-22 00:33:55 +00:00
|
|
|
const uint8_t kNaluLengthSize = 0;
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
SegmentTestBase::SegmentTestBase() {}
|
|
|
|
|
|
|
|
void SegmentTestBase::SetUp() {
|
2016-07-07 19:34:07 +00:00
|
|
|
SetPackagerVersionForTesting("test");
|
|
|
|
|
2016-04-06 06:32:44 +00:00
|
|
|
output_file_name_ = std::string(kMemoryFilePrefix) + "output-file.webm";
|
2017-05-13 00:02:12 +00:00
|
|
|
cur_timestamp_ = 0;
|
2015-12-22 00:33:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SegmentTestBase::TearDown() {
|
|
|
|
MemoryFile::DeleteAll();
|
|
|
|
}
|
|
|
|
|
2017-01-24 00:55:02 +00:00
|
|
|
std::shared_ptr<MediaSample> SegmentTestBase::CreateSample(
|
2016-01-07 22:50:40 +00:00
|
|
|
KeyFrameFlag key_frame_flag,
|
2021-08-04 18:56:44 +00:00
|
|
|
int64_t duration,
|
2016-01-07 22:50:40 +00:00
|
|
|
SideDataFlag side_data_flag) {
|
2017-01-24 00:55:02 +00:00
|
|
|
std::shared_ptr<MediaSample> sample;
|
2016-01-07 22:50:40 +00:00
|
|
|
const bool is_key_frame = key_frame_flag == kKeyFrame;
|
|
|
|
if (side_data_flag == kGenerateSideData) {
|
|
|
|
sample = MediaSample::CopyFrom(
|
|
|
|
kTestMediaSampleData, sizeof(kTestMediaSampleData),
|
|
|
|
kTestMediaSampleSideData, sizeof(kTestMediaSampleSideData),
|
|
|
|
is_key_frame);
|
|
|
|
} else {
|
|
|
|
sample = MediaSample::CopyFrom(kTestMediaSampleData,
|
|
|
|
sizeof(kTestMediaSampleData), is_key_frame);
|
|
|
|
}
|
2017-05-13 00:02:12 +00:00
|
|
|
sample->set_dts(cur_timestamp_);
|
|
|
|
sample->set_pts(cur_timestamp_);
|
2015-12-22 00:33:55 +00:00
|
|
|
sample->set_duration(duration);
|
|
|
|
|
2017-05-13 00:02:12 +00:00
|
|
|
cur_timestamp_ += duration;
|
2016-01-07 18:33:08 +00:00
|
|
|
return sample;
|
2015-12-22 00:33:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
MuxerOptions SegmentTestBase::CreateMuxerOptions() const {
|
|
|
|
MuxerOptions ret;
|
|
|
|
ret.output_file_name = output_file_name_;
|
|
|
|
// Use memory files for temp storage. Normally this would be a bad idea
|
|
|
|
// since it wouldn't support large files, but for tests the files are small.
|
2016-04-06 06:32:44 +00:00
|
|
|
ret.temp_dir = std::string(kMemoryFilePrefix) + "temp/";
|
2015-12-22 00:33:55 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-05-13 00:02:12 +00:00
|
|
|
VideoStreamInfo* SegmentTestBase::CreateVideoStreamInfo(
|
2021-08-04 18:56:44 +00:00
|
|
|
int32_t time_scale) const {
|
2017-05-15 16:22:06 +00:00
|
|
|
return new VideoStreamInfo(
|
2017-05-13 00:02:12 +00:00
|
|
|
kTrackId, time_scale, kDurationInSeconds * time_scale, kCodec,
|
|
|
|
H26xStreamFormat::kUnSpecified, kCodecString, NULL, 0, kWidth, kHeight,
|
2024-05-11 00:42:34 +00:00
|
|
|
kPixelWidth, kPixelHeight, kColorPrimaries, kMatrixCoefficients,
|
|
|
|
kTransferCharacteristics, kTrickPlayFactor, kNaluLengthSize, kLanguage,
|
|
|
|
false);
|
2015-12-22 00:33:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string SegmentTestBase::OutputFileName() const {
|
|
|
|
return output_file_name_;
|
|
|
|
}
|
|
|
|
|
2017-05-13 00:02:12 +00:00
|
|
|
SegmentTestBase::ClusterParser::ClusterParser() {}
|
2015-12-22 00:33:55 +00:00
|
|
|
|
|
|
|
SegmentTestBase::ClusterParser::~ClusterParser() {}
|
|
|
|
|
|
|
|
void SegmentTestBase::ClusterParser::PopulateFromCluster(
|
|
|
|
const std::string& file_name) {
|
2017-05-13 00:02:12 +00:00
|
|
|
frame_timecodes_.clear();
|
2015-12-22 00:33:55 +00:00
|
|
|
std::string file_contents;
|
|
|
|
ASSERT_TRUE(File::ReadFileToString(file_name.c_str(), &file_contents));
|
|
|
|
|
|
|
|
const uint8_t* data = reinterpret_cast<const uint8_t*>(file_contents.c_str());
|
|
|
|
const size_t size = file_contents.size();
|
|
|
|
WebMListParser cluster_parser(kWebMIdCluster, this);
|
|
|
|
size_t position = 0;
|
|
|
|
while (position < size) {
|
2016-11-09 02:11:13 +00:00
|
|
|
int read = cluster_parser.Parse(data + position,
|
|
|
|
static_cast<int>(size - position));
|
2015-12-22 00:33:55 +00:00
|
|
|
ASSERT_LT(0, read);
|
|
|
|
|
|
|
|
cluster_parser.Reset();
|
|
|
|
position += read;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SegmentTestBase::ClusterParser::PopulateFromSegment(
|
|
|
|
const std::string& file_name) {
|
2017-05-13 00:02:12 +00:00
|
|
|
frame_timecodes_.clear();
|
2015-12-22 00:33:55 +00:00
|
|
|
std::string file_contents;
|
|
|
|
ASSERT_TRUE(File::ReadFileToString(file_name.c_str(), &file_contents));
|
|
|
|
|
|
|
|
const uint8_t* data = reinterpret_cast<const uint8_t*>(file_contents.c_str());
|
|
|
|
const size_t size = file_contents.size();
|
|
|
|
WebMListParser header_parser(kWebMIdEBMLHeader, this);
|
2016-11-09 02:11:13 +00:00
|
|
|
int offset = header_parser.Parse(data, static_cast<int>(size));
|
2015-12-22 00:33:55 +00:00
|
|
|
ASSERT_LT(0, offset);
|
|
|
|
|
|
|
|
WebMListParser segment_parser(kWebMIdSegment, this);
|
2016-11-09 02:11:13 +00:00
|
|
|
ASSERT_LT(
|
|
|
|
0, segment_parser.Parse(data + offset, static_cast<int>(size) - offset));
|
2015-12-22 00:33:55 +00:00
|
|
|
}
|
|
|
|
|
2017-05-13 00:02:12 +00:00
|
|
|
size_t SegmentTestBase::ClusterParser::GetFrameCountForCluster(
|
|
|
|
size_t cluster_index) const {
|
|
|
|
DCHECK_LT(cluster_index, frame_timecodes_.size());
|
|
|
|
return frame_timecodes_[cluster_index].size();
|
|
|
|
}
|
|
|
|
|
|
|
|
int64_t SegmentTestBase::ClusterParser::GetFrameTimecode(
|
|
|
|
size_t cluster_index,
|
|
|
|
size_t frame_index) const {
|
|
|
|
DCHECK_LT(cluster_index, frame_timecodes_.size());
|
|
|
|
DCHECK_LT(frame_index, frame_timecodes_[cluster_index].size());
|
|
|
|
return frame_timecodes_[cluster_index][frame_index];
|
2015-12-22 00:33:55 +00:00
|
|
|
}
|
|
|
|
|
2016-11-09 02:11:13 +00:00
|
|
|
size_t SegmentTestBase::ClusterParser::cluster_count() const {
|
2017-05-13 00:02:12 +00:00
|
|
|
return frame_timecodes_.size();
|
2015-12-22 00:33:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
WebMParserClient* SegmentTestBase::ClusterParser::OnListStart(int id) {
|
|
|
|
if (id == kWebMIdCluster) {
|
|
|
|
if (in_cluster_)
|
|
|
|
return NULL;
|
|
|
|
|
2017-05-13 00:02:12 +00:00
|
|
|
frame_timecodes_.emplace_back();
|
|
|
|
cluster_timecode_ = -1;
|
2015-12-22 00:33:55 +00:00
|
|
|
in_cluster_ = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SegmentTestBase::ClusterParser::OnListEnd(int id) {
|
|
|
|
if (id == kWebMIdCluster) {
|
|
|
|
if (!in_cluster_)
|
|
|
|
return false;
|
|
|
|
in_cluster_ = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SegmentTestBase::ClusterParser::OnUInt(int id, int64_t val) {
|
2017-05-13 00:02:12 +00:00
|
|
|
if (id == kWebMIdTimecode)
|
|
|
|
cluster_timecode_ = val;
|
2015-12-22 00:33:55 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-12-01 17:32:19 +00:00
|
|
|
bool SegmentTestBase::ClusterParser::OnFloat(int /*id*/, double /*val*/) {
|
2015-12-22 00:33:55 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SegmentTestBase::ClusterParser::OnBinary(int id,
|
2017-05-13 00:02:12 +00:00
|
|
|
const uint8_t* data,
|
2023-12-01 17:32:19 +00:00
|
|
|
int /*size*/) {
|
2016-01-07 22:50:40 +00:00
|
|
|
if (in_cluster_ && (id == kWebMIdSimpleBlock || id == kWebMIdBlock)) {
|
2017-05-13 00:02:12 +00:00
|
|
|
if (cluster_timecode_ == -1) {
|
|
|
|
LOG(WARNING) << "Cluster timecode not yet available";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
int timecode = data[1] << 8 | data[2];
|
|
|
|
frame_timecodes_.back().push_back(cluster_timecode_ + timecode);
|
2015-12-22 00:33:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-12-01 17:32:19 +00:00
|
|
|
bool SegmentTestBase::ClusterParser::OnString(int /*id*/,
|
|
|
|
const std::string& /*str*/) {
|
2015-12-22 00:33:55 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace media
|
2016-05-20 21:19:33 +00:00
|
|
|
} // namespace shaka
|