fix: demuxer mp4

This commit is contained in:
langhuihui
2025-02-13 10:12:39 +08:00
parent c1a5ebda13
commit 942eeb11b0
14 changed files with 135 additions and 103 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 625 KiB

After

Width:  |  Height:  |  Size: 659 KiB

View File

@@ -25,12 +25,12 @@ mp4:
# enable: false # enable: false
publish: publish:
delayclosetimeout: 3s delayclosetimeout: 3s
# onpub: onpub:
# record: record:
# ^live/.+: ^live/.+:
# fragment: 10s fragment: 10s
# filepath: record/$0 filepath: record/$0
# type: mp4 # type: fmp4
onsub: onsub:
pull: pull:
^vod_mp4_\d+/(.+)$: $1 ^vod_mp4_\d+/(.+)$: $1

View File

@@ -142,9 +142,9 @@
try { try {
// Try different codec combinations // Try different codec combinations
const codecConfigs = [ const codecConfigs = [
'video/mp4; codecs="avc1.64001f"', // Video only //'video/mp4; codecs="avc1.64001f"', // Video only
'video/mp4; codecs="avc1.64001f,mp4a.40.2"', // Video + AAC 'video/mp4; codecs="avc1.64001f,mp4a.40.2"', // Video + AAC
'video/mp4' // Let the browser figure it out // 'video/mp4' // Let the browser figure it out
]; ];
let sourceBufferCreated = false; let sourceBufferCreated = false;

View File

@@ -1,59 +0,0 @@
package bits
// Reader is a bit stream reader
type Reader struct {
Data []byte
Offset int
}
// Skip skips n bits
func (r *Reader) Skip(n int) {
r.Offset += n
}
// ReadBit reads a single bit
func (r *Reader) ReadBit() (uint, error) {
if r.Offset/8 >= len(r.Data) {
return 0, nil
}
b := r.Data[r.Offset/8]
v := (b >> (7 - (r.Offset % 8))) & 0x01
r.Offset++
return uint(v), nil
}
// ReadExpGolomb reads an Exp-Golomb code
func (r *Reader) ReadExpGolomb() (uint, error) {
leadingZeroBits := 0
for {
b, err := r.ReadBit()
if err != nil {
return 0, err
}
if b == 1 {
break
}
leadingZeroBits++
}
result := uint(1<<leadingZeroBits) - 1
for i := 0; i < leadingZeroBits; i++ {
b, err := r.ReadBit()
if err != nil {
return 0, err
}
result = (result << 1) | uint(b)
}
return result, nil
}
// ReadSE reads a signed Exp-Golomb code
func (r *Reader) ReadSE() (int, error) {
val, err := r.ReadExpGolomb()
if err != nil {
return 0, err
}
sign := ((val & 0x01) << 1) - 1
val = ((val >> 1) + (val & 0x01)) * uint(sign)
return int(val), nil
}

View File

@@ -172,8 +172,8 @@ func WriteTo(w io.Writer, box ...IBox) (n int64, err error) {
if err != nil { if err != nil {
return return
} }
if n1 + n2 != int64(b.Size()) { if n1+n2 != int64(b.Size()) {
panic(fmt.Sprintf("write to %s size error, %d != %d", b.Type(), n1 + n2, b.Size())) panic(fmt.Sprintf("write to %s size error, %d != %d", b.Type(), n1+n2, b.Size()))
} }
n += n1 + n2 n += n1 + n2
} }
@@ -193,7 +193,7 @@ func ReadFrom(r io.Reader) (box IBox, err error) {
if !exists { if !exists {
return nil, fmt.Errorf("unknown box type: %s", baseBox.typ) return nil, fmt.Errorf("unknown box type: %s", baseBox.typ)
} }
b := reflect.New(t).Interface().(IBox) b := reflect.New(t.Elem()).Interface().(IBox)
var payload []byte var payload []byte
if baseBox.size == 1 { if baseBox.size == 1 {
if _, err = io.ReadFull(r, tmp[:]); err != nil { if _, err = io.ReadFull(r, tmp[:]); err != nil {
@@ -203,8 +203,10 @@ func ReadFrom(r io.Reader) (box IBox, err error) {
} else { } else {
payload = make([]byte, baseBox.size-BasicBoxLen) payload = make([]byte, baseBox.size-BasicBoxLen)
} }
_, err = io.ReadFull(r, payload) _, err = io.ReadFull(r, payload)
if err != nil {
return nil, err
}
boxHeader := b.Header() boxHeader := b.Header()
switch header := boxHeader.(type) { switch header := boxHeader.(type) {
case *BaseBox: case *BaseBox:
@@ -216,6 +218,9 @@ func ReadFrom(r io.Reader) (box IBox, err error) {
header.Flags = [3]byte(payload[1:4]) header.Flags = [3]byte(payload[1:4])
box, err = b.Unmarshal(payload[4:]) box, err = b.Unmarshal(payload[4:])
} }
if err == io.EOF {
return box, nil
}
return return
} }

View File

@@ -56,5 +56,5 @@ func (box *CTTSBox) Unmarshal(buf []byte) (IBox, error) {
} }
func init() { func init() {
RegisterBox[CTTSBox](TypeCTTS) RegisterBox[*CTTSBox](TypeCTTS)
} }

View File

@@ -105,9 +105,8 @@ func (box *DataInformationBox) WriteTo(w io.Writer) (n int64, err error) {
return WriteTo(w, box.Dref) return WriteTo(w, box.Dref)
} }
func (box *DataInformationBox) Unmarshal(buf []byte) (IBox, error) { func (box *DataInformationBox) Unmarshal(buf []byte) (b IBox, err error) {
r := bytes.NewReader(buf) b, err = ReadFrom(bytes.NewReader(buf))
b, err := ReadFrom(r)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -91,3 +91,7 @@ func MakeHdlrBox(hdt HandlerType) *HandlerBox {
} }
return hdlr return hdlr
} }
func init() {
RegisterBox[*HandlerBox](TypeHDLR)
}

View File

@@ -16,11 +16,12 @@ func (m *MdiaBox) WriteTo(w io.Writer) (n int64, err error) {
return WriteTo(w, m.MDHD, m.MINF, m.HDLR) return WriteTo(w, m.MDHD, m.MINF, m.HDLR)
} }
func (m *MdiaBox) Unmarshal(buf []byte) (IBox, error) { func (m *MdiaBox) Unmarshal(buf []byte) (b IBox, err error) {
r := bytes.NewReader(buf)
for { for {
b, err := ReadFrom(bytes.NewReader(buf)) b, err = ReadFrom(r)
if err != nil { if err != nil {
return nil, err return m, err
} }
switch box := b.(type) { switch box := b.(type) {
case *MediaHeaderBox: case *MediaHeaderBox:
@@ -46,12 +47,10 @@ func (m *MediaInformationBox) WriteTo(w io.Writer) (n int64, err error) {
return WriteTo(w, m.VMHD, m.SMHD, m.HMHD, m.STBL, m.DINF) return WriteTo(w, m.VMHD, m.SMHD, m.HMHD, m.STBL, m.DINF)
} }
func (m *MediaInformationBox) Unmarshal(buf []byte) (IBox, error) { func (m *MediaInformationBox) Unmarshal(buf []byte) (b IBox, err error) {
for { r := bytes.NewReader(buf)
b, err := ReadFrom(bytes.NewReader(buf)) for err == nil {
if err != nil { b, err = ReadFrom(r)
return nil, err
}
switch box := b.(type) { switch box := b.(type) {
case *VideoMediaHeaderBox: case *VideoMediaHeaderBox:
m.VMHD = box m.VMHD = box
@@ -65,8 +64,10 @@ func (m *MediaInformationBox) Unmarshal(buf []byte) (IBox, error) {
m.DINF = box m.DINF = box
} }
} }
return m, err
} }
func init() { func init() {
RegisterBox[*MdiaBox](TypeMDIA) RegisterBox[*MdiaBox](TypeMDIA)
RegisterBox[*MediaInformationBox](TypeMINF)
} }

View File

@@ -30,11 +30,11 @@ func (m *MoovBox) WriteTo(w io.Writer) (n int64, err error) {
} }
func (m *MoovBox) Unmarshal(buf []byte) (IBox, error) { func (m *MoovBox) Unmarshal(buf []byte) (IBox, error) {
r := bytes.NewReader(buf)
for { for {
b, err := ReadFrom(bytes.NewReader(buf)) b, err := ReadFrom(r)
if err != nil { if err != nil {
return nil, err return m, err
} }
switch box := b.(type) { switch box := b.(type) {
case *TrakBox: case *TrakBox:
@@ -51,17 +51,19 @@ func (e *EdtsBox) WriteTo(w io.Writer) (n int64, err error) {
return WriteTo(w, e.Elst) return WriteTo(w, e.Elst)
} }
func (e *EdtsBox) Unmarshal(buf []byte) (IBox, error) { func (e *EdtsBox) Unmarshal(buf []byte) (b IBox, err error) {
for { r := bytes.NewReader(buf)
b, err := ReadFrom(bytes.NewReader(buf)) for err == nil {
b, err = ReadFrom(r)
if err != nil { if err != nil {
return nil, err return e, err
} }
switch box := b.(type) { switch box := b.(type) {
case *EditListBox: case *EditListBox:
e.Elst = box e.Elst = box
} }
} }
return e, err
} }
func init() { func init() {

View File

@@ -210,9 +210,9 @@ func (visual *VisualSampleEntry) Unmarshal(buf []byte) (IBox, error) {
visual.FrameCount = binary.BigEndian.Uint16(buf[16:]) visual.FrameCount = binary.BigEndian.Uint16(buf[16:])
copy(visual.Compressorname[:], buf[18:50]) copy(visual.Compressorname[:], buf[18:50])
visual.Depth = binary.BigEndian.Uint16(buf[50:]) visual.Depth = binary.BigEndian.Uint16(buf[50:])
// 52 pre-defined
if len(buf) > 52 { if len(buf) > 54 {
box, err := ReadFrom(bytes.NewReader(buf[52:])) box, err := ReadFrom(bytes.NewReader(buf[54:]))
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -38,12 +38,10 @@ func (t *TrakBox) WriteTo(w io.Writer) (n int64, err error) {
return WriteTo(w, t.MDIA, t.EDTS, t.TKHD) return WriteTo(w, t.MDIA, t.EDTS, t.TKHD)
} }
func (t *TrakBox) Unmarshal(buf []byte) (IBox, error) { func (t *TrakBox) Unmarshal(buf []byte) (b IBox, err error) {
for { r := bytes.NewReader(buf)
b, err := ReadFrom(bytes.NewReader(buf)) for err == nil {
if err != nil { b, err = ReadFrom(r)
return t, err
}
switch box := b.(type) { switch box := b.(type) {
case *MdiaBox: case *MdiaBox:
t.MDIA = box t.MDIA = box
@@ -53,6 +51,7 @@ func (t *TrakBox) Unmarshal(buf []byte) (IBox, error) {
t.TKHD = box t.TKHD = box
} }
} }
return t, err
} }
// ParseSamples parses the sample table and builds the sample list // ParseSamples parses the sample table and builds the sample list

View File

@@ -50,6 +50,7 @@ type (
IsFragment bool IsFragment bool
// pssh []*PsshBox // pssh []*PsshBox
moov *MoovBox moov *MoovBox
mdat *MediaDataBox
QuicTime bool QuicTime bool
} }
) )
@@ -94,11 +95,14 @@ func (d *Demuxer) Demux() (err error) {
// } // }
// return // return
// } // }
var b IBox
for { for {
b, err := box.ReadFrom(d.reader) b, err = box.ReadFrom(d.reader)
if err != nil { if err != nil {
break if err == io.EOF {
break
}
return err
} }
switch box := b.(type) { switch box := b.(type) {
case *FileTypeBox: case *FileTypeBox:
@@ -107,6 +111,7 @@ func (d *Demuxer) Demux() (err error) {
} }
case *FreeBox: case *FreeBox:
case *MediaDataBox: case *MediaDataBox:
d.mdat = box
case *MoovBox: case *MoovBox:
if box.MVEX != nil { if box.MVEX != nil {
d.IsFragment = true d.IsFragment = true

View File

@@ -0,0 +1,76 @@
package mp4
import (
"fmt"
"io"
"os"
"reflect"
"strings"
"testing"
"m7s.live/v5/plugin/mp4/pkg/box"
)
// TestDemuxerBoxTree tests the Demuxer by reading a test MP4 file and printing the box tree structure.
func TestDemuxerBoxTree(t *testing.T) {
// Open the test mp4 file. It is assumed to be located in 'testdata/test_regular.mp4'.
f, err := os.Open("/Users/dexter/project/v5/monibuca/example/default/dump/test_regular.mp4")
if err != nil {
t.Fatalf("failed to open test mp4 file: %v", err)
}
defer f.Close()
// Create a new Demuxer with the file reader
d := NewDemuxer(f)
// Call Demux to process the file; we don't use the result directly here.
err = d.Demux()
if err != nil {
t.Fatalf("demuxing failed: %v", err)
}
// Reset the file pointer to the beginning to re-read boxes for tree display
if _, err := f.Seek(0, 0); err != nil {
t.Fatalf("failed to seek to beginning: %v", err)
}
fmt.Println("MP4 Box Tree:")
// Read and print each top-level box
for {
b, err := box.ReadFrom(f)
if err != nil {
if err == io.EOF {
break
}
t.Fatalf("failed to read box: %v", err)
}
printBox(b, 0)
}
}
// printBox prints a box's type and size, and recursively prints its children if available.
func printBox(b interface{}, indent int) {
ind := strings.Repeat(" ", indent)
// Determine the box type name using reflection
typeOfBox := reflect.TypeOf(b)
if typeOfBox.Kind() == reflect.Ptr {
typeOfBox = typeOfBox.Elem()
}
// Try to get the size from a method Size() int
var size int
if s, ok := b.(interface{ Size() int }); ok {
size = s.Size()
}
fmt.Printf("%s%s (size: %d)\n", ind, typeOfBox.Name(), size)
// If the box is a container and has child boxes, print them recursively.
if container, ok := b.(interface{ ChildrenBoxes() []interface{} }); ok {
for _, child := range container.ChildrenBoxes() {
printBox(child, indent+1)
}
} else if container, ok := b.(interface{ ChildrenBoxes() []any }); ok {
for _, child := range container.ChildrenBoxes() {
printBox(child, indent+1)
}
}
}