Add support for skip_encryption stream descriptor (#219)
This option makes it possible to control encryption for specific streams, e.g. for audio and video separately.
This commit is contained in:
parent
3443048e80
commit
bfe302bd5c
|
@ -107,7 +107,9 @@ const char kUsage[] =
|
||||||
" The group ID for the output stream. For HLS this is used as the\n"
|
" The group ID for the output stream. For HLS this is used as the\n"
|
||||||
" GROUP-ID attribute for EXT-X-MEDIA.\n"
|
" GROUP-ID attribute for EXT-X-MEDIA.\n"
|
||||||
" - playlist_name: Required for HLS output.\n"
|
" - playlist_name: Required for HLS output.\n"
|
||||||
" Name of the playlist for the stream. Usually ends with '.m3u8'.\n";
|
" Name of the playlist for the stream. Usually ends with '.m3u8'.\n"
|
||||||
|
" - skip_encryption=0|1: Optional. Defaults to 0 if not specified. If\n"
|
||||||
|
" it is set to 1, no encryption of the stream will be made.\n";
|
||||||
|
|
||||||
const char kMediaInfoSuffix[] = ".media_info";
|
const char kMediaInfoSuffix[] = ".media_info";
|
||||||
|
|
||||||
|
@ -378,7 +380,7 @@ bool CreateRemuxJobs(const StreamDescriptorList& stream_descriptors,
|
||||||
handlers.push_back(chunking_handler);
|
handlers.push_back(chunking_handler);
|
||||||
|
|
||||||
Status status;
|
Status status;
|
||||||
if (encryption_key_source) {
|
if (encryption_key_source && !stream_iter->skip_encryption) {
|
||||||
auto new_encryption_options = encryption_options;
|
auto new_encryption_options = encryption_options;
|
||||||
// Use Sample AES in MPEG2TS.
|
// Use Sample AES in MPEG2TS.
|
||||||
// TODO(kqyang): Consider adding a new flag to enable Sample AES as we
|
// TODO(kqyang): Consider adding a new flag to enable Sample AES as we
|
||||||
|
|
|
@ -31,6 +31,7 @@ enum FieldType {
|
||||||
kHlsGroupIdField,
|
kHlsGroupIdField,
|
||||||
kHlsPlaylistNameField,
|
kHlsPlaylistNameField,
|
||||||
kTrickPlayFactorField,
|
kTrickPlayFactorField,
|
||||||
|
kSkipEncryptionField,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FieldNameToTypeMapping {
|
struct FieldNameToTypeMapping {
|
||||||
|
@ -60,6 +61,7 @@ const FieldNameToTypeMapping kFieldNameTypeMappings[] = {
|
||||||
{"playlist_name", kHlsPlaylistNameField},
|
{"playlist_name", kHlsPlaylistNameField},
|
||||||
{"trick_play_factor", kTrickPlayFactorField},
|
{"trick_play_factor", kTrickPlayFactorField},
|
||||||
{"tpf", kTrickPlayFactorField},
|
{"tpf", kTrickPlayFactorField},
|
||||||
|
{"skip_encryption", kSkipEncryptionField},
|
||||||
};
|
};
|
||||||
|
|
||||||
FieldType GetFieldType(const std::string& field_name) {
|
FieldType GetFieldType(const std::string& field_name) {
|
||||||
|
@ -158,6 +160,21 @@ bool InsertStreamDescriptor(const std::string& descriptor_string,
|
||||||
descriptor.trick_play_factor = factor;
|
descriptor.trick_play_factor = factor;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case kSkipEncryptionField: {
|
||||||
|
unsigned skip_encryption_value;
|
||||||
|
if (!base::StringToUint(iter->second, &skip_encryption_value)) {
|
||||||
|
LOG(ERROR) << "Non-numeric option for skip encryption field "
|
||||||
|
"specified (" << iter->second << ").";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (skip_encryption_value > 1) {
|
||||||
|
LOG(ERROR) << "skip_encryption should be either 0 or 1.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
descriptor.skip_encryption = skip_encryption_value > 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
LOG(ERROR) << "Unknown field in stream descriptor (\"" << iter->first
|
LOG(ERROR) << "Unknown field in stream descriptor (\"" << iter->first
|
||||||
<< "\").";
|
<< "\").";
|
||||||
|
|
|
@ -34,6 +34,7 @@ struct StreamDescriptor {
|
||||||
std::string hls_group_id;
|
std::string hls_group_id;
|
||||||
std::string hls_playlist_name;
|
std::string hls_playlist_name;
|
||||||
uint32_t trick_play_factor = 0;
|
uint32_t trick_play_factor = 0;
|
||||||
|
bool skip_encryption = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
class StreamDescriptorCompareFn {
|
class StreamDescriptorCompareFn {
|
||||||
|
|
|
@ -240,6 +240,15 @@ class PackagerAppTest(unittest.TestCase):
|
||||||
self._VerifyDecryption(self.output[0], 'bear-640x360-a-golden.mp4')
|
self._VerifyDecryption(self.output[0], 'bear-640x360-a-golden.mp4')
|
||||||
self._VerifyDecryption(self.output[1], 'bear-640x360-v-golden.mp4')
|
self._VerifyDecryption(self.output[1], 'bear-640x360-v-golden.mp4')
|
||||||
|
|
||||||
|
def testPackageWithEncryptionOfOnlyVideoStream(self):
|
||||||
|
self.packager.Package(
|
||||||
|
self._GetStreams(['audio,skip_encryption=1', 'video']),
|
||||||
|
self._GetFlags(encryption=True))
|
||||||
|
self._DiffGold(self.output[0], 'bear-640x360-a-golden.mp4')
|
||||||
|
self._DiffGold(self.output[1], 'bear-640x360-v-cenc-golden.mp4')
|
||||||
|
self._DiffGold(self.mpd_output, 'bear-640x360-a-clear-v-cenc-golden.mpd')
|
||||||
|
self._VerifyDecryption(self.output[1], 'bear-640x360-v-golden.mp4')
|
||||||
|
|
||||||
def testPackageWithEncryptionAndTrickPlay(self):
|
def testPackageWithEncryptionAndTrickPlay(self):
|
||||||
self.packager.Package(
|
self.packager.Package(
|
||||||
self._GetStreams(['audio', 'video', 'video,trick_play_factor=1']),
|
self._GetStreams(['audio', 'video', 'video,trick_play_factor=1']),
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>-->
|
||||||
|
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.76317S">
|
||||||
|
<Period id="0">
|
||||||
|
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
||||||
|
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||||
|
<ContentProtection schemeIdUri="urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b">
|
||||||
|
<cenc:pssh>AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAExMjM0NTY3ODkwMTIzNDU2AAAAAA==</cenc:pssh>
|
||||||
|
</ContentProtection>
|
||||||
|
<Representation id="0" bandwidth="885590" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1">
|
||||||
|
<BaseURL>output_video.mp4</BaseURL>
|
||||||
|
<SegmentBase indexRange="1091-1158" timescale="30000">
|
||||||
|
<Initialization range="0-1090"/>
|
||||||
|
</SegmentBase>
|
||||||
|
</Representation>
|
||||||
|
</AdaptationSet>
|
||||||
|
<AdaptationSet id="1" contentType="audio" subsegmentAlignment="true">
|
||||||
|
<Representation id="1" bandwidth="126510" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
|
||||||
|
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
|
||||||
|
<BaseURL>output_audio_skip_encryption_1.mp4</BaseURL>
|
||||||
|
<SegmentBase indexRange="757-824" timescale="44100">
|
||||||
|
<Initialization range="0-756"/>
|
||||||
|
</SegmentBase>
|
||||||
|
</Representation>
|
||||||
|
</AdaptationSet>
|
||||||
|
</Period>
|
||||||
|
</MPD>
|
Loading…
Reference in New Issue