108 lines
2.1 KiB
Go
108 lines
2.1 KiB
Go
//go:build !disable_format_mp4
|
|
// +build !disable_format_mp4
|
|
|
|
package aac
|
|
|
|
import (
|
|
"bytes"
|
|
"github.com/edgeware/mp4ff/mp4"
|
|
"io"
|
|
)
|
|
|
|
import (
|
|
"errors"
|
|
)
|
|
|
|
type mp4Decoder struct {
|
|
mp4 *mp4.File
|
|
reader io.ReadSeekCloser
|
|
trackId uint32
|
|
cookie []byte
|
|
|
|
currentSegment int
|
|
currentFragment int
|
|
currentSample uint32
|
|
}
|
|
|
|
func tryDecodeMP4(r io.ReadSeekCloser) (*mp4Decoder, error) {
|
|
//TODO: mp4.DecModeLazyMdat errors in segmented files
|
|
parsedMp4, err := mp4.DecodeFile(r, mp4.WithDecodeMode(mp4.DecModeNormal))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var trackId uint32
|
|
var magicCookie []byte
|
|
|
|
for _, trak := range parsedMp4.Moov.Traks {
|
|
if box, err := trak.Mdia.Minf.Stbl.Stsd.GetSampleDescription(0); err == nil && box.Type() == "mp4a" {
|
|
if aseb, ok := box.(*mp4.AudioSampleEntryBox); ok {
|
|
trackId = trak.Tkhd.TrackID
|
|
magicCookie = aseb.Esds.DecConfig
|
|
break
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
if magicCookie == nil {
|
|
return nil, errors.New("could not find track entry")
|
|
}
|
|
|
|
return &mp4Decoder{
|
|
reader: r,
|
|
mp4: parsedMp4,
|
|
cookie: magicCookie,
|
|
trackId: trackId,
|
|
currentSample: 1,
|
|
}, nil
|
|
}
|
|
|
|
func (d *mp4Decoder) Read() (samples [][]byte) {
|
|
if d.mp4.IsFragmented() {
|
|
if d.currentSegment >= len(d.mp4.Segments) {
|
|
//EOF
|
|
return nil
|
|
}
|
|
segment := d.mp4.Segments[d.currentSegment]
|
|
|
|
if d.currentFragment >= len(segment.Fragments) {
|
|
d.currentSegment++
|
|
d.currentFragment = 0
|
|
return d.Read()
|
|
}
|
|
|
|
frag := segment.Fragments[d.currentFragment]
|
|
|
|
fullSamples, err := frag.GetFullSamples(&mp4.TrexBox{
|
|
TrackID: d.trackId,
|
|
})
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
|
|
for _, sample := range fullSamples {
|
|
samples = append(samples, sample.Data)
|
|
}
|
|
d.currentFragment++
|
|
|
|
return
|
|
} else {
|
|
if d.mp4.Mdat.Data == nil {
|
|
return nil
|
|
}
|
|
for _, trak := range d.mp4.Moov.Traks {
|
|
if trak.Tkhd.TrackID == d.trackId {
|
|
buf := new(bytes.Buffer)
|
|
if err := d.mp4.CopySampleData(buf, d.reader, trak, d.currentSample, d.currentSample); err != nil || buf.Len() == 0 {
|
|
return nil
|
|
}
|
|
d.currentSample++
|
|
|
|
return [][]byte{buf.Bytes()}
|
|
}
|
|
}
|
|
return
|
|
}
|
|
}
|