package mpegts import ( "bytes" "errors" "fmt" "io" "m7s.live/engine/v4/util" ) // ios13818-1-CN.pdf 46(60)-153(167)/page // // PMT // var DefaultPMTPacket = []byte{ // TS Header 0x47, 0x41, 0x00, 0x10, // Pointer Field 0x00, // PSI 0x02, 0xb0, 0x17, 0x00, 0x01, 0xc1, 0x00, 0x00, // PMT 0xe1, 0x01, 0xf0, 0x00, // H264 0x1b, 0xe1, 0x01, 0xf0, 0x00, // AAC 0x0f, 0xe1, 0x02, 0xf0, 0x00, //0x00, 0x00, 0x00, 0x00, 0x00, // CRC for not audio //0x00, 0x00, 0x00, 0x00, // CRC for AAC 0x9e, 0x28, 0xc6, 0xdd, // CRC for MP3 // 0x4e, 0x59, 0x3d, 0x1e, // Stuffing 157 bytes 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, } // TS Header : // SyncByte = 0x47 // TransportErrorIndicator = 0(B:0), PayloadUnitStartIndicator = 1(B:0), TransportPriority = 0(B:0), // Pid = 4097(0x1001), // TransportScramblingControl = 0(B:00), AdaptionFieldControl = 1(B:01), ContinuityCounter = 0(B:0000), // PSI : // TableID = 0x02, // SectionSyntaxIndicator = 1(B:1), Zero = 0(B:0), Reserved1 = 3(B:11), // SectionLength = 23(0x17) // ProgramNumber = 0x0001 // Reserved2 = 3(B:11), VersionNumber = (B:00000), CurrentNextIndicator = 1(B:0), // SectionNumber = 0x00 // LastSectionNumber = 0x00 // PMT: // Reserved3 = 15(B:1110), PcrPID = 256(0x100) // Reserved4 = 16(B:1111), ProgramInfoLength = 0(0x000) // H264: // StreamType = 0x1b, // Reserved5 = 15(B:1110), ElementaryPID = 256(0x100) // Reserved6 = 16(B:1111), EsInfoLength = 0(0x000) // AAC: // StreamType = 0x0f, // Reserved5 = 15(B:1110), ElementaryPID = 257(0x101) // Reserved6 = 16(B:1111), EsInfoLength = 0(0x000) type MpegTsPmtStream struct { StreamType byte // 8 bits 指示具有 PID值的包内承载的节目元类型,其 PID值由 elementary_PID所指定 Reserved5 byte // 3 bits 保留位 ElementaryPID uint16 // 13 bits 指定承载相关节目元的传输流包的 PID Reserved6 byte // 4 bits 保留位 EsInfoLength uint16 // 12 bits 该字段的头两比特必为'00',剩余 10比特指示紧随 ES_info_length字段的相关节目元描述符的字节数 // N Loop Descriptors Descriptor []MpegTsDescriptor // 不确定字节数,可变 } // Program Map Table (节目映射表) type MpegTsPMT struct { // PSI TableID byte // 8 bits 0x00->PAT,0x02->PMT SectionSyntaxIndicator byte // 1 bit 段语法标志位,固定为1 Zero byte // 1 bit 0 Reserved1 byte // 2 bits 保留位 SectionLength uint16 // 12 bits 该字段的头两比特必为'00',剩余 10 比特指定该分段的字节数,紧随 section_length 字段开始,并包括 CRC.此字段中的值应不超过 1021(0x3FD) ProgramNumber uint16 // 16 bits 指定 program_map_PID 所适用的节目 Reserved2 byte // 2 bits 保留位 VersionNumber byte // 5 bits 范围0-31,表示PAT的版本号 CurrentNextIndicator byte // 1 bit 发送的PAT是当前有效还是下一个PAT有效 SectionNumber byte // 8 bits 分段的号码.PAT可能分为多段传输.第一段为00,以后每个分段加1,最多可能有256个分段 LastSectionNumber byte // 8 bits 最后一个分段的号码 Reserved3 byte // 3 bits 保留位 0x07 PcrPID uint16 // 13 bits 指明TS包的PID值.该TS包含有PCR域,该PCR值对应于由节目号指定的对应节目.如果对于私有数据流的节目定义与PCR无关.这个域的值将为0x1FFF Reserved4 byte // 4 bits 预留位 0x0F ProgramInfoLength uint16 // 12 bits 前两位bit为00.该域指出跟随其后对节目信息的描述的byte数 ProgramInfoDescriptor []MpegTsDescriptor // N Loop Descriptors 可变 节目信息描述 // N Loop Stream []MpegTsPmtStream // PMT表里面的所有音视频索引信息 Crc32 uint32 // 32 bits 包含处理全部传输流节目映射分段之后,在附件 B 规定的解码器中给出寄存器零输出的 CRC 值 } func ReadPMT(r io.Reader) (pmt MpegTsPMT, err error) { lr, psi, err := ReadPSI(r, PSI_TYPE_PMT) if err != nil { return } pmt = psi.Pmt // reserved3(3) + pcrPID(13) pcrPID, err := util.ReadByteToUint16(lr, true) if err != nil { return } pmt.PcrPID = pcrPID & 0x1fff // reserved4(4) + programInfoLength(12) // programInfoLength(12) == 0x00(固定为0) + programInfoLength(10) programInfoLength, err := util.ReadByteToUint16(lr, true) if err != nil { return } pmt.ProgramInfoLength = programInfoLength & 0x3ff // 如果length>0那么,紧跟programInfoLength后面就有length个字节 if pmt.ProgramInfoLength > 0 { lr := &io.LimitedReader{R: lr, N: int64(pmt.ProgramInfoLength)} pmt.ProgramInfoDescriptor, err = ReadPMTDescriptor(lr) if err != nil { return } } // N Loop // 开始N循环,读取所有的流的信息 for lr.N > 0 { var streams MpegTsPmtStream // streamType(8) streams.StreamType, err = util.ReadByteToUint8(lr) if err != nil { return } // reserved5(3) + elementaryPID(13) streams.ElementaryPID, err = util.ReadByteToUint16(lr, true) if err != nil { return } streams.ElementaryPID = streams.ElementaryPID & 0x1fff // reserved6(4) + esInfoLength(12) // esInfoLength(12) == 0x00(固定为0) + esInfoLength(10) streams.EsInfoLength, err = util.ReadByteToUint16(lr, true) if err != nil { return } streams.EsInfoLength = streams.EsInfoLength & 0x3ff // 如果length>0那么,紧跟esInfoLength后面就有length个字节 if streams.EsInfoLength > 0 { lr := &io.LimitedReader{R: lr, N: int64(streams.EsInfoLength)} streams.Descriptor, err = ReadPMTDescriptor(lr) if err != nil { return } } // 每读取一个流的信息(音频流或者视频流或者其他),都保存起来 pmt.Stream = append(pmt.Stream, streams) } if cr, ok := r.(*util.Crc32Reader); ok { err = cr.ReadCrc32UIntAndCheck() if err != nil { return } } return } func ReadPMTDescriptor(lr *io.LimitedReader) (Desc []MpegTsDescriptor, err error) { var desc MpegTsDescriptor for lr.N > 0 { // tag (8) desc.Tag, err = util.ReadByteToUint8(lr) if err != nil { return } // length (8) desc.Length, err = util.ReadByteToUint8(lr) if err != nil { return } desc.Data = make([]byte, desc.Length) _, err = lr.Read(desc.Data) if err != nil { return } Desc = append(Desc, desc) } return } func WritePMTDescriptor(w io.Writer, descs []MpegTsDescriptor) (err error) { for _, desc := range descs { // tag(8) if err = util.WriteUint8ToByte(w, desc.Tag); err != nil { return } // length (8) if err = util.WriteUint8ToByte(w, uint8(len(desc.Data))); err != nil { return } // data if _, err = w.Write(desc.Data); err != nil { return } } return } func WritePMTBody(w io.Writer, pmt MpegTsPMT) (err error) { // reserved3(3) + pcrPID(13) if err = util.WriteUint16ToByte(w, pmt.PcrPID|7<<13, true); err != nil { return } // programInfoDescriptor 节目信息描述,字节数不能确定 bw := &bytes.Buffer{} if err = WritePMTDescriptor(bw, pmt.ProgramInfoDescriptor); err != nil { return } pmt.ProgramInfoLength = uint16(bw.Len()) // reserved4(4) + programInfoLength(12) // programInfoLength(12) == 0x00(固定为0) + programInfoLength(10) if err = util.WriteUint16ToByte(w, pmt.ProgramInfoLength|0xf000, true); err != nil { return } // programInfoDescriptor if _, err = w.Write(bw.Bytes()); err != nil { return } // 循环读取所有的流的信息(音频或者视频) for _, esinfo := range pmt.Stream { // streamType(8) if err = util.WriteUint8ToByte(w, esinfo.StreamType); err != nil { return } // reserved5(3) + elementaryPID(13) if err = util.WriteUint16ToByte(w, esinfo.ElementaryPID|7<<13, true); err != nil { return } // descriptor ES流信息描述,字节数不能确定 bw := &bytes.Buffer{} if err = WritePMTDescriptor(bw, esinfo.Descriptor); err != nil { return } esinfo.EsInfoLength = uint16(bw.Len()) // reserved6(4) + esInfoLength(12) // esInfoLength(12) == 0x00(固定为0) + esInfoLength(10) if err = util.WriteUint16ToByte(w, esinfo.EsInfoLength|0xf000, true); err != nil { return } // descriptor if _, err = w.Write(bw.Bytes()); err != nil { return } } return } func WritePMT(w io.Writer, pmt MpegTsPMT) (err error) { bw := &bytes.Buffer{} if err = WritePMTBody(bw, pmt); err != nil { return } if pmt.SectionLength == 0 { pmt.SectionLength = 2 + 3 + 4 + uint16(len(bw.Bytes())) } psi := MpegTsPSI{} psi.Pmt = pmt if err = WritePSI(w, PSI_TYPE_PMT, psi, bw.Bytes()); err != nil { return } return } func WritePMTPacket(w io.Writer, tsHeader []byte, pmt MpegTsPMT) (err error) { if pmt.TableID != TABLE_TSPMS { err = errors.New("PMT table ID error") return } // 将所有要写的数据(PMT),全部放入到buffer中去. // buffer 里面已经写好了整个PMT表(PointerField+PSI+PMT+CRC) bw := &bytes.Buffer{} if err = WritePMT(bw, pmt); err != nil { return } // TODO:如果Pmt.Stream里面包含的信息很大,大于188? stuffingBytes := util.GetFillBytes(0xff, TS_PACKET_SIZE-4-bw.Len()) var PMTPacket []byte PMTPacket = append(PMTPacket, tsHeader...) PMTPacket = append(PMTPacket, bw.Bytes()...) PMTPacket = append(PMTPacket, stuffingBytes...) fmt.Println("-------------------------") fmt.Println("Write PMT :", PMTPacket) fmt.Println("-------------------------") // 写PMT负载 if _, err = w.Write(PMTPacket); err != nil { return } return } func WriteDefaultPMTPacket(w io.Writer) (err error) { _, err = w.Write(DefaultPMTPacket) if err != nil { return } return }