1
0
Fork 0
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:
Winlin 2022-10-06 17:40:58 +08:00 committed by GitHub
parent 9c81a0e1bd
commit 5a420ece3b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
298 changed files with 43343 additions and 763 deletions

View 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.

View file

@ -0,0 +1,89 @@
### USAGE
1. 如何解析sps/pps/vps
以解析sps为例
```golang
//sps原始数据,不带start code(0x00000001)
var rawsps []byte = []byte{0x67,....}
//step1 创建BitStream
bs := codec.NewBitStream(rawsps)
//step2 解析sps
sps := &SPS{}
sps.Decode(bs)
```
2. 获取视频宽高
以h264为例子
```golang
//sps原始数据,以startcode开头(0x00000001)
var rawsps []byte = []byte{0x00,0x00,0x00,0x01,0x67,.....}
w, h := codec.GetH264Resolution(rawsps)
```
3. 生成Extradata
以h264为例子
```golang
//多个sps原始数据,以startcode开头(0x00000001)
var spss [][]byte = [][]byte{
[]byte{0x00,0x00,0x00,0x01,0x67,...},
[]byte{0x00,0x00,0x00,0x01,0x67,...},
....
}
//多个pps原始数据,以startcode开头(0x00000001)
var ppss [][]byte = [][]byte{
[]byte{0x00,0x00,0x00,0x01,0x68,...},
[]byte{0x00,0x00,0x00,0x01,0x68,...},
....
}
extranData := codec.CreateH264AVCCExtradata(spss,ppss)
```
4. Extradata转为Annex-B格式的sps,pps
以h264为例子
```golang
//一般从flv/mp4格式中获取 extraData
//解析出来多个sps,pps, 且sps pps 都以startcode开头
spss,ppss := codec.CovertExtradata(extraData)
```
5. 生成H265 extrandata
```golang
// H265的extra data 生成过程稍微复杂一些
//创建一个 HEVCRecordConfiguration 对象
hvcc := codec.NewHEVCRecordConfiguration()
//对每一个 sps/pps/vps,调用相应的UpdateSPS,UpdatePPS,UpdateVPS接口
hvcc.UpdateSPS(sps)
hvcc.UpdatePPS(pps)
hvcc.UpdateVPS(vps)
//调用Encode接口生成
extran := hvcc.Encode()
```
6. 获取对应的sps id/vps id/pps id
```golang
//以h264为例子有四个接口
//sps 以startcode 开头
codec.GetSPSIdWithStartCode(sps)
//sps2 不以startcode 开头
codec.GetSPSId(sps2)
//pps 以startcode 开头
codec.GetPPSIdWithStartCode(pps)
//pps2 不以startcode 开头
codec.GetPPSId(pps2)
```

View file

@ -0,0 +1,255 @@
package codec
import "errors"
// Table 31 Profiles
// index profile
// 0 Main profile
// 1 Low Complexity profile (LC)
// 2 Scalable Sampling Rate profile (SSR)
// 3 (reserved)
type AAC_PROFILE int
const (
MAIN AAC_PROFILE = iota
LC
SSR
)
type AAC_SAMPLING_FREQUENCY int
const (
AAC_SAMPLE_96000 AAC_SAMPLING_FREQUENCY = iota
AAC_SAMPLE_88200
AAC_SAMPLE_64000
AAC_SAMPLE_48000
AAC_SAMPLE_44100
AAC_SAMPLE_32000
AAC_SAMPLE_24000
AAC_SAMPLE_22050
AAC_SAMPLE_16000
AAC_SAMPLE_11025
AAC_SAMPLE_8000
)
var AAC_Sampling_Idx [11]int = [11]int{96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 11025, 8000}
// Table 4 Syntax of adts_sequence()
// adts_sequence() {
// while (nextbits() == syncword) {
// adts_frame();
// }
// }
// Table 5 Syntax of adts_frame()
// adts_frame() {
// adts_fixed_header();
// adts_variable_header();
// if (number_of_raw_data_blocks_in_frame == 0) {
// adts_error_check();
// raw_data_block();
// }
// else {
// adts_header_error_check();
// for (i = 0; i <= number_of_raw_data_blocks_in_frame;i++ {
// raw_data_block();
// adts_raw_data_block_error_check();
// }
// }
// }
// adts_fixed_header()
// {
// syncword; 12 bslbf
// ID; 1 bslbf
// layer; 2 uimsbf
// protection_absent; 1 bslbf
// profile; 2 uimsbf
// sampling_frequency_index; 4 uimsbf
// private_bit; 1 bslbf
// channel_configuration; 3 uimsbf
// original/copy; 1 bslbf
// home; 1 bslbf
// }
type ADTS_Fix_Header struct {
ID uint8
Layer uint8
Protection_absent uint8
Profile uint8
Sampling_frequency_index uint8
Private_bit uint8
Channel_configuration uint8
Originalorcopy uint8
Home uint8
}
// adts_variable_header() {
// copyright_identification_bit; 1 bslbf
// copyright_identification_start; 1 bslbf
// frame_length; 13 bslbf
// adts_buffer_fullness; 11 bslbf
// number_of_raw_data_blocks_in_frame; 2 uimsfb
// }
type ADTS_Variable_Header struct {
Copyright_identification_bit uint8
copyright_identification_start uint8
Frame_length uint16
Adts_buffer_fullness uint16
Number_of_raw_data_blocks_in_frame uint8
}
type ADTS_Frame_Header struct {
Fix_Header ADTS_Fix_Header
Variable_Header ADTS_Variable_Header
}
func NewAdtsFrameHeader() *ADTS_Frame_Header {
return &ADTS_Frame_Header{
Fix_Header: ADTS_Fix_Header{
ID: 0,
Layer: 0,
Protection_absent: 1,
Profile: uint8(MAIN),
Sampling_frequency_index: uint8(AAC_SAMPLE_44100),
Private_bit: 0,
Channel_configuration: 0,
Originalorcopy: 0,
Home: 0,
},
Variable_Header: ADTS_Variable_Header{
copyright_identification_start: 0,
Copyright_identification_bit: 0,
Frame_length: 0,
Adts_buffer_fullness: 0,
Number_of_raw_data_blocks_in_frame: 0,
},
}
}
func (frame *ADTS_Frame_Header) Decode(aac []byte) error {
_ = aac[6]
frame.Fix_Header.ID = aac[1] >> 3
frame.Fix_Header.Layer = aac[1] >> 1 & 0x03
frame.Fix_Header.Protection_absent = aac[1] & 0x01
frame.Fix_Header.Profile = aac[2] >> 6 & 0x03
frame.Fix_Header.Sampling_frequency_index = aac[2] >> 2 & 0x0F
frame.Fix_Header.Private_bit = aac[2] >> 1 & 0x01
frame.Fix_Header.Channel_configuration = (aac[2] & 0x01 << 2) | (aac[3] >> 6)
frame.Fix_Header.Originalorcopy = aac[3] >> 5 & 0x01
frame.Fix_Header.Home = aac[3] >> 4 & 0x01
frame.Variable_Header.Copyright_identification_bit = aac[3] >> 3 & 0x01
frame.Variable_Header.copyright_identification_start = aac[3] >> 2 & 0x01
frame.Variable_Header.Frame_length = (uint16(aac[3]&0x03) << 11) | (uint16(aac[4]) << 3) | (uint16(aac[5]>>5) & 0x07)
frame.Variable_Header.Adts_buffer_fullness = (uint16(aac[5]&0x1F) << 6) | uint16(aac[6]>>2)
frame.Variable_Header.Number_of_raw_data_blocks_in_frame = aac[6] & 0x03
return nil
}
func (frame *ADTS_Frame_Header) Encode() []byte {
var hdr []byte
if frame.Fix_Header.Protection_absent == 1 {
hdr = make([]byte, 7)
} else {
hdr = make([]byte, 9)
}
hdr[0] = 0xFF
hdr[1] = 0xF0
hdr[1] = hdr[1] | (frame.Fix_Header.ID << 3) | (frame.Fix_Header.Layer << 1) | frame.Fix_Header.Protection_absent
hdr[2] = frame.Fix_Header.Profile<<6 | frame.Fix_Header.Sampling_frequency_index<<2 | frame.Fix_Header.Private_bit<<1 | frame.Fix_Header.Channel_configuration>>2
hdr[3] = frame.Fix_Header.Channel_configuration<<6 | frame.Fix_Header.Originalorcopy<<5 | frame.Fix_Header.Home<<4
hdr[3] = hdr[3] | frame.Variable_Header.copyright_identification_start<<3 | frame.Variable_Header.Copyright_identification_bit<<2 | byte(frame.Variable_Header.Frame_length<<11)
hdr[4] = byte(frame.Variable_Header.Frame_length >> 3)
hdr[5] = byte((frame.Variable_Header.Frame_length&0x07)<<5) | byte(frame.Variable_Header.Adts_buffer_fullness>>3)
hdr[6] = byte(frame.Variable_Header.Adts_buffer_fullness&0x3F<<2) | frame.Variable_Header.Number_of_raw_data_blocks_in_frame
return hdr
}
func SampleToAACSampleIndex(sampling int) int {
for i, v := range AAC_Sampling_Idx {
if v == sampling {
return i
}
}
panic("not Found AAC Sample Index")
}
func AACSampleIdxToSample(idx int) int {
return AAC_Sampling_Idx[idx]
}
// +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
// | audio object type(5 bits) | sampling frequency index(4 bits) | channel configuration(4 bits) | GA framelength flag(1 bits) | GA Depends on core coder(1 bits) | GA Extension Flag(1 bits) |
// +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
type AudioSpecificConfiguration struct {
Audio_object_type uint8
Sample_freq_index uint8
Channel_configuration uint8
GA_framelength_flag uint8
GA_depends_on_core_coder uint8
GA_extension_flag uint8
}
func NewAudioSpecificConfiguration() *AudioSpecificConfiguration {
return &AudioSpecificConfiguration{
Audio_object_type: 0,
Sample_freq_index: 0,
Channel_configuration: 0,
GA_framelength_flag: 0,
GA_depends_on_core_coder: 0,
GA_extension_flag: 0,
}
}
func (asc *AudioSpecificConfiguration) Encode() []byte {
buf := make([]byte, 2)
buf[0] = (asc.Audio_object_type & 0x1f << 3) | (asc.Sample_freq_index & 0x0F >> 1)
buf[1] = (asc.Sample_freq_index & 0x0F << 7) | (asc.Channel_configuration & 0x0F << 3) | (asc.GA_framelength_flag & 0x01 << 2) | (asc.GA_depends_on_core_coder & 0x01 << 1) | (asc.GA_extension_flag & 0x01)
return buf
}
func (asc *AudioSpecificConfiguration) Decode(buf []byte) error {
if len(buf) < 2 {
return errors.New("len of buf < 2 ")
}
asc.Audio_object_type = buf[0] >> 3
asc.Sample_freq_index = (buf[0] & 0x07 << 1) | (buf[1] >> 7)
asc.Channel_configuration = buf[1] >> 3 & 0x0F
asc.GA_framelength_flag = buf[1] >> 2 & 0x01
asc.GA_depends_on_core_coder = buf[1] >> 1 & 0x01
asc.GA_extension_flag = buf[1] & 0x01
return nil
}
func ConvertADTSToASC(frame []byte) ([]byte, error) {
if len(frame) < 7 {
return nil, errors.New("len of frame < 7")
}
adts := NewAdtsFrameHeader()
adts.Decode(frame)
asc := NewAudioSpecificConfiguration()
asc.Audio_object_type = adts.Fix_Header.Profile + 1
asc.Channel_configuration = adts.Fix_Header.Channel_configuration
asc.Sample_freq_index = adts.Fix_Header.Sampling_frequency_index
return asc.Encode(), nil
}
func ConvertASCToADTS(asc []byte, aacbytes int) []byte {
aac_asc := NewAudioSpecificConfiguration()
aac_asc.Decode(asc)
aac_adts := NewAdtsFrameHeader()
aac_adts.Fix_Header.Profile = aac_asc.Audio_object_type - 1
aac_adts.Fix_Header.Channel_configuration = aac_asc.Channel_configuration
aac_adts.Fix_Header.Sampling_frequency_index = aac_asc.Sample_freq_index
aac_adts.Fix_Header.Protection_absent = 1
aac_adts.Variable_Header.Adts_buffer_fullness = 0x3F
aac_adts.Variable_Header.Frame_length = uint16(aacbytes)
return aac_adts.Encode()
}

View file

@ -0,0 +1,358 @@
package codec
import (
"encoding/binary"
)
var BitMask [8]byte = [8]byte{0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF}
type BitStream struct {
bits []byte
bytesOffset int
bitsOffset int
bitsmark int
bytemark int
}
func NewBitStream(buf []byte) *BitStream {
return &BitStream{
bits: buf,
bytesOffset: 0,
bitsOffset: 0,
bitsmark: 0,
bytemark: 0,
}
}
func (bs *BitStream) Uint8(n int) uint8 {
return uint8(bs.GetBits(n))
}
func (bs *BitStream) Uint16(n int) uint16 {
return uint16(bs.GetBits(n))
}
func (bs *BitStream) Uint32(n int) uint32 {
return uint32(bs.GetBits(n))
}
func (bs *BitStream) GetBytes(n int) []byte {
if bs.bytesOffset+n > len(bs.bits) {
panic("OUT OF RANGE")
}
if bs.bitsOffset != 0 {
panic("invaild operation")
}
data := make([]byte, n)
copy(data, bs.bits[bs.bytesOffset:bs.bytesOffset+n])
bs.bytesOffset += n
return data
}
//n <= 64
func (bs *BitStream) GetBits(n int) uint64 {
if bs.bytesOffset >= len(bs.bits) {
panic("OUT OF RANGE")
}
var ret uint64 = 0
if 8-bs.bitsOffset >= n {
ret = uint64((bs.bits[bs.bytesOffset] >> (8 - bs.bitsOffset - n)) & BitMask[n-1])
bs.bitsOffset += n
if bs.bitsOffset == 8 {
bs.bytesOffset++
bs.bitsOffset = 0
}
} else {
ret = uint64(bs.bits[bs.bytesOffset] & BitMask[8-bs.bitsOffset-1])
bs.bytesOffset++
n -= 8 - bs.bitsOffset
bs.bitsOffset = 0
for n > 0 {
if bs.bytesOffset >= len(bs.bits) {
panic("OUT OF RANGE")
}
if n >= 8 {
ret = ret<<8 | uint64(bs.bits[bs.bytesOffset])
bs.bytesOffset++
n -= 8
} else {
ret = (ret << n) | uint64((bs.bits[bs.bytesOffset]>>(8-n))&BitMask[n-1])
bs.bitsOffset = n
break
}
}
}
return ret
}
func (bs *BitStream) GetBit() uint8 {
if bs.bytesOffset >= len(bs.bits) {
panic("OUT OF RANGE")
}
ret := bs.bits[bs.bytesOffset] >> (7 - bs.bitsOffset) & 0x01
bs.bitsOffset++
if bs.bitsOffset >= 8 {
bs.bytesOffset++
bs.bitsOffset = 0
}
return ret
}
func (bs *BitStream) SkipBits(n int) {
bytecount := n / 8
bitscount := n % 8
bs.bytesOffset += bytecount
if bs.bitsOffset+bitscount < 8 {
bs.bitsOffset += bitscount
} else {
bs.bytesOffset += 1
bs.bitsOffset += bitscount - 8
}
}
func (bs *BitStream) Markdot() {
bs.bitsmark = bs.bitsOffset
bs.bytemark = bs.bytesOffset
}
func (bs *BitStream) DistanceFromMarkDot() int {
bytecount := bs.bytesOffset - bs.bytemark - 1
bitscount := bs.bitsOffset + (8 - bs.bitsmark)
return bytecount*8 + bitscount
}
func (bs *BitStream) RemainBytes() int {
if bs.bitsOffset > 0 {
return len(bs.bits) - bs.bytesOffset - 1
} else {
return len(bs.bits) - bs.bytesOffset
}
}
func (bs *BitStream) RemainBits() int {
if bs.bitsOffset > 0 {
return bs.RemainBytes()*8 + 8 - bs.bitsOffset
} else {
return bs.RemainBytes() * 8
}
}
func (bs *BitStream) Bits() []byte {
return bs.bits
}
func (bs *BitStream) RemainData() []byte {
return bs.bits[bs.bytesOffset:]
}
//无符号哥伦布熵编码
func (bs *BitStream) ReadUE() uint64 {
leadingZeroBits := 0
for bs.GetBit() == 0 {
leadingZeroBits++
}
if leadingZeroBits == 0 {
return 0
}
info := bs.GetBits(leadingZeroBits)
return uint64(1)<<leadingZeroBits - 1 + info
}
//有符号哥伦布熵编码
func (bs *BitStream) ReadSE() int64 {
v := bs.ReadUE()
if v%2 == 0 {
return -1 * int64(v/2)
} else {
return int64(v+1) / 2
}
}
func (bs *BitStream) ByteOffset() int {
return bs.bytesOffset
}
func (bs *BitStream) UnRead(n int) {
if n-bs.bitsOffset <= 0 {
bs.bitsOffset -= n
} else {
least := n - bs.bitsOffset
for least >= 8 {
bs.bytesOffset--
least -= 8
}
if least > 0 {
bs.bytesOffset--
bs.bitsOffset = 8 - least
}
}
}
func (bs *BitStream) NextBits(n int) uint64 {
r := bs.GetBits(n)
bs.UnRead(n)
return r
}
func (bs *BitStream) EOS() bool {
return bs.bytesOffset == len(bs.bits) && bs.bitsOffset == 0
}
type BitStreamWriter struct {
bits []byte
byteoffset int
bitsoffset int
bitsmark int
bytemark int
}
func NewBitStreamWriter(n int) *BitStreamWriter {
return &BitStreamWriter{
bits: make([]byte, n),
byteoffset: 0,
bitsoffset: 0,
bitsmark: 0,
bytemark: 0,
}
}
func (bsw *BitStreamWriter) expandSpace(n int) {
if (len(bsw.bits)-bsw.byteoffset-1)*8+8-bsw.bitsoffset < n {
newlen := 0
if len(bsw.bits)*8 < n {
newlen = len(bsw.bits) + n/8 + 1
} else {
newlen = len(bsw.bits) * 2
}
tmp := make([]byte, newlen)
copy(tmp, bsw.bits)
bsw.bits = tmp
}
}
func (bsw *BitStreamWriter) ByteOffset() int {
return bsw.byteoffset
}
func (bsw *BitStreamWriter) BitOffset() int {
return bsw.bitsoffset
}
func (bsw *BitStreamWriter) Markdot() {
bsw.bitsmark = bsw.bitsoffset
bsw.bytemark = bsw.byteoffset
}
func (bsw *BitStreamWriter) DistanceFromMarkDot() int {
bytecount := bsw.byteoffset - bsw.bytemark - 1
bitscount := bsw.bitsoffset + (8 - bsw.bitsmark)
return bytecount*8 + bitscount
}
func (bsw *BitStreamWriter) PutByte(v byte) {
bsw.expandSpace(8)
if bsw.bitsoffset == 0 {
bsw.bits[bsw.byteoffset] = v
bsw.byteoffset++
} else {
bsw.bits[bsw.byteoffset] |= v >> byte(bsw.bitsoffset)
bsw.byteoffset++
bsw.bits[bsw.byteoffset] = v & BitMask[bsw.bitsoffset-1]
}
}
func (bsw *BitStreamWriter) PutBytes(v []byte) {
if bsw.bitsoffset != 0 {
panic("bsw.bitsoffset > 0")
}
bsw.expandSpace(8 * len(v))
copy(bsw.bits[bsw.byteoffset:], v)
bsw.byteoffset += len(v)
}
func (bsw *BitStreamWriter) PutRepetValue(v byte, n int) {
if bsw.bitsoffset != 0 {
panic("bsw.bitsoffset > 0")
}
bsw.expandSpace(8 * n)
for i := 0; i < n; i++ {
bsw.bits[bsw.byteoffset] = v
bsw.byteoffset++
}
}
func (bsw *BitStreamWriter) PutUint8(v uint8, n int) {
bsw.PutUint64(uint64(v), n)
}
func (bsw *BitStreamWriter) PutUint16(v uint16, n int) {
bsw.PutUint64(uint64(v), n)
}
func (bsw *BitStreamWriter) PutUint32(v uint32, n int) {
bsw.PutUint64(uint64(v), n)
}
func (bsw *BitStreamWriter) PutUint64(v uint64, n int) {
bsw.expandSpace(n)
if 8-bsw.bitsoffset >= n {
bsw.bits[bsw.byteoffset] |= uint8(v) & BitMask[n-1] << (8 - bsw.bitsoffset - n)
bsw.bitsoffset += n
if bsw.bitsoffset == 8 {
bsw.bitsoffset = 0
bsw.byteoffset++
}
} else {
bsw.bits[bsw.byteoffset] |= uint8(v>>(n-int(8-bsw.bitsoffset))) & BitMask[8-bsw.bitsoffset-1]
bsw.byteoffset++
n -= 8 - bsw.bitsoffset
for n-8 >= 0 {
bsw.bits[bsw.byteoffset] = uint8(v>>(n-8)) & 0xFF
bsw.byteoffset++
n -= 8
}
bsw.bitsoffset = n
if n > 0 {
bsw.bits[bsw.byteoffset] |= (uint8(v) & BitMask[n-1]) << (8 - n)
}
}
}
func (bsw *BitStreamWriter) SetByte(v byte, where int) {
bsw.bits[where] = v
}
func (bsw *BitStreamWriter) SetUint16(v uint16, where int) {
binary.BigEndian.PutUint16(bsw.bits[where:where+2], v)
}
func (bsw *BitStreamWriter) Bits() []byte {
if bsw.byteoffset == len(bsw.bits) {
return bsw.bits
}
if bsw.bitsoffset > 0 {
return bsw.bits[0 : bsw.byteoffset+1]
} else {
return bsw.bits[0:bsw.byteoffset]
}
}
//用v 填充剩余字节
func (bsw *BitStreamWriter) FillRemainData(v byte) {
for i := bsw.byteoffset; i < len(bsw.bits); i++ {
bsw.bits[i] = v
}
bsw.byteoffset = len(bsw.bits)
bsw.bitsoffset = 0
}
func (bsw *BitStreamWriter) Reset() {
for i := 0; i < len(bsw.bits); i++ {
bsw.bits[i] = 0
}
bsw.bitsmark = 0
bsw.bytemark = 0
bsw.bitsoffset = 0
bsw.byteoffset = 0
}

View file

@ -0,0 +1,64 @@
package codec
type CodecID int
const (
CODECID_VIDEO_H264 CodecID = iota
CODECID_VIDEO_H265
CODECID_VIDEO_VP8
CODECID_AUDIO_AAC CodecID = iota + 98
CODECID_AUDIO_G711A
CODECID_AUDIO_G711U
CODECID_AUDIO_OPUS
CODECID_UNRECOGNIZED = 999
)
type H264_NAL_TYPE int
const (
H264_NAL_RESERVED H264_NAL_TYPE = iota
H264_NAL_P_SLICE
H264_NAL_SLICE_A
H264_NAL_SLICE_B
H264_NAL_SLICE_C
H264_NAL_I_SLICE
H264_NAL_SEI
H264_NAL_SPS
H264_NAL_PPS
H264_NAL_AUD
)
type H265_NAL_TYPE int
const (
H265_NAL_Slice_TRAIL_N H265_NAL_TYPE = iota
H265_NAL_LICE_TRAIL_R
H265_NAL_SLICE_TSA_N
H265_NAL_SLICE_TSA_R
H265_NAL_SLICE_STSA_N
H265_NAL_SLICE_STSA_R
H265_NAL_SLICE_RADL_N
H265_NAL_SLICE_RADL_R
H265_NAL_SLICE_RASL_N
H265_NAL_SLICE_RASL_R
//IDR
H265_NAL_SLICE_BLA_W_LP H265_NAL_TYPE = iota + 6
H265_NAL_SLICE_BLA_W_RADL
H265_NAL_SLICE_BLA_N_LP
H265_NAL_SLICE_IDR_W_RADL
H265_NAL_SLICE_IDR_N_LP
H265_NAL_SLICE_CRA
//vps pps sps
H265_NAL_VPS H265_NAL_TYPE = iota + 16
H265_NAL_SPS
H265_NAL_PPS
H265_NAL_AUD
//SEI
H265_NAL_SEI H265_NAL_TYPE = iota + 19
H265_NAL_SEI_SUFFIX
)

View file

@ -0,0 +1,3 @@
module github.com/yapingcat/gomedia/codec
go 1.16

View file

@ -0,0 +1,396 @@
package codec
import "encoding/binary"
// nal_unit( NumBytesInNALunit ) {
// forbidden_zero_bit All f(1)
// nal_ref_idc All u(2)
// nal_unit_type u(5)
// }
type H264NaluHdr struct {
Forbidden_zero_bit uint8
Nal_ref_idc uint8
Nal_unit_type uint8
}
func (hdr *H264NaluHdr) Decode(bs *BitStream) {
hdr.Forbidden_zero_bit = bs.GetBit()
hdr.Nal_ref_idc = bs.Uint8(2)
hdr.Nal_unit_type = bs.Uint8(5)
}
type SliceHeader struct {
First_mb_in_slice uint64
Slice_type uint64
Pic_parameter_set_id uint64
Frame_num uint64
}
//调用方根据sps中的log2_max_frame_num_minus4的值来解析Frame_num
func (sh *SliceHeader) Decode(bs *BitStream) {
sh.First_mb_in_slice = bs.ReadUE()
sh.Slice_type = bs.ReadUE()
sh.Pic_parameter_set_id = bs.ReadUE()
}
type SPS struct {
Profile_idc uint8
Constraint_set0_flag uint8
Constraint_set1_flag uint8
Constraint_set2_flag uint8
Constraint_set3_flag uint8
Constraint_set4_flag uint8
Constraint_set5_flag uint8
Reserved_zero_2bits uint8
Level_idc uint8
Seq_parameter_set_id uint64
Chroma_format_idc uint64
Separate_colour_plane_flag uint8
Bit_depth_luma_minus8 uint64
Bit_depth_chroma_minus8 uint64
Log2_max_frame_num_minus4 uint64
Pic_order_cnt_type uint64
Max_num_ref_frames uint64
Gaps_in_frame_num_value_allowed_flag uint8
Pic_width_in_mbs_minus1 uint64
Pic_height_in_map_units_minus1 uint64
Frame_mbs_only_flag uint8
Direct_8x8_inference_flag uint8
Frame_cropping_flag uint8
Frame_crop_left_offset uint64
Frame_crop_right_offset uint64
Frame_crop_top_offset uint64
Frame_crop_bottom_offset uint64
Vui_parameters_present_flag uint8
}
func (sps *SPS) Decode(bs *BitStream) {
sps.Profile_idc = bs.Uint8(8)
sps.Constraint_set0_flag = bs.GetBit()
sps.Constraint_set1_flag = bs.GetBit()
sps.Constraint_set2_flag = bs.GetBit()
sps.Constraint_set3_flag = bs.GetBit()
sps.Constraint_set4_flag = bs.GetBit()
sps.Constraint_set5_flag = bs.GetBit()
sps.Reserved_zero_2bits = bs.Uint8(2)
sps.Level_idc = bs.Uint8(8)
sps.Seq_parameter_set_id = bs.ReadUE()
if sps.Profile_idc == 100 || sps.Profile_idc == 110 ||
sps.Profile_idc == 122 || sps.Profile_idc == 244 ||
sps.Profile_idc == 44 || sps.Profile_idc == 83 ||
sps.Profile_idc == 86 || sps.Profile_idc == 118 || sps.Profile_idc == 128 {
sps.Chroma_format_idc = bs.ReadUE()
if sps.Chroma_format_idc == 3 {
sps.Separate_colour_plane_flag = bs.Uint8(1) //separate_colour_plane_flag
}
sps.Bit_depth_luma_minus8 = bs.ReadUE() //bit_depth_luma_minus8
sps.Bit_depth_chroma_minus8 = bs.ReadUE() //bit_depth_chroma_minus8
bs.SkipBits(1) //qpprime_y_zero_transform_bypass_flag
seq_scaling_matrix_present_flag := bs.GetBit()
if seq_scaling_matrix_present_flag == 1 {
//seq_scaling_list_present_flag[i]
if sps.Chroma_format_idc == 3 {
bs.SkipBits(12)
} else {
bs.SkipBits(8)
}
}
}
sps.Log2_max_frame_num_minus4 = bs.ReadUE()
sps.Pic_order_cnt_type = bs.ReadUE()
if sps.Pic_order_cnt_type == 0 {
bs.ReadUE() // log2_max_pic_order_cnt_lsb_minus4
} else if sps.Pic_order_cnt_type == 1 {
bs.SkipBits(1) //delta_pic_order_always_zero_flag
bs.ReadSE() //offset_for_non_ref_pic
bs.ReadSE() //offset_for_top_to_bottom_field
num_ref_frames_in_pic_order_cnt_cycle := bs.ReadUE()
for i := 0; i < int(num_ref_frames_in_pic_order_cnt_cycle); i++ {
bs.ReadSE() //offset_for_ref_frame
}
}
sps.Max_num_ref_frames = bs.ReadUE()
sps.Gaps_in_frame_num_value_allowed_flag = bs.GetBit()
sps.Pic_width_in_mbs_minus1 = bs.ReadUE()
sps.Pic_height_in_map_units_minus1 = bs.ReadUE()
sps.Frame_mbs_only_flag = bs.GetBit()
if sps.Frame_mbs_only_flag == 0 {
bs.SkipBits(1) // mb_adaptive_frame_field_flag
}
sps.Direct_8x8_inference_flag = bs.GetBit()
sps.Frame_cropping_flag = bs.GetBit()
if sps.Frame_cropping_flag == 1 {
sps.Frame_crop_left_offset = bs.ReadUE() //frame_crop_left_offset
sps.Frame_crop_right_offset = bs.ReadUE() //frame_crop_right_offset
sps.Frame_crop_top_offset = bs.ReadUE() //frame_crop_top_offset
sps.Frame_crop_bottom_offset = bs.ReadUE() //frame_crop_bottom_offset
}
sps.Vui_parameters_present_flag = bs.GetBit()
}
type PPS struct {
Pic_parameter_set_id uint64
Seq_parameter_set_id uint64
Entropy_coding_mode_flag uint8
Bottom_field_pic_order_in_frame_present_flag uint8
Num_slice_groups_minus1 uint64
}
func (pps *PPS) Decode(bs *BitStream) {
pps.Pic_parameter_set_id = bs.ReadUE()
pps.Seq_parameter_set_id = bs.ReadUE()
pps.Entropy_coding_mode_flag = bs.GetBit()
pps.Bottom_field_pic_order_in_frame_present_flag = bs.GetBit()
pps.Num_slice_groups_minus1 = bs.ReadUE()
}
type SEIReaderWriter interface {
Read(size uint16, bs *BitStream)
Write(bsw *BitStreamWriter)
}
type UserDataUnregistered struct {
UUID []byte
UserData []byte
}
func (udu *UserDataUnregistered) Read(size uint16, bs *BitStream) {
udu.UUID = bs.GetBytes(16)
udu.UserData = bs.GetBytes(int(size - 16))
}
func (udu *UserDataUnregistered) Write(bsw *BitStreamWriter) {
bsw.PutBytes(udu.UUID)
bsw.PutBytes(udu.UserData)
}
type SEI struct {
PayloadType uint16
PayloadSize uint16
Sei_payload SEIReaderWriter
}
func (sei *SEI) Decode(bs *BitStream) {
for bs.NextBits(8) == 0xFF {
sei.PayloadType += 255
}
sei.PayloadType += uint16(bs.Uint8(8))
for bs.NextBits(8) == 0xFF {
sei.PayloadSize += 255
}
sei.PayloadSize += uint16(bs.Uint8(8))
if sei.PayloadType == 5 {
sei.Sei_payload = new(UserDataUnregistered)
sei.Sei_payload.Read(sei.PayloadSize, bs)
}
}
func (sei *SEI) Encode(bsw *BitStreamWriter) []byte {
payloadType := sei.PayloadType
payloadSize := sei.PayloadSize
for payloadType >= 0xFF {
bsw.PutByte(0xFF)
payloadType -= 255
}
bsw.PutByte(uint8(payloadType))
for payloadSize >= 0xFF {
bsw.PutByte(0xFF)
payloadSize -= 255
}
bsw.PutByte(uint8(payloadSize))
sei.Sei_payload.Write(bsw)
return bsw.Bits()
}
func GetSPSIdWithStartCode(sps []byte) uint64 {
start, sc := FindStartCode(sps, 0)
return GetSPSId(sps[start+int(sc):])
}
func GetSPSId(sps []byte) uint64 {
sps = sps[1:]
bs := NewBitStream(sps)
bs.SkipBits(24)
return bs.ReadUE()
}
func GetPPSIdWithStartCode(pps []byte) uint64 {
start, sc := FindStartCode(pps, 0)
return GetPPSId(pps[start+int(sc):])
}
func GetPPSId(pps []byte) uint64 {
pps = pps[1:]
bs := NewBitStream(pps)
return bs.ReadUE()
}
//https://stackoverflow.com/questions/12018535/get-the-width-height-of-the-video-from-h-264-nalu
//int Width = ((pic_width_in_mbs_minus1 +1)*16) - frame_crop_right_offset *2 - frame_crop_left_offset *2;
//int Height = ((2 - frame_mbs_only_flag)* (pic_height_in_map_units_minus1 +1) * 16) - (frame_crop_bottom_offset* 2) - (frame_crop_top_offset* 2);
func GetH264Resolution(sps []byte) (width uint32, height uint32) {
start, sc := FindStartCode(sps, 0)
bs := NewBitStream(sps[start+int(sc)+1:])
var s SPS
s.Decode(bs)
widthInSample := (uint32(s.Pic_width_in_mbs_minus1) + 1) * 16
widthCrop := uint32(s.Frame_crop_left_offset)*2 - uint32(s.Frame_crop_right_offset)*2
width = widthInSample - widthCrop
heightInSample := ((2 - uint32(s.Frame_mbs_only_flag)) * (uint32(s.Pic_height_in_map_units_minus1) + 1) * 16)
heightCrop := uint32(s.Frame_crop_bottom_offset)*2 - uint32(s.Frame_crop_top_offset)*2
height = heightInSample - heightCrop
return
}
// aligned(8) class AVCDecoderConfigurationRecord {
// unsigned int(8) configurationVersion = 1;
// unsigned int(8) AVCProfileIndication;
// unsigned int(8) profile_compatibility;
// unsigned int(8) AVCLevelIndication;
// bit(6) reserved = 111111b;
// unsigned int(2) lengthSizeMinusOne;
// bit(3) reserved = 111b;
// unsigned int(5) numOfSequenceParameterSets;
// for (i=0; i< numOfSequenceParameterSets; i++) {
// unsigned int(16) sequenceParameterSetLength ;
// bit(8*sequenceParameterSetLength) sequenceParameterSetNALUnit;
// }
// unsigned int(8) numOfPictureParameterSets;
// for (i=0; i< numOfPictureParameterSets; i++) {
// unsigned int(16) pictureParameterSetLength;
// bit(8*pictureParameterSetLength) pictureParameterSetNALUnit;
// }
// if( profile_idc == 100 || profile_idc == 110 ||
// profile_idc == 122 || profile_idc == 144 )
// {
// bit(6) reserved = 111111b;
// unsigned int(2) chroma_format;
// bit(5) reserved = 11111b;
// unsigned int(3) bit_depth_luma_minus8;
// bit(5) reserved = 11111b;
// unsigned int(3) bit_depth_chroma_minus8;
// unsigned int(8) numOfSequenceParameterSetExt;
// for (i=0; i< numOfSequenceParameterSetExt; i++) {
// unsigned int(16) sequenceParameterSetExtLength;
// bit(8*sequenceParameterSetExtLength) sequenceParameterSetExtNALUnit;
// }
// }
// }
// }
// bits
// 8 version ( always 0x01 )
// 8 avc profile ( sps[0][1] )
// 8 avc compatibility ( sps[0][2] )
// 8 avc level ( sps[0][3] )
// 6 reserved ( all bits on )
// 2 NALULengthSizeMinusOne
// 3 reserved ( all bits on )
// 5 number of SPS NALUs (usually 1)
// repeated once per SPS:
// 16 SPS size
// variable SPS NALU data
// 8 number of PPS NALUs (usually 1)
// repeated once per PPS:
// 16 PPS size
// variable PPS NALU data
func CreateH264AVCCExtradata(spss [][]byte, ppss [][]byte) []byte {
extradata := make([]byte, 6, 256)
for i, sps := range spss {
start, sc := FindStartCode(sps, 0)
spss[i] = sps[start+int(sc):]
}
for i, pps := range ppss {
start, sc := FindStartCode(pps, 0)
ppss[i] = pps[start+int(sc):]
}
extradata[0] = 0x01
extradata[1] = spss[0][1]
extradata[2] = spss[0][2]
extradata[3] = spss[0][3]
extradata[4] = 0xFF
extradata[5] = 0xE0 | uint8(len(spss))
for _, sps := range spss {
spssize := make([]byte, 2)
binary.BigEndian.PutUint16(spssize, uint16(len(sps)))
extradata = append(extradata, spssize...)
extradata = append(extradata, sps...)
}
extradata = append(extradata, uint8(len(ppss)))
for _, pps := range ppss {
ppssize := make([]byte, 2)
binary.BigEndian.PutUint16(ppssize, uint16(len(pps)))
extradata = append(extradata, ppssize...)
extradata = append(extradata, pps...)
}
var h264sps SPS
h264sps.Decode(NewBitStream(spss[0][1:]))
if h264sps.Profile_idc == 100 ||
h264sps.Profile_idc == 110 ||
h264sps.Profile_idc == 122 ||
h264sps.Profile_idc == 144 {
tmp := make([]byte, 4)
tmp[0] = 0xFC | uint8(h264sps.Chroma_format_idc&0x03)
tmp[1] = 0xF8 | uint8(h264sps.Bit_depth_luma_minus8&0x07)
tmp[2] = 0xF8 | uint8(h264sps.Bit_depth_chroma_minus8&0x07)
tmp[3] = 0
extradata = append(extradata, tmp...)
}
return extradata
}
func CovertExtradata(extraData []byte) ([][]byte, [][]byte) {
spsnum := extraData[5] & 0x1F
spss := make([][]byte, spsnum)
offset := 6
for i := 0; i < int(spsnum); i++ {
spssize := binary.BigEndian.Uint16(extraData[offset:])
sps := make([]byte, spssize+4)
copy(sps, []byte{0x00, 0x00, 0x00, 0x01})
copy(sps[4:], extraData[offset+2:offset+2+int(spssize)])
offset += 2 + int(spssize)
spss[i] = sps
}
ppsnum := extraData[offset]
ppss := make([][]byte, ppsnum)
offset++
for i := 0; i < int(ppsnum); i++ {
ppssize := binary.BigEndian.Uint16(extraData[offset:])
pps := make([]byte, ppssize+4)
copy(pps, []byte{0x00, 0x00, 0x00, 0x01})
copy(pps[4:], extraData[offset+2:offset+2+int(ppssize)])
offset += 2 + int(ppssize)
ppss[i] = pps
}
return spss, ppss
}
func ConvertAnnexBToAVCC(annexb []byte) []byte {
start, sc := FindStartCode(annexb, 0)
if sc == START_CODE_4 {
binary.BigEndian.PutUint32(annexb[start:], uint32(len(annexb)-4))
return annexb
} else {
avcc := make([]byte, 1+len(annexb))
binary.BigEndian.PutUint32(avcc, uint32(len(annexb)-3))
copy(avcc[4:], annexb[start+3:])
return avcc
}
}
func CovertAVCCToAnnexB(avcc []byte) {
avcc[0] = 0x00
avcc[1] = 0x00
avcc[2] = 0x00
avcc[3] = 0x01
}

View file

@ -0,0 +1,998 @@
package codec
import (
"bytes"
)
// nal_unit_header() {
// forbidden_zero_bit f(1)
// nal_unit_type u(6)
// nuh_layer_id u(6)
// nuh_temporal_id_plus1 u(3)
// }
type H265NaluHdr struct {
Forbidden_zero_bit uint8
Nal_unit_type uint8
Nuh_layer_id uint8
Nuh_temporal_id_plus1 uint8
}
func (hdr *H265NaluHdr) Decode(bs *BitStream) {
hdr.Forbidden_zero_bit = bs.GetBit()
hdr.Nal_unit_type = bs.Uint8(6)
hdr.Nuh_layer_id = bs.Uint8(6)
hdr.Nuh_temporal_id_plus1 = bs.Uint8(3)
}
type VPS struct {
Vps_video_parameter_set_id uint8
Vps_base_layer_internal_flag uint8
Vps_base_layer_available_flag uint8
Vps_max_layers_minus1 uint8
Vps_max_sub_layers_minus1 uint8
Vps_temporal_id_nesting_flag uint8
Vps_reserved_0xffff_16bits uint16
Ptl ProfileTierLevel
Vps_sub_layer_ordering_info_present_flag uint8
Vps_max_dec_pic_buffering_minus1 [8]uint64
Vps_max_num_reorder_pics [8]uint64
Vps_max_latency_increase_plus1 [8]uint64
Vps_max_layer_id uint8
Vps_num_layer_sets_minus1 uint64
Layer_id_included_flag [][]uint8
Vps_timing_info_present_flag uint8
TimeInfo VPSTimeInfo
// Vps_extension_flag uint8
}
type VPSTimeInfo struct {
Vps_num_units_in_tick uint32
Vps_time_scale uint32
Vps_poc_proportional_to_timing_flag uint8
Vps_num_ticks_poc_diff_one_minus1 uint64
Vps_num_hrd_parameters uint64
Hrd_layer_set_idx []uint64
Cprms_present_flag []uint8
}
type ProfileTierLevel struct {
General_profile_space uint8
General_tier_flag uint8
General_profile_idc uint8
General_profile_compatibility_flag uint32
General_constraint_indicator_flag uint64
General_level_idc uint8
Sub_layer_profile_present_flag [8]uint8
Sub_layer_level_present_flag [8]uint8
}
//nalu without startcode
func (vps *VPS) Decode(nalu []byte) {
sodb := CovertRbspToSodb(nalu)
bs := NewBitStream(sodb)
hdr := H265NaluHdr{}
hdr.Decode(bs)
vps.Vps_video_parameter_set_id = bs.Uint8(4)
vps.Vps_base_layer_internal_flag = bs.Uint8(1)
vps.Vps_base_layer_available_flag = bs.Uint8(1)
vps.Vps_max_layers_minus1 = bs.Uint8(6)
vps.Vps_max_sub_layers_minus1 = bs.Uint8(3)
vps.Vps_temporal_id_nesting_flag = bs.Uint8(1)
vps.Vps_reserved_0xffff_16bits = bs.Uint16(16)
vps.Ptl = Profile_tier_level(1, vps.Vps_max_sub_layers_minus1, bs)
vps.Vps_sub_layer_ordering_info_present_flag = bs.Uint8(1)
var i int
if vps.Vps_sub_layer_ordering_info_present_flag > 0 {
i = 0
} else {
i = int(vps.Vps_max_sub_layers_minus1)
}
for ; i <= int(vps.Vps_max_sub_layers_minus1); i++ {
vps.Vps_max_dec_pic_buffering_minus1[i] = bs.ReadUE()
vps.Vps_max_num_reorder_pics[i] = bs.ReadUE()
vps.Vps_max_latency_increase_plus1[i] = bs.ReadUE()
}
vps.Vps_max_layer_id = bs.Uint8(6)
vps.Vps_num_layer_sets_minus1 = bs.ReadUE()
vps.Layer_id_included_flag = make([][]uint8, vps.Vps_num_layer_sets_minus1)
for i := 1; i <= int(vps.Vps_num_layer_sets_minus1); i++ {
vps.Layer_id_included_flag[i] = make([]uint8, vps.Vps_max_layer_id)
for j := 0; j <= int(vps.Vps_max_layer_id); j++ {
vps.Layer_id_included_flag[i][j] = bs.Uint8(1)
}
}
vps.Vps_timing_info_present_flag = bs.Uint8(1)
if vps.Vps_timing_info_present_flag == 1 {
vps.TimeInfo = ParserVPSTimeinfo(bs)
}
}
//ffmpeg hevc.c
//static void hvcc_parse_ptl(GetBitContext *gb,HEVCDecoderConfigurationRecord *hvcc,unsigned int max_sub_layers_minus1)
func Profile_tier_level(profilePresentFlag uint8, maxNumSubLayersMinus1 uint8, bs *BitStream) ProfileTierLevel {
var ptl ProfileTierLevel
ptl.General_profile_space = bs.Uint8(2)
ptl.General_tier_flag = bs.Uint8(1)
ptl.General_profile_idc = bs.Uint8(5)
ptl.General_profile_compatibility_flag = bs.Uint32(32)
ptl.General_constraint_indicator_flag = bs.GetBits(48)
ptl.General_level_idc = bs.Uint8(8)
for i := 0; i < int(maxNumSubLayersMinus1); i++ {
ptl.Sub_layer_profile_present_flag[i] = bs.GetBit()
ptl.Sub_layer_level_present_flag[i] = bs.GetBit()
}
if maxNumSubLayersMinus1 > 0 {
for i := maxNumSubLayersMinus1; i < 8; i++ {
bs.SkipBits(2)
}
}
for i := 0; i < int(maxNumSubLayersMinus1); i++ {
if ptl.Sub_layer_profile_present_flag[i] == 1 {
/*
* sub_layer_profile_space[i] u(2)
* sub_layer_tier_flag[i] u(1)
* sub_layer_profile_idc[i] u(5)
* sub_layer_profile_compatibility_flag[i][0..31] u(32)
* sub_layer_progressive_source_flag[i] u(1)
* sub_layer_interlaced_source_flag[i] u(1)
* sub_layer_non_packed_constraint_flag[i] u(1)
* sub_layer_frame_only_constraint_flag[i] u(1)
* sub_layer_reserved_zero_44bits[i] u(44)
*/
bs.SkipBits(88)
}
if ptl.Sub_layer_level_present_flag[i] == 1 {
bs.SkipBits(8)
}
}
return ptl
}
func ParserVPSTimeinfo(bs *BitStream) VPSTimeInfo {
var ti VPSTimeInfo
ti.Vps_num_units_in_tick = bs.Uint32(32)
ti.Vps_time_scale = bs.Uint32(32)
ti.Vps_poc_proportional_to_timing_flag = bs.Uint8(1)
if ti.Vps_poc_proportional_to_timing_flag == 1 {
ti.Vps_num_ticks_poc_diff_one_minus1 = bs.ReadUE()
}
ti.Vps_num_hrd_parameters = bs.ReadUE()
// for i := 0; i < int(ti.Vps_num_hrd_parameters); i++ {
// ti.Hrd_layer_set_idx[i] = bs.ReadUE()
// if i > 0 {
// ti.Cprms_present_flag[i] = bs.Uint8(1)
// }
// //Hrd_parameters(ti.Cprms_present_flag[i])
// }
return ti
}
type H265RawSPS struct {
Sps_video_parameter_set_id uint8
Sps_max_sub_layers_minus1 uint8
Sps_temporal_id_nesting_flag uint8
Ptl ProfileTierLevel
Sps_seq_parameter_set_id uint64
Chroma_format_idc uint64
Pic_width_in_luma_samples uint64
Pic_height_in_luma_samples uint64
Conformance_window_flag uint8
Conf_win_left_offset uint64
Conf_win_right_offset uint64
Conf_win_top_offset uint64
Conf_win_bottom_offset uint64
Bit_depth_luma_minus8 uint64
Bit_depth_chroma_minus8 uint64
Log2_max_pic_order_cnt_lsb_minus4 uint64
Sps_sub_layer_ordering_info_present_flag uint8
Vui_parameters_present_flag uint8
Vui VUI_Parameters
}
//nalu without startcode
func (sps *H265RawSPS) Decode(nalu []byte) {
sodb := CovertRbspToSodb(nalu)
bs := NewBitStream(sodb)
hdr := H265NaluHdr{}
hdr.Decode(bs)
sps.Sps_video_parameter_set_id = bs.Uint8(4)
sps.Sps_max_sub_layers_minus1 = bs.Uint8(3)
sps.Sps_temporal_id_nesting_flag = bs.Uint8(1)
sps.Ptl = Profile_tier_level(1, sps.Sps_max_sub_layers_minus1, bs)
sps.Sps_seq_parameter_set_id = bs.ReadUE()
sps.Chroma_format_idc = bs.ReadUE()
if sps.Chroma_format_idc == 3 {
bs.SkipBits(1)
}
sps.Pic_width_in_luma_samples = bs.ReadUE()
sps.Pic_height_in_luma_samples = bs.ReadUE()
sps.Conformance_window_flag = bs.Uint8(1)
if sps.Conformance_window_flag == 1 {
sps.Conf_win_left_offset = bs.ReadUE()
sps.Conf_win_right_offset = bs.ReadUE()
sps.Conf_win_top_offset = bs.ReadUE()
sps.Conf_win_bottom_offset = bs.ReadUE()
}
sps.Bit_depth_luma_minus8 = bs.ReadUE()
sps.Bit_depth_chroma_minus8 = bs.ReadUE()
sps.Log2_max_pic_order_cnt_lsb_minus4 = bs.ReadUE()
sps.Sps_sub_layer_ordering_info_present_flag = bs.Uint8(1)
i := 0
if sps.Sps_sub_layer_ordering_info_present_flag == 0 {
i = int(sps.Sps_max_sub_layers_minus1)
}
for ; i <= int(sps.Sps_max_sub_layers_minus1); i++ {
bs.ReadUE()
bs.ReadUE()
bs.ReadUE()
}
bs.ReadUE() // log2_min_luma_coding_block_size_minus3
bs.ReadUE() // log2_diff_max_min_luma_coding_block_size
bs.ReadUE() // log2_min_transform_block_size_minus2
bs.ReadUE() // log2_diff_max_min_transform_block_size
bs.ReadUE() // max_transform_hierarchy_depth_inter
bs.ReadUE() // max_transform_hierarchy_depth_intra
scaling_list_enabled_flag := bs.GetBit()
if scaling_list_enabled_flag > 0 {
sps_scaling_list_data_present_flag := bs.GetBit()
if sps_scaling_list_data_present_flag > 0 {
scaling_list_data(bs)
}
}
bs.SkipBits(1)
bs.SkipBits(1)
if bs.GetBit() == 1 {
bs.GetBits(4)
bs.GetBits(4)
bs.ReadUE()
bs.ReadUE()
bs.GetBit()
}
num_short_term_ref_pic_sets := bs.ReadUE()
if num_short_term_ref_pic_sets > 64 {
panic("beyond HEVC_MAX_SHORT_TERM_REF_PIC_SETS")
}
var num_delta_pocs [64]uint32
for i := 0; i < int(num_short_term_ref_pic_sets); i++ {
parse_rps(i, num_short_term_ref_pic_sets, num_delta_pocs, bs)
}
if bs.GetBit() == 1 {
num_long_term_ref_pics_sps := bs.ReadUE()
for i := 0; i < int(num_long_term_ref_pics_sps); i++ {
length := Min(int(sps.Log2_max_pic_order_cnt_lsb_minus4+4), 16)
bs.SkipBits(length)
bs.SkipBits(1)
}
}
bs.SkipBits(1)
bs.SkipBits(1)
sps.Vui_parameters_present_flag = bs.GetBit()
if sps.Vui_parameters_present_flag == 1 {
sps.Vui.Decode(bs, sps.Sps_max_sub_layers_minus1)
}
}
type VUI_Parameters struct {
Aspect_ratio_info_present_flag uint8
Overscan_info_present_flag uint8
Chroma_loc_info_present_flag uint8
Neutral_chroma_indication_flag uint8
Field_seq_flag uint8
Frame_field_info_present_flag uint8
Default_display_window_flag uint8
Vui_timing_info_present_flag uint8
Vui_num_units_in_tick uint32
Vui_time_scale uint32
Vui_poc_proportional_to_timing_flag uint8
Vui_hrd_parameters_present_flag uint8
Bitstream_restriction_flag uint8
Tiles_fixed_structure_flag uint8
Motion_vectors_over_pic_boundaries_flag uint8
Restricted_ref_pic_lists_flag uint8
Min_spatial_segmentation_idc uint64
Max_bytes_per_pic_denom uint64
Max_bits_per_min_cu_denom uint64
Log2_max_mv_length_horizontal uint64
Log2_max_mv_length_vertical uint64
}
func (vui *VUI_Parameters) Decode(bs *BitStream, max_sub_layers_minus1 uint8) {
vui.Aspect_ratio_info_present_flag = bs.Uint8(1)
if vui.Aspect_ratio_info_present_flag == 1 {
if bs.Uint8(8) == 255 {
bs.SkipBits(32)
}
}
vui.Overscan_info_present_flag = bs.Uint8(1)
if vui.Overscan_info_present_flag == 1 {
bs.SkipBits(1)
}
if bs.GetBit() == 1 {
bs.SkipBits(4)
if bs.GetBit() == 1 {
bs.SkipBits(24)
}
}
vui.Chroma_loc_info_present_flag = bs.GetBit()
if vui.Chroma_loc_info_present_flag == 1 {
bs.ReadUE()
bs.ReadUE()
}
vui.Neutral_chroma_indication_flag = bs.GetBit()
vui.Field_seq_flag = bs.GetBit()
vui.Frame_field_info_present_flag = bs.GetBit()
vui.Default_display_window_flag = bs.GetBit()
if vui.Default_display_window_flag == 1 {
bs.ReadUE()
bs.ReadUE()
bs.ReadUE()
bs.ReadUE()
}
vui.Vui_timing_info_present_flag = bs.GetBit()
if vui.Vui_timing_info_present_flag == 1 {
vui.Vui_num_units_in_tick = bs.Uint32(32)
vui.Vui_time_scale = bs.Uint32(32)
vui.Vui_poc_proportional_to_timing_flag = bs.GetBit()
if vui.Vui_poc_proportional_to_timing_flag == 1 {
bs.ReadUE()
}
vui.Vui_hrd_parameters_present_flag = bs.GetBit()
if vui.Vui_hrd_parameters_present_flag == 1 {
skip_hrd_parameters(1, uint32(max_sub_layers_minus1), bs)
}
}
vui.Bitstream_restriction_flag = bs.GetBit()
if vui.Bitstream_restriction_flag == 1 {
vui.Tiles_fixed_structure_flag = bs.GetBit()
vui.Motion_vectors_over_pic_boundaries_flag = bs.GetBit()
vui.Restricted_ref_pic_lists_flag = bs.GetBit()
vui.Min_spatial_segmentation_idc = bs.ReadUE()
vui.Max_bytes_per_pic_denom = bs.ReadUE()
vui.Max_bits_per_min_cu_denom = bs.ReadUE()
vui.Log2_max_mv_length_horizontal = bs.ReadUE()
vui.Log2_max_mv_length_vertical = bs.ReadUE()
}
}
func skip_hrd_parameters(cprms_present_flag uint8, max_sub_layers_minus1 uint32, bs *BitStream) {
nal_hrd_parameters_present_flag := uint8(0)
vcl_hrd_parameters_present_flag := uint8(0)
sub_pic_hrd_params_present_flag := uint8(0)
if cprms_present_flag == 1 {
nal_hrd_parameters_present_flag = bs.GetBit()
vcl_hrd_parameters_present_flag = bs.GetBit()
if nal_hrd_parameters_present_flag == 1 || vcl_hrd_parameters_present_flag == 1 {
sub_pic_hrd_params_present_flag = bs.GetBit()
if sub_pic_hrd_params_present_flag == 1 {
/*
* tick_divisor_minus2 u(8)
* du_cpb_removal_delay_increment_length_minus1 u(5)
* sub_pic_cpb_params_in_pic_timing_sei_flag u(1)
* dpb_output_delay_du_length_minus1 u(5)
*/
bs.SkipBits(19)
}
bs.SkipBits(8)
if sub_pic_hrd_params_present_flag == 1 {
// cpb_size_du_scale
bs.SkipBits(4)
}
/*
* initial_cpb_removal_delay_length_minus1 u(5)
* au_cpb_removal_delay_length_minus1 u(5)
* dpb_output_delay_length_minus1 u(5)
*/
bs.SkipBits(15)
}
}
for i := 0; i <= int(max_sub_layers_minus1); i++ {
fixed_pic_rate_general_flag := bs.GetBit()
fixed_pic_rate_within_cvs_flag := uint8(0)
low_delay_hrd_flag := uint8(0)
cpb_cnt_minus1 := uint32(0)
if fixed_pic_rate_general_flag == 0 {
fixed_pic_rate_within_cvs_flag = bs.GetBit()
}
if fixed_pic_rate_within_cvs_flag == 1 {
bs.ReadUE()
} else {
low_delay_hrd_flag = bs.GetBit()
}
if low_delay_hrd_flag == 0 {
cpb_cnt_minus1 = uint32(bs.ReadUE())
if cpb_cnt_minus1 > 31 {
panic("cpb_cnt_minus1 > 31")
}
}
skip_sub_layer_hrd_parameters := func() {
for i := 0; i < int(cpb_cnt_minus1); i++ {
bs.ReadUE()
bs.ReadUE()
if sub_pic_hrd_params_present_flag == 1 {
bs.ReadUE()
bs.ReadUE()
}
bs.SkipBits(1)
}
}
if nal_hrd_parameters_present_flag == 1 {
skip_sub_layer_hrd_parameters()
}
if vcl_hrd_parameters_present_flag == 1 {
skip_sub_layer_hrd_parameters()
}
}
}
func scaling_list_data(bs *BitStream) {
for i := 0; i < 4; i++ {
maxj := 6
if i == 3 {
maxj = 2
}
for j := 0; j < maxj; j++ {
if bs.GetBit() == 0 {
bs.ReadUE()
} else {
num_coeffs := Min(64, 1<<(4+(i<<1)))
if i > 1 {
bs.ReadSE()
}
for k := 0; k < num_coeffs; k++ {
bs.ReadSE()
}
}
}
}
}
func parse_rps(rps_idx int, nums_rps uint64, num_delta_pocs [64]uint32, bs *BitStream) {
if rps_idx > 0 && bs.GetBit() > 0 {
if rps_idx > int(nums_rps) {
panic("rps_idx > int(nums_rps)")
}
bs.SkipBits(1)
bs.ReadUE()
num_delta_pocs[rps_idx] = 0
for i := uint32(0); i <= num_delta_pocs[rps_idx-1]; i++ {
var use_delta_flag uint8
var used_by_curr_pic_flag uint8 = bs.GetBit()
if used_by_curr_pic_flag == 0 {
use_delta_flag = bs.GetBit()
}
if use_delta_flag > 0 || used_by_curr_pic_flag > 0 {
num_delta_pocs[rps_idx]++
}
}
} else {
num_negative_pics := bs.ReadUE()
num_positive_pics := bs.ReadUE()
if (num_negative_pics+num_positive_pics)*2 > uint64(bs.RemainBits()) {
panic("(num_negative_pics + num_positive_pics) * 2> uint64(bs.RemainBits())")
}
for i := 0; i < int(num_negative_pics); i++ {
bs.ReadUE()
bs.SkipBits(1)
}
for i := 0; i < int(num_positive_pics); i++ {
bs.ReadUE()
bs.SkipBits(1)
}
}
}
type H265RawPPS struct {
Pps_pic_parameter_set_id uint64
Pps_seq_parameter_set_id uint64
Dependent_slice_segments_enabled_flag uint8
Output_flag_present_flag uint8
Num_extra_slice_header_bits uint8
Sign_data_hiding_enabled_flag uint8
Cabac_init_present_flag uint8
Num_ref_idx_l0_default_active_minus1 uint64
Num_ref_idx_l1_default_active_minus1 uint64
Init_qp_minus26 int64
Constrained_intra_pred_flag uint8
Transform_skip_enabled_flag uint8
Cu_qp_delta_enabled_flag uint8
Diff_cu_qp_delta_depth uint64
Pps_cb_qp_offset int64
Pps_cr_qp_offset int64
Pps_slice_chroma_qp_offsets_present_flag uint8
Weighted_pred_flag uint8
Weighted_bipred_flag uint8
Transquant_bypass_enabled_flag uint8
Tiles_enabled_flag uint8
Entropy_coding_sync_enabled_flag uint8
}
//nalu without startcode
func (pps *H265RawPPS) Decode(nalu []byte) {
sodb := CovertRbspToSodb(nalu)
bs := NewBitStream(sodb)
hdr := H265NaluHdr{}
hdr.Decode(bs)
pps.Pps_pic_parameter_set_id = bs.ReadUE()
pps.Pps_seq_parameter_set_id = bs.ReadUE()
pps.Dependent_slice_segments_enabled_flag = bs.GetBit()
pps.Output_flag_present_flag = bs.GetBit()
pps.Num_extra_slice_header_bits = bs.Uint8(3)
pps.Sign_data_hiding_enabled_flag = bs.GetBit()
pps.Cabac_init_present_flag = bs.GetBit()
pps.Num_ref_idx_l0_default_active_minus1 = bs.ReadUE()
pps.Num_ref_idx_l1_default_active_minus1 = bs.ReadUE()
pps.Init_qp_minus26 = bs.ReadSE()
pps.Constrained_intra_pred_flag = bs.GetBit()
pps.Transform_skip_enabled_flag = bs.GetBit()
pps.Cu_qp_delta_enabled_flag = bs.GetBit()
if pps.Cu_qp_delta_enabled_flag == 1 {
pps.Diff_cu_qp_delta_depth = bs.ReadUE()
}
pps.Pps_cb_qp_offset = bs.ReadSE()
pps.Pps_cr_qp_offset = bs.ReadSE()
pps.Pps_slice_chroma_qp_offsets_present_flag = bs.GetBit()
pps.Weighted_pred_flag = bs.GetBit()
pps.Weighted_bipred_flag = bs.GetBit()
pps.Transquant_bypass_enabled_flag = bs.GetBit()
pps.Tiles_enabled_flag = bs.GetBit()
pps.Entropy_coding_sync_enabled_flag = bs.GetBit()
}
func GetH265Resolution(sps []byte) (width uint32, height uint32) {
start, sc := FindStartCode(sps, 0)
h265sps := H265RawSPS{}
h265sps.Decode(sps[start+int(sc):])
width = uint32(h265sps.Pic_width_in_luma_samples)
height = uint32(h265sps.Pic_height_in_luma_samples)
return
}
func GetVPSIdWithStartCode(vps []byte) uint8 {
start, sc := FindStartCode(vps, 0)
return GetVPSId(vps[start+int(sc):])
}
func GetVPSId(vps []byte) uint8 {
var rawvps VPS
rawvps.Decode(vps)
return rawvps.Vps_video_parameter_set_id
}
func GetH265SPSIdWithStartCode(sps []byte) uint64 {
start, sc := FindStartCode(sps, 0)
return GetH265SPSId(sps[start+int(sc):])
}
func GetH265SPSId(sps []byte) uint64 {
var rawsps H265RawSPS
rawsps.Decode(sps)
return rawsps.Sps_seq_parameter_set_id
}
func GetH65PPSIdWithStartCode(pps []byte) uint64 {
start, sc := FindStartCode(pps, 0)
return GetH265SPSId(pps[start+int(sc):])
}
func GetH265PPSId(pps []byte) uint64 {
var rawpps H265RawPPS
rawpps.Decode(pps)
return rawpps.Pps_pic_parameter_set_id
}
/*
ISO/IEC 14496-15:2017(E) 8.3.3.1.2 Syntax (p71)
aligned(8) class HEVCDecoderConfigurationRecord {
unsigned int(8) configurationVersion = 1;
unsigned int(2) general_profile_space;
unsigned int(1) general_tier_flag;
unsigned int(5) general_profile_idc;
unsigned int(32) general_profile_compatibility_flags;
unsigned int(48) general_constraint_indicator_flags;
unsigned int(8) general_level_idc;
bit(4) reserved = '1111'b;
unsigned int(12) min_spatial_segmentation_idc;
bit(6) reserved = '111111'b;
unsigned int(2) parallelismType;
bit(6) reserved = '111111'b;
unsigned int(2) chromaFormat;
bit(5) reserved = '11111'b;
unsigned int(3) bitDepthLumaMinus8;
bit(5) reserved = '11111'b;
unsigned int(3) bitDepthChromaMinus8;
bit(16) avgFrameRate;
bit(2) constantFrameRate;
bit(3) numTemporalLayers;
bit(1) temporalIdNested;
unsigned int(2) lengthSizeMinusOne;
unsigned int(8) numOfArrays;
for (j=0; j < numOfArrays; j++) {
bit(1) array_completeness;
unsigned int(1) reserved = 0;
unsigned int(6) NAL_unit_type;
unsigned int(16) numNalus;
for (i=0; i< numNalus; i++) {
unsigned int(16) nalUnitLength;
bit(8*nalUnitLength) nalUnit;
}
}
}
*/
type NalUnit struct {
NalUnitLength uint16
Nalu []byte
}
type HVCCNALUnitArray struct {
Array_completeness uint8
NAL_unit_type uint8
NumNalus uint16
NalUnits []*NalUnit
}
type HEVCRecordConfiguration struct {
ConfigurationVersion uint8
General_profile_space uint8
General_tier_flag uint8
General_profile_idc uint8
General_profile_compatibility_flags uint32
General_constraint_indicator_flags uint64
General_level_idc uint8
Min_spatial_segmentation_idc uint16
ParallelismType uint8
ChromaFormat uint8
BitDepthLumaMinus8 uint8
BitDepthChromaMinus8 uint8
AvgFrameRate uint16
ConstantFrameRate uint8
NumTemporalLayers uint8
TemporalIdNested uint8
LengthSizeMinusOne uint8
NumOfArrays uint8
Arrays []*HVCCNALUnitArray
}
func NewHEVCRecordConfiguration() *HEVCRecordConfiguration {
return &HEVCRecordConfiguration{
ConfigurationVersion: 1,
General_profile_compatibility_flags: 0xffffffff,
General_constraint_indicator_flags: 0xffffffffffffffff,
Min_spatial_segmentation_idc: 4097,
LengthSizeMinusOne: 3,
}
}
func (hvcc *HEVCRecordConfiguration) Encode() []byte {
bsw := NewBitStreamWriter(512)
bsw.PutByte(hvcc.ConfigurationVersion)
bsw.PutUint8(hvcc.General_profile_space, 2)
bsw.PutUint8(hvcc.General_tier_flag, 1)
bsw.PutUint8(hvcc.General_profile_idc, 5)
bsw.PutUint32(hvcc.General_profile_compatibility_flags, 32)
bsw.PutUint64(hvcc.General_constraint_indicator_flags, 48)
bsw.PutByte(hvcc.General_level_idc)
bsw.PutUint8(0x0F, 4)
bsw.PutUint16(hvcc.Min_spatial_segmentation_idc, 12)
bsw.PutUint8(0x3F, 6)
//ffmpeg hvcc_write(AVIOContext *pb, HEVCDecoderConfigurationRecord *hvcc)
/*
* parallelismType indicates the type of parallelism that is used to meet
* the restrictions imposed by min_spatial_segmentation_idc when the value
* of min_spatial_segmentation_idc is greater than 0.
*/
if hvcc.Min_spatial_segmentation_idc == 0 {
hvcc.ParallelismType = 0
}
bsw.PutUint8(hvcc.ParallelismType, 2)
bsw.PutUint8(0x3F, 6)
bsw.PutUint8(hvcc.ChromaFormat, 2)
bsw.PutUint8(0x1F, 5)
bsw.PutUint8(hvcc.BitDepthLumaMinus8, 3)
bsw.PutUint8(0x1F, 5)
bsw.PutUint8(hvcc.BitDepthChromaMinus8, 3)
bsw.PutUint16(hvcc.AvgFrameRate, 16)
bsw.PutUint8(hvcc.ConstantFrameRate, 2)
bsw.PutUint8(hvcc.NumTemporalLayers, 3)
bsw.PutUint8(hvcc.TemporalIdNested, 1)
bsw.PutUint8(hvcc.LengthSizeMinusOne, 2)
bsw.PutByte(uint8(len(hvcc.Arrays)))
for _, arrays := range hvcc.Arrays {
bsw.PutUint8(arrays.Array_completeness, 1)
bsw.PutUint8(0, 1)
bsw.PutUint8(arrays.NAL_unit_type, 6)
bsw.PutUint16(arrays.NumNalus, 16)
for _, nalu := range arrays.NalUnits {
bsw.PutUint16(nalu.NalUnitLength, 16)
bsw.PutBytes(nalu.Nalu)
}
}
return bsw.Bits()
}
func (hvcc *HEVCRecordConfiguration) Decode(hevc []byte) {
bs := NewBitStream(hevc)
hvcc.ConfigurationVersion = bs.Uint8(8)
hvcc.General_profile_space = bs.Uint8(2)
hvcc.General_tier_flag = bs.Uint8(1)
hvcc.General_profile_idc = bs.Uint8(5)
hvcc.General_profile_compatibility_flags = bs.Uint32(32)
hvcc.General_constraint_indicator_flags = bs.GetBits(48)
hvcc.General_level_idc = bs.Uint8(8)
bs.SkipBits(4)
hvcc.Min_spatial_segmentation_idc = bs.Uint16(12)
bs.SkipBits(6)
hvcc.ParallelismType = bs.Uint8(2)
bs.SkipBits(6)
hvcc.ChromaFormat = bs.Uint8(2)
bs.SkipBits(5)
hvcc.BitDepthLumaMinus8 = bs.Uint8(3)
bs.SkipBits(5)
hvcc.BitDepthChromaMinus8 = bs.Uint8(3)
hvcc.AvgFrameRate = bs.Uint16(16)
hvcc.ConstantFrameRate = bs.Uint8(2)
hvcc.NumTemporalLayers = bs.Uint8(3)
hvcc.TemporalIdNested = bs.Uint8(1)
hvcc.LengthSizeMinusOne = bs.Uint8(2)
hvcc.NumOfArrays = bs.Uint8(8)
hvcc.Arrays = make([]*HVCCNALUnitArray, hvcc.NumOfArrays)
for i := 0; i < int(hvcc.NumOfArrays); i++ {
hvcc.Arrays[i] = new(HVCCNALUnitArray)
hvcc.Arrays[i].Array_completeness = bs.GetBit()
bs.SkipBits(1)
hvcc.Arrays[i].NAL_unit_type = bs.Uint8(6)
hvcc.Arrays[i].NumNalus = bs.Uint16(16)
hvcc.Arrays[i].NalUnits = make([]*NalUnit, hvcc.Arrays[i].NumNalus)
for j := 0; j < int(hvcc.Arrays[i].NumNalus); j++ {
hvcc.Arrays[i].NalUnits[j] = new(NalUnit)
hvcc.Arrays[i].NalUnits[j].NalUnitLength = bs.Uint16(16)
hvcc.Arrays[i].NalUnits[j].Nalu = bs.GetBytes(int(hvcc.Arrays[i].NalUnits[j].NalUnitLength))
}
}
}
func (hvcc *HEVCRecordConfiguration) UpdateSPS(sps []byte) {
start, sc := FindStartCode(sps, 0)
sps = sps[start+int(sc):]
var rawsps H265RawSPS
rawsps.Decode(sps)
spsid := rawsps.Sps_seq_parameter_set_id
var needUpdate bool = false
i := 0
for ; i < len(hvcc.Arrays); i++ {
arrays := hvcc.Arrays[i]
found := false
if arrays.NAL_unit_type == uint8(H265_NAL_SPS) {
j := 0
for ; j < len(arrays.NalUnits); j++ {
if spsid != GetH265SPSId(arrays.NalUnits[j].Nalu) {
found = true
continue
}
//find the same sps nalu
if arrays.NalUnits[j].NalUnitLength == uint16(len(sps)) && bytes.Equal(arrays.NalUnits[j].Nalu, sps) {
return
}
tmpsps := make([]byte, len(sps))
copy(tmpsps, sps)
arrays.NalUnits[j].Nalu = tmpsps
arrays.NalUnits[j].NalUnitLength = uint16(len(tmpsps))
needUpdate = true
break
}
if j == len(arrays.NalUnits) {
nalu := &NalUnit{
Nalu: make([]byte, len(sps)),
NalUnitLength: uint16(len(sps)),
}
copy(nalu.Nalu, sps)
arrays.NalUnits = append(arrays.NalUnits, nalu)
needUpdate = true
}
}
if found {
break
}
}
if i == len(hvcc.Arrays) {
nua := &HVCCNALUnitArray{
Array_completeness: 1,
NAL_unit_type: 33,
NumNalus: 1,
NalUnits: make([]*NalUnit, 1),
}
nu := &NalUnit{
NalUnitLength: uint16(len(sps)),
Nalu: make([]byte, len(sps)),
}
copy(nu.Nalu, sps)
nua.NalUnits[0] = nu
hvcc.Arrays = append(hvcc.Arrays, nua)
needUpdate = true
}
if needUpdate {
hvcc.NumTemporalLayers = uint8(Max(int(hvcc.NumTemporalLayers), int(rawsps.Sps_max_sub_layers_minus1+1)))
hvcc.TemporalIdNested = rawsps.Sps_temporal_id_nesting_flag
hvcc.ChromaFormat = uint8(rawsps.Chroma_format_idc)
hvcc.BitDepthChromaMinus8 = uint8(rawsps.Bit_depth_chroma_minus8)
hvcc.BitDepthLumaMinus8 = uint8(rawsps.Bit_depth_luma_minus8)
hvcc.updatePtl(rawsps.Ptl)
hvcc.updateVui(rawsps.Vui)
}
}
func (hvcc *HEVCRecordConfiguration) UpdatePPS(pps []byte) {
start, sc := FindStartCode(pps, 0)
pps = pps[start+int(sc):]
var rawpps H265RawPPS
rawpps.Decode(pps)
ppsid := rawpps.Pps_pic_parameter_set_id
var needUpdate bool = false
i := 0
for ; i < len(hvcc.Arrays); i++ {
arrays := hvcc.Arrays[i]
found := false
if arrays.NAL_unit_type == uint8(H265_NAL_PPS) {
j := 0
for ; j < len(arrays.NalUnits); j++ {
if ppsid != GetH265PPSId(arrays.NalUnits[j].Nalu) {
found = true
continue
}
//find the same sps nalu
if arrays.NalUnits[j].NalUnitLength == uint16(len(pps)) && bytes.Equal(arrays.NalUnits[j].Nalu, pps) {
return
}
tmppps := make([]byte, len(pps))
copy(tmppps, pps)
arrays.NalUnits[j].Nalu = tmppps
arrays.NalUnits[j].NalUnitLength = uint16(len(tmppps))
needUpdate = true
break
}
if j == len(arrays.NalUnits) {
nalu := &NalUnit{
Nalu: make([]byte, len(pps)),
NalUnitLength: uint16(len(pps)),
}
copy(nalu.Nalu, pps)
arrays.NalUnits = append(arrays.NalUnits, nalu)
needUpdate = true
}
}
if found {
break
}
}
if i == len(hvcc.Arrays) {
nua := &HVCCNALUnitArray{
Array_completeness: 1,
NAL_unit_type: 34,
NumNalus: 1,
NalUnits: make([]*NalUnit, 1),
}
nu := &NalUnit{
NalUnitLength: uint16(len(pps)),
Nalu: make([]byte, len(pps)),
}
copy(nu.Nalu, pps)
nua.NalUnits[0] = nu
hvcc.Arrays = append(hvcc.Arrays, nua)
needUpdate = true
}
if needUpdate {
if rawpps.Entropy_coding_sync_enabled_flag == 1 && rawpps.Tiles_enabled_flag == 1 {
hvcc.ParallelismType = 0
} else if rawpps.Entropy_coding_sync_enabled_flag == 1 {
hvcc.ParallelismType = 3
} else if rawpps.Tiles_enabled_flag == 1 {
hvcc.ParallelismType = 2
} else {
hvcc.ParallelismType = 1
}
}
}
func (hvcc *HEVCRecordConfiguration) UpdateVPS(vps []byte) {
start, sc := FindStartCode(vps, 0)
vps = vps[start+int(sc):]
var rawvps VPS
rawvps.Decode(vps)
vpsid := rawvps.Vps_video_parameter_set_id
var needUpdate bool = false
i := 0
for ; i < len(hvcc.Arrays); i++ {
arrays := hvcc.Arrays[i]
found := false
if arrays.NAL_unit_type == uint8(H265_NAL_VPS) {
found = true
j := 0
for ; j < len(arrays.NalUnits); j++ {
if vpsid != GetVPSId(arrays.NalUnits[j].Nalu) {
found = true
continue
}
//find the same sps nalu
if arrays.NalUnits[j].NalUnitLength == uint16(len(vps)) && bytes.Equal(arrays.NalUnits[j].Nalu, vps) {
return
}
tmpvps := make([]byte, len(vps))
copy(tmpvps, vps)
arrays.NalUnits[j].Nalu = tmpvps
arrays.NalUnits[j].NalUnitLength = uint16(len(tmpvps))
needUpdate = true
break
}
if j == len(arrays.NalUnits) {
nalu := &NalUnit{
Nalu: make([]byte, len(vps)),
NalUnitLength: uint16(len(vps)),
}
copy(nalu.Nalu, vps)
arrays.NalUnits = append(arrays.NalUnits, nalu)
needUpdate = true
}
}
if found {
break
}
}
if i == len(hvcc.Arrays) {
nua := &HVCCNALUnitArray{
Array_completeness: 1,
NAL_unit_type: 32,
NumNalus: 1,
NalUnits: make([]*NalUnit, 1),
}
nu := &NalUnit{
NalUnitLength: uint16(len(vps)),
Nalu: make([]byte, len(vps)),
}
copy(nu.Nalu, vps)
nua.NalUnits[0] = nu
hvcc.Arrays = append(hvcc.Arrays, nua)
needUpdate = true
}
if needUpdate {
hvcc.NumTemporalLayers = uint8(Max(int(hvcc.NumTemporalLayers), int(rawvps.Vps_max_layers_minus1+1)))
hvcc.updatePtl(rawvps.Ptl)
}
}
func (hvcc *HEVCRecordConfiguration) ToNalus() (nalus []byte) {
startcode := []byte{0x00, 0x00, 0x00, 0x01}
for _, arrays := range hvcc.Arrays {
for _, unit := range arrays.NalUnits {
nalus = append(nalus, startcode...)
nalus = append(nalus, unit.Nalu[:unit.NalUnitLength]...)
}
}
return
}
func (hvcc *HEVCRecordConfiguration) updatePtl(ptl ProfileTierLevel) {
hvcc.General_profile_space = ptl.General_profile_space
if hvcc.General_tier_flag < ptl.General_tier_flag {
hvcc.General_level_idc = ptl.General_level_idc
} else {
hvcc.General_level_idc = uint8(Max(int(hvcc.General_level_idc), int(ptl.General_level_idc)))
}
hvcc.General_tier_flag = uint8(Max(int(hvcc.General_tier_flag), int(ptl.General_tier_flag)))
hvcc.General_profile_idc = uint8(Max(int(hvcc.General_profile_idc), int(ptl.General_profile_idc)))
hvcc.General_profile_compatibility_flags &= ptl.General_profile_compatibility_flag
hvcc.General_constraint_indicator_flags &= ptl.General_constraint_indicator_flag
}
func (hvcc *HEVCRecordConfiguration) updateVui(vui VUI_Parameters) {
hvcc.Min_spatial_segmentation_idc = uint16(Min(int(hvcc.Min_spatial_segmentation_idc), int(vui.Min_spatial_segmentation_idc)))
}

View file

@ -0,0 +1,430 @@
package codec
import (
"encoding/binary"
"errors"
)
// rfc6716 https://datatracker.ietf.org/doc/html/rfc6716
//
// TOC byte
// 0
// 0 1 2 3 4 5 6 7
// +-+-+-+-+-+-+-+-+
// | config |s| c |
// +-+-+-+-+-+-+-+-+
// +-----------------------+-----------+-----------+-------------------+
// | Configuration | Mode | Bandwidth | Frame Sizes |
// | Number(s) | | | |
// +-----------------------+-----------+-----------+-------------------+
// | 0...3 | SILK-only | NB | 10, 20, 40, 60 ms |
// | | | | |
// | 4...7 | SILK-only | MB | 10, 20, 40, 60 ms |
// | | | | |
// | 8...11 | SILK-only | WB | 10, 20, 40, 60 ms |
// | | | | |
// | 12...13 | Hybrid | SWB | 10, 20 ms |
// | | | | |
// | 14...15 | Hybrid | FB | 10, 20 ms |
// | | | | |
// | 16...19 | CELT-only | NB | 2.5, 5, 10, 20 ms |
// | | | | |
// | 20...23 | CELT-only | WB | 2.5, 5, 10, 20 ms |
// | | | | |
// | 24...27 | CELT-only | SWB | 2.5, 5, 10, 20 ms |
// | | | | |
// | 28...31 | CELT-only | FB | 2.5, 5, 10, 20 ms |
// +-----------------------+-----------+-----------+-------------------+
// s: with 0 indicating mono and 1 indicating stereo.
//
// c : codes 0 to 3
// 0: 1 frame in the packet
// 1: 2 frames in the packet, each with equal compressed size
// 2: 2 frames in the packet, with different compressed sizes
// 3: an arbitrary number of frames in the packet
// Frame Length Coding
// 0: No frame (Discontinuous Transmission (DTX) or lost packet)
// 1...251: Length of the frame in bytes
// 252...255: A second byte is needed. The total length is (second_byte*4)+first_byte
// Code 0:
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | config |s|0|0| |
// +-+-+-+-+-+-+-+-+ |
// | Compressed frame 1 (N-1 bytes)... :
// : |
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// Code 1:
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | config |s|0|1| |
// +-+-+-+-+-+-+-+-+ :
// | Compressed frame 1 ((N-1)/2 bytes)... |
// : +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ :
// | Compressed frame 2 ((N-1)/2 bytes)... |
// : +-+-+-+-+-+-+-+-+
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// Code 2:
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | config |s|1|0| N1 (1-2 bytes): |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ :
// | Compressed frame 1 (N1 bytes)... |
// : +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
// | Compressed frame 2... :
// : |
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//Code 3:
// Frame Count Byte
// 0
// 0 1 2 3 4 5 6 7
// +-+-+-+-+-+-+-+-+
// |v|p| M |
// +-+-+-+-+-+-+-+-+
// v: 0 - CBR 1 - VBR
// p: 0 - no padding 1 - padding after frame
// M: frame count
// A CBR Code 3 Packet
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | config |s|1|1|0|p| M | Padding length (Optional) :
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// : Compressed frame 1 (R/M bytes)... :
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// : Compressed frame 2 (R/M bytes)... :
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// : ... :
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// : Compressed frame M (R/M bytes)... :
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// : Opus Padding (Optional)... |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
//
// A VBR Code 3 Packet
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | config |s|1|1|1|p| M | Padding length (Optional) :
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// : N1 (1-2 bytes): N2 (1-2 bytes): ... : N[M-1] |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// : Compressed frame 1 (N1 bytes)... :
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// : Compressed frame 2 (N2 bytes)... :
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// : ... :
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | |
// : Compressed frame M... :
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// : Opus Padding (Optional)... |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
var (
/// 10ms,20ms,40ms,60ms, samplerate 48000
// sample num per millisecond
// 48000 / 1000ms * 10 = 480 ...
SLKOpusSampleSize [4]int = [4]int{480, 960, 1920, 2880}
HybridOpusSampleSize [4]int = [4]int{480, 960}
CELTOpusSampleSize [4]int = [4]int{120, 210, 480, 960}
)
func OpusPacketDuration(packet []byte) uint64 {
config := int(packet[0] >> 3)
code := packet[0] & 0x03
frameCount := 0
var duration uint64
if code == 0 {
frameCount = 1
} else if code == 1 || code == 2 {
frameCount = 2
} else if code == 3 {
frameCount = int(packet[1] & 0x1F)
} else {
panic("code must <= 3")
}
switch {
case config >= 0 && config < 12:
duration = uint64(frameCount * SLKOpusSampleSize[config%4])
case config >= 12 && config < 16:
duration = uint64(frameCount * HybridOpusSampleSize[config%2])
case config >= 16 && config < 32:
duration = uint64(frameCount * CELTOpusSampleSize[config%4])
default:
panic("unkown opus config")
}
return duration
}
//ffmpeg opus.h OpusPacket
type OpusPacket struct {
Code int
Config int
Stereo int
Vbr int
FrameCount int
FrameLen []uint16
Frame []byte
Duration uint64
}
func DecodeOpusPacket(packet []byte) *OpusPacket {
pkt := &OpusPacket{}
pkt.Code = int(packet[0] & 0x03)
pkt.Stereo = int((packet[0] >> 2) & 0x01)
pkt.Config = int(packet[0] >> 3)
switch pkt.Code {
case 0:
pkt.FrameCount = 1
pkt.FrameLen = make([]uint16, 1)
pkt.FrameLen[0] = uint16(len(packet) - 1)
pkt.Frame = packet[1:]
case 1:
pkt.FrameCount = 2
pkt.FrameLen = make([]uint16, 1)
pkt.FrameLen[0] = uint16(len(packet)-1) / 2
pkt.Frame = packet[1:]
case 2:
pkt.FrameCount = 2
hdr := 1
N1 := int(packet[1])
if N1 >= 252 {
N1 = N1 + int(packet[2]*4)
hdr = 2
}
pkt.FrameLen = make([]uint16, 2)
pkt.FrameLen[0] = uint16(N1)
pkt.FrameLen[1] = uint16(len(packet)-hdr) - uint16(N1)
case 3:
hdr := 2
pkt.Vbr = int(packet[1] >> 7)
padding := packet[1] >> 6
pkt.FrameCount = int(packet[1] & 0x1F)
paddingLen := 0
if padding == 1 {
for packet[hdr] == 255 {
paddingLen += 254
hdr++
}
paddingLen += int(packet[hdr])
}
if pkt.Vbr == 0 {
pkt.FrameLen = make([]uint16, 1)
pkt.FrameLen[0] = uint16(len(packet)-hdr-paddingLen) / uint16(pkt.FrameCount)
pkt.Frame = packet[hdr : hdr+int(pkt.FrameLen[0]*uint16(pkt.FrameCount))]
} else {
n := 0
for i := 0; i < int(pkt.FrameCount)-1; i++ {
N1 := int(packet[hdr])
hdr += 1
if N1 >= 252 {
N1 = N1 + int(packet[hdr]*4)
hdr += 1
}
n += N1
pkt.FrameLen = append(pkt.FrameLen, uint16(N1))
}
lastFrameLen := len(packet) - hdr - paddingLen - n
pkt.FrameLen = append(pkt.FrameLen, uint16(lastFrameLen))
pkt.Frame = packet[hdr : hdr+n+lastFrameLen]
}
default:
panic("Error C must <= 3")
}
OpusPacketDuration(packet)
return pkt
}
const (
LEFT_CHANNEL = 0
RIGHT_CHANNEL = 1
)
var (
vorbisChanLayoutOffset [8][8]byte = [8][8]byte{
{0},
{0, 1},
{0, 2, 1},
{0, 1, 2, 3},
{0, 2, 1, 3, 4},
{0, 2, 1, 5, 3, 4},
{0, 2, 1, 6, 5, 3, 4},
{0, 2, 1, 7, 5, 6, 3, 4},
}
)
type ChannelOrder func(channels int, idx int) int
func defalutOrder(channels int, idx int) int {
return idx
}
func vorbisOrder(channels int, idx int) int {
return int(vorbisChanLayoutOffset[channels-1][idx])
}
type ChannelMap struct {
StreamIdx int
ChannelIdx int
Silence bool
Copy bool
CopyFrom int
}
type OpusContext struct {
Preskip int
SampleRate int
ChannelCount int
StreamCount int
StereoStreamCount int
OutputGain uint16
MapType uint8
ChannelMaps []ChannelMap
}
// opus ID Head
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | 'O' | 'p' | 'u' | 's' |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | 'H' | 'e' | 'a' | 'd' |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Version = 1 | Channel Count | Pre-skip |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Input Sample Rate (Hz) |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Output Gain (Q7.8 in dB) | Mapping Family| |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ :
// | |
// : Optional Channel Mapping Table... :
// | |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+
// | Stream Count |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Coupled Count | Channel Mapping... :
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
func (ctx *OpusContext) ParseExtranData(extraData []byte) error {
if string(extraData[0:8]) != "OpusHead" {
return errors.New("magic signature must equal OpusHead")
}
_ = extraData[8] // version
ctx.ChannelCount = int(extraData[9])
ctx.Preskip = int(binary.LittleEndian.Uint16(extraData[10:]))
ctx.SampleRate = int(binary.LittleEndian.Uint32(extraData[12:]))
ctx.OutputGain = binary.LittleEndian.Uint16(extraData[16:])
ctx.MapType = extraData[18]
var channel []byte
var order ChannelOrder
if ctx.MapType == 0 {
ctx.StreamCount = 1
ctx.StereoStreamCount = ctx.ChannelCount - 1
channel = []byte{0, 1}
order = defalutOrder
} else if ctx.MapType == 1 || ctx.MapType == 2 || ctx.MapType == 255 {
ctx.StreamCount = int(extraData[19])
ctx.StereoStreamCount = int(extraData[20])
if ctx.MapType == 1 {
channel = extraData[21 : 21+ctx.ChannelCount]
order = vorbisOrder
}
} else {
return errors.New("unsupport map type 255")
}
for i := 0; i < ctx.ChannelCount; i++ {
cm := ChannelMap{}
index := channel[order(ctx.ChannelCount, i)]
if index == 255 {
cm.Silence = true
continue
} else if index > byte(ctx.StereoStreamCount)+byte(ctx.StreamCount) {
return errors.New("index must < (streamcount + stereo streamcount)")
}
for j := 0; j < i; j++ {
if channel[order(ctx.ChannelCount, i)] == index {
cm.Copy = true
cm.CopyFrom = j
break
}
}
if int(index) < 2*ctx.StereoStreamCount {
cm.StreamIdx = int(index) / 2
if index&1 == 0 {
cm.ChannelIdx = LEFT_CHANNEL
} else {
cm.ChannelIdx = RIGHT_CHANNEL
}
} else {
cm.StreamIdx = int(index) - ctx.StereoStreamCount
cm.ChannelIdx = 0
}
ctx.ChannelMaps = append(ctx.ChannelMaps, cm)
}
return nil
}
func (ctx *OpusContext) WriteOpusExtraData() []byte {
extraData := make([]byte, 19)
copy(extraData, string("OpusHead"))
extraData[8] = 0x01
extraData[9] = byte(ctx.ChannelCount)
binary.LittleEndian.PutUint16(extraData[10:], uint16(ctx.Preskip))
binary.LittleEndian.PutUint32(extraData[12:], uint32(ctx.SampleRate))
return extraData
}
func WriteDefaultOpusExtraData() []byte {
return []byte{
'O', 'p', 'u', 's', 'H', 'e', 'a', 'd',
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
}
}

View file

@ -0,0 +1,257 @@
package codec
import "fmt"
type START_CODE_TYPE int
const (
START_CODE_3 START_CODE_TYPE = 3
START_CODE_4 = 4
)
func FindStartCode(nalu []byte, offset int) (int, START_CODE_TYPE) {
for i := offset; i < len(nalu)-4; i++ {
if nalu[i] == 0x00 && nalu[i+1] == 0x00 {
if nalu[i+2] == 0x01 {
return i, START_CODE_3
} else if nalu[i+2] == 0x00 && nalu[i+3] == 0x01 {
return i, START_CODE_4
}
}
}
return -1, START_CODE_3
}
func FindSyncword(aac []byte, offset int) int {
for i := offset; i < len(aac); i++ {
if aac[i] == 0xFF && aac[i+1]&0xF0 == 0xF0 {
return i
}
}
return -1
}
func SplitFrame(frames []byte, onFrame func(nalu []byte) bool) {
beg, sc := FindStartCode(frames, 0)
for beg >= 0 {
end, sc2 := FindStartCode(frames, beg+int(sc))
if end == -1 {
if onFrame != nil {
onFrame(frames[beg+int(sc):])
}
break
}
if onFrame != nil && onFrame(frames[beg+int(sc):end]) == false {
break
}
beg = end
sc = sc2
}
}
func SplitFrameWithStartCode(frames []byte, onFrame func(nalu []byte) bool) {
beg, sc := FindStartCode(frames, 0)
for beg >= 0 {
end, sc2 := FindStartCode(frames, beg+int(sc))
if end == -1 {
if onFrame != nil {
onFrame(frames[beg:])
}
break
}
if onFrame != nil && onFrame(frames[beg:end]) == false {
break
}
beg = end
sc = sc2
}
}
func SplitAACFrame(frames []byte, onFrame func(aac []byte)) {
var adts ADTS_Frame_Header
start := FindSyncword(frames, 0)
for start >= 0 {
adts.Decode(frames[start:])
onFrame(frames[start : start+int(adts.Variable_Header.Frame_length)])
start = FindSyncword(frames, start+int(adts.Variable_Header.Frame_length))
}
}
func H264NaluType(h264 []byte) H264_NAL_TYPE {
loc, sc := FindStartCode(h264, 0)
return H264_NAL_TYPE(h264[loc+int(sc)] & 0x1F)
}
func H264NaluTypeWithoutStartCode(h264 []byte) H264_NAL_TYPE {
return H264_NAL_TYPE(h264[0] & 0x1F)
}
func H265NaluType(h265 []byte) H265_NAL_TYPE {
loc, sc := FindStartCode(h265, 0)
return H265_NAL_TYPE((h265[loc+int(sc)] >> 1) & 0x3F)
}
func H265NaluTypeWithoutStartCode(h265 []byte) H265_NAL_TYPE {
return H265_NAL_TYPE((h265[0] >> 1) & 0x3F)
}
func GetH264FirstMbInSlice(nalu []byte) uint64 {
start, sc := FindStartCode(nalu, 0)
bs := NewBitStream(nalu[start+int(sc)+1:])
sliceHdr := &SliceHeader{}
sliceHdr.Decode(bs)
return sliceHdr.First_mb_in_slice
}
func GetH265FirstMbInSlice(nalu []byte) uint64 {
start, sc := FindStartCode(nalu, 0)
bs := NewBitStream(nalu[start+int(sc)+2:])
sliceHdr := &SliceHeader{}
sliceHdr.Decode(bs)
return sliceHdr.First_mb_in_slice
}
func IsH264IDRFrame(h264 []byte) bool {
ret := false
onnalu := func(nalu []byte) bool {
nal_type := H264NaluTypeWithoutStartCode(nalu)
if nal_type < 5 {
return false
} else if nal_type == 5 {
ret = true
return false
} else {
return true
}
}
SplitFrame(h264, onnalu)
return ret
}
func IsH264VCLNaluType(nal_type H264_NAL_TYPE) bool {
if nal_type <= H264_NAL_I_SLICE && nal_type > H264_NAL_RESERVED {
return true
}
return false
}
func IsH265VCLNaluType(nal_type H265_NAL_TYPE) bool {
if (nal_type <= H265_NAL_SLICE_CRA && nal_type >= H265_NAL_SLICE_BLA_W_LP) ||
(nal_type <= H265_NAL_SLICE_RASL_R && nal_type >= H265_NAL_Slice_TRAIL_N) {
return true
}
return false
}
func IsH265IDRFrame(h265 []byte) bool {
ret := false
onnalu := func(nalu []byte) bool {
nal_type := H264NaluTypeWithoutStartCode(nalu)
if nal_type <= 9 && nal_type >= 0 {
return false
} else if nal_type >= 16 && nal_type <= 21 {
ret = true
return false
} else {
return true
}
}
SplitFrame(h265, onnalu)
return ret
}
func Max(x, y int) int {
if x > y {
return x
} else {
return y
}
}
func Min(x, y int) int {
if x > y {
return y
} else {
return x
}
}
func ShowPacketHexdump(data []byte) {
for k := 0; k < len(data); k++ {
if k%8 == 0 && k != 0 {
fmt.Printf("\n")
}
fmt.Printf("%02x ", data[k])
}
fmt.Printf("\n")
}
var crc32table [256]uint32 = [256]uint32{
0x00000000, 0xB71DC104, 0x6E3B8209, 0xD926430D, 0xDC760413, 0x6B6BC517,
0xB24D861A, 0x0550471E, 0xB8ED0826, 0x0FF0C922, 0xD6D68A2F, 0x61CB4B2B,
0x649B0C35, 0xD386CD31, 0x0AA08E3C, 0xBDBD4F38, 0x70DB114C, 0xC7C6D048,
0x1EE09345, 0xA9FD5241, 0xACAD155F, 0x1BB0D45B, 0xC2969756, 0x758B5652,
0xC836196A, 0x7F2BD86E, 0xA60D9B63, 0x11105A67, 0x14401D79, 0xA35DDC7D,
0x7A7B9F70, 0xCD665E74, 0xE0B62398, 0x57ABE29C, 0x8E8DA191, 0x39906095,
0x3CC0278B, 0x8BDDE68F, 0x52FBA582, 0xE5E66486, 0x585B2BBE, 0xEF46EABA,
0x3660A9B7, 0x817D68B3, 0x842D2FAD, 0x3330EEA9, 0xEA16ADA4, 0x5D0B6CA0,
0x906D32D4, 0x2770F3D0, 0xFE56B0DD, 0x494B71D9, 0x4C1B36C7, 0xFB06F7C3,
0x2220B4CE, 0x953D75CA, 0x28803AF2, 0x9F9DFBF6, 0x46BBB8FB, 0xF1A679FF,
0xF4F63EE1, 0x43EBFFE5, 0x9ACDBCE8, 0x2DD07DEC, 0x77708634, 0xC06D4730,
0x194B043D, 0xAE56C539, 0xAB068227, 0x1C1B4323, 0xC53D002E, 0x7220C12A,
0xCF9D8E12, 0x78804F16, 0xA1A60C1B, 0x16BBCD1F, 0x13EB8A01, 0xA4F64B05,
0x7DD00808, 0xCACDC90C, 0x07AB9778, 0xB0B6567C, 0x69901571, 0xDE8DD475,
0xDBDD936B, 0x6CC0526F, 0xB5E61162, 0x02FBD066, 0xBF469F5E, 0x085B5E5A,
0xD17D1D57, 0x6660DC53, 0x63309B4D, 0xD42D5A49, 0x0D0B1944, 0xBA16D840,
0x97C6A5AC, 0x20DB64A8, 0xF9FD27A5, 0x4EE0E6A1, 0x4BB0A1BF, 0xFCAD60BB,
0x258B23B6, 0x9296E2B2, 0x2F2BAD8A, 0x98366C8E, 0x41102F83, 0xF60DEE87,
0xF35DA999, 0x4440689D, 0x9D662B90, 0x2A7BEA94, 0xE71DB4E0, 0x500075E4,
0x892636E9, 0x3E3BF7ED, 0x3B6BB0F3, 0x8C7671F7, 0x555032FA, 0xE24DF3FE,
0x5FF0BCC6, 0xE8ED7DC2, 0x31CB3ECF, 0x86D6FFCB, 0x8386B8D5, 0x349B79D1,
0xEDBD3ADC, 0x5AA0FBD8, 0xEEE00C69, 0x59FDCD6D, 0x80DB8E60, 0x37C64F64,
0x3296087A, 0x858BC97E, 0x5CAD8A73, 0xEBB04B77, 0x560D044F, 0xE110C54B,
0x38368646, 0x8F2B4742, 0x8A7B005C, 0x3D66C158, 0xE4408255, 0x535D4351,
0x9E3B1D25, 0x2926DC21, 0xF0009F2C, 0x471D5E28, 0x424D1936, 0xF550D832,
0x2C769B3F, 0x9B6B5A3B, 0x26D61503, 0x91CBD407, 0x48ED970A, 0xFFF0560E,
0xFAA01110, 0x4DBDD014, 0x949B9319, 0x2386521D, 0x0E562FF1, 0xB94BEEF5,
0x606DADF8, 0xD7706CFC, 0xD2202BE2, 0x653DEAE6, 0xBC1BA9EB, 0x0B0668EF,
0xB6BB27D7, 0x01A6E6D3, 0xD880A5DE, 0x6F9D64DA, 0x6ACD23C4, 0xDDD0E2C0,
0x04F6A1CD, 0xB3EB60C9, 0x7E8D3EBD, 0xC990FFB9, 0x10B6BCB4, 0xA7AB7DB0,
0xA2FB3AAE, 0x15E6FBAA, 0xCCC0B8A7, 0x7BDD79A3, 0xC660369B, 0x717DF79F,
0xA85BB492, 0x1F467596, 0x1A163288, 0xAD0BF38C, 0x742DB081, 0xC3307185,
0x99908A5D, 0x2E8D4B59, 0xF7AB0854, 0x40B6C950, 0x45E68E4E, 0xF2FB4F4A,
0x2BDD0C47, 0x9CC0CD43, 0x217D827B, 0x9660437F, 0x4F460072, 0xF85BC176,
0xFD0B8668, 0x4A16476C, 0x93300461, 0x242DC565, 0xE94B9B11, 0x5E565A15,
0x87701918, 0x306DD81C, 0x353D9F02, 0x82205E06, 0x5B061D0B, 0xEC1BDC0F,
0x51A69337, 0xE6BB5233, 0x3F9D113E, 0x8880D03A, 0x8DD09724, 0x3ACD5620,
0xE3EB152D, 0x54F6D429, 0x7926A9C5, 0xCE3B68C1, 0x171D2BCC, 0xA000EAC8,
0xA550ADD6, 0x124D6CD2, 0xCB6B2FDF, 0x7C76EEDB, 0xC1CBA1E3, 0x76D660E7,
0xAFF023EA, 0x18EDE2EE, 0x1DBDA5F0, 0xAAA064F4, 0x738627F9, 0xC49BE6FD,
0x09FDB889, 0xBEE0798D, 0x67C63A80, 0xD0DBFB84, 0xD58BBC9A, 0x62967D9E,
0xBBB03E93, 0x0CADFF97, 0xB110B0AF, 0x060D71AB, 0xDF2B32A6, 0x6836F3A2,
0x6D66B4BC, 0xDA7B75B8, 0x035D36B5, 0xB440F7B1,
}
func CalcCrc32(crc uint32, buffer []byte) uint32 {
var i int = 0
for i = 0; i < len(buffer); i++ {
crc = crc32table[(crc^uint32(buffer[i]))&0xff] ^ (crc >> 8)
}
return crc
}
func CovertRbspToSodb(rbsp []byte) []byte {
bs := NewBitStream(rbsp)
bsw := NewBitStreamWriter(len(rbsp))
for !bs.EOS() {
if bs.RemainBytes() > 3 && bs.NextBits(24) == 0x000003 {
bsw.PutByte(bs.Uint8(8))
bsw.PutByte(bs.Uint8(8))
bs.SkipBits(8)
} else {
bsw.PutByte(bs.Uint8(8))
}
}
return bsw.Bits()
}

View file

@ -0,0 +1,72 @@
package codec
import "errors"
type VP8FrameTag struct {
FrameType uint32 //0: I frame , 1: P frame
Version uint32
Display uint32
FirstPartSize uint32
}
type VP8KeyFrameHead struct {
Width int
Height int
HorizScale int
VertScale int
}
func DecodeFrameTag(frame []byte) (*VP8FrameTag, error) {
if len(frame) < 3 {
return nil, errors.New("frame bytes < 3")
}
var tmp uint32 = (uint32(frame[2]) << 16) | (uint32(frame[1]) << 8) | uint32(frame[0])
tag := &VP8FrameTag{}
tag.FrameType = tmp & 0x01
tag.Version = (tmp >> 1) & 0x07
tag.Display = (tmp >> 4) & 0x01
tag.FirstPartSize = (tmp >> 5) & 0x7FFFF
return tag, nil
}
func DecodeKeyFrameHead(frame []byte) (*VP8KeyFrameHead, error) {
if len(frame) < 7 {
return nil, errors.New("frame bytes < 3")
}
if frame[0] != 0x9d || frame[1] != 0x01 || frame[2] != 0x2a {
return nil, errors.New("not find Start code")
}
head := &VP8KeyFrameHead{}
head.Width = int(uint16(frame[4]&0x3f)<<8 | uint16(frame[3]))
head.HorizScale = int(frame[4] >> 6)
head.Height = int(uint16(frame[6]&0x3f)<<8 | uint16(frame[5]))
head.VertScale = int(frame[6] >> 6)
return head, nil
}
func IsKeyFrame(frame []byte) bool {
tag, err := DecodeFrameTag(frame)
if err != nil {
return false
}
if tag.FrameType == 0 {
return true
} else {
return false
}
}
func GetResloution(frame []byte) (width int, height int, err error) {
if !IsKeyFrame(frame) {
return 0, 0, errors.New("the frame is not Key frame")
}
head, err := DecodeKeyFrameHead(frame[3:])
if err != nil {
return 0, 0, err
}
return head.Width, head.Height, nil
}

View 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.

View 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

View 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=

View 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)
}

View 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包过程中解码回调psmsystem headerpes包等
//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
}

View 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
}

View 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
}

View 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]
}

View 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
}
}
}

View 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
}