1
1
mirror of https://github.com/wader/fq.git synced 2024-11-27 14:14:58 +03:00
fq/pkg/bitio/multireader.go
Mattias Wadman 7b27e506f1 mp4,bitio: Fix broken pssh decoding and add proper reader cloning to bitio
PSSH decoding probably got broken in some refactoring. system id is 16 bytes,
also scalar mapper should use cloned reader to not affect reader which in the case
broke reading system id bytes.

Add test with playread and widevine pssh boxes

Related to #282
2022-05-28 13:42:38 +02:00

130 lines
2.4 KiB
Go

package bitio
import (
"errors"
"io"
)
// TODO: smarter, track index?
func endPos(rs Seeker) (int64, error) {
c, err := rs.SeekBits(0, io.SeekCurrent)
if err != nil {
return 0, err
}
e, err := rs.SeekBits(0, io.SeekEnd)
if err != nil {
return 0, err
}
_, err = rs.SeekBits(c, io.SeekStart)
if err != nil {
return 0, err
}
return e, nil
}
// MultiReader is a bitio.ReaderAtSeeker concatinating multiple bitio.ReadAtSeeker:s.
// Similar to io.MultiReader.
type MultiReader struct {
pos int64
readers []ReadAtSeeker
readerEnds []int64
}
// NewMultiReader returns a new bitio.MultiReader.
func NewMultiReader(rs ...ReadAtSeeker) (*MultiReader, error) {
readerEnds := make([]int64, len(rs))
var esSum int64
for i, r := range rs {
e, err := endPos(r)
if err != nil {
return nil, err
}
esSum += e
readerEnds[i] = esSum
}
return &MultiReader{readers: rs, readerEnds: readerEnds}, nil
}
func (m *MultiReader) ReadBitsAt(p []byte, nBits int64, bitOff int64) (n int64, err error) {
var end int64
if len(m.readers) > 0 {
end = m.readerEnds[len(m.readers)-1]
}
if end <= bitOff {
return 0, io.EOF
}
prevAtEnd := int64(0)
readerAt := m.readers[0]
for i, end := range m.readerEnds {
if bitOff < end {
readerAt = m.readers[i]
break
}
prevAtEnd = end
}
rBits, err := readerAt.ReadBitsAt(p, nBits, bitOff-prevAtEnd)
if errors.Is(err, io.EOF) {
if bitOff+rBits < end {
err = nil
}
}
return rBits, err
}
func (m *MultiReader) ReadBits(p []byte, nBits int64) (n int64, err error) {
n, err = m.ReadBitsAt(p, nBits, m.pos)
m.pos += n
return n, err
}
func (m *MultiReader) SeekBits(bitOff int64, whence int) (int64, error) {
var p int64
var end int64
if len(m.readers) > 0 {
end = m.readerEnds[len(m.readers)-1]
}
switch whence {
case io.SeekStart:
p = bitOff
case io.SeekCurrent:
p = m.pos + bitOff
case io.SeekEnd:
p = end + bitOff
default:
panic("unknown whence")
}
if p < 0 || p > end {
return 0, ErrOffset
}
m.pos = p
return p, nil
}
func (m *MultiReader) CloneReader() (Reader, error) {
return m.CloneReaderAtSeeker()
}
func (m *MultiReader) CloneReadSeeker() (ReadSeeker, error) {
return m.CloneReaderAtSeeker()
}
func (m *MultiReader) CloneReadAtSeeker() (ReadAtSeeker, error) {
return m.CloneReaderAtSeeker()
}
func (m *MultiReader) CloneReaderAtSeeker() (ReaderAtSeeker, error) {
return &MultiReader{
pos: 0,
readers: m.readers,
readerEnds: m.readerEnds,
}, nil
}