Skip to content

Commit e4ca85a

Browse files
Cawb07stuarthicks
authored andcommitted
Fix marshaling ContentProtectioner & unmarshaling in AdaptationSet (#53)
* Make AdaptationSet implement Unmarshaler to handle unmarshaling interface type ContentProtectioner * Fix mpd/mpd_test.go
1 parent 12a54ee commit e4ca85a

File tree

2 files changed

+218
-6
lines changed

2 files changed

+218
-6
lines changed

mpd/mpd.go

Lines changed: 216 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,129 @@ type AdaptationSet struct {
132132
Representations []*Representation `xml:"Representation,omitempty"`
133133
}
134134

135+
func (as *AdaptationSet) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
136+
137+
adaptationSet := struct {
138+
CommonAttributesAndElements
139+
XMLName xml.Name `xml:"AdaptationSet"`
140+
ID *string `xml:"id,attr"`
141+
SegmentAlignment *bool `xml:"segmentAlignment,attr"`
142+
Lang *string `xml:"lang,attr"`
143+
Group *string `xml:"group,attr"`
144+
PAR *string `xml:"par,attr"`
145+
MinBandwidth *string `xml:"minBandwidth,attr"`
146+
MaxBandwidth *string `xml:"maxBandwidth,attr"`
147+
MinWidth *string `xml:"minWidth,attr"`
148+
MaxWidth *string `xml:"maxWidth,attr"`
149+
ContentProtection []ContentProtectioner `xml:"ContentProtection,omitempty"` // Common attribute, can be deprecated here
150+
Roles []*Role `xml:"Role,omitempty"`
151+
SegmentBase *SegmentBase `xml:"SegmentBase,omitempty"`
152+
SegmentList *SegmentList `xml:"SegmentList,omitempty"`
153+
SegmentTemplate *SegmentTemplate `xml:"SegmentTemplate,omitempty"` // Live Profile Only
154+
Representations []*Representation `xml:"Representation,omitempty"`
155+
}{}
156+
157+
var (
158+
contentProtectionTags []ContentProtectioner
159+
roles []*Role
160+
segmentBase *SegmentBase
161+
segmentList *SegmentList
162+
segmentTemplate *SegmentTemplate
163+
representations []*Representation
164+
)
165+
166+
// decode inner elements
167+
for {
168+
t, err := d.Token()
169+
if err != nil {
170+
return err
171+
}
172+
173+
switch tt := t.(type) {
174+
case xml.StartElement:
175+
switch tt.Name.Local {
176+
case "ContentProtection":
177+
var (
178+
schemeUri string
179+
cp ContentProtectioner
180+
)
181+
182+
for _, attr := range tt.Attr {
183+
if attr.Name.Local == "schemeIdUri" {
184+
schemeUri = attr.Value
185+
}
186+
}
187+
switch schemeUri {
188+
case CONTENT_PROTECTION_ROOT_SCHEME_ID_URI:
189+
cp = new(CENCContentProtection)
190+
case CONTENT_PROTECTION_PLAYREADY_SCHEME_ID:
191+
cp = new(PlayreadyContentProtection)
192+
case CONTENT_PROTECTION_WIDEVINE_SCHEME_ID:
193+
cp = new(WidevineContentProtection)
194+
default:
195+
cp = new(ContentProtection)
196+
}
197+
198+
err = d.DecodeElement(cp, &tt)
199+
if err != nil {
200+
return err
201+
}
202+
contentProtectionTags = append(contentProtectionTags, cp)
203+
case "Role":
204+
rl := new(Role)
205+
err = d.DecodeElement(rl, &tt)
206+
if err != nil {
207+
return err
208+
}
209+
roles = append(roles, rl)
210+
case "SegmentBase":
211+
sb := new(SegmentBase)
212+
err = d.DecodeElement(sb, &tt)
213+
if err != nil {
214+
return err
215+
}
216+
segmentBase = sb
217+
case "SegmentList":
218+
sl := new(SegmentList)
219+
err = d.DecodeElement(sl, &tt)
220+
if err != nil {
221+
return err
222+
}
223+
segmentList = sl
224+
case "SegmentTemplate":
225+
st := new(SegmentTemplate)
226+
err = d.DecodeElement(st, &tt)
227+
if err != nil {
228+
return err
229+
}
230+
segmentTemplate = st
231+
case "Representation":
232+
rp := new(Representation)
233+
err = d.DecodeElement(rp, &tt)
234+
if err != nil {
235+
return err
236+
}
237+
representations = append(representations, rp)
238+
default:
239+
return errors.New("Unrecognized element in AdaptationSet")
240+
}
241+
case xml.EndElement:
242+
if tt == start.End() {
243+
d.DecodeElement(&adaptationSet, &start)
244+
*as = adaptationSet
245+
as.ContentProtection = contentProtectionTags
246+
as.Roles = roles
247+
as.SegmentBase = segmentBase
248+
as.SegmentList = segmentList
249+
as.SegmentTemplate = segmentTemplate
250+
as.Representations = representations
251+
return nil
252+
}
253+
}
254+
255+
}
256+
}
257+
135258
// Constants for DRM / ContentProtection
136259
const (
137260
CONTENT_PROTECTION_ROOT_SCHEME_ID_URI = "urn:mpeg:dash:mp4protection:2011"
@@ -154,29 +277,118 @@ type ContentProtection struct {
154277
AdaptationSet *AdaptationSet `xml:"-"`
155278
XMLName xml.Name `xml:"ContentProtection"`
156279
SchemeIDURI *string `xml:"schemeIdUri,attr"` // Default: urn:mpeg:dash:mp4protection:2011
157-
XMLNS *string `xml:"xmlns:cenc,attr"` // Default: urn:mpeg:cenc:2013
280+
XMLNS *string `xml:"cenc,attr"` // Default: urn:mpeg:cenc:2013
158281
}
159282

160283
type CENCContentProtection struct {
161284
ContentProtection
162-
DefaultKID *string `xml:"cenc:default_KID,attr"`
285+
DefaultKID *string `xml:"default_KID,attr"`
163286
Value *string `xml:"value,attr"` // Default: cenc
164287
}
165288

166289
type PlayreadyContentProtection struct {
167290
ContentProtection
291+
PlayreadyXMLNS *string `xml:"mspr,attr,omitempty"`
292+
PRO *string `xml:"pro,omitempty"`
293+
PSSH *string `xml:"pssh,omitempty"`
294+
}
295+
296+
type WidevineContentProtection struct {
297+
ContentProtection
298+
PSSH *string `xml:"pssh,omitempty"`
299+
}
300+
301+
type ContentProtectionMarshal struct {
302+
AdaptationSet *AdaptationSet `xml:"-"`
303+
XMLName xml.Name `xml:"ContentProtection"`
304+
SchemeIDURI *string `xml:"schemeIdUri,attr"` // Default: urn:mpeg:dash:mp4protection:2011
305+
XMLNS *string `xml:"xmlns:cenc,attr"` // Default: urn:mpeg:cenc:2013
306+
}
307+
308+
type CENCContentProtectionMarshal struct {
309+
ContentProtectionMarshal
310+
DefaultKID *string `xml:"cenc:default_KID,attr"`
311+
Value *string `xml:"value,attr"` // Default: cenc
312+
}
313+
314+
type PlayreadyContentProtectionMarshal struct {
315+
ContentProtectionMarshal
168316
PlayreadyXMLNS *string `xml:"xmlns:mspr,attr,omitempty"`
169317
PRO *string `xml:"mspr:pro,omitempty"`
170318
PSSH *string `xml:"cenc:pssh,omitempty"`
171319
}
172320

173-
type WidevineContentProtection struct {
174-
ContentProtection
321+
type WidevineContentProtectionMarshal struct {
322+
ContentProtectionMarshal
175323
PSSH *string `xml:"cenc:pssh,omitempty"`
176324
}
177325

178326
func (s ContentProtection) ContentProtected() {}
179327

328+
func (s ContentProtection) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
329+
err := e.Encode(&ContentProtectionMarshal{
330+
s.AdaptationSet,
331+
s.XMLName,
332+
s.SchemeIDURI,
333+
s.XMLNS,
334+
})
335+
if err != nil {
336+
return err
337+
}
338+
return nil
339+
}
340+
341+
func (s CENCContentProtection) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
342+
err := e.Encode(&CENCContentProtectionMarshal{
343+
ContentProtectionMarshal{
344+
s.AdaptationSet,
345+
s.XMLName,
346+
s.SchemeIDURI,
347+
s.XMLNS,
348+
},
349+
s.DefaultKID,
350+
s.Value,
351+
})
352+
if err != nil {
353+
return err
354+
}
355+
return nil
356+
}
357+
358+
func (s PlayreadyContentProtection) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
359+
err := e.Encode(&PlayreadyContentProtectionMarshal{
360+
ContentProtectionMarshal{
361+
s.AdaptationSet,
362+
s.XMLName,
363+
s.SchemeIDURI,
364+
s.XMLNS,
365+
},
366+
s.PlayreadyXMLNS,
367+
s.PRO,
368+
s.PSSH,
369+
})
370+
if err != nil {
371+
return err
372+
}
373+
return nil
374+
}
375+
376+
func (s WidevineContentProtection) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
377+
err := e.Encode(&WidevineContentProtectionMarshal{
378+
ContentProtectionMarshal{
379+
s.AdaptationSet,
380+
s.XMLName,
381+
s.SchemeIDURI,
382+
s.XMLNS,
383+
},
384+
s.PSSH,
385+
})
386+
if err != nil {
387+
return err
388+
}
389+
return nil
390+
}
391+
180392
type Role struct {
181393
AdaptationSet *AdaptationSet `xml:"-"`
182394
SchemeIDURI *string `xml:"schemeIdUri,attr"`

mpd/mpd_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ func TestAddNewContentProtectionRoot(t *testing.T) {
386386
}
387387

388388
type TestProprietaryContentProtection struct {
389-
ContentProtection
389+
ContentProtectionMarshal
390390
TestAttrA string `xml:"a,attr,omitempty"`
391391
TestAttrB string `xml:"b,attr,omitempty"`
392392
}
@@ -397,7 +397,7 @@ func TestAddNewContentProtection_Proprietary(t *testing.T) {
397397
m := NewMPD(DASH_PROFILE_LIVE, VALID_MEDIA_PRESENTATION_DURATION, VALID_MIN_BUFFER_TIME)
398398
as, _ := m.AddNewAdaptationSetVideoWithID("7357", DASH_MIME_TYPE_VIDEO_MP4, VALID_SCAN_TYPE, VALID_SEGMENT_ALIGNMENT, VALID_START_WITH_SAP)
399399

400-
cp := &ContentProtection{
400+
cp := &ContentProtectionMarshal{
401401
SchemeIDURI: Strptr(CONTENT_PROTECTION_ROOT_SCHEME_ID_URI),
402402
}
403403

0 commit comments

Comments
 (0)