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