Skip to content

Commit

Permalink
Merge pull request #198 from Dash-Industry-Forum/derive-contenttype
Browse files Browse the repository at this point in the history
fix: set contentType from mimeType or codecs
  • Loading branch information
tobbee authored Jun 14, 2024
2 parents 3676173 + 8467a36 commit 7452fb8
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 9 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Fixed

- Will now set contentType from mimeType on AdaptationSet or Representation level.
- If contentType and mimedType is not present, contentType will be set from codecs string.

## [1.4.1] - 2024-05-28

### Fixed
Expand Down
2 changes: 2 additions & 0 deletions cmd/livesim2/app/asset.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ func (am *assetMgr) loadAsset(mpdPath string) error {
md.Dur = mpd.MediaPresentationDuration.String()
asset.MPDs[mpdName] = md

fillContentTypes(assetPath, mpd.Periods[0])

for _, as := range mpd.Periods[0].AdaptationSets {
if as.SegmentTemplate == nil {
return fmt.Errorf("no SegmentTemplate in adaptation set")
Expand Down
77 changes: 68 additions & 9 deletions cmd/livesim2/app/livempd.go
Original file line number Diff line number Diff line change
Expand Up @@ -749,16 +749,75 @@ func orderAdaptationSetsByContentType(aSets []*m.AdaptationSetType) []*m.Adaptat
func fillContentTypes(assetPath string, period *m.Period) {
for _, as := range period.AdaptationSets {
if as.ContentType == "" {
switch as.MimeType {
case "video/mp4":
as.ContentType = "video"
case "audio/mp4":
as.ContentType = "audio"
case "application/mp4":
as.ContentType = "text"
default:
slog.Warn("no contentType and unknown mimeType", "asset", assetPath, "mimeType", as.MimeType)
as.ContentType = m.RFC6838ContentTypeType(contentTypeFromMimeType(as.MimeType))
if as.ContentType == "" {
as.ContentType = m.RFC6838ContentTypeType(guessContentTypeForAS(as))
if as.ContentType == "" {
asID := "not set"
if as.Id != nil {
asID = fmt.Sprintf("%d", *as.Id)
}
slog.Warn("no contentType, unknown mimeType, and no known codecs", "asset", assetPath, "adaptationSetID", asID)
}
}
}
}
}

var videoCodecPrefixes = []string{"avc", "hev", "hvc"}
var audioCodecPrefixes = []string{"mp4a", "ac-3", "ec-3"}
var textCodecPrefixes = []string{"stpp", "wvtt"}

func matchesPrefix(s string, prefixes []string) bool {
for _, prefix := range prefixes {
if strings.HasPrefix(s, prefix) {
return true
}
}
return false
}

// guesssContentTypeForAS guesses the content type based on codecs and other data in the AdaptationSet or its Representations.
func guessContentTypeForAS(as *m.AdaptationSetType) string {
if as.Codecs != "" {
switch {
case matchesPrefix(as.Codecs, videoCodecPrefixes):
return "video"
case matchesPrefix(as.Codecs, audioCodecPrefixes):
return "audio"
case matchesPrefix(as.Codecs, textCodecPrefixes):
return "text"
}
}

for _, rep := range as.Representations {
contentType := contentTypeFromMimeType(rep.MimeType)
if contentType != "" {
return contentType
}
if rep.Codecs != "" {
switch {
case matchesPrefix(rep.Codecs, videoCodecPrefixes):
return "video"
case matchesPrefix(rep.Codecs, audioCodecPrefixes):
return "audio"
case matchesPrefix(rep.Codecs, textCodecPrefixes):
return "text"
}
}
}
return ""
}

func contentTypeFromMimeType(mimeType string) string {
switch mimeType {
case "video/mp4":
return "video"
case "audio/mp4":
return "audio"
case "application/mp4":
return "text"
default:
return ""
}
}
8 changes: 8 additions & 0 deletions cmd/livesim2/app/livempd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -984,6 +984,12 @@ func TestFillContentTypes(t *testing.T) {
{Id: Ptr(uint32(2)), RepresentationBaseType: m.RepresentationBaseType{MimeType: "application/mp4"}},
{Id: Ptr(uint32(4)), ContentType: "audio"},
{Id: Ptr(uint32(4))},
{Id: Ptr(uint32(4)), Representations: []*m.RepresentationType{
{RepresentationBaseType: m.RepresentationBaseType{MimeType: "video/mp4"}},
}},
{Id: Ptr(uint32(4)), Representations: []*m.RepresentationType{
{RepresentationBaseType: m.RepresentationBaseType{Codecs: "ac-3"}},
}},
},
}
fillContentTypes("theAsset", p)
Expand All @@ -992,4 +998,6 @@ func TestFillContentTypes(t *testing.T) {
assert.Equal(t, m.RFC6838ContentTypeType("text"), p.AdaptationSets[2].ContentType)
assert.Equal(t, m.RFC6838ContentTypeType("audio"), p.AdaptationSets[3].ContentType)
assert.Equal(t, m.RFC6838ContentTypeType(""), p.AdaptationSets[4].ContentType)
assert.Equal(t, m.RFC6838ContentTypeType("video"), p.AdaptationSets[5].ContentType)
assert.Equal(t, m.RFC6838ContentTypeType("audio"), p.AdaptationSets[6].ContentType)
}

0 comments on commit 7452fb8

Please sign in to comment.