Do not partially encrypt a segment

Mimic iso-bmff behavior: either all the samples in a segment are encrypted
or all the samples are clear.

Change-Id: I03bdbbf5a4b690f4d87c4dceb0f8155e6fae941e
This commit is contained in:
Kongqun Yang 2016-08-02 16:43:23 -07:00
parent 23f2913248
commit de9667080f
4 changed files with 60 additions and 40 deletions

View File

@ -19,7 +19,6 @@ const std::string kKeyId = "4c6f72656d20697073756d20646f6c6f";
const std::string kIv = "0123456789012345";
const std::string kKey = "01234567890123456789012345678901";
const std::string kPsshData = "";
const uint8_t kBasicSupportData[] = {
// ID: EBML Header, Payload Size: 31
0x1a, 0x45, 0xdf, 0xa3, 0x9f,
@ -37,8 +36,8 @@ const uint8_t kBasicSupportData[] = {
0x42, 0x87, 0x81, 0x02,
// DocTypeReadVersion: 2
0x42, 0x85, 0x81, 0x02,
// ID: Segment, Payload Size: 411
0x18, 0x53, 0x80, 0x67, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x9b,
// ID: Segment, Payload Size: 432
0x18, 0x53, 0x80, 0x67, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xb0,
// ID: SeekHead, Payload Size: 58
0x11, 0x4d, 0x9b, 0x74, 0xba,
// ID: Seek, Payload Size: 11
@ -63,8 +62,8 @@ const uint8_t kBasicSupportData[] = {
0x4d, 0xbb, 0x8c,
// SeekID: binary(4) (Cues)
0x53, 0xab, 0x84, 0x1c, 0x53, 0xbb, 0x6b,
// SeekPosition: 392
0x53, 0xac, 0x82, 0x01, 0x88,
// SeekPosition: 398
0x53, 0xac, 0x82, 0x01, 0x8e,
// ID: Void, Payload Size: 24
0xec, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@ -131,8 +130,8 @@ const uint8_t kBasicSupportData[] = {
0x54, 0xb0, 0x81, 0x64,
// DisplayHeight: 100
0x54, 0xba, 0x81, 0x64,
// ID: Cluster, Payload Size: 101
0x1f, 0x43, 0xb6, 0x75, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65,
// ID: Cluster, Payload Size: 45
0x1f, 0x43, 0xb6, 0x75, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d,
// Timecode: 0
0xe7, 0x81, 0x00,
// ID: SimpleBlock, Payload Size: 10
@ -141,44 +140,48 @@ const uint8_t kBasicSupportData[] = {
0x00,
// Frame Data:
0xde, 0xad, 0xbe, 0xef, 0x00,
// ID: SimpleBlock, Payload Size: 18
0xa3, 0x92, 0x81, 0x03, 0xe8, 0x80,
// ID: SimpleBlock, Payload Size: 10
0xa3, 0x8a, 0x81, 0x03, 0xe8, 0x80,
// Signal Byte: Clear
0x00,
// Frame Data:
0xde, 0xad, 0xbe, 0xef, 0x00,
// ID: BlockGroup, Payload Size: 16
0xa0, 0x90,
// ID: Block, Payload Size: 10
0xa1, 0x8a, 0x81, 0x07, 0xd0, 0x00,
// Signal Byte: Clear
0x00,
// Frame Data:
0xde, 0xad, 0xbe, 0xef, 0x00,
// BlockDuration: 1000
0x9b, 0x82, 0x03, 0xe8,
// ID: Cluster, Payload Size: 50
0x1f, 0x43, 0xb6, 0x75, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32,
// Timecode: 3000
0xe7, 0x82, 0x0b, 0xb8,
// ID: SimpleBlock: Payload Size: 18
0xa3, 0x92, 0x81, 0x00,0x00, 0x80,
// Signal Byte: Encrypted
0x01,
// IV:
0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x23, 0x45,
// Frame Data:
0xcc, 0x03, 0xef, 0xc4, 0xf4,
// ID: SimpleBlock, Payload Size: 18
0xa3, 0x92, 0x81, 0x07, 0xd0, 0x80,
// Signal Byte: Encrypted
0x01,
// IV:
0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x23, 0x46,
// Frame Data:
0xbf, 0x38, 0x72, 0x20, 0xac,
// ID: SimpleBlock, Payload Size: 18
0xa3, 0x92, 0x81, 0x0b, 0xb8, 0x80,
// Signal Byte: Encrypted
0x01,
// IV:
0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x23, 0x47,
// Frame Data:
0x0d, 0x8e, 0xae, 0xbe, 0xd0,
// ID: BlockGroup, Payload Size: 24
0xa0, 0x98,
// ID: Block, Payload Size: 18
0xa1, 0x92, 0x81, 0x0f, 0xa0, 0x00,
0xa1, 0x92, 0x81, 0x03, 0xe8, 0x00,
// Signal Byte: Encrypted
0x01,
// IV:
0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x23, 0x48,
0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x23, 0x46,
// Frame Data:
0xa5, 0x97, 0xf8, 0x9e, 0x87,
0xbf, 0x38, 0x72, 0x20, 0xac,
// BlockDuration: 1000
0x9b, 0x82, 0x03, 0xe8,
// ID: Cues, Payload Size: 14
0x1c, 0x53, 0xbb, 0x6b, 0x8e,
// ID: Cues, Payload Size: 29
0x1c, 0x53, 0xbb, 0x6b, 0x9d,
// ID: CuePoint, Payload Size: 12
0xbb, 0x8c,
// CueTime: 0
@ -188,7 +191,17 @@ const uint8_t kBasicSupportData[] = {
// CueTrack: 1
0xf7, 0x81, 0x01,
// CueClusterPosition: 279
0xf1, 0x82, 0x01, 0x17
0xf1, 0x82, 0x01, 0x17,
// ID: CuePoint, Payload Size: 13
0xbb, 0x8d,
// CueTime: 3000
0xb3, 0x82, 0x0b, 0xb8,
// ID: CueTrackPositions, Payload Size: 7
0xb7, 0x87,
// CueTrack: 1
0xf7, 0x81, 0x01,
// CueClusterPosition: 336
0xf1, 0x82, 0x01, 0x50,
};
} // namespace
@ -213,9 +226,12 @@ class EncrypedSegmenterTest : public SegmentTestBase {
TEST_F(EncrypedSegmenterTest, BasicSupport) {
MuxerOptions options = CreateMuxerOptions();
options.segment_duration = 3.0;
ASSERT_NO_FATAL_FAILURE(InitializeSegmenter(options));
// Write the samples to the Segmenter.
// There should be 2 segments with the first segment in clear and the second
// segment encrypted.
for (int i = 0; i < 5; i++) {
scoped_refptr<MediaSample> sample =
CreateSample(kKeyFrame, kDuration, kNoSideData);
@ -228,4 +244,3 @@ TEST_F(EncrypedSegmenterTest, BasicSupport) {
} // namespace media
} // namespace shaka

View File

@ -32,6 +32,8 @@ int64_t kSecondsToNs = 1000000000L;
Segmenter::Segmenter(const MuxerOptions& options)
: reference_frame_timestamp_(0),
options_(options),
clear_lead_(0),
enable_encryption_(false),
info_(NULL),
muxer_listener_(NULL),
progress_listener_(NULL),
@ -144,6 +146,15 @@ Status Segmenter::AddSample(scoped_refptr<MediaSample> sample) {
segment_length_sec_ = 0;
cluster_length_sec_ = 0;
wrote_frame = true;
if (encryptor_ && !enable_encryption_) {
if (sample->pts() - first_timestamp_ >=
clear_lead_ * info_->time_scale()) {
enable_encryption_ = true;
if (muxer_listener_)
muxer_listener_->OnEncryptionStart();
}
}
}
} else if (cluster_length_sec_ >= options_.fragment_duration) {
if (sample->is_key_frame() || !options_.fragment_sap_aligned) {
@ -161,20 +172,13 @@ Status Segmenter::AddSample(scoped_refptr<MediaSample> sample) {
// Encrypt the frame.
if (encryptor_) {
const bool encrypt_frame =
static_cast<double>(sample->pts() - first_timestamp_) /
info_->time_scale() >=
clear_lead_;
status = encryptor_->EncryptFrame(sample, encrypt_frame);
status = encryptor_->EncryptFrame(sample, enable_encryption_);
if (!status.ok()) {
LOG(ERROR) << "Error encrypting frame.";
return status;
}
if (encrypt_frame && muxer_listener_)
muxer_listener_->OnEncryptionStart();
}
// Add the sample to the durations even though we have not written the frame
// yet. This is needed to make sure we split Clusters at the correct point.
// These are only used in this method.

View File

@ -135,6 +135,7 @@ class Segmenter {
const MuxerOptions& options_;
std::unique_ptr<Encryptor> encryptor_;
double clear_lead_;
bool enable_encryption_; // Encryption is enabled only after clear_lead_.
std::unique_ptr<mkvmuxer::Cluster> cluster_;
mkvmuxer::Cues cues_;