Kirika/audio/format/aac/mp4.go
2022-04-23 20:41:14 +02:00

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
}
}