diff --git a/go.mod b/go.mod
index d60a7c1..0d06d1f 100644
--- a/go.mod
+++ b/go.mod
@@ -1,3 +1,3 @@
module github.com/cbsinteractive/go-dash/v3
-go 1.16
+go 1.22
diff --git a/helpers/testfixtures/testfixtures.go b/helpers/testfixtures/testfixtures.go
index d00a071..d0368d3 100644
--- a/helpers/testfixtures/testfixtures.go
+++ b/helpers/testfixtures/testfixtures.go
@@ -2,7 +2,6 @@ package testfixtures
import (
"fmt"
- "io/ioutil"
"os"
"testing"
@@ -11,7 +10,7 @@ import (
// Load test fixture from path relative to fixtures directory
func LoadFixture(path string) (js string) {
- f, err := ioutil.ReadFile(path)
+ f, err := os.ReadFile(path)
if err != nil {
panic(fmt.Sprintf("LoadFixture Error. ioutil.ReadFile. path = %s, Err = %s", path, err.Error()))
}
@@ -22,8 +21,8 @@ func CompareFixture(t *testing.T, fixturePath string, actualContent string) {
t.Helper()
expectedContent := LoadFixture(fixturePath)
if os.Getenv("GENERATE_FIXTURES") != "" {
- _ = ioutil.WriteFile(fixturePath, []byte(actualContent), os.ModePerm)
- fmt.Println("Wrote fixture: " + fixturePath)
+ _ = os.WriteFile(fixturePath, []byte(actualContent), os.ModePerm)
+ fmt.Println("GEN FIXTURES - Wrote fixture: " + fixturePath)
return
}
require.EqualString(t, expectedContent, actualContent)
diff --git a/mpd/fixtures/ondemand_withdolby.mpd b/mpd/fixtures/ondemand_withdolby.mpd
new file mode 100644
index 0000000..7497836
--- /dev/null
+++ b/mpd/fixtures/ondemand_withdolby.mpd
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+ AAAAYXBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAAEEIARIQWr3VL1VKTyq40GH3YUJRVRoIY2FzdGxhYnMiGFdyM1ZMMVZLVHlxNDBHSDNZVUpSVlE9PTIHZGVmYXVsdA==
+
+
+ BgIAAAEAAQD8ATwAVwBSAE0ASABFAEEARABFAFIAIAB4AG0AbABuAHMAPQAiAGgAdAB0AHAAOgAvAC8AcwBjAGgAZQBtAGEAcwAuAG0AaQBjAHIAbwBzAG8AZgB0AC4AYwBvAG0ALwBEAFIATQAvADIAMAAwADcALwAwADMALwBQAGwAYQB5AFIAZQBhAGQAeQBIAGUAYQBkAGUAcgAiACAAdgBlAHIAcwBpAG8AbgA9ACIANAAuADAALgAwAC4AMAAiAD4APABEAEEAVABBAD4APABQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsARQBZAEwARQBOAD4AMQA2ADwALwBLAEUAWQBMAEUATgA+ADwAQQBMAEcASQBEAD4AQQBFAFMAQwBUAFIAPAAvAEEATABHAEkARAA+ADwALwBQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsASQBEAD4ATAA5AFcAOQBXAGsAcABWAEsAawArADQAMABHAEgAMwBZAFUASgBSAFYAUQA9AD0APAAvAEsASQBEAD4APABDAEgARQBDAEsAUwBVAE0APgBJAEsAegBZADIASABaAEwAQQBsAEkAPQA8AC8AQwBIAEUAQwBLAFMAVQBNAD4APAAvAEQAQQBUAEEAPgA8AC8AVwBSAE0ASABFAEEARABFAFIAPgA=
+ AAACJnBzc2gAAAAAmgTweZhAQoarkuZb4IhflQAAAgYGAgAAAQABAPwBPABXAFIATQBIAEUAQQBEAEUAUgAgAHgAbQBsAG4AcwA9ACIAaAB0AHQAcAA6AC8ALwBzAGMAaABlAG0AYQBzAC4AbQBpAGMAcgBvAHMAbwBmAHQALgBjAG8AbQAvAEQAUgBNAC8AMgAwADAANwAvADAAMwAvAFAAbABhAHkAUgBlAGEAZAB5AEgAZQBhAGQAZQByACIAIAB2AGUAcgBzAGkAbwBuAD0AIgA0AC4AMAAuADAALgAwACIAPgA8AEQAQQBUAEEAPgA8AFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBFAFkATABFAE4APgAxADYAPAAvAEsARQBZAEwARQBOAD4APABBAEwARwBJAEQAPgBBAEUAUwBDAFQAUgA8AC8AQQBMAEcASQBEAD4APAAvAFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBJAEQAPgBMADkAVwA5AFcAawBwAFYASwBrACsANAAwAEcASAAzAFkAVQBKAFIAVgBRAD0APQA8AC8ASwBJAEQAPgA8AEMASABFAEMASwBTAFUATQA+AEkASwB6AFkAMgBIAFoATABBAGwASQA9ADwALwBDAEgARQBDAEsAUwBVAE0APgA8AC8ARABBAFQAQQA+ADwALwBXAFIATQBIAEUAQQBEAEUAUgA+AA==
+
+
+
+ 800k/output-audio-en-US.mp4
+
+
+
+
+
+
+
+
+
+ AAAAYXBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAAEEIARIQWr3VL1VKTyq40GH3YUJRVRoIY2FzdGxhYnMiGFdyM1ZMMVZLVHlxNDBHSDNZVUpSVlE9PTIHZGVmYXVsdA==
+
+
+ BgIAAAEAAQD8ATwAVwBSAE0ASABFAEEARABFAFIAIAB4AG0AbABuAHMAPQAiAGgAdAB0AHAAOgAvAC8AcwBjAGgAZQBtAGEAcwAuAG0AaQBjAHIAbwBzAG8AZgB0AC4AYwBvAG0ALwBEAFIATQAvADIAMAAwADcALwAwADMALwBQAGwAYQB5AFIAZQBhAGQAeQBIAGUAYQBkAGUAcgAiACAAdgBlAHIAcwBpAG8AbgA9ACIANAAuADAALgAwAC4AMAAiAD4APABEAEEAVABBAD4APABQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsARQBZAEwARQBOAD4AMQA2ADwALwBLAEUAWQBMAEUATgA+ADwAQQBMAEcASQBEAD4AQQBFAFMAQwBUAFIAPAAvAEEATABHAEkARAA+ADwALwBQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsASQBEAD4ATAA5AFcAOQBXAGsAcABWAEsAawArADQAMABHAEgAMwBZAFUASgBSAFYAUQA9AD0APAAvAEsASQBEAD4APABDAEgARQBDAEsAUwBVAE0APgBJAEsAegBZADIASABaAEwAQQBsAEkAPQA8AC8AQwBIAEUAQwBLAFMAVQBNAD4APAAvAEQAQQBUAEEAPgA8AC8AVwBSAE0ASABFAEEARABFAFIAPgA=
+ AAACJnBzc2gAAAAAmgTweZhAQoarkuZb4IhflQAAAgYGAgAAAQABAPwBPABXAFIATQBIAEUAQQBEAEUAUgAgAHgAbQBsAG4AcwA9ACIAaAB0AHQAcAA6AC8ALwBzAGMAaABlAG0AYQBzAC4AbQBpAGMAcgBvAHMAbwBmAHQALgBjAG8AbQAvAEQAUgBNAC8AMgAwADAANwAvADAAMwAvAFAAbABhAHkAUgBlAGEAZAB5AEgAZQBhAGQAZQByACIAIAB2AGUAcgBzAGkAbwBuAD0AIgA0AC4AMAAuADAALgAwACIAPgA8AEQAQQBUAEEAPgA8AFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBFAFkATABFAE4APgAxADYAPAAvAEsARQBZAEwARQBOAD4APABBAEwARwBJAEQAPgBBAEUAUwBDAFQAUgA8AC8AQQBMAEcASQBEAD4APAAvAFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBJAEQAPgBMADkAVwA5AFcAawBwAFYASwBrACsANAAwAEcASAAzAFkAVQBKAFIAVgBRAD0APQA8AC8ASwBJAEQAPgA8AEMASABFAEMASwBTAFUATQA+AEkASwB6AFkAMgBIAFoATABBAGwASQA9ADwALwBDAEgARQBDAEsAUwBVAE0APgA8AC8ARABBAFQAQQA+ADwALwBXAFIATQBIAEUAQQBEAEUAUgA+AA==
+
+
+
+ 800k/output-audio-AD-en-US.mp4
+
+
+
+
+
+
+
+
+
+
+ AAAAYXBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAAEEIARIQWr3VL1VKTyq40GH3YUJRVRoIY2FzdGxhYnMiGFdyM1ZMMVZLVHlxNDBHSDNZVUpSVlE9PTIHZGVmYXVsdA==
+
+
+ BgIAAAEAAQD8ATwAVwBSAE0ASABFAEEARABFAFIAIAB4AG0AbABuAHMAPQAiAGgAdAB0AHAAOgAvAC8AcwBjAGgAZQBtAGEAcwAuAG0AaQBjAHIAbwBzAG8AZgB0AC4AYwBvAG0ALwBEAFIATQAvADIAMAAwADcALwAwADMALwBQAGwAYQB5AFIAZQBhAGQAeQBIAGUAYQBkAGUAcgAiACAAdgBlAHIAcwBpAG8AbgA9ACIANAAuADAALgAwAC4AMAAiAD4APABEAEEAVABBAD4APABQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsARQBZAEwARQBOAD4AMQA2ADwALwBLAEUAWQBMAEUATgA+ADwAQQBMAEcASQBEAD4AQQBFAFMAQwBUAFIAPAAvAEEATABHAEkARAA+ADwALwBQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsASQBEAD4ATAA5AFcAOQBXAGsAcABWAEsAawArADQAMABHAEgAMwBZAFUASgBSAFYAUQA9AD0APAAvAEsASQBEAD4APABDAEgARQBDAEsAUwBVAE0APgBJAEsAegBZADIASABaAEwAQQBsAEkAPQA8AC8AQwBIAEUAQwBLAFMAVQBNAD4APAAvAEQAQQBUAEEAPgA8AC8AVwBSAE0ASABFAEEARABFAFIAPgA=
+ AAACJnBzc2gAAAAAmgTweZhAQoarkuZb4IhflQAAAgYGAgAAAQABAPwBPABXAFIATQBIAEUAQQBEAEUAUgAgAHgAbQBsAG4AcwA9ACIAaAB0AHQAcAA6AC8ALwBzAGMAaABlAG0AYQBzAC4AbQBpAGMAcgBvAHMAbwBmAHQALgBjAG8AbQAvAEQAUgBNAC8AMgAwADAANwAvADAAMwAvAFAAbABhAHkAUgBlAGEAZAB5AEgAZQBhAGQAZQByACIAIAB2AGUAcgBzAGkAbwBuAD0AIgA0AC4AMAAuADAALgAwACIAPgA8AEQAQQBUAEEAPgA8AFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBFAFkATABFAE4APgAxADYAPAAvAEsARQBZAEwARQBOAD4APABBAEwARwBJAEQAPgBBAEUAUwBDAFQAUgA8AC8AQQBMAEcASQBEAD4APAAvAFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBJAEQAPgBMADkAVwA5AFcAawBwAFYASwBrACsANAAwAEcASAAzAFkAVQBKAFIAVgBRAD0APQA8AC8ASwBJAEQAPgA8AEMASABFAEMASwBTAFUATQA+AEkASwB6AFkAMgBIAFoATABBAGwASQA9ADwALwBDAEgARQBDAEsAUwBVAE0APgA8AC8ARABBAFQAQQA+ADwALwBXAFIATQBIAEUAQQBEAEUAUgA+AA==
+
+
+
+ 800k/output-video-1.mp4
+
+
+
+
+
+ 1200k/output-video-1.mp4
+
+
+
+
+
+
+
+
+ AAAAYXBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAAEEIARIQWr3VL1VKTyq40GH3YUJRVRoIY2FzdGxhYnMiGFdyM1ZMMVZLVHlxNDBHSDNZVUpSVlE9PTIHZGVmYXVsdA==
+
+
+ BgIAAAEAAQD8ATwAVwBSAE0ASABFAEEARABFAFIAIAB4AG0AbABuAHMAPQAiAGgAdAB0AHAAOgAvAC8AcwBjAGgAZQBtAGEAcwAuAG0AaQBjAHIAbwBzAG8AZgB0AC4AYwBvAG0ALwBEAFIATQAvADIAMAAwADcALwAwADMALwBQAGwAYQB5AFIAZQBhAGQAeQBIAGUAYQBkAGUAcgAiACAAdgBlAHIAcwBpAG8AbgA9ACIANAAuADAALgAwAC4AMAAiAD4APABEAEEAVABBAD4APABQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsARQBZAEwARQBOAD4AMQA2ADwALwBLAEUAWQBMAEUATgA+ADwAQQBMAEcASQBEAD4AQQBFAFMAQwBUAFIAPAAvAEEATABHAEkARAA+ADwALwBQAFIATwBUAEUAQwBUAEkATgBGAE8APgA8AEsASQBEAD4ATAA5AFcAOQBXAGsAcABWAEsAawArADQAMABHAEgAMwBZAFUASgBSAFYAUQA9AD0APAAvAEsASQBEAD4APABDAEgARQBDAEsAUwBVAE0APgBJAEsAegBZADIASABaAEwAQQBsAEkAPQA8AC8AQwBIAEUAQwBLAFMAVQBNAD4APAAvAEQAQQBUAEEAPgA8AC8AVwBSAE0ASABFAEEARABFAFIAPgA=
+ AAACJnBzc2gAAAAAmgTweZhAQoarkuZb4IhflQAAAgYGAgAAAQABAPwBPABXAFIATQBIAEUAQQBEAEUAUgAgAHgAbQBsAG4AcwA9ACIAaAB0AHQAcAA6AC8ALwBzAGMAaABlAG0AYQBzAC4AbQBpAGMAcgBvAHMAbwBmAHQALgBjAG8AbQAvAEQAUgBNAC8AMgAwADAANwAvADAAMwAvAFAAbABhAHkAUgBlAGEAZAB5AEgAZQBhAGQAZQByACIAIAB2AGUAcgBzAGkAbwBuAD0AIgA0AC4AMAAuADAALgAwACIAPgA8AEQAQQBUAEEAPgA8AFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBFAFkATABFAE4APgAxADYAPAAvAEsARQBZAEwARQBOAD4APABBAEwARwBJAEQAPgBBAEUAUwBDAFQAUgA8AC8AQQBMAEcASQBEAD4APAAvAFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBJAEQAPgBMADkAVwA5AFcAawBwAFYASwBrACsANAAwAEcASAAzAFkAVQBKAFIAVgBRAD0APQA8AC8ASwBJAEQAPgA8AEMASABFAEMASwBTAFUATQA+AEkASwB6AFkAMgBIAFoATABBAGwASQA9ADwALwBDAEgARQBDAEsAUwBVAE0APgA8AC8ARABBAFQAQQA+ADwALwBXAFIATQBIAEUAQQBEAEUAUgA+AA==
+
+
+
+ 800k/output-video-1.mp4
+
+
+
+
+
+ 1200k/output-video-1.mp4
+
+
+
+
+
+
+
+
+
+ http://example.com/content/sintel/subtitles/subtitles_en.vtt
+
+
+
+
diff --git a/mpd/mpd.go b/mpd/mpd.go
index ccea914..2efb925 100644
--- a/mpd/mpd.go
+++ b/mpd/mpd.go
@@ -72,7 +72,8 @@ var (
type MPD struct {
XMLNs *string `xml:"xmlns,attr"`
- XMLNsDolby *string `xml:"xmlns:dolby,attr"`
+ XMLNsDolby *XmlnsAttr `xml:"dolby,attr"`
+ XMLNsSCTE214 *XmlnsAttr `xml:"scte214,attr"`
Scte35NS *Scte35NS `xml:"scte35,attr,omitempty"`
XsiNS *XmlnsAttr `xml:"xsi,attr,omitempty"`
XsiSchemaLocation *XsiSL `xml:"schemaLocation,attr,omitempty"`
@@ -108,9 +109,27 @@ func (s *XmlnsAttr) UnmarshalXMLAttr(attr xml.Attr) error {
}
func (s *XmlnsAttr) MarshalXMLAttr(name xml.Name) (xml.Attr, error) {
+ if s == nil {
+ return xml.Attr{}, nil
+ }
return xml.Attr{Name: xml.Name{Local: fmt.Sprintf("xmlns:%s", s.XmlName.Local)}, Value: s.Value}, nil
}
+type Scte214Attr struct {
+ XmlName xml.Name
+ Value string
+}
+
+func (s *Scte214Attr) UnmarshalXMLAttr(attr xml.Attr) error {
+ s.XmlName = attr.Name
+ s.Value = attr.Value
+ return nil
+}
+
+func (s *Scte214Attr) MarshalXMLAttr(name xml.Name) (xml.Attr, error) {
+ return xml.Attr{Name: xml.Name{Local: fmt.Sprintf("scte214:%s", s.XmlName.Local)}, Value: s.Value}, nil
+}
+
type XsiSL struct {
XmlName xml.Name
Value string
@@ -246,9 +265,17 @@ func (as *AdaptationSet) UnmarshalXML(d *xml.Decoder, start xml.StartElement) er
return err
}
*as = AdaptationSet(n.wrappedAdaptationSet)
+
+ if as.Roles != nil {
+ as.Roles = n.Roles
+ }
+
as.ContentProtection = make([]ContentProtectioner, len(n.ContentProtection))
- for i := range n.ContentProtection {
- as.ContentProtection[i] = n.ContentProtection[i]
+ copy(as.ContentProtection, n.ContentProtection)
+
+ for i := range as.Representations {
+ as.Representations[i].SupplementalCodecs = n.Representations[i].SupplementalCodecs
+ as.Representations[i].SupplementalProfiles = n.Representations[i].SupplementalProfiles
}
return nil
}
@@ -434,15 +461,17 @@ type Representation struct {
CommonAttributesAndElements
AdaptationSet *AdaptationSet `xml:"-"`
AudioChannelConfiguration *AudioChannelConfiguration `xml:"AudioChannelConfiguration,omitempty"`
- AudioSamplingRate *int64 `xml:"audioSamplingRate,attr"` // Audio
- Bandwidth *int64 `xml:"bandwidth,attr"` // Audio + Video
- Codecs *string `xml:"codecs,attr"` // Audio + Video
- FrameRate *string `xml:"frameRate,attr,omitempty"` // Video
- Height *int64 `xml:"height,attr"` // Video
- ID *string `xml:"id,attr"` // Audio + Video
- Width *int64 `xml:"width,attr"` // Video
- BaseURL []string `xml:"BaseURL,omitempty"` // On-Demand Profile
- SegmentBase *SegmentBase `xml:"SegmentBase,omitempty"` // On-Demand Profile
+ AudioSamplingRate *int64 `xml:"audioSamplingRate,attr"` // Audio
+ Bandwidth *int64 `xml:"bandwidth,attr"` // Audio + Video
+ Codecs *string `xml:"codecs,attr"` // Audio + Video
+ SupplementalCodecs *Scte214Attr `xml:"supplementalCodecs,attr,omitempty"` // Video
+ SupplementalProfiles *Scte214Attr `xml:"supplementalProfiles,attr,omitempty"` // Video
+ FrameRate *string `xml:"frameRate,attr,omitempty"` // Video
+ Height *int64 `xml:"height,attr"` // Video
+ ID *string `xml:"id,attr"` // Audio + Video
+ Width *int64 `xml:"width,attr"` // Video
+ BaseURL []string `xml:"BaseURL,omitempty"` // On-Demand Profile
+ SegmentBase *SegmentBase `xml:"SegmentBase,omitempty"` // On-Demand Profile
SegmentList *SegmentList `xml:"SegmentList,omitempty"`
SegmentTemplate *SegmentTemplate `xml:"SegmentTemplate,omitempty"`
}
@@ -460,7 +489,17 @@ type AudioChannelConfiguration struct {
}
func (m *MPD) SetDolbyXMLNs() {
- m.XMLNsDolby = Strptr("http://www.dolby.com/ns/online/DASH")
+ m.XMLNsDolby = &XmlnsAttr{
+ XmlName: xml.Name{Space: "xmlns", Local: "dolby"},
+ Value: "http://www.dolby.com/ns/online/DASH",
+ }
+}
+
+func (m *MPD) SetScte214XMLNs() {
+ m.XMLNsSCTE214 = &XmlnsAttr{
+ XmlName: xml.Name{Space: "xmlns", Local: "scte214"},
+ Value: "urn:scte:dash:scte214-extensions",
+ }
}
// Creates a new static MPD object.
@@ -1114,6 +1153,30 @@ func (as *AdaptationSet) AddNewRepresentationVideo(bandwidth int64, codecs strin
return r, nil
}
+// Adds supplementalCodecs and supplementalProfiles to a Representation
+// supplementalCodecs - scte214:supplementalCodecs attribute for Dovi 8.1 signaling (optional).
+// supplementalProfiles - scte214:supplementalProfiles attribute for Dovi 8.1 signaling (optional).
+func (r *Representation) AddScte214VideoCodecProperties(supplementalCodecs string, supplementalProfiles string) (*Representation, error) {
+ // For Dovi 8.1 signaling both supplementalCodecs and supplementalProfiles should be added
+ if len(supplementalCodecs) > 0 && len(supplementalProfiles) > 0 {
+ r.SupplementalCodecs = &Scte214Attr{
+ XmlName: xml.Name{
+ Space: "scte214",
+ Local: "supplementalCodecs",
+ },
+ Value: supplementalCodecs,
+ }
+ r.SupplementalProfiles = &Scte214Attr{
+ XmlName: xml.Name{
+ Space: "scte214",
+ Local: "supplementalProfiles",
+ },
+ Value: supplementalProfiles,
+ }
+ }
+ return r, nil
+}
+
// Adds a new Subtitle representation to an AdaptationSet.
// bandwidth - in Bits/s (i.e. 256).
// id - ID for this representation, will get used as $RepresentationID$ in template strings.
diff --git a/mpd/mpd_read_write_test.go b/mpd/mpd_read_write_test.go
index 6934faf..92d3a17 100644
--- a/mpd/mpd_read_write_test.go
+++ b/mpd/mpd_read_write_test.go
@@ -123,6 +123,21 @@ func TestNewMPDOnDemandWriteToString(t *testing.T) {
require.EqualString(t, expectedXML, xmlStr)
}
+func TestNewMPDOnDemandwithDolbyWriteToString(t *testing.T) {
+ m := NewMPD(DASH_PROFILE_ONDEMAND, VALID_MEDIA_PRESENTATION_DURATION, VALID_MIN_BUFFER_TIME)
+ m.SetDolbyXMLNs()
+ m.SetScte214XMLNs()
+
+ xmlStr, err := m.WriteToString()
+ require.NoError(t, err)
+ expectedXML := `
+
+
+
+`
+ require.EqualString(t, expectedXML, xmlStr)
+}
+
func TestAddNewAdaptationSetAudioWriteToString(t *testing.T) {
m := NewMPD(DASH_PROFILE_LIVE, VALID_MEDIA_PRESENTATION_DURATION, VALID_MIN_BUFFER_TIME)
@@ -519,3 +534,96 @@ func TestWriteComment(t *testing.T) {
`
require.EqualString(t, answer, s)
}
+
+func OnDemandProfileWithDolby() *MPD {
+ m := NewMPD(DASH_PROFILE_ONDEMAND, "PT30S", VALID_MIN_BUFFER_TIME)
+ m.SetDolbyXMLNs()
+ m.SetScte214XMLNs()
+
+ // Main audio adaptation set
+ audioAS, _ := m.AddNewAdaptationSetAudioWithID("1", DASH_MIME_TYPE_AUDIO_MP4, VALID_SEGMENT_ALIGNMENT, VALID_START_WITH_SAP, "en-US")
+ _, _ = audioAS.AddNewRole("urn:mpeg:dash:role:2011", "main")
+
+ _, _ = audioAS.AddNewContentProtectionRoot("08e367028f33436ca5dd60ffe5571e60")
+ _, _ = audioAS.AddNewContentProtectionSchemeWidevineWithPSSH(getValidWVHeaderBytes())
+ _, _ = audioAS.AddNewContentProtectionSchemePlayreadyWithPSSH(VALID_PLAYREADY_PRO)
+ _, _ = audioAS.AddNewAccessibilityElement(ACCESSIBILITY_ELEMENT_SCHEME_DESCRIPTIVE_AUDIO, "1")
+
+ audioRep, _ := audioAS.AddNewRepresentationAudio(44100, 128558, "mp4a.40.5", "800k/audio-en-US")
+ _ = audioRep.SetNewBaseURL("800k/output-audio-en-US.mp4")
+ _, _ = audioRep.AddNewSegmentBase("629-756", "0-628")
+
+ // audio description adaptation set
+ audioAD, _ := m.AddNewAdaptationSetAudioWithID("2", DASH_MIME_TYPE_AUDIO_MP4, VALID_SEGMENT_ALIGNMENT, VALID_START_WITH_SAP, "en-US")
+ _, _ = audioAD.AddNewRole("urn:mpeg:dash:role:2011", "description")
+ _, _ = audioAD.AddNewAccessibilityElement(ACCESSIBILITY_ELEMENT_SCHEME_DESCRIPTIVE_AUDIO, "1")
+
+ _, _ = audioAD.AddNewContentProtectionRoot("08e367028f33436ca5dd60ffe5571e60")
+ _, _ = audioAD.AddNewContentProtectionSchemeWidevineWithPSSH(getValidWVHeaderBytes())
+ _, _ = audioAD.AddNewContentProtectionSchemePlayreadyWithPSSH(VALID_PLAYREADY_PRO)
+ _, _ = audioAD.AddNewAccessibilityElement(ACCESSIBILITY_ELEMENT_SCHEME_DESCRIPTIVE_AUDIO, "1")
+
+ audioADRep, _ := audioAD.AddNewRepresentationAudio(44100, 128558, "mp4a.40.5", "800k/audio-AD-en-US")
+ _ = audioADRep.SetNewBaseURL("800k/output-audio-AD-en-US.mp4")
+ _, _ = audioADRep.AddNewSegmentBase("629-756", "0-628")
+
+ // video avc adaptation set
+ videoAS, _ := m.AddNewAdaptationSetVideoWithID("3", DASH_MIME_TYPE_VIDEO_MP4, VALID_SCAN_TYPE, VALID_SEGMENT_ALIGNMENT, VALID_START_WITH_SAP)
+ _, _ = videoAS.AddNewRole("urn:mpeg:dash:role:2011", "main")
+
+ _, _ = videoAS.AddNewContentProtectionRoot("08e367028f33436ca5dd60ffe5571e60")
+ _, _ = videoAS.AddNewContentProtectionSchemeWidevineWithPSSH(getValidWVHeaderBytes())
+ _, _ = videoAS.AddNewContentProtectionSchemePlayreadyWithPSSH(VALID_PLAYREADY_PRO)
+
+ videoRep1, _ := videoAS.AddNewRepresentationVideo(1100690, "avc1.4d401e", "800k/video-1", "30000/1001", 640, 360)
+ _ = videoRep1.SetNewBaseURL("800k/output-video-1.mp4")
+ _, _ = videoRep1.AddNewSegmentBase("686-813", "0-685")
+
+ videoRep2, _ := videoAS.AddNewRepresentationVideo(1633516, "avc1.4d401f", "1200k/video-1", "30000/1001", 960, 540)
+ _ = videoRep2.SetNewBaseURL("1200k/output-video-1.mp4")
+ _, _ = videoRep2.AddNewSegmentBase("686-813", "0-685")
+
+ // video hevc adaptation set with Dolby Vision signaling
+ videoAS1, _ := m.AddNewAdaptationSetVideoWithID("4", DASH_MIME_TYPE_VIDEO_MP4, VALID_SCAN_TYPE, VALID_SEGMENT_ALIGNMENT, VALID_START_WITH_SAP)
+ _, _ = videoAS1.AddNewRole("urn:mpeg:dash:role:2011", "main")
+
+ _, _ = videoAS1.AddNewContentProtectionRoot("08e367028f33436ca5dd60ffe5571e60")
+ _, _ = videoAS1.AddNewContentProtectionSchemeWidevineWithPSSH(getValidWVHeaderBytes())
+ _, _ = videoAS1.AddNewContentProtectionSchemePlayreadyWithPSSH(VALID_PLAYREADY_PRO)
+
+ videoRep3, _ := videoAS1.AddNewRepresentationVideo(1100690, "hev1.2.4.L63.90", "800k/video-1", "30000/1001", 640, 360)
+ _, _ = videoRep3.AddScte214VideoCodecProperties("dvhe.08.07", "db1p")
+ _ = videoRep3.SetNewBaseURL("800k/output-video-1.mp4")
+ _, _ = videoRep3.AddNewSegmentBase("686-813", "0-685")
+
+ videoRep4, _ := videoAS1.AddNewRepresentationVideo(1633516, "hev1.2.4.L93.90", "1200k/video-1", "30000/1001", 960, 540)
+ _, _ = videoRep4.AddScte214VideoCodecProperties("dvhe.08.07", "db4h")
+ _ = videoRep4.SetNewBaseURL("1200k/output-video-1.mp4")
+ _, _ = videoRep4.AddNewSegmentBase("686-813", "0-685")
+
+ // subtitle adaptation set
+ subtitleAS, _ := m.AddNewAdaptationSetSubtitleWithID("5", DASH_MIME_TYPE_SUBTITLE_VTT, VALID_LANG, VALID_SUBTITLE_LABEL)
+ _, _ = subtitleAS.AddNewRole("urn:mpeg:dash:role:2011", "subtitle")
+ subtitleRep, _ := subtitleAS.AddNewRepresentationSubtitle(VALID_SUBTITLE_BANDWIDTH, VALID_SUBTITLE_ID)
+ _ = subtitleRep.SetNewBaseURL(VALID_SUBTITLE_URL)
+
+ return m
+}
+
+func TestOnDemandProfileWithDolbyWriteToString(t *testing.T) {
+ m := OnDemandProfileWithDolby()
+ require.NotNil(t, m)
+ xmlStr, err := m.WriteToString()
+ require.NoError(t, err)
+ testfixtures.CompareFixture(t, "fixtures/ondemand_withdolby.mpd", xmlStr)
+}
+
+func TestOnDemandProfileWithDolbyWriteToFile(t *testing.T) {
+ m := OnDemandProfileWithDolby()
+ require.NotNil(t, m)
+ err := m.WriteToFile("test-withdolby-ondemand.mpd")
+ xmlStr := testfixtures.LoadFixture("test-withdolby-ondemand.mpd")
+ testfixtures.CompareFixture(t, "fixtures/ondemand_withdolby.mpd", xmlStr)
+ defer os.Remove("test-withdolby-ondemand.mpd")
+ require.NoError(t, err)
+}
diff --git a/mpd/mpd_test.go b/mpd/mpd_test.go
index 39d4146..9343cfa 100644
--- a/mpd/mpd_test.go
+++ b/mpd/mpd_test.go
@@ -2,6 +2,7 @@ package mpd
import (
"encoding/base64"
+ "encoding/xml"
"path/filepath"
"strconv"
"testing"
@@ -243,6 +244,38 @@ func TestNewMPDOnDemand(t *testing.T) {
require.EqualString(t, expectedString, actualString)
}
+func TestNewMPDOnDemandWithDolby(t *testing.T) {
+ m := NewMPD(DASH_PROFILE_ONDEMAND, VALID_MEDIA_PRESENTATION_DURATION, VALID_MIN_BUFFER_TIME)
+ m.SetDolbyXMLNs()
+ m.SetScte214XMLNs()
+
+ require.NotNil(t, m)
+ expectedMPD := &MPD{
+ XMLNs: Strptr("urn:mpeg:dash:schema:mpd:2011"),
+ XMLNsDolby: &XmlnsAttr{
+ XmlName: xml.Name{Space: "xmlns", Local: "dolby"},
+ Value: "http://www.dolby.com/ns/online/DASH",
+ },
+ XMLNsSCTE214: &XmlnsAttr{
+ XmlName: xml.Name{Space: "xmlns", Local: "scte214"},
+ Value: "urn:scte:dash:scte214-extensions",
+ },
+ Profiles: Strptr((string)(DASH_PROFILE_ONDEMAND)),
+ Type: Strptr("static"),
+ MediaPresentationDuration: Strptr(VALID_MEDIA_PRESENTATION_DURATION),
+ MinBufferTime: Strptr(VALID_MIN_BUFFER_TIME),
+ period: &Period{},
+ Periods: []*Period{{}},
+ }
+
+ expectedString, err := expectedMPD.WriteToString()
+ require.NoError(t, err)
+ actualString, err := m.WriteToString()
+ require.NoError(t, err)
+
+ require.EqualString(t, expectedString, actualString)
+}
+
func TestAddAdaptationSetErrorNil(t *testing.T) {
m := NewMPD(DASH_PROFILE_LIVE, VALID_MEDIA_PRESENTATION_DURATION, VALID_MIN_BUFFER_TIME)