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:
Kyle Alexander 2016-11-11 15:17:17 -08:00
parent d8d94da250
commit 0c2ee4c844
23 changed files with 225 additions and 47 deletions

View File

@ -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));

View File

@ -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[] =

View File

@ -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);

View File

@ -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:

View File

@ -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();

View File

@ -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;

View File

@ -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_;

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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]),

View File

@ -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;
}

View File

@ -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()) {

View File

@ -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.

View File

@ -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));

View File

@ -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;

View File

@ -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 =

View File

@ -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);

View File

@ -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(),

View File

@ -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);

View File

@ -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);
}

View File

@ -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;

View File

@ -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 {