Skip to content

Commit

Permalink
Merge pull request #170 from monyone/master
Browse files Browse the repository at this point in the history
Feat: add ISO 14496-30 WebVTT Box
  • Loading branch information
sunfish-shogi authored Jan 8, 2025
2 parents ce47850 + c888274 commit 89fe2fe
Show file tree
Hide file tree
Showing 2 changed files with 282 additions and 0 deletions.
127 changes: 127 additions & 0 deletions box_types_iso14496_30.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package mp4

/*********************** WebVTT Sample Entry ****************************/

func BoxTypeVttC() BoxType { return StrToBoxType("vttC") }
func BoxTypeVlab() BoxType { return StrToBoxType("vlab") }
func BoxTypeWvtt() BoxType { return StrToBoxType("wvtt") }

func init() {
AddBoxDef(&WebVTTConfigurationBox{})
AddBoxDef(&WebVTTSourceLabelBox{})
AddAnyTypeBoxDef(&WVTTSampleEntry{}, BoxTypeWvtt())
}

type WebVTTConfigurationBox struct {
Box
Config string `mp4:"0,string"`
}

func (WebVTTConfigurationBox) GetType() BoxType {
return BoxTypeVttC()
}

type WebVTTSourceLabelBox struct {
Box
SourceLabel string `mp4:"0,string"`
}

func (WebVTTSourceLabelBox) GetType() BoxType {
return BoxTypeVlab()
}

type WVTTSampleEntry struct {
SampleEntry `mp4:"0,extend"`
}

/*********************** WebVTT Sample Format ****************************/

func BoxTypeVttc() BoxType { return StrToBoxType("vttc") }
func BoxTypeVsid() BoxType { return StrToBoxType("vsid") }
func BoxTypeCtim() BoxType { return StrToBoxType("ctim") }
func BoxTypeIden() BoxType { return StrToBoxType("iden") }
func BoxTypeSttg() BoxType { return StrToBoxType("sttg") }
func BoxTypePayl() BoxType { return StrToBoxType("payl") }
func BoxTypeVtte() BoxType { return StrToBoxType("vtte") }
func BoxTypeVtta() BoxType { return StrToBoxType("vtta") }

func init() {
AddBoxDef(&VTTCueBox{})
AddBoxDef(&CueSourceIDBox{})
AddBoxDef(&CueTimeBox{})
AddBoxDef(&CueIDBox{})
AddBoxDef(&CueSettingsBox{})
AddBoxDef(&CuePayloadBox{})
AddBoxDef(&VTTEmptyCueBox{})
AddBoxDef(&VTTAdditionalTextBox{})
}

type VTTCueBox struct {
Box
}

func (VTTCueBox) GetType() BoxType {
return BoxTypeVttc()
}

type CueSourceIDBox struct {
Box
SourceId uint32 `mp4:"0,size=32"`
}

func (CueSourceIDBox) GetType() BoxType {
return BoxTypeVsid()
}

type CueTimeBox struct {
Box
CueCurrentTime string `mp4:"0,string"`
}

func (CueTimeBox) GetType() BoxType {
return BoxTypeCtim()
}

type CueIDBox struct {
Box
CueId string `mp4:"0,string"`
}

func (CueIDBox) GetType() BoxType {
return BoxTypeIden()
}

type CueSettingsBox struct {
Box
Settings string `mp4:"0,string"`
}

func (CueSettingsBox) GetType() BoxType {
return BoxTypeSttg()
}

type CuePayloadBox struct {
Box
CueText string `mp4:"0,string"`
}

func (CuePayloadBox) GetType() BoxType {
return BoxTypePayl()
}

type VTTEmptyCueBox struct {
Box
}

func (VTTEmptyCueBox) GetType() BoxType {
return BoxTypeVtte()
}

type VTTAdditionalTextBox struct {
Box
CueAdditionalText string `mp4:"0,string"`
}

func (VTTAdditionalTextBox) GetType() BoxType {
return BoxTypeVtta()
}
155 changes: 155 additions & 0 deletions box_types_iso14496_30_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package mp4

import (
"bytes"
"io"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestBoxTypesISO14496_30(t *testing.T) {
testCases := []struct {
name string
src IImmutableBox
dst IBox
bin []byte
str string
ctx Context
}{
{
name: "vttC",
src: &WebVTTConfigurationBox{
Config: "WEBVTT\n",
},
dst: &WebVTTConfigurationBox{},
bin: []byte{'W', 'E', 'B', 'V', 'T', 'T', '\n', 0 },
str: `Config="WEBVTT."`,
},
{
name: "vlab",
src: &WebVTTSourceLabelBox{
SourceLabel: "Source",
},
dst: &WebVTTSourceLabelBox{},
bin: []byte{'S', 'o', 'u', 'r', 'c', 'e', 0 },
str: `SourceLabel="Source"`,
},
{
name: "wvtt",
src: &WVTTSampleEntry{
SampleEntry: SampleEntry{
AnyTypeBox: AnyTypeBox{Type: StrToBoxType("wvtt")},
DataReferenceIndex: 0x1234,
},
},
dst: &WVTTSampleEntry{SampleEntry: SampleEntry{AnyTypeBox: AnyTypeBox{Type: StrToBoxType("wvtt")}}},
bin: []byte{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x12, 0x34 },
str: `DataReferenceIndex=4660`,
},
{
name: "vttc",
src: &VTTCueBox{},
dst: &VTTCueBox{},
bin: []byte(nil),
str: ``,
},
{
name: "vsid",
src: &CueSourceIDBox{
SourceId: 0,
},
dst: &CueSourceIDBox{},
bin: []byte{ 0, 0, 0, 0 },
str: `SourceId=0`,
},
{
name: "ctim",
src: &CueTimeBox{
CueCurrentTime: "00:00:00.000",
},
dst: &CueTimeBox{},
bin: []byte{'0', '0', ':', '0', '0', ':', '0', '0', '.', '0', '0', '0', 0 },
str: `CueCurrentTime="00:00:00.000"`,
},
{
name: "iden",
src: &CueIDBox{
CueId: "example_id",
},
dst: &CueIDBox{},
bin: []byte{'e', 'x', 'a', 'm', 'p', 'l', 'e', '_', 'i', 'd', 0 },
str: `CueId="example_id"`,
},
{
name: "sttg",
src: &CueSettingsBox{
Settings: "line=0",
},
dst: &CueSettingsBox{},
bin: []byte{'l', 'i', 'n', 'e', '=', '0', 0 },
str: `Settings="line=0"`,
},
{
name: "payl",
src: &CuePayloadBox{
CueText: "sample",
},
dst: &CuePayloadBox{},
bin: []byte{'s', 'a', 'm', 'p', 'l', 'e', 0 },
str: `CueText="sample"`,
},
{
name: "vtte",
src: &VTTEmptyCueBox{},
dst: &VTTEmptyCueBox{},
bin: []byte(nil),
str: ``,
},
{
name: "vtta",
src: &VTTAdditionalTextBox{
CueAdditionalText: "test",
},
dst: &VTTAdditionalTextBox{},
bin: []byte{'t', 'e', 's', 't', 0},
str: `CueAdditionalText="test"`,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
// Marshal
buf := bytes.NewBuffer(nil)
n, err := Marshal(buf, tc.src, tc.ctx)
require.NoError(t, err)
assert.Equal(t, uint64(len(tc.bin)), n)
assert.Equal(t, tc.bin, buf.Bytes())

// Unmarshal
r := bytes.NewReader(tc.bin)
n, err = Unmarshal(r, uint64(len(tc.bin)), tc.dst, tc.ctx)
require.NoError(t, err)
assert.Equal(t, uint64(buf.Len()), n)
assert.Equal(t, tc.src, tc.dst)
s, err := r.Seek(0, io.SeekCurrent)
require.NoError(t, err)
assert.Equal(t, int64(buf.Len()), s)

// UnmarshalAny
dst, n, err := UnmarshalAny(bytes.NewReader(tc.bin), tc.src.GetType(), uint64(len(tc.bin)), tc.ctx)
require.NoError(t, err)
assert.Equal(t, uint64(buf.Len()), n)
assert.Equal(t, tc.src, dst)
s, err = r.Seek(0, io.SeekCurrent)
require.NoError(t, err)
assert.Equal(t, int64(buf.Len()), s)

// Stringify
str, err := Stringify(tc.src, tc.ctx)
require.NoError(t, err)
assert.Equal(t, tc.str, str)
})
}
}

0 comments on commit 89fe2fe

Please sign in to comment.