mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
GB28181: Support GB28181-2016 protocol. v5.0.74 (#3201)
01. Support GB config as StreamCaster. 02. Support disable GB by --gb28181=off. 03. Add utests for SIP examples. 04. Wireshark plugin to decode TCP/9000 as rtp.rfc4571 05. Support MPEGPS program stream codec. 06. Add utest for PS stream codec. 07. Decode MPEGPS packet stream. 08. Carry RTP and PS packet as helper in PS message. 09. Support recover from error mode. 10. Support process by a pack of PS/TS messages. 11. Add statistic for recovered and msgs dropped. 12. Recover from err position fastly. 13. Define state machine for GB session. 14. Bind context to GB session. 15. Re-invite when media disconnected. 16. Update GitHub actions with GB28181. 17. Support parse CANDIDATE by env or pip. 18. Support mux GB28181 to RTMP. 19. Support regression test by srs-bench.
This commit is contained in:
parent
9c81a0e1bd
commit
5a420ece3b
298 changed files with 43343 additions and 763 deletions
21
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/LICENSE
generated
vendored
Normal file
21
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2021 caoyaping
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
89
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/README.md
generated
vendored
Normal file
89
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/README.md
generated
vendored
Normal 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)
|
||||
|
||||
|
||||
|
||||
```
|
255
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/aac.go
generated
vendored
Normal file
255
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/aac.go
generated
vendored
Normal 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()
|
||||
}
|
358
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/bitstream.go
generated
vendored
Normal file
358
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/bitstream.go
generated
vendored
Normal 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
|
||||
}
|
64
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/codec.go
generated
vendored
Normal file
64
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/codec.go
generated
vendored
Normal 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
|
||||
)
|
3
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/go.mod
generated
vendored
Normal file
3
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/go.mod
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
module github.com/yapingcat/gomedia/codec
|
||||
|
||||
go 1.16
|
396
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/h264.go
generated
vendored
Normal file
396
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/h264.go
generated
vendored
Normal 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 = ‘111111’b;
|
||||
// unsigned int(2) lengthSizeMinusOne;
|
||||
// bit(3) reserved = ‘111’b;
|
||||
// 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 = ‘111111’b;
|
||||
// unsigned int(2) chroma_format;
|
||||
// bit(5) reserved = ‘11111’b;
|
||||
// unsigned int(3) bit_depth_luma_minus8;
|
||||
// bit(5) reserved = ‘11111’b;
|
||||
// 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
|
||||
}
|
998
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/h265.go
generated
vendored
Normal file
998
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/h265.go
generated
vendored
Normal 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)))
|
||||
}
|
430
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/opus.go
generated
vendored
Normal file
430
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/opus.go
generated
vendored
Normal 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,
|
||||
}
|
||||
}
|
257
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/util.go
generated
vendored
Normal file
257
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/util.go
generated
vendored
Normal 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()
|
||||
}
|
72
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/vp8.go
generated
vendored
Normal file
72
trunk/3rdparty/srs-bench/vendor/github.com/yapingcat/gomedia/codec/vp8.go
generated
vendored
Normal 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
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue