mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
GB28181: Support GB28181-2016 protocol. v5.0.74 (#3201)
01. Support GB config as StreamCaster. 02. Support disable GB by --gb28181=off. 03. Add utests for SIP examples. 04. Wireshark plugin to decode TCP/9000 as rtp.rfc4571 05. Support MPEGPS program stream codec. 06. Add utest for PS stream codec. 07. Decode MPEGPS packet stream. 08. Carry RTP and PS packet as helper in PS message. 09. Support recover from error mode. 10. Support process by a pack of PS/TS messages. 11. Add statistic for recovered and msgs dropped. 12. Recover from err position fastly. 13. Define state machine for GB session. 14. Bind context to GB session. 15. Re-invite when media disconnected. 16. Update GitHub actions with GB28181. 17. Support parse CANDIDATE by env or pip. 18. Support mux GB28181 to RTMP. 19. Support regression test by srs-bench.
This commit is contained in:
parent
9c81a0e1bd
commit
5a420ece3b
298 changed files with 43343 additions and 763 deletions
21
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/mpeg2/LICENSE
generated
vendored
Normal file
21
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/mpeg2/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2021 caoyaping
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
5
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/mpeg2/go.mod
generated
vendored
Normal file
5
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/mpeg2/go.mod
generated
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
module github.com/yapingcat/gomedia/mpeg2
|
||||
|
||||
go 1.16
|
||||
|
||||
require github.com/yapingcat/gomedia/codec v0.0.0-20220609081842-9e0c0e8a19a0
|
2
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/mpeg2/go.sum
generated
vendored
Normal file
2
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/mpeg2/go.sum
generated
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
github.com/yapingcat/gomedia/codec v0.0.0-20220609081842-9e0c0e8a19a0 h1:gAmdgY8sSyyw081bp3gdwNwpXWeYddcCF0ZfzRG1Au8=
|
||||
github.com/yapingcat/gomedia/codec v0.0.0-20220609081842-9e0c0e8a19a0/go.mod h1:obSECV6X3NPUsLL0olA7DurvQHKMq7J3iBTNQ4bL/vQ=
|
349
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/mpeg2/pes-proto.go
generated
vendored
Normal file
349
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/mpeg2/pes-proto.go
generated
vendored
Normal file
|
@ -0,0 +1,349 @@
|
|||
package mpeg2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/yapingcat/gomedia/codec"
|
||||
)
|
||||
|
||||
var H264_AUD_NALU []byte = []byte{0x00, 0x00, 0x00, 0x01, 0x09, 0xF0} //ffmpeg mpegtsenc.c mpegts_write_packet_internal
|
||||
var H265_AUD_NALU []byte = []byte{0x00, 0x00, 0x00, 0x01, 0x46, 0x01, 0x50}
|
||||
|
||||
type PES_STREMA_ID int
|
||||
|
||||
const (
|
||||
PES_STREAM_END PES_STREMA_ID = 0xB9
|
||||
PES_STREAM_START PES_STREMA_ID = 0xBA
|
||||
PES_STREAM_SYSTEM_HEAD PES_STREMA_ID = 0xBB
|
||||
PES_STREAM_MAP PES_STREMA_ID = 0xBC
|
||||
PES_STREAM_PRIVATE PES_STREMA_ID = 0xBD
|
||||
PES_STREAM_AUDIO PES_STREMA_ID = 0xC0
|
||||
PES_STREAM_VIDEO PES_STREMA_ID = 0xE0
|
||||
)
|
||||
|
||||
func findPESIDByStreamType(cid TS_STREAM_TYPE) PES_STREMA_ID {
|
||||
if cid == TS_STREAM_AAC {
|
||||
return PES_STREAM_AUDIO
|
||||
} else if cid == TS_STREAM_H264 || cid == TS_STREAM_H265 {
|
||||
return PES_STREAM_VIDEO
|
||||
} else {
|
||||
return PES_STREAM_PRIVATE
|
||||
}
|
||||
}
|
||||
|
||||
type PesPacket struct {
|
||||
Stream_id uint8
|
||||
PES_packet_length uint16
|
||||
PES_scrambling_control uint8
|
||||
PES_priority uint8
|
||||
Data_alignment_indicator uint8
|
||||
Copyright uint8
|
||||
Original_or_copy uint8
|
||||
PTS_DTS_flags uint8
|
||||
ESCR_flag uint8
|
||||
ES_rate_flag uint8
|
||||
DSM_trick_mode_flag uint8
|
||||
Additional_copy_info_flag uint8
|
||||
PES_CRC_flag uint8
|
||||
PES_extension_flag uint8
|
||||
PES_header_data_length uint8
|
||||
Pts uint64
|
||||
Dts uint64
|
||||
ESCR_base uint64
|
||||
ESCR_extension uint16
|
||||
ES_rate uint32
|
||||
Trick_mode_control uint8
|
||||
Trick_value uint8
|
||||
Additional_copy_info uint8
|
||||
Previous_PES_packet_CRC uint16
|
||||
Pes_payload []byte
|
||||
//TODO
|
||||
//if ( PES_extension_flag == '1')
|
||||
// PES_private_data_flag uint8
|
||||
// pack_header_field_flag uint8
|
||||
// program_packet_sequence_counter_flag uint8
|
||||
// P_STD_buffer_flag uint8
|
||||
// PES_extension_flag_2 uint8
|
||||
// PES_private_data [16]byte
|
||||
}
|
||||
|
||||
func NewPesPacket() *PesPacket {
|
||||
return new(PesPacket)
|
||||
}
|
||||
|
||||
func (pkg *PesPacket) PrettyPrint(file *os.File) {
|
||||
file.WriteString(fmt.Sprintf("stream_id:%d\n", pkg.Stream_id))
|
||||
file.WriteString(fmt.Sprintf("PES_packet_length:%d\n", pkg.PES_packet_length))
|
||||
file.WriteString(fmt.Sprintf("PES_scrambling_control:%d\n", pkg.PES_scrambling_control))
|
||||
file.WriteString(fmt.Sprintf("PES_priority:%d\n", pkg.PES_priority))
|
||||
file.WriteString(fmt.Sprintf("data_alignment_indicator:%d\n", pkg.Data_alignment_indicator))
|
||||
file.WriteString(fmt.Sprintf("copyright:%d\n", pkg.Copyright))
|
||||
file.WriteString(fmt.Sprintf("original_or_copy:%d\n", pkg.Original_or_copy))
|
||||
file.WriteString(fmt.Sprintf("PTS_DTS_flags:%d\n", pkg.PTS_DTS_flags))
|
||||
file.WriteString(fmt.Sprintf("ESCR_flag:%d\n", pkg.ESCR_flag))
|
||||
file.WriteString(fmt.Sprintf("ES_rate_flag:%d\n", pkg.ES_rate_flag))
|
||||
file.WriteString(fmt.Sprintf("DSM_trick_mode_flag:%d\n", pkg.DSM_trick_mode_flag))
|
||||
file.WriteString(fmt.Sprintf("additional_copy_info_flag:%d\n", pkg.Additional_copy_info_flag))
|
||||
file.WriteString(fmt.Sprintf("PES_CRC_flag:%d\n", pkg.PES_CRC_flag))
|
||||
file.WriteString(fmt.Sprintf("PES_extension_flag:%d\n", pkg.PES_extension_flag))
|
||||
file.WriteString(fmt.Sprintf("PES_header_data_length:%d\n", pkg.PES_header_data_length))
|
||||
if pkg.PTS_DTS_flags&0x02 == 0x02 {
|
||||
file.WriteString(fmt.Sprintf("PTS:%d\n", pkg.Pts))
|
||||
}
|
||||
if pkg.PTS_DTS_flags&0x03 == 0x03 {
|
||||
file.WriteString(fmt.Sprintf("DTS:%d\n", pkg.Dts))
|
||||
}
|
||||
|
||||
if pkg.ESCR_flag == 1 {
|
||||
file.WriteString(fmt.Sprintf("ESCR_base:%d\n", pkg.ESCR_base))
|
||||
file.WriteString(fmt.Sprintf("ESCR_extension:%d\n", pkg.ESCR_extension))
|
||||
}
|
||||
|
||||
if pkg.ES_rate_flag == 1 {
|
||||
file.WriteString(fmt.Sprintf("ES_rate:%d\n", pkg.ES_rate))
|
||||
}
|
||||
|
||||
if pkg.DSM_trick_mode_flag == 1 {
|
||||
file.WriteString(fmt.Sprintf("trick_mode_control:%d\n", pkg.Trick_mode_control))
|
||||
}
|
||||
|
||||
if pkg.Additional_copy_info_flag == 1 {
|
||||
file.WriteString(fmt.Sprintf("additional_copy_info:%d\n", pkg.Additional_copy_info))
|
||||
}
|
||||
|
||||
if pkg.PES_CRC_flag == 1 {
|
||||
file.WriteString(fmt.Sprintf("previous_PES_packet_CRC:%d\n", pkg.Previous_PES_packet_CRC))
|
||||
}
|
||||
file.WriteString("PES_packet_data_byte:\n")
|
||||
file.WriteString(fmt.Sprintf(" Size: %d\n", len(pkg.Pes_payload)))
|
||||
file.WriteString(" data:")
|
||||
for i := 0; i < 12 && i < len(pkg.Pes_payload); i++ {
|
||||
if i%4 == 0 {
|
||||
file.WriteString("\n")
|
||||
file.WriteString(" ")
|
||||
}
|
||||
file.WriteString(fmt.Sprintf("0x%02x ", pkg.Pes_payload[i]))
|
||||
}
|
||||
file.WriteString("\n")
|
||||
}
|
||||
|
||||
func (pkg *PesPacket) Decode(bs *codec.BitStream) error {
|
||||
if bs.RemainBytes() < 9 {
|
||||
return errNeedMore
|
||||
}
|
||||
bs.SkipBits(24) //packet_start_code_prefix
|
||||
pkg.Stream_id = bs.Uint8(8) //stream_id
|
||||
pkg.PES_packet_length = bs.Uint16(16)
|
||||
bs.SkipBits(2) //'10'
|
||||
pkg.PES_scrambling_control = bs.Uint8(2)
|
||||
pkg.PES_priority = bs.Uint8(1)
|
||||
pkg.Data_alignment_indicator = bs.Uint8(1)
|
||||
pkg.Copyright = bs.Uint8(1)
|
||||
pkg.Original_or_copy = bs.Uint8(1)
|
||||
pkg.PTS_DTS_flags = bs.Uint8(2)
|
||||
pkg.ESCR_flag = bs.Uint8(1)
|
||||
pkg.ES_rate_flag = bs.Uint8(1)
|
||||
pkg.DSM_trick_mode_flag = bs.Uint8(1)
|
||||
pkg.Additional_copy_info_flag = bs.Uint8(1)
|
||||
pkg.PES_CRC_flag = bs.Uint8(1)
|
||||
pkg.PES_extension_flag = bs.Uint8(1)
|
||||
pkg.PES_header_data_length = bs.Uint8(8)
|
||||
if bs.RemainBytes() < int(pkg.PES_header_data_length) {
|
||||
bs.UnRead(9 * 8)
|
||||
return errNeedMore
|
||||
}
|
||||
bs.Markdot()
|
||||
if pkg.PTS_DTS_flags&0x02 == 0x02 {
|
||||
bs.SkipBits(4)
|
||||
pkg.Pts = bs.GetBits(3)
|
||||
bs.SkipBits(1)
|
||||
pkg.Pts = (pkg.Pts << 15) | bs.GetBits(15)
|
||||
bs.SkipBits(1)
|
||||
pkg.Pts = (pkg.Pts << 15) | bs.GetBits(15)
|
||||
bs.SkipBits(1)
|
||||
}
|
||||
if pkg.PTS_DTS_flags&0x03 == 0x03 {
|
||||
bs.SkipBits(4)
|
||||
pkg.Dts = bs.GetBits(3)
|
||||
bs.SkipBits(1)
|
||||
pkg.Dts = (pkg.Dts << 15) | bs.GetBits(15)
|
||||
bs.SkipBits(1)
|
||||
pkg.Dts = (pkg.Dts << 15) | bs.GetBits(15)
|
||||
bs.SkipBits(1)
|
||||
} else {
|
||||
pkg.Dts = pkg.Pts
|
||||
}
|
||||
|
||||
if pkg.ESCR_flag == 1 {
|
||||
bs.SkipBits(2)
|
||||
pkg.ESCR_base = bs.GetBits(3)
|
||||
bs.SkipBits(1)
|
||||
pkg.ESCR_base = (pkg.Pts << 15) | bs.GetBits(15)
|
||||
bs.SkipBits(1)
|
||||
pkg.ESCR_base = (pkg.Pts << 15) | bs.GetBits(15)
|
||||
bs.SkipBits(1)
|
||||
pkg.ESCR_extension = bs.Uint16(9)
|
||||
bs.SkipBits(1)
|
||||
}
|
||||
|
||||
if pkg.ES_rate_flag == 1 {
|
||||
bs.SkipBits(1)
|
||||
pkg.ES_rate = bs.Uint32(22)
|
||||
bs.SkipBits(1)
|
||||
}
|
||||
|
||||
if pkg.DSM_trick_mode_flag == 1 {
|
||||
pkg.Trick_mode_control = bs.Uint8(3)
|
||||
pkg.Trick_value = bs.Uint8(5)
|
||||
}
|
||||
|
||||
if pkg.Additional_copy_info_flag == 1 {
|
||||
pkg.Additional_copy_info = bs.Uint8(7)
|
||||
}
|
||||
|
||||
if pkg.PES_CRC_flag == 1 {
|
||||
pkg.Previous_PES_packet_CRC = bs.Uint16(16)
|
||||
}
|
||||
|
||||
loc := bs.DistanceFromMarkDot()
|
||||
bs.SkipBits(int(pkg.PES_header_data_length)*8 - loc) // skip remaining header
|
||||
|
||||
// the -3 bytes are the combined lengths
|
||||
// of all fields between PES_packet_length and PES_header_data_length (2 bytes)
|
||||
// and the PES_header_data_length itself (1 byte)
|
||||
dataLen := int(pkg.PES_packet_length - 3 - uint16(pkg.PES_header_data_length))
|
||||
|
||||
if bs.RemainBytes() < dataLen {
|
||||
pkg.Pes_payload = bs.RemainData()
|
||||
bs.UnRead((9 + int(pkg.PES_header_data_length)) * 8)
|
||||
return errNeedMore
|
||||
}
|
||||
|
||||
if pkg.PES_packet_length == 0 || bs.RemainBytes() <= dataLen {
|
||||
pkg.Pes_payload = bs.RemainData()
|
||||
bs.SkipBits(bs.RemainBits())
|
||||
} else {
|
||||
pkg.Pes_payload = bs.RemainData()[:dataLen]
|
||||
bs.SkipBits(dataLen * 8)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pkg *PesPacket) DecodeMpeg1(bs *codec.BitStream) error {
|
||||
if bs.RemainBytes() < 6 {
|
||||
return errNeedMore
|
||||
}
|
||||
bs.SkipBits(24) //packet_start_code_prefix
|
||||
pkg.Stream_id = bs.Uint8(8) //stream_id
|
||||
pkg.PES_packet_length = bs.Uint16(16)
|
||||
if pkg.PES_packet_length != 0 && bs.RemainBytes() < int(pkg.PES_packet_length) {
|
||||
bs.UnRead(6 * 8)
|
||||
return errNeedMore
|
||||
}
|
||||
bs.Markdot()
|
||||
for bs.NextBits(8) == 0xFF {
|
||||
bs.SkipBits(8)
|
||||
}
|
||||
if bs.NextBits(2) == 0x01 {
|
||||
bs.SkipBits(16)
|
||||
}
|
||||
if bs.NextBits(4) == 0x02 {
|
||||
bs.SkipBits(4)
|
||||
pkg.Pts = bs.GetBits(3)
|
||||
bs.SkipBits(1)
|
||||
pkg.Pts = pkg.Pts<<15 | bs.GetBits(15)
|
||||
bs.SkipBits(1)
|
||||
pkg.Pts = pkg.Pts<<15 | bs.GetBits(15)
|
||||
bs.SkipBits(1)
|
||||
} else if bs.NextBits(4) == 0x03 {
|
||||
bs.SkipBits(4)
|
||||
pkg.Pts = bs.GetBits(3)
|
||||
bs.SkipBits(1)
|
||||
pkg.Pts = pkg.Pts<<15 | bs.GetBits(15)
|
||||
bs.SkipBits(1)
|
||||
pkg.Pts = pkg.Pts<<15 | bs.GetBits(15)
|
||||
bs.SkipBits(1)
|
||||
pkg.Dts = bs.GetBits(3)
|
||||
bs.SkipBits(1)
|
||||
pkg.Dts = pkg.Pts<<15 | bs.GetBits(15)
|
||||
bs.SkipBits(1)
|
||||
pkg.Dts = pkg.Pts<<15 | bs.GetBits(15)
|
||||
bs.SkipBits(1)
|
||||
} else if bs.NextBits(8) == 0x0F {
|
||||
bs.SkipBits(8)
|
||||
} else {
|
||||
return errParser
|
||||
}
|
||||
loc := bs.DistanceFromMarkDot() / 8
|
||||
if pkg.PES_packet_length < uint16(loc) {
|
||||
return errParser
|
||||
}
|
||||
if pkg.PES_packet_length == 0 ||
|
||||
bs.RemainBits() <= int(pkg.PES_packet_length-uint16(loc))*8 {
|
||||
pkg.Pes_payload = bs.RemainData()
|
||||
bs.SkipBits(bs.RemainBits())
|
||||
} else {
|
||||
pkg.Pes_payload = bs.RemainData()[:pkg.PES_packet_length-uint16(loc)]
|
||||
bs.SkipBits(int(pkg.PES_packet_length-uint16(loc)) * 8)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pkg *PesPacket) Encode(bsw *codec.BitStreamWriter) {
|
||||
bsw.PutBytes([]byte{0x00, 0x00, 0x01})
|
||||
bsw.PutByte(pkg.Stream_id)
|
||||
bsw.PutUint16(pkg.PES_packet_length, 16)
|
||||
bsw.PutUint8(0x02, 2)
|
||||
bsw.PutUint8(pkg.PES_scrambling_control, 2)
|
||||
bsw.PutUint8(pkg.PES_priority, 1)
|
||||
bsw.PutUint8(pkg.Data_alignment_indicator, 1)
|
||||
bsw.PutUint8(pkg.Copyright, 1)
|
||||
bsw.PutUint8(pkg.Original_or_copy, 1)
|
||||
bsw.PutUint8(pkg.PTS_DTS_flags, 2)
|
||||
bsw.PutUint8(pkg.ESCR_flag, 1)
|
||||
bsw.PutUint8(pkg.ES_rate_flag, 1)
|
||||
bsw.PutUint8(pkg.DSM_trick_mode_flag, 1)
|
||||
bsw.PutUint8(pkg.Additional_copy_info_flag, 1)
|
||||
bsw.PutUint8(pkg.PES_CRC_flag, 1)
|
||||
bsw.PutUint8(pkg.PES_extension_flag, 1)
|
||||
bsw.PutByte(pkg.PES_header_data_length)
|
||||
if pkg.PTS_DTS_flags == 0x02 {
|
||||
bsw.PutUint8(0x02, 4)
|
||||
bsw.PutUint64(pkg.Pts>>30, 3)
|
||||
bsw.PutUint8(0x01, 1)
|
||||
bsw.PutUint64(pkg.Pts>>15, 15)
|
||||
bsw.PutUint8(0x01, 1)
|
||||
bsw.PutUint64(pkg.Pts, 15)
|
||||
bsw.PutUint8(0x01, 1)
|
||||
}
|
||||
|
||||
if pkg.PTS_DTS_flags == 0x03 {
|
||||
bsw.PutUint8(0x03, 4)
|
||||
bsw.PutUint64(pkg.Pts>>30, 3)
|
||||
bsw.PutUint8(0x01, 1)
|
||||
bsw.PutUint64(pkg.Pts>>15, 15)
|
||||
bsw.PutUint8(0x01, 1)
|
||||
bsw.PutUint64(pkg.Pts, 15)
|
||||
bsw.PutUint8(0x01, 1)
|
||||
bsw.PutUint8(0x01, 4)
|
||||
bsw.PutUint64(pkg.Dts>>30, 3)
|
||||
bsw.PutUint8(0x01, 1)
|
||||
bsw.PutUint64(pkg.Dts>>15, 15)
|
||||
bsw.PutUint8(0x01, 1)
|
||||
bsw.PutUint64(pkg.Dts, 15)
|
||||
bsw.PutUint8(0x01, 1)
|
||||
}
|
||||
|
||||
if pkg.ESCR_flag == 1 {
|
||||
bsw.PutUint8(0x03, 2)
|
||||
bsw.PutUint64(pkg.ESCR_base>>30, 3)
|
||||
bsw.PutUint8(0x01, 1)
|
||||
bsw.PutUint64(pkg.ESCR_base>>15, 15)
|
||||
bsw.PutUint8(0x01, 1)
|
||||
bsw.PutUint64(pkg.ESCR_base, 15)
|
||||
bsw.PutUint8(0x01, 1)
|
||||
}
|
||||
bsw.PutBytes(pkg.Pes_payload)
|
||||
}
|
280
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/mpeg2/ps-demuxer.go
generated
vendored
Normal file
280
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/mpeg2/ps-demuxer.go
generated
vendored
Normal file
|
@ -0,0 +1,280 @@
|
|||
package mpeg2
|
||||
|
||||
import (
|
||||
"github.com/yapingcat/gomedia/codec"
|
||||
)
|
||||
|
||||
type psstream struct {
|
||||
sid uint8
|
||||
cid PS_STREAM_TYPE
|
||||
pts uint64
|
||||
dts uint64
|
||||
streamBuf []byte
|
||||
}
|
||||
|
||||
func newpsstream(sid uint8, cid PS_STREAM_TYPE) *psstream {
|
||||
return &psstream{
|
||||
sid: sid,
|
||||
cid: cid,
|
||||
streamBuf: make([]byte, 0, 4096),
|
||||
}
|
||||
}
|
||||
|
||||
type PSDemuxer struct {
|
||||
streamMap map[uint8]*psstream
|
||||
pkg *PSPacket
|
||||
mpeg1 bool
|
||||
cache []byte
|
||||
OnFrame func(frame []byte, cid PS_STREAM_TYPE, pts uint64, dts uint64)
|
||||
//解ps包过程中,解码回调psm,system header,pes包等
|
||||
//decodeResult 解码ps包时的产生的错误
|
||||
//这个回调主要用于debug,查看是否ps包存在问题
|
||||
OnPacket func(pkg Display, decodeResult error)
|
||||
}
|
||||
|
||||
func NewPSDemuxer() *PSDemuxer {
|
||||
return &PSDemuxer{
|
||||
streamMap: make(map[uint8]*psstream),
|
||||
pkg: new(PSPacket),
|
||||
cache: make([]byte, 0, 256),
|
||||
OnFrame: nil,
|
||||
OnPacket: nil,
|
||||
}
|
||||
}
|
||||
|
||||
func (psdemuxer *PSDemuxer) Input(data []byte) error {
|
||||
var bs *codec.BitStream
|
||||
if len(psdemuxer.cache) > 0 {
|
||||
psdemuxer.cache = append(psdemuxer.cache, data...)
|
||||
bs = codec.NewBitStream(psdemuxer.cache)
|
||||
} else {
|
||||
bs = codec.NewBitStream(data)
|
||||
}
|
||||
|
||||
saveReseved := func() {
|
||||
tmpcache := make([]byte, bs.RemainBytes())
|
||||
copy(tmpcache, bs.RemainData())
|
||||
psdemuxer.cache = tmpcache
|
||||
}
|
||||
|
||||
var ret error = nil
|
||||
for !bs.EOS() {
|
||||
if mpegerr, ok := ret.(Error); ok {
|
||||
if mpegerr.NeedMore() {
|
||||
saveReseved()
|
||||
}
|
||||
break
|
||||
}
|
||||
if bs.RemainBits() < 32 {
|
||||
ret = errNeedMore
|
||||
saveReseved()
|
||||
break
|
||||
}
|
||||
prefix_code := bs.NextBits(32)
|
||||
switch prefix_code {
|
||||
case 0x000001BA: //pack header
|
||||
if psdemuxer.pkg.Header == nil {
|
||||
psdemuxer.pkg.Header = new(PSPackHeader)
|
||||
}
|
||||
ret = psdemuxer.pkg.Header.Decode(bs)
|
||||
psdemuxer.mpeg1 = psdemuxer.pkg.Header.IsMpeg1
|
||||
if psdemuxer.OnPacket != nil {
|
||||
psdemuxer.OnPacket(psdemuxer.pkg.Header, ret)
|
||||
}
|
||||
case 0x000001BB: //system header
|
||||
if psdemuxer.pkg.Header == nil {
|
||||
panic("psdemuxer.pkg.Header must not be nil")
|
||||
}
|
||||
if psdemuxer.pkg.System == nil {
|
||||
psdemuxer.pkg.System = new(System_header)
|
||||
}
|
||||
ret = psdemuxer.pkg.System.Decode(bs)
|
||||
if psdemuxer.OnPacket != nil {
|
||||
psdemuxer.OnPacket(psdemuxer.pkg.System, ret)
|
||||
}
|
||||
case 0x000001BC: //program stream map
|
||||
if psdemuxer.pkg.Psm == nil {
|
||||
psdemuxer.pkg.Psm = new(Program_stream_map)
|
||||
}
|
||||
if ret = psdemuxer.pkg.Psm.Decode(bs); ret == nil {
|
||||
for _, streaminfo := range psdemuxer.pkg.Psm.Stream_map {
|
||||
if _, found := psdemuxer.streamMap[streaminfo.Elementary_stream_id]; !found {
|
||||
stream := newpsstream(streaminfo.Elementary_stream_id, PS_STREAM_TYPE(streaminfo.Stream_type))
|
||||
psdemuxer.streamMap[stream.sid] = stream
|
||||
}
|
||||
}
|
||||
}
|
||||
if psdemuxer.OnPacket != nil {
|
||||
psdemuxer.OnPacket(psdemuxer.pkg.Psm, ret)
|
||||
}
|
||||
case 0x000001BD, 0x000001BE, 0x000001BF, 0x000001F0, 0x000001F1,
|
||||
0x000001F2, 0x000001F3, 0x000001F4, 0x000001F5, 0x000001F6,
|
||||
0x000001F7, 0x000001F8, 0x000001F9, 0x000001FA, 0x000001FB:
|
||||
if psdemuxer.pkg.CommPes == nil {
|
||||
psdemuxer.pkg.CommPes = new(CommonPesPacket)
|
||||
}
|
||||
ret = psdemuxer.pkg.CommPes.Decode(bs)
|
||||
case 0x000001FF: //program stream directory
|
||||
if psdemuxer.pkg.Psd == nil {
|
||||
psdemuxer.pkg.Psd = new(Program_stream_directory)
|
||||
}
|
||||
ret = psdemuxer.pkg.Psd.Decode(bs)
|
||||
case 0x000001B9: //MPEG_program_end_code
|
||||
continue
|
||||
default:
|
||||
if prefix_code&0xFFFFFFE0 == 0x000001C0 || prefix_code&0xFFFFFFE0 == 0x000001E0 {
|
||||
if psdemuxer.pkg.Pes == nil {
|
||||
psdemuxer.pkg.Pes = NewPesPacket()
|
||||
}
|
||||
if psdemuxer.mpeg1 {
|
||||
ret = psdemuxer.pkg.Pes.DecodeMpeg1(bs)
|
||||
} else {
|
||||
ret = psdemuxer.pkg.Pes.Decode(bs)
|
||||
}
|
||||
if psdemuxer.OnPacket != nil {
|
||||
psdemuxer.OnPacket(psdemuxer.pkg.Pes, ret)
|
||||
}
|
||||
if ret == nil {
|
||||
if stream, found := psdemuxer.streamMap[psdemuxer.pkg.Pes.Stream_id]; found {
|
||||
if psdemuxer.mpeg1 && stream.cid == PS_STREAM_UNKNOW {
|
||||
psdemuxer.guessCodecid(stream)
|
||||
}
|
||||
psdemuxer.demuxPespacket(stream, psdemuxer.pkg.Pes)
|
||||
} else {
|
||||
if psdemuxer.mpeg1 {
|
||||
stream := newpsstream(psdemuxer.pkg.Pes.Stream_id, PS_STREAM_UNKNOW)
|
||||
psdemuxer.streamMap[stream.sid] = stream
|
||||
stream.streamBuf = append(stream.streamBuf, psdemuxer.pkg.Pes.Pes_payload...)
|
||||
stream.pts = psdemuxer.pkg.Pes.Pts
|
||||
stream.dts = psdemuxer.pkg.Pes.Dts
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bs.SkipBits(8)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ret == nil && len(psdemuxer.cache) > 0 {
|
||||
psdemuxer.cache = nil
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (psdemuxer *PSDemuxer) Flush() {
|
||||
for _, stream := range psdemuxer.streamMap {
|
||||
if len(stream.streamBuf) == 0 {
|
||||
continue
|
||||
}
|
||||
if psdemuxer.OnFrame != nil {
|
||||
psdemuxer.OnFrame(stream.streamBuf, stream.cid, stream.pts/90, stream.dts/90)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (psdemuxer *PSDemuxer) guessCodecid(stream *psstream) {
|
||||
if stream.sid&0xE0 == uint8(PES_STREAM_AUDIO) {
|
||||
stream.cid = PS_STREAM_AAC
|
||||
} else if stream.sid&0xE0 == uint8(PES_STREAM_VIDEO) {
|
||||
h264score := 0
|
||||
h265score := 0
|
||||
codec.SplitFrame(stream.streamBuf, func(nalu []byte) bool {
|
||||
h264nalutype := codec.H264NaluTypeWithoutStartCode(nalu)
|
||||
h265nalutype := codec.H265NaluTypeWithoutStartCode(nalu)
|
||||
if h264nalutype == codec.H264_NAL_PPS ||
|
||||
h264nalutype == codec.H264_NAL_SPS ||
|
||||
h264nalutype == codec.H264_NAL_I_SLICE {
|
||||
h264score += 2
|
||||
} else if h264nalutype < 5 {
|
||||
h264score += 1
|
||||
} else if h264nalutype > 20 {
|
||||
h264score -= 1
|
||||
}
|
||||
|
||||
if h265nalutype == codec.H265_NAL_PPS ||
|
||||
h265nalutype == codec.H265_NAL_SPS ||
|
||||
h265nalutype == codec.H265_NAL_VPS ||
|
||||
(h265nalutype >= codec.H265_NAL_SLICE_BLA_W_LP && h265nalutype <= codec.H265_NAL_SLICE_CRA) {
|
||||
h265score += 2
|
||||
} else if h265nalutype >= codec.H265_NAL_Slice_TRAIL_N && h265nalutype <= codec.H265_NAL_SLICE_RASL_R {
|
||||
h265score += 1
|
||||
} else if h265nalutype > 40 {
|
||||
h265score -= 1
|
||||
}
|
||||
if h264score > h265score && h264score >= 4 {
|
||||
stream.cid = PS_STREAM_H264
|
||||
} else if h264score < h265score && h265score >= 4 {
|
||||
stream.cid = PS_STREAM_H265
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (psdemuxer *PSDemuxer) demuxPespacket(stream *psstream, pes *PesPacket) error {
|
||||
switch stream.cid {
|
||||
case PS_STREAM_AAC, PS_STREAM_G711A, PS_STREAM_G711U:
|
||||
return psdemuxer.demuxAudio(stream, pes)
|
||||
case PS_STREAM_H264, PS_STREAM_H265:
|
||||
return psdemuxer.demuxH26x(stream, pes)
|
||||
case PS_STREAM_UNKNOW:
|
||||
if stream.pts != pes.Pts {
|
||||
stream.streamBuf = nil
|
||||
}
|
||||
stream.streamBuf = append(stream.streamBuf, pes.Pes_payload...)
|
||||
stream.pts = pes.Pts
|
||||
stream.dts = pes.Dts
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (psdemuxer *PSDemuxer) demuxAudio(stream *psstream, pes *PesPacket) error {
|
||||
if stream.pts != pes.Pts && len(stream.streamBuf) > 0 {
|
||||
if psdemuxer.OnFrame != nil {
|
||||
psdemuxer.OnFrame(stream.streamBuf, stream.cid, stream.pts/90, stream.dts/90)
|
||||
}
|
||||
stream.streamBuf = stream.streamBuf[:0]
|
||||
}
|
||||
stream.streamBuf = append(stream.streamBuf, pes.Pes_payload...)
|
||||
stream.pts = pes.Pts
|
||||
stream.dts = pes.Dts
|
||||
return nil
|
||||
}
|
||||
|
||||
func (psdemuxer *PSDemuxer) demuxH26x(stream *psstream, pes *PesPacket) error {
|
||||
if len(stream.streamBuf) == 0 {
|
||||
stream.pts = pes.Pts
|
||||
stream.dts = pes.Dts
|
||||
}
|
||||
stream.streamBuf = append(stream.streamBuf, pes.Pes_payload...)
|
||||
start, sc := codec.FindStartCode(stream.streamBuf, 0)
|
||||
for start >= 0 {
|
||||
end, sc2 := codec.FindStartCode(stream.streamBuf, start+int(sc))
|
||||
if end < 0 {
|
||||
break
|
||||
}
|
||||
if stream.cid == PS_STREAM_H264 {
|
||||
naluType := codec.H264NaluType(stream.streamBuf[start:])
|
||||
if naluType != codec.H264_NAL_AUD {
|
||||
if psdemuxer.OnFrame != nil {
|
||||
psdemuxer.OnFrame(stream.streamBuf[start:end], stream.cid, stream.pts/90, stream.dts/90)
|
||||
}
|
||||
}
|
||||
} else if stream.cid == PS_STREAM_H265 {
|
||||
naluType := codec.H265NaluType(stream.streamBuf[start:])
|
||||
if naluType != codec.H265_NAL_AUD {
|
||||
if psdemuxer.OnFrame != nil {
|
||||
psdemuxer.OnFrame(stream.streamBuf[start:end], stream.cid, stream.pts/90, stream.dts/90)
|
||||
}
|
||||
}
|
||||
}
|
||||
start = end
|
||||
sc = sc2
|
||||
}
|
||||
stream.streamBuf = stream.streamBuf[start:]
|
||||
stream.pts = pes.Pts
|
||||
stream.dts = pes.Dts
|
||||
return nil
|
||||
}
|
148
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/mpeg2/ps-muxer.go
generated
vendored
Normal file
148
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/mpeg2/ps-muxer.go
generated
vendored
Normal file
|
@ -0,0 +1,148 @@
|
|||
package mpeg2
|
||||
|
||||
import "github.com/yapingcat/gomedia/codec"
|
||||
|
||||
type PSMuxer struct {
|
||||
system *System_header
|
||||
psm *Program_stream_map
|
||||
OnPacket func(pkg []byte)
|
||||
firstframe bool
|
||||
}
|
||||
|
||||
func NewPsMuxer() *PSMuxer {
|
||||
muxer := new(PSMuxer)
|
||||
muxer.firstframe = true
|
||||
muxer.system = new(System_header)
|
||||
muxer.system.Rate_bound = 26234
|
||||
muxer.psm = new(Program_stream_map)
|
||||
muxer.psm.Current_next_indicator = 1
|
||||
muxer.psm.Program_stream_map_version = 1
|
||||
muxer.OnPacket = nil
|
||||
return muxer
|
||||
}
|
||||
|
||||
func (muxer *PSMuxer) AddStream(cid PS_STREAM_TYPE) uint8 {
|
||||
if cid == PS_STREAM_H265 || cid == PS_STREAM_H264 {
|
||||
es := NewElementary_Stream(uint8(PES_STREAM_VIDEO) + muxer.system.Video_bound)
|
||||
es.P_STD_buffer_bound_scale = 1
|
||||
es.P_STD_buffer_size_bound = 400
|
||||
muxer.system.Streams = append(muxer.system.Streams, es)
|
||||
muxer.system.Video_bound++
|
||||
muxer.psm.Stream_map = append(muxer.psm.Stream_map, NewElementary_stream_elem(uint8(cid), es.Stream_id))
|
||||
muxer.psm.Program_stream_map_version++
|
||||
return es.Stream_id
|
||||
} else {
|
||||
es := NewElementary_Stream(uint8(PES_STREAM_AUDIO) + muxer.system.Audio_bound)
|
||||
es.P_STD_buffer_bound_scale = 0
|
||||
es.P_STD_buffer_size_bound = 32
|
||||
muxer.system.Streams = append(muxer.system.Streams, es)
|
||||
muxer.system.Audio_bound++
|
||||
muxer.psm.Stream_map = append(muxer.psm.Stream_map, NewElementary_stream_elem(uint8(cid), es.Stream_id))
|
||||
muxer.psm.Program_stream_map_version++
|
||||
return es.Stream_id
|
||||
}
|
||||
}
|
||||
|
||||
func (muxer *PSMuxer) Write(sid uint8, frame []byte, pts uint64, dts uint64) error {
|
||||
var stream *Elementary_stream_elem = nil
|
||||
for _, es := range muxer.psm.Stream_map {
|
||||
if es.Elementary_stream_id == sid {
|
||||
stream = es
|
||||
break
|
||||
}
|
||||
}
|
||||
if stream == nil {
|
||||
return errNotFound
|
||||
}
|
||||
var withaud bool = false
|
||||
var idr_flag bool = false
|
||||
var first bool = true
|
||||
var vcl bool = false
|
||||
if stream.Stream_type == uint8(PS_STREAM_H264) || stream.Stream_type == uint8(PS_STREAM_H265) {
|
||||
codec.SplitFrame(frame, func(nalu []byte) bool {
|
||||
if stream.Stream_type == uint8(PS_STREAM_H264) {
|
||||
nalu_type := codec.H264NaluTypeWithoutStartCode(nalu)
|
||||
if nalu_type == codec.H264_NAL_AUD {
|
||||
withaud = true
|
||||
return false
|
||||
} else if codec.IsH264VCLNaluType(nalu_type) {
|
||||
if nalu_type == codec.H264_NAL_I_SLICE {
|
||||
idr_flag = true
|
||||
}
|
||||
vcl = true
|
||||
return false
|
||||
}
|
||||
return true
|
||||
} else {
|
||||
nalu_type := codec.H265NaluTypeWithoutStartCode(nalu)
|
||||
if nalu_type == codec.H265_NAL_AUD {
|
||||
withaud = true
|
||||
return false
|
||||
} else if codec.IsH265VCLNaluType(nalu_type) {
|
||||
if nalu_type >= codec.H265_NAL_SLICE_BLA_W_LP && nalu_type <= codec.H265_NAL_SLICE_CRA {
|
||||
idr_flag = true
|
||||
}
|
||||
vcl = true
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
dts = dts * 90
|
||||
pts = pts * 90
|
||||
bsw := codec.NewBitStreamWriter(1024)
|
||||
var pack PSPackHeader
|
||||
pack.System_clock_reference_base = dts - 3600
|
||||
pack.System_clock_reference_extension = 0
|
||||
pack.Program_mux_rate = 6106
|
||||
pack.Encode(bsw)
|
||||
if muxer.firstframe || idr_flag {
|
||||
muxer.system.Encode(bsw)
|
||||
muxer.psm.Encode(bsw)
|
||||
muxer.firstframe = false
|
||||
}
|
||||
if muxer.OnPacket != nil {
|
||||
muxer.OnPacket(bsw.Bits())
|
||||
}
|
||||
bsw.Reset()
|
||||
pespkg := NewPesPacket()
|
||||
for len(frame) > 0 {
|
||||
peshdrlen := 13
|
||||
pespkg.Stream_id = sid
|
||||
pespkg.PTS_DTS_flags = 0x03
|
||||
pespkg.PES_header_data_length = 10
|
||||
pespkg.Pts = pts
|
||||
pespkg.Dts = dts
|
||||
if idr_flag {
|
||||
pespkg.Data_alignment_indicator = 1
|
||||
}
|
||||
if first && !withaud && vcl {
|
||||
if stream.Stream_type == uint8(PS_STREAM_H264) {
|
||||
pespkg.Pes_payload = append(pespkg.Pes_payload, H264_AUD_NALU...)
|
||||
peshdrlen += 6
|
||||
} else if stream.Stream_type == uint8(PS_STREAM_H265) {
|
||||
pespkg.Pes_payload = append(pespkg.Pes_payload, H265_AUD_NALU...)
|
||||
peshdrlen += 7
|
||||
}
|
||||
}
|
||||
if peshdrlen+len(frame) >= 0xFFFF {
|
||||
pespkg.PES_packet_length = 0xFFFF
|
||||
pespkg.Pes_payload = append(pespkg.Pes_payload, frame[0:0xFFFF-peshdrlen]...)
|
||||
frame = frame[0xFFFF-peshdrlen:]
|
||||
} else {
|
||||
pespkg.PES_packet_length = uint16(peshdrlen + len(frame))
|
||||
pespkg.Pes_payload = append(pespkg.Pes_payload, frame[0:]...)
|
||||
frame = frame[:0]
|
||||
}
|
||||
pespkg.Encode(bsw)
|
||||
pespkg.Pes_payload = pespkg.Pes_payload[:0]
|
||||
if muxer.OnPacket != nil {
|
||||
muxer.OnPacket(bsw.Bits())
|
||||
}
|
||||
bsw.Reset()
|
||||
first = false
|
||||
}
|
||||
return nil
|
||||
}
|
521
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/mpeg2/ps-proto.go
generated
vendored
Normal file
521
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/mpeg2/ps-proto.go
generated
vendored
Normal file
|
@ -0,0 +1,521 @@
|
|||
package mpeg2
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/yapingcat/gomedia/codec"
|
||||
)
|
||||
|
||||
type Error interface {
|
||||
NeedMore() bool
|
||||
ParserError() bool
|
||||
StreamIdNotFound() bool
|
||||
}
|
||||
|
||||
var errNeedMore error = &needmoreError{}
|
||||
|
||||
type needmoreError struct{}
|
||||
|
||||
func (e *needmoreError) Error() string { return "need more bytes" }
|
||||
func (e *needmoreError) NeedMore() bool { return true }
|
||||
func (e *needmoreError) ParserError() bool { return false }
|
||||
func (e *needmoreError) StreamIdNotFound() bool { return false }
|
||||
|
||||
var errParser error = &parserError{}
|
||||
|
||||
type parserError struct{}
|
||||
|
||||
func (e *parserError) Error() string { return "parser packet error" }
|
||||
func (e *parserError) NeedMore() bool { return false }
|
||||
func (e *parserError) ParserError() bool { return true }
|
||||
func (e *parserError) StreamIdNotFound() bool { return false }
|
||||
|
||||
var errNotFound error = &sidNotFoundError{}
|
||||
|
||||
type sidNotFoundError struct{}
|
||||
|
||||
func (e *sidNotFoundError) Error() string { return "stream id not found" }
|
||||
func (e *sidNotFoundError) NeedMore() bool { return false }
|
||||
func (e *sidNotFoundError) ParserError() bool { return false }
|
||||
func (e *sidNotFoundError) StreamIdNotFound() bool { return true }
|
||||
|
||||
type PS_STREAM_TYPE int
|
||||
|
||||
const (
|
||||
PS_STREAM_UNKNOW PS_STREAM_TYPE = 0xFF
|
||||
PS_STREAM_AAC PS_STREAM_TYPE = 0x0F
|
||||
PS_STREAM_H264 PS_STREAM_TYPE = 0x1B
|
||||
PS_STREAM_H265 PS_STREAM_TYPE = 0x24
|
||||
PS_STREAM_G711A PS_STREAM_TYPE = 0x90
|
||||
PS_STREAM_G711U PS_STREAM_TYPE = 0x91
|
||||
)
|
||||
|
||||
// Table 2-33 – Program Stream pack header
|
||||
// pack_header() {
|
||||
// pack_start_code 32 bslbf
|
||||
// '01' 2 bslbf
|
||||
// system_clock_reference_base [32..30] 3 bslbf
|
||||
// marker_bit 1 bslbf
|
||||
// system_clock_reference_base [29..15] 15 bslbf
|
||||
// marker_bit 1 bslbf
|
||||
// system_clock_reference_base [14..0] 15 bslbf
|
||||
// marker_bit 1 bslbf
|
||||
// system_clock_reference_extension 9 uimsbf
|
||||
// marker_bit 1 bslbf
|
||||
// program_mux_rate 22 uimsbf
|
||||
// marker_bit 1 bslbf
|
||||
// marker_bit 1 bslbf
|
||||
// reserved 5 bslbf
|
||||
// pack_stuffing_length 3 uimsbf
|
||||
// for (i = 0; i < pack_stuffing_length; i++) {
|
||||
// stuffing_byte 8 bslbf
|
||||
// }
|
||||
// if (nextbits() == system_header_start_code) {
|
||||
// system_header ()
|
||||
// }
|
||||
// }
|
||||
|
||||
type PSPackHeader struct {
|
||||
IsMpeg1 bool
|
||||
System_clock_reference_base uint64 //33 bits
|
||||
System_clock_reference_extension uint16 //9 bits
|
||||
Program_mux_rate uint32 //22 bits
|
||||
Pack_stuffing_length uint8 //3 bitss
|
||||
}
|
||||
|
||||
func (ps_pkg_hdr *PSPackHeader) PrettyPrint(file *os.File) {
|
||||
file.WriteString(fmt.Sprintf("IsMpeg1:%t\n", ps_pkg_hdr.IsMpeg1))
|
||||
file.WriteString(fmt.Sprintf("System_clock_reference_base:%d\n", ps_pkg_hdr.System_clock_reference_base))
|
||||
file.WriteString(fmt.Sprintf("System_clock_reference_extension:%d\n", ps_pkg_hdr.System_clock_reference_extension))
|
||||
file.WriteString(fmt.Sprintf("Program_mux_rate:%d\n", ps_pkg_hdr.Program_mux_rate))
|
||||
file.WriteString(fmt.Sprintf("Pack_stuffing_length:%d\n", ps_pkg_hdr.Pack_stuffing_length))
|
||||
}
|
||||
|
||||
func (ps_pkg_hdr *PSPackHeader) Decode(bs *codec.BitStream) error {
|
||||
if bs.RemainBytes() < 5 {
|
||||
return errNeedMore
|
||||
}
|
||||
if bs.Uint32(32) != 0x000001BA {
|
||||
panic("ps header must start with 000001BA")
|
||||
}
|
||||
|
||||
if bs.NextBits(2) == 0x01 { //mpeg2
|
||||
if bs.RemainBytes() < 10 {
|
||||
return errNeedMore
|
||||
}
|
||||
return ps_pkg_hdr.decodeMpeg2(bs)
|
||||
} else if bs.NextBits(4) == 0x02 { //mpeg1
|
||||
if bs.RemainBytes() < 8 {
|
||||
return errNeedMore
|
||||
}
|
||||
ps_pkg_hdr.IsMpeg1 = true
|
||||
return ps_pkg_hdr.decodeMpeg1(bs)
|
||||
} else {
|
||||
return errParser
|
||||
}
|
||||
}
|
||||
|
||||
func (ps_pkg_hdr *PSPackHeader) decodeMpeg2(bs *codec.BitStream) error {
|
||||
bs.SkipBits(2)
|
||||
ps_pkg_hdr.System_clock_reference_base = bs.GetBits(3)
|
||||
bs.SkipBits(1)
|
||||
ps_pkg_hdr.System_clock_reference_base = ps_pkg_hdr.System_clock_reference_base<<15 | bs.GetBits(15)
|
||||
bs.SkipBits(1)
|
||||
ps_pkg_hdr.System_clock_reference_base = ps_pkg_hdr.System_clock_reference_base<<15 | bs.GetBits(15)
|
||||
bs.SkipBits(1)
|
||||
ps_pkg_hdr.System_clock_reference_extension = bs.Uint16(9)
|
||||
bs.SkipBits(1)
|
||||
ps_pkg_hdr.Program_mux_rate = bs.Uint32(22)
|
||||
bs.SkipBits(1)
|
||||
bs.SkipBits(1)
|
||||
bs.SkipBits(5)
|
||||
ps_pkg_hdr.Pack_stuffing_length = bs.Uint8(3)
|
||||
if bs.RemainBytes() < int(ps_pkg_hdr.Pack_stuffing_length) {
|
||||
bs.UnRead(10 * 8)
|
||||
return errNeedMore
|
||||
}
|
||||
bs.SkipBits(int(ps_pkg_hdr.Pack_stuffing_length) * 8)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ps_pkg_hdr *PSPackHeader) decodeMpeg1(bs *codec.BitStream) error {
|
||||
bs.SkipBits(4)
|
||||
ps_pkg_hdr.System_clock_reference_base = bs.GetBits(3)
|
||||
bs.SkipBits(1)
|
||||
ps_pkg_hdr.System_clock_reference_base = ps_pkg_hdr.System_clock_reference_base<<15 | bs.GetBits(15)
|
||||
bs.SkipBits(1)
|
||||
ps_pkg_hdr.System_clock_reference_base = ps_pkg_hdr.System_clock_reference_base<<15 | bs.GetBits(15)
|
||||
bs.SkipBits(1)
|
||||
ps_pkg_hdr.System_clock_reference_extension = 1
|
||||
ps_pkg_hdr.Program_mux_rate = bs.Uint32(7)
|
||||
bs.SkipBits(1)
|
||||
ps_pkg_hdr.Program_mux_rate = ps_pkg_hdr.Program_mux_rate<<15 | bs.Uint32(15)
|
||||
bs.SkipBits(1)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ps_pkg_hdr *PSPackHeader) Encode(bsw *codec.BitStreamWriter) {
|
||||
bsw.PutBytes([]byte{0x00, 0x00, 0x01, 0xBA})
|
||||
bsw.PutUint8(1, 2)
|
||||
bsw.PutUint64(ps_pkg_hdr.System_clock_reference_base>>30, 3)
|
||||
bsw.PutUint8(1, 1)
|
||||
bsw.PutUint64(ps_pkg_hdr.System_clock_reference_base>>15, 15)
|
||||
bsw.PutUint8(1, 1)
|
||||
bsw.PutUint64(ps_pkg_hdr.System_clock_reference_base, 15)
|
||||
bsw.PutUint8(1, 1)
|
||||
bsw.PutUint16(ps_pkg_hdr.System_clock_reference_extension, 9)
|
||||
bsw.PutUint8(1, 1)
|
||||
bsw.PutUint32(ps_pkg_hdr.Program_mux_rate, 22)
|
||||
bsw.PutUint8(1, 1)
|
||||
bsw.PutUint8(1, 1)
|
||||
bsw.PutUint8(0x1F, 5)
|
||||
bsw.PutUint8(ps_pkg_hdr.Pack_stuffing_length, 3)
|
||||
bsw.PutRepetValue(0xFF, int(ps_pkg_hdr.Pack_stuffing_length))
|
||||
}
|
||||
|
||||
type Elementary_Stream struct {
|
||||
Stream_id uint8
|
||||
P_STD_buffer_bound_scale uint8
|
||||
P_STD_buffer_size_bound uint16
|
||||
}
|
||||
|
||||
func NewElementary_Stream(sid uint8) *Elementary_Stream {
|
||||
return &Elementary_Stream{
|
||||
Stream_id: sid,
|
||||
}
|
||||
}
|
||||
|
||||
// system_header () {
|
||||
// system_header_start_code 32 bslbf
|
||||
// header_length 16 uimsbf
|
||||
// marker_bit 1 bslbf
|
||||
// rate_bound 22 uimsbf
|
||||
// marker_bit 1 bslbf
|
||||
// audio_bound 6 uimsbf
|
||||
// fixed_flag 1 bslbf
|
||||
// CSPS_flag 1 bslbf
|
||||
// system_audio_lock_flag 1 bslbf
|
||||
// system_video_lock_flag 1 bslbf
|
||||
// marker_bit 1 bslbf
|
||||
// video_bound 5 uimsbf
|
||||
// packet_rate_restriction_flag 1 bslbf
|
||||
// reserved_bits 7 bslbf
|
||||
// while (nextbits () == '1') {
|
||||
// stream_id 8 uimsbf
|
||||
// '11' 2 bslbf
|
||||
// P-STD_buffer_bound_scale 1 bslbf
|
||||
// P-STD_buffer_size_bound 13 uimsbf
|
||||
// }
|
||||
// }
|
||||
|
||||
type System_header struct {
|
||||
Header_length uint16
|
||||
Rate_bound uint32
|
||||
Audio_bound uint8
|
||||
Fixed_flag uint8
|
||||
CSPS_flag uint8
|
||||
System_audio_lock_flag uint8
|
||||
System_video_lock_flag uint8
|
||||
Video_bound uint8
|
||||
Packet_rate_restriction_flag uint8
|
||||
Streams []*Elementary_Stream
|
||||
}
|
||||
|
||||
func (sh *System_header) PrettyPrint(file *os.File) {
|
||||
file.WriteString(fmt.Sprintf("Header_length:%d\n", sh.Header_length))
|
||||
file.WriteString(fmt.Sprintf("Rate_bound:%d\n", sh.Rate_bound))
|
||||
file.WriteString(fmt.Sprintf("Audio_bound:%d\n", sh.Audio_bound))
|
||||
file.WriteString(fmt.Sprintf("Fixed_flag:%d\n", sh.Fixed_flag))
|
||||
file.WriteString(fmt.Sprintf("CSPS_flag:%d\n", sh.CSPS_flag))
|
||||
file.WriteString(fmt.Sprintf("System_audio_lock_flag:%d\n", sh.System_audio_lock_flag))
|
||||
file.WriteString(fmt.Sprintf("System_video_lock_flag:%d\n", sh.System_video_lock_flag))
|
||||
file.WriteString(fmt.Sprintf("Video_bound:%d\n", sh.Video_bound))
|
||||
file.WriteString(fmt.Sprintf("Packet_rate_restriction_flag:%d\n", sh.Packet_rate_restriction_flag))
|
||||
for i, es := range sh.Streams {
|
||||
file.WriteString(fmt.Sprintf("----streams %d\n", i))
|
||||
file.WriteString(fmt.Sprintf(" Stream_id:%d\n", es.Stream_id))
|
||||
file.WriteString(fmt.Sprintf(" P_STD_buffer_bound_scale:%d\n", es.P_STD_buffer_bound_scale))
|
||||
file.WriteString(fmt.Sprintf(" P_STD_buffer_size_bound:%d\n", es.P_STD_buffer_size_bound))
|
||||
}
|
||||
}
|
||||
|
||||
func (sh *System_header) Encode(bsw *codec.BitStreamWriter) {
|
||||
bsw.PutBytes([]byte{0x00, 0x00, 0x01, 0xBB})
|
||||
loc := bsw.ByteOffset()
|
||||
bsw.PutUint16(0, 16)
|
||||
bsw.Markdot()
|
||||
bsw.PutUint8(1, 1)
|
||||
bsw.PutUint32(sh.Rate_bound, 22)
|
||||
bsw.PutUint8(1, 1)
|
||||
bsw.PutUint8(sh.Audio_bound, 6)
|
||||
bsw.PutUint8(sh.Fixed_flag, 1)
|
||||
bsw.PutUint8(sh.CSPS_flag, 1)
|
||||
bsw.PutUint8(sh.System_audio_lock_flag, 1)
|
||||
bsw.PutUint8(sh.System_video_lock_flag, 1)
|
||||
bsw.PutUint8(1, 1)
|
||||
bsw.PutUint8(sh.Video_bound, 5)
|
||||
bsw.PutUint8(sh.Packet_rate_restriction_flag, 1)
|
||||
bsw.PutUint8(0x7F, 7)
|
||||
for _, stream := range sh.Streams {
|
||||
bsw.PutUint8(stream.Stream_id, 8)
|
||||
bsw.PutUint8(3, 2)
|
||||
bsw.PutUint8(stream.P_STD_buffer_bound_scale, 1)
|
||||
bsw.PutUint16(stream.P_STD_buffer_size_bound, 13)
|
||||
}
|
||||
length := bsw.DistanceFromMarkDot() / 8
|
||||
bsw.SetUint16(uint16(length), loc)
|
||||
}
|
||||
|
||||
func (sh *System_header) Decode(bs *codec.BitStream) error {
|
||||
if bs.RemainBytes() < 12 {
|
||||
return errNeedMore
|
||||
}
|
||||
if bs.Uint32(32) != 0x000001BB {
|
||||
panic("system header must start with 000001BB")
|
||||
}
|
||||
sh.Header_length = bs.Uint16(16)
|
||||
if bs.RemainBytes() < int(sh.Header_length) {
|
||||
bs.UnRead(6 * 8)
|
||||
return errNeedMore
|
||||
}
|
||||
if sh.Header_length < 6 || (sh.Header_length-6)%3 != 0 {
|
||||
return errParser
|
||||
}
|
||||
bs.SkipBits(1)
|
||||
sh.Rate_bound = bs.Uint32(22)
|
||||
bs.SkipBits(1)
|
||||
sh.Audio_bound = bs.Uint8(6)
|
||||
sh.Fixed_flag = bs.Uint8(1)
|
||||
sh.CSPS_flag = bs.Uint8(1)
|
||||
sh.System_audio_lock_flag = bs.Uint8(1)
|
||||
sh.System_video_lock_flag = bs.Uint8(1)
|
||||
bs.SkipBits(1)
|
||||
sh.Video_bound = bs.Uint8(5)
|
||||
sh.Packet_rate_restriction_flag = bs.Uint8(1)
|
||||
bs.SkipBits(7)
|
||||
sh.Streams = sh.Streams[:0]
|
||||
least := sh.Header_length - 6
|
||||
for least > 0 && bs.NextBits(1) == 0x01 {
|
||||
es := new(Elementary_Stream)
|
||||
es.Stream_id = bs.Uint8(8)
|
||||
bs.SkipBits(2)
|
||||
es.P_STD_buffer_bound_scale = bs.GetBit()
|
||||
es.P_STD_buffer_size_bound = bs.Uint16(13)
|
||||
sh.Streams = append(sh.Streams, es)
|
||||
least -= 3
|
||||
}
|
||||
if least > 0 {
|
||||
return errParser
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Elementary_stream_elem struct {
|
||||
Stream_type uint8
|
||||
Elementary_stream_id uint8
|
||||
Elementary_stream_info_length uint16
|
||||
}
|
||||
|
||||
func NewElementary_stream_elem(stype uint8, esid uint8) *Elementary_stream_elem {
|
||||
return &Elementary_stream_elem{
|
||||
Stream_type: stype,
|
||||
Elementary_stream_id: esid,
|
||||
}
|
||||
}
|
||||
|
||||
// program_stream_map() {
|
||||
// packet_start_code_prefix 24 bslbf
|
||||
// map_stream_id 8 uimsbf
|
||||
// program_stream_map_length 16 uimsbf
|
||||
// current_next_indicator 1 bslbf
|
||||
// reserved 2 bslbf
|
||||
// program_stream_map_version 5 uimsbf
|
||||
// reserved 7 bslbf
|
||||
// marker_bit 1 bslbf
|
||||
// program_stream_info_length 16 uimsbf
|
||||
// for (i = 0; i < N; i++) {
|
||||
// descriptor()
|
||||
// }
|
||||
// elementary_stream_map_length 16 uimsbf
|
||||
// for (i = 0; i < N1; i++) {
|
||||
// stream_type 8 uimsbf
|
||||
// elementary_stream_id 8 uimsbf
|
||||
// elementary_stream_info_length 16 uimsbf
|
||||
// for (i = 0; i < N2; i++) {
|
||||
// descriptor()
|
||||
// }
|
||||
// }
|
||||
// CRC_32 32 rpchof
|
||||
// }
|
||||
|
||||
type Program_stream_map struct {
|
||||
Map_stream_id uint8
|
||||
Program_stream_map_length uint16
|
||||
Current_next_indicator uint8
|
||||
Program_stream_map_version uint8
|
||||
Program_stream_info_length uint16
|
||||
Elementary_stream_map_length uint16
|
||||
Stream_map []*Elementary_stream_elem
|
||||
}
|
||||
|
||||
func (psm *Program_stream_map) PrettyPrint(file *os.File) {
|
||||
file.WriteString(fmt.Sprintf("map_stream_id:%d\n", psm.Map_stream_id))
|
||||
file.WriteString(fmt.Sprintf("program_stream_map_length:%d\n", psm.Program_stream_map_length))
|
||||
file.WriteString(fmt.Sprintf("current_next_indicator:%d\n", psm.Current_next_indicator))
|
||||
file.WriteString(fmt.Sprintf("program_stream_map_version:%d\n", psm.Program_stream_map_version))
|
||||
file.WriteString(fmt.Sprintf("program_stream_info_length:%d\n", psm.Program_stream_info_length))
|
||||
file.WriteString(fmt.Sprintf("elementary_stream_map_length:%d\n", psm.Elementary_stream_map_length))
|
||||
for i, es := range psm.Stream_map {
|
||||
file.WriteString(fmt.Sprintf("----ES stream %d\n", i))
|
||||
if es.Stream_type == uint8(PS_STREAM_AAC) {
|
||||
file.WriteString(" stream_type:AAC\n")
|
||||
} else if es.Stream_type == uint8(PS_STREAM_G711A) {
|
||||
file.WriteString(" stream_type:G711A\n")
|
||||
} else if es.Stream_type == uint8(PS_STREAM_G711U) {
|
||||
file.WriteString(" stream_type:G711U\n")
|
||||
} else if es.Stream_type == uint8(PS_STREAM_H264) {
|
||||
file.WriteString(" stream_type:H264\n")
|
||||
} else if es.Stream_type == uint8(PS_STREAM_H265) {
|
||||
file.WriteString(" stream_type:H265\n")
|
||||
}
|
||||
file.WriteString(fmt.Sprintf(" elementary_stream_id:%d\n", es.Elementary_stream_id))
|
||||
file.WriteString(fmt.Sprintf(" elementary_stream_info_length:%d\n", es.Elementary_stream_info_length))
|
||||
}
|
||||
}
|
||||
|
||||
func (psm *Program_stream_map) Encode(bsw *codec.BitStreamWriter) {
|
||||
bsw.PutBytes([]byte{0x00, 0x00, 0x01, 0xBC})
|
||||
loc := bsw.ByteOffset()
|
||||
bsw.PutUint16(psm.Program_stream_map_length, 16)
|
||||
bsw.Markdot()
|
||||
bsw.PutUint8(psm.Current_next_indicator, 1)
|
||||
bsw.PutUint8(3, 2)
|
||||
bsw.PutUint8(psm.Program_stream_map_version, 5)
|
||||
bsw.PutUint8(0x7F, 7)
|
||||
bsw.PutUint8(1, 1)
|
||||
bsw.PutUint16(0, 16)
|
||||
psm.Elementary_stream_map_length = uint16(len(psm.Stream_map) * 4)
|
||||
bsw.PutUint16(psm.Elementary_stream_map_length, 16)
|
||||
for _, streaminfo := range psm.Stream_map {
|
||||
bsw.PutUint8(streaminfo.Stream_type, 8)
|
||||
bsw.PutUint8(streaminfo.Elementary_stream_id, 8)
|
||||
bsw.PutUint16(0, 16)
|
||||
}
|
||||
length := bsw.DistanceFromMarkDot()/8 + 4
|
||||
bsw.SetUint16(uint16(length), loc)
|
||||
crc := codec.CalcCrc32(0xffffffff, bsw.Bits()[bsw.ByteOffset()-int(length-4)-4:bsw.ByteOffset()])
|
||||
tmpcrc := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(tmpcrc, crc)
|
||||
bsw.PutBytes(tmpcrc)
|
||||
}
|
||||
|
||||
func (psm *Program_stream_map) Decode(bs *codec.BitStream) error {
|
||||
if bs.RemainBytes() < 16 {
|
||||
return errNeedMore
|
||||
}
|
||||
if bs.Uint32(24) != 0x000001 {
|
||||
panic("program stream map must startwith 0x000001")
|
||||
}
|
||||
psm.Map_stream_id = bs.Uint8(8)
|
||||
if psm.Map_stream_id != 0xBC {
|
||||
panic("map stream id must be 0xBC")
|
||||
}
|
||||
psm.Program_stream_map_length = bs.Uint16(16)
|
||||
if bs.RemainBytes() < int(psm.Program_stream_map_length) {
|
||||
bs.UnRead(6 * 8)
|
||||
return errNeedMore
|
||||
}
|
||||
psm.Current_next_indicator = bs.Uint8(1)
|
||||
bs.SkipBits(2)
|
||||
psm.Program_stream_map_version = bs.Uint8(5)
|
||||
bs.SkipBits(8)
|
||||
psm.Program_stream_info_length = bs.Uint16(16)
|
||||
if bs.RemainBytes() < int(psm.Program_stream_info_length)+2 {
|
||||
bs.UnRead(10 * 8)
|
||||
return errNeedMore
|
||||
}
|
||||
bs.SkipBits(int(psm.Program_stream_info_length) * 8)
|
||||
psm.Elementary_stream_map_length = bs.Uint16(16)
|
||||
if psm.Program_stream_map_length != 6+psm.Program_stream_info_length+psm.Elementary_stream_map_length+4 {
|
||||
return errParser
|
||||
}
|
||||
if bs.RemainBytes() < int(psm.Elementary_stream_map_length)+4 {
|
||||
bs.UnRead(12*8 + int(psm.Program_stream_info_length)*8)
|
||||
return errNeedMore
|
||||
}
|
||||
|
||||
i := 0
|
||||
psm.Stream_map = psm.Stream_map[:0]
|
||||
for i < int(psm.Elementary_stream_map_length) {
|
||||
elem := new(Elementary_stream_elem)
|
||||
elem.Stream_type = bs.Uint8(8)
|
||||
elem.Elementary_stream_id = bs.Uint8(8)
|
||||
elem.Elementary_stream_info_length = bs.Uint16(16)
|
||||
//TODO Parser descriptor
|
||||
if bs.RemainBytes() < int(elem.Elementary_stream_info_length) {
|
||||
return errParser
|
||||
}
|
||||
bs.SkipBits(int(elem.Elementary_stream_info_length) * 8)
|
||||
i += int(4 + elem.Elementary_stream_info_length)
|
||||
psm.Stream_map = append(psm.Stream_map, elem)
|
||||
}
|
||||
|
||||
if i != int(psm.Elementary_stream_map_length) {
|
||||
return errParser
|
||||
}
|
||||
|
||||
bs.SkipBits(32)
|
||||
return nil
|
||||
}
|
||||
|
||||
type Program_stream_directory struct {
|
||||
PES_packet_length uint16
|
||||
}
|
||||
|
||||
func (psd *Program_stream_directory) Decode(bs *codec.BitStream) error {
|
||||
if bs.RemainBytes() < 6 {
|
||||
return errNeedMore
|
||||
}
|
||||
if bs.Uint32(32) != 0x000001FF {
|
||||
panic("program stream directory 000001FF")
|
||||
}
|
||||
psd.PES_packet_length = bs.Uint16(16)
|
||||
if bs.RemainBytes() < int(psd.PES_packet_length) {
|
||||
bs.UnRead(6 * 8)
|
||||
return errNeedMore
|
||||
}
|
||||
//TODO Program Stream directory
|
||||
bs.SkipBits(int(psd.PES_packet_length) * 8)
|
||||
return nil
|
||||
}
|
||||
|
||||
type CommonPesPacket struct {
|
||||
Stream_id uint8
|
||||
PES_packet_length uint16
|
||||
}
|
||||
|
||||
func (compes *CommonPesPacket) Decode(bs *codec.BitStream) error {
|
||||
if bs.RemainBytes() < 6 {
|
||||
return errNeedMore
|
||||
}
|
||||
bs.SkipBits(24)
|
||||
compes.Stream_id = bs.Uint8(8)
|
||||
compes.PES_packet_length = bs.Uint16(16)
|
||||
if bs.RemainBytes() < int(compes.PES_packet_length) {
|
||||
bs.UnRead(6 * 8)
|
||||
return errNeedMore
|
||||
}
|
||||
bs.SkipBits(int(compes.PES_packet_length) * 8)
|
||||
return nil
|
||||
}
|
||||
|
||||
type PSPacket struct {
|
||||
Header *PSPackHeader
|
||||
System *System_header
|
||||
Psm *Program_stream_map
|
||||
Psd *Program_stream_directory
|
||||
CommPes *CommonPesPacket
|
||||
Pes *PesPacket
|
||||
}
|
218
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/mpeg2/ts-demuxer.go
generated
vendored
Normal file
218
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/mpeg2/ts-demuxer.go
generated
vendored
Normal file
|
@ -0,0 +1,218 @@
|
|||
package mpeg2
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"github.com/yapingcat/gomedia/codec"
|
||||
)
|
||||
|
||||
type pakcet_t struct {
|
||||
payload []byte
|
||||
pts uint64
|
||||
dts uint64
|
||||
}
|
||||
|
||||
func newPacket_t(size uint32) *pakcet_t {
|
||||
return &pakcet_t{
|
||||
payload: make([]byte, 0, size),
|
||||
pts: 0,
|
||||
dts: 0,
|
||||
}
|
||||
}
|
||||
|
||||
type tsstream struct {
|
||||
cid TS_STREAM_TYPE
|
||||
pes_sid PES_STREMA_ID
|
||||
pes_pkg *PesPacket
|
||||
pkg *pakcet_t
|
||||
}
|
||||
|
||||
type tsprogram struct {
|
||||
pn uint16
|
||||
streams map[uint16]*tsstream
|
||||
}
|
||||
|
||||
type TSDemuxer struct {
|
||||
programs map[uint16]*tsprogram
|
||||
OnFrame func(cid TS_STREAM_TYPE, frame []byte, pts uint64, dts uint64)
|
||||
OnTSPacket func(pkg *TSPacket)
|
||||
}
|
||||
|
||||
func NewTSDemuxer() *TSDemuxer {
|
||||
return &TSDemuxer{
|
||||
programs: make(map[uint16]*tsprogram),
|
||||
OnFrame: nil,
|
||||
OnTSPacket: nil,
|
||||
}
|
||||
}
|
||||
|
||||
func (demuxer *TSDemuxer) Input(r io.Reader) error {
|
||||
buf := make([]byte, TS_PAKCET_SIZE)
|
||||
_, err := io.ReadFull(r, buf)
|
||||
if err != nil {
|
||||
return errNeedMore
|
||||
}
|
||||
for {
|
||||
bs := codec.NewBitStream(buf)
|
||||
var pkg TSPacket
|
||||
if err := pkg.DecodeHeader(bs); err != nil {
|
||||
return err
|
||||
}
|
||||
if pkg.PID == uint16(TS_PID_PAT) {
|
||||
if pkg.Payload_unit_start_indicator == 1 {
|
||||
bs.SkipBits(8)
|
||||
}
|
||||
pat := NewPat()
|
||||
if err := pat.Decode(bs); err != nil {
|
||||
return err
|
||||
}
|
||||
pkg.Payload = pat
|
||||
if pat.Table_id != uint8(TS_TID_PAS) {
|
||||
return errors.New("pat table id is wrong")
|
||||
}
|
||||
for _, pmt := range pat.Pmts {
|
||||
if pmt.Program_number != 0x0000 {
|
||||
if _, found := demuxer.programs[pmt.PID]; !found {
|
||||
demuxer.programs[pmt.PID] = &tsprogram{pn: 0, streams: make(map[uint16]*tsstream)}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for p, s := range demuxer.programs {
|
||||
if p == pkg.PID { // pmt table
|
||||
if pkg.Payload_unit_start_indicator == 1 {
|
||||
bs.SkipBits(8) //pointer filed
|
||||
}
|
||||
pmt := NewPmt()
|
||||
if err := pmt.Decode(bs); err != nil {
|
||||
return err
|
||||
}
|
||||
pkg.Payload = pmt
|
||||
s.pn = pmt.Program_number
|
||||
for _, ps := range pmt.Streams {
|
||||
if _, found := s.streams[ps.Elementary_PID]; !found {
|
||||
s.streams[ps.Elementary_PID] = &tsstream{
|
||||
cid: TS_STREAM_TYPE(ps.StreamType),
|
||||
pes_sid: findPESIDByStreamType(TS_STREAM_TYPE(ps.StreamType)),
|
||||
pes_pkg: NewPesPacket(),
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for sid, stream := range s.streams {
|
||||
if sid != pkg.PID {
|
||||
continue
|
||||
}
|
||||
if pkg.Payload_unit_start_indicator == 1 {
|
||||
err := stream.pes_pkg.Decode(bs)
|
||||
// ignore error if it was a short payload read, next ts packet should append missing data
|
||||
if err != nil && !(errors.Is(err, errNeedMore) && stream.pes_pkg.Pes_payload != nil) {
|
||||
return err
|
||||
}
|
||||
pkg.Payload = stream.pes_pkg
|
||||
} else {
|
||||
stream.pes_pkg.Pes_payload = bs.RemainData()
|
||||
pkg.Payload = bs.RemainData()
|
||||
}
|
||||
stype := findPESIDByStreamType(stream.cid)
|
||||
if stype == PES_STREAM_AUDIO {
|
||||
demuxer.doAudioPesPacket(stream, pkg.Payload_unit_start_indicator)
|
||||
} else if stype == PES_STREAM_VIDEO {
|
||||
demuxer.doVideoPesPacket(stream, pkg.Payload_unit_start_indicator)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if demuxer.OnTSPacket != nil {
|
||||
demuxer.OnTSPacket(&pkg)
|
||||
}
|
||||
_, err := io.ReadFull(r, buf)
|
||||
if err != nil {
|
||||
if errors.Is(err, io.EOF) {
|
||||
break
|
||||
} else {
|
||||
return errNeedMore
|
||||
}
|
||||
}
|
||||
}
|
||||
demuxer.flush()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (demuxer *TSDemuxer) flush() {
|
||||
for _, pm := range demuxer.programs {
|
||||
for _, stream := range pm.streams {
|
||||
if stream.pkg == nil || len(stream.pkg.payload) == 0 {
|
||||
continue
|
||||
}
|
||||
if demuxer.OnFrame != nil {
|
||||
demuxer.OnFrame(stream.cid, stream.pkg.payload, stream.pkg.pts/90, stream.pkg.dts/90)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (demuxer *TSDemuxer) doVideoPesPacket(stream *tsstream, start uint8) {
|
||||
if stream.cid != TS_STREAM_H264 && stream.cid != TS_STREAM_H265 {
|
||||
return
|
||||
}
|
||||
if stream.pkg == nil {
|
||||
stream.pkg = newPacket_t(1024)
|
||||
stream.pkg.pts = stream.pes_pkg.Pts
|
||||
stream.pkg.dts = stream.pes_pkg.Dts
|
||||
}
|
||||
stream.pkg.payload = append(stream.pkg.payload, stream.pes_pkg.Pes_payload...)
|
||||
demuxer.splitH26XFrame(stream)
|
||||
stream.pkg.pts = stream.pes_pkg.Pts
|
||||
stream.pkg.dts = stream.pes_pkg.Dts
|
||||
}
|
||||
|
||||
func (demuxer *TSDemuxer) doAudioPesPacket(stream *tsstream, start uint8) {
|
||||
if stream.cid != TS_STREAM_AAC {
|
||||
return
|
||||
}
|
||||
|
||||
if stream.pkg == nil {
|
||||
stream.pkg = newPacket_t(1024)
|
||||
stream.pkg.pts = stream.pes_pkg.Pts
|
||||
stream.pkg.dts = stream.pes_pkg.Dts
|
||||
}
|
||||
|
||||
if len(stream.pkg.payload) > 0 && (start == 1 || stream.pes_pkg.Pts != stream.pkg.pts) {
|
||||
if demuxer.OnFrame != nil {
|
||||
demuxer.OnFrame(stream.cid, stream.pkg.payload, stream.pkg.pts/90, stream.pkg.dts/90)
|
||||
}
|
||||
stream.pkg.payload = stream.pkg.payload[:0]
|
||||
}
|
||||
stream.pkg.payload = append(stream.pkg.payload, stream.pes_pkg.Pes_payload...)
|
||||
stream.pkg.pts = stream.pes_pkg.Pts
|
||||
stream.pkg.dts = stream.pes_pkg.Dts
|
||||
}
|
||||
|
||||
func (demuxer *TSDemuxer) splitH26XFrame(stream *tsstream) {
|
||||
data := stream.pkg.payload
|
||||
start, _ := codec.FindStartCode(data, 0)
|
||||
datalen := len(data)
|
||||
for start < datalen {
|
||||
end, _ := codec.FindStartCode(data, start+3)
|
||||
if end < 0 {
|
||||
break
|
||||
}
|
||||
if (stream.cid == TS_STREAM_H264 && codec.H264NaluTypeWithoutStartCode(data[start:end]) == codec.H264_NAL_AUD) ||
|
||||
(stream.cid == TS_STREAM_H265 && codec.H265NaluTypeWithoutStartCode(data[start:end]) == codec.H265_NAL_AUD) {
|
||||
start = end
|
||||
continue
|
||||
}
|
||||
if demuxer.OnFrame != nil {
|
||||
demuxer.OnFrame(stream.cid, data[start:end], stream.pkg.pts/90, stream.pkg.dts/90)
|
||||
}
|
||||
start = end
|
||||
}
|
||||
if start == 0 {
|
||||
return
|
||||
}
|
||||
copy(stream.pkg.payload, data[start:datalen])
|
||||
stream.pkg.payload = stream.pkg.payload[0 : datalen-start]
|
||||
}
|
333
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/mpeg2/ts-muxer.go
generated
vendored
Normal file
333
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/mpeg2/ts-muxer.go
generated
vendored
Normal file
|
@ -0,0 +1,333 @@
|
|||
package mpeg2
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/yapingcat/gomedia/codec"
|
||||
)
|
||||
|
||||
type pes_stream struct {
|
||||
pid uint16
|
||||
cc uint8
|
||||
streamtype TS_STREAM_TYPE
|
||||
}
|
||||
|
||||
func NewPESStream(pid uint16, cid TS_STREAM_TYPE) *pes_stream {
|
||||
return &pes_stream{
|
||||
pid: pid,
|
||||
cc: 0,
|
||||
streamtype: cid,
|
||||
}
|
||||
}
|
||||
|
||||
type table_pmt struct {
|
||||
pid uint16
|
||||
cc uint8
|
||||
pcr_pid uint16
|
||||
version_number uint8
|
||||
pm uint16
|
||||
streams []*pes_stream
|
||||
}
|
||||
|
||||
func NewTablePmt() *table_pmt {
|
||||
return &table_pmt{
|
||||
pid: 0,
|
||||
cc: 0,
|
||||
pcr_pid: 0,
|
||||
version_number: 0,
|
||||
pm: 0,
|
||||
streams: make([]*pes_stream, 0, 2),
|
||||
}
|
||||
}
|
||||
|
||||
type table_pat struct {
|
||||
cc uint8
|
||||
version_number uint8
|
||||
pmts []*table_pmt
|
||||
}
|
||||
|
||||
func NewTablePat() *table_pat {
|
||||
return &table_pat{
|
||||
cc: 0,
|
||||
version_number: 0,
|
||||
pmts: make([]*table_pmt, 0, 8),
|
||||
}
|
||||
}
|
||||
|
||||
type TSMuxer struct {
|
||||
pat *table_pat
|
||||
stream_pid uint16
|
||||
pmt_pid uint16
|
||||
pat_period uint64
|
||||
OnPacket func(pkg []byte)
|
||||
}
|
||||
|
||||
func NewTSMuxer() *TSMuxer {
|
||||
return &TSMuxer{
|
||||
pat: NewTablePat(),
|
||||
stream_pid: 0x100,
|
||||
pmt_pid: 0x200,
|
||||
pat_period: 0,
|
||||
OnPacket: nil,
|
||||
}
|
||||
}
|
||||
|
||||
func (mux *TSMuxer) AddStream(cid TS_STREAM_TYPE) uint16 {
|
||||
if mux.pat == nil {
|
||||
mux.pat = NewTablePat()
|
||||
}
|
||||
if len(mux.pat.pmts) == 0 {
|
||||
tmppmt := NewTablePmt()
|
||||
tmppmt.pid = mux.pmt_pid
|
||||
tmppmt.pm = 1
|
||||
mux.pmt_pid++
|
||||
mux.pat.pmts = append(mux.pat.pmts, tmppmt)
|
||||
}
|
||||
sid := mux.stream_pid
|
||||
tmpstream := NewPESStream(sid, cid)
|
||||
mux.stream_pid++
|
||||
mux.pat.pmts[0].streams = append(mux.pat.pmts[0].streams, tmpstream)
|
||||
return sid
|
||||
}
|
||||
|
||||
/// Muxer audio/video stream data
|
||||
/// pid: stream id by AddStream
|
||||
/// pts: audio/video stream timestamp in ms
|
||||
/// dts: audio/video stream timestamp in ms
|
||||
func (mux *TSMuxer) Write(pid uint16, data []byte, pts uint64, dts uint64) error {
|
||||
var whichpmt *table_pmt = nil
|
||||
var whichstream *pes_stream = nil
|
||||
for _, pmt := range mux.pat.pmts {
|
||||
for _, stream := range pmt.streams {
|
||||
if stream.pid == pid {
|
||||
whichpmt = pmt
|
||||
whichstream = stream
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if whichpmt == nil || whichstream == nil {
|
||||
return errors.New("not Found pid stream")
|
||||
}
|
||||
if whichpmt.pcr_pid == 0 || (findPESIDByStreamType(whichstream.streamtype) == PES_STREAM_VIDEO && whichpmt.pcr_pid != pid) {
|
||||
whichpmt.pcr_pid = pid
|
||||
}
|
||||
|
||||
var withaud bool = false
|
||||
|
||||
if whichstream.streamtype == TS_STREAM_H264 || whichstream.streamtype == TS_STREAM_H265 {
|
||||
codec.SplitFrame(data, func(nalu []byte) bool {
|
||||
if whichstream.streamtype == TS_STREAM_H264 {
|
||||
nalu_type := codec.H264NaluTypeWithoutStartCode(nalu)
|
||||
if nalu_type == codec.H264_NAL_AUD {
|
||||
withaud = true
|
||||
return false
|
||||
} else if codec.IsH264VCLNaluType(nalu_type) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
} else {
|
||||
nalu_type := codec.H265NaluTypeWithoutStartCode(nalu)
|
||||
if nalu_type == codec.H265_NAL_AUD {
|
||||
withaud = true
|
||||
return false
|
||||
} else if codec.IsH265VCLNaluType(nalu_type) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if mux.pat_period == 0 || mux.pat_period+400 < dts {
|
||||
mux.pat_period = dts
|
||||
if mux.pat_period == 0 {
|
||||
mux.pat_period = 1 //avoid write pat twice
|
||||
}
|
||||
tmppat := NewPat()
|
||||
tmppat.Version_number = mux.pat.version_number
|
||||
for _, pmt := range mux.pat.pmts {
|
||||
tmppm := PmtPair{
|
||||
Program_number: pmt.pm,
|
||||
PID: pmt.pid,
|
||||
}
|
||||
tmppat.Pmts = append(tmppat.Pmts, tmppm)
|
||||
}
|
||||
mux.writePat(tmppat)
|
||||
|
||||
for _, pmt := range mux.pat.pmts {
|
||||
tmppmt := NewPmt()
|
||||
tmppmt.Program_number = pmt.pm
|
||||
tmppmt.Version_number = pmt.version_number
|
||||
tmppmt.PCR_PID = pmt.pcr_pid
|
||||
for _, stream := range pmt.streams {
|
||||
var sp StreamPair
|
||||
sp.StreamType = uint8(stream.streamtype)
|
||||
sp.Elementary_PID = stream.pid
|
||||
sp.ES_Info_Length = 0
|
||||
tmppmt.Streams = append(tmppmt.Streams, sp)
|
||||
}
|
||||
mux.writePmt(tmppmt, pmt)
|
||||
}
|
||||
}
|
||||
|
||||
flag := false
|
||||
switch whichstream.streamtype {
|
||||
case TS_STREAM_H264:
|
||||
flag = codec.IsH264IDRFrame(data)
|
||||
case TS_STREAM_H265:
|
||||
flag = codec.IsH265IDRFrame(data)
|
||||
}
|
||||
|
||||
mux.writePES(whichstream, whichpmt, data, pts*90, dts*90, flag, withaud)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mux *TSMuxer) writePat(pat *Pat) {
|
||||
var tshdr TSPacket
|
||||
tshdr.Payload_unit_start_indicator = 1
|
||||
tshdr.PID = 0
|
||||
tshdr.Adaptation_field_control = 0x01
|
||||
tshdr.Continuity_counter = mux.pat.cc
|
||||
mux.pat.cc++
|
||||
mux.pat.cc = (mux.pat.cc + 1) % 16
|
||||
bsw := codec.NewBitStreamWriter(TS_PAKCET_SIZE)
|
||||
tshdr.EncodeHeader(bsw)
|
||||
bsw.PutByte(0x00) //pointer
|
||||
pat.Encode(bsw)
|
||||
bsw.FillRemainData(0xff)
|
||||
if mux.OnPacket != nil {
|
||||
mux.OnPacket(bsw.Bits())
|
||||
}
|
||||
}
|
||||
|
||||
func (mux *TSMuxer) writePmt(pmt *Pmt, t_pmt *table_pmt) {
|
||||
var tshdr TSPacket
|
||||
tshdr.Payload_unit_start_indicator = 1
|
||||
tshdr.PID = t_pmt.pid
|
||||
tshdr.Adaptation_field_control = 0x01
|
||||
tshdr.Continuity_counter = t_pmt.cc
|
||||
t_pmt.cc = (t_pmt.cc + 1) % 16
|
||||
bsw := codec.NewBitStreamWriter(TS_PAKCET_SIZE)
|
||||
tshdr.EncodeHeader(bsw)
|
||||
bsw.PutByte(0x00) //pointer
|
||||
pmt.Encode(bsw)
|
||||
bsw.FillRemainData(0xff)
|
||||
if mux.OnPacket != nil {
|
||||
mux.OnPacket(bsw.Bits())
|
||||
}
|
||||
}
|
||||
|
||||
func (mux *TSMuxer) writePES(pes *pes_stream, pmt *table_pmt, data []byte, pts uint64, dts uint64, idr_flag bool, withaud bool) {
|
||||
var firstPesPacket bool = true
|
||||
bsw := codec.NewBitStreamWriter(TS_PAKCET_SIZE)
|
||||
for {
|
||||
bsw.Reset()
|
||||
var tshdr TSPacket
|
||||
if firstPesPacket {
|
||||
tshdr.Payload_unit_start_indicator = 1
|
||||
}
|
||||
tshdr.PID = pes.pid
|
||||
tshdr.Adaptation_field_control = 0x01
|
||||
tshdr.Continuity_counter = pes.cc
|
||||
headlen := 4
|
||||
pes.cc = (pes.cc + 1) % 16
|
||||
var adaptation *Adaptation_field = nil
|
||||
if firstPesPacket && idr_flag {
|
||||
adaptation = new(Adaptation_field)
|
||||
tshdr.Adaptation_field_control = tshdr.Adaptation_field_control | 0x20
|
||||
adaptation.Random_access_indicator = 1
|
||||
headlen += 2
|
||||
}
|
||||
|
||||
if firstPesPacket && pes.pid == pmt.pcr_pid {
|
||||
if adaptation == nil {
|
||||
adaptation = new(Adaptation_field)
|
||||
headlen += 2
|
||||
}
|
||||
tshdr.Adaptation_field_control = tshdr.Adaptation_field_control | 0x20
|
||||
adaptation.PCR_flag = 1
|
||||
var pcr_base uint64 = 0
|
||||
var pcr_ext uint16 = 0
|
||||
if dts == 0 {
|
||||
pcr_base = pts * 300 / 300
|
||||
pcr_ext = uint16(pts * 300 % 300)
|
||||
} else {
|
||||
pcr_base = dts * 300 / 300
|
||||
pcr_ext = uint16(dts * 300 % 300)
|
||||
}
|
||||
adaptation.Program_clock_reference_base = pcr_base
|
||||
adaptation.Program_clock_reference_extension = pcr_ext
|
||||
headlen += 6
|
||||
}
|
||||
|
||||
var payload []byte
|
||||
var pespkg *PesPacket = nil
|
||||
if firstPesPacket {
|
||||
oldheadlen := headlen
|
||||
headlen += 19
|
||||
if !withaud && pes.streamtype == TS_STREAM_H264 {
|
||||
headlen += 6
|
||||
payload = append(payload, H264_AUD_NALU...)
|
||||
} else if !withaud && pes.streamtype == TS_STREAM_H265 {
|
||||
payload = append(payload, H265_AUD_NALU...)
|
||||
headlen += 7
|
||||
}
|
||||
pespkg = NewPesPacket()
|
||||
pespkg.PTS_DTS_flags = 0x03
|
||||
pespkg.PES_header_data_length = 10
|
||||
pespkg.Pts = pts
|
||||
pespkg.Dts = dts
|
||||
pespkg.Stream_id = uint8(findPESIDByStreamType(pes.streamtype))
|
||||
if idr_flag {
|
||||
pespkg.Data_alignment_indicator = 1
|
||||
}
|
||||
if headlen-oldheadlen-6+len(data) > 0xFFFF {
|
||||
pespkg.PES_packet_length = 0
|
||||
} else {
|
||||
pespkg.PES_packet_length = uint16(len(data) + headlen - oldheadlen - 6)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if len(data)+headlen < TS_PAKCET_SIZE {
|
||||
if adaptation == nil {
|
||||
adaptation = new(Adaptation_field)
|
||||
headlen += 1
|
||||
if TS_PAKCET_SIZE-len(data)-headlen >= 1 {
|
||||
headlen += 1
|
||||
} else {
|
||||
adaptation.SingleStuffingByte = true
|
||||
}
|
||||
}
|
||||
adaptation.Stuffing_byte = uint8(TS_PAKCET_SIZE - len(data) - headlen)
|
||||
payload = append(payload, data...)
|
||||
data = data[:0]
|
||||
} else {
|
||||
payload = append(payload, data[0:TS_PAKCET_SIZE-headlen]...)
|
||||
data = data[TS_PAKCET_SIZE-headlen:]
|
||||
}
|
||||
|
||||
if adaptation != nil {
|
||||
tshdr.Field = adaptation
|
||||
tshdr.Adaptation_field_control |= 0x02
|
||||
}
|
||||
tshdr.EncodeHeader(bsw)
|
||||
if pespkg != nil {
|
||||
pespkg.Pes_payload = payload
|
||||
pespkg.Encode(bsw)
|
||||
} else {
|
||||
bsw.PutBytes(payload)
|
||||
}
|
||||
firstPesPacket = false
|
||||
if mux.OnPacket != nil {
|
||||
if len(bsw.Bits()) != TS_PAKCET_SIZE {
|
||||
panic("packet ts packet failed")
|
||||
}
|
||||
mux.OnPacket(bsw.Bits())
|
||||
}
|
||||
if len(data) == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
602
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/mpeg2/ts-proto.go
generated
vendored
Normal file
602
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/mpeg2/ts-proto.go
generated
vendored
Normal file
|
@ -0,0 +1,602 @@
|
|||
package mpeg2
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/yapingcat/gomedia/codec"
|
||||
)
|
||||
|
||||
//PID
|
||||
type TS_PID int
|
||||
|
||||
const (
|
||||
TS_PID_PAT TS_PID = 0x0000
|
||||
TS_PID_CAT
|
||||
TS_PID_TSDT
|
||||
TS_PID_IPMP
|
||||
TS_PID_Nil = 0x1FFFF
|
||||
)
|
||||
|
||||
//Table id
|
||||
type PAT_TID int
|
||||
|
||||
const (
|
||||
TS_TID_PAS PAT_TID = 0x00 // program_association_section
|
||||
TS_TID_CAS = 0x01 // conditional_access_section(CA_section)
|
||||
TS_TID_PMS = 0x02 // TS_program_map_section
|
||||
TS_TID_SDS = 0x03 //TS_description_section
|
||||
TS_TID_FORBIDDEN PAT_TID = 0xFF
|
||||
)
|
||||
|
||||
type TS_STREAM_TYPE int
|
||||
|
||||
const (
|
||||
TS_STREAM_AAC TS_STREAM_TYPE = 0x0F
|
||||
TS_STREAM_H264 TS_STREAM_TYPE = 0x1B
|
||||
TS_STREAM_H265 TS_STREAM_TYPE = 0x24
|
||||
)
|
||||
|
||||
const (
|
||||
TS_PAKCET_SIZE = 188
|
||||
)
|
||||
|
||||
type Display interface {
|
||||
PrettyPrint(file *os.File)
|
||||
}
|
||||
|
||||
// transport_packet(){
|
||||
// sync_byte 8 bslbf
|
||||
// transport_error_indicator 1 bslbf
|
||||
// payload_unit_start_indicator 1 bslbf
|
||||
// transport_priority 1 bslbf
|
||||
// PID 13 uimsbf
|
||||
// transport_scrambling_control 2 bslbf
|
||||
// adaptation_field_control 2 bslbf
|
||||
// continuity_counter 4 uimsbf
|
||||
// if(adaptation_field_control = = '10' || adaptation_field_control = = '11'){
|
||||
// adaptation_field()
|
||||
// }
|
||||
// if(adaptation_field_control = = '01' || adaptation_field_control = = '11') {
|
||||
// for (i = 0; i < N; i++){
|
||||
// data_byte 8 bslbf
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
type TSPacket struct {
|
||||
Transport_error_indicator uint8
|
||||
Payload_unit_start_indicator uint8
|
||||
Transport_priority uint8
|
||||
PID uint16
|
||||
Transport_scrambling_control uint8
|
||||
Adaptation_field_control uint8
|
||||
Continuity_counter uint8
|
||||
Field *Adaptation_field
|
||||
Payload interface{}
|
||||
}
|
||||
|
||||
func (pkg *TSPacket) PrettyPrint(file *os.File) {
|
||||
file.WriteString(fmt.Sprintf("Transport_error_indicator:%d\n", pkg.Transport_error_indicator))
|
||||
file.WriteString(fmt.Sprintf("Payload_unit_start_indicator:%d\n", pkg.Payload_unit_start_indicator))
|
||||
file.WriteString(fmt.Sprintf("Transport_priority:%d\n", pkg.Transport_priority))
|
||||
file.WriteString(fmt.Sprintf("PID:%d\n", pkg.PID))
|
||||
file.WriteString(fmt.Sprintf("Transport_scrambling_control:%d\n", pkg.Transport_scrambling_control))
|
||||
file.WriteString(fmt.Sprintf("Adaptation_field_control:%d\n", pkg.Adaptation_field_control))
|
||||
file.WriteString(fmt.Sprintf("Continuity_counter:%d\n", pkg.Continuity_counter))
|
||||
}
|
||||
|
||||
func (pkg *TSPacket) EncodeHeader(bsw *codec.BitStreamWriter) {
|
||||
bsw.PutByte(0x47)
|
||||
bsw.PutUint8(pkg.Transport_error_indicator, 1)
|
||||
bsw.PutUint8(pkg.Payload_unit_start_indicator, 1)
|
||||
bsw.PutUint8(pkg.Transport_priority, 1)
|
||||
bsw.PutUint16(pkg.PID, 13)
|
||||
bsw.PutUint8(pkg.Transport_scrambling_control, 2)
|
||||
bsw.PutUint8(pkg.Adaptation_field_control, 2)
|
||||
bsw.PutUint8(pkg.Continuity_counter, 4)
|
||||
if pkg.Field != nil && (pkg.Adaptation_field_control&0x02) != 0 {
|
||||
pkg.Field.Encode(bsw)
|
||||
}
|
||||
}
|
||||
|
||||
func (pkg *TSPacket) DecodeHeader(bs *codec.BitStream) error {
|
||||
sync_byte := bs.Uint8(8)
|
||||
if sync_byte != 0x47 {
|
||||
return errors.New("ts packet must start with 0x47")
|
||||
}
|
||||
pkg.Transport_error_indicator = bs.GetBit()
|
||||
pkg.Payload_unit_start_indicator = bs.GetBit()
|
||||
pkg.Transport_priority = bs.GetBit()
|
||||
pkg.PID = bs.Uint16(13)
|
||||
pkg.Transport_scrambling_control = bs.Uint8(2)
|
||||
pkg.Adaptation_field_control = bs.Uint8(2)
|
||||
pkg.Continuity_counter = bs.Uint8(4)
|
||||
if pkg.Adaptation_field_control == 0x02 || pkg.Adaptation_field_control == 0x03 {
|
||||
if pkg.Field == nil {
|
||||
pkg.Field = new(Adaptation_field)
|
||||
}
|
||||
err := pkg.Field.Decode(bs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//
|
||||
// adaptation_field() {
|
||||
// adaptation_field_length
|
||||
// if (adaptation_field_length > 0) {
|
||||
// discontinuity_indicator
|
||||
// random_access_indicator
|
||||
// elementary_stream_priority_indicator
|
||||
// PCR_flag
|
||||
// OPCR_flag
|
||||
// splicing_point_flag
|
||||
// transport_private_data_flag
|
||||
// adaptation_field_extension_flag
|
||||
// if (PCR_flag == '1') {
|
||||
// program_clock_reference_base
|
||||
// reserved
|
||||
// program_clock_reference_extension
|
||||
// }
|
||||
// if (OPCR_flag == '1') {
|
||||
// original_program_clock_reference_base
|
||||
// reserved
|
||||
// original_program_clock_reference_extension
|
||||
// }
|
||||
// if (splicing_point_flag == '1') {
|
||||
// splice_countdown
|
||||
// }
|
||||
// if (transport_private_data_flag == '1') {
|
||||
// transport_private_data_length
|
||||
// for (i = 0; i < transport_private_data_length; i++) {
|
||||
// private_data_byte
|
||||
// }
|
||||
// }
|
||||
// if (adaptation_field_extension_flag == '1') {
|
||||
// adaptation_field_extension_length
|
||||
// ltw_flag piecewise_rate_flag
|
||||
// seamless_splice_flag
|
||||
// reserved
|
||||
// if (ltw_flag == '1') {
|
||||
// ltw_valid_flag
|
||||
// ltw_offset
|
||||
// }
|
||||
// if (piecewise_rate_flag == '1') {
|
||||
// reserved
|
||||
// piecewise_rate
|
||||
// }
|
||||
// if (seamless_splice_flag == '1') {
|
||||
// splice_type
|
||||
// DTS_next_AU[32..30]
|
||||
// marker_bit
|
||||
// DTS_next_AU[29..15]
|
||||
// marker_bit
|
||||
// DTS_next_AU[14..0]
|
||||
// marker_bit 1
|
||||
// }
|
||||
// for (i = 0; i < N; i++) {
|
||||
// reserved 8
|
||||
// }
|
||||
// }
|
||||
// for (i = 0; i < N; i++) {
|
||||
// stuffing_byte 8
|
||||
// }
|
||||
// }
|
||||
|
||||
type Adaptation_field struct {
|
||||
SingleStuffingByte bool // The value 0 is for inserting a single stuffing byte in a Transport Stream packet
|
||||
Adaptation_field_length uint8 //8 uimsbf
|
||||
Discontinuity_indicator uint8 //1 bslbf
|
||||
Random_access_indicator uint8 //1 bslbf
|
||||
Elementary_stream_priority_indicator uint8 //1 bslbf
|
||||
PCR_flag uint8 //1 bslbf
|
||||
OPCR_flag uint8 //1 bslbf
|
||||
Splicing_point_flag uint8 //1 bslbf
|
||||
Transport_private_data_flag uint8 //1 bslbf
|
||||
Adaptation_field_extension_flag uint8 //1 bslbf
|
||||
Program_clock_reference_base uint64 //33 uimsbf
|
||||
Program_clock_reference_extension uint16 //9 uimsbf
|
||||
Original_program_clock_reference_base uint64 //33 uimsbf
|
||||
Original_program_clock_reference_extension uint16 //9 uimsbf
|
||||
Splice_countdown uint8 //8 uimsbf
|
||||
Transport_private_data_length uint8 //8 uimsbf
|
||||
Adaptation_field_extension_length uint8 //8 uimsbf
|
||||
Ltw_flag uint8 //1 bslbf
|
||||
Piecewise_rate_flag uint8 //1 bslbf
|
||||
Seamless_splice_flag uint8 //1 bslbf
|
||||
Ltw_valid_flag uint8 //1 bslbf
|
||||
Ltw_offset uint16 //15 uimsbf
|
||||
Piecewise_rate uint32 //22 uimsbf
|
||||
Splice_type uint8 //4 uimsbf
|
||||
DTS_next_AU uint64
|
||||
Stuffing_byte uint8
|
||||
}
|
||||
|
||||
func (adaptation *Adaptation_field) PrettyPrint(file *os.File) {
|
||||
file.WriteString(fmt.Sprintf("Adaptation_field_length:%d\n", adaptation.Adaptation_field_length))
|
||||
file.WriteString(fmt.Sprintf("Discontinuity_indicator:%d\n", adaptation.Discontinuity_indicator))
|
||||
file.WriteString(fmt.Sprintf("Random_access_indicator:%d\n", adaptation.Random_access_indicator))
|
||||
file.WriteString(fmt.Sprintf("Elementary_stream_priority_indicator:%d\n", adaptation.Elementary_stream_priority_indicator))
|
||||
file.WriteString(fmt.Sprintf("PCR_flag:%d\n", adaptation.PCR_flag))
|
||||
file.WriteString(fmt.Sprintf("OPCR_flag:%d\n", adaptation.OPCR_flag))
|
||||
file.WriteString(fmt.Sprintf("Splicing_point_flag:%d\n", adaptation.Splicing_point_flag))
|
||||
file.WriteString(fmt.Sprintf("Transport_private_data_flag:%d\n", adaptation.Transport_private_data_flag))
|
||||
file.WriteString(fmt.Sprintf("Adaptation_field_extension_flag:%d\n", adaptation.Adaptation_field_extension_flag))
|
||||
if adaptation.PCR_flag == 1 {
|
||||
file.WriteString(fmt.Sprintf("Program_clock_reference_base:%d\n", adaptation.Program_clock_reference_base))
|
||||
file.WriteString(fmt.Sprintf("Program_clock_reference_extension:%d\n", adaptation.Program_clock_reference_extension))
|
||||
}
|
||||
if adaptation.OPCR_flag == 1 {
|
||||
file.WriteString(fmt.Sprintf("Original_program_clock_reference_base:%d\n", adaptation.Original_program_clock_reference_base))
|
||||
file.WriteString(fmt.Sprintf("Original_program_clock_reference_extension:%d\n", adaptation.Original_program_clock_reference_extension))
|
||||
}
|
||||
if adaptation.Splicing_point_flag == 1 {
|
||||
file.WriteString(fmt.Sprintf("Splice_countdown:%d\n", adaptation.Splice_countdown))
|
||||
}
|
||||
if adaptation.Transport_private_data_flag == 1 {
|
||||
file.WriteString(fmt.Sprintf("Transport_private_data_length:%d\n", adaptation.Transport_private_data_length))
|
||||
}
|
||||
if adaptation.Adaptation_field_extension_flag == 1 {
|
||||
file.WriteString(fmt.Sprintf("Adaptation_field_extension_length:%d\n", adaptation.Adaptation_field_extension_length))
|
||||
file.WriteString(fmt.Sprintf("Ltw_flag:%d\n", adaptation.Ltw_flag))
|
||||
file.WriteString(fmt.Sprintf("Piecewise_rate_flag:%d\n", adaptation.Piecewise_rate_flag))
|
||||
file.WriteString(fmt.Sprintf("Seamless_splice_flag:%d\n", adaptation.Seamless_splice_flag))
|
||||
if adaptation.Ltw_flag == 1 {
|
||||
file.WriteString(fmt.Sprintf("Ltw_valid_flag:%d\n", adaptation.Ltw_valid_flag))
|
||||
file.WriteString(fmt.Sprintf("Ltw_offset:%d\n", adaptation.Ltw_offset))
|
||||
}
|
||||
if adaptation.Piecewise_rate_flag == 1 {
|
||||
file.WriteString(fmt.Sprintf("Piecewise_rate:%d\n", adaptation.Piecewise_rate))
|
||||
}
|
||||
if adaptation.Seamless_splice_flag == 1 {
|
||||
file.WriteString(fmt.Sprintf("Splice_type:%d\n", adaptation.Splice_type))
|
||||
file.WriteString(fmt.Sprintf("DTS_next_AU:%d\n", adaptation.DTS_next_AU))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (adaptation *Adaptation_field) Encode(bsw *codec.BitStreamWriter) {
|
||||
loc := bsw.ByteOffset()
|
||||
bsw.PutUint8(adaptation.Adaptation_field_length, 8)
|
||||
if adaptation.SingleStuffingByte {
|
||||
return
|
||||
}
|
||||
bsw.Markdot()
|
||||
bsw.PutUint8(adaptation.Discontinuity_indicator, 1)
|
||||
bsw.PutUint8(adaptation.Random_access_indicator, 1)
|
||||
bsw.PutUint8(adaptation.Elementary_stream_priority_indicator, 1)
|
||||
bsw.PutUint8(adaptation.PCR_flag, 1)
|
||||
bsw.PutUint8(adaptation.OPCR_flag, 1)
|
||||
bsw.PutUint8(adaptation.Splicing_point_flag, 1)
|
||||
bsw.PutUint8(0 /*adaptation.Transport_private_data_flag*/, 1)
|
||||
bsw.PutUint8(0 /*adaptation.Adaptation_field_extension_flag*/, 1)
|
||||
if adaptation.PCR_flag == 1 {
|
||||
bsw.PutUint64(adaptation.Program_clock_reference_base, 33)
|
||||
bsw.PutUint8(0, 6)
|
||||
bsw.PutUint16(adaptation.Program_clock_reference_extension, 9)
|
||||
}
|
||||
if adaptation.OPCR_flag == 1 {
|
||||
bsw.PutUint64(adaptation.Original_program_clock_reference_base, 33)
|
||||
bsw.PutUint8(0, 6)
|
||||
bsw.PutUint16(adaptation.Original_program_clock_reference_extension, 9)
|
||||
}
|
||||
if adaptation.Splicing_point_flag == 1 {
|
||||
bsw.PutUint8(adaptation.Splice_countdown, 8)
|
||||
}
|
||||
//TODO
|
||||
// if adaptation.Transport_private_data_flag == 0 {
|
||||
// }
|
||||
// if adaptation.Adaptation_field_extension_flag == 0 {
|
||||
// }
|
||||
adaptation.Adaptation_field_length = uint8(bsw.DistanceFromMarkDot() / 8)
|
||||
bsw.PutRepetValue(0xff, int(adaptation.Stuffing_byte))
|
||||
adaptation.Adaptation_field_length += adaptation.Stuffing_byte
|
||||
bsw.SetByte(adaptation.Adaptation_field_length, loc)
|
||||
}
|
||||
|
||||
func (adaptation *Adaptation_field) Decode(bs *codec.BitStream) error {
|
||||
if bs.RemainBytes() < 1 {
|
||||
return errors.New("len of data < 1 byte")
|
||||
}
|
||||
adaptation.Adaptation_field_length = bs.Uint8(8)
|
||||
startoffset := bs.ByteOffset()
|
||||
//fmt.Printf("Adaptation_field_length=%d\n", adaptation.Adaptation_field_length)
|
||||
if bs.RemainBytes() < int(adaptation.Adaptation_field_length) {
|
||||
return errors.New("len of data < Adaptation_field_length")
|
||||
}
|
||||
if adaptation.Adaptation_field_length == 0 {
|
||||
return nil
|
||||
}
|
||||
adaptation.Discontinuity_indicator = bs.GetBit()
|
||||
adaptation.Random_access_indicator = bs.GetBit()
|
||||
adaptation.Elementary_stream_priority_indicator = bs.GetBit()
|
||||
adaptation.PCR_flag = bs.GetBit()
|
||||
adaptation.OPCR_flag = bs.GetBit()
|
||||
adaptation.Splicing_point_flag = bs.GetBit()
|
||||
adaptation.Transport_private_data_flag = bs.GetBit()
|
||||
adaptation.Adaptation_field_extension_flag = bs.GetBit()
|
||||
if adaptation.PCR_flag == 1 {
|
||||
adaptation.Program_clock_reference_base = bs.GetBits(33)
|
||||
bs.SkipBits(6)
|
||||
adaptation.Program_clock_reference_extension = uint16(bs.GetBits(9))
|
||||
}
|
||||
if adaptation.OPCR_flag == 1 {
|
||||
adaptation.Original_program_clock_reference_base = bs.GetBits(33)
|
||||
bs.SkipBits(6)
|
||||
adaptation.Original_program_clock_reference_extension = uint16(bs.GetBits(9))
|
||||
}
|
||||
if adaptation.Splicing_point_flag == 1 {
|
||||
adaptation.Splice_countdown = bs.Uint8(8)
|
||||
}
|
||||
if adaptation.Transport_private_data_flag == 1 {
|
||||
adaptation.Transport_private_data_length = bs.Uint8(8)
|
||||
bs.SkipBits(8 * int(adaptation.Transport_private_data_length))
|
||||
}
|
||||
if adaptation.Adaptation_field_extension_flag == 1 {
|
||||
adaptation.Adaptation_field_extension_length = bs.Uint8(8)
|
||||
bs.Markdot()
|
||||
adaptation.Ltw_flag = bs.GetBit()
|
||||
adaptation.Piecewise_rate_flag = bs.GetBit()
|
||||
adaptation.Seamless_splice_flag = bs.GetBit()
|
||||
bs.SkipBits(5)
|
||||
if adaptation.Ltw_flag == 1 {
|
||||
adaptation.Ltw_valid_flag = bs.GetBit()
|
||||
adaptation.Ltw_offset = uint16(bs.GetBits(15))
|
||||
}
|
||||
if adaptation.Piecewise_rate_flag == 1 {
|
||||
bs.SkipBits(2)
|
||||
adaptation.Piecewise_rate = uint32(bs.GetBits(22))
|
||||
}
|
||||
if adaptation.Seamless_splice_flag == 1 {
|
||||
adaptation.Splice_type = uint8(bs.GetBits(4))
|
||||
adaptation.DTS_next_AU = bs.GetBits(3)
|
||||
bs.SkipBits(1)
|
||||
adaptation.DTS_next_AU = adaptation.DTS_next_AU<<15 | bs.GetBits(15)
|
||||
bs.SkipBits(1)
|
||||
adaptation.DTS_next_AU = adaptation.DTS_next_AU<<15 | bs.GetBits(15)
|
||||
bs.SkipBits(1)
|
||||
}
|
||||
bitscount := bs.DistanceFromMarkDot()
|
||||
if bitscount%8 > 0 {
|
||||
panic("maybe parser ts file failed")
|
||||
}
|
||||
bs.SkipBits(int(adaptation.Adaptation_field_extension_length*8 - uint8(bitscount)))
|
||||
}
|
||||
endoffset := bs.ByteOffset()
|
||||
bs.SkipBits((int(adaptation.Adaptation_field_length) - (endoffset - startoffset)) * 8)
|
||||
return nil
|
||||
}
|
||||
|
||||
type PmtPair struct {
|
||||
Program_number uint16
|
||||
PID uint16
|
||||
}
|
||||
|
||||
type Pat struct {
|
||||
Table_id uint8 //8 uimsbf
|
||||
Section_syntax_indicator uint8 //1 bslbf
|
||||
Section_length uint16 //12 uimsbf
|
||||
Transport_stream_id uint16 //16 uimsbf
|
||||
Version_number uint8 //5 uimsbf
|
||||
Current_next_indicator uint8 //1 bslbf
|
||||
Section_number uint8 //8 uimsbf
|
||||
Last_section_number uint8 //8 uimsbf
|
||||
Pmts []PmtPair
|
||||
}
|
||||
|
||||
func NewPat() *Pat {
|
||||
return &Pat{
|
||||
Table_id: uint8(TS_TID_PAS),
|
||||
Pmts: make([]PmtPair, 0, 8),
|
||||
}
|
||||
}
|
||||
|
||||
func (pat *Pat) PrettyPrint(file *os.File) {
|
||||
file.WriteString(fmt.Sprintf("Table id:%d\n", pat.Table_id))
|
||||
file.WriteString(fmt.Sprintf("Section_syntax_indicator:%d\n", pat.Section_syntax_indicator))
|
||||
file.WriteString(fmt.Sprintf("Section_length:%d\n", pat.Section_length))
|
||||
file.WriteString(fmt.Sprintf("Transport_stream_id:%d\n", pat.Transport_stream_id))
|
||||
file.WriteString(fmt.Sprintf("Version_number:%d\n", pat.Version_number))
|
||||
file.WriteString(fmt.Sprintf("Current_next_indicator:%d\n", pat.Current_next_indicator))
|
||||
file.WriteString(fmt.Sprintf("Section_number:%d\n", pat.Section_number))
|
||||
file.WriteString(fmt.Sprintf("Last_section_number:%d\n", pat.Last_section_number))
|
||||
for i, pmt := range pat.Pmts {
|
||||
file.WriteString(fmt.Sprintf("----pmt %d\n", i))
|
||||
file.WriteString(fmt.Sprintf(" program_number:%d\n", pmt.Program_number))
|
||||
if pmt.Program_number == 0x0000 {
|
||||
file.WriteString(fmt.Sprintf(" network_PID:%d\n", pmt.PID))
|
||||
} else {
|
||||
file.WriteString(fmt.Sprintf(" program_map_PID:%d\n", pmt.PID))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (pat *Pat) Encode(bsw *codec.BitStreamWriter) {
|
||||
bsw.PutUint8(0x00, 8)
|
||||
loc := bsw.ByteOffset()
|
||||
bsw.PutUint8(pat.Section_syntax_indicator, 1)
|
||||
bsw.PutUint8(0x00, 1)
|
||||
bsw.PutUint8(0x03, 2)
|
||||
bsw.PutUint16(0, 12)
|
||||
bsw.Markdot()
|
||||
bsw.PutUint16(pat.Transport_stream_id, 16)
|
||||
bsw.PutUint8(0x03, 2)
|
||||
bsw.PutUint8(pat.Version_number, 5)
|
||||
bsw.PutUint8(pat.Current_next_indicator, 1)
|
||||
bsw.PutUint8(pat.Section_number, 8)
|
||||
bsw.PutUint8(pat.Last_section_number, 8)
|
||||
for _, pms := range pat.Pmts {
|
||||
bsw.PutUint16(pms.Program_number, 16)
|
||||
bsw.PutUint8(0x07, 3)
|
||||
bsw.PutUint16(pms.PID, 13)
|
||||
}
|
||||
length := bsw.DistanceFromMarkDot()
|
||||
//|Section_syntax_indicator|'0'|reserved|Section_length|
|
||||
pat.Section_length = uint16(length)/8 + 4
|
||||
bsw.SetUint16(pat.Section_length&0x0FFF|(uint16(pat.Section_syntax_indicator)<<15)|0x3000, loc)
|
||||
crc := codec.CalcCrc32(0xffffffff, bsw.Bits()[bsw.ByteOffset()-int(pat.Section_length-4)-3:bsw.ByteOffset()])
|
||||
tmpcrc := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(tmpcrc, crc)
|
||||
bsw.PutBytes(tmpcrc)
|
||||
}
|
||||
|
||||
func (pat *Pat) Decode(bs *codec.BitStream) error {
|
||||
pat.Table_id = bs.Uint8(8)
|
||||
|
||||
if pat.Table_id != uint8(TS_TID_PAS) {
|
||||
return errors.New("table id is Not TS_TID_PAS")
|
||||
}
|
||||
pat.Section_syntax_indicator = bs.Uint8(1)
|
||||
bs.SkipBits(3)
|
||||
pat.Section_length = bs.Uint16(12)
|
||||
pat.Transport_stream_id = bs.Uint16(16)
|
||||
bs.SkipBits(2)
|
||||
pat.Version_number = bs.Uint8(5)
|
||||
pat.Current_next_indicator = bs.Uint8(1)
|
||||
pat.Section_number = bs.Uint8(8)
|
||||
pat.Last_section_number = bs.Uint8(8)
|
||||
for i := 0; i+4 <= int(pat.Section_length)-5-4; i = i + 4 {
|
||||
tmp := PmtPair{
|
||||
Program_number: 0,
|
||||
PID: 0,
|
||||
}
|
||||
tmp.Program_number = bs.Uint16(16)
|
||||
bs.SkipBits(3)
|
||||
tmp.PID = bs.Uint16(13)
|
||||
pat.Pmts = append(pat.Pmts, tmp)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type StreamPair struct {
|
||||
StreamType uint8 //8 uimsbf
|
||||
Elementary_PID uint16 //13 uimsbf
|
||||
ES_Info_Length uint16 //12 uimsbf
|
||||
}
|
||||
|
||||
type Pmt struct {
|
||||
Table_id uint8 //8 uimsbf
|
||||
Section_syntax_indicator uint8 //1 bslbf
|
||||
Section_length uint16 //12 uimsbf
|
||||
Program_number uint16 //16 uimsbf
|
||||
Version_number uint8 //5 uimsbf
|
||||
Current_next_indicator uint8 //1 bslbf
|
||||
Section_number uint8 //8 uimsbf
|
||||
Last_section_number uint8 //8 uimsbf
|
||||
PCR_PID uint16 //13 uimsbf
|
||||
Program_info_length uint16 //12 uimsbf
|
||||
Streams []StreamPair
|
||||
}
|
||||
|
||||
func NewPmt() *Pmt {
|
||||
return &Pmt{
|
||||
Table_id: uint8(TS_TID_PMS),
|
||||
Streams: make([]StreamPair, 0, 8),
|
||||
}
|
||||
}
|
||||
|
||||
func (pmt *Pmt) PrettyPrint(file *os.File) {
|
||||
file.WriteString(fmt.Sprintf("Table id:%d\n", pmt.Table_id))
|
||||
file.WriteString(fmt.Sprintf("Section_syntax_indicator:%d\n", pmt.Section_syntax_indicator))
|
||||
file.WriteString(fmt.Sprintf("Section_length:%d\n", pmt.Section_length))
|
||||
file.WriteString(fmt.Sprintf("Program_number:%d\n", pmt.Program_number))
|
||||
file.WriteString(fmt.Sprintf("Version_number:%d\n", pmt.Version_number))
|
||||
file.WriteString(fmt.Sprintf("Current_next_indicator:%d\n", pmt.Current_next_indicator))
|
||||
file.WriteString(fmt.Sprintf("Section_number:%d\n", pmt.Section_number))
|
||||
file.WriteString(fmt.Sprintf("Last_section_number:%d\n", pmt.Last_section_number))
|
||||
file.WriteString(fmt.Sprintf("PCR_PID:%d\n", pmt.PCR_PID))
|
||||
file.WriteString(fmt.Sprintf("program_info_length:%d\n", pmt.Program_info_length))
|
||||
for i, stream := range pmt.Streams {
|
||||
file.WriteString(fmt.Sprintf("----stream %d\n", i))
|
||||
if stream.StreamType == uint8(TS_STREAM_AAC) {
|
||||
file.WriteString(" stream_type:AAC\n")
|
||||
} else if stream.StreamType == uint8(TS_STREAM_H264) {
|
||||
file.WriteString(" stream_type:H264\n")
|
||||
} else if stream.StreamType == uint8(TS_STREAM_H265) {
|
||||
file.WriteString(" stream_type:H265\n")
|
||||
}
|
||||
file.WriteString(fmt.Sprintf(" elementary_PID:%d\n", stream.Elementary_PID))
|
||||
file.WriteString(fmt.Sprintf(" ES_info_length:%d\n", stream.ES_Info_Length))
|
||||
}
|
||||
}
|
||||
|
||||
func (pmt *Pmt) Encode(bsw *codec.BitStreamWriter) {
|
||||
bsw.PutUint8(pmt.Table_id, 8)
|
||||
loc := bsw.ByteOffset()
|
||||
bsw.PutUint8(pmt.Section_syntax_indicator, 1)
|
||||
bsw.PutUint8(0x00, 1)
|
||||
bsw.PutUint8(0x03, 2)
|
||||
bsw.PutUint16(pmt.Section_length, 12)
|
||||
bsw.Markdot()
|
||||
bsw.PutUint16(pmt.Program_number, 16)
|
||||
bsw.PutUint8(0x03, 2)
|
||||
bsw.PutUint8(pmt.Version_number, 5)
|
||||
bsw.PutUint8(pmt.Current_next_indicator, 1)
|
||||
bsw.PutUint8(pmt.Section_number, 8)
|
||||
bsw.PutUint8(pmt.Last_section_number, 8)
|
||||
bsw.PutUint8(0x07, 3)
|
||||
bsw.PutUint16(pmt.PCR_PID, 13)
|
||||
bsw.PutUint8(0x0f, 4)
|
||||
//TODO Program info length
|
||||
bsw.PutUint16(0x0000 /*pmt.Program_info_length*/, 12)
|
||||
for _, stream := range pmt.Streams {
|
||||
bsw.PutUint8(stream.StreamType, 8)
|
||||
bsw.PutUint8(0x00, 3)
|
||||
bsw.PutUint16(stream.Elementary_PID, 13)
|
||||
bsw.PutUint8(0x00, 4)
|
||||
//TODO ES_info
|
||||
bsw.PutUint8(0 /*ES_info_length*/, 12)
|
||||
}
|
||||
length := bsw.DistanceFromMarkDot()
|
||||
pmt.Section_length = uint16(length)/8 + 4
|
||||
bsw.SetUint16(pmt.Section_length&0x0FFF|(uint16(pmt.Section_syntax_indicator)<<15)|0x3000, loc)
|
||||
crc := codec.CalcCrc32(0xffffffff, bsw.Bits()[bsw.ByteOffset()-int(pmt.Section_length-4)-3:bsw.ByteOffset()])
|
||||
tmpcrc := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(tmpcrc, crc)
|
||||
bsw.PutBytes(tmpcrc)
|
||||
}
|
||||
|
||||
func (pmt *Pmt) Decode(bs *codec.BitStream) error {
|
||||
pmt.Table_id = bs.Uint8(8)
|
||||
if pmt.Table_id != uint8(TS_TID_PMS) {
|
||||
return errors.New("table id is Not TS_TID_PAS")
|
||||
}
|
||||
pmt.Section_syntax_indicator = bs.Uint8(1)
|
||||
bs.SkipBits(3)
|
||||
pmt.Section_length = bs.Uint16(12)
|
||||
pmt.Program_number = bs.Uint16(16)
|
||||
bs.SkipBits(2)
|
||||
pmt.Version_number = bs.Uint8(5)
|
||||
pmt.Current_next_indicator = bs.Uint8(1)
|
||||
pmt.Section_number = bs.Uint8(8)
|
||||
pmt.Last_section_number = bs.Uint8(8)
|
||||
bs.SkipBits(3)
|
||||
pmt.PCR_PID = bs.Uint16(13)
|
||||
bs.SkipBits(4)
|
||||
pmt.Program_info_length = bs.Uint16(12)
|
||||
//TODO N loop descriptors
|
||||
bs.SkipBits(int(pmt.Program_info_length) * 8)
|
||||
//fmt.Printf("section length %d pmt.Pogram_info_length=%d\n", pmt.Section_length, pmt.Pogram_info_length)
|
||||
for i := 0; i < int(pmt.Section_length)-9-int(pmt.Program_info_length)-4; {
|
||||
tmp := StreamPair{
|
||||
StreamType: 0,
|
||||
Elementary_PID: 0,
|
||||
ES_Info_Length: 0,
|
||||
}
|
||||
tmp.StreamType = bs.Uint8(8)
|
||||
bs.SkipBits(3)
|
||||
tmp.Elementary_PID = bs.Uint16(13)
|
||||
bs.SkipBits(4)
|
||||
tmp.ES_Info_Length = bs.Uint16(12)
|
||||
//TODO N loop descriptors
|
||||
bs.SkipBits(int(tmp.ES_Info_Length) * 8)
|
||||
pmt.Streams = append(pmt.Streams, tmp)
|
||||
i += 5 + int(tmp.ES_Info_Length)
|
||||
}
|
||||
return nil
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue