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
|
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.
|
// NewDecoderReader creates a new Decoder object from a Reader.
|
||||||
func NewDecoderReader(reader io.ReadCloser) (d *Decoder, err error) {
|
func NewDecoderReader(reader io.ReadCloser) (d *Decoder, err error) {
|
||||||
d = new(Decoder)
|
d = new(Decoder)
|
||||||
|
@ -282,6 +308,33 @@ func NewDecoderReader(reader io.ReadCloser) (d *Decoder, err error) {
|
||||||
return
|
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.
|
// Close closes a decoder and frees the resources.
|
||||||
func (d *Decoder) Close() {
|
func (d *Decoder) Close() {
|
||||||
if d.d != nil {
|
if d.d != nil {
|
||||||
|
|
|
@ -58,6 +58,52 @@ func TestDecode(t *testing.T) {
|
||||||
d.Close()
|
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) {
|
func TestDecodeReader(t *testing.T) {
|
||||||
a := assert.New(t)
|
a := assert.New(t)
|
||||||
|
|
||||||
|
@ -109,6 +155,57 @@ func TestDecodeReader(t *testing.T) {
|
||||||
d.Close()
|
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) {
|
func TestEncode(t *testing.T) {
|
||||||
a := assert.New(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