diff --git a/encoder.go b/encoder.go index 48f9cf2..22ccddf 100644 --- a/encoder.go +++ b/encoder.go @@ -44,6 +44,10 @@ func (e *FrameEncoder) GetInputSize() int { return int(e.handle.input_packet_size) } +func (e *FrameEncoder) GetSamplesPerPacket() int { + return int(e.handle.frames_per_packet) +} + func (e *FrameEncoder) WritePacket(pcm []byte) []byte { output := make([]byte, int(e.handle.output_max_packet_size)) outBytes := C.alac_encoder_write(&e.handle, (*C.uchar)(unsafe.Pointer(&pcm[0])), C.int(len(pcm)), (*C.uchar)(unsafe.Pointer(&output[0]))) diff --git a/mp4.go b/mp4.go index 27ecdf3..e287132 100644 --- a/mp4.go +++ b/mp4.go @@ -8,12 +8,16 @@ import ( ) type FormatEncoder struct { - encoder *FrameEncoder - writer io.Writer - buffer []byte - segmentDuration int64 - trackId uint32 - seqNumber uint32 + encoder *FrameEncoder + writer io.Writer + sampleRate int + buffer []byte + outputBuffer [][]byte + segmentDuration time.Duration + samplesPerPacket int + packetsWritten int + trackId uint32 + seqNumber uint32 } type alacBox struct { @@ -58,13 +62,16 @@ func NewFormatEncoder(writer io.Writer, sampleRate, channels, bitDepth int, fast e := &FormatEncoder{ encoder: NewFrameEncoder(sampleRate, channels, bitDepth, fastMode), writer: writer, - segmentDuration: segmentDuration.Milliseconds(), + sampleRate: sampleRate, + segmentDuration: segmentDuration, } if e.encoder == nil { return nil } + e.samplesPerPacket = e.encoder.GetSamplesPerPacket() + init := mp4.CreateEmptyInit() init.AddEmptyTrack(uint32(sampleRate), "audio", "en") e.trackId = init.Moov.Mvhd.NextTrackID - 1 @@ -84,21 +91,39 @@ func NewFormatEncoder(writer io.Writer, sampleRate, channels, bitDepth int, fast } func (e *FormatEncoder) outputPacket(packet []byte) { - //TODO: more frames + e.outputBuffer = append(e.outputBuffer, packet) + + if time.Duration(float64(time.Second)*(float64(e.samplesPerPacket*len(e.outputBuffer))/float64(e.sampleRate))) >= e.segmentDuration { + e.outputSegment() + } + +} + +func (e *FormatEncoder) outputSegment() { + if len(e.outputBuffer) == 0 { + return + } + 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) + + for _, b := range e.outputBuffer { + frag.AddFullSampleToTrack(mp4.FullSample{ + Sample: mp4.Sample{ + Dur: uint32(e.samplesPerPacket), + Size: uint32(len(b)), + }, + DecodeTime: uint64(e.samplesPerPacket * e.packetsWritten), + Data: b, + }, e.trackId) + e.packetsWritten++ + } seg.Encode(e.writer) e.seqNumber++ + e.outputBuffer = nil + } func (e *FormatEncoder) Write(pcm []byte) { diff --git a/mp4_test.go b/mp4_test.go index 2d601c5..1cd3e01 100644 --- a/mp4_test.go +++ b/mp4_test.go @@ -30,7 +30,7 @@ func TestEncodeMP4(t *testing.T) { } defer o.Close() - encoder := NewFormatEncoder(o, 44100, 2, 16, false, time.Second) + encoder := NewFormatEncoder(o, 44100, 2, 16, false, time.Millisecond*100) iterationSize := 65536 for len(data) > iterationSize {