Add 'pssh' box for clear lead fragments as well
This is to workaround a Chrome limitation that CDM must be initialized before starting the playback. CDM can only be initialized with a valid 'pssh'. Change-Id: Ia34e90dac42abbcdf0193fe4e3c971c87debdd42
This commit is contained in:
parent
b25834a910
commit
e7fe62763d
|
@ -51,20 +51,21 @@ Status EncryptingFragmenter::InitializeFragment() {
|
|||
if (!status.ok())
|
||||
return status;
|
||||
|
||||
// Enable encryption for this fragment if |clear_time_| becomes non-positive.
|
||||
if (clear_time_ <= 0)
|
||||
return PrepareFragmentForEncryption();
|
||||
traf()->auxiliary_size.sample_info_sizes.clear();
|
||||
traf()->auxiliary_offset.offsets.clear();
|
||||
|
||||
// Otherwise, this fragment should be in clear text.
|
||||
// At most two sample description entries, an encrypted entry and a clear
|
||||
// entry, are generated. The 1-based clear entry index is always 2.
|
||||
const uint32 kClearSampleDescriptionIndex = 2;
|
||||
const bool enable_encryption = clear_time_ <= 0;
|
||||
if (!enable_encryption) {
|
||||
// This fragment should be in clear text.
|
||||
// At most two sample description entries, an encrypted entry and a clear
|
||||
// entry, are generated. The 1-based clear entry index is always 2.
|
||||
const uint32 kClearSampleDescriptionIndex = 2;
|
||||
|
||||
traf()->header.flags |=
|
||||
TrackFragmentHeader::kSampleDescriptionIndexPresentMask;
|
||||
traf()->header.sample_description_index = kClearSampleDescriptionIndex;
|
||||
|
||||
return Status::OK;
|
||||
traf()->header.flags |=
|
||||
TrackFragmentHeader::kSampleDescriptionIndexPresentMask;
|
||||
traf()->header.sample_description_index = kClearSampleDescriptionIndex;
|
||||
}
|
||||
return PrepareFragmentForEncryption(enable_encryption);
|
||||
}
|
||||
|
||||
void EncryptingFragmenter::FinalizeFragment() {
|
||||
|
@ -78,10 +79,9 @@ void EncryptingFragmenter::FinalizeFragment() {
|
|||
Fragmenter::FinalizeFragment();
|
||||
}
|
||||
|
||||
Status EncryptingFragmenter::PrepareFragmentForEncryption() {
|
||||
traf()->auxiliary_size.sample_info_sizes.clear();
|
||||
traf()->auxiliary_offset.offsets.clear();
|
||||
return encryptor_ ? Status::OK : CreateEncryptor();
|
||||
Status EncryptingFragmenter::PrepareFragmentForEncryption(
|
||||
bool enable_encryption) {
|
||||
return (!enable_encryption || encryptor_) ? Status::OK : CreateEncryptor();
|
||||
}
|
||||
|
||||
void EncryptingFragmenter::FinalizeFragmentForEncryption() {
|
||||
|
|
|
@ -45,7 +45,7 @@ class EncryptingFragmenter : public Fragmenter {
|
|||
protected:
|
||||
/// Prepare current fragment for encryption.
|
||||
/// @return OK on success, an error status otherwise.
|
||||
virtual Status PrepareFragmentForEncryption();
|
||||
virtual Status PrepareFragmentForEncryption(bool enable_encryption);
|
||||
/// Finalize current fragment for encryption.
|
||||
virtual void FinalizeFragmentForEncryption();
|
||||
|
||||
|
|
|
@ -37,9 +37,9 @@ KeyRotationFragmenter::KeyRotationFragmenter(
|
|||
|
||||
KeyRotationFragmenter::~KeyRotationFragmenter() {}
|
||||
|
||||
Status KeyRotationFragmenter::PrepareFragmentForEncryption() {
|
||||
traf()->auxiliary_size.sample_info_sizes.clear();
|
||||
traf()->auxiliary_offset.offsets.clear();
|
||||
Status KeyRotationFragmenter::PrepareFragmentForEncryption(
|
||||
bool enable_encryption) {
|
||||
bool need_to_refresh_encryptor = !encryptor();
|
||||
|
||||
size_t current_crypto_period_index =
|
||||
traf()->decode_time.decode_time / crypto_period_duration_;
|
||||
|
@ -50,17 +50,34 @@ Status KeyRotationFragmenter::PrepareFragmentForEncryption() {
|
|||
if (!status.ok())
|
||||
return status;
|
||||
set_encryption_key(encryption_key.Pass());
|
||||
|
||||
status = CreateEncryptor();
|
||||
if (!status.ok())
|
||||
return status;
|
||||
prev_crypto_period_index_ = current_crypto_period_index;
|
||||
need_to_refresh_encryptor = true;
|
||||
}
|
||||
|
||||
EncryptionKey* encryption_key = EncryptingFragmenter::encryption_key();
|
||||
DCHECK(encryption_key);
|
||||
AesCtrEncryptor* encryptor = EncryptingFragmenter::encryptor();
|
||||
DCHECK(encryptor);
|
||||
// One and only one 'pssh' box is needed.
|
||||
if (moof_->pssh.empty())
|
||||
moof_->pssh.resize(1);
|
||||
DCHECK(encryption_key());
|
||||
moof_->pssh[0].raw_box = encryption_key()->pssh;
|
||||
|
||||
// Skip the following steps if the current fragment is not going to be
|
||||
// encrypted. 'pssh' box needs to be included in the fragment, which is
|
||||
// performed above, regardless of whether the fragment is encrypted. This is
|
||||
// necessary for two reasons: 1) Requesting keys before reaching encrypted
|
||||
// content avoids playback delay due to license requests; 2) In Chrome, CDM
|
||||
// must be initialized before starting the playback and CDM can only be
|
||||
// initialized with a valid 'pssh'.
|
||||
if (!enable_encryption) {
|
||||
DCHECK(!encryptor());
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
if (need_to_refresh_encryptor) {
|
||||
Status status = CreateEncryptor();
|
||||
if (!status.ok())
|
||||
return status;
|
||||
}
|
||||
DCHECK(encryptor());
|
||||
|
||||
// Key rotation happens in fragment boundary only in this implementation,
|
||||
// i.e. there is at most one key for the fragment. So there should be only
|
||||
|
@ -69,8 +86,9 @@ Status KeyRotationFragmenter::PrepareFragmentForEncryption() {
|
|||
traf()->sample_group_description.grouping_type = FOURCC_SEIG;
|
||||
traf()->sample_group_description.entries.resize(1);
|
||||
traf()->sample_group_description.entries[0].is_encrypted = true;
|
||||
traf()->sample_group_description.entries[0].iv_size = encryptor->iv().size();
|
||||
traf()->sample_group_description.entries[0].key_id = encryption_key->key_id;
|
||||
traf()->sample_group_description.entries[0].iv_size =
|
||||
encryptor()->iv().size();
|
||||
traf()->sample_group_description.entries[0].key_id = encryption_key()->key_id;
|
||||
|
||||
// Fill in SampleToGroup box information.
|
||||
traf()->sample_to_group.grouping_type = FOURCC_SEIG;
|
||||
|
@ -79,11 +97,6 @@ Status KeyRotationFragmenter::PrepareFragmentForEncryption() {
|
|||
traf()->sample_to_group.entries[0].group_description_index =
|
||||
SampleToGroupEntry::kTrackFragmentGroupDescriptionIndexBase + 1;
|
||||
|
||||
// One and only one 'pssh' box is needed.
|
||||
if (moof_->pssh.empty())
|
||||
moof_->pssh.resize(1);
|
||||
moof_->pssh[0].raw_box = encryption_key->pssh;
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ class KeyRotationFragmenter : public EncryptingFragmenter {
|
|||
protected:
|
||||
/// @name Fragmenter implementation overrides.
|
||||
/// @{
|
||||
virtual Status PrepareFragmentForEncryption() OVERRIDE;
|
||||
virtual Status PrepareFragmentForEncryption(bool enable_encryption) OVERRIDE;
|
||||
virtual void FinalizeFragmentForEncryption() OVERRIDE;
|
||||
/// @}
|
||||
|
||||
|
|
Loading…
Reference in New Issue