Added support for Ogg decoding
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
DataHoarder 2022-03-05 10:34:19 +01:00
parent 827e6c3f72
commit 2fd5e32855
3 changed files with 150 additions and 0 deletions

View file

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

View file

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

Binary file not shown.