package go_alac import ( "github.com/edgeware/mp4ff/bits" "github.com/edgeware/mp4ff/mp4" "io" "time" ) type FormatEncoder struct { encoder *FrameEncoder writer io.Writer buffer []byte segmentDuration int64 trackId uint32 seqNumber uint32 } type alacBox struct { cookie []byte } func (b *alacBox) Type() string { return "alac" } // Size - calculated size of box func (b *alacBox) Size() uint64 { return uint64(12 + len(b.cookie)) } // Encode - write box to w func (b *alacBox) Encode(w io.Writer) error { sw := bits.NewFixedSliceWriter(int(b.Size())) err := b.EncodeSW(sw) if err != nil { return err } _, err = w.Write(sw.Bytes()) return err } func (b *alacBox) EncodeSW(sw bits.SliceWriter) error { err := mp4.EncodeHeaderSW(b, sw) if err != nil { return err } sw.WriteUint32(0) //version sw.WriteBytes(b.cookie) return sw.AccError() } func (b *alacBox) Info(w io.Writer, specificBoxLevels, indent, indentStep string) error { return nil } func NewFormatEncoder(writer io.Writer, sampleRate, channels, bitDepth int, fastMode bool, segmentDuration time.Duration) *FormatEncoder { e := &FormatEncoder{ encoder: NewFrameEncoder(sampleRate, channels, bitDepth, fastMode), writer: writer, segmentDuration: segmentDuration.Milliseconds(), } if e.encoder == nil { return nil } init := mp4.CreateEmptyInit() init.AddEmptyTrack(uint32(sampleRate), "audio", "en") e.trackId = init.Moov.Mvhd.NextTrackID - 1 trak := init.Moov.Trak stsd := trak.Mdia.Minf.Stbl.Stsd //TODO: this does not work with 96kHz freq etc. mp4a := mp4.CreateAudioSampleEntryBox("alac", uint16(channels), uint16(bitDepth), uint16(sampleRate), &alacBox{ cookie: e.encoder.GetMagicCookie(), }) stsd.AddChild(mp4a) init.Encode(writer) return e } func (e *FormatEncoder) outputPacket(packet []byte) { //TODO: more frames seg := mp4.NewMediaSegment() frag, _ := mp4.CreateFragment(e.seqNumber, e.trackId) seg.AddFragment(frag) frag.AddFullSampleToTrack(mp4.FullSample{ Sample: mp4.Sample{ Dur: 4096, //TODO Size: uint32(len(packet)), }, DecodeTime: uint64(4096 * e.seqNumber), Data: packet, }, e.trackId) seg.Encode(e.writer) e.seqNumber++ } func (e *FormatEncoder) Write(pcm []byte) { if e.encoder == nil { return } e.buffer = append(e.buffer, pcm...) inputSize := e.encoder.GetInputSize() for len(e.buffer) >= inputSize { e.outputPacket(e.encoder.WritePacket(e.buffer[:inputSize])) e.buffer = e.buffer[inputSize:] } } func (e *FormatEncoder) Flush() { if e.encoder == nil { return } if len(e.buffer) > 0 { e.outputPacket(e.encoder.WritePacket(e.buffer)) e.buffer = nil } //TODO: flush end }