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