@@ -2,6 +2,7 @@ package mpd
22
33import (
44 "errors"
5+ "strings"
56
67 . "github.com/zencoder/go-dash/helpers/ptrs"
78)
2324 ErrBaseURLEmpty = errors .New ("Base URL empty" )
2425 ErrSegmentBaseOnDemandProfileOnly = errors .New ("Segment Base can only be used with On-Demand Profile" )
2526 ErrSegmentBaseNil = errors .New ("Segment Base nil" )
27+ ErrInvalidDefaultKID = errors .New ("Invalid Default KID string, should be 32 characters" )
28+ ErrPROEmpty = errors .New ("PlayReady PRO empty" )
29+ ErrContentProtectionNil = errors .New ("Content Protection nil" )
2630)
2731
2832type MPD struct {
@@ -39,14 +43,40 @@ type Period struct {
3943}
4044
4145type AdaptationSet struct {
42- MPD * MPD `xml:"-"`
43- MimeType * string `xml:"mimeType,attr"`
44- ScanType * string `xml:"scanType,attr"`
45- SegmentAlignment * bool `xml:"segmentAlignment,attr"`
46- StartWithSAP * int64 `xml:"startWithSAP,attr"`
47- Lang * string `xml:"lang,attr"`
48- SegmentTemplate * SegmentTemplate `xml:"SegmentTemplate,omitempty"` // Live Profile Only
49- Representations []* Representation `xml:"Representation,omitempty"`
46+ MPD * MPD `xml:"-"`
47+ MimeType * string `xml:"mimeType,attr"`
48+ ScanType * string `xml:"scanType,attr"`
49+ SegmentAlignment * bool `xml:"segmentAlignment,attr"`
50+ StartWithSAP * int64 `xml:"startWithSAP,attr"`
51+ Lang * string `xml:"lang,attr"`
52+ ContentProtection []* ContentProtection `xml:"ContentProtection,omitempty"`
53+ SegmentTemplate * SegmentTemplate `xml:"SegmentTemplate,omitempty"` // Live Profile Only
54+ Representations []* Representation `xml:"Representation,omitempty"`
55+ }
56+
57+ /*
58+ <ContentProtection cenc:default_KID="09e36702-8f33-436c-a5dd60ffe6671e70" schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc" xmlns:cenc="urn:mpeg:cenc:2013"/>
59+ <ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed"/>
60+ <ContentProtection schemeIdUri="urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95">
61+ <mspr:pro>mgIAAAEAAQCQAjwAVwBSAE0ASABFAEEARABFAFIAIAB4AG0AbABuAHMAPQAiAGgAdAB0AHAAOgAvAC8AcwBjAGgAZQBtAGEAcwAuAG0AaQBjAHIAbwBzAG8AZgB0AC4AYwBvAG0ALwBEAFIATQAvADIAMAAwADcALwAwADMALwBQAGwAYQB5AFIAZQBhAGQAeQBIAGUAYQBkAGUAcgAiACAAdgBlAHIAcwBpAG8AbgA9ACIANAAuADAALgAwAC4AMAAiAD4APABEAEEAVABBAD4APABQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsARQBZAEwARQBOAD4AMQA2ADwALwBLAEUAWQBMAEUATgA+ADwAQQBMAEcASQBEAD4AQQBFAFMAQwBUAFIAPAAvAEEATABHAEkARAA+ADwALwBQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsASQBEAD4AQQBtAGYAagBDAFQATwBQAGIARQBPAGwAMwBXAEQALwA1AG0AYwBlAGMAQQA9AD0APAAvAEsASQBEAD4APABDAEgARQBDAEsAUwBVAE0APgBCAEcAdwAxAGEAWQBaADEAWQBYAE0APQA8AC8AQwBIAEUAQwBLAFMAVQBNAD4APABMAEEAXwBVAFIATAA+AGgAdAB0AHAAOgAvAC8AcABsAGEAeQByAGUAYQBkAHkALgBkAGkAcgBlAGMAdAB0AGEAcABzAC4AbgBlAHQALwBwAHIALwBzAHYAYwAvAHIAaQBnAGgAdABzAG0AYQBuAGEAZwBlAHIALgBhAHMAbQB4ADwALwBMAEEAXwBVAFIATAA+ADwALwBEAEEAVABBAD4APAAvAFcAUgBNAEgARQBBAEQARQBSAD4A</mspr:pro>
62+ </ContentProtection>
63+ */
64+
65+ const (
66+ CONTENT_PROTECTION_ROOT_SCHEME_ID_URI = "urn:mpeg:dash:mp4protection:2011"
67+ CONTENT_PROTECTION_ROOT_VALUE = "cenc"
68+ CONTENT_PROTECTION_ROOT_XMLNS = "urn:mpeg:cenc:2013"
69+ CONTENT_PROTECTION_WIDEVINE_SCHEME_ID = "urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed"
70+ CONTENT_PROTECTION_PLAYREADY_SCHEME_ID = "urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95"
71+ )
72+
73+ type ContentProtection struct {
74+ AdaptationSet * AdaptationSet `xml:"-"`
75+ DefaultKID * string `xml:"cenc:default_KID,attr"`
76+ SchemeIDURI * string `xml:"schemeIdUri,attr"` // Default: urn:mpeg:dash:mp4protection:2011
77+ Value * string `xml:"value,attr"` // Default: cenc
78+ XMLNS * string `xml:"xmlns:cenc,attr"` // Default: urn:mpeg:cenc:2013
79+ PlayreadyPRO * string `xml:"mspr:pro,omitempty"`
5080}
5181
5282// Live Profile Only
@@ -131,6 +161,93 @@ func (m *MPD) AddAdaptationSet(as *AdaptationSet) error {
131161 return nil
132162}
133163
164+ /*
165+ <ContentProtection cenc:default_KID="09e36702-8f33-436c-a5dd60ffe6671e70" schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc" xmlns:cenc="urn:mpeg:cenc:2013"/>
166+ <ContentProtection schemeIdUri="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed"/>
167+ <ContentProtection schemeIdUri="urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95">
168+ <mspr:pro>mgIAAAEAAQCQAjwAVwBSAE0ASABFAEEARABFAFIAIAB4AG0AbABuAHMAPQAiAGgAdAB0AHAAOgAvAC8AcwBjAGgAZQBtAGEAcwAuAG0AaQBjAHIAbwBzAG8AZgB0AC4AYwBvAG0ALwBEAFIATQAvADIAMAAwADcALwAwADMALwBQAGwAYQB5AFIAZQBhAGQAeQBIAGUAYQBkAGUAcgAiACAAdgBlAHIAcwBpAG8AbgA9ACIANAAuADAALgAwAC4AMAAiAD4APABEAEEAVABBAD4APABQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsARQBZAEwARQBOAD4AMQA2ADwALwBLAEUAWQBMAEUATgA+ADwAQQBMAEcASQBEAD4AQQBFAFMAQwBUAFIAPAAvAEEATABHAEkARAA+ADwALwBQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsASQBEAD4AQQBtAGYAagBDAFQATwBQAGIARQBPAGwAMwBXAEQALwA1AG0AYwBlAGMAQQA9AD0APAAvAEsASQBEAD4APABDAEgARQBDAEsAUwBVAE0APgBCAEcAdwAxAGEAWQBaADEAWQBYAE0APQA8AC8AQwBIAEUAQwBLAFMAVQBNAD4APABMAEEAXwBVAFIATAA+AGgAdAB0AHAAOgAvAC8AcABsAGEAeQByAGUAYQBkAHkALgBkAGkAcgBlAGMAdAB0AGEAcABzAC4AbgBlAHQALwBwAHIALwBzAHYAYwAvAHIAaQBnAGgAdABzAG0AYQBuAGEAZwBlAHIALgBhAHMAbQB4ADwALwBMAEEAXwBVAFIATAA+ADwALwBEAEEAVABBAD4APAAvAFcAUgBNAEgARQBBAEQARQBSAD4A</mspr:pro>
169+ </ContentProtection>
170+
171+
172+ type ContentProtection struct {
173+ AdaptationSet *AdaptationSet `xml:"-"`
174+ DefaultKID *string `xml:"cenc:default_KID,attr"`
175+ SchemeIDURI *string `xml:"schemeIdUri,attr"` // Default: urn:mpeg:dash:mp4protection:2011
176+ Value *string `xml:"value,attr"` // Default: cenc
177+ XMLNS *string `xml:"xmlns:cenc,attr"` // Default: urn:mpeg:cenc:2013
178+ PlayReadyPRO *string `xml:"mspr:pro,omitempty"`
179+ }
180+
181+ const (
182+ CONTENT_PROTECTION_ROOT_SCHEME_ID_URI = "urn:mpeg:dash:mp4protection:2011"
183+ CONTENT_PROTECTION_ROOT_VALUE = "cenc"
184+ CONTENT_PROTECTION_ROOT_XMLNS = "urn:mpeg:cenc:2013"
185+ )
186+ */
187+
188+ func (as * AdaptationSet ) AddNewContentProtectionRoot (defaultKIDHex string ) (* ContentProtection , error ) {
189+ if len (defaultKIDHex ) != 32 || defaultKIDHex == "" {
190+ return nil , ErrInvalidDefaultKID
191+ }
192+
193+ // Convert the KID into the correct format
194+ defaultKID := strings .ToLower (defaultKIDHex [0 :8 ] + "-" + defaultKIDHex [8 :12 ] + "-" + defaultKIDHex [12 :16 ] + "-" + defaultKIDHex [16 :32 ])
195+
196+ cp := & ContentProtection {
197+ DefaultKID : Strptr (defaultKID ),
198+ SchemeIDURI : Strptr (CONTENT_PROTECTION_ROOT_SCHEME_ID_URI ),
199+ Value : Strptr (CONTENT_PROTECTION_ROOT_VALUE ),
200+ XMLNS : Strptr (CONTENT_PROTECTION_ROOT_XMLNS ),
201+ }
202+
203+ err := as .AddContentProtection (cp )
204+ if err != nil {
205+ return nil , err
206+ }
207+
208+ return cp , nil
209+ }
210+
211+ func (as * AdaptationSet ) AddNewContentProtectionSchemeWidevine () (* ContentProtection , error ) {
212+ cp := & ContentProtection {
213+ SchemeIDURI : Strptr (CONTENT_PROTECTION_WIDEVINE_SCHEME_ID ),
214+ }
215+
216+ err := as .AddContentProtection (cp )
217+ if err != nil {
218+ return nil , err
219+ }
220+
221+ return cp , nil
222+ }
223+
224+ func (as * AdaptationSet ) AddNewContentProtectionSchemePlayready (pro string ) (* ContentProtection , error ) {
225+ if pro == "" {
226+ return nil , ErrPROEmpty
227+ }
228+
229+ cp := & ContentProtection {
230+ SchemeIDURI : Strptr (CONTENT_PROTECTION_PLAYREADY_SCHEME_ID ),
231+ PlayreadyPRO : Strptr (pro ),
232+ }
233+
234+ err := as .AddContentProtection (cp )
235+ if err != nil {
236+ return nil , err
237+ }
238+
239+ return cp , nil
240+ }
241+
242+ func (as * AdaptationSet ) AddContentProtection (cp * ContentProtection ) error {
243+ if cp == nil {
244+ return ErrContentProtectionNil
245+ }
246+
247+ as .ContentProtection = append (as .ContentProtection , cp )
248+ return nil
249+ }
250+
134251func (as * AdaptationSet ) SetNewSegmentTemplate (duration int64 , init string , media string , startNumber int64 , timescale int64 ) (* SegmentTemplate , error ) {
135252 st := & SegmentTemplate {
136253 Duration : Intptr (duration ),
0 commit comments