Shortcut asking Decoder for current position, replace panics with errors (#43)

This change
* adds a shortcut to get the current position by Seek for performance
* replaces panics with errors so that go-mp3 behaves more gracefully
This commit is contained in:
gonutz 2021-04-07 16:55:13 +02:00 committed by GitHub
parent cc618d1297
commit 00f4ca53d8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 31 additions and 13 deletions

View file

@ -15,7 +15,7 @@
package mp3
import (
"fmt"
"errors"
"io"
"github.com/hajimehoshi/go-mp3/internal/consts"
@ -69,8 +69,17 @@ func (d *Decoder) Read(buf []byte) (int, error) {
// Seek is io.Seeker's Seek.
//
// Seek panics when the underlying source is not io.Seeker.
// Seek returns an error when the underlying source is not io.Seeker.
//
// Note that seek uses a byte offset but samples are aligned to 4 bytes (2
// channels, 2 bytes each). Be careful to seek to an offset that is divisible by
// 4 if you want to read at full sample boundaries.
func (d *Decoder) Seek(offset int64, whence int) (int64, error) {
if offset == 0 && whence == io.SeekCurrent {
// Handle the special case of asking for the current position specially.
return d.pos, nil
}
npos := int64(0)
switch whence {
case io.SeekStart:
@ -80,7 +89,7 @@ func (d *Decoder) Seek(offset int64, whence int) (int64, error) {
case io.SeekEnd:
npos = d.Length() + offset
default:
panic(fmt.Sprintf("mp3: invalid whence: %v", whence))
return 0, errors.New("mp3: invalid whence")
}
d.pos = npos
d.buf = nil

View file

@ -15,6 +15,7 @@
package frameheader
import (
"errors"
"fmt"
"io"
@ -49,16 +50,16 @@ func (f FrameHeader) SamplingFrequency() consts.SamplingFrequency {
return consts.SamplingFrequency(int(f&0x00000c00) >> 10)
}
func (f FrameHeader) SamplingFrequencyValue() int {
func (f FrameHeader) SamplingFrequencyValue() (int, error) {
switch f.SamplingFrequency() {
case 0:
return 44100 >> uint(f.LowSamplingFrequency())
return 44100 >> uint(f.LowSamplingFrequency()), nil
case 1:
return 48000 >> uint(f.LowSamplingFrequency())
return 48000 >> uint(f.LowSamplingFrequency()), nil
case 2:
return 32000 >> uint(f.LowSamplingFrequency())
return 32000 >> uint(f.LowSamplingFrequency()), nil
}
panic("not reached")
return 0, errors.New("mp3: frame header has invalid sample frequency")
}
// PaddingBit returns the padding bit stored in position 9
@ -185,10 +186,14 @@ func (f FrameHeader) Bitrate() int {
return bitrates[f.LowSamplingFrequency()][f.Layer()-1][f.BitrateIndex()]
}
func (f FrameHeader) FrameSize() int {
return ((144*f.Bitrate())/
f.SamplingFrequencyValue() +
func (f FrameHeader) FrameSize() (int, error) {
freq, err := f.SamplingFrequencyValue()
if err != nil {
return 0, err
}
size := ((144*f.Bitrate())/freq +
int(f.PaddingBit())) >> uint(f.LowSamplingFrequency())
return size, nil
}
func (f FrameHeader) SideInfoSize() int {

View file

@ -64,7 +64,10 @@ var sideInfoBitsToRead = [2][4]int{
func Read(source FullReader, header frameheader.FrameHeader) (*SideInfo, error) {
nch := header.NumberOfChannels()
framesize := header.FrameSize()
framesize, err := header.FrameSize()
if err != nil {
return nil, err
}
if framesize > 2000 {
return nil, fmt.Errorf("mp3: framesize = %d\n", framesize)
}

View file

@ -15,6 +15,7 @@
package mp3
import (
"errors"
"io"
)
@ -27,7 +28,7 @@ type source struct {
func (s *source) Seek(position int64, whence int) (int64, error) {
seeker, ok := s.reader.(io.Seeker)
if !ok {
panic("mp3: source must be io.Seeker")
return 0, errors.New("mp3: source must be io.Seeker")
}
s.buf = nil
n, err := seeker.Seek(position, whence)