libflac: Add seek and tell callbacks to encoder

This allows the encoder to update the STREAMINFO correctly.
This commit is contained in:
Will Newton 2015-05-13 14:35:41 +01:00
parent 1f685aa3b0
commit 876bdde887
2 changed files with 59 additions and 4 deletions

View file

@ -54,6 +54,22 @@ encoderWriteCallback_cgo(const FLAC__StreamEncoder *encoder,
data);
}
FLAC__StreamEncoderSeekStatus
encoderSeekCallback_cgo(const FLAC__StreamEncoder *encoder,
FLAC__uint64 absolute_byte_offset,
void *data)
{
return encoderSeekCallback(encoder, absolute_byte_offset, data);
}
FLAC__StreamEncoderTellStatus
encoderTellCallback_cgo(const FLAC__StreamEncoder *encoder,
FLAC__uint64 *absolute_byte_offset,
void *data)
{
return encoderTellCallback(encoder, absolute_byte_offset, data);
}
extern const char *
get_decoder_error_str(FLAC__StreamDecoderErrorStatus status)
{

View file

@ -51,6 +51,15 @@ encoderWriteCallback_cgo(const FLAC__StreamEncoder *,
unsigned,
void *);
FLAC__StreamEncoderSeekStatus
encoderSeekCallback_cgo(const FLAC__StreamEncoder *,
FLAC__uint64,
void *);
FLAC__StreamEncoderTellStatus
encoderTellCallback_cgo(const FLAC__StreamEncoder *,
FLAC__uint64 *,
void *);
extern const char *
get_decoder_error_str(FLAC__StreamDecoderErrorStatus status);
@ -71,6 +80,12 @@ get_audio_samples(int32_t *output, const FLAC__int32 **input,
*/
import "C"
type FlacWriter interface {
io.Writer
io.Closer
io.Seeker
}
// Frame is an interleaved buffer of audio data with the specified parameters.
type Frame struct {
Channels int
@ -94,7 +109,7 @@ type Decoder struct {
// Encoder is a FLAC encoder.
type Encoder struct {
e *C.FLAC__StreamEncoder
writer io.WriteCloser
writer FlacWriter
Channels int
Depth int
Rate int
@ -281,8 +296,29 @@ func encoderWriteCallback(e *C.FLAC__StreamEncoder, buffer *C.FLAC__byte, bytes
return C.FLAC__STREAM_ENCODER_WRITE_STATUS_OK
}
// NewEncoderWriter creates a new Encoder object from a Writer.
func NewEncoderWriter(writer io.WriteCloser, channels int, depth int, rate int) (e *Encoder, err error) {
//export encoderSeekCallback
func encoderSeekCallback(e *C.FLAC__StreamEncoder, absPos C.FLAC__uint64, data unsafe.Pointer) C.FLAC__StreamEncoderWriteStatus {
encoder := (*Encoder)(data)
_, err := encoder.writer.Seek(int64(absPos), 0)
if err != nil {
return C.FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR
}
return C.FLAC__STREAM_ENCODER_SEEK_STATUS_OK
}
//export encoderTellCallback
func encoderTellCallback(e *C.FLAC__StreamEncoder, absPos *C.FLAC__uint64, data unsafe.Pointer) C.FLAC__StreamEncoderWriteStatus {
encoder := (*Encoder)(data)
newPos, err := encoder.writer.Seek(0, 1)
if err != nil {
return C.FLAC__STREAM_ENCODER_TELL_STATUS_ERROR
}
*absPos = C.FLAC__uint64(newPos)
return C.FLAC__STREAM_ENCODER_TELL_STATUS_OK
}
// NewEncoderWriter creates a new Encoder object from a FlacWriter.
func NewEncoderWriter(writer FlacWriter, channels int, depth int, rate int) (e *Encoder, err error) {
if channels == 0 {
return nil, errors.New("channels must be greater than 0")
}
@ -300,7 +336,10 @@ func NewEncoderWriter(writer io.WriteCloser, channels int, depth int, rate int)
C.FLAC__stream_encoder_set_bits_per_sample(e.e, C.uint(depth))
C.FLAC__stream_encoder_set_sample_rate(e.e, C.uint(rate))
status := C.FLAC__stream_encoder_init_stream(e.e,
(C.FLAC__StreamEncoderWriteCallback)(unsafe.Pointer(C.encoderWriteCallback_cgo)), nil, nil, nil, unsafe.Pointer(e))
(C.FLAC__StreamEncoderWriteCallback)(unsafe.Pointer(C.encoderWriteCallback_cgo)),
(C.FLAC__StreamEncoderSeekCallback)(unsafe.Pointer(C.encoderSeekCallback_cgo)),
(C.FLAC__StreamEncoderTellCallback)(unsafe.Pointer(C.encoderTellCallback_cgo)),
nil, unsafe.Pointer(e))
if status != C.FLAC__STREAM_ENCODER_INIT_STATUS_OK {
return nil, errors.New("failed to open file")
}