API change: add WriteCloser encoder api, add streamable, compression level, block size parameters
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
104c7240cc
commit
4a6d617742
80
libflac.go
80
libflac.go
|
@ -167,11 +167,12 @@ type Decoder struct {
|
|||
|
||||
// Encoder is a FLAC encoder.
|
||||
type Encoder struct {
|
||||
e *C.FLAC__StreamEncoder
|
||||
writer FlacWriter
|
||||
Channels int
|
||||
Depth int
|
||||
Rate int
|
||||
e *C.FLAC__StreamEncoder
|
||||
writer io.WriteCloser
|
||||
writeSeeker FlacWriter
|
||||
Channels int
|
||||
Depth int
|
||||
Rate int
|
||||
}
|
||||
|
||||
//export decoderErrorCallback
|
||||
|
@ -362,7 +363,10 @@ func encoderWriteCallback(e *C.FLAC__StreamEncoder, buffer *C.FLAC__byte, bytes
|
|||
//export encoderSeekCallback
|
||||
func encoderSeekCallback(e *C.FLAC__StreamEncoder, absPos C.FLAC__uint64, data unsafe.Pointer) C.FLAC__StreamEncoderWriteStatus {
|
||||
encoder := encoderPtrs.get(e)
|
||||
_, err := encoder.writer.Seek(int64(absPos), 0)
|
||||
if encoder.writeSeeker == nil {
|
||||
return C.FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR
|
||||
}
|
||||
_, err := encoder.writeSeeker.Seek(int64(absPos), 0)
|
||||
if err != nil {
|
||||
return C.FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR
|
||||
}
|
||||
|
@ -372,7 +376,10 @@ func encoderSeekCallback(e *C.FLAC__StreamEncoder, absPos C.FLAC__uint64, data u
|
|||
//export encoderTellCallback
|
||||
func encoderTellCallback(e *C.FLAC__StreamEncoder, absPos *C.FLAC__uint64, data unsafe.Pointer) C.FLAC__StreamEncoderWriteStatus {
|
||||
encoder := encoderPtrs.get(e)
|
||||
newPos, err := encoder.writer.Seek(0, 1)
|
||||
if encoder.writeSeeker == nil {
|
||||
return C.FLAC__STREAM_ENCODER_TELL_STATUS_ERROR
|
||||
}
|
||||
newPos, err := encoder.writeSeeker.Seek(0, 1)
|
||||
if err != nil {
|
||||
return C.FLAC__STREAM_ENCODER_TELL_STATUS_ERROR
|
||||
}
|
||||
|
@ -380,8 +387,50 @@ func encoderTellCallback(e *C.FLAC__StreamEncoder, absPos *C.FLAC__uint64, data
|
|||
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) {
|
||||
// NewEncoderWriteSeeker creates a new Encoder object from a FlacWriter.
|
||||
func NewEncoderWriteSeeker(writer FlacWriter, channels int, depth int, rate int, compressionLevel int, streamable bool, blockSize int) (e *Encoder, err error) {
|
||||
if channels == 0 {
|
||||
return nil, errors.New("channels must be greater than 0")
|
||||
}
|
||||
if !(depth == 16 || depth == 24) {
|
||||
return nil, errors.New("depth must be 16 or 24")
|
||||
}
|
||||
e = new(Encoder)
|
||||
e.e = C.FLAC__stream_encoder_new()
|
||||
if e.e == nil {
|
||||
return nil, errors.New("failed to create decoder")
|
||||
}
|
||||
encoderPtrs.add(e)
|
||||
e.writer = writer
|
||||
e.writeSeeker = writer
|
||||
runtime.SetFinalizer(e, (*Encoder).Close)
|
||||
|
||||
C.FLAC__stream_encoder_set_channels(e.e, C.uint(channels))
|
||||
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))
|
||||
C.FLAC__stream_encoder_set_compression_level(e.e, C.uint(compressionLevel))
|
||||
C.FLAC__stream_encoder_set_blocksize(e.e, C.uint(blockSize))
|
||||
if streamable {
|
||||
C.FLAC__stream_encoder_set_streamable_subset(e.e, C.FLAC__bool(1))
|
||||
} else {
|
||||
C.FLAC__stream_encoder_set_streamable_subset(e.e, C.FLAC__bool(0))
|
||||
}
|
||||
status := C.FLAC__stream_encoder_init_stream(e.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, nil)
|
||||
if status != C.FLAC__STREAM_ENCODER_INIT_STATUS_OK {
|
||||
return nil, fmt.Errorf("failed to open file, status = %d, state = %d", int(status), int(C.FLAC__stream_encoder_get_state(e.e)))
|
||||
}
|
||||
e.Channels = channels
|
||||
e.Depth = depth
|
||||
e.Rate = rate
|
||||
return
|
||||
}
|
||||
|
||||
// NewEncoderWriter creates a new Encoder object from an io.WriteCloser.
|
||||
func NewEncoderWriter(writer io.WriteCloser, channels int, depth int, rate int, compressionLevel int, streamable bool, blockSize int) (e *Encoder, err error) {
|
||||
if channels == 0 {
|
||||
return nil, errors.New("channels must be greater than 0")
|
||||
}
|
||||
|
@ -399,13 +448,20 @@ func NewEncoderWriter(writer FlacWriter, channels int, depth int, rate int) (e *
|
|||
C.FLAC__stream_encoder_set_channels(e.e, C.uint(channels))
|
||||
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))
|
||||
C.FLAC__stream_encoder_set_compression_level(e.e, C.uint(compressionLevel))
|
||||
C.FLAC__stream_encoder_set_blocksize(e.e, C.uint(blockSize))
|
||||
if streamable {
|
||||
C.FLAC__stream_encoder_set_streamable_subset(e.e, C.FLAC__bool(1))
|
||||
} else {
|
||||
C.FLAC__stream_encoder_set_streamable_subset(e.e, C.FLAC__bool(0))
|
||||
}
|
||||
status := C.FLAC__stream_encoder_init_stream(e.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,
|
||||
nil,
|
||||
nil, nil)
|
||||
if status != C.FLAC__STREAM_ENCODER_INIT_STATUS_OK {
|
||||
return nil, errors.New("failed to open file")
|
||||
return nil, fmt.Errorf("failed to open file, status = %d, state = %d", int(status), int(C.FLAC__stream_encoder_get_state(e.e)))
|
||||
}
|
||||
e.Channels = channels
|
||||
e.Depth = depth
|
||||
|
|
|
@ -230,7 +230,49 @@ func TestRoundTripReaderWriter(t *testing.T) {
|
|||
|
||||
writer, _ := os.Create(outputFile)
|
||||
|
||||
e, err := NewEncoderWriter(writer, d.Channels, d.Depth, d.Rate)
|
||||
e, err := NewEncoderWriter(writer, d.Channels, d.Depth, d.Rate, 8, true, 0)
|
||||
|
||||
samples := 0
|
||||
|
||||
for {
|
||||
f, err := d.ReadFrame()
|
||||
if err == nil || err == io.EOF {
|
||||
if f != nil {
|
||||
_ = e.WriteFrame(*f)
|
||||
samples = samples + len(f.Buffer)
|
||||
}
|
||||
} else {
|
||||
a.Equal(err, nil, "error reported")
|
||||
break
|
||||
}
|
||||
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
a.Equal(samples, 200000, "all samples read")
|
||||
d.Close()
|
||||
e.Close()
|
||||
|
||||
os.Remove(outputFile)
|
||||
}
|
||||
|
||||
func TestRoundTripReaderWriterSeeker(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
|
||||
inputFile := "testdata/sine24-00.flac"
|
||||
outputFile := "testdata/test-seek.flac"
|
||||
|
||||
reader, _ := os.Open(inputFile)
|
||||
|
||||
d, err := NewDecoderReader(reader)
|
||||
|
||||
a.Equal(err, nil, "err is nil")
|
||||
|
||||
writer, _ := os.Create(outputFile)
|
||||
|
||||
e, err := NewEncoderWriteSeeker(writer, d.Channels, d.Depth, d.Rate, 8, false, 0)
|
||||
|
||||
samples := 0
|
||||
|
||||
|
|
Loading…
Reference in a new issue