diff --git a/codec/aacparser/parser.go b/codec/aacparser/parser.go index 75a6449..6432574 100644 --- a/codec/aacparser/parser.go +++ b/codec/aacparser/parser.go @@ -1,7 +1,7 @@ package aacparser import ( - "github.com/nareix/bits" + "github.com/nareix/joy4/utils/bits" "github.com/nareix/joy4/av" "time" "fmt" diff --git a/codec/h264parser/parser.go b/codec/h264parser/parser.go index af66322..35c8d83 100644 --- a/codec/h264parser/parser.go +++ b/codec/h264parser/parser.go @@ -3,8 +3,8 @@ package h264parser import ( "github.com/nareix/joy4/av" - "github.com/nareix/bits" - "github.com/nareix/bits/pio" + "github.com/nareix/joy4/utils/bits" + "github.com/nareix/joy4/utils/bits/pio" "fmt" "bytes" ) diff --git a/format/flv/flv.go b/format/flv/flv.go index 694d980..6f07da6 100644 --- a/format/flv/flv.go +++ b/format/flv/flv.go @@ -3,7 +3,7 @@ package flv import ( "bufio" "fmt" - "github.com/nareix/bits/pio" + "github.com/nareix/joy4/utils/bits/pio" "github.com/nareix/joy4/av" "github.com/nareix/joy4/av/avutil" "github.com/nareix/joy4/codec" diff --git a/format/flv/flvio/amf0.go b/format/flv/flvio/amf0.go index ed605d1..05b4a03 100644 --- a/format/flv/flvio/amf0.go +++ b/format/flv/flvio/amf0.go @@ -5,7 +5,7 @@ import ( "math" "fmt" "time" - "github.com/nareix/bits/pio" + "github.com/nareix/joy4/utils/bits/pio" ) type AMF0ParseError struct { diff --git a/format/flv/flvio/flvio.go b/format/flv/flvio/flvio.go index eb063a5..aca0770 100644 --- a/format/flv/flvio/flvio.go +++ b/format/flv/flvio/flvio.go @@ -2,7 +2,7 @@ package flvio import ( "fmt" - "github.com/nareix/bits/pio" + "github.com/nareix/joy4/utils/bits/pio" "github.com/nareix/joy4/av" "io" "time" diff --git a/format/mp4/mp4io/atoms.go b/format/mp4/mp4io/atoms.go index 8818212..c90485c 100644 --- a/format/mp4/mp4io/atoms.go +++ b/format/mp4/mp4io/atoms.go @@ -1,6 +1,6 @@ package mp4io -import "github.com/nareix/bits/pio" +import "github.com/nareix/joy4/utils/bits/pio" import "time" const MOOF = Tag(0x6d6f6f66) diff --git a/format/mp4/mp4io/gen/gen.go b/format/mp4/mp4io/gen/gen.go index 1c9653e..1a2857f 100644 --- a/format/mp4/mp4io/gen/gen.go +++ b/format/mp4/mp4io/gen/gen.go @@ -967,7 +967,7 @@ func genatoms(filename, outfilename string) { &ast.GenDecl{ Tok: token.IMPORT, Specs: []ast.Spec{ - &ast.ImportSpec{Path: &ast.BasicLit{Kind: token.STRING, Value: `"github.com/nareix/bits/pio"`}}, + &ast.ImportSpec{Path: &ast.BasicLit{Kind: token.STRING, Value: `"github.com/nareix/joy4/utils/bits/pio"`}}, }, }, &ast.GenDecl{ diff --git a/format/mp4/mp4io/mp4io.go b/format/mp4/mp4io/mp4io.go index f604dfb..0227a84 100644 --- a/format/mp4/mp4io/mp4io.go +++ b/format/mp4/mp4io/mp4io.go @@ -2,7 +2,7 @@ package mp4io import ( - "github.com/nareix/bits/pio" + "github.com/nareix/joy4/utils/bits/pio" "os" "io" "fmt" diff --git a/format/mp4/muxer.go b/format/mp4/muxer.go index 342ecf6..d1ef7e0 100644 --- a/format/mp4/muxer.go +++ b/format/mp4/muxer.go @@ -7,7 +7,7 @@ import ( "github.com/nareix/joy4/codec/aacparser" "github.com/nareix/joy4/codec/h264parser" "github.com/nareix/joy4/format/mp4/mp4io" - "github.com/nareix/bits/pio" + "github.com/nareix/joy4/utils/bits/pio" "io" "bufio" ) diff --git a/format/rtmp/rtmp.go b/format/rtmp/rtmp.go index 2ba9847..d7cd56d 100644 --- a/format/rtmp/rtmp.go +++ b/format/rtmp/rtmp.go @@ -8,7 +8,7 @@ import ( "crypto/sha256" "encoding/hex" "fmt" - "github.com/nareix/bits/pio" + "github.com/nareix/joy4/utils/bits/pio" "github.com/nareix/joy4/av" "github.com/nareix/joy4/av/avutil" "github.com/nareix/joy4/format/flv" diff --git a/format/rtsp/client.go b/format/rtsp/client.go index c9fca83..5f57e4c 100644 --- a/format/rtsp/client.go +++ b/format/rtsp/client.go @@ -8,7 +8,7 @@ import ( "encoding/binary" "encoding/hex" "fmt" - "github.com/nareix/bits/pio" + "github.com/nareix/joy4/utils/bits/pio" "github.com/nareix/joy4/av" "github.com/nareix/joy4/av/avutil" "github.com/nareix/joy4/codec" diff --git a/format/ts/demuxer.go b/format/ts/demuxer.go index 20cb0be..df9c0cf 100644 --- a/format/ts/demuxer.go +++ b/format/ts/demuxer.go @@ -4,7 +4,7 @@ import ( "bufio" "fmt" "time" - "github.com/nareix/bits/pio" + "github.com/nareix/joy4/utils/bits/pio" "github.com/nareix/joy4/av" "github.com/nareix/joy4/format/ts/tsio" "github.com/nareix/joy4/codec/aacparser" diff --git a/format/ts/tsio/tsio.go b/format/ts/tsio/tsio.go index d18bd8b..ee4563e 100644 --- a/format/ts/tsio/tsio.go +++ b/format/ts/tsio/tsio.go @@ -5,7 +5,7 @@ import ( "io" "time" "fmt" - "github.com/nareix/bits/pio" + "github.com/nareix/joy4/utils/bits/pio" ) const ( diff --git a/utils/bits/bits.go b/utils/bits/bits.go new file mode 100644 index 0000000..4a09f0a --- /dev/null +++ b/utils/bits/bits.go @@ -0,0 +1,118 @@ +package bits + +import ( + "io" +) + +type Reader struct { + R io.Reader + n int + bits uint64 +} + +func (self *Reader) ReadBits64(n int) (bits uint64, err error) { + if self.n < n { + var b [8]byte + var got int + want := (n - self.n + 7) / 8 + if got, err = self.R.Read(b[:want]); err != nil { + return + } + if got < want { + err = io.EOF + return + } + for i := 0; i < got; i++ { + self.bits <<= 8 + self.bits |= uint64(b[i]) + } + self.n += got * 8 + } + bits = self.bits >> uint(self.n-n) + self.bits ^= bits << uint(self.n-n) + self.n -= n + return +} + +func (self *Reader) ReadBits(n int) (bits uint, err error) { + var bits64 uint64 + if bits64, err = self.ReadBits64(n); err != nil { + return + } + bits = uint(bits64) + return +} + +func (self *Reader) Read(p []byte) (n int, err error) { + for n < len(p) { + want := 8 + if len(p)-n < want { + want = len(p) - n + } + var bits uint64 + if bits, err = self.ReadBits64(want * 8); err != nil { + break + } + for i := 0; i < want; i++ { + p[n+i] = byte(bits >> uint((want-i-1)*8)) + } + n += want + } + return +} + +type Writer struct { + W io.Writer + n int + bits uint64 +} + +func (self *Writer) WriteBits64(bits uint64, n int) (err error) { + if self.n+n > 64 { + move := uint(64 - self.n) + mask := bits >> move + self.bits = (self.bits << move) | mask + self.n = 64 + if err = self.FlushBits(); err != nil { + return + } + n -= int(move) + bits ^= (mask << move) + } + self.bits = (self.bits << uint(n)) | bits + self.n += n + return +} + +func (self *Writer) WriteBits(bits uint, n int) (err error) { + return self.WriteBits64(uint64(bits), n) +} + +func (self *Writer) Write(p []byte) (n int, err error) { + for n < len(p) { + if err = self.WriteBits64(uint64(p[n]), 8); err != nil { + return + } + n++ + } + return +} + +func (self *Writer) FlushBits() (err error) { + if self.n > 0 { + var b [8]byte + bits := self.bits + if self.n%8 != 0 { + bits <<= uint(8 - (self.n % 8)) + } + want := (self.n + 7) / 8 + for i := 0; i < want; i++ { + b[i] = byte(bits >> uint((want-i-1)*8)) + } + if _, err = self.W.Write(b[:want]); err != nil { + return + } + self.n = 0 + } + return +} diff --git a/utils/bits/bits_test.go b/utils/bits/bits_test.go new file mode 100644 index 0000000..c4957c9 --- /dev/null +++ b/utils/bits/bits_test.go @@ -0,0 +1,51 @@ +package bits + +import ( + "bytes" + "testing" +) + +func TestBits(t *testing.T) { + rdata := []byte{0xf3, 0xb3, 0x45, 0x60} + rbuf := bytes.NewReader(rdata[:]) + r := &Reader{R: rbuf} + var u32 uint + if u32, _ = r.ReadBits(4); u32 != 0xf { + t.FailNow() + } + if u32, _ = r.ReadBits(4); u32 != 0x3 { + t.FailNow() + } + if u32, _ = r.ReadBits(2); u32 != 0x2 { + t.FailNow() + } + if u32, _ = r.ReadBits(2); u32 != 0x3 { + t.FailNow() + } + b := make([]byte, 2) + if r.Read(b); b[0] != 0x34 || b[1] != 0x56 { + t.FailNow() + } + + wbuf := &bytes.Buffer{} + w := &Writer{W: wbuf} + w.WriteBits(0xf, 4) + w.WriteBits(0x3, 4) + w.WriteBits(0x2, 2) + w.WriteBits(0x3, 2) + n, _ := w.Write([]byte{0x34, 0x56}) + if n != 2 { + t.FailNow() + } + w.FlushBits() + wdata := wbuf.Bytes() + if wdata[0] != 0xf3 || wdata[1] != 0xb3 || wdata[2] != 0x45 || wdata[3] != 0x60 { + t.FailNow() + } + + b = make([]byte, 8) + PutUInt64BE(b, 0x11223344, 32) + if b[0] != 0x11 || b[1] != 0x22 || b[2] != 0x33 || b[3] != 0x44 { + t.FailNow() + } +} diff --git a/utils/bits/bufio/bufio.go b/utils/bits/bufio/bufio.go new file mode 100644 index 0000000..ec7eedf --- /dev/null +++ b/utils/bits/bufio/bufio.go @@ -0,0 +1,23 @@ +package bufio + +import ( + "io" +) + +type Reader struct { + buf [][]byte + R io.ReadSeeker +} + +func NewReaderSize(r io.ReadSeeker, size int) *Reader { + buf := make([]byte, size*2) + return &Reader{ + R: r, + buf: [][]byte{buf[0:size], buf[size:]}, + } +} + +func (self *Reader) ReadAt(b []byte, off int64) (n int, err error) { + return +} + diff --git a/utils/bits/golomb_reader.go b/utils/bits/golomb_reader.go new file mode 100644 index 0000000..da57cb2 --- /dev/null +++ b/utils/bits/golomb_reader.go @@ -0,0 +1,65 @@ +package bits + +import ( + "io" +) + +type GolombBitReader struct { + R io.Reader + buf [1]byte + left byte +} + +func (self *GolombBitReader) ReadBit() (res uint, err error) { + if self.left == 0 { + if _, err = self.R.Read(self.buf[:]); err != nil { + return + } + self.left = 8 + } + self.left-- + res = uint(self.buf[0]>>self.left) & 1 + return +} + +func (self *GolombBitReader) ReadBits(n int) (res uint, err error) { + for i := 0; i < n; i++ { + var bit uint + if bit, err = self.ReadBit(); err != nil { + return + } + res |= bit << uint(n-i-1) + } + return +} + +func (self *GolombBitReader) ReadExponentialGolombCode() (res uint, err error) { + i := 0 + for { + var bit uint + if bit, err = self.ReadBit(); err != nil { + return + } + if !(bit == 0 && i < 32) { + break + } + i++ + } + if res, err = self.ReadBits(i); err != nil { + return + } + res += (1 << uint(i)) - 1 + return +} + +func (self *GolombBitReader) ReadSE() (res uint, err error) { + if res, err = self.ReadExponentialGolombCode(); err != nil { + return + } + if res&0x01 != 0 { + res = (res + 1) / 2 + } else { + res = -res / 2 + } + return +} diff --git a/utils/bits/pio/pio.go b/utils/bits/pio/pio.go new file mode 100644 index 0000000..3d56bef --- /dev/null +++ b/utils/bits/pio/pio.go @@ -0,0 +1,5 @@ + +package pio + +var RecommendBufioSize = 1024*64 + diff --git a/utils/bits/pio/reader.go b/utils/bits/pio/reader.go new file mode 100644 index 0000000..87f024b --- /dev/null +++ b/utils/bits/pio/reader.go @@ -0,0 +1,91 @@ + +package pio + +func U8(b []byte) (i uint8) { + return b[0] +} + +func U16BE(b []byte) (i uint16) { + i = uint16(b[0]) + i <<= 8; i |= uint16(b[1]) + return +} + +func I16BE(b []byte) (i int16) { + i = int16(b[0]) + i <<= 8; i |= int16(b[1]) + return +} + +func I24BE(b []byte) (i int32) { + i = int32(int8(b[0])) + i <<= 8; i |= int32(b[1]) + i <<= 8; i |= int32(b[2]) + return +} + +func U24BE(b []byte) (i uint32) { + i = uint32(b[0]) + i <<= 8; i |= uint32(b[1]) + i <<= 8; i |= uint32(b[2]) + return +} + +func I32BE(b []byte) (i int32) { + i = int32(int8(b[0])) + i <<= 8; i |= int32(b[1]) + i <<= 8; i |= int32(b[2]) + i <<= 8; i |= int32(b[3]) + return +} + +func U32LE(b []byte) (i uint32) { + i = uint32(b[3]) + i <<= 8; i |= uint32(b[2]) + i <<= 8; i |= uint32(b[1]) + i <<= 8; i |= uint32(b[0]) + return +} + +func U32BE(b []byte) (i uint32) { + i = uint32(b[0]) + i <<= 8; i |= uint32(b[1]) + i <<= 8; i |= uint32(b[2]) + i <<= 8; i |= uint32(b[3]) + return +} + +func U40BE(b []byte) (i uint64) { + i = uint64(b[0]) + i <<= 8; i |= uint64(b[1]) + i <<= 8; i |= uint64(b[2]) + i <<= 8; i |= uint64(b[3]) + i <<= 8; i |= uint64(b[4]) + return +} + +func U64BE(b []byte) (i uint64) { + i = uint64(b[0]) + i <<= 8; i |= uint64(b[1]) + i <<= 8; i |= uint64(b[2]) + i <<= 8; i |= uint64(b[3]) + i <<= 8; i |= uint64(b[4]) + i <<= 8; i |= uint64(b[5]) + i <<= 8; i |= uint64(b[6]) + i <<= 8; i |= uint64(b[7]) + return +} + +func I64BE(b []byte) (i int64) { + i = int64(int8(b[0])) + i <<= 8; i |= int64(b[1]) + i <<= 8; i |= int64(b[2]) + i <<= 8; i |= int64(b[3]) + i <<= 8; i |= int64(b[4]) + i <<= 8; i |= int64(b[5]) + i <<= 8; i |= int64(b[6]) + i <<= 8; i |= int64(b[7]) + return +} + + diff --git a/utils/bits/pio/vec.go b/utils/bits/pio/vec.go new file mode 100644 index 0000000..30d5e92 --- /dev/null +++ b/utils/bits/pio/vec.go @@ -0,0 +1,69 @@ +package pio + +func VecLen(vec [][]byte) (n int) { + for _, b := range vec { + n += len(b) + } + return +} + +func VecSliceTo(in [][]byte, out [][]byte, s int, e int) (n int) { + if s < 0 { + s = 0 + } + + if e >= 0 && e < s { + panic("pio: VecSlice start > end") + } + + i := 0 + off := 0 + for s > 0 && i < len(in) { + left := len(in[i]) + read := s + if left < read { + read = left + } + left -= read + off += read + s -= read + e -= read + if left == 0 { + i++ + off = 0 + } + } + if s > 0 { + panic("pio: VecSlice start out of range") + } + + for e != 0 && i < len(in) { + left := len(in[i])-off + read := left + if e > 0 && e < read { + read = e + } + out[n] = in[i][off:off+read] + n++ + left -= read + e -= read + off += read + if left == 0 { + i++ + off = 0 + } + } + if e > 0 { + panic("pio: VecSlice end out of range") + } + + return +} + +func VecSlice(in [][]byte, s int, e int) (out [][]byte) { + out = make([][]byte, len(in)) + n := VecSliceTo(in, out, s, e) + out = out[:n] + return +} + diff --git a/utils/bits/pio/vec_test.go b/utils/bits/pio/vec_test.go new file mode 100644 index 0000000..99ebb55 --- /dev/null +++ b/utils/bits/pio/vec_test.go @@ -0,0 +1,22 @@ + +package pio + +import ( + "fmt" +) + +func ExampleVec() { + vec := [][]byte{[]byte{1,2,3}, []byte{4,5,6,7,8,9}, []byte{10,11,12,13}} + println(VecLen(vec)) + + vec = VecSlice(vec, 1, -1) + fmt.Println(vec) + + vec = VecSlice(vec, 2, -1) + fmt.Println(vec) + + vec = VecSlice(vec, 8, 8) + fmt.Println(vec) + + // Output: +} diff --git a/utils/bits/pio/writer.go b/utils/bits/pio/writer.go new file mode 100644 index 0000000..2e709f9 --- /dev/null +++ b/utils/bits/pio/writer.go @@ -0,0 +1,89 @@ + +package pio + +func PutU8(b []byte, v uint8) { + b[0] = v +} + +func PutI16BE(b []byte, v int16) { + b[0] = byte(v>>8) + b[1] = byte(v) +} + +func PutU16BE(b []byte, v uint16) { + b[0] = byte(v>>8) + b[1] = byte(v) +} + +func PutI24BE(b []byte, v int32) { + b[0] = byte(v>>16) + b[1] = byte(v>>8) + b[2] = byte(v) +} + +func PutU24BE(b []byte, v uint32) { + b[0] = byte(v>>16) + b[1] = byte(v>>8) + b[2] = byte(v) +} + +func PutI32BE(b []byte, v int32) { + b[0] = byte(v>>24) + b[1] = byte(v>>16) + b[2] = byte(v>>8) + b[3] = byte(v) +} + +func PutU32BE(b []byte, v uint32) { + b[0] = byte(v>>24) + b[1] = byte(v>>16) + b[2] = byte(v>>8) + b[3] = byte(v) +} + +func PutU32LE(b []byte, v uint32) { + b[3] = byte(v>>24) + b[2] = byte(v>>16) + b[1] = byte(v>>8) + b[0] = byte(v) +} + +func PutU40BE(b []byte, v uint64) { + b[0] = byte(v>>32) + b[1] = byte(v>>24) + b[2] = byte(v>>16) + b[3] = byte(v>>8) + b[4] = byte(v) +} + +func PutU48BE(b []byte, v uint64) { + b[0] = byte(v>>40) + b[1] = byte(v>>32) + b[2] = byte(v>>24) + b[3] = byte(v>>16) + b[4] = byte(v>>8) + b[5] = byte(v) +} + +func PutU64BE(b []byte, v uint64) { + b[0] = byte(v>>56) + b[1] = byte(v>>48) + b[2] = byte(v>>40) + b[3] = byte(v>>32) + b[4] = byte(v>>24) + b[5] = byte(v>>16) + b[6] = byte(v>>8) + b[7] = byte(v) +} + +func PutI64BE(b []byte, v int64) { + b[0] = byte(v>>56) + b[1] = byte(v>>48) + b[2] = byte(v>>40) + b[3] = byte(v>>32) + b[4] = byte(v>>24) + b[5] = byte(v>>16) + b[6] = byte(v>>8) + b[7] = byte(v) +} +