From 141c92205e9f9db2c355a9a87ab28e469b2e2507 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torbjo=CC=88rn=20Einarsson?= Date: Tue, 27 Oct 2020 08:45:44 +0100 Subject: [PATCH 1/9] Add MPD@maxSegmentDuration --- mpd.go | 3 +++ mpd_test.go | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/mpd.go b/mpd.go index 7081f17..1f18fac 100644 --- a/mpd.go +++ b/mpd.go @@ -70,6 +70,7 @@ type MPD struct { AvailabilityStartTime *string `xml:"availabilityStartTime,attr"` MediaPresentationDuration *string `xml:"mediaPresentationDuration,attr"` MinBufferTime *string `xml:"minBufferTime,attr"` + MaxSegmentDuration *string `xml:"maxSegmentDuration,attr,omitempty"` SuggestedPresentationDelay *string `xml:"suggestedPresentationDelay,attr"` TimeShiftBufferDepth *string `xml:"timeShiftBufferDepth,attr"` PublishTime *string `xml:"publishTime,attr"` @@ -94,6 +95,7 @@ type mpdMarshal struct { AvailabilityStartTime *string `xml:"availabilityStartTime,attr"` MediaPresentationDuration *string `xml:"mediaPresentationDuration,attr"` MinBufferTime *string `xml:"minBufferTime,attr"` + MaxSegmentDuration *string `xml:"maxSegmentDuration,attr,omitempty"` SuggestedPresentationDelay *string `xml:"suggestedPresentationDelay,attr"` TimeShiftBufferDepth *string `xml:"timeShiftBufferDepth,attr"` Profiles string `xml:"profiles,attr"` @@ -268,6 +270,7 @@ func modifyMPD(mpd *MPD) *mpdMarshal { AvailabilityStartTime: copyobj.String(mpd.AvailabilityStartTime), MediaPresentationDuration: copyobj.String(mpd.MediaPresentationDuration), MinBufferTime: copyobj.String(mpd.MinBufferTime), + MaxSegmentDuration: copyobj.String(mpd.MaxSegmentDuration), SuggestedPresentationDelay: copyobj.String(mpd.SuggestedPresentationDelay), TimeShiftBufferDepth: copyobj.String(mpd.TimeShiftBufferDepth), PublishTime: copyobj.String(mpd.PublishTime), diff --git a/mpd_test.go b/mpd_test.go index 18a0ae3..56ac5a5 100644 --- a/mpd_test.go +++ b/mpd_test.go @@ -64,7 +64,7 @@ func (s *MPDSuite) TestUnmarshalMarshalVodBaseURL(c *C) { func TestMPDEqual(t *testing.T) { a := &MPD{} b := &mpdMarshal{} - require.Equal(t, 16, reflect.ValueOf(a).Elem().NumField(), + require.Equal(t, 17, reflect.ValueOf(a).Elem().NumField(), "model was updated, need to update this test and function modifyMPD") require.Equal(t, reflect.ValueOf(a).Elem().NumField(), reflect.ValueOf(b).Elem().NumField(), "MPD element count not equal mpdMarshal") From 282bd0e8a198a1da6c2e061609d54cfbbd12697e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torbjo=CC=88rn=20Einarsson?= Date: Tue, 27 Oct 2020 08:46:43 +0100 Subject: [PATCH 2/9] Add Representation@AudioChannelConfiguration --- mpd.go | 85 ++++++++++++++++++++++++++++++++--------------------- mpd_test.go | 2 +- 2 files changed, 53 insertions(+), 34 deletions(-) diff --git a/mpd.go b/mpd.go index 1f18fac..664028e 100644 --- a/mpd.go +++ b/mpd.go @@ -190,31 +190,33 @@ type adaptationSetMarshal struct { // Representation represents XSD's RepresentationType. type Representation struct { - ID *string `xml:"id,attr"` - Width *uint64 `xml:"width,attr"` - Height *uint64 `xml:"height,attr"` - SAR *string `xml:"sar,attr"` - FrameRate *string `xml:"frameRate,attr"` - Bandwidth *uint64 `xml:"bandwidth,attr"` - AudioSamplingRate *string `xml:"audioSamplingRate,attr"` - Codecs *string `xml:"codecs,attr"` - BaseURL *string `xml:"BaseURL,omitempty"` - ContentProtections []DRMDescriptor `xml:"ContentProtection,omitempty"` - SegmentTemplate *SegmentTemplate `xml:"SegmentTemplate,omitempty"` + ID *string `xml:"id,attr"` + Width *uint64 `xml:"width,attr"` + Height *uint64 `xml:"height,attr"` + SAR *string `xml:"sar,attr"` + FrameRate *string `xml:"frameRate,attr"` + Bandwidth *uint64 `xml:"bandwidth,attr"` + AudioSamplingRate *string `xml:"audioSamplingRate,attr"` + Codecs *string `xml:"codecs,attr"` + BaseURL *string `xml:"BaseURL,omitempty"` + ContentProtections []DRMDescriptor `xml:"ContentProtection,omitempty"` + SegmentTemplate *SegmentTemplate `xml:"SegmentTemplate,omitempty"` + AudioChannelConfiguration *AudioChannelConfiguration `xml:"AudioChannelConfiguration,omitempty"` } type representationMarshal struct { - ID *string `xml:"id,attr"` - Width *uint64 `xml:"width,attr"` - Height *uint64 `xml:"height,attr"` - SAR *string `xml:"sar,attr"` - FrameRate *string `xml:"frameRate,attr"` - Bandwidth *uint64 `xml:"bandwidth,attr"` - AudioSamplingRate *string `xml:"audioSamplingRate,attr"` - Codecs *string `xml:"codecs,attr"` - BaseURL *string `xml:"BaseURL,omitempty"` - ContentProtections []drmDescriptorMarshal `xml:"ContentProtection,omitempty"` - SegmentTemplate *SegmentTemplate `xml:"SegmentTemplate,omitempty"` + ID *string `xml:"id,attr"` + Width *uint64 `xml:"width,attr"` + Height *uint64 `xml:"height,attr"` + SAR *string `xml:"sar,attr"` + FrameRate *string `xml:"frameRate,attr"` + Bandwidth *uint64 `xml:"bandwidth,attr"` + AudioSamplingRate *string `xml:"audioSamplingRate,attr"` + Codecs *string `xml:"codecs,attr"` + BaseURL *string `xml:"BaseURL,omitempty"` + ContentProtections []drmDescriptorMarshal `xml:"ContentProtection,omitempty"` + SegmentTemplate *SegmentTemplate `xml:"SegmentTemplate,omitempty"` + AudioChannelConfiguration *AudioChannelConfiguration `xml:"AudioChannelConfiguration,omitempty"` } // Descriptor represents XSD's DescriptorType. @@ -329,23 +331,34 @@ func modifyRepresentations(rs []Representation) []representationMarshal { rsm := make([]representationMarshal, 0, len(rs)) for _, r := range rs { representation := representationMarshal{ - AudioSamplingRate: copyobj.String(r.AudioSamplingRate), - Bandwidth: copyobj.UInt64(r.Bandwidth), - Codecs: copyobj.String(r.Codecs), - FrameRate: copyobj.String(r.FrameRate), - Height: copyobj.UInt64(r.Height), - ID: copyobj.String(r.ID), - Width: copyobj.UInt64(r.Width), - SegmentTemplate: copySegmentTemplate(r.SegmentTemplate), - SAR: copyobj.String(r.SAR), - ContentProtections: modifyContentProtections(r.ContentProtections), - BaseURL: copyobj.String(r.BaseURL), + AudioSamplingRate: copyobj.String(r.AudioSamplingRate), + Bandwidth: copyobj.UInt64(r.Bandwidth), + Codecs: copyobj.String(r.Codecs), + FrameRate: copyobj.String(r.FrameRate), + Height: copyobj.UInt64(r.Height), + ID: copyobj.String(r.ID), + Width: copyobj.UInt64(r.Width), + SegmentTemplate: copySegmentTemplate(r.SegmentTemplate), + SAR: copyobj.String(r.SAR), + ContentProtections: modifyContentProtections(r.ContentProtections), + BaseURL: copyobj.String(r.BaseURL), + AudioChannelConfiguration: copyAudioChannelConfiguration(r.AudioChannelConfiguration), } rsm = append(rsm, representation) } return rsm } +func copyAudioChannelConfiguration(acc *AudioChannelConfiguration) *AudioChannelConfiguration { + if acc == nil { + return nil + } + return &AudioChannelConfiguration{ + SchemeIDURI: copyobj.String(acc.SchemeIDURI), + Value: copyobj.String(acc.Value), + } +} + func copySegmentTemplate(st *SegmentTemplate) *SegmentTemplate { if st == nil { return nil @@ -397,3 +410,9 @@ func modifyPssh(p *Pssh) *psshMarshal { Value: copyobj.String(p.Value), } } + +// AudioChannelConfiguration represents XSD's AudioChannelConfiguration type. +type AudioChannelConfiguration struct { + SchemeIDURI *string `xml:"schemeIdUri,attr"` + Value *string `xml:"value,attr,omitempty"` +} diff --git a/mpd_test.go b/mpd_test.go index 56ac5a5..972387a 100644 --- a/mpd_test.go +++ b/mpd_test.go @@ -91,7 +91,7 @@ func TestAdaptationSetEqual(t *testing.T) { func TestRepresentationEqual(t *testing.T) { a := &Representation{} b := &representationMarshal{} - require.Equal(t, 11, reflect.ValueOf(a).Elem().NumField(), + require.Equal(t, 12, reflect.ValueOf(a).Elem().NumField(), "model was updated, need to update this test and function modifyRepresentations") require.Equal(t, reflect.ValueOf(a).Elem().NumField(), reflect.ValueOf(b).Elem().NumField(), "Representation element count not equal Representation") From bbdab2410a814d356c4a60d88a6cd9de81295518 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torbjo=CC=88rn=20Einarsson?= Date: Tue, 27 Oct 2020 08:47:19 +0100 Subject: [PATCH 3/9] Add AdaptationSet.contentType --- mpd.go | 3 +++ mpd_test.go | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/mpd.go b/mpd.go index 664028e..5e233a7 100644 --- a/mpd.go +++ b/mpd.go @@ -163,6 +163,7 @@ type periodMarshal struct { // AdaptationSet represents XSD's AdaptationSetType. type AdaptationSet struct { + ContentType string `xml:"contentType,attr,omitempty"` MimeType string `xml:"mimeType,attr"` SegmentAlignment ConditionalUint `xml:"segmentAlignment,attr"` StartWithSAP *uint64 `xml:"startWithSAP,attr"` @@ -176,6 +177,7 @@ type AdaptationSet struct { } type adaptationSetMarshal struct { + ContentType string `xml:"contentType,attr,omitempty"` MimeType string `xml:"mimeType,attr"` SegmentAlignment ConditionalUint `xml:"segmentAlignment,attr"` StartWithSAP *uint64 `xml:"startWithSAP,attr"` @@ -314,6 +316,7 @@ func modifyAdaptationSets(as []*AdaptationSet) []*adaptationSetMarshal { BitstreamSwitching: copyobj.Bool(a.BitstreamSwitching), Codecs: copyobj.String(a.Codecs), Lang: copyobj.String(a.Lang), + ContentType: a.ContentType, MimeType: a.MimeType, SegmentAlignment: a.SegmentAlignment, StartWithSAP: copyobj.UInt64(a.StartWithSAP), diff --git a/mpd_test.go b/mpd_test.go index 972387a..c107399 100644 --- a/mpd_test.go +++ b/mpd_test.go @@ -82,7 +82,7 @@ func TestPeriodEqual(t *testing.T) { func TestAdaptationSetEqual(t *testing.T) { a := &AdaptationSet{} b := &adaptationSetMarshal{} - require.Equal(t, 10, reflect.ValueOf(a).Elem().NumField(), + require.Equal(t, 11, reflect.ValueOf(a).Elem().NumField(), "model was updated, need to update this test and function modifyAdaptationSets") require.Equal(t, reflect.ValueOf(a).Elem().NumField(), reflect.ValueOf(b).Elem().NumField(), "AdaptationSet element count not equal adaptationSetMarshal") From 45a7eaed0027cc793e098fda572252dc69394ae1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torbjo=CC=88rn=20Einarsson?= Date: Tue, 27 Oct 2020 08:54:18 +0100 Subject: [PATCH 4/9] Add more video attributes to AdaptationSet --- mpd.go | 18 ++++++++++++++++++ mpd_test.go | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/mpd.go b/mpd.go index 5e233a7..24424fa 100644 --- a/mpd.go +++ b/mpd.go @@ -172,6 +172,12 @@ type AdaptationSet struct { SubsegmentStartsWithSAP *uint64 `xml:"subsegmentStartsWithSAP,attr"` Lang *string `xml:"lang,attr"` ContentProtections []DRMDescriptor `xml:"ContentProtection,omitempty"` + Par *string `xml:"par,attr"` + MinWidth *uint64 `xml:"minWidth,attr"` + MaxWidth *uint64 `xml:"maxWidth,attr"` + MinHeight *uint64 `xml:"minHeight,attr"` + MaxHeight *uint64 `xml:"maxHeight,attr"` + MaxFrameRate *string `xml:"maxFrameRate,attr"` Representations []Representation `xml:"Representation,omitempty"` Codecs *string `xml:"codecs,attr"` } @@ -186,6 +192,12 @@ type adaptationSetMarshal struct { SubsegmentStartsWithSAP *uint64 `xml:"subsegmentStartsWithSAP,attr"` Lang *string `xml:"lang,attr"` ContentProtections []drmDescriptorMarshal `xml:"ContentProtection,omitempty"` + Par *string `xml:"par,attr"` + MinWidth *uint64 `xml:"minWidth,attr"` + MaxWidth *uint64 `xml:"maxWidth,attr"` + MinHeight *uint64 `xml:"minHeight,attr"` + MaxHeight *uint64 `xml:"maxHeight,attr"` + MaxFrameRate *string `xml:"maxFrameRate,attr"` Representations []representationMarshal `xml:"Representation,omitempty"` Codecs *string `xml:"codecs,attr"` } @@ -320,6 +332,12 @@ func modifyAdaptationSets(as []*AdaptationSet) []*adaptationSetMarshal { MimeType: a.MimeType, SegmentAlignment: a.SegmentAlignment, StartWithSAP: copyobj.UInt64(a.StartWithSAP), + Par: copyobj.String(a.Par), + MinWidth: copyobj.UInt64(a.MinWidth), + MaxWidth: copyobj.UInt64(a.MaxWidth), + MinHeight: copyobj.UInt64(a.MinHeight), + MaxHeight: copyobj.UInt64(a.MaxHeight), + MaxFrameRate: copyobj.String(a.MaxFrameRate), SubsegmentAlignment: a.SubsegmentAlignment, SubsegmentStartsWithSAP: copyobj.UInt64(a.SubsegmentStartsWithSAP), Representations: modifyRepresentations(a.Representations), diff --git a/mpd_test.go b/mpd_test.go index c107399..92317bb 100644 --- a/mpd_test.go +++ b/mpd_test.go @@ -82,7 +82,7 @@ func TestPeriodEqual(t *testing.T) { func TestAdaptationSetEqual(t *testing.T) { a := &AdaptationSet{} b := &adaptationSetMarshal{} - require.Equal(t, 11, reflect.ValueOf(a).Elem().NumField(), + require.Equal(t, 17, reflect.ValueOf(a).Elem().NumField(), "model was updated, need to update this test and function modifyAdaptationSets") require.Equal(t, reflect.ValueOf(a).Elem().NumField(), reflect.ValueOf(b).Elem().NumField(), "AdaptationSet element count not equal adaptationSetMarshal") From 42278e2bd2c8b97413a4faa2c46f9d701d3fe3c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torbjo=CC=88rn=20Einarsson?= Date: Tue, 27 Oct 2020 19:12:38 +0100 Subject: [PATCH 5/9] Add PresentationInfo with Title --- mpd.go | 85 ++++++++++++++++++++++++++++++++--------------------- mpd_test.go | 2 +- 2 files changed, 52 insertions(+), 35 deletions(-) diff --git a/mpd.go b/mpd.go index 24424fa..2f56398 100644 --- a/mpd.go +++ b/mpd.go @@ -63,44 +63,46 @@ var ( // MPD represents root XML element for parse. type MPD struct { - XMLName xml.Name `xml:"MPD"` - XMLNS *string `xml:"xmlns,attr"` - Type *string `xml:"type,attr"` - MinimumUpdatePeriod *string `xml:"minimumUpdatePeriod,attr"` - AvailabilityStartTime *string `xml:"availabilityStartTime,attr"` - MediaPresentationDuration *string `xml:"mediaPresentationDuration,attr"` - MinBufferTime *string `xml:"minBufferTime,attr"` - MaxSegmentDuration *string `xml:"maxSegmentDuration,attr,omitempty"` - SuggestedPresentationDelay *string `xml:"suggestedPresentationDelay,attr"` - TimeShiftBufferDepth *string `xml:"timeShiftBufferDepth,attr"` - PublishTime *string `xml:"publishTime,attr"` - Profiles string `xml:"profiles,attr"` - XSI *string `xml:"xsi,attr,omitempty"` - SCTE35 *string `xml:"scte35,attr,omitempty"` - XSISchemaLocation *string `xml:"schemaLocation,attr"` - ID *string `xml:"id,attr"` - Period []Period `xml:"Period,omitempty"` + XMLName xml.Name `xml:"MPD"` + XMLNS *string `xml:"xmlns,attr"` + Type *string `xml:"type,attr"` + MinimumUpdatePeriod *string `xml:"minimumUpdatePeriod,attr"` + AvailabilityStartTime *string `xml:"availabilityStartTime,attr"` + MediaPresentationDuration *string `xml:"mediaPresentationDuration,attr"` + MinBufferTime *string `xml:"minBufferTime,attr"` + MaxSegmentDuration *string `xml:"maxSegmentDuration,attr,omitempty"` + SuggestedPresentationDelay *string `xml:"suggestedPresentationDelay,attr"` + TimeShiftBufferDepth *string `xml:"timeShiftBufferDepth,attr"` + PublishTime *string `xml:"publishTime,attr"` + Profiles string `xml:"profiles,attr"` + XSI *string `xml:"xsi,attr,omitempty"` + SCTE35 *string `xml:"scte35,attr,omitempty"` + XSISchemaLocation *string `xml:"schemaLocation,attr"` + ID *string `xml:"id,attr"` + ProgramInformation *ProgramInformation `xml:"ProgramInformation,omitempty"` + Period []Period `xml:"Period,omitempty"` } // MPD represents root XML element for Marshal. type mpdMarshal struct { - XMLName xml.Name `xml:"MPD"` - XSI *string `xml:"xmlns:xsi,attr,omitempty"` - XMLNS *string `xml:"xmlns,attr"` - XSISchemaLocation *string `xml:"xsi:schemaLocation,attr"` - ID *string `xml:"id,attr"` - Type *string `xml:"type,attr"` - PublishTime *string `xml:"publishTime,attr"` - MinimumUpdatePeriod *string `xml:"minimumUpdatePeriod,attr"` - AvailabilityStartTime *string `xml:"availabilityStartTime,attr"` - MediaPresentationDuration *string `xml:"mediaPresentationDuration,attr"` - MinBufferTime *string `xml:"minBufferTime,attr"` - MaxSegmentDuration *string `xml:"maxSegmentDuration,attr,omitempty"` - SuggestedPresentationDelay *string `xml:"suggestedPresentationDelay,attr"` - TimeShiftBufferDepth *string `xml:"timeShiftBufferDepth,attr"` - Profiles string `xml:"profiles,attr"` - SCTE35 *string `xml:"xmlns:scte35,attr,omitempty"` - Period []periodMarshal `xml:"Period,omitempty"` + XMLName xml.Name `xml:"MPD"` + XSI *string `xml:"xmlns:xsi,attr,omitempty"` + XMLNS *string `xml:"xmlns,attr"` + XSISchemaLocation *string `xml:"xsi:schemaLocation,attr"` + ID *string `xml:"id,attr"` + Type *string `xml:"type,attr"` + PublishTime *string `xml:"publishTime,attr"` + MinimumUpdatePeriod *string `xml:"minimumUpdatePeriod,attr"` + AvailabilityStartTime *string `xml:"availabilityStartTime,attr"` + MediaPresentationDuration *string `xml:"mediaPresentationDuration,attr"` + MinBufferTime *string `xml:"minBufferTime,attr"` + MaxSegmentDuration *string `xml:"maxSegmentDuration,attr,omitempty"` + SuggestedPresentationDelay *string `xml:"suggestedPresentationDelay,attr"` + TimeShiftBufferDepth *string `xml:"timeShiftBufferDepth,attr"` + Profiles string `xml:"profiles,attr"` + SCTE35 *string `xml:"xmlns:scte35,attr,omitempty"` + ProgramInformation *ProgramInformation `xml:"ProgramInformation,omitempty"` + Period []periodMarshal `xml:"Period,omitempty"` } // Do not try to use encoding.TextMarshaler and encoding.TextUnmarshaler: @@ -145,6 +147,11 @@ func (m *MPD) Decode(b []byte) error { return xml.Unmarshal(b, m) } +// ProgramInformation - MPD Program info. +type ProgramInformation struct { + Title string `xml:"Title,omitempty"` +} + // Period represents XSD's PeriodType. type Period struct { Start *string `xml:"start,attr"` @@ -296,6 +303,7 @@ func modifyMPD(mpd *MPD) *mpdMarshal { SCTE35: copyobj.String(mpd.SCTE35), XSISchemaLocation: copyobj.String(mpd.XSISchemaLocation), ID: copyobj.String(mpd.ID), + ProgramInformation: copyProgramInformation(mpd.ProgramInformation), Period: modifyPeriod(mpd.Period), } } @@ -318,6 +326,15 @@ func modifyPeriod(ps []Period) []periodMarshal { return pms } +func copyProgramInformation(p *ProgramInformation) *ProgramInformation { + if p == nil { + return nil + } + return &ProgramInformation{ + Title: p.Title, + } +} + func modifyAdaptationSets(as []*AdaptationSet) []*adaptationSetMarshal { if as == nil { return nil diff --git a/mpd_test.go b/mpd_test.go index 92317bb..fa28db5 100644 --- a/mpd_test.go +++ b/mpd_test.go @@ -64,7 +64,7 @@ func (s *MPDSuite) TestUnmarshalMarshalVodBaseURL(c *C) { func TestMPDEqual(t *testing.T) { a := &MPD{} b := &mpdMarshal{} - require.Equal(t, 17, reflect.ValueOf(a).Elem().NumField(), + require.Equal(t, 18, reflect.ValueOf(a).Elem().NumField(), "model was updated, need to update this test and function modifyMPD") require.Equal(t, reflect.ValueOf(a).Elem().NumField(), reflect.ValueOf(b).Elem().NumField(), "MPD element count not equal mpdMarshal") From 081b01a7e0b439ff7d974641c7030a781a9fccdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torbjo=CC=88rn=20Einarsson?= Date: Tue, 27 Oct 2020 19:12:10 +0100 Subject: [PATCH 6/9] Fix SegmentTemplate to handle case with no SegmentTimeline --- mpd.go | 34 ++++++++++++++++++++++------------ mpd_test.go | 2 +- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/mpd.go b/mpd.go index 2f56398..1689bab 100644 --- a/mpd.go +++ b/mpd.go @@ -257,7 +257,7 @@ type drmDescriptorMarshal struct { Pssh *psshMarshal `xml:"cenc:pssh"` } -// Pssh represents XSD's CencPsshType . +// Pssh represents XSD's CencPsshType. type Pssh struct { Cenc *string `xml:"cenc,attr"` Value *string `xml:",chardata"` @@ -270,12 +270,18 @@ type psshMarshal struct { // SegmentTemplate represents XSD's SegmentTemplateType. type SegmentTemplate struct { - Timescale *uint64 `xml:"timescale,attr"` - Media *string `xml:"media,attr"` - Initialization *string `xml:"initialization,attr"` - StartNumber *uint64 `xml:"startNumber,attr"` - PresentationTimeOffset *uint64 `xml:"presentationTimeOffset,attr"` - SegmentTimelineS []SegmentTimelineS `xml:"SegmentTimeline>S,omitempty"` + Timescale *uint64 `xml:"timescale,attr"` + Media *string `xml:"media,attr"` + Initialization *string `xml:"initialization,attr"` + Duration *uint64 `xml:"duration,attr"` + StartNumber *uint64 `xml:"startNumber,attr"` + PresentationTimeOffset *uint64 `xml:"presentationTimeOffset,attr"` + SegmentTimeline *SegmentTimeline `xml:"SegmentTimeline,omitempty"` +} + +// SegmentTimeLine represent a SegmentTimeline node. +type SegmentTimeline struct { + S []SegmentTimelineS `xml:"S,omitempty"` } // SegmentTimelineS represents XSD's SegmentTimelineType's inner S elements. @@ -405,15 +411,19 @@ func copySegmentTemplate(st *SegmentTemplate) *SegmentTemplate { Timescale: copyobj.UInt64(st.Timescale), Media: copyobj.String(st.Media), Initialization: copyobj.String(st.Initialization), + Duration: copyobj.UInt64(st.Duration), StartNumber: copyobj.UInt64(st.StartNumber), PresentationTimeOffset: copyobj.UInt64(st.PresentationTimeOffset), - SegmentTimelineS: copySegmentTimelineS(st.SegmentTimelineS), + SegmentTimeline: copySegmentTimeline(st.SegmentTimeline), } } -func copySegmentTimelineS(st []SegmentTimelineS) []SegmentTimelineS { - stm := make([]SegmentTimelineS, 0, len(st)) - for _, s := range st { +func copySegmentTimeline(st *SegmentTimeline) *SegmentTimeline { + if st == nil || len(st.S) == 0 { + return nil + } + stm := make([]SegmentTimelineS, 0, len(st.S)) + for _, s := range st.S { segmentTimelineS := SegmentTimelineS{ T: s.T, D: s.D, @@ -421,7 +431,7 @@ func copySegmentTimelineS(st []SegmentTimelineS) []SegmentTimelineS { } stm = append(stm, segmentTimelineS) } - return stm + return &SegmentTimeline{S: stm} } func modifyContentProtections(ds []DRMDescriptor) []drmDescriptorMarshal { diff --git a/mpd_test.go b/mpd_test.go index fa28db5..4bbefbf 100644 --- a/mpd_test.go +++ b/mpd_test.go @@ -99,7 +99,7 @@ func TestRepresentationEqual(t *testing.T) { func TestSegmentTemplateEqual(t *testing.T) { a := &SegmentTemplate{} - require.Equal(t, 6, reflect.ValueOf(a).Elem().NumField(), + require.Equal(t, 7, reflect.ValueOf(a).Elem().NumField(), "model was updated, need to update this test and function copySegmentTemplate") } From 30f2ba108e3783c435e44a9f4ec5033747785c34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torbjo=CC=88rn=20Einarsson?= Date: Tue, 27 Oct 2020 13:59:04 +0100 Subject: [PATCH 7/9] Add Role and general DescriptorType --- mpd.go | 69 ++++++++++++++++++++++++++++------------------------- mpd_test.go | 2 +- 2 files changed, 38 insertions(+), 33 deletions(-) diff --git a/mpd.go b/mpd.go index 1689bab..3e9cf0b 100644 --- a/mpd.go +++ b/mpd.go @@ -185,6 +185,7 @@ type AdaptationSet struct { MinHeight *uint64 `xml:"minHeight,attr"` MaxHeight *uint64 `xml:"maxHeight,attr"` MaxFrameRate *string `xml:"maxFrameRate,attr"` + Role *DescriptorType `xml:"Role,omitempty"` Representations []Representation `xml:"Representation,omitempty"` Codecs *string `xml:"codecs,attr"` } @@ -205,39 +206,40 @@ type adaptationSetMarshal struct { MinHeight *uint64 `xml:"minHeight,attr"` MaxHeight *uint64 `xml:"maxHeight,attr"` MaxFrameRate *string `xml:"maxFrameRate,attr"` + Role *DescriptorType `xml:"Role,omitempty"` Representations []representationMarshal `xml:"Representation,omitempty"` Codecs *string `xml:"codecs,attr"` } // Representation represents XSD's RepresentationType. type Representation struct { - ID *string `xml:"id,attr"` - Width *uint64 `xml:"width,attr"` - Height *uint64 `xml:"height,attr"` - SAR *string `xml:"sar,attr"` - FrameRate *string `xml:"frameRate,attr"` - Bandwidth *uint64 `xml:"bandwidth,attr"` - AudioSamplingRate *string `xml:"audioSamplingRate,attr"` - Codecs *string `xml:"codecs,attr"` - BaseURL *string `xml:"BaseURL,omitempty"` - ContentProtections []DRMDescriptor `xml:"ContentProtection,omitempty"` - SegmentTemplate *SegmentTemplate `xml:"SegmentTemplate,omitempty"` - AudioChannelConfiguration *AudioChannelConfiguration `xml:"AudioChannelConfiguration,omitempty"` + ID *string `xml:"id,attr"` + Width *uint64 `xml:"width,attr"` + Height *uint64 `xml:"height,attr"` + SAR *string `xml:"sar,attr"` + FrameRate *string `xml:"frameRate,attr"` + Bandwidth *uint64 `xml:"bandwidth,attr"` + AudioSamplingRate *string `xml:"audioSamplingRate,attr"` + Codecs *string `xml:"codecs,attr"` + BaseURL *string `xml:"BaseURL,omitempty"` + ContentProtections []DRMDescriptor `xml:"ContentProtection,omitempty"` + SegmentTemplate *SegmentTemplate `xml:"SegmentTemplate,omitempty"` + AudioChannelConfiguration *DescriptorType `xml:"AudioChannelConfiguration,omitempty"` } type representationMarshal struct { - ID *string `xml:"id,attr"` - Width *uint64 `xml:"width,attr"` - Height *uint64 `xml:"height,attr"` - SAR *string `xml:"sar,attr"` - FrameRate *string `xml:"frameRate,attr"` - Bandwidth *uint64 `xml:"bandwidth,attr"` - AudioSamplingRate *string `xml:"audioSamplingRate,attr"` - Codecs *string `xml:"codecs,attr"` - BaseURL *string `xml:"BaseURL,omitempty"` - ContentProtections []drmDescriptorMarshal `xml:"ContentProtection,omitempty"` - SegmentTemplate *SegmentTemplate `xml:"SegmentTemplate,omitempty"` - AudioChannelConfiguration *AudioChannelConfiguration `xml:"AudioChannelConfiguration,omitempty"` + ID *string `xml:"id,attr"` + Width *uint64 `xml:"width,attr"` + Height *uint64 `xml:"height,attr"` + SAR *string `xml:"sar,attr"` + FrameRate *string `xml:"frameRate,attr"` + Bandwidth *uint64 `xml:"bandwidth,attr"` + AudioSamplingRate *string `xml:"audioSamplingRate,attr"` + Codecs *string `xml:"codecs,attr"` + BaseURL *string `xml:"BaseURL,omitempty"` + ContentProtections []drmDescriptorMarshal `xml:"ContentProtection,omitempty"` + SegmentTemplate *SegmentTemplate `xml:"SegmentTemplate,omitempty"` + AudioChannelConfiguration *DescriptorType `xml:"AudioChannelConfiguration,omitempty"` } // Descriptor represents XSD's DescriptorType. @@ -363,6 +365,7 @@ func modifyAdaptationSets(as []*AdaptationSet) []*adaptationSetMarshal { MaxFrameRate: copyobj.String(a.MaxFrameRate), SubsegmentAlignment: a.SubsegmentAlignment, SubsegmentStartsWithSAP: copyobj.UInt64(a.SubsegmentStartsWithSAP), + Role: copyDescriptorType(a.Role), Representations: modifyRepresentations(a.Representations), ContentProtections: modifyContentProtections(a.ContentProtections), } @@ -386,20 +389,21 @@ func modifyRepresentations(rs []Representation) []representationMarshal { SAR: copyobj.String(r.SAR), ContentProtections: modifyContentProtections(r.ContentProtections), BaseURL: copyobj.String(r.BaseURL), - AudioChannelConfiguration: copyAudioChannelConfiguration(r.AudioChannelConfiguration), + AudioChannelConfiguration: copyDescriptorType(r.AudioChannelConfiguration), } rsm = append(rsm, representation) } return rsm } -func copyAudioChannelConfiguration(acc *AudioChannelConfiguration) *AudioChannelConfiguration { - if acc == nil { +func copyDescriptorType(dt *DescriptorType) *DescriptorType { + if dt == nil { return nil } - return &AudioChannelConfiguration{ - SchemeIDURI: copyobj.String(acc.SchemeIDURI), - Value: copyobj.String(acc.Value), + return &DescriptorType{ + SchemeIDURI: copyobj.String(dt.SchemeIDURI), + Value: copyobj.String(dt.Value), + ID: copyobj.String(dt.ID), } } @@ -459,8 +463,9 @@ func modifyPssh(p *Pssh) *psshMarshal { } } -// AudioChannelConfiguration represents XSD's AudioChannelConfiguration type. -type AudioChannelConfiguration struct { +// DescriptorType - used in many places to represent data. +type DescriptorType struct { SchemeIDURI *string `xml:"schemeIdUri,attr"` Value *string `xml:"value,attr,omitempty"` + ID *string `xml:"id,attr,omitempty"` } diff --git a/mpd_test.go b/mpd_test.go index 4bbefbf..419c5dc 100644 --- a/mpd_test.go +++ b/mpd_test.go @@ -82,7 +82,7 @@ func TestPeriodEqual(t *testing.T) { func TestAdaptationSetEqual(t *testing.T) { a := &AdaptationSet{} b := &adaptationSetMarshal{} - require.Equal(t, 17, reflect.ValueOf(a).Elem().NumField(), + require.Equal(t, 18, reflect.ValueOf(a).Elem().NumField(), "model was updated, need to update this test and function modifyAdaptationSets") require.Equal(t, reflect.ValueOf(a).Elem().NumField(), reflect.ValueOf(b).Elem().NumField(), "AdaptationSet element count not equal adaptationSetMarshal") From 530fb9807fb1e3260597caabf865fcdad7d74178 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torbjo=CC=88rn=20Einarsson?= Date: Tue, 23 Nov 2021 18:44:43 +0100 Subject: [PATCH 8/9] Add SegmentTemplate in AdaptationSet and order attribute before children --- mpd.go | 9 ++++++--- mpd_test.go | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/mpd.go b/mpd.go index 3e9cf0b..5d7e44c 100644 --- a/mpd.go +++ b/mpd.go @@ -178,14 +178,15 @@ type AdaptationSet struct { SubsegmentAlignment ConditionalUint `xml:"subsegmentAlignment,attr"` SubsegmentStartsWithSAP *uint64 `xml:"subsegmentStartsWithSAP,attr"` Lang *string `xml:"lang,attr"` - ContentProtections []DRMDescriptor `xml:"ContentProtection,omitempty"` Par *string `xml:"par,attr"` MinWidth *uint64 `xml:"minWidth,attr"` MaxWidth *uint64 `xml:"maxWidth,attr"` MinHeight *uint64 `xml:"minHeight,attr"` MaxHeight *uint64 `xml:"maxHeight,attr"` MaxFrameRate *string `xml:"maxFrameRate,attr"` + ContentProtections []DRMDescriptor `xml:"ContentProtection,omitempty"` Role *DescriptorType `xml:"Role,omitempty"` + SegmentTemplate *SegmentTemplate `xml:"SegmentTemplate,omitempty"` Representations []Representation `xml:"Representation,omitempty"` Codecs *string `xml:"codecs,attr"` } @@ -199,14 +200,15 @@ type adaptationSetMarshal struct { SubsegmentAlignment ConditionalUint `xml:"subsegmentAlignment,attr"` SubsegmentStartsWithSAP *uint64 `xml:"subsegmentStartsWithSAP,attr"` Lang *string `xml:"lang,attr"` - ContentProtections []drmDescriptorMarshal `xml:"ContentProtection,omitempty"` Par *string `xml:"par,attr"` MinWidth *uint64 `xml:"minWidth,attr"` MaxWidth *uint64 `xml:"maxWidth,attr"` MinHeight *uint64 `xml:"minHeight,attr"` MaxHeight *uint64 `xml:"maxHeight,attr"` MaxFrameRate *string `xml:"maxFrameRate,attr"` + ContentProtections []drmDescriptorMarshal `xml:"ContentProtection,omitempty"` Role *DescriptorType `xml:"Role,omitempty"` + SegmentTemplate *SegmentTemplate `xml:"SegmentTemplate,omitempty"` Representations []representationMarshal `xml:"Representation,omitempty"` Codecs *string `xml:"codecs,attr"` } @@ -365,9 +367,10 @@ func modifyAdaptationSets(as []*AdaptationSet) []*adaptationSetMarshal { MaxFrameRate: copyobj.String(a.MaxFrameRate), SubsegmentAlignment: a.SubsegmentAlignment, SubsegmentStartsWithSAP: copyobj.UInt64(a.SubsegmentStartsWithSAP), + ContentProtections: modifyContentProtections(a.ContentProtections), Role: copyDescriptorType(a.Role), + SegmentTemplate: copySegmentTemplate(a.SegmentTemplate), Representations: modifyRepresentations(a.Representations), - ContentProtections: modifyContentProtections(a.ContentProtections), } asm = append(asm, adaptationSet) } diff --git a/mpd_test.go b/mpd_test.go index 419c5dc..8bd6bab 100644 --- a/mpd_test.go +++ b/mpd_test.go @@ -82,7 +82,7 @@ func TestPeriodEqual(t *testing.T) { func TestAdaptationSetEqual(t *testing.T) { a := &AdaptationSet{} b := &adaptationSetMarshal{} - require.Equal(t, 18, reflect.ValueOf(a).Elem().NumField(), + require.Equal(t, 19, reflect.ValueOf(a).Elem().NumField(), "model was updated, need to update this test and function modifyAdaptationSets") require.Equal(t, reflect.ValueOf(a).Elem().NumField(), reflect.ValueOf(b).Elem().NumField(), "AdaptationSet element count not equal adaptationSetMarshal") From 859fd187ce9ad0f392249092491183110b92f387 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torbjo=CC=88rn=20Einarsson?= Date: Tue, 27 Oct 2020 13:31:54 +0100 Subject: [PATCH 9/9] New test content fixture_livesim_vod.mpd --- fixture_livesim_vod.mpd | 20 ++++++++++++++++++++ mpd_test.go | 6 ++++++ 2 files changed, 26 insertions(+) create mode 100644 fixture_livesim_vod.mpd diff --git a/fixture_livesim_vod.mpd b/fixture_livesim_vod.mpd new file mode 100644 index 0000000..4ccf620 --- /dev/null +++ b/fixture_livesim_vod.mpd @@ -0,0 +1,20 @@ + + + + Media Presentation Description from DASH-IF live simulator + + + + + + + + + + + + + + + + diff --git a/mpd_test.go b/mpd_test.go index 8bd6bab..0387cc0 100644 --- a/mpd_test.go +++ b/mpd_test.go @@ -1,6 +1,7 @@ package mpd import ( + "fmt" "io/ioutil" "reflect" "strings" @@ -17,6 +18,7 @@ type MPDSuite struct{} var _ = Suite(&MPDSuite{}) func testUnmarshalMarshal(c *C, name string) { + fmt.Println(name) expected, err := ioutil.ReadFile(name) c.Assert(err, IsNil) @@ -61,6 +63,10 @@ func (s *MPDSuite) TestUnmarshalMarshalVodBaseURL(c *C) { testUnmarshalMarshal(c, "fixture_vod_with_base_url.mpd") } +func (s *MPDSuite) TestUnmarshalMarshalLiveSimVod(c *C) { + testUnmarshalMarshal(c, "fixture_livesim_vod.mpd") +} + func TestMPDEqual(t *testing.T) { a := &MPD{} b := &mpdMarshal{}