Added support for Ogg decoding
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
827e6c3f72
commit
2fd5e32855
53
libflac.go
53
libflac.go
|
@ -255,6 +255,32 @@ func NewDecoder(name string) (d *Decoder, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
// NewDecoderOgg creates a new Decoder object.
|
||||
func NewDecoderOgg(name string) (d *Decoder, err error) {
|
||||
d = new(Decoder)
|
||||
d.d = C.FLAC__stream_decoder_new()
|
||||
if d.d == nil {
|
||||
return nil, errors.New("failed to create decoder")
|
||||
}
|
||||
c := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(c))
|
||||
runtime.SetFinalizer(d, (*Decoder).Close)
|
||||
status := C.FLAC__stream_decoder_init_ogg_file(d.d, c,
|
||||
(C.FLAC__StreamDecoderWriteCallback)(unsafe.Pointer(C.decoderWriteCallback_cgo)),
|
||||
(C.FLAC__StreamDecoderMetadataCallback)(unsafe.Pointer(C.decoderMetadataCallback_cgo)),
|
||||
(C.FLAC__StreamDecoderErrorCallback)(unsafe.Pointer(C.decoderErrorCallback_cgo)),
|
||||
nil)
|
||||
if status != C.FLAC__STREAM_DECODER_INIT_STATUS_OK {
|
||||
return nil, errors.New("failed to open file")
|
||||
}
|
||||
decoderPtrs.add(d)
|
||||
ret := C.FLAC__stream_decoder_process_until_end_of_metadata(d.d)
|
||||
if ret == 0 || d.error || d.Channels == 0 {
|
||||
return nil, fmt.Errorf("failed to process metadata %s", d.errorStr)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// NewDecoderReader creates a new Decoder object from a Reader.
|
||||
func NewDecoderReader(reader io.ReadCloser) (d *Decoder, err error) {
|
||||
d = new(Decoder)
|
||||
|
@ -282,6 +308,33 @@ func NewDecoderReader(reader io.ReadCloser) (d *Decoder, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
// NewDecoderReaderOgg creates a new Decoder object from a Reader of Ogg.
|
||||
func NewDecoderReaderOgg(reader io.ReadCloser) (d *Decoder, err error) {
|
||||
d = new(Decoder)
|
||||
d.d = C.FLAC__stream_decoder_new()
|
||||
if d.d == nil {
|
||||
return nil, errors.New("failed to create decoder")
|
||||
}
|
||||
d.reader = reader
|
||||
runtime.SetFinalizer(d, (*Decoder).Close)
|
||||
status := C.FLAC__stream_decoder_init_ogg_stream(d.d,
|
||||
(C.FLAC__StreamDecoderReadCallback)(unsafe.Pointer(C.decoderReadCallback_cgo)),
|
||||
nil, nil, nil, nil,
|
||||
(C.FLAC__StreamDecoderWriteCallback)(unsafe.Pointer(C.decoderWriteCallback_cgo)),
|
||||
(C.FLAC__StreamDecoderMetadataCallback)(unsafe.Pointer(C.decoderMetadataCallback_cgo)),
|
||||
(C.FLAC__StreamDecoderErrorCallback)(unsafe.Pointer(C.decoderErrorCallback_cgo)),
|
||||
nil)
|
||||
if status != C.FLAC__STREAM_DECODER_INIT_STATUS_OK {
|
||||
return nil, errors.New("failed to open stream")
|
||||
}
|
||||
decoderPtrs.add(d)
|
||||
ret := C.FLAC__stream_decoder_process_until_end_of_metadata(d.d)
|
||||
if ret == 0 || d.error || d.Channels == 0 {
|
||||
return nil, fmt.Errorf("failed to process metadata %s", d.errorStr)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Close closes a decoder and frees the resources.
|
||||
func (d *Decoder) Close() {
|
||||
if d.d != nil {
|
||||
|
|
|
@ -58,6 +58,52 @@ func TestDecode(t *testing.T) {
|
|||
d.Close()
|
||||
}
|
||||
|
||||
func TestDecodeOgg(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
|
||||
d, err := NewDecoderOgg("testdata/nonexistent.ogg")
|
||||
a.Equal(d, (*Decoder)(nil), "decoder is nil")
|
||||
a.NotNil(err, "err is not nil")
|
||||
|
||||
d, err = NewDecoderOgg("testdata/sine24-00.ogg")
|
||||
|
||||
a.Equal(err, nil, "err is nil")
|
||||
a.Equal(d.Channels, 1, "channels is 1")
|
||||
a.Equal(d.Depth, 24, "depth is 24")
|
||||
a.Equal(d.Rate, 48000, "depth is 48000")
|
||||
|
||||
samples := 0
|
||||
|
||||
f, err := d.ReadFrame()
|
||||
|
||||
a.Equal(err, nil, "err is nil")
|
||||
a.Equal(f.Channels, 1, "channels is 1")
|
||||
a.Equal(f.Depth, 24, "depth is 24")
|
||||
a.Equal(f.Rate, 48000, "depth is 48000")
|
||||
|
||||
samples = samples + len(f.Buffer)
|
||||
|
||||
for {
|
||||
f, err := d.ReadFrame()
|
||||
|
||||
if err == nil || err == io.EOF {
|
||||
if f != nil {
|
||||
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()
|
||||
}
|
||||
|
||||
func TestDecodeReader(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
|
||||
|
@ -109,6 +155,57 @@ func TestDecodeReader(t *testing.T) {
|
|||
d.Close()
|
||||
}
|
||||
|
||||
func TestDecodeReaderOgg(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
|
||||
reader, _ := os.Open("testdata/nonexistent.ogg")
|
||||
|
||||
d, err := NewDecoderReaderOgg(reader)
|
||||
|
||||
a.Equal(d, (*Decoder)(nil), "decoder is nil")
|
||||
a.Error(err)
|
||||
|
||||
reader, _ = os.Open("testdata/sine24-00.ogg")
|
||||
|
||||
d, err = NewDecoderReaderOgg(reader)
|
||||
|
||||
a.Equal(err, nil, "err is nil")
|
||||
a.Equal(d.Channels, 1, "channels is 1")
|
||||
a.Equal(d.Depth, 24, "depth is 24")
|
||||
a.Equal(d.Rate, 48000, "depth is 48000")
|
||||
|
||||
samples := 0
|
||||
|
||||
f, err := d.ReadFrame()
|
||||
|
||||
a.Equal(err, nil, "err is nil")
|
||||
a.Equal(f.Channels, 1, "channels is 1")
|
||||
a.Equal(f.Depth, 24, "depth is 24")
|
||||
a.Equal(f.Rate, 48000, "depth is 48000")
|
||||
|
||||
samples = samples + len(f.Buffer)
|
||||
|
||||
for {
|
||||
f, err := d.ReadFrame()
|
||||
|
||||
if err == nil || err == io.EOF {
|
||||
if f != nil {
|
||||
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()
|
||||
}
|
||||
|
||||
func TestEncode(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
|
||||
|
|
BIN
testdata/sine24-00.ogg
vendored
Normal file
BIN
testdata/sine24-00.ogg
vendored
Normal file
Binary file not shown.
Loading…
Reference in a new issue