Skip to content

Commit 8101305

Browse files
authored
Merge branch 'master' into suggestedPresentationDelay
2 parents 5fd38ad + 2358130 commit 8101305

File tree

7 files changed

+114
-1
lines changed

7 files changed

+114
-1
lines changed

mpd/fixtures/hbbtv_profile.mpd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
<Representation audioSamplingRate="44100" bandwidth="67095" codecs="mp4a.40.2" id="800">
1616
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"></AudioChannelConfiguration>
1717
</Representation>
18+
<Accessibility schemeIdUri="urn:tva:metadata:cs:AudioPurposeCS:2007" value="1"></Accessibility>
1819
</AdaptationSet>
1920
<AdaptationSet mimeType="video/mp4" startWithSAP="1" scanType="progressive" id="7357" segmentAlignment="true">
2021
<ContentProtection schemeIdUri="urn:mpeg:dash:mp4protection:2011" xmlns:cenc="urn:mpeg:cenc:2013" cenc:default_KID="08e36702-8f33-436c-a5dd-60ffe5571e60" value="cenc"></ContentProtection>

mpd/fixtures/live_profile.mpd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
<Role schemeIdUri="urn:mpeg:dash:role:2011" value="main"></Role>
1414
<SegmentTemplate duration="1968" initialization="$RepresentationID$/audio/en/init.mp4" media="$RepresentationID$/audio/en/seg-$Number$.m4f" startNumber="0" timescale="1000"></SegmentTemplate>
1515
<Representation audioSamplingRate="44100" bandwidth="67095" codecs="mp4a.40.2" id="800"></Representation>
16+
<Accessibility schemeIdUri="urn:tva:metadata:cs:AudioPurposeCS:2007" value="1"></Accessibility>
1617
</AdaptationSet>
1718
<AdaptationSet mimeType="video/mp4" startWithSAP="1" scanType="progressive" id="7357" segmentAlignment="true">
1819
<ContentProtection schemeIdUri="urn:mpeg:dash:mp4protection:2011" xmlns:cenc="urn:mpeg:cenc:2013" cenc:default_KID="08e36702-8f33-436c-a5dd-60ffe5571e60" value="cenc"></ContentProtection>

mpd/fixtures/live_profile_dynamic.mpd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
<Role schemeIdUri="urn:mpeg:dash:role:2011" value="main"></Role>
1414
<SegmentTemplate duration="1968" initialization="$RepresentationID$/audio/en/init.mp4" media="$RepresentationID$/audio/en/seg-$Number$.m4f" startNumber="0" timescale="1000"></SegmentTemplate>
1515
<Representation audioSamplingRate="44100" bandwidth="67095" codecs="mp4a.40.2" id="800"></Representation>
16+
<Accessibility schemeIdUri="urn:tva:metadata:cs:AudioPurposeCS:2007" value="1"></Accessibility>
1617
</AdaptationSet>
1718
<AdaptationSet mimeType="video/mp4" startWithSAP="1" scanType="progressive" id="7357" segmentAlignment="true">
1819
<ContentProtection schemeIdUri="urn:mpeg:dash:mp4protection:2011" xmlns:cenc="urn:mpeg:cenc:2013" cenc:default_KID="08e36702-8f33-436c-a5dd-60ffe5571e60" value="cenc"></ContentProtection>

mpd/fixtures/ondemand_profile.mpd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
<Initialization range="0-628"></Initialization>
1717
</SegmentBase>
1818
</Representation>
19+
<Accessibility schemeIdUri="urn:tva:metadata:cs:AudioPurposeCS:2007" value="1"></Accessibility>
1920
</AdaptationSet>
2021
<AdaptationSet mimeType="video/mp4" startWithSAP="1" scanType="progressive" id="7357" segmentAlignment="true">
2122
<ContentProtection schemeIdUri="urn:mpeg:dash:mp4protection:2011" xmlns:cenc="urn:mpeg:cenc:2013" cenc:default_KID="08e36702-8f33-436c-a5dd-60ffe5571e60" value="cenc"></ContentProtection>

mpd/mpd.go

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"encoding/hex"
66
"encoding/xml"
77
"errors"
8+
"fmt"
89
"strings"
910
"time"
1011

@@ -33,6 +34,12 @@ const (
3334
AUDIO_CHANNEL_CONFIGURATION_MPEG_DOLBY AudioChannelConfigurationScheme = "tag:dolby.com,2014:dash:audio_channel_configuration:2011"
3435
)
3536

37+
// AccessibilityElementScheme is the scheme definition for an Accessibility element
38+
type AccessibilityElementScheme string
39+
40+
// Accessibility descriptor values for Audio Description
41+
const ACCESSIBILITY_ELEMENT_SCHEME_DESCRIPTIVE_AUDIO AccessibilityElementScheme = "urn:tva:metadata:cs:AudioPurposeCS:2007"
42+
3643
// Constants for some known MIME types, this is a limited list and others can be used.
3744
const (
3845
DASH_MIME_TYPE_VIDEO_MP4 string = "video/mp4"
@@ -50,6 +57,7 @@ var (
5057
ErrSegmentTemplateLiveProfileOnly = errors.New("Segment template can only be used with Live Profile")
5158
ErrSegmentTemplateNil = errors.New("Segment Template nil ")
5259
ErrRepresentationNil = errors.New("Representation nil")
60+
ErrAccessibilityNil = errors.New("Accessibility nil")
5361
ErrBaseURLEmpty = errors.New("Base URL empty")
5462
ErrSegmentBaseOnDemandProfileOnly = errors.New("Segment Base can only be used with On-Demand Profile")
5563
ErrSegmentBaseNil = errors.New("Segment Base nil")
@@ -137,6 +145,7 @@ type AdaptationSet struct {
137145
SegmentList *SegmentList `xml:"SegmentList,omitempty"`
138146
SegmentTemplate *SegmentTemplate `xml:"SegmentTemplate,omitempty"` // Live Profile Only
139147
Representations []*Representation `xml:"Representation,omitempty"`
148+
AccessibilityElems []*Accessibility `xml:"Accessibility,omitempty"`
140149
}
141150

142151
func (as *AdaptationSet) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
@@ -162,6 +171,7 @@ func (as *AdaptationSet) UnmarshalXML(d *xml.Decoder, start xml.StartElement) er
162171
SegmentList *SegmentList `xml:"SegmentList,omitempty"`
163172
SegmentTemplate *SegmentTemplate `xml:"SegmentTemplate,omitempty"` // Live Profile Only
164173
Representations []*Representation `xml:"Representation,omitempty"`
174+
AccessibilityElems []*Accessibility `xml:"Accessibility,omitempty"`
165175
}{}
166176

167177
var (
@@ -245,8 +255,14 @@ func (as *AdaptationSet) UnmarshalXML(d *xml.Decoder, start xml.StartElement) er
245255
return err
246256
}
247257
representations = append(representations, rp)
258+
case "Accessibility":
259+
ac := new(Accessibility)
260+
err = d.DecodeElement(ac, &tt)
261+
if err != nil {
262+
return err
263+
}
248264
default:
249-
return errors.New("Unrecognized element in AdaptationSet")
265+
return fmt.Errorf("unrecognized element in AdaptationSet %q", tt.Name.Local)
250266
}
251267
case xml.EndElement:
252268
if tt == start.End() {
@@ -440,6 +456,12 @@ type Representation struct {
440456
SegmentTemplate *SegmentTemplate `xml:"SegmentTemplate,omitempty"`
441457
}
442458

459+
type Accessibility struct {
460+
AdaptationSet *AdaptationSet `xml:"-"`
461+
SchemeIdUri *string `xml:"schemeIdUri,attr,omitempty"`
462+
Value *string `xml:"value,attr,omitempty"`
463+
}
464+
443465
type AudioChannelConfiguration struct {
444466
SchemeIDURI *string `xml:"schemeIdUri,attr"`
445467
// Value will be an int for non-Dolby Schemes, and a hexstring for Dolby Schemes, hence we make it a string
@@ -1024,6 +1046,16 @@ func (as *AdaptationSet) addRepresentation(r *Representation) error {
10241046
return nil
10251047
}
10261048

1049+
// Internal helper method for adding an Accessibility element to an AdaptationSet.
1050+
func (as *AdaptationSet) addAccessibility(a *Accessibility) error {
1051+
if a == nil {
1052+
return ErrAccessibilityNil
1053+
}
1054+
a.AdaptationSet = as
1055+
as.AccessibilityElems = append(as.AccessibilityElems, a)
1056+
return nil
1057+
}
1058+
10271059
// Adds a new Role to an AdaptationSet
10281060
// schemeIdUri - Scheme ID URI string (i.e. urn:mpeg:dash:role:2011)
10291061
// value - Value for this role, (i.e. caption, subtitle, main, alternate, supplementary, commentary, dub)
@@ -1037,6 +1069,23 @@ func (as *AdaptationSet) AddNewRole(schemeIDURI string, value string) (*Role, er
10371069
return r, nil
10381070
}
10391071

1072+
// AddNewAccessibilityElement adds a new accessibility element to an adaptation set
1073+
// schemeIdUri - Scheme ID URI for the Accessibility element (i.e. urn:tva:metadata:cs:AudioPurposeCS:2007)
1074+
// value - specified value based on scheme
1075+
func (as *AdaptationSet) AddNewAccessibilityElement(scheme AccessibilityElementScheme, val string) (*Accessibility, error) {
1076+
accessibility := &Accessibility{
1077+
SchemeIdUri: Strptr((string)(scheme)),
1078+
Value: Strptr(val),
1079+
}
1080+
1081+
err := as.addAccessibility(accessibility)
1082+
if err != nil {
1083+
return nil, err
1084+
}
1085+
1086+
return accessibility, nil
1087+
}
1088+
10401089
// Sets the BaseURL for a Representation.
10411090
// baseURL - Base URL as a string (i.e. 800k/output-audio-und.mp4)
10421091
func (r *Representation) SetNewBaseURL(baseURL string) error {

mpd/mpd_read_write_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,35 @@ func TestExampleAddNewPeriod(t *testing.T) {
207207
testfixtures.CompareFixture(t, "fixtures/newperiod.mpd", xmlStr)
208208
}
209209

210+
func TestAddNewAccessibilityElementWriteToString(t *testing.T) {
211+
m := NewMPD(DASH_PROFILE_LIVE, VALID_MEDIA_PRESENTATION_DURATION, VALID_MIN_BUFFER_TIME)
212+
audioAS, err := m.AddNewAdaptationSetAudioWithID("7357", DASH_MIME_TYPE_AUDIO_MP4, VALID_SEGMENT_ALIGNMENT,
213+
VALID_START_WITH_SAP, VALID_LANG)
214+
if err != nil {
215+
t.Errorf("AddNewAccessibilityElement() error adding audio adaptation set: %v", err)
216+
return
217+
}
218+
219+
_, err = audioAS.AddNewAccessibilityElement(ACCESSIBILITY_ELEMENT_SCHEME_DESCRIPTIVE_AUDIO, "1")
220+
if err != nil {
221+
t.Errorf("AddNewAccessibilityElement() error adding accessibility element: %v", err)
222+
return
223+
}
224+
225+
xmlStr, err := m.WriteToString()
226+
require.NoError(t, err)
227+
expectedXML := `<?xml version="1.0" encoding="UTF-8"?>
228+
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" profiles="urn:mpeg:dash:profile:isoff-live:2011" type="static" mediaPresentationDuration="PT6M16S" minBufferTime="PT1.97S">
229+
<Period>
230+
<AdaptationSet mimeType="audio/mp4" startWithSAP="1" id="7357" segmentAlignment="true" lang="en">
231+
<Accessibility schemeIdUri="urn:tva:metadata:cs:AudioPurposeCS:2007" value="1"></Accessibility>
232+
</AdaptationSet>
233+
</Period>
234+
</MPD>
235+
`
236+
require.EqualString(t, expectedXML, xmlStr)
237+
}
238+
210239
func LiveProfile() *MPD {
211240
m := NewMPD(DASH_PROFILE_LIVE, VALID_MEDIA_PRESENTATION_DURATION, VALID_MIN_BUFFER_TIME,
212241
AttrAvailabilityStartTime(VALID_AVAILABILITY_START_TIME))
@@ -221,6 +250,7 @@ func LiveProfile() *MPD {
221250

222251
_, _ = audioAS.SetNewSegmentTemplate(1968, "$RepresentationID$/audio/en/init.mp4", "$RepresentationID$/audio/en/seg-$Number$.m4f", 0, 1000)
223252
_, _ = audioAS.AddNewRepresentationAudio(44100, 67095, "mp4a.40.2", "800")
253+
_, _ = audioAS.AddNewAccessibilityElement(ACCESSIBILITY_ELEMENT_SCHEME_DESCRIPTIVE_AUDIO, "1")
224254

225255
videoAS, _ := m.AddNewAdaptationSetVideoWithID("7357", DASH_MIME_TYPE_VIDEO_MP4, VALID_SCAN_TYPE, VALID_SEGMENT_ALIGNMENT, VALID_START_WITH_SAP)
226256

@@ -277,6 +307,7 @@ func LiveProfileDynamic() *MPD {
277307

278308
_, _ = audioAS.SetNewSegmentTemplate(1968, "$RepresentationID$/audio/en/init.mp4", "$RepresentationID$/audio/en/seg-$Number$.m4f", 0, 1000)
279309
_, _ = audioAS.AddNewRepresentationAudio(44100, 67095, "mp4a.40.2", "800")
310+
_, _ = audioAS.AddNewAccessibilityElement(ACCESSIBILITY_ELEMENT_SCHEME_DESCRIPTIVE_AUDIO, "1")
280311

281312
videoAS, _ := m.AddNewAdaptationSetVideoWithID("7357", DASH_MIME_TYPE_VIDEO_MP4, VALID_SCAN_TYPE, VALID_SEGMENT_ALIGNMENT, VALID_START_WITH_SAP)
282313

@@ -332,6 +363,7 @@ func HbbTVProfile() *MPD {
332363
_, _ = audioAS.SetNewSegmentTemplate(1968, "$RepresentationID$/audio/en/init.mp4", "$RepresentationID$/audio/en/seg-$Number$.m4f", 0, 1000)
333364
r, _ := audioAS.AddNewRepresentationAudio(44100, 67095, "mp4a.40.2", "800")
334365
_, _ = r.AddNewAudioChannelConfiguration(AUDIO_CHANNEL_CONFIGURATION_MPEG_DASH, "2")
366+
_, _ = audioAS.AddNewAccessibilityElement(ACCESSIBILITY_ELEMENT_SCHEME_DESCRIPTIVE_AUDIO, "1")
335367

336368
videoAS, _ := m.AddNewAdaptationSetVideoWithID("7357", DASH_MIME_TYPE_VIDEO_MP4, VALID_SCAN_TYPE, VALID_SEGMENT_ALIGNMENT, VALID_START_WITH_SAP)
337369

@@ -380,6 +412,7 @@ func OnDemandProfile() *MPD {
380412
_, _ = audioAS.AddNewContentProtectionRoot("08e367028f33436ca5dd60ffe5571e60")
381413
_, _ = audioAS.AddNewContentProtectionSchemeWidevineWithPSSH(getValidWVHeaderBytes())
382414
_, _ = audioAS.AddNewContentProtectionSchemePlayreadyWithPSSH(VALID_PLAYREADY_PRO)
415+
_, _ = audioAS.AddNewAccessibilityElement(ACCESSIBILITY_ELEMENT_SCHEME_DESCRIPTIVE_AUDIO, "1")
383416

384417
audioRep, _ := audioAS.AddNewRepresentationAudio(44100, 128558, "mp4a.40.5", "800k/audio-und")
385418
_ = audioRep.SetNewBaseURL("800k/output-audio-und.mp4")

mpd/mpd_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,3 +457,30 @@ func getValidWVHeaderBytes() []byte {
457457
}
458458
return wvHeader
459459
}
460+
461+
func TestAddNewAccessibilityElement(t *testing.T) {
462+
m := NewMPD(DASH_PROFILE_LIVE, VALID_MEDIA_PRESENTATION_DURATION, VALID_MIN_BUFFER_TIME)
463+
audioAS, err := m.AddNewAdaptationSetAudioWithID("7357", DASH_MIME_TYPE_AUDIO_MP4, VALID_SEGMENT_ALIGNMENT,
464+
VALID_START_WITH_SAP, VALID_LANG)
465+
if err != nil {
466+
t.Errorf("AddNewAccessibilityElement() error adding audio adaptation set: %v", err)
467+
return
468+
}
469+
470+
_, err = audioAS.AddNewAccessibilityElement(ACCESSIBILITY_ELEMENT_SCHEME_DESCRIPTIVE_AUDIO, "1")
471+
if err != nil {
472+
t.Errorf("AddNewAccessibilityElement() error adding accessibility element: %v", err)
473+
return
474+
}
475+
476+
if g, e := len(audioAS.AccessibilityElems), 1; g != e {
477+
t.Errorf("AddNewAccessibilityElement() wrong number of accessibility elements, got: %d, expected: %d",
478+
g, e)
479+
return
480+
}
481+
482+
elem := audioAS.AccessibilityElems[0]
483+
484+
require.EqualStringPtr(t, Strptr((string)(ACCESSIBILITY_ELEMENT_SCHEME_DESCRIPTIVE_AUDIO)), elem.SchemeIdUri)
485+
require.EqualStringPtr(t, Strptr("1"), elem.Value)
486+
}

0 commit comments

Comments
 (0)