diff --git a/checksum.go b/checksum.go index 6c2d97e..61fe192 100644 --- a/checksum.go +++ b/checksum.go @@ -65,13 +65,13 @@ type Crc32Reader struct { Crc32 uint32 } -var debugCrc32 = false +var DebugCrc32 = false func (self *Crc32Reader) Read(b []byte) (n int, err error) { if n, err = self.R.Read(b); err != nil { return } - if debugCrc32 { + if DebugCrc32 { fmt.Println("crc32: update", hex.EncodeToString(b)) } self.Crc32 = updateIeeeCrc32(self.Crc32, b) @@ -83,7 +83,7 @@ func (self *Crc32Reader) ReadCrc32UIntAndCheck() (err error) { return } if self.Crc32 != 0 { - err = fmt.Errorf("crc32 != 0") + err = fmt.Errorf("crc32(%x) != 0", self.Crc32) return } return diff --git a/example/test.go b/example/test.go index 22ade5e..6ab86a1 100644 --- a/example/test.go +++ b/example/test.go @@ -8,6 +8,7 @@ import ( ts "../" "fmt" "encoding/hex" + "flag" ) type Stream struct { @@ -27,7 +28,7 @@ type Sample struct { Data []byte } -func readSamples(ch chan Sample) { +func readSamples(filename string, ch chan Sample) { defer func() { close(ch) }() @@ -36,7 +37,7 @@ func readSamples(ch chan Sample) { var file *os.File var err error - if file, err = os.Open("/tmp/out.ts"); err != nil { + if file, err = os.Open(filename); err != nil { return } @@ -137,8 +138,46 @@ func readSamples(ch chan Sample) { } func main() { + input := flag.String("i", "", "input file") + output := flag.String("o", "", "output file") + flag.Parse() + + var file *os.File + var err error + ch := make(chan Sample, 0) - go readSamples(ch) + go readSamples(*input, ch) + + if *output != "" { + if file, err = os.Create(*output); err != nil { + return + } + } + + writePAT := func() (err error) { + w := &ts.TSWriter{ + W: file, + PID: 0, + } + pat := ts.PAT { + Entries: []ts.PATEntry{ + {ProgramNumber: 1, ProgramMapPID: 4096}, + }, + } + bw := &bytes.Buffer{} + if err = ts.WritePAT(bw, pat); err != nil { + return + } + if err = w.Write(bw.Bytes(), false); err != nil { + return + } + return + } + + if file != nil { + writePAT() + file.Close() + } for { var sample Sample @@ -147,8 +186,10 @@ func main() { break } if sample.Type == ts.ElementaryStreamTypeH264 { - fmt.Println("sample", len(sample.Data), "PCR", sample.PCR) - fmt.Print(hex.Dump(sample.Data)) + if false { + fmt.Println("sample: ", len(sample.Data), "PCR", sample.PCR) + //fmt.Print(hex.Dump(sample.Data)) + } } } } diff --git a/reader.go b/reader.go index b24f1cb..dc49f9a 100644 --- a/reader.go +++ b/reader.go @@ -7,6 +7,8 @@ import ( "io/ioutil" ) +var DebugReader = true + func ReadUInt(r io.Reader, n int) (res uint, err error) { var b [4]byte if _, err = r.Read(b[0:n]); err != nil { @@ -55,7 +57,7 @@ func ReadTSHeader(r io.Reader) (self TSHeader, err error) { return } - if debug { + if DebugReader { fmt.Printf("ts: flags %s\n", FieldsDumper{ Fields: []struct{ Length int @@ -99,7 +101,7 @@ func ReadTSHeader(r io.Reader) (self TSHeader, err error) { return } - if debug { + if DebugReader { fmt.Printf("ts: ext_flags %s\n", FieldsDumper{ Fields: []struct{ Length int @@ -127,7 +129,7 @@ func ReadTSHeader(r io.Reader) (self TSHeader, err error) { } // clock is 27MHz self.PCR = UIntToPCR(v) - if debug { + if DebugReader { fmt.Printf("ts: PCR %d %f\n", self.PCR, float64(self.PCR)/27000000) } } @@ -168,7 +170,7 @@ func ReadTSHeader(r io.Reader) (self TSHeader, err error) { return } - if debug { + if DebugReader { // rubish //fmt.Println("ts: ", data) } @@ -216,17 +218,8 @@ func ReadPSI(r io.Reader) (self PSI, lr *io.LimitedReader, cr *Crc32Reader, err } length = flags & 0x3FF - if debug { - fmt.Printf("psi: %s\n", FieldsDumper{ - Fields: []struct{ - Length int - Desc string - }{ - {4, "reserved"}, - }, - Val: flags, - Length: 16, - }) + if DebugReader { + fmt.Printf("psi: tableid=%d len=%d\n", self.TableId, length) } lr = &io.LimitedReader{R: cr, N: int64(length)} @@ -243,7 +236,7 @@ func ReadPSI(r io.Reader) (self PSI, lr *io.LimitedReader, cr *Crc32Reader, err return } - if debug { + if DebugReader { fmt.Printf("psi: %s\n", FieldsDumper{ Fields: []struct{ Length int @@ -268,7 +261,7 @@ func ReadPSI(r io.Reader) (self PSI, lr *io.LimitedReader, cr *Crc32Reader, err return } - if debug { + if DebugReader { fmt.Printf("psi: table_id=%x table_extension=%x secnum=%x lastsecnum=%x\n", self.TableId, self.TableIdExtension, @@ -299,7 +292,7 @@ func ReadPMT(r io.Reader) (self PMT, err error) { } self.PCRPID = flags & 0x1fff - if debug { + if DebugReader { fmt.Printf("pmt: %s\n", FieldsDumper{ Fields: []struct{ Length int @@ -375,12 +368,15 @@ func ReadPMT(r io.Reader) (self PMT, err error) { self.ElementaryStreamInfos = append(self.ElementaryStreamInfos, info) } - if debug { + if DebugReader { fmt.Printf("pmt: ProgramDescriptors %v\n", self.ProgramDescriptors) fmt.Printf("pmt: ElementaryStreamInfos %v\n", self.ElementaryStreamInfos) } if err = cr.ReadCrc32UIntAndCheck(); err != nil { + if DebugReader { + fmt.Printf("pmt: %s\n", err) + } return } @@ -416,10 +412,13 @@ func ReadPAT(r io.Reader) (self PAT, err error) { } if err = cr.ReadCrc32UIntAndCheck(); err != nil { + if DebugReader { + fmt.Printf("pat: %s\n", err) + } return } - if debug { + if DebugReader { fmt.Printf("pat: %v\n", self) } @@ -461,7 +460,7 @@ func ReadPESHeader(r io.Reader) (res *PESHeader, err error) { return } - if debug { + if DebugReader { fmt.Printf("pes: %s\n", FieldsDumper{ Fields: []struct{ Length int @@ -489,7 +488,7 @@ func ReadPESHeader(r io.Reader) (res *PESHeader, err error) { return } - if debug { + if DebugReader { fmt.Printf("pes: %s\n", FieldsDumper{ Fields: []struct{ Length int @@ -521,7 +520,7 @@ func ReadPESHeader(r io.Reader) (res *PESHeader, err error) { } self.PTS = PESUIntToTs(v) - if debug { + if DebugReader { fmt.Printf("pes: pts %x=>%x %f\n", v, self.PTS, float64(self.PTS)/90000) } @@ -533,7 +532,7 @@ func ReadPESHeader(r io.Reader) (res *PESHeader, err error) { return } self.DTS = PESUIntToTs(v) - if debug { + if DebugReader { fmt.Printf("pes: dts %d\n", self.PTS) } } diff --git a/ts.go b/ts.go index c59ade7..c0e943e 100644 --- a/ts.go +++ b/ts.go @@ -5,8 +5,6 @@ import ( "fmt" ) -const debug = true - const ( ElementaryStreamTypeH264 = 0x1B ElementaryStreamTypeAdtsAAC = 0x0F diff --git a/writer.go b/writer.go index 6465168..73b62ea 100644 --- a/writer.go +++ b/writer.go @@ -2,16 +2,12 @@ package ts import ( - _ "fmt" + "fmt" "io" "bytes" ) -type TSWriter struct { - W io.Writer - ContinuityCounter uint - PayloadUnitStart bool -} +const DebugWriter = true func WriteUInt64(w io.Writer, val uint64, n int) (err error) { var b [8]byte @@ -19,7 +15,7 @@ func WriteUInt64(w io.Writer, val uint64, n int) (err error) { b[i] = byte(val) val >>= 8 } - if _, err = w.Write(b[:]); err != nil { + if _, err = w.Write(b[:n]); err != nil { return } return @@ -108,6 +104,63 @@ func WriteTSHeader(w io.Writer, self TSHeader) (err error) { return } +type TSWriter struct { + W io.Writer + PID uint + PCR uint64 + OPCR uint64 + ContinuityCounter uint +} + +func (self *TSWriter) Write(b []byte, RandomAccessIndicator bool) (err error) { + for i := 0; len(b) > 0; i++ { + header := TSHeader{ + PID: self.PID, + PCR: self.PCR, + OPCR: self.OPCR, + ContinuityCounter: self.ContinuityCounter, + RandomAccessIndicator: RandomAccessIndicator, + } + if i == 0 { + header.PayloadUnitStart = true + } + bw := &bytes.Buffer{} + if err = WriteTSHeader(bw, header); err != nil { + return + } + + var data []byte + dataLen := 188-bw.Len() + + if DebugWriter { + fmt.Printf("tsw: datalen=%d blen=%d\n", dataLen, len(b)) + } + + if len(b) > dataLen { + data = b[:dataLen] + b = b[dataLen:] + } else { + data = make([]byte, dataLen) + copy(data, b) + for i := len(b); i < dataLen; i++ { + data[i] = 0xff + } + b = b[len(b):] + } + + if _, err = self.W.Write(bw.Bytes()); err != nil { + return + } + if _, err = self.W.Write(data); err != nil { + return + } + + self.ContinuityCounter++ + } + + return +} + func WritePSI(w io.Writer, self PSI, data []byte) (err error) { // pointer(8) // table_id(8) @@ -135,10 +188,14 @@ func WritePSI(w io.Writer, self PSI, data []byte) (err error) { var flags, length uint length = 2+3+4+uint(len(data)) flags = 0xb<<10|length - if err = WriteUInt(cw, flags, 1); err != nil { + if err = WriteUInt(cw, flags, 2); err != nil { return } + if DebugWriter { + fmt.Printf("wpsi: flags=%x\n", flags) + } + // Table ID extension(16) if err = WriteUInt(cw, self.TableIdExtension, 2); err != nil { return @@ -166,13 +223,17 @@ func WritePSI(w io.Writer, self PSI, data []byte) (err error) { } // crc(32) - if err = WriteUInt(w, uint(cw.Crc32), 4); err != nil { + if err = WriteUInt(w, bswap32(uint(cw.Crc32)), 4); err != nil { return } return } +func bswap32(v uint) uint { + return (v>>24)|((v>>16)&0xff)<<8|((v>>8)&0xff)<<16|(v&0xff)<<24 +} + func WritePES(w io.Writer, self PESHeader, data []byte) (err error) { // http://dvd.sourceforge.net/dvdinfo/pes-hdr.html