Add support for 4K and 8K content.
Adds UHD1 and UHD2 track types to support 4K and 8K content. Bug: Closes #163 Change-Id: I8fd893725cae88e9944244a48607cbaab591b401
This commit is contained in:
parent
d8d94da250
commit
0c2ee4c844
|
@ -334,6 +334,8 @@ bool CreateRemuxJobs(const StreamDescriptorList& stream_descriptors,
|
|||
if (key_source) {
|
||||
muxer->SetKeySource(key_source,
|
||||
FLAGS_max_sd_pixels,
|
||||
FLAGS_max_hd_pixels,
|
||||
FLAGS_max_uhd1_pixels,
|
||||
FLAGS_clear_lead,
|
||||
FLAGS_crypto_period_duration,
|
||||
GetProtectionScheme(FLAGS_protection_scheme));
|
||||
|
|
|
@ -37,8 +37,18 @@ DEFINE_string(policy,
|
|||
"rights.");
|
||||
DEFINE_int32(max_sd_pixels,
|
||||
768 * 576,
|
||||
"If the video track has more pixels per frame than max_sd_pixels, "
|
||||
"it is considered as HD, SD otherwise. Default: 768 * 576.");
|
||||
"The video track is considered SD if its max pixels per frame is "
|
||||
"no higher than max_sd_pixels. Default: 442368 (768 x 576).");
|
||||
DEFINE_int32(max_hd_pixels,
|
||||
1920 * 1080,
|
||||
"The video track is considered HD if its max pixels per frame is "
|
||||
"higher than max_sd_pixels, but no higher than max_hd_pixels. "
|
||||
"Default: 2073600 (1920 x 1080).");
|
||||
DEFINE_int32(max_uhd1_pixels,
|
||||
4096 * 2160,
|
||||
"The video track is considered UHD1 if its max pixels per frame "
|
||||
"is higher than max_hd_pixels, but no higher than max_uhd1_pixels."
|
||||
" Otherwise it is UHD2. Default: 8847360 (4096 x 2160).");
|
||||
DEFINE_string(signer, "", "The name of the signer.");
|
||||
DEFINE_string(aes_signing_key,
|
||||
"",
|
||||
|
@ -119,6 +129,22 @@ bool ValidateWidevineCryptoFlags() {
|
|||
PrintError("--max_sd_pixels must be positive.");
|
||||
success = false;
|
||||
}
|
||||
if (FLAGS_max_hd_pixels <= 0) {
|
||||
PrintError("--max_hd_pixels must be positive.");
|
||||
success = false;
|
||||
}
|
||||
if (FLAGS_max_uhd1_pixels <= 0) {
|
||||
PrintError("--max_uhd1_pixels must be positive.");
|
||||
success = false;
|
||||
}
|
||||
if (FLAGS_max_hd_pixels <= FLAGS_max_sd_pixels) {
|
||||
PrintError("--max_hd_pixels must be greater than --max_sd_pixels.");
|
||||
success = false;
|
||||
}
|
||||
if (FLAGS_max_uhd1_pixels <= FLAGS_max_hd_pixels) {
|
||||
PrintError("--max_uhd1_pixels must be greater than --max_hd_pixels.");
|
||||
success = false;
|
||||
}
|
||||
|
||||
const bool aes = !FLAGS_signer.empty() && FLAGS_rsa_signing_key_path.empty();
|
||||
const char aes_label[] =
|
||||
|
|
|
@ -18,6 +18,8 @@ DECLARE_string(key_server_url);
|
|||
DECLARE_string(content_id);
|
||||
DECLARE_string(policy);
|
||||
DECLARE_int32(max_sd_pixels);
|
||||
DECLARE_int32(max_hd_pixels);
|
||||
DECLARE_int32(max_uhd1_pixels);
|
||||
DECLARE_string(signer);
|
||||
DECLARE_string(aes_signing_key);
|
||||
DECLARE_string(aes_signing_iv);
|
||||
|
|
|
@ -22,6 +22,10 @@ KeySource::TrackType KeySource::GetTrackTypeFromString(
|
|||
return TRACK_TYPE_SD;
|
||||
if (track_type_string == "HD")
|
||||
return TRACK_TYPE_HD;
|
||||
if (track_type_string == "UHD1")
|
||||
return TRACK_TYPE_UHD1;
|
||||
if (track_type_string == "UHD2")
|
||||
return TRACK_TYPE_UHD2;
|
||||
if (track_type_string == "AUDIO")
|
||||
return TRACK_TYPE_AUDIO;
|
||||
if (track_type_string == "UNSPECIFIED")
|
||||
|
@ -36,6 +40,10 @@ std::string KeySource::TrackTypeToString(TrackType track_type) {
|
|||
return "SD";
|
||||
case TRACK_TYPE_HD:
|
||||
return "HD";
|
||||
case TRACK_TYPE_UHD1:
|
||||
return "UHD1";
|
||||
case TRACK_TYPE_UHD2:
|
||||
return "UHD2";
|
||||
case TRACK_TYPE_AUDIO:
|
||||
return "AUDIO";
|
||||
default:
|
||||
|
|
|
@ -33,9 +33,11 @@ class KeySource {
|
|||
TRACK_TYPE_UNKNOWN = 0,
|
||||
TRACK_TYPE_SD = 1,
|
||||
TRACK_TYPE_HD = 2,
|
||||
TRACK_TYPE_AUDIO = 3,
|
||||
TRACK_TYPE_UNSPECIFIED = 4,
|
||||
NUM_VALID_TRACK_TYPES = 4
|
||||
TRACK_TYPE_UHD1 = 3,
|
||||
TRACK_TYPE_UHD2 = 4,
|
||||
TRACK_TYPE_AUDIO = 5,
|
||||
TRACK_TYPE_UNSPECIFIED = 6,
|
||||
NUM_VALID_TRACK_TYPES = 6
|
||||
};
|
||||
|
||||
KeySource();
|
||||
|
|
|
@ -20,6 +20,8 @@ Muxer::Muxer(const MuxerOptions& options)
|
|||
initialized_(false),
|
||||
encryption_key_source_(NULL),
|
||||
max_sd_pixels_(0),
|
||||
max_hd_pixels_(0),
|
||||
max_uhd1_pixels_(0),
|
||||
clear_lead_in_seconds_(0),
|
||||
crypto_period_duration_in_seconds_(0),
|
||||
protection_scheme_(FOURCC_NULL),
|
||||
|
@ -30,12 +32,16 @@ Muxer::~Muxer() {}
|
|||
|
||||
void Muxer::SetKeySource(KeySource* encryption_key_source,
|
||||
uint32_t max_sd_pixels,
|
||||
uint32_t max_hd_pixels,
|
||||
uint32_t max_uhd1_pixels,
|
||||
double clear_lead_in_seconds,
|
||||
double crypto_period_duration_in_seconds,
|
||||
FourCC protection_scheme) {
|
||||
DCHECK(encryption_key_source);
|
||||
encryption_key_source_ = encryption_key_source;
|
||||
max_sd_pixels_ = max_sd_pixels;
|
||||
max_hd_pixels_ = max_hd_pixels;
|
||||
max_uhd1_pixels_ = max_uhd1_pixels;
|
||||
clear_lead_in_seconds_ = clear_lead_in_seconds;
|
||||
crypto_period_duration_in_seconds_ = crypto_period_duration_in_seconds;
|
||||
protection_scheme_ = protection_scheme;
|
||||
|
|
|
@ -35,12 +35,23 @@ class Muxer {
|
|||
explicit Muxer(const MuxerOptions& options);
|
||||
virtual ~Muxer();
|
||||
|
||||
// TODO(kqyang): refactor max_sd_pixels through crypto_period_duration into
|
||||
// an encapsulated EncryptionParams structure.
|
||||
|
||||
/// Set encryption key source.
|
||||
/// @param encryption_key_source points to the encryption key source. The
|
||||
/// caller retains ownership, and should not be NULL.
|
||||
/// @param max_sd_pixels specifies the threshold to determine whether a video
|
||||
/// track should be considered as SD or HD. If the track has more
|
||||
/// pixels per frame than max_sd_pixels, it is HD, SD otherwise.
|
||||
/// track should be considered as SD. If the max pixels per frame is
|
||||
/// no higher than max_sd_pixels, it is SD.
|
||||
/// @param max_hd_pixels specifies the threshold to determine whether a video
|
||||
/// track should be considered as HD. If the max pixels per frame is
|
||||
/// higher than max_sd_pixels, but no higher than max_hd_pixels,
|
||||
/// it is HD.
|
||||
/// @param max_uhd1_pixels specifies the threshold to determine whether a video
|
||||
/// track should be considered as UHD1. If the max pixels per frame is
|
||||
/// higher than max_hd_pixels, but no higher than max_uhd1_pixels,
|
||||
/// it is UHD1. Otherwise it is UHD2.
|
||||
/// @param clear_lead_in_seconds specifies clear lead duration in seconds.
|
||||
/// @param crypto_period_duration_in_seconds specifies crypto period duration
|
||||
/// in seconds. A positive value means key rotation is enabled, the
|
||||
|
@ -49,6 +60,8 @@ class Muxer {
|
|||
/// 'cbc1', 'cbcs'.
|
||||
void SetKeySource(KeySource* encryption_key_source,
|
||||
uint32_t max_sd_pixels,
|
||||
uint32_t max_hd_pixels,
|
||||
uint32_t max_uhd1_pixels,
|
||||
double clear_lead_in_seconds,
|
||||
double crypto_period_duration_in_seconds,
|
||||
FourCC protection_scheme);
|
||||
|
@ -89,6 +102,8 @@ class Muxer {
|
|||
return encryption_key_source_;
|
||||
}
|
||||
uint32_t max_sd_pixels() const { return max_sd_pixels_; }
|
||||
uint32_t max_hd_pixels() const { return max_hd_pixels_; }
|
||||
uint32_t max_uhd1_pixels() const { return max_uhd1_pixels_; }
|
||||
double clear_lead_in_seconds() const { return clear_lead_in_seconds_; }
|
||||
double crypto_period_duration_in_seconds() const {
|
||||
return crypto_period_duration_in_seconds_;
|
||||
|
@ -120,6 +135,8 @@ class Muxer {
|
|||
std::vector<MediaStream*> streams_;
|
||||
KeySource* encryption_key_source_;
|
||||
uint32_t max_sd_pixels_;
|
||||
uint32_t max_hd_pixels_;
|
||||
uint32_t max_uhd1_pixels_;
|
||||
double clear_lead_in_seconds_;
|
||||
double crypto_period_duration_in_seconds_;
|
||||
FourCC protection_scheme_;
|
||||
|
|
|
@ -155,7 +155,9 @@ std::string GetSegmentName(const std::string& segment_template,
|
|||
}
|
||||
|
||||
KeySource::TrackType GetTrackTypeForEncryption(const StreamInfo& stream_info,
|
||||
uint32_t max_sd_pixels) {
|
||||
uint32_t max_sd_pixels,
|
||||
uint32_t max_hd_pixels,
|
||||
uint32_t max_uhd1_pixels) {
|
||||
if (stream_info.stream_type() == kStreamAudio)
|
||||
return KeySource::TRACK_TYPE_AUDIO;
|
||||
|
||||
|
@ -166,8 +168,14 @@ KeySource::TrackType GetTrackTypeForEncryption(const StreamInfo& stream_info,
|
|||
const VideoStreamInfo& video_stream_info =
|
||||
static_cast<const VideoStreamInfo&>(stream_info);
|
||||
uint32_t pixels = video_stream_info.width() * video_stream_info.height();
|
||||
return (pixels > max_sd_pixels) ? KeySource::TRACK_TYPE_HD
|
||||
: KeySource::TRACK_TYPE_SD;
|
||||
if (pixels > max_uhd1_pixels) {
|
||||
return KeySource::TRACK_TYPE_UHD2;
|
||||
} else if (pixels > max_hd_pixels) {
|
||||
return KeySource::TRACK_TYPE_UHD1;
|
||||
} else if (pixels > max_sd_pixels) {
|
||||
return KeySource::TRACK_TYPE_HD;
|
||||
}
|
||||
return KeySource::TRACK_TYPE_SD;
|
||||
}
|
||||
|
||||
} // namespace media
|
||||
|
|
|
@ -42,10 +42,14 @@ std::string GetSegmentName(const std::string& segment_template,
|
|||
/// Determine the track type for encryption from input.
|
||||
/// @param stream_info is the info of the stream.
|
||||
/// @param max_sd_pixels is the maximum number of pixels to be considered SD.
|
||||
/// Anything above is HD.
|
||||
/// @param max_hd_pixels is the maximum number of pixels to be considered HD.
|
||||
/// @param max_uhd1_pixels is the maximum number of pixels to be considered UHD1.
|
||||
/// Anything above is UHD2.
|
||||
/// @return track type for encryption.
|
||||
KeySource::TrackType GetTrackTypeForEncryption(const StreamInfo& stream_info,
|
||||
uint32_t max_sd_pixels);
|
||||
uint32_t max_sd_pixels,
|
||||
uint32_t max_hd_pixels,
|
||||
uint32_t max_uhd1_pixels);
|
||||
|
||||
} // namespace media
|
||||
} // namespace shaka
|
||||
|
|
|
@ -401,6 +401,12 @@ void WidevineKeySource::FillRequest(bool enable_key_rotation,
|
|||
base::DictionaryValue* track_hd = new base::DictionaryValue();
|
||||
track_hd->SetString("type", "HD");
|
||||
tracks->Append(track_hd);
|
||||
base::DictionaryValue* track_uhd1 = new base::DictionaryValue();
|
||||
track_uhd1->SetString("type", "UHD1");
|
||||
tracks->Append(track_uhd1);
|
||||
base::DictionaryValue* track_uhd2 = new base::DictionaryValue();
|
||||
track_uhd2->SetString("type", "UHD2");
|
||||
tracks->Append(track_uhd2);
|
||||
base::DictionaryValue* track_audio = new base::DictionaryValue();
|
||||
track_audio->SetString("type", "AUDIO");
|
||||
tracks->Append(track_audio);
|
||||
|
|
|
@ -45,13 +45,16 @@ const char kLicenseStatusUnknownError[] = "UNKNOWN_ERROR";
|
|||
|
||||
const char kExpectedRequestMessageFormat[] =
|
||||
"{\"content_id\":\"%s\",\"drm_types\":[\"WIDEVINE\"],\"policy\":\"%s\","
|
||||
"\"tracks\":[{\"type\":\"SD\"},{\"type\":\"HD\"},{\"type\":\"AUDIO\"}]}";
|
||||
"\"tracks\":[{\"type\":\"SD\"},{\"type\":\"HD\"},{\"type\":\"UHD1\"},"
|
||||
"{\"type\":\"UHD2\"},{\"type\":\"AUDIO\"}]}";
|
||||
const char kExpectedRequestMessageWithAssetIdFormat[] =
|
||||
"{\"asset_id\":%u,\"drm_types\":[\"WIDEVINE\"],"
|
||||
"\"tracks\":[{\"type\":\"SD\"},{\"type\":\"HD\"},{\"type\":\"AUDIO\"}]}";
|
||||
"\"tracks\":[{\"type\":\"SD\"},{\"type\":\"HD\"},{\"type\":\"UHD1\"},"
|
||||
"{\"type\":\"UHD2\"},{\"type\":\"AUDIO\"}]}";
|
||||
const char kExpectedRequestMessageWithPsshFormat[] =
|
||||
"{\"drm_types\":[\"WIDEVINE\"],\"pssh_data\":\"%s\","
|
||||
"\"tracks\":[{\"type\":\"SD\"},{\"type\":\"HD\"},{\"type\":\"AUDIO\"}]}";
|
||||
"\"tracks\":[{\"type\":\"SD\"},{\"type\":\"HD\"},{\"type\":\"UHD1\"},"
|
||||
"{\"type\":\"UHD2\"},{\"type\":\"AUDIO\"}]}";
|
||||
const char kExpectedSignedMessageFormat[] =
|
||||
"{\"request\":\"%s\",\"signature\":\"%s\",\"signer\":\"%s\"}";
|
||||
const char kTrackFormat[] =
|
||||
|
@ -99,9 +102,9 @@ std::string GetMockPsshData(const std::string& track_type) {
|
|||
}
|
||||
|
||||
std::string GenerateMockLicenseResponse() {
|
||||
const std::string kTrackTypes[] = {"SD", "HD", "AUDIO"};
|
||||
const std::string kTrackTypes[] = {"SD", "HD", "UHD1", "UHD2", "AUDIO"};
|
||||
std::string tracks;
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
for (size_t i = 0; i < 5; ++i) {
|
||||
if (!tracks.empty())
|
||||
tracks += ",";
|
||||
tracks += base::StringPrintf(
|
||||
|
@ -115,9 +118,9 @@ std::string GenerateMockLicenseResponse() {
|
|||
}
|
||||
|
||||
std::string GenerateMockClassicLicenseResponse() {
|
||||
const std::string kTrackTypes[] = {"SD", "HD", "AUDIO"};
|
||||
const std::string kTrackTypes[] = {"SD", "HD", "UHD1", "UHD2", "AUDIO"};
|
||||
std::string tracks;
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
for (size_t i = 0; i < 5; ++i) {
|
||||
if (!tracks.empty())
|
||||
tracks += ",";
|
||||
tracks += base::StringPrintf(
|
||||
|
@ -180,7 +183,7 @@ class WidevineKeySourceTest : public ::testing::Test,
|
|||
|
||||
void VerifyKeys(bool classic) {
|
||||
EncryptionKey encryption_key;
|
||||
const std::string kTrackTypes[] = {"SD", "HD", "AUDIO"};
|
||||
const std::string kTrackTypes[] = {"SD", "HD", "UHD1", "UHD2", "AUDIO"};
|
||||
for (size_t i = 0; i < arraysize(kTrackTypes); ++i) {
|
||||
ASSERT_OK(widevine_key_source_->GetKey(
|
||||
KeySource::GetTrackTypeFromString(kTrackTypes[i]),
|
||||
|
@ -228,6 +231,10 @@ TEST_P(WidevineKeySourceTest, GetTrackTypeFromString) {
|
|||
KeySource::GetTrackTypeFromString("SD"));
|
||||
EXPECT_EQ(KeySource::TRACK_TYPE_HD,
|
||||
KeySource::GetTrackTypeFromString("HD"));
|
||||
EXPECT_EQ(KeySource::TRACK_TYPE_UHD1,
|
||||
KeySource::GetTrackTypeFromString("UHD1"));
|
||||
EXPECT_EQ(KeySource::TRACK_TYPE_UHD2,
|
||||
KeySource::GetTrackTypeFromString("UHD2"));
|
||||
EXPECT_EQ(KeySource::TRACK_TYPE_AUDIO,
|
||||
KeySource::GetTrackTypeFromString("AUDIO"));
|
||||
EXPECT_EQ(KeySource::TRACK_TYPE_UNKNOWN,
|
||||
|
@ -413,7 +420,8 @@ namespace {
|
|||
const char kCryptoPeriodRequestMessageFormat[] =
|
||||
"{\"content_id\":\"%s\",\"crypto_period_count\":%u,\"drm_types\":["
|
||||
"\"WIDEVINE\"],\"first_crypto_period_index\":%u,\"policy\":\"%s\","
|
||||
"\"tracks\":[{\"type\":\"SD\"},{\"type\":\"HD\"},{\"type\":\"AUDIO\"}]}";
|
||||
"\"tracks\":[{\"type\":\"SD\"},{\"type\":\"HD\"},{\"type\":\"UHD1\"},"
|
||||
"{\"type\":\"UHD2\"},{\"type\":\"AUDIO\"}]}";
|
||||
|
||||
const char kCryptoPeriodTrackFormat[] =
|
||||
"{\"type\":\"%s\",\"key_id\":\"%s\",\"key\":"
|
||||
|
@ -427,12 +435,12 @@ std::string GetMockKey(const std::string& track_type, uint32_t index) {
|
|||
std::string GenerateMockKeyRotationLicenseResponse(
|
||||
uint32_t initial_crypto_period_index,
|
||||
uint32_t crypto_period_count) {
|
||||
const std::string kTrackTypes[] = {"SD", "HD", "AUDIO"};
|
||||
const std::string kTrackTypes[] = {"SD", "HD", "UHD1", "UHD2", "AUDIO"};
|
||||
std::string tracks;
|
||||
for (uint32_t index = initial_crypto_period_index;
|
||||
index < initial_crypto_period_index + crypto_period_count;
|
||||
++index) {
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
for (size_t i = 0; i < 5; ++i) {
|
||||
if (!tracks.empty())
|
||||
tracks += ",";
|
||||
tracks += base::StringPrintf(
|
||||
|
@ -495,8 +503,8 @@ TEST_P(WidevineKeySourceTest, KeyRotationTest) {
|
|||
|
||||
EncryptionKey encryption_key;
|
||||
for (size_t i = 0; i < arraysize(kCryptoPeriodIndexes); ++i) {
|
||||
const std::string kTrackTypes[] = {"SD", "HD", "AUDIO"};
|
||||
for (size_t j = 0; j < 3; ++j) {
|
||||
const std::string kTrackTypes[] = {"SD", "HD", "UHD1", "UHD2", "AUDIO"};
|
||||
for (size_t j = 0; j < 5; ++j) {
|
||||
ASSERT_OK(widevine_key_source_->GetCryptoPeriodKey(
|
||||
kCryptoPeriodIndexes[i],
|
||||
KeySource::GetTrackTypeFromString(kTrackTypes[j]),
|
||||
|
|
|
@ -24,7 +24,8 @@ Status TsMuxer::Initialize() {
|
|||
segmenter_.reset(new TsSegmenter(options(), muxer_listener()));
|
||||
Status status =
|
||||
segmenter_->Initialize(*streams()[0]->info(), encryption_key_source(),
|
||||
max_sd_pixels(), clear_lead_in_seconds());
|
||||
max_sd_pixels(), max_hd_pixels(),
|
||||
max_uhd1_pixels(), clear_lead_in_seconds());
|
||||
FireOnMediaStartEvent();
|
||||
return status;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,8 @@ TsSegmenter::~TsSegmenter() {}
|
|||
Status TsSegmenter::Initialize(const StreamInfo& stream_info,
|
||||
KeySource* encryption_key_source,
|
||||
uint32_t max_sd_pixels,
|
||||
uint32_t max_hd_pixels,
|
||||
uint32_t max_uhd1_pixels,
|
||||
double clear_lead_in_seconds) {
|
||||
if (muxer_options_.segment_template.empty())
|
||||
return Status(error::MUXER_FAILURE, "Segment template not specified.");
|
||||
|
@ -47,7 +49,8 @@ Status TsSegmenter::Initialize(const StreamInfo& stream_info,
|
|||
if (encryption_key_source) {
|
||||
std::unique_ptr<EncryptionKey> encryption_key(new EncryptionKey());
|
||||
const KeySource::TrackType type =
|
||||
GetTrackTypeForEncryption(stream_info, max_sd_pixels);
|
||||
GetTrackTypeForEncryption(stream_info, max_sd_pixels,
|
||||
max_hd_pixels, max_uhd1_pixels);
|
||||
Status status = encryption_key_source->GetKey(type, encryption_key.get());
|
||||
|
||||
if (encryption_key->iv.empty()) {
|
||||
|
|
|
@ -43,6 +43,8 @@ class TsSegmenter {
|
|||
Status Initialize(const StreamInfo& stream_info,
|
||||
KeySource* encryption_key_source,
|
||||
uint32_t max_sd_pixels,
|
||||
uint32_t max_hd_pixels,
|
||||
uint32_t max_uhd1_pixels,
|
||||
double clear_lead_in_seconds);
|
||||
|
||||
/// Finalize the segmenter.
|
||||
|
|
|
@ -124,7 +124,7 @@ TEST_F(TsSegmenterTest, Initialize) {
|
|||
segmenter.InjectPesPacketGeneratorForTesting(
|
||||
std::move(mock_pes_packet_generator_));
|
||||
|
||||
EXPECT_OK(segmenter.Initialize(*stream_info, nullptr, 0, 0));
|
||||
EXPECT_OK(segmenter.Initialize(*stream_info, nullptr, 0, 0, 0, 0));
|
||||
}
|
||||
|
||||
TEST_F(TsSegmenterTest, AddSample) {
|
||||
|
@ -171,7 +171,7 @@ TEST_F(TsSegmenterTest, AddSample) {
|
|||
segmenter.InjectPesPacketGeneratorForTesting(
|
||||
std::move(mock_pes_packet_generator_));
|
||||
|
||||
EXPECT_OK(segmenter.Initialize(*stream_info, nullptr, 0, 0));
|
||||
EXPECT_OK(segmenter.Initialize(*stream_info, nullptr, 0, 0, 0, 0));
|
||||
EXPECT_OK(segmenter.AddSample(sample));
|
||||
}
|
||||
|
||||
|
@ -275,7 +275,7 @@ TEST_F(TsSegmenterTest, PassedSegmentDuration) {
|
|||
segmenter.InjectTsWriterForTesting(std::move(mock_ts_writer_));
|
||||
segmenter.InjectPesPacketGeneratorForTesting(
|
||||
std::move(mock_pes_packet_generator_));
|
||||
EXPECT_OK(segmenter.Initialize(*stream_info, nullptr, 0, 0));
|
||||
EXPECT_OK(segmenter.Initialize(*stream_info, nullptr, 0, 0, 0, 0));
|
||||
EXPECT_OK(segmenter.AddSample(sample1));
|
||||
EXPECT_OK(segmenter.AddSample(sample2));
|
||||
}
|
||||
|
@ -302,7 +302,7 @@ TEST_F(TsSegmenterTest, InitializeThenFinalize) {
|
|||
segmenter.InjectTsWriterForTesting(std::move(mock_ts_writer_));
|
||||
segmenter.InjectPesPacketGeneratorForTesting(
|
||||
std::move(mock_pes_packet_generator_));
|
||||
EXPECT_OK(segmenter.Initialize(*stream_info, nullptr, 0, 0));
|
||||
EXPECT_OK(segmenter.Initialize(*stream_info, nullptr, 0, 0, 0, 0));
|
||||
EXPECT_OK(segmenter.Finalize());
|
||||
}
|
||||
|
||||
|
@ -333,7 +333,7 @@ TEST_F(TsSegmenterTest, Finalize) {
|
|||
segmenter.InjectTsWriterForTesting(std::move(mock_ts_writer_));
|
||||
segmenter.InjectPesPacketGeneratorForTesting(
|
||||
std::move(mock_pes_packet_generator_));
|
||||
EXPECT_OK(segmenter.Initialize(*stream_info, nullptr, 0, 0));
|
||||
EXPECT_OK(segmenter.Initialize(*stream_info, nullptr, 0, 0, 0, 0));
|
||||
segmenter.SetTsWriterFileOpenedForTesting(true);
|
||||
EXPECT_OK(segmenter.Finalize());
|
||||
}
|
||||
|
@ -439,7 +439,7 @@ TEST_F(TsSegmenterTest, SegmentOnlyBeforeKeyFrame) {
|
|||
segmenter.InjectTsWriterForTesting(std::move(mock_ts_writer_));
|
||||
segmenter.InjectPesPacketGeneratorForTesting(
|
||||
std::move(mock_pes_packet_generator_));
|
||||
EXPECT_OK(segmenter.Initialize(*stream_info, nullptr, 0, 0));
|
||||
EXPECT_OK(segmenter.Initialize(*stream_info, nullptr, 0, 0, 0, 0));
|
||||
EXPECT_OK(segmenter.AddSample(key_frame_sample1));
|
||||
EXPECT_OK(segmenter.AddSample(non_key_frame_sample));
|
||||
EXPECT_OK(segmenter.AddSample(key_frame_sample2));
|
||||
|
@ -475,11 +475,14 @@ TEST_F(TsSegmenterTest, WithEncryptionNoClearLead) {
|
|||
.WillOnce(Return(Status::OK));
|
||||
|
||||
const uint32_t k480pPixels = 640 * 480;
|
||||
const uint32_t k1080pPixels = 1920 * 1080;
|
||||
const uint32_t k2160pPixels = 4096 * 2160;
|
||||
// Set this to 0 so that Finalize will call
|
||||
// PesPacketGenerator::SetEncryptionKey().
|
||||
// Even tho no samples have been added.
|
||||
const double kClearLeadSeconds = 0;
|
||||
EXPECT_OK(segmenter.Initialize(*stream_info, &mock_key_source, k480pPixels,
|
||||
k1080pPixels, k2160pPixels,
|
||||
kClearLeadSeconds));
|
||||
}
|
||||
|
||||
|
@ -513,11 +516,14 @@ TEST_F(TsSegmenterTest, WithEncryptionNoClearLeadNoMuxerListener) {
|
|||
.WillOnce(Return(Status::OK));
|
||||
|
||||
const uint32_t k480pPixels = 640 * 480;
|
||||
const uint32_t k1080pPixels = 1920 * 1080;
|
||||
const uint32_t k2160pPixels = 4096 * 2160;
|
||||
// Set this to 0 so that Finalize will call
|
||||
// PesPacketGenerator::SetEncryptionKey().
|
||||
// Even tho no samples have been added.
|
||||
const double kClearLeadSeconds = 0;
|
||||
EXPECT_OK(segmenter.Initialize(*stream_info, &mock_key_source, k480pPixels,
|
||||
k1080pPixels, k2160pPixels,
|
||||
kClearLeadSeconds));
|
||||
}
|
||||
|
||||
|
@ -530,6 +536,8 @@ TEST_F(TsSegmenterTest, WithEncryptionWithClearLead) {
|
|||
MuxerOptions options;
|
||||
|
||||
options.segment_duration = 1.0;
|
||||
const uint32_t k1080pPixels = 1920 * 1080;
|
||||
const uint32_t k2160pPixels = 4096 * 2160;
|
||||
const double kClearLeadSeconds = 1.0;
|
||||
options.segment_template = "file$Number$.ts";
|
||||
|
||||
|
@ -610,6 +618,7 @@ TEST_F(TsSegmenterTest, WithEncryptionWithClearLead) {
|
|||
|
||||
EXPECT_CALL(mock_listener, OnEncryptionInfoReady(_, _, _, _, _));
|
||||
EXPECT_OK(segmenter.Initialize(*stream_info, &mock_key_source, 0,
|
||||
k1080pPixels, k2160pPixels,
|
||||
kClearLeadSeconds));
|
||||
EXPECT_OK(segmenter.AddSample(sample1));
|
||||
|
||||
|
|
|
@ -144,8 +144,9 @@ Status MP4Muxer::Initialize() {
|
|||
|
||||
const Status segmenter_initialized = segmenter_->Initialize(
|
||||
streams(), muxer_listener(), progress_listener(), encryption_key_source(),
|
||||
max_sd_pixels(), clear_lead_in_seconds(),
|
||||
crypto_period_duration_in_seconds(), protection_scheme());
|
||||
max_sd_pixels(), max_hd_pixels(), max_uhd1_pixels(),
|
||||
clear_lead_in_seconds(), crypto_period_duration_in_seconds(),
|
||||
protection_scheme());
|
||||
|
||||
if (!segmenter_initialized.ok())
|
||||
return segmenter_initialized;
|
||||
|
|
|
@ -167,6 +167,8 @@ Status Segmenter::Initialize(const std::vector<MediaStream*>& streams,
|
|||
ProgressListener* progress_listener,
|
||||
KeySource* encryption_key_source,
|
||||
uint32_t max_sd_pixels,
|
||||
uint32_t max_hd_pixels,
|
||||
uint32_t max_uhd1_pixels,
|
||||
double clear_lead_in_seconds,
|
||||
double crypto_period_duration_in_seconds,
|
||||
FourCC protection_scheme) {
|
||||
|
@ -196,7 +198,8 @@ Status Segmenter::Initialize(const std::vector<MediaStream*>& streams,
|
|||
}
|
||||
|
||||
KeySource::TrackType track_type =
|
||||
GetTrackTypeForEncryption(*streams[i]->info(), max_sd_pixels);
|
||||
GetTrackTypeForEncryption(*streams[i]->info(), max_sd_pixels,
|
||||
max_hd_pixels, max_uhd1_pixels);
|
||||
SampleDescription& description =
|
||||
moov_->tracks[i].media.information.sample_table.description;
|
||||
ProtectionPattern pattern =
|
||||
|
|
|
@ -55,8 +55,16 @@ class Segmenter {
|
|||
/// the encryption keys. It can be NULL to indicate that no encryption
|
||||
/// is required.
|
||||
/// @param max_sd_pixels specifies the threshold to determine whether a video
|
||||
/// track should be considered as SD or HD. If the track has more
|
||||
/// pixels per frame than max_sd_pixels, it is HD, SD otherwise.
|
||||
/// track should be considered as SD. If the max pixels per frame is
|
||||
/// no higher than max_sd_pixels, it is SD.
|
||||
/// @param max_hd_pixels specifies the threshold to determine whether a video
|
||||
/// track should be considered as HD. If the max pixels per frame is
|
||||
/// higher than max_sd_pixels, but no higher than max_hd_pixels,
|
||||
/// it is HD.
|
||||
/// @param max_uhd1_pixels specifies the threshold to determine whether a video
|
||||
/// track should be considered as UHD1. If the max pixels per frame is
|
||||
/// higher than max_hd_pixels, but no higher than max_uhd1_pixels,
|
||||
/// it is UHD1. Otherwise it is UHD2.
|
||||
/// @param clear_time specifies clear lead duration in seconds.
|
||||
/// @param crypto_period_duration specifies crypto period duration in seconds.
|
||||
/// @param protection_scheme specifies the protection scheme: 'cenc', 'cens',
|
||||
|
@ -67,6 +75,8 @@ class Segmenter {
|
|||
ProgressListener* progress_listener,
|
||||
KeySource* encryption_key_source,
|
||||
uint32_t max_sd_pixels,
|
||||
uint32_t max_hd_pixels,
|
||||
uint32_t max_uhd1_pixels,
|
||||
double clear_lead_in_seconds,
|
||||
double crypto_period_duration_in_seconds,
|
||||
FourCC protection_scheme);
|
||||
|
|
|
@ -54,6 +54,8 @@ Status Segmenter::Initialize(std::unique_ptr<MkvWriter> writer,
|
|||
MuxerListener* muxer_listener,
|
||||
KeySource* encryption_key_source,
|
||||
uint32_t max_sd_pixels,
|
||||
uint32_t max_hd_pixels,
|
||||
uint32_t max_uhd1_pixels,
|
||||
double clear_lead_in_seconds) {
|
||||
muxer_listener_ = muxer_listener;
|
||||
info_ = info;
|
||||
|
@ -82,7 +84,9 @@ Status Segmenter::Initialize(std::unique_ptr<MkvWriter> writer,
|
|||
Status status;
|
||||
if (encryption_key_source) {
|
||||
status = InitializeEncryptor(encryption_key_source,
|
||||
max_sd_pixels);
|
||||
max_sd_pixels,
|
||||
max_hd_pixels,
|
||||
max_uhd1_pixels);
|
||||
if (!status.ok())
|
||||
return status;
|
||||
}
|
||||
|
@ -366,10 +370,13 @@ Status Segmenter::CreateAudioTrack(AudioStreamInfo* info) {
|
|||
}
|
||||
|
||||
Status Segmenter::InitializeEncryptor(KeySource* key_source,
|
||||
uint32_t max_sd_pixels) {
|
||||
uint32_t max_sd_pixels,
|
||||
uint32_t max_hd_pixels,
|
||||
uint32_t max_uhd1_pixels) {
|
||||
encryptor_.reset(new Encryptor());
|
||||
const KeySource::TrackType track_type =
|
||||
GetTrackTypeForEncryption(*info_, max_sd_pixels);
|
||||
GetTrackTypeForEncryption(*info_, max_sd_pixels, max_hd_pixels,
|
||||
max_uhd1_pixels);
|
||||
if (track_type == KeySource::TrackType::TRACK_TYPE_UNKNOWN)
|
||||
return Status::OK;
|
||||
return encryptor_->Initialize(muxer_listener_, track_type, info_->codec(),
|
||||
|
|
|
@ -46,8 +46,16 @@ class Segmenter {
|
|||
/// the encryption keys. It can be NULL to indicate that no encryption
|
||||
/// is required.
|
||||
/// @param max_sd_pixels specifies the threshold to determine whether a video
|
||||
/// track should be considered as SD or HD. If the track has more
|
||||
/// pixels per frame than max_sd_pixels, it is HD, SD otherwise.
|
||||
/// track should be considered as SD. If the max pixels per frame is
|
||||
/// no higher than max_sd_pixels, it is SD.
|
||||
/// @param max_hd_pixels specifies the threshold to determine whether a video
|
||||
/// track should be considered as HD. If the max pixels per frame is
|
||||
/// higher than max_sd_pixels, but no higher than max_hd_pixels,
|
||||
/// it is HD.
|
||||
/// @param max_uhd1_pixels specifies the threshold to determine whether a video
|
||||
/// track should be considered as UHD1. If the max pixels per frame is
|
||||
/// higher than max_hd_pixels, but no higher than max_uhd1_pixels,
|
||||
/// it is UHD1. Otherwise it is UHD2.
|
||||
/// @param clear_time specifies clear lead duration in seconds.
|
||||
/// @return OK on success, an error status otherwise.
|
||||
Status Initialize(std::unique_ptr<MkvWriter> writer,
|
||||
|
@ -56,6 +64,8 @@ class Segmenter {
|
|||
MuxerListener* muxer_listener,
|
||||
KeySource* encryption_key_source,
|
||||
uint32_t max_sd_pixels,
|
||||
uint32_t max_hd_pixels,
|
||||
uint32_t max_uhd1_pixels,
|
||||
double clear_lead_in_seconds);
|
||||
|
||||
/// Finalize the segmenter.
|
||||
|
@ -114,7 +124,8 @@ class Segmenter {
|
|||
private:
|
||||
Status CreateVideoTrack(VideoStreamInfo* info);
|
||||
Status CreateAudioTrack(AudioStreamInfo* info);
|
||||
Status InitializeEncryptor(KeySource* key_source, uint32_t max_sd_pixels);
|
||||
Status InitializeEncryptor(KeySource* key_source, uint32_t max_sd_pixels,
|
||||
uint32_t max_hd_pixels, uint32_t max_uhd1_pixels);
|
||||
|
||||
// Writes the previous frame to the file.
|
||||
Status WriteFrame(bool write_duration);
|
||||
|
|
|
@ -56,6 +56,7 @@ class SegmentTestBase : public ::testing::Test {
|
|||
ASSERT_OK(segmenter->Initialize(
|
||||
std::move(writer), info, NULL /* progress_listener */,
|
||||
NULL /* muxer_listener */, key_source, 0 /* max_sd_pixels */,
|
||||
0 /* max_hd_pixels */, 0 /* max_uhd1_pixels */,
|
||||
1 /* clear_lead_in_seconds */));
|
||||
*result = std::move(segmenter);
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ Status WebMMuxer::Initialize() {
|
|||
Status initialized = segmenter_->Initialize(
|
||||
std::move(writer), streams()[0]->info().get(), progress_listener(),
|
||||
muxer_listener(), encryption_key_source(), max_sd_pixels(),
|
||||
clear_lead_in_seconds());
|
||||
max_hd_pixels(), max_uhd1_pixels(), clear_lead_in_seconds());
|
||||
|
||||
if (!initialized.ok())
|
||||
return initialized;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "packager/media/base/fourccs.h"
|
||||
#include "packager/media/base/media_stream.h"
|
||||
#include "packager/media/base/muxer.h"
|
||||
#include "packager/media/base/muxer_util.h"
|
||||
#include "packager/media/base/stream_info.h"
|
||||
#include "packager/media/base/test/status_test_util.h"
|
||||
#include "packager/media/formats/mp4/mp4_muxer.h"
|
||||
|
@ -57,6 +58,11 @@ const char kKeyHex[] = "6fc96fe628a265b13aeddec0bc421f4d";
|
|||
const double kClearLeadInSeconds = 1.5;
|
||||
const double kCryptoDurationInSeconds = 0; // Key rotation is disabled.
|
||||
|
||||
// Track resolution constants.
|
||||
const uint32_t kMaxSDPixels = 640 * 480;
|
||||
const uint32_t kMaxHDPixels = 1920 * 1080;
|
||||
const uint32_t kMaxUHD1Pixels = 4096 * 2160;
|
||||
|
||||
MediaStream* FindFirstStreamOfType(
|
||||
const std::vector<std::unique_ptr<MediaStream>>& streams,
|
||||
StreamType stream_type) {
|
||||
|
@ -178,7 +184,8 @@ void PackagerTestBasic::Remux(const std::string& input,
|
|||
|
||||
if (enable_encryption) {
|
||||
muxer_video->SetKeySource(encryption_key_source.get(),
|
||||
KeySource::TRACK_TYPE_SD, kClearLeadInSeconds,
|
||||
kMaxSDPixels, kMaxHDPixels,
|
||||
kMaxUHD1Pixels, kClearLeadInSeconds,
|
||||
kCryptoDurationInSeconds, FOURCC_cenc);
|
||||
}
|
||||
}
|
||||
|
@ -198,7 +205,8 @@ void PackagerTestBasic::Remux(const std::string& input,
|
|||
|
||||
if (enable_encryption) {
|
||||
muxer_audio->SetKeySource(encryption_key_source.get(),
|
||||
KeySource::TRACK_TYPE_SD, kClearLeadInSeconds,
|
||||
kMaxSDPixels, kMaxHDPixels,
|
||||
kMaxUHD1Pixels, kClearLeadInSeconds,
|
||||
kCryptoDurationInSeconds, FOURCC_cenc);
|
||||
}
|
||||
}
|
||||
|
@ -314,6 +322,39 @@ TEST_P(PackagerTestBasic, MP4MuxerLanguageWithSubtag) {
|
|||
ASSERT_EQ("por", stream->info()->language());
|
||||
}
|
||||
|
||||
TEST_P(PackagerTestBasic, GetTrackTypeForEncryption) {
|
||||
Demuxer demuxer(GetFullPath(GetParam()));
|
||||
ASSERT_OK(demuxer.Initialize());
|
||||
|
||||
MediaStream* video_stream = FindFirstVideoStream(demuxer.streams());
|
||||
MediaStream* audio_stream = FindFirstAudioStream(demuxer.streams());
|
||||
|
||||
// Typical resolution constraints should set the resolution in the SD range
|
||||
KeySource::TrackType track_type = GetTrackTypeForEncryption(
|
||||
*video_stream->info(), kMaxSDPixels, kMaxHDPixels, kMaxUHD1Pixels);
|
||||
ASSERT_EQ(FixedKeySource::GetTrackTypeFromString("SD"), track_type);
|
||||
|
||||
// Setting the max SD value to 1 should set the resolution in the HD range
|
||||
track_type = GetTrackTypeForEncryption(
|
||||
*video_stream->info(), 1, kMaxHDPixels, kMaxUHD1Pixels);
|
||||
ASSERT_EQ(FixedKeySource::GetTrackTypeFromString("HD"), track_type);
|
||||
|
||||
// Setting the max HD value to 2 should set the resolution in the UHD1 range
|
||||
track_type = GetTrackTypeForEncryption(
|
||||
*video_stream->info(), 1, 2, kMaxUHD1Pixels);
|
||||
ASSERT_EQ(FixedKeySource::GetTrackTypeFromString("UHD1"), track_type);
|
||||
|
||||
// Setting the max UHD1 value to 3 should set the resolution in the UHD2 range
|
||||
track_type = GetTrackTypeForEncryption(
|
||||
*video_stream->info(), 1, 2, 3);
|
||||
ASSERT_EQ(FixedKeySource::GetTrackTypeFromString("UHD2"), track_type);
|
||||
|
||||
// Audio stream should always set the track_type to AUDIO
|
||||
track_type = GetTrackTypeForEncryption(
|
||||
*audio_stream->info(), kMaxSDPixels, kMaxHDPixels, kMaxUHD1Pixels);
|
||||
ASSERT_EQ(FixedKeySource::GetTrackTypeFromString("AUDIO"), track_type);
|
||||
}
|
||||
|
||||
class PackagerTest : public PackagerTestBasic {
|
||||
public:
|
||||
void SetUp() override {
|
||||
|
|
Loading…
Reference in New Issue