Support Marlin DRM signaling in DASH
Only Marlin Adaptive Streaming Specification – Simple Profile is supported. Two additional updates: - Remove FairPlay ContentProtection element from DASH mpd as FairPlay does not define a signaling in DASH. - Updated end to end test to include all DRMs we support. Closes #381. Change-Id: Id12269b471ea34983b782cbd92f687332292ef59
This commit is contained in:
parent
fc0c5ddf0d
commit
8d11e5ea64
|
@ -26,6 +26,7 @@ Shaka Packager supports:
|
||||||
- [Widevine](http://www.widevine.com/)
|
- [Widevine](http://www.widevine.com/)
|
||||||
- [PlayReady](https://www.microsoft.com/playready/)¹
|
- [PlayReady](https://www.microsoft.com/playready/)¹
|
||||||
- [FairPlay](https://developer.apple.com/streaming/fps/)¹
|
- [FairPlay](https://developer.apple.com/streaming/fps/)¹
|
||||||
|
- [Marlin](https://www.intertrust.com/marlin-drm/)¹
|
||||||
- Encryption standards:
|
- Encryption standards:
|
||||||
- [CENC](https://en.wikipedia.org/wiki/MPEG_Common_Encryption)
|
- [CENC](https://en.wikipedia.org/wiki/MPEG_Common_Encryption)
|
||||||
- [SAMPLE-AES](https://developer.apple.com/library/content/documentation/AudioVideo/Conceptual/HLS_Sample_Encryption/Intro/Intro.html)
|
- [SAMPLE-AES](https://developer.apple.com/library/content/documentation/AudioVideo/Conceptual/HLS_Sample_Encryption/Intro/Intro.html)
|
||||||
|
|
|
@ -17,4 +17,5 @@ General encryption options
|
||||||
--protection_systems
|
--protection_systems
|
||||||
|
|
||||||
Protection systems to be generated. Supported protection systems include
|
Protection systems to be generated. Supported protection systems include
|
||||||
Widevine, PlayReady, FairPlay, and CommonSystem (https://goo.gl/s8RIhr).
|
Widevine, PlayReady, FairPlay, Marlin, and
|
||||||
|
CommonSystem (https://goo.gl/s8RIhr).
|
||||||
|
|
|
@ -266,6 +266,7 @@ bool ParseProtectionSystems(
|
||||||
{"common", EncryptionParams::ProtectionSystem::kCommonSystem},
|
{"common", EncryptionParams::ProtectionSystem::kCommonSystem},
|
||||||
{"commonsystem", EncryptionParams::ProtectionSystem::kCommonSystem},
|
{"commonsystem", EncryptionParams::ProtectionSystem::kCommonSystem},
|
||||||
{"fairplay", EncryptionParams::ProtectionSystem::kFairPlay},
|
{"fairplay", EncryptionParams::ProtectionSystem::kFairPlay},
|
||||||
|
{"marlin", EncryptionParams::ProtectionSystem::kMarlin},
|
||||||
{"playready", EncryptionParams::ProtectionSystem::kPlayReady},
|
{"playready", EncryptionParams::ProtectionSystem::kPlayReady},
|
||||||
{"widevine", EncryptionParams::ProtectionSystem::kWidevine},
|
{"widevine", EncryptionParams::ProtectionSystem::kWidevine},
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,8 +16,6 @@
|
||||||
#include "packager/media/base/raw_key_source.h"
|
#include "packager/media/base/raw_key_source.h"
|
||||||
#include "packager/media/base/request_signer.h"
|
#include "packager/media/base/request_signer.h"
|
||||||
#include "packager/media/base/widevine_key_source.h"
|
#include "packager/media/base/widevine_key_source.h"
|
||||||
#include "packager/media/chunking/chunking_handler.h"
|
|
||||||
#include "packager/media/crypto/encryption_handler.h"
|
|
||||||
#include "packager/mpd/base/mpd_options.h"
|
#include "packager/mpd/base/mpd_options.h"
|
||||||
#include "packager/status.h"
|
#include "packager/status.h"
|
||||||
|
|
||||||
|
@ -55,6 +53,9 @@ int GetProtectionSystemsFlag(
|
||||||
case EncryptionParams::ProtectionSystem::kFairPlay:
|
case EncryptionParams::ProtectionSystem::kFairPlay:
|
||||||
protection_systems_flags |= FAIRPLAY_PROTECTION_SYSTEM_FLAG;
|
protection_systems_flags |= FAIRPLAY_PROTECTION_SYSTEM_FLAG;
|
||||||
break;
|
break;
|
||||||
|
case EncryptionParams::ProtectionSystem::kMarlin:
|
||||||
|
protection_systems_flags |= MARLIN_PROTECTION_SYSTEM_FLAG;
|
||||||
|
break;
|
||||||
case EncryptionParams::ProtectionSystem::kPlayReady:
|
case EncryptionParams::ProtectionSystem::kPlayReady:
|
||||||
protection_systems_flags |= PLAYREADY_PROTECTION_SYSTEM_FLAG;
|
protection_systems_flags |= PLAYREADY_PROTECTION_SYSTEM_FLAG;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -12,4 +12,5 @@ DEFINE_string(
|
||||||
protection_systems,
|
protection_systems,
|
||||||
"",
|
"",
|
||||||
"Protection systems to be generated. Supported protection systems include "
|
"Protection systems to be generated. Supported protection systems include "
|
||||||
"Widevine, PlayReady, FairPlay, and CommonSystem (https://goo.gl/s8RIhr).");
|
"Widevine, PlayReady, FairPlay, Marlin and "
|
||||||
|
"CommonSystem (https://goo.gl/s8RIhr).");
|
||||||
|
|
|
@ -398,7 +398,7 @@ class PackagerAppTest(unittest.TestCase):
|
||||||
def _GetFlags(self,
|
def _GetFlags(self,
|
||||||
strip_parameter_set_nalus=True,
|
strip_parameter_set_nalus=True,
|
||||||
encryption=False,
|
encryption=False,
|
||||||
fairplay=False,
|
protection_systems=None,
|
||||||
protection_scheme=None,
|
protection_scheme=None,
|
||||||
vp9_subsample_encryption=True,
|
vp9_subsample_encryption=True,
|
||||||
decryption=False,
|
decryption=False,
|
||||||
|
@ -443,12 +443,13 @@ class PackagerAppTest(unittest.TestCase):
|
||||||
if not random_iv:
|
if not random_iv:
|
||||||
flags.append('--iv=' + self.encryption_iv)
|
flags.append('--iv=' + self.encryption_iv)
|
||||||
|
|
||||||
if fairplay:
|
if protection_systems:
|
||||||
fairplay_key_uri = ('skd://www.license.com/'
|
flags += ['--protection_systems=' + protection_systems]
|
||||||
'getkey?KeyId=31323334-3536-3738-3930-313233343536')
|
if 'FairPlay' in protection_systems:
|
||||||
flags += [
|
fairplay_key_uri = ('skd://www.license.com/getkey?'
|
||||||
'--protection_systems=FairPlay', '--hls_key_uri=' + fairplay_key_uri
|
'KeyId=31323334-3536-3738-3930-313233343536')
|
||||||
]
|
flags += ['--hls_key_uri=' + fairplay_key_uri]
|
||||||
|
|
||||||
if protection_scheme:
|
if protection_scheme:
|
||||||
flags += ['--protection_scheme', protection_scheme]
|
flags += ['--protection_scheme', protection_scheme]
|
||||||
if not vp9_subsample_encryption:
|
if not vp9_subsample_encryption:
|
||||||
|
@ -862,12 +863,15 @@ class PackagerFunctionalTest(PackagerAppTest):
|
||||||
self._GetFlags(encryption=True, output_dash=True))
|
self._GetFlags(encryption=True, output_dash=True))
|
||||||
self._CheckTestResults('encryption', verify_decryption=True)
|
self._CheckTestResults('encryption', verify_decryption=True)
|
||||||
|
|
||||||
def testEncryptionWithFairplay(self):
|
def testEncryptionWithMultiDrms(self):
|
||||||
self.assertPackageSuccess(
|
self.assertPackageSuccess(
|
||||||
self._GetStreams(['audio', 'video']),
|
self._GetStreams(['audio', 'video']),
|
||||||
self._GetFlags(
|
self._GetFlags(
|
||||||
encryption=True, fairplay=True, output_dash=True, output_hls=True))
|
encryption=True,
|
||||||
self._CheckTestResults('encryption-with-fairplay')
|
protection_systems='Widevine,PlayReady,FairPlay,Marlin',
|
||||||
|
output_dash=True,
|
||||||
|
output_hls=True))
|
||||||
|
self._CheckTestResults('encryption-with-multi-drms')
|
||||||
|
|
||||||
# Test deprecated flag --enable_fixed_key_encryption, which is still
|
# Test deprecated flag --enable_fixed_key_encryption, which is still
|
||||||
# supported currently.
|
# supported currently.
|
||||||
|
@ -1096,7 +1100,8 @@ class PackagerFunctionalTest(PackagerAppTest):
|
||||||
segmented=True,
|
segmented=True,
|
||||||
hls=True,
|
hls=True,
|
||||||
test_files=['bear-640x360.ts']),
|
test_files=['bear-640x360.ts']),
|
||||||
self._GetFlags(encryption=True, output_hls=True, fairplay=True))
|
self._GetFlags(
|
||||||
|
encryption=True, protection_systems='FairPlay', output_hls=True))
|
||||||
self._CheckTestResults('avc-ts-with-encryption-and-fairplay')
|
self._CheckTestResults('avc-ts-with-encryption-and-fairplay')
|
||||||
|
|
||||||
def testAvcAc3TsWithEncryption(self):
|
def testAvcAc3TsWithEncryption(self):
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
<?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" 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.7360665798187256S">
|
|
||||||
<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:29701fe4-3cc7-4a34-8c5b-ae90c7439a47"/>
|
|
||||||
<Representation id="0" bandwidth="977743" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1">
|
|
||||||
<BaseURL>bear-640x360-video.mp4</BaseURL>
|
|
||||||
<SegmentBase indexRange="1075-1142" timescale="30000">
|
|
||||||
<Initialization range="0-1074"/>
|
|
||||||
</SegmentBase>
|
|
||||||
</Representation>
|
|
||||||
</AdaptationSet>
|
|
||||||
<AdaptationSet id="1" contentType="audio" subsegmentAlignment="true">
|
|
||||||
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
|
||||||
<ContentProtection schemeIdUri="urn:uuid:29701fe4-3cc7-4a34-8c5b-ae90c7439a47"/>
|
|
||||||
<Representation id="1" bandwidth="133663" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
|
|
||||||
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
|
|
||||||
<BaseURL>bear-640x360-audio.mp4</BaseURL>
|
|
||||||
<SegmentBase indexRange="951-1018" timescale="44100">
|
|
||||||
<Initialization range="0-950"/>
|
|
||||||
</SegmentBase>
|
|
||||||
</Representation>
|
|
||||||
</AdaptationSet>
|
|
||||||
</Period>
|
|
||||||
</MPD>
|
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,47 @@
|
||||||
|
<?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" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" xmlns:mas="urn:marlin:mas:1-0:services:schemas:mpd" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.7360665798187256S">
|
||||||
|
<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:9a04f079-9840-4286-ab92-e65be0885f95">
|
||||||
|
<cenc:pssh>AAACOnBzc2gBAAAAmgTweZhAQoarkuZb4IhflQAAAAExMjM0NTY3ODkwMTIzNDU2AAACBgYCAAABAAEA/AE8AFcAUgBNAEgARQBBAEQARQBSACAAeABtAGwAbgBzAD0AIgBoAHQAdABwADoALwAvAHMAYwBoAGUAbQBhAHMALgBtAGkAYwByAG8AcwBvAGYAdAAuAGMAbwBtAC8ARABSAE0ALwAyADAAMAA3AC8AMAAzAC8AUABsAGEAeQBSAGUAYQBkAHkASABlAGEAZABlAHIAIgAgAHYAZQByAHMAaQBvAG4APQAiADQALgAwAC4AMAAuADAAIgA+ADwARABBAFQAQQA+ADwAUABSAE8AVABFAEMAVABJAE4ARgBPAD4APABLAEUAWQBMAEUATgA+ADEANgA8AC8ASwBFAFkATABFAE4APgA8AEEATABHAEkARAA+AEEARQBTAEMAVABSADwALwBBAEwARwBJAEQAPgA8AC8AUABSAE8AVABFAEMAVABJAE4ARgBPAD4APABLAEkARAA+AE4ARABNAHkATQBUAFkAMQBPAEQAYwA1AE0ARABFAHkATQB6AFEAMQBOAGcAPQA9ADwALwBLAEkARAA+ADwAQwBIAEUAQwBLAFMAVQBNAD4AbAA1AEwAbwBVAGcASwA5AEsAQwBnAD0APAAvAEMASABFAEMASwBTAFUATQA+ADwALwBEAEEAVABBAD4APAAvAFcAUgBNAEgARQBBAEQARQBSAD4A</cenc:pssh>
|
||||||
|
</ContentProtection>
|
||||||
|
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
||||||
|
<cenc:pssh>AAAAOHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABgSEDEyMzQ1Njc4OTAxMjM0NTZI49yVmwY=</cenc:pssh>
|
||||||
|
</ContentProtection>
|
||||||
|
<ContentProtection schemeIdUri="urn:uuid:5e629af5-38da-4063-8977-97ffbd9902d4">
|
||||||
|
<mas:MarlinContentIds>
|
||||||
|
<mas:MarlinContentId>urn:marlin:kid:31323334353637383930313233343536</mas:MarlinContentId>
|
||||||
|
</mas:MarlinContentIds>
|
||||||
|
</ContentProtection>
|
||||||
|
<Representation id="0" bandwidth="977743" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1">
|
||||||
|
<BaseURL>bear-640x360-video.mp4</BaseURL>
|
||||||
|
<SegmentBase indexRange="1701-1768" timescale="30000">
|
||||||
|
<Initialization range="0-1700"/>
|
||||||
|
</SegmentBase>
|
||||||
|
</Representation>
|
||||||
|
</AdaptationSet>
|
||||||
|
<AdaptationSet id="1" contentType="audio" subsegmentAlignment="true">
|
||||||
|
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||||
|
<ContentProtection schemeIdUri="urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95">
|
||||||
|
<cenc:pssh>AAACOnBzc2gBAAAAmgTweZhAQoarkuZb4IhflQAAAAExMjM0NTY3ODkwMTIzNDU2AAACBgYCAAABAAEA/AE8AFcAUgBNAEgARQBBAEQARQBSACAAeABtAGwAbgBzAD0AIgBoAHQAdABwADoALwAvAHMAYwBoAGUAbQBhAHMALgBtAGkAYwByAG8AcwBvAGYAdAAuAGMAbwBtAC8ARABSAE0ALwAyADAAMAA3AC8AMAAzAC8AUABsAGEAeQBSAGUAYQBkAHkASABlAGEAZABlAHIAIgAgAHYAZQByAHMAaQBvAG4APQAiADQALgAwAC4AMAAuADAAIgA+ADwARABBAFQAQQA+ADwAUABSAE8AVABFAEMAVABJAE4ARgBPAD4APABLAEUAWQBMAEUATgA+ADEANgA8AC8ASwBFAFkATABFAE4APgA8AEEATABHAEkARAA+AEEARQBTAEMAVABSADwALwBBAEwARwBJAEQAPgA8AC8AUABSAE8AVABFAEMAVABJAE4ARgBPAD4APABLAEkARAA+AE4ARABNAHkATQBUAFkAMQBPAEQAYwA1AE0ARABFAHkATQB6AFEAMQBOAGcAPQA9ADwALwBLAEkARAA+ADwAQwBIAEUAQwBLAFMAVQBNAD4AbAA1AEwAbwBVAGcASwA5AEsAQwBnAD0APAAvAEMASABFAEMASwBTAFUATQA+ADwALwBEAEEAVABBAD4APAAvAFcAUgBNAEgARQBBAEQARQBSAD4A</cenc:pssh>
|
||||||
|
</ContentProtection>
|
||||||
|
<ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed">
|
||||||
|
<cenc:pssh>AAAAOHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABgSEDEyMzQ1Njc4OTAxMjM0NTZI49yVmwY=</cenc:pssh>
|
||||||
|
</ContentProtection>
|
||||||
|
<ContentProtection schemeIdUri="urn:uuid:5e629af5-38da-4063-8977-97ffbd9902d4">
|
||||||
|
<mas:MarlinContentIds>
|
||||||
|
<mas:MarlinContentId>urn:marlin:kid:31323334353637383930313233343536</mas:MarlinContentId>
|
||||||
|
</mas:MarlinContentIds>
|
||||||
|
</ContentProtection>
|
||||||
|
<Representation id="1" bandwidth="133663" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
|
||||||
|
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
|
||||||
|
<BaseURL>bear-640x360-audio.mp4</BaseURL>
|
||||||
|
<SegmentBase indexRange="1577-1644" timescale="44100">
|
||||||
|
<Initialization range="0-1576"/>
|
||||||
|
</SegmentBase>
|
||||||
|
</Representation>
|
||||||
|
</AdaptationSet>
|
||||||
|
</Period>
|
||||||
|
</MPD>
|
|
@ -3,10 +3,11 @@
|
||||||
## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>
|
## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>
|
||||||
#EXT-X-TARGETDURATION:2
|
#EXT-X-TARGETDURATION:2
|
||||||
#EXT-X-PLAYLIST-TYPE:VOD
|
#EXT-X-PLAYLIST-TYPE:VOD
|
||||||
#EXT-X-MAP:URI="bear-640x360-audio.mp4",BYTERANGE="951@0"
|
#EXT-X-MAP:URI="bear-640x360-audio.mp4",BYTERANGE="1577@0"
|
||||||
|
#EXT-X-KEY:METHOD=SAMPLE-AES-CTR,URI="data:text/plain;base64,AAAAOHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABgSEDEyMzQ1Njc4OTAxMjM0NTZI49yVmwY=",KEYID=0x31323334353637383930313233343536,KEYFORMATVERSIONS="1",KEYFORMAT="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed"
|
||||||
#EXT-X-KEY:METHOD=SAMPLE-AES-CTR,URI="skd://www.license.com/getkey?KeyId=31323334-3536-3738-3930-313233343536",KEYFORMATVERSIONS="1",KEYFORMAT="com.apple.streamingkeydelivery"
|
#EXT-X-KEY:METHOD=SAMPLE-AES-CTR,URI="skd://www.license.com/getkey?KeyId=31323334-3536-3738-3930-313233343536",KEYFORMATVERSIONS="1",KEYFORMAT="com.apple.streamingkeydelivery"
|
||||||
#EXTINF:1.022,
|
#EXTINF:1.022,
|
||||||
#EXT-X-BYTERANGE:17028@1019
|
#EXT-X-BYTERANGE:17028@1645
|
||||||
bear-640x360-audio.mp4
|
bear-640x360-audio.mp4
|
||||||
#EXTINF:0.998,
|
#EXTINF:0.998,
|
||||||
#EXT-X-BYTERANGE:16682
|
#EXT-X-BYTERANGE:16682
|
|
@ -3,10 +3,11 @@
|
||||||
## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>
|
## Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>
|
||||||
#EXT-X-TARGETDURATION:2
|
#EXT-X-TARGETDURATION:2
|
||||||
#EXT-X-PLAYLIST-TYPE:VOD
|
#EXT-X-PLAYLIST-TYPE:VOD
|
||||||
#EXT-X-MAP:URI="bear-640x360-video.mp4",BYTERANGE="1075@0"
|
#EXT-X-MAP:URI="bear-640x360-video.mp4",BYTERANGE="1701@0"
|
||||||
|
#EXT-X-KEY:METHOD=SAMPLE-AES-CTR,URI="data:text/plain;base64,AAAAOHBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAABgSEDEyMzQ1Njc4OTAxMjM0NTZI49yVmwY=",KEYID=0x31323334353637383930313233343536,KEYFORMATVERSIONS="1",KEYFORMAT="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed"
|
||||||
#EXT-X-KEY:METHOD=SAMPLE-AES-CTR,URI="skd://www.license.com/getkey?KeyId=31323334-3536-3738-3930-313233343536",KEYFORMATVERSIONS="1",KEYFORMAT="com.apple.streamingkeydelivery"
|
#EXT-X-KEY:METHOD=SAMPLE-AES-CTR,URI="skd://www.license.com/getkey?KeyId=31323334-3536-3738-3930-313233343536",KEYFORMATVERSIONS="1",KEYFORMAT="com.apple.streamingkeydelivery"
|
||||||
#EXTINF:1.001,
|
#EXTINF:1.001,
|
||||||
#EXT-X-BYTERANGE:99313@1143
|
#EXT-X-BYTERANGE:99313@1769
|
||||||
bear-640x360-video.mp4
|
bear-640x360-video.mp4
|
||||||
#EXTINF:1.001,
|
#EXTINF:1.001,
|
||||||
#EXT-X-BYTERANGE:122340
|
#EXT-X-BYTERANGE:122340
|
|
@ -33,6 +33,13 @@ KeySource::KeySource(int protection_systems_flags, FourCC protection_scheme) {
|
||||||
no_pssh_systems_.emplace_back(std::begin(kFairPlaySystemId),
|
no_pssh_systems_.emplace_back(std::begin(kFairPlaySystemId),
|
||||||
std::end(kFairPlaySystemId));
|
std::end(kFairPlaySystemId));
|
||||||
}
|
}
|
||||||
|
// We only support Marlin Adaptive Streaming Specification – Simple Profile
|
||||||
|
// with Implicit Content ID Mapping, which does not need a PSSH. Marlin
|
||||||
|
// specific PSSH with Explicit Content ID Mapping is not generated.
|
||||||
|
if (protection_systems_flags & MARLIN_PROTECTION_SYSTEM_FLAG) {
|
||||||
|
no_pssh_systems_.emplace_back(std::begin(kMarlinSystemId),
|
||||||
|
std::end(kMarlinSystemId));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KeySource::~KeySource() = default;
|
KeySource::~KeySource() = default;
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
namespace shaka {
|
namespace shaka {
|
||||||
namespace media {
|
namespace media {
|
||||||
|
|
||||||
|
// System Ids are defined in https://dashif.org/identifiers/content_protection/.
|
||||||
|
|
||||||
// Common SystemID defined by EME, which requires Key System implementations
|
// Common SystemID defined by EME, which requires Key System implementations
|
||||||
// supporting ISO Common Encryption to support this SystemID and format.
|
// supporting ISO Common Encryption to support this SystemID and format.
|
||||||
// https://goo.gl/kUv2Xd
|
// https://goo.gl/kUv2Xd
|
||||||
|
@ -23,6 +25,11 @@ const uint8_t kFairPlaySystemId[] = {0x29, 0x70, 0x1F, 0xE4, 0x3C, 0xC7,
|
||||||
0x4A, 0x34, 0x8C, 0x5B, 0xAE, 0x90,
|
0x4A, 0x34, 0x8C, 0x5B, 0xAE, 0x90,
|
||||||
0xC7, 0x43, 0x9A, 0x47};
|
0xC7, 0x43, 0x9A, 0x47};
|
||||||
|
|
||||||
|
// Marlin Adaptive Streaming Specification – Simple Profile, V1.0.
|
||||||
|
const uint8_t kMarlinSystemId[] = {0x5E, 0x62, 0x9A, 0xF5, 0x38, 0xDA,
|
||||||
|
0x40, 0x63, 0x89, 0x77, 0x97, 0xFF,
|
||||||
|
0xBD, 0x99, 0x02, 0xD4};
|
||||||
|
|
||||||
const uint8_t kPlayReadySystemId[] = {0x9a, 0x04, 0xf0, 0x79, 0x98, 0x40,
|
const uint8_t kPlayReadySystemId[] = {0x9a, 0x04, 0xf0, 0x79, 0x98, 0x40,
|
||||||
0x42, 0x86, 0xab, 0x92, 0xe6, 0x5b,
|
0x42, 0x86, 0xab, 0x92, 0xe6, 0x5b,
|
||||||
0xe0, 0x88, 0x5f, 0x95};
|
0xe0, 0x88, 0x5f, 0x95};
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#define PLAYREADY_PROTECTION_SYSTEM_FLAG 0x02
|
#define PLAYREADY_PROTECTION_SYSTEM_FLAG 0x02
|
||||||
#define WIDEVINE_PROTECTION_SYSTEM_FLAG 0x04
|
#define WIDEVINE_PROTECTION_SYSTEM_FLAG 0x04
|
||||||
#define FAIRPLAY_PROTECTION_SYSTEM_FLAG 0x08
|
#define FAIRPLAY_PROTECTION_SYSTEM_FLAG 0x08
|
||||||
|
#define MARLIN_PROTECTION_SYSTEM_FLAG 0x10
|
||||||
|
|
||||||
namespace shaka {
|
namespace shaka {
|
||||||
namespace media {
|
namespace media {
|
||||||
|
|
|
@ -119,6 +119,7 @@ struct EncryptionParams {
|
||||||
enum class ProtectionSystem {
|
enum class ProtectionSystem {
|
||||||
kCommonSystem,
|
kCommonSystem,
|
||||||
kFairPlay,
|
kFairPlay,
|
||||||
|
kMarlin,
|
||||||
kPlayReady,
|
kPlayReady,
|
||||||
kWidevine,
|
kWidevine,
|
||||||
};
|
};
|
||||||
|
|
|
@ -46,10 +46,13 @@ void AddMpdNameSpaceInfo(XmlNode* mpd) {
|
||||||
mpd->SetStringAttribute("xsi:schemaLocation", kDashSchemaMpd2011);
|
mpd->SetStringAttribute("xsi:schemaLocation", kDashSchemaMpd2011);
|
||||||
|
|
||||||
static const char kCencNamespace[] = "urn:mpeg:cenc:2013";
|
static const char kCencNamespace[] = "urn:mpeg:cenc:2013";
|
||||||
|
static const char kMarlinNamespace[] =
|
||||||
|
"urn:marlin:mas:1-0:services:schemas:mpd";
|
||||||
static const char kXmlNamespaceXlink[] = "http://www.w3.org/1999/xlink";
|
static const char kXmlNamespaceXlink[] = "http://www.w3.org/1999/xlink";
|
||||||
|
|
||||||
const std::map<std::string, std::string> uris = {
|
const std::map<std::string, std::string> uris = {
|
||||||
{"cenc", kCencNamespace},
|
{"cenc", kCencNamespace},
|
||||||
|
{"mas", kMarlinNamespace},
|
||||||
{"xlink", kXmlNamespaceXlink},
|
{"xlink", kXmlNamespaceXlink},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -302,6 +302,42 @@ void UpdateContentProtectionPsshHelper(
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
// UUID for Marlin Adaptive Streaming Specification – Simple Profile from
|
||||||
|
// https://dashif.org/identifiers/content_protection/.
|
||||||
|
const char kMarlinUUID[] = "5e629af5-38da-4063-8977-97ffbd9902d4";
|
||||||
|
// Unofficial FairPlay system id extracted from
|
||||||
|
// https://forums.developer.apple.com/thread/6185.
|
||||||
|
const char kFairPlayUUID[] = "29701fe4-3cc7-4a34-8c5b-ae90c7439a47";
|
||||||
|
|
||||||
|
Element GenerateMarlinContentIds(const std::string& key_id) {
|
||||||
|
// See https://github.com/google/shaka-packager/issues/381 for details.
|
||||||
|
static const char kMarlinContentIdName[] = "mas:MarlinContentId";
|
||||||
|
static const char kMarlinContentIdPrefix[] = "urn:marlin:kid:";
|
||||||
|
static const char kMarlinContentIdsName[] = "mas:MarlinContentIds";
|
||||||
|
|
||||||
|
Element marlin_content_id;
|
||||||
|
marlin_content_id.name = kMarlinContentIdName;
|
||||||
|
marlin_content_id.content =
|
||||||
|
kMarlinContentIdPrefix + base::HexEncode(key_id.data(), key_id.size());
|
||||||
|
|
||||||
|
Element marlin_content_ids;
|
||||||
|
marlin_content_ids.name = kMarlinContentIdsName;
|
||||||
|
marlin_content_ids.subelements.push_back(marlin_content_id);
|
||||||
|
|
||||||
|
return marlin_content_ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
Element GenerateCencPsshElement(const std::string& pssh) {
|
||||||
|
std::string base64_encoded_pssh;
|
||||||
|
base::Base64Encode(base::StringPiece(pssh.data(), pssh.size()),
|
||||||
|
&base64_encoded_pssh);
|
||||||
|
Element cenc_pssh;
|
||||||
|
cenc_pssh.name = kPsshElementName;
|
||||||
|
cenc_pssh.content = base64_encoded_pssh;
|
||||||
|
return cenc_pssh;
|
||||||
|
}
|
||||||
|
|
||||||
// Helper function. This works because Representation and AdaptationSet both
|
// Helper function. This works because Representation and AdaptationSet both
|
||||||
// have AddContentProtectionElement().
|
// have AddContentProtectionElement().
|
||||||
template <typename ContentProtectionParent>
|
template <typename ContentProtectionParent>
|
||||||
|
@ -349,18 +385,20 @@ void AddContentProtectionElementsHelperTemplated(
|
||||||
|
|
||||||
ContentProtectionElement drm_content_protection;
|
ContentProtectionElement drm_content_protection;
|
||||||
drm_content_protection.scheme_id_uri = "urn:uuid:" + entry.uuid();
|
drm_content_protection.scheme_id_uri = "urn:uuid:" + entry.uuid();
|
||||||
|
|
||||||
if (entry.has_name_version())
|
if (entry.has_name_version())
|
||||||
drm_content_protection.value = entry.name_version();
|
drm_content_protection.value = entry.name_version();
|
||||||
|
|
||||||
if (!entry.pssh().empty()) {
|
if (entry.uuid() == kFairPlayUUID) {
|
||||||
std::string base64_encoded_pssh;
|
VLOG(1) << "Skipping FairPlay ContentProtection element as FairPlay does "
|
||||||
base::Base64Encode(
|
"not support DASH signaling.";
|
||||||
base::StringPiece(entry.pssh().data(), entry.pssh().size()),
|
continue;
|
||||||
&base64_encoded_pssh);
|
} else if (entry.uuid() == kMarlinUUID) {
|
||||||
Element cenc_pssh;
|
drm_content_protection.subelements.push_back(
|
||||||
cenc_pssh.name = kPsshElementName;
|
GenerateMarlinContentIds(protected_content.default_key_id()));
|
||||||
cenc_pssh.content = base64_encoded_pssh;
|
} else if (!entry.pssh().empty()) {
|
||||||
drm_content_protection.subelements.push_back(cenc_pssh);
|
drm_content_protection.subelements.push_back(
|
||||||
|
GenerateCencPsshElement(entry.pssh()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!key_id_uuid_format.empty() && !is_mp4_container) {
|
if (!key_id_uuid_format.empty() && !is_mp4_container) {
|
||||||
|
|
|
@ -141,12 +141,15 @@ bool XmlNode::AddElements(const std::vector<Element>& elements) {
|
||||||
child_node.SetStringAttribute(attribute_it->first.c_str(),
|
child_node.SetStringAttribute(attribute_it->first.c_str(),
|
||||||
attribute_it->second);
|
attribute_it->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note that somehow |SetContent| needs to be called before |AddElements|
|
||||||
|
// otherwise the added children will be overwritten by the content.
|
||||||
|
child_node.SetContent(child_element.content);
|
||||||
|
|
||||||
// Recursively set children for the child.
|
// Recursively set children for the child.
|
||||||
if (!child_node.AddElements(child_element.subelements))
|
if (!child_node.AddElements(child_element.subelements))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
child_node.SetContent(child_element.content);
|
|
||||||
|
|
||||||
if (!xmlAddChild(node_.get(), child_node.GetRawPtr())) {
|
if (!xmlAddChild(node_.get(), child_node.GetRawPtr())) {
|
||||||
LOG(ERROR) << "Failed to set child " << child_element.name
|
LOG(ERROR) << "Failed to set child " << child_element.name
|
||||||
<< " to parent element "
|
<< " to parent element "
|
||||||
|
|
Loading…
Reference in New Issue