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:
parent
cc618d1297
commit
00f4ca53d8
15
decode.go
15
decode.go
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue