Change to use ProtectionSystemSpecificInfo.
* EncryptionKey now contains them rather than a PSSH box. * Outputs PSSH boxes for each entry. * Outputs a ContentProtection element for each entry. * Removed SystemName and UUID from KeySource. * Removed --scheme_id_uri packager argument. Issue #88 Change-Id: I2651784c3220fd64f5b1773fdcd70285690cf8c0
This commit is contained in:
parent
f3e19fc002
commit
144cdc5e59
|
@ -17,14 +17,6 @@ DEFINE_bool(output_media_info,
|
|||
"'.media_info'. Exclusive with --mpd_output.");
|
||||
DEFINE_string(mpd_output, "",
|
||||
"MPD output file name. Exclusive with --output_media_info.");
|
||||
DEFINE_string(scheme_id_uri,
|
||||
"urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed",
|
||||
"This flag only applies if output_media_info is true. This value "
|
||||
"will be set in MediaInfo if the stream is encrypted. "
|
||||
"If the stream is encrypted, MPD requires a <ContentProtection> "
|
||||
"element which requires the schemeIdUri attribute. "
|
||||
"Default value is Widevine PSSH system ID, and it is valid only "
|
||||
"for ISO BMFF.");
|
||||
DEFINE_string(base_urls,
|
||||
"",
|
||||
"Comma separated BaseURLs for the MPD. The values will be added "
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
DECLARE_bool(output_media_info);
|
||||
DECLARE_string(mpd_output);
|
||||
DECLARE_string(scheme_id_uri);
|
||||
DECLARE_string(base_urls);
|
||||
DECLARE_double(availability_time_offset);
|
||||
DECLARE_double(minimum_update_period);
|
||||
|
|
|
@ -307,15 +307,11 @@ bool CreateRemuxJobs(const StreamDescriptorList& stream_descriptors,
|
|||
scoped_ptr<VodMediaInfoDumpMuxerListener>
|
||||
vod_media_info_dump_muxer_listener(
|
||||
new VodMediaInfoDumpMuxerListener(output_media_info_file_name));
|
||||
vod_media_info_dump_muxer_listener->SetContentProtectionSchemeIdUri(
|
||||
FLAGS_scheme_id_uri);
|
||||
muxer_listener = vod_media_info_dump_muxer_listener.Pass();
|
||||
}
|
||||
if (mpd_notifier) {
|
||||
scoped_ptr<MpdNotifyMuxerListener> mpd_notify_muxer_listener(
|
||||
new MpdNotifyMuxerListener(mpd_notifier));
|
||||
mpd_notify_muxer_listener->SetContentProtectionSchemeIdUri(
|
||||
FLAGS_scheme_id_uri);
|
||||
muxer_listener = mpd_notify_muxer_listener.Pass();
|
||||
}
|
||||
|
||||
|
|
|
@ -10,12 +10,6 @@
|
|||
#include "packager/media/base/aes_encryptor.h"
|
||||
#include "packager/media/base/buffer_writer.h"
|
||||
|
||||
namespace {
|
||||
// TODO(kqyang): Consider making it configurable.
|
||||
const char kDefaultUUID[] = "edef8ba9-79d6-4ace-a3c8-27dcd51d21ed";
|
||||
const char kDefaultSystemName[] = "";
|
||||
} // namespace
|
||||
|
||||
namespace edash_packager {
|
||||
namespace media {
|
||||
|
||||
|
@ -81,24 +75,28 @@ Status KeySource::GetCryptoPeriodKey(uint32_t crypto_period_index,
|
|||
std::rotate(key->key.begin(),
|
||||
key->key.begin() + (crypto_period_index % key->key.size()),
|
||||
key->key.end());
|
||||
const size_t kPsshHeaderSize = 32u;
|
||||
std::vector<uint8_t> pssh_data(key->pssh.begin() + kPsshHeaderSize,
|
||||
key->pssh.end());
|
||||
|
||||
std::vector<uint8_t> pssh_data(
|
||||
key->key_system_info[0].pssh_data().begin(),
|
||||
key->key_system_info[0].pssh_data().end());
|
||||
std::rotate(pssh_data.begin(),
|
||||
pssh_data.begin() + (crypto_period_index % pssh_data.size()),
|
||||
pssh_data.end());
|
||||
key->pssh = PsshBoxFromPsshData(pssh_data);
|
||||
|
||||
// Since this should only be used for testing, use the Widevine system id.
|
||||
// TODO(modmaker): Change to FixedKeySource
|
||||
ProtectionSystemSpecificInfo info;
|
||||
info.add_key_id(key->key_id);
|
||||
info.set_system_id(kWidevineSystemId, arraysize(kWidevineSystemId));
|
||||
info.set_pssh_box_version(0);
|
||||
info.set_pssh_data(pssh_data);
|
||||
|
||||
key->key_system_info.clear();
|
||||
key->key_system_info.push_back(info);
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
std::string KeySource::UUID() {
|
||||
return kDefaultUUID;
|
||||
}
|
||||
|
||||
std::string KeySource::SystemName() {
|
||||
return kDefaultSystemName;
|
||||
}
|
||||
|
||||
scoped_ptr<KeySource> KeySource::CreateFromHexStrings(
|
||||
const std::string& key_id_hex,
|
||||
const std::string& key_hex,
|
||||
|
@ -130,9 +128,15 @@ scoped_ptr<KeySource> KeySource::CreateFromHexStrings(
|
|||
}
|
||||
}
|
||||
|
||||
encryption_key->pssh = PsshBoxFromPsshData(pssh_data);
|
||||
return scoped_ptr<KeySource>(
|
||||
new KeySource(encryption_key.Pass()));
|
||||
// TODO(modmaker): Change to FixedKeySource
|
||||
ProtectionSystemSpecificInfo info;
|
||||
info.add_key_id(encryption_key->key_id);
|
||||
info.set_system_id(kWidevineSystemId, arraysize(kWidevineSystemId));
|
||||
info.set_pssh_box_version(0);
|
||||
info.set_pssh_data(pssh_data);
|
||||
|
||||
encryption_key->key_system_info.push_back(info);
|
||||
return scoped_ptr<KeySource>(new KeySource(encryption_key.Pass()));
|
||||
}
|
||||
|
||||
KeySource::TrackType KeySource::GetTrackTypeFromString(
|
||||
|
@ -163,26 +167,6 @@ std::string KeySource::TrackTypeToString(TrackType track_type) {
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<uint8_t> KeySource::PsshBoxFromPsshData(
|
||||
const std::vector<uint8_t>& pssh_data) {
|
||||
const uint8_t kPsshFourCC[] = {'p', 's', 's', 'h'};
|
||||
const uint32_t kVersionAndFlags = 0;
|
||||
|
||||
const uint32_t pssh_data_size = pssh_data.size();
|
||||
const uint32_t total_size =
|
||||
sizeof(total_size) + sizeof(kPsshFourCC) + sizeof(kVersionAndFlags) +
|
||||
sizeof(kWidevineSystemId) + sizeof(pssh_data_size) + pssh_data_size;
|
||||
|
||||
BufferWriter writer;
|
||||
writer.AppendInt(total_size);
|
||||
writer.AppendArray(kPsshFourCC, sizeof(kPsshFourCC));
|
||||
writer.AppendInt(kVersionAndFlags);
|
||||
writer.AppendArray(kWidevineSystemId, sizeof(kWidevineSystemId));
|
||||
writer.AppendInt(pssh_data_size);
|
||||
writer.AppendVector(pssh_data);
|
||||
return std::vector<uint8_t>(writer.Buffer(), writer.Buffer() + writer.Size());
|
||||
}
|
||||
|
||||
KeySource::KeySource() {}
|
||||
KeySource::KeySource(scoped_ptr<EncryptionKey> encryption_key)
|
||||
: encryption_key_(encryption_key.Pass()) {
|
||||
|
|
|
@ -7,9 +7,11 @@
|
|||
#ifndef MEDIA_BASE_KEY_SOURCE_H_
|
||||
#define MEDIA_BASE_KEY_SOURCE_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "packager/base/memory/scoped_ptr.h"
|
||||
#include "packager/media/base/protection_system_specific_info.h"
|
||||
#include "packager/media/base/status.h"
|
||||
|
||||
namespace edash_packager {
|
||||
|
@ -23,9 +25,9 @@ struct EncryptionKey {
|
|||
EncryptionKey();
|
||||
~EncryptionKey();
|
||||
|
||||
std::vector<ProtectionSystemSpecificInfo> key_system_info;
|
||||
std::vector<uint8_t> key_id;
|
||||
std::vector<uint8_t> key;
|
||||
std::vector<uint8_t> pssh;
|
||||
std::vector<uint8_t> iv;
|
||||
};
|
||||
|
||||
|
@ -91,19 +93,6 @@ class KeySource {
|
|||
TrackType track_type,
|
||||
EncryptionKey* key);
|
||||
|
||||
/// Returns the UUID of the key source in human readable form.
|
||||
/// UUIDs are listed here:
|
||||
/// http://dashif.org/identifiers/protection/
|
||||
/// @return UUID of the key source, empty string if not specified.
|
||||
virtual std::string UUID();
|
||||
|
||||
/// Returns the name, and possibly with a version number, of the key source.
|
||||
/// (This would be the ContentProtection@value attribute in the MPD. DASH-IF-
|
||||
/// IOP v3.0 recommends this to be the DRM system and version name in human
|
||||
/// readable from.)
|
||||
/// @return the name of the key source, empty string if not specified.
|
||||
virtual std::string SystemName();
|
||||
|
||||
/// Create KeySource object from hex strings.
|
||||
/// @param key_id_hex is the key id in hex string.
|
||||
/// @param key_hex is the key in hex string.
|
||||
|
@ -127,11 +116,6 @@ class KeySource {
|
|||
protected:
|
||||
KeySource();
|
||||
|
||||
/// @return the raw bytes of the pssh box with system ID and box header
|
||||
/// included.
|
||||
static std::vector<uint8_t> PsshBoxFromPsshData(
|
||||
const std::vector<uint8_t>& pssh_data);
|
||||
|
||||
private:
|
||||
explicit KeySource(scoped_ptr<EncryptionKey> encryption_key);
|
||||
|
||||
|
|
|
@ -36,18 +36,18 @@ class ProtectionSystemSpecificInfo {
|
|||
/// Creates a PSSH box for the current data.
|
||||
std::vector<uint8_t> CreateBox() const;
|
||||
|
||||
uint8_t version() const { return version_; }
|
||||
uint8_t pssh_box_version() const { return version_; }
|
||||
const std::vector<uint8_t>& system_id() const { return system_id_; }
|
||||
const std::vector<std::vector<uint8_t>>& key_ids() const { return key_ids_; }
|
||||
const std::vector<uint8_t>& pssh_data() const { return pssh_data_; }
|
||||
|
||||
void set_version(uint8_t version) {
|
||||
void set_pssh_box_version(uint8_t version) {
|
||||
DCHECK_LT(version, 2);
|
||||
version_ = version;
|
||||
}
|
||||
void set_system_id(const std::vector<uint8_t>& system_id) {
|
||||
DCHECK_EQ(16u, system_id.size());
|
||||
system_id_ = system_id;
|
||||
void set_system_id(const uint8_t* system_id, size_t system_id_size) {
|
||||
DCHECK_EQ(16u, system_id_size);
|
||||
system_id_.assign(system_id, system_id + system_id_size);
|
||||
}
|
||||
void add_key_id(const std::vector<uint8_t>& key_id) {
|
||||
DCHECK_EQ(16u, key_id.size());
|
||||
|
|
|
@ -72,7 +72,7 @@ TEST_F(PsshTest, ParseBoxes_SupportsV0) {
|
|||
ASSERT_EQ(0u, info[0].key_ids().size());
|
||||
EXPECT_EQ(test_system_id_, info[0].system_id());
|
||||
EXPECT_EQ(test_pssh_data_, info[0].pssh_data());
|
||||
EXPECT_EQ(0, info[0].version());
|
||||
EXPECT_EQ(0, info[0].pssh_box_version());
|
||||
}
|
||||
|
||||
TEST_F(PsshTest, ParseBoxes_SupportsV1) {
|
||||
|
@ -85,7 +85,7 @@ TEST_F(PsshTest, ParseBoxes_SupportsV1) {
|
|||
EXPECT_EQ(test_system_id_, info[0].system_id());
|
||||
EXPECT_EQ(test_key_id_, info[0].key_ids()[0]);
|
||||
EXPECT_EQ(test_pssh_data_, info[0].pssh_data());
|
||||
EXPECT_EQ(1, info[0].version());
|
||||
EXPECT_EQ(1, info[0].pssh_box_version());
|
||||
}
|
||||
|
||||
TEST_F(PsshTest, ParseBoxes_SupportsConcatenatedBoxes) {
|
||||
|
@ -103,25 +103,25 @@ TEST_F(PsshTest, ParseBoxes_SupportsConcatenatedBoxes) {
|
|||
EXPECT_EQ(test_system_id_, info[0].system_id());
|
||||
EXPECT_EQ(test_key_id_, info[0].key_ids()[0]);
|
||||
EXPECT_EQ(test_pssh_data_, info[0].pssh_data());
|
||||
EXPECT_EQ(1, info[0].version());
|
||||
EXPECT_EQ(1, info[0].pssh_box_version());
|
||||
|
||||
ASSERT_EQ(0u, info[1].key_ids().size());
|
||||
EXPECT_EQ(test_system_id_, info[1].system_id());
|
||||
EXPECT_EQ(test_pssh_data_, info[1].pssh_data());
|
||||
EXPECT_EQ(0, info[1].version());
|
||||
EXPECT_EQ(0, info[1].pssh_box_version());
|
||||
|
||||
ASSERT_EQ(1u, info[2].key_ids().size());
|
||||
EXPECT_EQ(test_system_id_, info[2].system_id());
|
||||
EXPECT_EQ(test_key_id_, info[2].key_ids()[0]);
|
||||
EXPECT_EQ(test_pssh_data_, info[2].pssh_data());
|
||||
EXPECT_EQ(1, info[2].version());
|
||||
EXPECT_EQ(1, info[2].pssh_box_version());
|
||||
}
|
||||
|
||||
TEST_F(PsshTest, CreateBox_MakesV0Boxes) {
|
||||
ProtectionSystemSpecificInfo info;
|
||||
info.set_system_id(test_system_id_);
|
||||
info.set_system_id(kTestSystemIdArray, arraysize(kTestSystemIdArray));
|
||||
info.set_pssh_data(test_pssh_data_);
|
||||
info.set_version(0);
|
||||
info.set_pssh_box_version(0);
|
||||
|
||||
EXPECT_EQ(v0_box_, info.CreateBox());
|
||||
}
|
||||
|
@ -129,9 +129,9 @@ TEST_F(PsshTest, CreateBox_MakesV0Boxes) {
|
|||
TEST_F(PsshTest, CreateBox_MakesV1Boxes) {
|
||||
ProtectionSystemSpecificInfo info;
|
||||
info.add_key_id(test_key_id_);
|
||||
info.set_system_id(test_system_id_);
|
||||
info.set_system_id(kTestSystemIdArray, arraysize(kTestSystemIdArray));
|
||||
info.set_pssh_data(test_pssh_data_);
|
||||
info.set_version(1);
|
||||
info.set_pssh_box_version(1);
|
||||
|
||||
EXPECT_EQ(v1_box_, info.CreateBox());
|
||||
}
|
||||
|
|
|
@ -279,10 +279,6 @@ Status WidevineKeySource::GetCryptoPeriodKey(uint32_t crypto_period_index,
|
|||
return GetKeyInternal(crypto_period_index, track_type, key);
|
||||
}
|
||||
|
||||
std::string WidevineKeySource::UUID() {
|
||||
return "edef8ba9-79d6-4ace-a3c8-27dcd51d21ed";
|
||||
}
|
||||
|
||||
void WidevineKeySource::set_signer(scoped_ptr<RequestSigner> signer) {
|
||||
signer_ = signer.Pass();
|
||||
}
|
||||
|
@ -557,14 +553,23 @@ bool WidevineKeySource::ExtractEncryptionKey(
|
|||
if (!GetKeyIdFromTrack(*track_dict, &encryption_key->key_id))
|
||||
return false;
|
||||
|
||||
ProtectionSystemSpecificInfo info;
|
||||
info.add_key_id(encryption_key->key_id);
|
||||
info.set_system_id(kWidevineSystemId, arraysize(kWidevineSystemId));
|
||||
info.set_pssh_box_version(0);
|
||||
|
||||
std::vector<uint8_t> pssh_data;
|
||||
if (!GetPsshDataFromTrack(*track_dict, &pssh_data))
|
||||
return false;
|
||||
encryption_key->pssh = PsshBoxFromPsshData(pssh_data);
|
||||
info.set_pssh_data(pssh_data);
|
||||
|
||||
encryption_key->key_system_info.push_back(info);
|
||||
}
|
||||
encryption_key_map[track_type] = encryption_key.release();
|
||||
}
|
||||
|
||||
// NOTE: To support version 1 pssh, update ProtectionSystemSpecificInfo to
|
||||
// include all key IDs in |encryption_key_map|.
|
||||
DCHECK(!encryption_key_map.empty());
|
||||
if (!enable_key_rotation) {
|
||||
encryption_key_map_ = encryption_key_map;
|
||||
|
|
|
@ -44,7 +44,6 @@ class WidevineKeySource : public KeySource {
|
|||
Status GetCryptoPeriodKey(uint32_t crypto_period_index,
|
||||
TrackType track_type,
|
||||
EncryptionKey* key) override;
|
||||
std::string UUID() override;
|
||||
/// @}
|
||||
|
||||
/// Set signer for the key source.
|
||||
|
|
|
@ -81,7 +81,10 @@ std::string ToString(const std::vector<uint8_t> v) {
|
|||
}
|
||||
|
||||
std::string GetMockKeyId(const std::string& track_type) {
|
||||
return "MockKeyId" + track_type;
|
||||
// Key ID must be 16 characters.
|
||||
std::string key_id = "MockKeyId" + track_type;
|
||||
key_id.resize(16, '~');
|
||||
return key_id;
|
||||
}
|
||||
|
||||
std::string GetMockKey(const std::string& track_type) {
|
||||
|
@ -122,12 +125,6 @@ std::string GenerateMockClassicLicenseResponse() {
|
|||
return base::StringPrintf(kLicenseResponseFormat, "OK", tracks.c_str());
|
||||
}
|
||||
|
||||
std::string GetPsshDataFromPsshBox(const std::string& pssh_box) {
|
||||
const size_t kPsshDataOffset = 32u;
|
||||
DCHECK_LT(kPsshDataOffset, pssh_box.size());
|
||||
return pssh_box.substr(kPsshDataOffset);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace media {
|
||||
|
@ -186,10 +183,11 @@ class WidevineKeySourceTest : public ::testing::Test {
|
|||
&encryption_key));
|
||||
EXPECT_EQ(GetMockKey(kTrackTypes[i]), ToString(encryption_key.key));
|
||||
if (!classic) {
|
||||
ASSERT_EQ(1u, encryption_key.key_system_info.size());
|
||||
EXPECT_EQ(GetMockKeyId(kTrackTypes[i]),
|
||||
ToString(encryption_key.key_id));
|
||||
EXPECT_EQ(GetMockPsshData(kTrackTypes[i]),
|
||||
GetPsshDataFromPsshBox(ToString(encryption_key.pssh)));
|
||||
ToString(encryption_key.key_system_info[0].pssh_data()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -395,7 +393,7 @@ const char kCryptoPeriodRequestMessageFormat[] =
|
|||
"\"tracks\":[{\"type\":\"SD\"},{\"type\":\"HD\"},{\"type\":\"AUDIO\"}]}";
|
||||
|
||||
const char kCryptoPeriodTrackFormat[] =
|
||||
"{\"type\":\"%s\",\"key_id\":\"\",\"key\":"
|
||||
"{\"type\":\"%s\",\"key_id\":\"%s\",\"key\":"
|
||||
"\"%s\",\"pssh\":[{\"drm_type\":\"WIDEVINE\",\"data\":\"\"}], "
|
||||
"\"crypto_period_index\":%u}";
|
||||
|
||||
|
@ -417,6 +415,7 @@ std::string GenerateMockKeyRotationLicenseResponse(
|
|||
tracks += base::StringPrintf(
|
||||
kCryptoPeriodTrackFormat,
|
||||
kTrackTypes[i].c_str(),
|
||||
Base64Encode(GetMockKeyId(kTrackTypes[i])).c_str(),
|
||||
Base64Encode(GetMockKey(kTrackTypes[i], index)).c_str(),
|
||||
index);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "packager/base/logging.h"
|
||||
#include "packager/media/base/audio_stream_info.h"
|
||||
#include "packager/media/base/video_stream_info.h"
|
||||
#include "packager/media/base/protection_system_specific_info.h"
|
||||
#include "packager/media/event/muxer_listener_internal.h"
|
||||
#include "packager/mpd/base/media_info.pb.h"
|
||||
#include "packager/mpd/base/mpd_notifier.h"
|
||||
|
@ -27,31 +28,26 @@ MpdNotifyMuxerListener::MpdNotifyMuxerListener(MpdNotifier* mpd_notifier)
|
|||
|
||||
MpdNotifyMuxerListener::~MpdNotifyMuxerListener() {}
|
||||
|
||||
void MpdNotifyMuxerListener::SetContentProtectionSchemeIdUri(
|
||||
const std::string& scheme_id_uri) {
|
||||
scheme_id_uri_ = scheme_id_uri;
|
||||
}
|
||||
|
||||
void MpdNotifyMuxerListener::OnEncryptionInfoReady(
|
||||
bool is_initial_encryption_info,
|
||||
const std::string& content_protection_uuid,
|
||||
const std::string& content_protection_name_version,
|
||||
const std::vector<uint8_t>& key_id,
|
||||
const std::vector<uint8_t>& pssh) {
|
||||
const std::vector<ProtectionSystemSpecificInfo>& key_system_info) {
|
||||
if (is_initial_encryption_info) {
|
||||
LOG_IF(WARNING, is_encrypted_)
|
||||
<< "Updating initial encryption information.";
|
||||
content_protection_uuid_ = content_protection_uuid;
|
||||
content_protection_name_version_ = content_protection_name_version;
|
||||
default_key_id_.assign(key_id.begin(), key_id.end());
|
||||
pssh_.assign(pssh.begin(), pssh.end());
|
||||
key_system_info_ = key_system_info;
|
||||
is_encrypted_ = true;
|
||||
return;
|
||||
}
|
||||
|
||||
bool updated = mpd_notifier_->NotifyEncryptionUpdate(
|
||||
notification_id_, content_protection_uuid, key_id, pssh);
|
||||
LOG_IF(WARNING, !updated) << "Failed to update encryption info.";
|
||||
for (const ProtectionSystemSpecificInfo& info : key_system_info) {
|
||||
std::string drm_uuid = internal::CreateUUIDString(info.system_id());
|
||||
std::vector<uint8_t> new_pssh = info.CreateBox();
|
||||
bool updated = mpd_notifier_->NotifyEncryptionUpdate(
|
||||
notification_id_, drm_uuid, key_id, new_pssh);
|
||||
LOG_IF(WARNING, !updated) << "Failed to update encryption info.";
|
||||
}
|
||||
}
|
||||
|
||||
void MpdNotifyMuxerListener::OnMediaStart(
|
||||
|
@ -70,9 +66,8 @@ void MpdNotifyMuxerListener::OnMediaStart(
|
|||
}
|
||||
|
||||
if (is_encrypted_) {
|
||||
internal::SetContentProtectionFields(
|
||||
content_protection_uuid_, content_protection_name_version_,
|
||||
default_key_id_, pssh_, media_info.get());
|
||||
internal::SetContentProtectionFields(default_key_id_, key_system_info_,
|
||||
media_info.get());
|
||||
}
|
||||
|
||||
if (mpd_notifier_->dash_profile() == kLiveProfile) {
|
||||
|
|
|
@ -31,17 +31,12 @@ class MpdNotifyMuxerListener : public MuxerListener {
|
|||
explicit MpdNotifyMuxerListener(MpdNotifier* mpd_notifier);
|
||||
~MpdNotifyMuxerListener() override;
|
||||
|
||||
/// If the stream is encrypted use this as 'schemeIdUri' attribute for
|
||||
/// ContentProtection element.
|
||||
void SetContentProtectionSchemeIdUri(const std::string& scheme_id_uri);
|
||||
|
||||
/// @name MuxerListener implementation overrides.
|
||||
/// @{
|
||||
void OnEncryptionInfoReady(bool is_initial_encryption_info,
|
||||
const std::string& content_protection_uuid,
|
||||
const std::string& content_protection_name_version,
|
||||
const std::vector<uint8_t>& key_id,
|
||||
const std::vector<uint8_t>& pssh) override;
|
||||
const std::vector<ProtectionSystemSpecificInfo>&
|
||||
key_system_info) override;
|
||||
void OnMediaStart(const MuxerOptions& muxer_options,
|
||||
const StreamInfo& stream_info,
|
||||
uint32_t time_scale,
|
||||
|
@ -71,14 +66,11 @@ class MpdNotifyMuxerListener : public MuxerListener {
|
|||
MpdNotifier* const mpd_notifier_;
|
||||
uint32_t notification_id_;
|
||||
scoped_ptr<MediaInfo> media_info_;
|
||||
std::string scheme_id_uri_;
|
||||
|
||||
bool is_encrypted_;
|
||||
// Storage for values passed to OnEncryptionInfoReady().
|
||||
std::string content_protection_uuid_;
|
||||
std::string content_protection_name_version_;
|
||||
std::string default_key_id_;
|
||||
std::string pssh_;
|
||||
std::vector<ProtectionSystemSpecificInfo> key_system_info_;
|
||||
|
||||
// Saves all the subsegment information for VOD. This should be used to call
|
||||
// MpdNotifier::NotifyNewSegment() after NotifyNewSegment() is called
|
||||
|
|
|
@ -29,10 +29,7 @@ namespace {
|
|||
|
||||
// Can be any string, we just want to check that it is preserved in the
|
||||
// protobuf.
|
||||
const char kTestUUID[] = "somebogusuuid";
|
||||
const char kDrmName[] = "drmname";
|
||||
const char kDefaultKeyId[] = "defaultkeyid";
|
||||
const char kPssh[] = "pssh";
|
||||
const bool kInitialEncryptionInfo = true;
|
||||
const bool kNonInitialEncryptionInfo = false;
|
||||
|
||||
|
@ -152,22 +149,20 @@ TEST_F(MpdNotifyMuxerListenerTest, VodEncryptedContent) {
|
|||
|
||||
const std::vector<uint8_t> default_key_id(
|
||||
kDefaultKeyId, kDefaultKeyId + arraysize(kDefaultKeyId) - 1);
|
||||
const std::vector<uint8_t> pssh(kPssh, kPssh + arraysize(kPssh) - 1);
|
||||
|
||||
const std::string kExpectedMediaInfo =
|
||||
std::string(kExpectedDefaultMediaInfo) +
|
||||
"protected_content {\n"
|
||||
" content_protection_entry {\n"
|
||||
" uuid: 'somebogusuuid'\n"
|
||||
" name_version: 'drmname'\n"
|
||||
" pssh: 'pssh'\n"
|
||||
" uuid: 'edef8ba9-79d6-4ace-a3c8-27dcd51d21ed'\n"
|
||||
" pssh: '" + std::string(kExpectedDefaultPsshBox) + "'\n"
|
||||
" }\n"
|
||||
" default_key_id: 'defaultkeyid'\n"
|
||||
"}\n";
|
||||
|
||||
EXPECT_CALL(*notifier_, NotifyNewContainer(_, _)).Times(0);
|
||||
listener_->OnEncryptionInfoReady(kInitialEncryptionInfo, kTestUUID, kDrmName,
|
||||
default_key_id, pssh);
|
||||
listener_->OnEncryptionInfoReady(kInitialEncryptionInfo,
|
||||
default_key_id, GetDefaultKeySystemInfo());
|
||||
|
||||
listener_->OnMediaStart(muxer_options, *video_stream_info,
|
||||
kDefaultReferenceTimeScale,
|
||||
|
@ -275,7 +270,7 @@ TEST_F(MpdNotifyMuxerListenerTest, LiveNoKeyRotation) {
|
|||
scoped_refptr<StreamInfo> video_stream_info =
|
||||
CreateVideoStreamInfo(video_params);
|
||||
|
||||
const char kExpectedMediaInfo[] =
|
||||
const std::string kExpectedMediaInfo =
|
||||
"video_info {\n"
|
||||
" codec: \"avc1.010101\"\n"
|
||||
" width: 720\n"
|
||||
|
@ -291,9 +286,8 @@ TEST_F(MpdNotifyMuxerListenerTest, LiveNoKeyRotation) {
|
|||
"protected_content {\n"
|
||||
" default_key_id: \"defaultkeyid\"\n"
|
||||
" content_protection_entry {\n"
|
||||
" uuid: \"somebogusuuid\"\n"
|
||||
" name_version: \"drmname\"\n"
|
||||
" pssh: \"pssh\"\n"
|
||||
" uuid: 'edef8ba9-79d6-4ace-a3c8-27dcd51d21ed'\n"
|
||||
" pssh: \"" + std::string(kExpectedDefaultPsshBox) + "\"\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
|
||||
|
@ -305,7 +299,6 @@ TEST_F(MpdNotifyMuxerListenerTest, LiveNoKeyRotation) {
|
|||
const uint64_t kSegmentFileSize2 = 83743u;
|
||||
const std::vector<uint8_t> default_key_id(
|
||||
kDefaultKeyId, kDefaultKeyId + arraysize(kDefaultKeyId) - 1);
|
||||
const std::vector<uint8_t> pssh(kPssh, kPssh + arraysize(kPssh) - 1);
|
||||
|
||||
InSequence s;
|
||||
EXPECT_CALL(*notifier_, NotifyEncryptionUpdate(_, _, _, _)).Times(0);
|
||||
|
@ -319,8 +312,8 @@ TEST_F(MpdNotifyMuxerListenerTest, LiveNoKeyRotation) {
|
|||
NotifyNewSegment(_, kStartTime2, kDuration2, kSegmentFileSize2));
|
||||
EXPECT_CALL(*notifier_, Flush());
|
||||
|
||||
listener_->OnEncryptionInfoReady(kInitialEncryptionInfo, kTestUUID, kDrmName,
|
||||
default_key_id, pssh);
|
||||
listener_->OnEncryptionInfoReady(kInitialEncryptionInfo,
|
||||
default_key_id, GetDefaultKeySystemInfo());
|
||||
listener_->OnMediaStart(muxer_options, *video_stream_info,
|
||||
kDefaultReferenceTimeScale,
|
||||
MuxerListener::kContainerMp4);
|
||||
|
@ -368,7 +361,6 @@ TEST_F(MpdNotifyMuxerListenerTest, LiveWithKeyRotation) {
|
|||
const uint64_t kSegmentFileSize2 = 83743u;
|
||||
const std::vector<uint8_t> default_key_id(
|
||||
kDefaultKeyId, kDefaultKeyId + arraysize(kDefaultKeyId) - 1);
|
||||
const std::vector<uint8_t> pssh(kPssh, kPssh + arraysize(kPssh) - 1);
|
||||
|
||||
InSequence s;
|
||||
EXPECT_CALL(*notifier_,
|
||||
|
@ -382,13 +374,14 @@ TEST_F(MpdNotifyMuxerListenerTest, LiveWithKeyRotation) {
|
|||
NotifyNewSegment(_, kStartTime2, kDuration2, kSegmentFileSize2));
|
||||
EXPECT_CALL(*notifier_, Flush());
|
||||
|
||||
listener_->OnEncryptionInfoReady(kInitialEncryptionInfo, "", "",
|
||||
default_key_id, std::vector<uint8_t>());
|
||||
listener_->OnEncryptionInfoReady(kInitialEncryptionInfo, default_key_id,
|
||||
std::vector<ProtectionSystemSpecificInfo>());
|
||||
listener_->OnMediaStart(muxer_options, *video_stream_info,
|
||||
kDefaultReferenceTimeScale,
|
||||
MuxerListener::kContainerMp4);
|
||||
listener_->OnEncryptionInfoReady(kNonInitialEncryptionInfo, kTestUUID,
|
||||
kDrmName, std::vector<uint8_t>(), pssh);
|
||||
listener_->OnEncryptionInfoReady(kNonInitialEncryptionInfo,
|
||||
std::vector<uint8_t>(),
|
||||
GetDefaultKeySystemInfo());
|
||||
listener_->OnNewSegment(kStartTime1, kDuration1, kSegmentFileSize1);
|
||||
listener_->OnNewSegment(kStartTime2, kDuration2, kSegmentFileSize2);
|
||||
::testing::Mock::VerifyAndClearExpectations(notifier_.get());
|
||||
|
|
|
@ -19,8 +19,9 @@
|
|||
namespace edash_packager {
|
||||
namespace media {
|
||||
|
||||
class StreamInfo;
|
||||
struct MuxerOptions;
|
||||
class ProtectionSystemSpecificInfo;
|
||||
class StreamInfo;
|
||||
|
||||
/// MuxerListener is an event handler that can be registered to a muxer.
|
||||
/// A MuxerListener cannot be shared amongst muxer instances, in other words,
|
||||
|
@ -40,14 +41,10 @@ class MuxerListener {
|
|||
// Called when the media's encryption information is ready. This should be
|
||||
// called before OnMediaStart(), if the media is encrypted.
|
||||
// All the parameters may be empty just to notify that the media is encrypted.
|
||||
// |content_protection_uuid| is one of the UUIDs listed here
|
||||
// http://dashif.org/identifiers/protection/. This should be in human
|
||||
// readable form.
|
||||
// |is_initial_encryption_info| is true if this is the first encryption info
|
||||
// for the media.
|
||||
// In general, this flag should always be true for non-key-rotated media and
|
||||
// should be called only once.
|
||||
// |content_protection_name_version| is the DRM system and version name.
|
||||
// |key_id| is the key ID for the media.
|
||||
// The format should be a vector of uint8_t, i.e. not (necessarily) human
|
||||
// readable hex string.
|
||||
|
@ -56,13 +53,10 @@ class MuxerListener {
|
|||
// 'tenc' box.
|
||||
// If |is_initial_encryption_info| is false then |key_id| is the new key ID
|
||||
// for the for the next crypto period.
|
||||
// |pssh| is the whole 'pssh' box.
|
||||
virtual void OnEncryptionInfoReady(
|
||||
bool is_initial_encryption_info,
|
||||
const std::string& content_protection_uuid,
|
||||
const std::string& content_protection_name_version,
|
||||
const std::vector<uint8_t>& key_id,
|
||||
const std::vector<uint8_t>& pssh) = 0;
|
||||
const std::vector<ProtectionSystemSpecificInfo>& key_system_info) = 0;
|
||||
|
||||
// Called when muxing starts.
|
||||
// For MPEG DASH Live profile, the initialization segment information is
|
||||
|
|
|
@ -9,8 +9,11 @@
|
|||
#include <math.h>
|
||||
|
||||
#include "packager/base/logging.h"
|
||||
#include "packager/base/strings/string_number_conversions.h"
|
||||
#include "packager/base/strings/string_util.h"
|
||||
#include "packager/media/base/audio_stream_info.h"
|
||||
#include "packager/media/base/muxer_options.h"
|
||||
#include "packager/media/base/protection_system_specific_info.h"
|
||||
#include "packager/media/base/video_stream_info.h"
|
||||
#include "packager/media/filters/ec3_audio_util.h"
|
||||
#include "packager/mpd/base/media_info.pb.h"
|
||||
|
@ -213,10 +216,8 @@ bool SetVodInformation(bool has_init_range,
|
|||
}
|
||||
|
||||
void SetContentProtectionFields(
|
||||
const std::string& content_protection_uuid,
|
||||
const std::string& content_protection_name_version,
|
||||
const std::string& default_key_id,
|
||||
const std::string& pssh,
|
||||
const std::vector<ProtectionSystemSpecificInfo>& key_system_info,
|
||||
MediaInfo* media_info) {
|
||||
DCHECK(media_info);
|
||||
MediaInfo::ProtectedContent* protected_content =
|
||||
|
@ -225,21 +226,26 @@ void SetContentProtectionFields(
|
|||
if (!default_key_id.empty())
|
||||
protected_content->set_default_key_id(default_key_id);
|
||||
|
||||
if (content_protection_uuid.empty() &&
|
||||
content_protection_name_version.empty() && pssh.empty()) {
|
||||
return;
|
||||
for (const ProtectionSystemSpecificInfo& info : key_system_info) {
|
||||
MediaInfo::ProtectedContent::ContentProtectionEntry* entry =
|
||||
protected_content->add_content_protection_entry();
|
||||
if (!info.system_id().empty())
|
||||
entry->set_uuid(CreateUUIDString(info.system_id()));
|
||||
|
||||
const std::vector<uint8_t> pssh = info.CreateBox();
|
||||
entry->set_pssh(pssh.data(), pssh.size());
|
||||
}
|
||||
}
|
||||
|
||||
MediaInfo::ProtectedContent::ContentProtectionEntry* entry =
|
||||
protected_content->add_content_protection_entry();
|
||||
if (!content_protection_uuid.empty())
|
||||
entry->set_uuid(content_protection_uuid);
|
||||
|
||||
if (!content_protection_name_version.empty())
|
||||
entry->set_name_version(content_protection_name_version);
|
||||
|
||||
if (!pssh.empty())
|
||||
entry->set_pssh(pssh);
|
||||
std::string CreateUUIDString(const std::vector<uint8_t>& data) {
|
||||
DCHECK_EQ(16u, data.size());
|
||||
std::string uuid = base::HexEncode(data.data(), data.size());
|
||||
base::StringToLowerASCII(&uuid);
|
||||
uuid.insert(20, "-");
|
||||
uuid.insert(16, "-");
|
||||
uuid.insert(12, "-");
|
||||
uuid.insert(8, "-");
|
||||
return uuid;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
|
|
@ -45,22 +45,20 @@ bool SetVodInformation(bool has_init_range,
|
|||
uint64_t file_size,
|
||||
MediaInfo* media_info);
|
||||
|
||||
/// @param content_protection_uuid is the UUID of the content protection
|
||||
/// in human readable form.
|
||||
/// @param content_protection_name_version is the DRM name and verion.
|
||||
/// @param default_key_id is the key ID for this media in hex (i.e. non-human
|
||||
/// readable, typically 16 bytes.)
|
||||
/// @param pssh is the pssh for the media in hex (i.e. non-human readable, raw
|
||||
/// 'pssh' box.)
|
||||
/// @param key_system_info the key-system specific info for the media.
|
||||
/// @param media_info is where the content protection information is stored and
|
||||
/// cannot be null.
|
||||
void SetContentProtectionFields(
|
||||
const std::string& content_protection_uuid,
|
||||
const std::string& content_protection_name_version,
|
||||
const std::string& default_key_id,
|
||||
const std::string& pssh,
|
||||
const std::vector<ProtectionSystemSpecificInfo>& key_system_info,
|
||||
MediaInfo* media_info);
|
||||
|
||||
/// Creates a UUID string from the given binary data. The data must be 16 bytes
|
||||
/// long. Outputs: "00000000-0000-0000-0000-000000000000"
|
||||
std::string CreateUUIDString(const std::vector<uint8_t>& data);
|
||||
|
||||
} // namespace internal
|
||||
} // namespace media
|
||||
} // namespace edash_packager
|
||||
|
|
|
@ -94,6 +94,20 @@ void SetDefaultMuxerOptionsValues(MuxerOptions* muxer_options) {
|
|||
muxer_options->temp_dir.clear();
|
||||
}
|
||||
|
||||
std::vector<ProtectionSystemSpecificInfo> GetDefaultKeySystemInfo() {
|
||||
const uint8_t kPsshData[] = {'p', 's', 's', 'h'};
|
||||
|
||||
ProtectionSystemSpecificInfo info;
|
||||
info.set_system_id(kWidevineSystemId, arraysize(kWidevineSystemId));
|
||||
info.set_pssh_data(
|
||||
std::vector<uint8_t>(kPsshData, kPsshData + arraysize(kPsshData)));
|
||||
info.set_pssh_box_version(0);
|
||||
|
||||
std::vector<ProtectionSystemSpecificInfo> key_system_info;
|
||||
key_system_info.push_back(info);
|
||||
return key_system_info;
|
||||
}
|
||||
|
||||
void ExpectMediaInfoEqual(const MediaInfo& expect, const MediaInfo& actual) {
|
||||
ASSERT_TRUE(MediaInfoEqual(expect, actual));
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "packager/base/memory/ref_counted.h"
|
||||
#include "packager/media/base/key_source.h"
|
||||
#include "packager/media/base/muxer_options.h"
|
||||
#include "packager/media/base/stream_info.h"
|
||||
#include "packager/media/base/video_stream_info.h"
|
||||
|
@ -20,6 +21,12 @@ namespace edash_packager {
|
|||
|
||||
namespace media {
|
||||
|
||||
// A string containing the escaped PSSH box (for use with a MediaInfo proto).
|
||||
// This is a full v0 PSSH box with the Widevine system ID and the PSSH data
|
||||
// 'pssh'
|
||||
const char kExpectedDefaultPsshBox[] =
|
||||
"\\000\\000\\000$pssh\\000\\000\\000\\000\\355\\357\\213\\251y\\326J\\316"
|
||||
"\\243\\310\\'\\334\\325\\035!\\355\\000\\000\\000\\4pssh";
|
||||
const char kExpectedDefaultMediaInfo[] =
|
||||
"bandwidth: 7620\n"
|
||||
"video_info {\n"
|
||||
|
@ -87,6 +94,9 @@ VideoStreamInfoParameters GetDefaultVideoStreamInfoParams();
|
|||
// Returns the "default" values for OnMediaEnd().
|
||||
OnMediaEndParameters GetDefaultOnMediaEndParams();
|
||||
|
||||
// Returns the "default" ProtectionSystemSpecificInfo for testing.
|
||||
std::vector<ProtectionSystemSpecificInfo> GetDefaultKeySystemInfo();
|
||||
|
||||
// Sets "default" values for muxer_options for testing.
|
||||
void SetDefaultMuxerOptionsValues(MuxerOptions* muxer_options);
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "packager/base/logging.h"
|
||||
#include "packager/media/base/muxer_options.h"
|
||||
#include "packager/media/base/stream_info.h"
|
||||
#include "packager/media/base/protection_system_specific_info.h"
|
||||
#include "packager/media/event/muxer_listener_internal.h"
|
||||
#include "packager/media/file/file.h"
|
||||
#include "packager/mpd/base/media_info.pb.h"
|
||||
|
@ -24,24 +25,15 @@ VodMediaInfoDumpMuxerListener::VodMediaInfoDumpMuxerListener(
|
|||
|
||||
VodMediaInfoDumpMuxerListener::~VodMediaInfoDumpMuxerListener() {}
|
||||
|
||||
void VodMediaInfoDumpMuxerListener::SetContentProtectionSchemeIdUri(
|
||||
const std::string& scheme_id_uri) {
|
||||
scheme_id_uri_ = scheme_id_uri;
|
||||
}
|
||||
|
||||
void VodMediaInfoDumpMuxerListener::OnEncryptionInfoReady(
|
||||
bool is_initial_encryption_info,
|
||||
const std::string& content_protection_uuid,
|
||||
const std::string& content_protection_name_version,
|
||||
const std::vector<uint8_t>& default_key_id,
|
||||
const std::vector<uint8_t>& pssh) {
|
||||
const std::vector<ProtectionSystemSpecificInfo>& key_system_info) {
|
||||
LOG_IF(WARNING, !is_initial_encryption_info)
|
||||
<< "Updating (non initial) encryption info is not supported by "
|
||||
"this module.";
|
||||
content_protection_uuid_ = content_protection_uuid;
|
||||
content_protection_name_version_ = content_protection_name_version;
|
||||
default_key_id_.assign(default_key_id.begin(), default_key_id.end());
|
||||
pssh_.assign(pssh.begin(), pssh.end());
|
||||
key_system_info_ = key_system_info;
|
||||
is_encrypted_ = true;
|
||||
}
|
||||
|
||||
|
@ -63,8 +55,7 @@ void VodMediaInfoDumpMuxerListener::OnMediaStart(
|
|||
|
||||
if (is_encrypted_) {
|
||||
internal::SetContentProtectionFields(
|
||||
content_protection_uuid_, content_protection_name_version_,
|
||||
default_key_id_, pssh_, media_info_.get());
|
||||
default_key_id_, key_system_info_, media_info_.get());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,17 +30,12 @@ class VodMediaInfoDumpMuxerListener : public MuxerListener {
|
|||
VodMediaInfoDumpMuxerListener(const std::string& output_file_name);
|
||||
~VodMediaInfoDumpMuxerListener() override;
|
||||
|
||||
/// If the stream is encrypted use this as 'schemeIdUri' attribute for
|
||||
/// ContentProtection element.
|
||||
void SetContentProtectionSchemeIdUri(const std::string& scheme_id_uri);
|
||||
|
||||
/// @name MuxerListener implementation overrides.
|
||||
/// @{
|
||||
void OnEncryptionInfoReady(bool is_initial_encryption_info,
|
||||
const std::string& content_protection_uuid,
|
||||
const std::string& content_protection_name_version,
|
||||
const std::vector<uint8_t>& default_key_id,
|
||||
const std::vector<uint8_t>& pssh) override;
|
||||
const std::vector<ProtectionSystemSpecificInfo>&
|
||||
key_system_info) override;
|
||||
void OnMediaStart(const MuxerOptions& muxer_options,
|
||||
const StreamInfo& stream_info,
|
||||
uint32_t time_scale,
|
||||
|
@ -71,15 +66,12 @@ class VodMediaInfoDumpMuxerListener : public MuxerListener {
|
|||
private:
|
||||
|
||||
std::string output_file_name_;
|
||||
std::string scheme_id_uri_;
|
||||
scoped_ptr<MediaInfo> media_info_;
|
||||
|
||||
bool is_encrypted_;
|
||||
// Storage for values passed to OnEncryptionInfoReady().
|
||||
std::string content_protection_uuid_;
|
||||
std::string content_protection_name_version_;
|
||||
std::string default_key_id_;
|
||||
std::string pssh_;
|
||||
std::vector<ProtectionSystemSpecificInfo> key_system_info_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(VodMediaInfoDumpMuxerListener);
|
||||
};
|
||||
|
|
|
@ -24,15 +24,7 @@ const bool kEnableEncryption = true;
|
|||
const uint8_t kBogusDefaultKeyId[] = {0x5f, 0x64, 0x65, 0x66, 0x61, 0x75,
|
||||
0x6c, 0x74, 0x5f, 0x6b, 0x65, 0x79,
|
||||
0x5f, 0x69, 0x64, 0x5f};
|
||||
// 'pssh'. Not a valid pssh box.
|
||||
const uint8_t kInvalidPssh[] = {
|
||||
0x70, 0x73, 0x73, 0x68
|
||||
};
|
||||
|
||||
// This should be in the uuid field of the protobuf. This is not a valid UUID
|
||||
// format but the protobof generation shouldn't care.
|
||||
const char kTestUUID[] = "myuuid";
|
||||
const char kTestContentProtectionName[] = "MyContentProtection version 1";
|
||||
const bool kInitialEncryptionInfo = true;
|
||||
} // namespace
|
||||
|
||||
|
@ -85,14 +77,9 @@ class VodMediaInfoDumpMuxerListenerTest : public ::testing::Test {
|
|||
kBogusDefaultKeyId,
|
||||
kBogusDefaultKeyId + arraysize(kBogusDefaultKeyId));
|
||||
|
||||
// This isn't a valid pssh box but the MediaInfo protobuf creator
|
||||
// shouldn't worry about it.
|
||||
std::vector<uint8_t> invalid_pssh(kInvalidPssh,
|
||||
kInvalidPssh + arraysize(kInvalidPssh));
|
||||
|
||||
listener_->OnEncryptionInfoReady(kInitialEncryptionInfo, kTestUUID,
|
||||
kTestContentProtectionName,
|
||||
bogus_default_key_id, invalid_pssh);
|
||||
listener_->OnEncryptionInfoReady(kInitialEncryptionInfo,
|
||||
bogus_default_key_id,
|
||||
GetDefaultKeySystemInfo());
|
||||
}
|
||||
listener_->OnMediaStart(muxer_options, stream_info, kReferenceTimeScale,
|
||||
MuxerListener::kContainerMp4);
|
||||
|
@ -162,15 +149,13 @@ TEST_F(VodMediaInfoDumpMuxerListenerTest, UnencryptedStream_Normal) {
|
|||
}
|
||||
|
||||
TEST_F(VodMediaInfoDumpMuxerListenerTest, EncryptedStream_Normal) {
|
||||
listener_->SetContentProtectionSchemeIdUri("http://foo.com/bar");
|
||||
|
||||
scoped_refptr<StreamInfo> stream_info =
|
||||
CreateVideoStreamInfo(GetDefaultVideoStreamInfoParams());
|
||||
FireOnMediaStartWithDefaultMuxerOptions(*stream_info, kEnableEncryption);
|
||||
OnMediaEndParameters media_end_param = GetDefaultOnMediaEndParams();
|
||||
FireOnMediaEndWithParams(media_end_param);
|
||||
|
||||
const char kExpectedProtobufOutput[] =
|
||||
const std::string kExpectedProtobufOutput =
|
||||
"bandwidth: 7620\n"
|
||||
"video_info {\n"
|
||||
" codec: 'avc1.010101'\n"
|
||||
|
@ -194,9 +179,8 @@ TEST_F(VodMediaInfoDumpMuxerListenerTest, EncryptedStream_Normal) {
|
|||
"media_duration_seconds: 10.5\n"
|
||||
"protected_content {\n"
|
||||
" content_protection_entry {\n"
|
||||
" uuid: 'myuuid'\n"
|
||||
" name_version: 'MyContentProtection version 1'\n"
|
||||
" pssh: 'pssh'\n"
|
||||
" uuid: 'edef8ba9-79d6-4ace-a3c8-27dcd51d21ed'\n"
|
||||
" pssh: '" + std::string(kExpectedDefaultPsshBox) + "'\n"
|
||||
" }\n"
|
||||
" default_key_id: '_default_key_id_'\n"
|
||||
"}\n";
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace media {
|
|||
namespace mp4 {
|
||||
|
||||
namespace {
|
||||
const bool kInitialEncryptionInfo = false;
|
||||
const bool kInitialEncryptionInfo = true;
|
||||
} // namespace
|
||||
|
||||
KeyRotationFragmenter::KeyRotationFragmenter(MovieFragment* moof,
|
||||
|
@ -58,17 +58,18 @@ Status KeyRotationFragmenter::PrepareFragmentForEncryption(
|
|||
need_to_refresh_encryptor = true;
|
||||
}
|
||||
|
||||
// One and only one 'pssh' box is needed.
|
||||
if (moof_->pssh.empty())
|
||||
moof_->pssh.resize(1);
|
||||
DCHECK(encryption_key());
|
||||
moof_->pssh[0].raw_box = encryption_key()->pssh;
|
||||
const std::vector<ProtectionSystemSpecificInfo>& system_info =
|
||||
encryption_key()->key_system_info;
|
||||
moof_->pssh.resize(system_info.size());
|
||||
for (size_t i = 0; i < system_info.size(); i++) {
|
||||
moof_->pssh[i].raw_box = system_info[i].CreateBox();
|
||||
}
|
||||
|
||||
if (muxer_listener_) {
|
||||
muxer_listener_->OnEncryptionInfoReady(
|
||||
!kInitialEncryptionInfo,
|
||||
encryption_key_source_->UUID(), encryption_key_source_->SystemName(),
|
||||
encryption_key()->key_id, encryption_key()->pssh);
|
||||
muxer_listener_->OnEncryptionInfoReady(!kInitialEncryptionInfo,
|
||||
encryption_key()->key_id,
|
||||
encryption_key()->key_system_info);
|
||||
}
|
||||
|
||||
// Skip the following steps if the current fragment is not going to be
|
||||
|
|
|
@ -165,11 +165,11 @@ Status Segmenter::Initialize(const std::vector<MediaStream*>& streams,
|
|||
kKeyRotationDefaultKeyId + arraysize(kKeyRotationDefaultKeyId));
|
||||
GenerateEncryptedSampleEntry(encryption_key, clear_lead_in_seconds,
|
||||
&description);
|
||||
|
||||
if (muxer_listener_) {
|
||||
muxer_listener_->OnEncryptionInfoReady(
|
||||
kInitialEncryptionInfo, encryption_key_source->UUID(),
|
||||
encryption_key_source->SystemName(), encryption_key.key_id,
|
||||
std::vector<uint8_t>());
|
||||
kInitialEncryptionInfo, encryption_key.key_id,
|
||||
encryption_key.key_system_info);
|
||||
}
|
||||
|
||||
fragmenters_[i] = new KeyRotationFragmenter(
|
||||
|
@ -190,17 +190,16 @@ Status Segmenter::Initialize(const std::vector<MediaStream*>& streams,
|
|||
GenerateEncryptedSampleEntry(*encryption_key, clear_lead_in_seconds,
|
||||
&description);
|
||||
|
||||
// One and only one pssh box is needed.
|
||||
if (moov_->pssh.empty()) {
|
||||
moov_->pssh.resize(1);
|
||||
moov_->pssh[0].raw_box = encryption_key->pssh;
|
||||
moov_->pssh.resize(encryption_key->key_system_info.size());
|
||||
for (size_t i = 0; i < encryption_key->key_system_info.size(); i++) {
|
||||
moov_->pssh[i].raw_box = encryption_key->key_system_info[i].CreateBox();
|
||||
}
|
||||
|
||||
// Also only one default key id.
|
||||
if (muxer_listener_) {
|
||||
muxer_listener_->OnEncryptionInfoReady(
|
||||
kInitialEncryptionInfo,
|
||||
encryption_key_source->UUID(), encryption_key_source->SystemName(),
|
||||
encryption_key->key_id, encryption_key->pssh);
|
||||
muxer_listener_->OnEncryptionInfoReady(kInitialEncryptionInfo,
|
||||
encryption_key->key_id,
|
||||
encryption_key->key_system_info);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace media {
|
|||
namespace {
|
||||
|
||||
const uint64_t kDuration = 1000;
|
||||
const std::string kKeyId = "68656c6c6f20776f726c64";
|
||||
const std::string kKeyId = "4c6f72656d20697073756d20646f6c6f";
|
||||
const std::string kIv = "0123456789012345";
|
||||
const std::string kKey = "01234567890123456789012345678901";
|
||||
const std::string kPsshData = "";
|
||||
|
@ -37,8 +37,8 @@ const uint8_t kBasicSupportData[] = {
|
|||
0x42, 0x87, 0x81, 0x02,
|
||||
// DocTypeReadVersion: 2
|
||||
0x42, 0x85, 0x81, 0x02,
|
||||
// ID: Segment, Payload Size: 406
|
||||
0x18, 0x53, 0x80, 0x67, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x96,
|
||||
// ID: Segment, Payload Size: 411
|
||||
0x18, 0x53, 0x80, 0x67, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x9b,
|
||||
// ID: SeekHead, Payload Size: 30
|
||||
0x11, 0x4d, 0x9b, 0x74, 0x9e,
|
||||
// ID: Seek, Payload Size: 12
|
||||
|
@ -46,13 +46,13 @@ const uint8_t kBasicSupportData[] = {
|
|||
// SeekID: binary(4) (Cluster)
|
||||
0x53, 0xab, 0x84, 0x1f, 0x43, 0xb6, 0x75,
|
||||
// SeekPosition: 322
|
||||
0x53, 0xac, 0x82, 0x01, 0x42,
|
||||
0x53, 0xac, 0x82, 0x01, 0x47,
|
||||
// ID: Seek, Payload Size: 12
|
||||
0x4d, 0xbb, 0x8c,
|
||||
// SeekID: binary(4) (Cues)
|
||||
0x53, 0xab, 0x84, 0x1c, 0x53, 0xbb, 0x6b,
|
||||
// SeekPosition: 429
|
||||
0x53, 0xac, 0x82, 0x01, 0xb3,
|
||||
0x53, 0xac, 0x82, 0x01, 0xb8,
|
||||
// ID: Void, Payload Size: 52
|
||||
0xec, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
@ -75,10 +75,10 @@ const uint8_t kBasicSupportData[] = {
|
|||
0x65, 0x2f, 0x65, 0x64, 0x61, 0x73, 0x68, 0x2d, 0x70, 0x61, 0x63, 0x6b,
|
||||
0x61, 0x67, 0x65, 0x72, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
|
||||
0x20, 0x74, 0x65, 0x73, 0x74,
|
||||
// ID: Tracks, Payload Size: 87
|
||||
0x16, 0x54, 0xae, 0x6b, 0xd7,
|
||||
// ID: Track, Payload Size: 85
|
||||
0xae, 0xd5,
|
||||
// ID: Tracks, Payload Size: 92
|
||||
0x16, 0x54, 0xae, 0x6b, 0xdc,
|
||||
// ID: Track, Payload Size: 90
|
||||
0xae, 0xda,
|
||||
// TrackNumber: 1
|
||||
0xd7, 0x81, 0x01,
|
||||
// TrackUID: 1
|
||||
|
@ -89,24 +89,24 @@ const uint8_t kBasicSupportData[] = {
|
|||
0x86, 0x85, 0x56, 0x5f, 0x56, 0x50, 0x38,
|
||||
// Language: 'en'
|
||||
0x22, 0xb5, 0x9c, 0x82, 0x65, 0x6e,
|
||||
// ID: ContentEncodings, Payload Size: 43
|
||||
0x6d, 0x80, 0xab,
|
||||
// ID: ContentEncoding, Payload Size: 40
|
||||
0x62, 0x40, 0xa8,
|
||||
// ID: ContentEncodings, Payload Size: 48
|
||||
0x6d, 0x80, 0xb0,
|
||||
// ID: ContentEncoding, Payload Size: 45
|
||||
0x62, 0x40, 0xad,
|
||||
// ContentEncodingOrder: 0
|
||||
0x50, 0x31, 0x81, 0x00,
|
||||
// ContentEncodingScope: 1
|
||||
0x50, 0x32, 0x81, 0x01,
|
||||
// ContentEncodingType: 1
|
||||
0x50, 0x33, 0x81, 0x01,
|
||||
// ID: ContentEncryption, Payload Size: 25
|
||||
0x50, 0x35, 0x99,
|
||||
// ID: ContentEncryption, Payload Size: 30
|
||||
0x50, 0x35, 0x9e,
|
||||
// ContentEncAlgo: 5
|
||||
0x47, 0xe1, 0x81, 0x05,
|
||||
// ContentEncKeyID: binary(11)
|
||||
0x47, 0xe2, 0x8b,
|
||||
0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c,
|
||||
0x64,
|
||||
// ContentEncKeyID: binary(16)
|
||||
0x47, 0xe2, 0x90,
|
||||
0x4c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70,
|
||||
0x73, 0x75, 0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f,
|
||||
// ID: ContentEncAESSettings, Payload Size: 4
|
||||
0x47, 0xe7, 0x84,
|
||||
// AESSettingsCipherMode: 1
|
||||
|
@ -177,8 +177,8 @@ const uint8_t kBasicSupportData[] = {
|
|||
0xb7, 0x87,
|
||||
// CueTrack: 1
|
||||
0xf7, 0x81, 0x01,
|
||||
// CueClusterPosition: 274
|
||||
0xf1, 0x82, 0x01, 0x12
|
||||
// CueClusterPosition: 279
|
||||
0xf1, 0x82, 0x01, 0x17
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -119,9 +119,9 @@ Status Encryptor::CreateEncryptor(MuxerListener* muxer_listener,
|
|||
|
||||
if (muxer_listener) {
|
||||
const bool kInitialEncryptionInfo = true;
|
||||
muxer_listener->OnEncryptionInfoReady(
|
||||
kInitialEncryptionInfo, key_source->UUID(), key_source->SystemName(),
|
||||
encryption_key->key_id, encryption_key->pssh);
|
||||
muxer_listener->OnEncryptionInfoReady(kInitialEncryptionInfo,
|
||||
encryption_key->key_id,
|
||||
encryption_key->key_system_info);
|
||||
}
|
||||
|
||||
key_ = encryption_key.Pass();
|
||||
|
|
|
@ -268,7 +268,7 @@ TEST_P(SimpleMpdNotifierTest, UpdateEncryption) {
|
|||
" content_protection_entry {\n"
|
||||
" uuid: 'myuuid'\n"
|
||||
" name_version: 'MyContentProtection version 1'\n"
|
||||
" pssh: 'pssh1'\n"
|
||||
" pssh: 'psshsomethingelse'\n"
|
||||
" }\n"
|
||||
" default_key_id: '_default_key_id_'\n"
|
||||
"}\n"
|
||||
|
|
Loading…
Reference in New Issue