Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 61 additions & 12 deletions mpd/mpd.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,14 +93,16 @@ type AdaptationSet struct {

// Constants for DRM / ContentProtection
const (
CONTENT_PROTECTION_ROOT_SCHEME_ID_URI = "urn:mpeg:dash:mp4protection:2011"
CONTENT_PROTECTION_ROOT_VALUE = "cenc"
CENC_XMLNS = "urn:mpeg:cenc:2013"
CONTENT_PROTECTION_WIDEVINE_SCHEME_ID = "urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed"
CONTENT_PROTECTION_WIDEVINE_SCHEME_HEX = "edef8ba979d64acea3c827dcd51d21ed"
CONTENT_PROTECTION_PLAYREADY_SCHEME_ID = "urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95"
CONTENT_PROTECTION_PLAYREADY_SCHEME_HEX = "9a04f07998404286ab92e65be0885f95"
CONTENT_PROTECTION_PLAYREADY_XMLNS = "urn:microsoft:playready"
CONTENT_PROTECTION_ROOT_SCHEME_ID_URI = "urn:mpeg:dash:mp4protection:2011"
CONTENT_PROTECTION_ROOT_VALUE = "cenc"
CENC_XMLNS = "urn:mpeg:cenc:2013"
CONTENT_PROTECTION_WIDEVINE_SCHEME_ID = "urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed"
CONTENT_PROTECTION_WIDEVINE_SCHEME_HEX = "edef8ba979d64acea3c827dcd51d21ed"
CONTENT_PROTECTION_PLAYREADY_SCHEME_ID = "urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95"
CONTENT_PROTECTION_PLAYREADY_SCHEME_HEX = "9a04f07998404286ab92e65be0885f95"
CONTENT_PROTECTION_PLAYREADY_SCHEME_V10_ID = "urn:uuid:79f0049a-4098-8642-ab92-e65be0885f95"
CONTENT_PROTECTION_PLAYREADY_SCHEME_V10_HEX = "79f0049a40988642ab92e65be0885f95"
CONTENT_PROTECTION_PLAYREADY_XMLNS = "urn:microsoft:playready"
)

type ContentProtectioner interface {
Expand Down Expand Up @@ -332,7 +334,7 @@ func NewWidevineContentProtection(wvHeader []byte) (*WidevineContentProtection,
// AddNewContentProtectionSchemePlayready adds a new content protection scheme for PlayReady DRM.
// pro - PlayReady Object Header, as a Base64 encoded string.
func (as *AdaptationSet) AddNewContentProtectionSchemePlayready(pro string) (*PlayreadyContentProtection, error) {
cp, err := newPlayreadyContentProtection(pro)
cp, err := newPlayreadyContentProtection(pro, CONTENT_PROTECTION_PLAYREADY_SCHEME_ID)
if err != nil {
return nil, err
}
Expand All @@ -344,7 +346,22 @@ func (as *AdaptationSet) AddNewContentProtectionSchemePlayready(pro string) (*Pl
return cp, nil
}

func newPlayreadyContentProtection(pro string) (*PlayreadyContentProtection, error) {
// AddNewContentProtectionSchemePlayreadyV10 adds a new content protection scheme for PlayReady v1.0 DRM.
// pro - PlayReady Object Header, as a Base64 encoded string.
func (as *AdaptationSet) AddNewContentProtectionSchemePlayreadyV10(pro string) (*PlayreadyContentProtection, error) {
cp, err := newPlayreadyContentProtection(pro, CONTENT_PROTECTION_PLAYREADY_SCHEME_V10_ID)
if err != nil {
return nil, err
}

err = as.AddContentProtection(cp)
if err != nil {
return nil, err
}
return cp, nil
}

func newPlayreadyContentProtection(pro string, schemeIDURI string) (*PlayreadyContentProtection, error) {
if pro == "" {
return nil, ErrPROEmpty
}
Expand All @@ -353,7 +370,7 @@ func newPlayreadyContentProtection(pro string) (*PlayreadyContentProtection, err
PlayreadyXMLNS: Strptr(CONTENT_PROTECTION_PLAYREADY_XMLNS),
PRO: Strptr(pro),
}
cp.SchemeIDURI = Strptr(CONTENT_PROTECTION_PLAYREADY_SCHEME_ID)
cp.SchemeIDURI = Strptr(schemeIDURI)

return cp, nil
}
Expand All @@ -362,7 +379,7 @@ func newPlayreadyContentProtection(pro string) (*PlayreadyContentProtection, err
// will include both ms:pro and cenc:pssh subelements
// pro - PlayReady Object Header, as a Base64 encoded string.
func (as *AdaptationSet) AddNewContentProtectionSchemePlayreadyWithPSSH(pro string) (*PlayreadyContentProtection, error) {
cp, err := newPlayreadyContentProtection(pro)
cp, err := newPlayreadyContentProtection(pro, CONTENT_PROTECTION_PLAYREADY_SCHEME_ID)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -390,6 +407,38 @@ func (as *AdaptationSet) AddNewContentProtectionSchemePlayreadyWithPSSH(pro stri
return cp, nil
}

// AddNewContentProtectionSchemePlayreadyV10WithPSSH adds a new content protection scheme for PlayReady v1.0 DRM. The scheme
// will include both ms:pro and cenc:pssh subelements
// pro - PlayReady Object Header, as a Base64 encoded string.
func (as *AdaptationSet) AddNewContentProtectionSchemePlayreadyV10WithPSSH(pro string) (*PlayreadyContentProtection, error) {
cp, err := newPlayreadyContentProtection(pro, CONTENT_PROTECTION_PLAYREADY_SCHEME_V10_ID)
if err != nil {
return nil, err
}
cp.XMLNS = Strptr(CENC_XMLNS)
prSystemID, err := hex.DecodeString(CONTENT_PROTECTION_PLAYREADY_SCHEME_V10_HEX)
if err != nil {
panic(err.Error())
}

proBin, err := base64.StdEncoding.DecodeString(pro)
if err != nil {
return nil, err
}

psshBox, err := makePSSHBox(prSystemID, proBin)
if err != nil {
return nil, err
}
cp.PSSH = Strptr(base64.StdEncoding.EncodeToString(psshBox))

err = as.AddContentProtection(cp)
if err != nil {
return nil, err
}
return cp, nil
}

// Internal helper method for adding a ContentProtection to an AdaptationSet.
func (as *AdaptationSet) AddContentProtection(cp ContentProtectioner) error {
if cp == nil {
Expand Down
44 changes: 44 additions & 0 deletions mpd/mpd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,32 @@ func (s *MPDSuite) TestAddNewContentProtectionSchemePlayready() {
assert.Equal(s.T(), expectedCP, cp)
}

func (s *MPDSuite) TestAddNewContentProtectionSchemePlayreadyV10ErrorEmptyPRO() {
m := NewMPD(DASH_PROFILE_LIVE, VALID_MEDIA_PRESENTATION_DURATION, VALID_MIN_BUFFER_TIME)
as, _ := m.AddNewAdaptationSetVideo(DASH_MIME_TYPE_VIDEO_MP4, VALID_SCAN_TYPE, VALID_SEGMENT_ALIGNMENT, VALID_START_WITH_SAP)

cp, err := as.AddNewContentProtectionSchemePlayreadyV10("")
assert.NotNil(s.T(), err)
assert.Equal(s.T(), ErrPROEmpty, err)
assert.Nil(s.T(), cp)
}

func (s *MPDSuite) TestAddNewContentProtectionSchemePlayreadyV10() {
m := NewMPD(DASH_PROFILE_LIVE, VALID_MEDIA_PRESENTATION_DURATION, VALID_MIN_BUFFER_TIME)
as, _ := m.AddNewAdaptationSetVideo(DASH_MIME_TYPE_VIDEO_MP4, VALID_SCAN_TYPE, VALID_SEGMENT_ALIGNMENT, VALID_START_WITH_SAP)

cp, err := as.AddNewContentProtectionSchemePlayreadyV10(VALID_PLAYREADY_PRO)
assert.Nil(s.T(), err)
assert.NotNil(s.T(), cp)
expectedCP := &PlayreadyContentProtection{
PlayreadyXMLNS: Strptr(VALID_PLAYREADY_XMLNS),
PRO: Strptr(VALID_PLAYREADY_PRO),
}
expectedCP.SchemeIDURI = Strptr(CONTENT_PROTECTION_PLAYREADY_SCHEME_V10_ID)

assert.Equal(s.T(), expectedCP, cp)
}

func (s *MPDSuite) TestAddNewContentProtectionSchemePlayreadyWithPSSH() {
m := NewMPD(DASH_PROFILE_LIVE, VALID_MEDIA_PRESENTATION_DURATION, VALID_MIN_BUFFER_TIME)
as, _ := m.AddNewAdaptationSetVideo(DASH_MIME_TYPE_VIDEO_MP4, VALID_SCAN_TYPE, VALID_SEGMENT_ALIGNMENT, VALID_START_WITH_SAP)
Expand All @@ -348,6 +374,24 @@ func (s *MPDSuite) TestAddNewContentProtectionSchemePlayreadyWithPSSH() {
assert.Equal(s.T(), expectedCP, cp)
}

func (s *MPDSuite) TestAddNewContentProtectionSchemePlayreadyV10WithPSSH() {
m := NewMPD(DASH_PROFILE_LIVE, VALID_MEDIA_PRESENTATION_DURATION, VALID_MIN_BUFFER_TIME)
as, _ := m.AddNewAdaptationSetVideo(DASH_MIME_TYPE_VIDEO_MP4, VALID_SCAN_TYPE, VALID_SEGMENT_ALIGNMENT, VALID_START_WITH_SAP)

cp, err := as.AddNewContentProtectionSchemePlayreadyV10WithPSSH(VALID_PLAYREADY_PRO)
assert.Nil(s.T(), err)
assert.NotNil(s.T(), cp)
expectedCP := &PlayreadyContentProtection{
PlayreadyXMLNS: Strptr(VALID_PLAYREADY_XMLNS),
PRO: Strptr(VALID_PLAYREADY_PRO),
}
expectedCP.SchemeIDURI = Strptr(CONTENT_PROTECTION_PLAYREADY_SCHEME_V10_ID)
expectedCP.XMLNS = Strptr(CENC_XMLNS)
expectedCP.PSSH = Strptr("AAACJnBzc2gAAAAAefAEmkCYhkKrkuZb4IhflQAAAgYGAgAAAQABAPwBPABXAFIATQBIAEUAQQBEAEUAUgAgAHgAbQBsAG4AcwA9ACIAaAB0AHQAcAA6AC8ALwBzAGMAaABlAG0AYQBzAC4AbQBpAGMAcgBvAHMAbwBmAHQALgBjAG8AbQAvAEQAUgBNAC8AMgAwADAANwAvADAAMwAvAFAAbABhAHkAUgBlAGEAZAB5AEgAZQBhAGQAZQByACIAIAB2AGUAcgBzAGkAbwBuAD0AIgA0AC4AMAAuADAALgAwACIAPgA8AEQAQQBUAEEAPgA8AFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBFAFkATABFAE4APgAxADYAPAAvAEsARQBZAEwARQBOAD4APABBAEwARwBJAEQAPgBBAEUAUwBDAFQAUgA8AC8AQQBMAEcASQBEAD4APAAvAFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBJAEQAPgBMADkAVwA5AFcAawBwAFYASwBrACsANAAwAEcASAAzAFkAVQBKAFIAVgBRAD0APQA8AC8ASwBJAEQAPgA8AEMASABFAEMASwBTAFUATQA+AEkASwB6AFkAMgBIAFoATABBAGwASQA9ADwALwBDAEgARQBDAEsAUwBVAE0APgA8AC8ARABBAFQAQQA+ADwALwBXAFIATQBIAEUAQQBEAEUAUgA+AA==")

assert.Equal(s.T(), expectedCP, cp)
}

func (s *MPDSuite) TestSetNewSegmentTemplate() {
m := NewMPD(DASH_PROFILE_LIVE, VALID_MEDIA_PRESENTATION_DURATION, VALID_MIN_BUFFER_TIME)
audioAS, _ := m.AddNewAdaptationSetAudio(DASH_MIME_TYPE_AUDIO_MP4, VALID_SEGMENT_ALIGNMENT, VALID_START_WITH_SAP, VALID_LANG)
Expand Down