diff --git a/.gitignore b/.gitignore
index 5e184a6..e3ef4f3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,4 @@ vendor/
.idea/
\#*
*~
+.DS_Store
diff --git a/go.mod b/go.mod
index da472a9..dad688c 100644
--- a/go.mod
+++ b/go.mod
@@ -1,3 +1,3 @@
module github.com/zencoder/go-dash/v3
-go 1.13
+go 1.22
diff --git a/mpd/fixtures/ondemand_withdolby.mpd b/mpd/fixtures/ondemand_withdolby.mpd
new file mode 100644
index 0000000..7eca4a1
--- /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 9972443..d328c41 100644
--- a/mpd/mpd.go
+++ b/mpd/mpd.go
@@ -5,6 +5,7 @@ import (
"encoding/hex"
"encoding/xml"
"errors"
+ "fmt"
"strings"
"time"
@@ -70,24 +71,58 @@ var (
)
type MPD struct {
- XMLNs *string `xml:"xmlns,attr"`
- XMLNsDolby *string `xml:"xmlns:dolby,attr"`
- Profiles *string `xml:"profiles,attr"`
- Type *string `xml:"type,attr"`
- MediaPresentationDuration *string `xml:"mediaPresentationDuration,attr"`
- MinBufferTime *string `xml:"minBufferTime,attr"`
- AvailabilityStartTime *string `xml:"availabilityStartTime,attr,omitempty"`
- MinimumUpdatePeriod *string `xml:"minimumUpdatePeriod,attr"`
- PublishTime *string `xml:"publishTime,attr"`
- TimeShiftBufferDepth *string `xml:"timeShiftBufferDepth,attr"`
- SuggestedPresentationDelay *Duration `xml:"suggestedPresentationDelay,attr,omitempty"`
- BaseURL []string `xml:"BaseURL,omitempty"`
- Location string `xml:"Location,omitempty"`
+ XMLNs *string `xml:"xmlns,attr"`
+ XMLNsDolby *XmlnsAttr `xml:"dolby,attr"`
+ XMLNsSCTE214 *XmlnsAttr `xml:"scte214,attr"`
+ Profiles *string `xml:"profiles,attr"`
+ Type *string `xml:"type,attr"`
+ MediaPresentationDuration *string `xml:"mediaPresentationDuration,attr"`
+ MinBufferTime *string `xml:"minBufferTime,attr"`
+ AvailabilityStartTime *string `xml:"availabilityStartTime,attr,omitempty"`
+ MinimumUpdatePeriod *string `xml:"minimumUpdatePeriod,attr"`
+ PublishTime *string `xml:"publishTime,attr"`
+ TimeShiftBufferDepth *string `xml:"timeShiftBufferDepth,attr"`
+ SuggestedPresentationDelay *Duration `xml:"suggestedPresentationDelay,attr,omitempty"`
+ BaseURL []string `xml:"BaseURL,omitempty"`
+ Location string `xml:"Location,omitempty"`
period *Period
Periods []*Period `xml:"Period,omitempty"`
UTCTiming *DescriptorType `xml:"UTCTiming,omitempty"`
}
+type XmlnsAttr struct {
+ XmlName xml.Name
+ Value string
+}
+
+func (s *XmlnsAttr) UnmarshalXMLAttr(attr xml.Attr) error {
+ s.XmlName = attr.Name
+ s.Value = attr.Value
+ return nil
+}
+
+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 Period struct {
ID string `xml:"id,attr,omitempty"`
Duration Duration `xml:"duration,attr,omitempty"`
@@ -200,10 +235,9 @@ func (as *AdaptationSet) UnmarshalXML(d *xml.Decoder, start xml.StartElement) er
return err
}
*as = AdaptationSet(n.wrappedAdaptationSet)
+
as.ContentProtection = make([]ContentProtectioner, len(n.ContentProtection))
- for i := range n.ContentProtection {
- as.ContentProtection[i] = n.ContentProtection[i]
- }
+ copy(as.ContentProtection, n.ContentProtection)
return nil
}
@@ -369,15 +403,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"`
}
@@ -395,7 +431,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.
@@ -1049,6 +1095,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 80981b3..379414e 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)
@@ -500,3 +515,96 @@ func TestWriteToFileTruncate(t *testing.T) {
xmlStr = testfixtures.LoadFixture(out)
testfixtures.CompareFixture(t, "fixtures/truncate_short.mpd", xmlStr)
}
+
+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 19ab6c1..8fd3dc6 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)