Pass content protection information to MuxerListener
- The UUID and DRM name can be fetched from KeySource. - Add ProtectedContent message to MediaInfo. The message contains basic information for the protected content, such as the default key ID for the content. - The message is required to separate Representations with different content protection information into different AdaptationSets. Change-Id: Ib9dc834ae0abf93b7ca0acdf52a865b1394a4816
This commit is contained in:
parent
21e43966db
commit
5c8efd332e
|
@ -14,6 +14,8 @@ namespace {
|
||||||
const uint8_t kWidevineSystemId[] = {0xed, 0xef, 0x8b, 0xa9, 0x79, 0xd6,
|
const uint8_t kWidevineSystemId[] = {0xed, 0xef, 0x8b, 0xa9, 0x79, 0xd6,
|
||||||
0x4a, 0xce, 0xa3, 0xc8, 0x27, 0xdc,
|
0x4a, 0xce, 0xa3, 0xc8, 0x27, 0xdc,
|
||||||
0xd5, 0x1d, 0x21, 0xed};
|
0xd5, 0x1d, 0x21, 0xed};
|
||||||
|
const char kDefaultUUID[] = "";
|
||||||
|
const char kDefaultSystemName[] = "";
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace edash_packager {
|
namespace edash_packager {
|
||||||
|
@ -67,6 +69,14 @@ Status KeySource::GetCryptoPeriodKey(uint32_t crypto_period_index,
|
||||||
return Status(error::UNIMPLEMENTED, "");
|
return Status(error::UNIMPLEMENTED, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
|
|
@ -83,6 +83,19 @@ 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.
|
||||||
|
|
|
@ -236,6 +236,10 @@ 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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@ class WidevineKeySource : public KeySource {
|
||||||
virtual Status GetCryptoPeriodKey(uint32_t crypto_period_index,
|
virtual Status GetCryptoPeriodKey(uint32_t crypto_period_index,
|
||||||
TrackType track_type,
|
TrackType track_type,
|
||||||
EncryptionKey* key) OVERRIDE;
|
EncryptionKey* key) OVERRIDE;
|
||||||
|
virtual std::string UUID() OVERRIDE;
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
/// Set signer for the key source.
|
/// Set signer for the key source.
|
||||||
|
|
|
@ -19,7 +19,7 @@ namespace edash_packager {
|
||||||
namespace media {
|
namespace media {
|
||||||
|
|
||||||
MpdNotifyMuxerListener::MpdNotifyMuxerListener(MpdNotifier* mpd_notifier)
|
MpdNotifyMuxerListener::MpdNotifyMuxerListener(MpdNotifier* mpd_notifier)
|
||||||
: mpd_notifier_(mpd_notifier), notification_id_(0) {
|
: mpd_notifier_(mpd_notifier), notification_id_(0), is_encrypted_(false) {
|
||||||
DCHECK(mpd_notifier);
|
DCHECK(mpd_notifier);
|
||||||
DCHECK(mpd_notifier->dash_profile() == kOnDemandProfile ||
|
DCHECK(mpd_notifier->dash_profile() == kOnDemandProfile ||
|
||||||
mpd_notifier->dash_profile() == kLiveProfile);
|
mpd_notifier->dash_profile() == kLiveProfile);
|
||||||
|
@ -32,12 +32,23 @@ void MpdNotifyMuxerListener::SetContentProtectionSchemeIdUri(
|
||||||
scheme_id_uri_ = scheme_id_uri;
|
scheme_id_uri_ = scheme_id_uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MpdNotifyMuxerListener::OnEncryptionInfoReady(
|
||||||
|
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) {
|
||||||
|
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());
|
||||||
|
is_encrypted_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
void MpdNotifyMuxerListener::OnMediaStart(
|
void MpdNotifyMuxerListener::OnMediaStart(
|
||||||
const MuxerOptions& muxer_options,
|
const MuxerOptions& muxer_options,
|
||||||
const StreamInfo& stream_info,
|
const StreamInfo& stream_info,
|
||||||
uint32_t time_scale,
|
uint32_t time_scale,
|
||||||
ContainerType container_type,
|
ContainerType container_type) {
|
||||||
bool is_encrypted) {
|
|
||||||
scoped_ptr<MediaInfo> media_info(new MediaInfo());
|
scoped_ptr<MediaInfo> media_info(new MediaInfo());
|
||||||
if (!internal::GenerateMediaInfo(muxer_options,
|
if (!internal::GenerateMediaInfo(muxer_options,
|
||||||
stream_info,
|
stream_info,
|
||||||
|
@ -48,7 +59,17 @@ void MpdNotifyMuxerListener::OnMediaStart(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_encrypted) {
|
if (is_encrypted_) {
|
||||||
|
internal::SetContentProtectionFields(
|
||||||
|
content_protection_uuid_, content_protection_name_version_,
|
||||||
|
default_key_id_, pssh_, media_info.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_encrypted_) {
|
||||||
|
// TODO(rkuroiwa): When MediaInfo's content protection fields are processed
|
||||||
|
// in MpdBuilder (e.g. content_protection_uuid, default_key_id) then skip
|
||||||
|
// this step if scheme_id_uri_'s UUID == content_protection_uuid_.
|
||||||
|
// Also consider removing SetContentProtectionSchemeIdUri().
|
||||||
if (!internal::AddContentProtectionElements(
|
if (!internal::AddContentProtectionElements(
|
||||||
container_type, scheme_id_uri_, media_info.get())) {
|
container_type, scheme_id_uri_, media_info.get())) {
|
||||||
LOG(ERROR) << "Failed to add content protection elements.";
|
LOG(ERROR) << "Failed to add content protection elements.";
|
||||||
|
|
|
@ -36,11 +36,15 @@ class MpdNotifyMuxerListener : public MuxerListener {
|
||||||
|
|
||||||
/// @name MuxerListener implementation overrides.
|
/// @name MuxerListener implementation overrides.
|
||||||
/// @{
|
/// @{
|
||||||
|
virtual void OnEncryptionInfoReady(
|
||||||
|
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;
|
||||||
virtual void OnMediaStart(const MuxerOptions& muxer_options,
|
virtual void OnMediaStart(const MuxerOptions& muxer_options,
|
||||||
const StreamInfo& stream_info,
|
const StreamInfo& stream_info,
|
||||||
uint32_t time_scale,
|
uint32_t time_scale,
|
||||||
ContainerType container_type,
|
ContainerType container_type) OVERRIDE;
|
||||||
bool is_encrypted) OVERRIDE;
|
|
||||||
virtual void OnSampleDurationReady(uint32_t sample_duration) OVERRIDE;
|
virtual void OnSampleDurationReady(uint32_t sample_duration) OVERRIDE;
|
||||||
virtual void OnMediaEnd(bool has_init_range,
|
virtual void OnMediaEnd(bool has_init_range,
|
||||||
uint64_t init_range_start,
|
uint64_t init_range_start,
|
||||||
|
@ -61,6 +65,13 @@ class MpdNotifyMuxerListener : public MuxerListener {
|
||||||
scoped_ptr<MediaInfo> media_info_;
|
scoped_ptr<MediaInfo> media_info_;
|
||||||
std::string scheme_id_uri_;
|
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_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(MpdNotifyMuxerListener);
|
DISALLOW_COPY_AND_ASSIGN(MpdNotifyMuxerListener);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
//
|
//
|
||||||
// Event handler for events fired by Muxer.
|
// Event handler for events fired by Muxer.
|
||||||
|
|
||||||
|
// TODO(rkuroiwa): Document using doxygen style comments.
|
||||||
|
|
||||||
#ifndef MEDIA_EVENT_MUXER_LISTENER_H_
|
#ifndef MEDIA_EVENT_MUXER_LISTENER_H_
|
||||||
#define MEDIA_EVENT_MUXER_LISTENER_H_
|
#define MEDIA_EVENT_MUXER_LISTENER_H_
|
||||||
|
|
||||||
|
@ -34,7 +36,24 @@ class MuxerListener {
|
||||||
|
|
||||||
virtual ~MuxerListener() {};
|
virtual ~MuxerListener() {};
|
||||||
|
|
||||||
// Called when muxing starts. This event happens before any other events.
|
// 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.
|
||||||
|
// |content_protection_name_version| is the DRM system and version name.
|
||||||
|
// For ISO BMFF (MP4) media:
|
||||||
|
// |default_key_id| is the default_KID in 'tenc' box. The format should
|
||||||
|
// be a vector of uint8_t, i.e. not (necessarily) human readable hex string.
|
||||||
|
// |pssh| is the whole 'pssh' box.
|
||||||
|
virtual void OnEncryptionInfoReady(
|
||||||
|
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) = 0;
|
||||||
|
|
||||||
|
// Called when muxing starts.
|
||||||
// For MPEG DASH Live profile, the initialization segment information is
|
// For MPEG DASH Live profile, the initialization segment information is
|
||||||
// available from StreamInfo.
|
// available from StreamInfo.
|
||||||
// |time_scale| is a reference time scale that overrides the time scale
|
// |time_scale| is a reference time scale that overrides the time scale
|
||||||
|
@ -42,8 +61,7 @@ class MuxerListener {
|
||||||
virtual void OnMediaStart(const MuxerOptions& muxer_options,
|
virtual void OnMediaStart(const MuxerOptions& muxer_options,
|
||||||
const StreamInfo& stream_info,
|
const StreamInfo& stream_info,
|
||||||
uint32_t time_scale,
|
uint32_t time_scale,
|
||||||
ContainerType container_type,
|
ContainerType container_type) = 0;
|
||||||
bool is_encrypted) = 0;
|
|
||||||
|
|
||||||
/// Called when the average sample duration of the media is determined.
|
/// Called when the average sample duration of the media is determined.
|
||||||
/// @param sample_duration in timescale of the media.
|
/// @param sample_duration in timescale of the media.
|
||||||
|
|
|
@ -201,6 +201,8 @@ bool SetVodInformation(bool has_init_range,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(rkuroiwa): Move this logic to MpdBuilder? MuxerListener probably doesn't
|
||||||
|
// need to know this.
|
||||||
bool AddContentProtectionElements(MuxerListener::ContainerType container_type,
|
bool AddContentProtectionElements(MuxerListener::ContainerType container_type,
|
||||||
const std::string& user_scheme_id_uri,
|
const std::string& user_scheme_id_uri,
|
||||||
MediaInfo* media_info) {
|
MediaInfo* media_info) {
|
||||||
|
@ -237,6 +239,36 @@ bool AddContentProtectionElements(MuxerListener::ContainerType container_type,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
MediaInfo* media_info) {
|
||||||
|
DCHECK(media_info);
|
||||||
|
MediaInfo::ProtectedContent* protected_content =
|
||||||
|
media_info->mutable_protected_content();
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace media
|
} // namespace media
|
||||||
} // namespace edash_packager
|
} // namespace edash_packager
|
||||||
|
|
|
@ -54,6 +54,22 @@ bool AddContentProtectionElements(MuxerListener::ContainerType container_type,
|
||||||
const std::string& user_scheme_id_uri,
|
const std::string& user_scheme_id_uri,
|
||||||
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
|
||||||
|
/// readable, typically 16 bytes.)
|
||||||
|
/// @param pssh is the pssh for the media in hex (i.e. non-human readable, raw
|
||||||
|
/// 'pssh' box.)
|
||||||
|
/// @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,
|
||||||
|
MediaInfo* media_info);
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace media
|
} // namespace media
|
||||||
} // namespace edash_packager
|
} // namespace edash_packager
|
||||||
|
|
|
@ -20,7 +20,7 @@ namespace media {
|
||||||
|
|
||||||
VodMediaInfoDumpMuxerListener::VodMediaInfoDumpMuxerListener(
|
VodMediaInfoDumpMuxerListener::VodMediaInfoDumpMuxerListener(
|
||||||
const std::string& output_file_name)
|
const std::string& output_file_name)
|
||||||
: output_file_name_(output_file_name) {}
|
: output_file_name_(output_file_name), is_encrypted_(false) {}
|
||||||
|
|
||||||
VodMediaInfoDumpMuxerListener::~VodMediaInfoDumpMuxerListener() {}
|
VodMediaInfoDumpMuxerListener::~VodMediaInfoDumpMuxerListener() {}
|
||||||
|
|
||||||
|
@ -29,12 +29,23 @@ void VodMediaInfoDumpMuxerListener::SetContentProtectionSchemeIdUri(
|
||||||
scheme_id_uri_ = scheme_id_uri;
|
scheme_id_uri_ = scheme_id_uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VodMediaInfoDumpMuxerListener::OnEncryptionInfoReady(
|
||||||
|
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) {
|
||||||
|
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());
|
||||||
|
is_encrypted_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
void VodMediaInfoDumpMuxerListener::OnMediaStart(
|
void VodMediaInfoDumpMuxerListener::OnMediaStart(
|
||||||
const MuxerOptions& muxer_options,
|
const MuxerOptions& muxer_options,
|
||||||
const StreamInfo& stream_info,
|
const StreamInfo& stream_info,
|
||||||
uint32_t time_scale,
|
uint32_t time_scale,
|
||||||
ContainerType container_type,
|
ContainerType container_type) {
|
||||||
bool is_encrypted) {
|
|
||||||
DCHECK(muxer_options.single_segment);
|
DCHECK(muxer_options.single_segment);
|
||||||
media_info_.reset(new MediaInfo());
|
media_info_.reset(new MediaInfo());
|
||||||
if (!internal::GenerateMediaInfo(muxer_options,
|
if (!internal::GenerateMediaInfo(muxer_options,
|
||||||
|
@ -46,7 +57,13 @@ void VodMediaInfoDumpMuxerListener::OnMediaStart(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_encrypted) {
|
if (is_encrypted_) {
|
||||||
|
internal::SetContentProtectionFields(
|
||||||
|
content_protection_uuid_, content_protection_name_version_,
|
||||||
|
default_key_id_, pssh_, media_info_.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_encrypted_) {
|
||||||
if (!internal::AddContentProtectionElements(
|
if (!internal::AddContentProtectionElements(
|
||||||
container_type, scheme_id_uri_, media_info_.get())) {
|
container_type, scheme_id_uri_, media_info_.get())) {
|
||||||
LOG(ERROR) << "Failed to add content protection elements.";
|
LOG(ERROR) << "Failed to add content protection elements.";
|
||||||
|
|
|
@ -36,11 +36,16 @@ class VodMediaInfoDumpMuxerListener : public MuxerListener {
|
||||||
|
|
||||||
/// @name MuxerListener implementation overrides.
|
/// @name MuxerListener implementation overrides.
|
||||||
/// @{
|
/// @{
|
||||||
virtual void OnMediaStart(const MuxerOptions& muxer_options,
|
virtual void OnEncryptionInfoReady(
|
||||||
|
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;
|
||||||
|
virtual void OnMediaStart(
|
||||||
|
const MuxerOptions& muxer_options,
|
||||||
const StreamInfo& stream_info,
|
const StreamInfo& stream_info,
|
||||||
uint32_t time_scale,
|
uint32_t time_scale,
|
||||||
ContainerType container_type,
|
ContainerType container_type) OVERRIDE;
|
||||||
bool is_encrypted) OVERRIDE;
|
|
||||||
virtual void OnSampleDurationReady(uint32_t sample_duration) OVERRIDE;
|
virtual void OnSampleDurationReady(uint32_t sample_duration) OVERRIDE;
|
||||||
virtual void OnMediaEnd(bool has_init_range,
|
virtual void OnMediaEnd(bool has_init_range,
|
||||||
uint64_t init_range_start,
|
uint64_t init_range_start,
|
||||||
|
@ -63,6 +68,13 @@ class VodMediaInfoDumpMuxerListener : public MuxerListener {
|
||||||
std::string scheme_id_uri_;
|
std::string scheme_id_uri_;
|
||||||
scoped_ptr<MediaInfo> media_info_;
|
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_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(VodMediaInfoDumpMuxerListener);
|
DISALLOW_COPY_AND_ASSIGN(VodMediaInfoDumpMuxerListener);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,19 @@
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
const bool kEnableEncryption = true;
|
const bool kEnableEncryption = true;
|
||||||
|
// '_default_key_id_' (length 16).
|
||||||
|
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";
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace edash_packager {
|
namespace edash_packager {
|
||||||
|
@ -178,11 +191,21 @@ class VodMediaInfoDumpMuxerListenerTest : public ::testing::Test {
|
||||||
MuxerOptions muxer_options;
|
MuxerOptions muxer_options;
|
||||||
SetDefaultMuxerOptionsValues(&muxer_options);
|
SetDefaultMuxerOptionsValues(&muxer_options);
|
||||||
const uint32_t kReferenceTimeScale = 1000;
|
const uint32_t kReferenceTimeScale = 1000;
|
||||||
listener_->OnMediaStart(muxer_options,
|
if (enable_encryption) {
|
||||||
stream_info,
|
std::vector<uint8_t> bogus_default_key_id(
|
||||||
kReferenceTimeScale,
|
kBogusDefaultKeyId,
|
||||||
MuxerListener::kContainerMp4,
|
kBogusDefaultKeyId + arraysize(kBogusDefaultKeyId));
|
||||||
enable_encryption);
|
|
||||||
|
// 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(kTestUUID, kTestContentProtectionName,
|
||||||
|
bogus_default_key_id, invalid_pssh);
|
||||||
|
}
|
||||||
|
listener_->OnMediaStart(muxer_options, stream_info, kReferenceTimeScale,
|
||||||
|
MuxerListener::kContainerMp4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FireOnMediaEndWithParams(const OnMediaEndParameters& params) {
|
void FireOnMediaEndWithParams(const OnMediaEndParameters& params) {
|
||||||
|
@ -285,7 +308,16 @@ TEST_F(VodMediaInfoDumpMuxerListenerTest, EncryptedStream_Normal) {
|
||||||
"reference_time_scale: 1000\n"
|
"reference_time_scale: 1000\n"
|
||||||
"container_type: 1\n"
|
"container_type: 1\n"
|
||||||
"media_file_name: 'test_output_file_name.mp4'\n"
|
"media_file_name: 'test_output_file_name.mp4'\n"
|
||||||
"media_duration_seconds: 10.5\n";
|
"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"
|
||||||
|
" }\n"
|
||||||
|
" default_key_id: '_default_key_id_'\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
ASSERT_NO_FATAL_FAILURE(ExpectTempFileToEqual(kExpectedProtobufOutput));
|
ASSERT_NO_FATAL_FAILURE(ExpectTempFileToEqual(kExpectedProtobufOutput));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -244,8 +244,7 @@ void MP4Muxer::FireOnMediaStartEvent() {
|
||||||
muxer_listener()->OnMediaStart(options(),
|
muxer_listener()->OnMediaStart(options(),
|
||||||
*streams().front()->info(),
|
*streams().front()->info(),
|
||||||
timescale,
|
timescale,
|
||||||
MuxerListener::kContainerMp4,
|
MuxerListener::kContainerMp4);
|
||||||
encryption_key_source() != NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MP4Muxer::FireOnMediaEndEvent() {
|
void MP4Muxer::FireOnMediaEndEvent() {
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "packager/media/base/media_stream.h"
|
#include "packager/media/base/media_stream.h"
|
||||||
#include "packager/media/base/muxer_options.h"
|
#include "packager/media/base/muxer_options.h"
|
||||||
#include "packager/media/base/video_stream_info.h"
|
#include "packager/media/base/video_stream_info.h"
|
||||||
|
#include "packager/media/event/muxer_listener.h"
|
||||||
#include "packager/media/event/progress_listener.h"
|
#include "packager/media/event/progress_listener.h"
|
||||||
#include "packager/media/formats/mp4/box_definitions.h"
|
#include "packager/media/formats/mp4/box_definitions.h"
|
||||||
#include "packager/media/formats/mp4/key_rotation_fragmenter.h"
|
#include "packager/media/formats/mp4/key_rotation_fragmenter.h"
|
||||||
|
@ -196,6 +197,13 @@ Status Segmenter::Initialize(const std::vector<MediaStream*>& streams,
|
||||||
if (moov_->pssh.empty()) {
|
if (moov_->pssh.empty()) {
|
||||||
moov_->pssh.resize(1);
|
moov_->pssh.resize(1);
|
||||||
moov_->pssh[0].raw_box = encryption_key->pssh;
|
moov_->pssh[0].raw_box = encryption_key->pssh;
|
||||||
|
|
||||||
|
// Also only one default key id.
|
||||||
|
if (muxer_listener_) {
|
||||||
|
muxer_listener_->OnEncryptionInfoReady(
|
||||||
|
encryption_key_source->UUID(), encryption_key_source->SystemName(),
|
||||||
|
encryption_key->key_id, encryption_key->pssh);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fragmenters_[i] = new EncryptingFragmenter(
|
fragmenters_[i] = new EncryptingFragmenter(
|
||||||
|
|
|
@ -55,6 +55,26 @@ message MediaInfo {
|
||||||
optional string language = 2;
|
optional string language = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message ProtectedContent {
|
||||||
|
message ContentProtectionEntry {
|
||||||
|
// Human readable UUID of the DRM.
|
||||||
|
optional string uuid = 1;
|
||||||
|
// Human readable DRM name and version string.
|
||||||
|
// e.g. "My Content Protection v1.0"
|
||||||
|
optional string name_version = 2;
|
||||||
|
// The raw 'pssh' box for the media.
|
||||||
|
optional bytes pssh = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The default key ID for the encrypted media.
|
||||||
|
optional bytes default_key_id = 1;
|
||||||
|
repeated ContentProtectionEntry content_protection_entry = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(rkuroiwa): Remove this. <ContentProtection> element that must be added
|
||||||
|
// should be done by directly using the MpdBuilder interface.
|
||||||
|
// Use this to specify ContentProtection elements that should be set in
|
||||||
|
// the MPD, if ContentProtectionEntry is not sufficient.
|
||||||
message ContentProtectionXml {
|
message ContentProtectionXml {
|
||||||
message AttributeNameValuePair {
|
message AttributeNameValuePair {
|
||||||
optional string name = 1;
|
optional string name = 1;
|
||||||
|
@ -85,6 +105,10 @@ message MediaInfo {
|
||||||
optional TextInfo text_info = 4;
|
optional TextInfo text_info = 4;
|
||||||
repeated ContentProtectionXml content_protections = 5;
|
repeated ContentProtectionXml content_protections = 5;
|
||||||
|
|
||||||
|
// This is set if the content is protected with a content protection,
|
||||||
|
// i.e. encrypted.
|
||||||
|
optional ProtectedContent protected_content = 15;
|
||||||
|
|
||||||
// This is the reference time scale if there are multiple VideoInfo and/or
|
// This is the reference time scale if there are multiple VideoInfo and/or
|
||||||
// AudioInfo.
|
// AudioInfo.
|
||||||
optional uint32 reference_time_scale = 13;
|
optional uint32 reference_time_scale = 13;
|
||||||
|
|
Loading…
Reference in New Issue