API change: add WriteCloser encoder api, add streamable, compression level, block size parameters
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
DataHoarder 2022-02-23 16:27:28 +01:00
parent 104c7240cc
commit 4a6d617742
2 changed files with 111 additions and 13 deletions

View file

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

View file

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