Rewrite AnnexB/AVCC parsers

This commit is contained in:
Alexey Khit
2023-08-16 16:50:55 +03:00
parent e1be2d9e48
commit 1dd3dbbcd8
28 changed files with 513 additions and 176 deletions
+7
View File
@@ -82,6 +82,13 @@ func (r *Reader) ReadBits16(n byte) (res uint16) {
return
}
func (r *Reader) ReadBits64(n byte) (res uint64) {
for i := n - 1; i != 255; i-- {
res |= uint64(r.ReadBit()) << i
}
return
}
// ReadUEGolomb - ReadExponentialGolomb (unsigned)
func (r *Reader) ReadUEGolomb() uint32 {
var size byte
+2 -2
View File
@@ -17,7 +17,7 @@ import (
"time"
"github.com/AlexxIT/go2rtc/pkg/core"
"github.com/AlexxIT/go2rtc/pkg/h264"
"github.com/AlexxIT/go2rtc/pkg/h264/annexb"
"github.com/AlexxIT/go2rtc/pkg/tcp"
"github.com/pion/rtp"
)
@@ -226,7 +226,7 @@ func (c *Client) Handle() error {
Header: rtp.Header{
Timestamp: core.Now90000(),
},
Payload: h264.AnnexB2AVC(b[6:]),
Payload: annexb.EncodeToAVCC(b[6:], false),
}
c.videoTrack.WriteRTP(pkt)
} else {
+8 -6
View File
@@ -8,14 +8,16 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/AlexxIT/go2rtc/pkg/core"
"github.com/AlexxIT/go2rtc/pkg/h264"
"github.com/AlexxIT/go2rtc/pkg/h265"
"github.com/pion/rtp"
"io"
"net"
"net/url"
"time"
"github.com/AlexxIT/go2rtc/pkg/core"
"github.com/AlexxIT/go2rtc/pkg/h264"
"github.com/AlexxIT/go2rtc/pkg/h264/annexb"
"github.com/AlexxIT/go2rtc/pkg/h265"
"github.com/pion/rtp"
)
type Client struct {
@@ -173,7 +175,7 @@ func (c *Client) Handle() error {
switch dataType {
case 0x1FC, 0x1FE: // video IFrame
payload := h264.AnnexB2AVC(b[16:])
payload := annexb.EncodeToAVCC(b[16:], false)
if c.videoTrack == nil {
fps := b[5]
@@ -208,7 +210,7 @@ func (c *Client) Handle() error {
packet := &rtp.Packet{
Header: rtp.Header{Timestamp: c.videoTS},
Payload: h264.AnnexB2AVC(b[8:]),
Payload: annexb.EncodeToAVCC(b[8:], false),
}
//log.Printf("[DVR] %v, len: %d, ts: %10d", h265.Types(packet.Payload), len(packet.Payload), packet.Timestamp)
+2 -2
View File
@@ -7,7 +7,7 @@ import (
"github.com/AlexxIT/go2rtc/pkg/aac"
"github.com/AlexxIT/go2rtc/pkg/core"
"github.com/AlexxIT/go2rtc/pkg/h264/avc"
"github.com/AlexxIT/go2rtc/pkg/h264"
"github.com/pion/rtp"
)
@@ -101,7 +101,7 @@ func (c *Client) Describe() error {
continue
}
codec := avc.ConfigToCodec(b[5:])
codec := h264.ConfigToCodec(b[5:])
media := &core.Media{
Kind: core.KindVideo,
Direction: core.DirectionRecvonly,
+1
View File
@@ -13,3 +13,4 @@ Payloader code taken from [pion](https://github.com/pion/rtp) library. And chang
- [AVC profiles table](https://developer.mozilla.org/ru/docs/Web/Media/Formats/codecs_parameter)
- [Supported Media for Google Cast](https://developers.google.com/cast/docs/media)
- [Two stream formats, Annex-B, AVCC (H.264) and HVCC (H.265)](https://www.programmersought.com/article/3901815022/)
- https://docs.aws.amazon.com/kinesisvideostreams/latest/dg/producer-reference-nal.html
+129
View File
@@ -0,0 +1,129 @@
// Package annexb - universal for H264 and H265
package annexb
import (
"bytes"
"encoding/binary"
)
const StartCode = "\x00\x00\x00\x01"
const startAUD = StartCode + "\x09\xF0" + StartCode
// EncodeToAVCC
// will change original slice data!
// safeAppend should be used if original slice has useful data after end (part of other slice)
//
// FFmpeg MPEG-TS: 00000001 AUD 00000001 SPS 00000001 PPS 000001 IFrame
// FFmpeg H264: 00000001 SPS 00000001 PPS 000001 IFrame 00000001 PFrame
func EncodeToAVCC(b []byte, safeAppend bool) []byte {
const minSize = len(StartCode) + 1
// 1. Check frist "start code"
if len(b) < len(startAUD) || string(b[:len(StartCode)]) != StartCode {
return nil
}
// 2. Skip Access unit delimiter (AUD) from FFmpeg
if string(b[:len(startAUD)]) == startAUD {
b = b[6:]
}
var start int
for i, n := minSize, len(b)-minSize; i < n; {
// 3. Check "start code" (first 2 bytes)
if b[i] != 0 || b[i+1] != 0 {
i++
continue
}
// 4. Check "start code" (3 bytes size or 4 bytes size)
if b[i+2] == 1 {
if safeAppend {
// protect original slice from "damage"
b = bytes.Clone(b)
safeAppend = false
}
// convert start code from 3 bytes to 4 bytes
b = append(b, 0)
copy(b[i+1:], b[i:])
n++
} else if b[i+2] != 0 || b[i+3] != 1 {
i++
continue
}
// 5. Set size for previous AU
size := uint32(i - start - len(StartCode))
binary.BigEndian.PutUint32(b[start:], size)
start = i
i += minSize
}
// 6. Set size for last AU
size := uint32(len(b) - start - len(StartCode))
binary.BigEndian.PutUint32(b[start:], size)
return b
}
func DecodeAVCC(b []byte) []byte {
b = bytes.Clone(b)
for i := 0; i < len(b); {
size := int(binary.BigEndian.Uint32(b[i:]))
b[i] = 0
b[i+1] = 0
b[i+2] = 0
b[i+3] = 1
i += 4 + size
}
return b
}
const (
h264PFrame = 1
h264IFrame = 5
h264SPS = 7
h264PPS = 8
h265VPS = 32
h265PFrame = 1
)
// IndexFrame - get new frame start position in the AnnexB stream
func IndexFrame(b []byte) int {
if len(b) < len(startAUD) {
return -1
}
for i := len(startAUD); ; {
if di := bytes.Index(b[i:], []byte(StartCode)); di < 0 {
break
} else {
i += di + 4 // move to NALU start
}
if i >= len(b) {
break
}
h264Type := b[i] & 0b1_1111
switch h264Type {
case h264PFrame, h264SPS:
return i - 4 // move to start code
case h264IFrame, h264PPS:
continue
}
h265Type := (b[i] >> 1) & 0b11_1111
switch h265Type {
case h265PFrame, h265VPS:
return i - 4 // move to start code
}
}
return -1
}
+1 -102
View File
@@ -3,46 +3,12 @@ package h264
import (
"bytes"
"encoding/binary"
"github.com/AlexxIT/go2rtc/pkg/core"
"github.com/pion/rtp"
)
func AnnexB2AVC(b []byte) []byte {
for i := 0; i < len(b); {
if i+4 >= len(b) {
break
}
size := bytes.Index(b[i+4:], []byte{0, 0, 0, 1})
if size < 0 {
size = len(b) - (i + 4)
}
binary.BigEndian.PutUint32(b[i:], uint32(size))
i += size + 4
}
return b
}
func AVCtoAnnexB(b []byte) []byte {
b = bytes.Clone(b)
for i := 0; i < len(b); {
size := int(binary.BigEndian.Uint32(b[i:]))
b[i] = 0
b[i+1] = 0
b[i+2] = 0
b[i+3] = 1
i += 4 + size
}
return b
}
const forbiddenZeroBit = 0x80
const nalUnitType = 0x1F
// DecodeStream - find and return first AU in AVC format
// Deprecated: DecodeStream - find and return first AU in AVC format
// useful for processing live streams with unknown separator size
func DecodeStream(annexb []byte) ([]byte, int) {
startPos := -1
@@ -154,70 +120,3 @@ func IndexFrom(b []byte, sep []byte, from int) int {
return bytes.Index(b, sep)
}
func EncodeAVC(nals ...[]byte) (avc []byte) {
var i, n int
for _, nal := range nals {
if i = len(nal); i > 0 {
n += 4 + i
}
}
avc = make([]byte, n)
n = 0
for _, nal := range nals {
if i = len(nal); i > 0 {
binary.BigEndian.PutUint32(avc[n:], uint32(i))
n += 4 + copy(avc[n+4:], nal)
}
}
return
}
func RepairAVC(codec *core.Codec, handler core.HandlerFunc) core.HandlerFunc {
sps, pps := GetParameterSet(codec.FmtpLine)
ps := EncodeAVC(sps, pps)
return func(packet *rtp.Packet) {
if NALUType(packet.Payload) == NALUTypeIFrame {
packet.Payload = Join(ps, packet.Payload)
}
handler(packet)
}
}
func SplitAVC(data []byte) [][]byte {
var nals [][]byte
for {
// get AVC length
size := int(binary.BigEndian.Uint32(data)) + 4
// check if multiple items in one packet
if size < len(data) {
nals = append(nals, data[:size])
data = data[size:]
} else {
nals = append(nals, data)
break
}
}
return nals
}
func Types(data []byte) []byte {
var types []byte
for {
types = append(types, NALUType(data))
size := 4 + int(binary.BigEndian.Uint32(data))
if size < len(data) {
data = data[size:]
} else {
break
}
}
return types
}
-22
View File
@@ -1,22 +0,0 @@
package avc
import (
"encoding/hex"
"testing"
"github.com/stretchr/testify/require"
)
func TestDecodeConfig(t *testing.T) {
s := "01640033ffe1000c67640033ac1514a02800f19001000468ee3cb0"
src, err := hex.DecodeString(s)
require.Nil(t, err)
profile, sps, pps := DecodeConfig(src)
require.NotNil(t, profile)
require.NotNil(t, sps)
require.NotNil(t, pps)
dst := EncodeConfig(sps, pps)
require.Equal(t, src, dst)
}
+111
View File
@@ -0,0 +1,111 @@
// Package h264 - AVCC format related functions
package h264
import (
"bytes"
"encoding/base64"
"encoding/binary"
"encoding/hex"
"github.com/AlexxIT/go2rtc/pkg/core"
"github.com/pion/rtp"
)
func RepairAVCC(codec *core.Codec, handler core.HandlerFunc) core.HandlerFunc {
sps, pps := GetParameterSet(codec.FmtpLine)
ps := JoinNALU(sps, pps)
return func(packet *rtp.Packet) {
if NALUType(packet.Payload) == NALUTypeIFrame {
packet.Payload = Join(ps, packet.Payload)
}
handler(packet)
}
}
func JoinNALU(nalus ...[]byte) (avcc []byte) {
var i, n int
for _, nalu := range nalus {
if i = len(nalu); i > 0 {
n += 4 + i
}
}
avcc = make([]byte, n)
n = 0
for _, nal := range nalus {
if i = len(nal); i > 0 {
binary.BigEndian.PutUint32(avcc[n:], uint32(i))
n += 4 + copy(avcc[n+4:], nal)
}
}
return
}
func SplitNALU(avcc []byte) [][]byte {
var nals [][]byte
for {
// get AVC length
size := int(binary.BigEndian.Uint32(avcc)) + 4
// check if multiple items in one packet
if size < len(avcc) {
nals = append(nals, avcc[:size])
avcc = avcc[size:]
} else {
nals = append(nals, avcc)
break
}
}
return nals
}
func NALUTypes(avcc []byte) []byte {
var types []byte
for {
types = append(types, NALUType(avcc))
size := 4 + int(binary.BigEndian.Uint32(avcc))
if size < len(avcc) {
avcc = avcc[size:]
} else {
break
}
}
return types
}
func AVCCToCodec(avcc []byte) *core.Codec {
buf := bytes.NewBufferString("packetization-mode=1")
for {
size := 4 + int(binary.BigEndian.Uint32(avcc))
switch NALUType(avcc) {
case NALUTypeSPS:
buf.WriteString(";profile-level-id=")
buf.WriteString(hex.EncodeToString(avcc[5:8]))
buf.WriteString(";sprop-parameter-sets=")
buf.WriteString(base64.StdEncoding.EncodeToString(avcc[4:size]))
case NALUTypePPS:
buf.WriteString(",")
buf.WriteString(base64.StdEncoding.EncodeToString(avcc[4:size]))
}
if size < len(avcc) {
avcc = avcc[size:]
} else {
break
}
}
return &core.Codec{
Name: core.CodecH264,
ClockRate: 90000,
FmtpLine: buf.String(),
PayloadType: core.PayloadTypeRAW,
}
}
@@ -1,12 +1,27 @@
package avc
package h264
import (
"encoding/base64"
"encoding/hex"
"testing"
"github.com/stretchr/testify/require"
)
func TestDecodeConfig(t *testing.T) {
s := "01640033ffe1000c67640033ac1514a02800f19001000468ee3cb0"
src, err := hex.DecodeString(s)
require.Nil(t, err)
profile, sps, pps := DecodeConfig(src)
require.NotNil(t, profile)
require.NotNil(t, sps)
require.NotNil(t, pps)
dst := EncodeConfig(sps, pps)
require.Equal(t, src, dst)
}
func TestDecodeSPS(t *testing.T) {
s := "Z0IAMukAUAHjQgAAB9IAAOqcCAA=" // Amcrest AD410
b, err := base64.StdEncoding.DecodeString(s)
@@ -14,7 +29,7 @@ func TestDecodeSPS(t *testing.T) {
sps := DecodeSPS(b)
require.Equal(t, uint16(2560), sps.Width())
require.Equal(t, uint16(1920), sps.Heigth())
require.Equal(t, uint16(1920), sps.Height())
s = "R00AKZmgHgCJ+WEAAAMD6AAATiCE" // Sonoff
b, err = base64.StdEncoding.DecodeString(s)
@@ -22,5 +37,5 @@ func TestDecodeSPS(t *testing.T) {
sps = DecodeSPS(b)
require.Equal(t, uint16(1920), sps.Width())
require.Equal(t, uint16(1080), sps.Heigth())
require.Equal(t, uint16(1080), sps.Height())
}
+3 -1
View File
@@ -1,4 +1,5 @@
package avc
// Package h264 - MPEG4 format related functions
package h264
import (
"bytes"
@@ -9,6 +10,7 @@ import (
"github.com/AlexxIT/go2rtc/pkg/core"
)
// DecodeConfig - extract profile, SPS and PPS from MPEG4 config
func DecodeConfig(conf []byte) (profile []byte, sps []byte, pps []byte) {
if len(conf) < 6 || conf[0] != 1 {
return
+4 -2
View File
@@ -2,7 +2,9 @@ package h264
import (
"encoding/binary"
"github.com/AlexxIT/go2rtc/pkg/core"
"github.com/AlexxIT/go2rtc/pkg/h264/annexb"
"github.com/pion/rtp"
"github.com/pion/rtp/codecs"
)
@@ -15,7 +17,7 @@ func RTPDepay(codec *core.Codec, handler core.HandlerFunc) core.HandlerFunc {
depack := &codecs.H264Packet{IsAVC: true}
sps, pps := GetParameterSet(codec.FmtpLine)
ps := EncodeAVC(sps, pps)
ps := JoinNALU(sps, pps)
buf := make([]byte, 0, 512*1024) // 512K
@@ -81,7 +83,7 @@ func RTPDepay(codec *core.Codec, handler core.HandlerFunc) core.HandlerFunc {
// some Chinese buggy cameras has single packet with SPS+PPS+IFrame separated by 00 00 00 01
// https://github.com/AlexxIT/WebRTC/issues/391
// https://github.com/AlexxIT/WebRTC/issues/392
AnnexB2AVC(payload)
payload = annexb.EncodeToAVCC(payload, false)
}
//log.Printf("[AVC] %v, len: %d, ts: %10d, seq: %d", Types(payload), len(payload), packet.Timestamp, packet.SequenceNumber)
+17 -17
View File
@@ -1,4 +1,4 @@
package avc
package h264
import "github.com/AlexxIT/go2rtc/pkg/bits"
@@ -49,11 +49,26 @@ type SPS struct {
sar_height uint32
}
func (s *SPS) Width() uint16 {
width := 16 * (s.pic_width_in_mbs_minus_1 + 1)
crop := 2 * (s.frame_crop_left_offset + s.frame_crop_right_offset)
return uint16(width - crop)
}
func (s *SPS) Height() uint16 {
height := 16 * (s.pic_height_in_map_units_minus_1 + 1)
crop := 2 * (s.frame_crop_top_offset + s.frame_crop_bottom_offset)
if s.frame_mbs_only_flag == 0 {
height *= 2
}
return uint16(height - crop)
}
func DecodeSPS(sps []byte) *SPS {
r := bits.NewReader(sps)
hdr := r.ReadByte()
if hdr&0x1F != 7 {
if hdr&0x1F != NALUTypeSPS {
return nil
}
@@ -147,18 +162,3 @@ func DecodeSPS(sps []byte) *SPS {
return s
}
func (s *SPS) Width() uint16 {
width := 16 * (s.pic_width_in_mbs_minus_1 + 1)
crop := 2 * (s.frame_crop_left_offset + s.frame_crop_right_offset)
return uint16(width - crop)
}
func (s *SPS) Heigth() uint16 {
height := 16 * (s.pic_height_in_map_units_minus_1 + 1)
crop := 2 * (s.frame_crop_top_offset + s.frame_crop_bottom_offset)
if s.frame_mbs_only_flag == 0 {
height *= 2
}
return uint16(height - crop)
}
+1 -1
View File
@@ -5,7 +5,7 @@ import "github.com/AlexxIT/go2rtc/pkg/h264"
const forbiddenZeroBit = 0x80
const nalUnitType = 0x3F
// DecodeStream - find and return first AU in AVC format
// Deprecated: DecodeStream - find and return first AU in AVC format
// useful for processing live streams with unknown separator size
func DecodeStream(annexb []byte) ([]byte, int) {
startPos := -1
+43
View File
@@ -0,0 +1,43 @@
// Package h265 - AVCC format related functions
package h265
import (
"bytes"
"encoding/base64"
"encoding/binary"
"github.com/AlexxIT/go2rtc/pkg/core"
)
func AVCCToCodec(avcc []byte) *core.Codec {
buf := bytes.NewBufferString("profile-id=1")
for {
size := 4 + int(binary.BigEndian.Uint32(avcc))
switch NALUType(avcc) {
case NALUTypeVPS:
buf.WriteString(";sprop-vps=")
buf.WriteString(base64.StdEncoding.EncodeToString(avcc[4:size]))
case NALUTypeSPS:
buf.WriteString(";sprop-sps=")
buf.WriteString(base64.StdEncoding.EncodeToString(avcc[4:size]))
case NALUTypePPS:
buf.WriteString(";sprop-pps=")
buf.WriteString(base64.StdEncoding.EncodeToString(avcc[4:size]))
}
if size < len(avcc) {
avcc = avcc[size:]
} else {
break
}
}
return &core.Codec{
Name: core.CodecH265,
ClockRate: 90000,
FmtpLine: buf.String(),
PayloadType: core.PayloadTypeRAW,
}
}
+19
View File
@@ -0,0 +1,19 @@
package h265
import (
"encoding/base64"
"testing"
"github.com/stretchr/testify/require"
)
func TestDecodeSPS(t *testing.T) {
s := "QgEBAWAAAAMAAAMAAAMAAAMAmaAAoAgBaH+KrTuiS7/8AAQABbAgApMuADN/mAE="
b, err := base64.StdEncoding.DecodeString(s)
require.Nil(t, err)
sps := DecodeSPS(b)
require.NotNil(t, sps)
require.Equal(t, uint16(5120), sps.Width())
require.Equal(t, uint16(1440), sps.Height())
}
+2 -1
View File
@@ -1,4 +1,5 @@
package hvc
// Package h265 - MPEG4 format related functions
package h265
import "encoding/binary"
+126
View File
@@ -0,0 +1,126 @@
package h265
import (
"bytes"
"github.com/AlexxIT/go2rtc/pkg/bits"
)
// http://www.itu.int/rec/T-REC-H.265
//goland:noinspection GoSnakeCaseUsage
type SPS struct {
sps_video_parameter_set_id uint8
sps_max_sub_layers_minus1 uint8
sps_temporal_id_nesting_flag byte
general_profile_space uint8
general_tier_flag byte
general_profile_idc uint8
general_profile_compatibility_flags uint32
general_level_idc uint8
sub_layer_profile_present_flag []byte
sub_layer_level_present_flag []byte
sps_seq_parameter_set_id uint32
chroma_format_idc uint32
separate_colour_plane_flag byte
pic_width_in_luma_samples uint32
pic_height_in_luma_samples uint32
}
func (s *SPS) Width() uint16 {
return uint16(s.pic_width_in_luma_samples)
}
func (s *SPS) Height() uint16 {
return uint16(s.pic_height_in_luma_samples)
}
func DecodeSPS(nalu []byte) *SPS {
rbsp := bytes.ReplaceAll(nalu[2:], []byte{0, 0, 3}, []byte{0, 0})
r := bits.NewReader(rbsp)
s := &SPS{}
s.sps_video_parameter_set_id = r.ReadBits8(4)
s.sps_max_sub_layers_minus1 = r.ReadBits8(3)
s.sps_temporal_id_nesting_flag = r.ReadBit()
if !s.profile_tier_level(r) {
return nil
}
s.sps_seq_parameter_set_id = r.ReadUEGolomb()
s.chroma_format_idc = r.ReadUEGolomb()
if s.chroma_format_idc == 3 {
s.separate_colour_plane_flag = r.ReadBit()
}
s.pic_width_in_luma_samples = r.ReadUEGolomb()
s.pic_height_in_luma_samples = r.ReadUEGolomb()
//...
if r.EOF {
return nil
}
return s
}
// profile_tier_level supports ONLY general_profile_idc == 1
// over variants very complicated...
//
//goland:noinspection GoSnakeCaseUsage
func (s *SPS) profile_tier_level(r *bits.Reader) bool {
s.general_profile_space = r.ReadBits8(2)
s.general_tier_flag = r.ReadBit()
s.general_profile_idc = r.ReadBits8(5)
s.general_profile_compatibility_flags = r.ReadBits(32)
_ = r.ReadBits64(48) // other flags
if s.general_profile_idc != 1 {
return false
}
s.general_level_idc = r.ReadBits8(8)
s.sub_layer_profile_present_flag = make([]byte, s.sps_max_sub_layers_minus1)
s.sub_layer_level_present_flag = make([]byte, s.sps_max_sub_layers_minus1)
for i := byte(0); i < s.sps_max_sub_layers_minus1; i++ {
s.sub_layer_profile_present_flag[i] = r.ReadBit()
s.sub_layer_level_present_flag[i] = r.ReadBit()
}
if s.sps_max_sub_layers_minus1 > 0 {
for i := s.sps_max_sub_layers_minus1; i < 8; i++ {
_ = r.ReadBits8(2) // reserved_zero_2bits
}
}
for i := byte(0); i < s.sps_max_sub_layers_minus1; i++ {
if s.sub_layer_profile_present_flag[i] != 0 {
_ = r.ReadBits8(2) // sub_layer_profile_space
_ = r.ReadBit() // sub_layer_tier_flag
sub_layer_profile_idc := r.ReadBits8(5) // sub_layer_profile_idc
_ = r.ReadBits(32) // sub_layer_profile_compatibility_flag
_ = r.ReadBits64(48) // other flags
if sub_layer_profile_idc != 1 {
return false
}
}
if s.sub_layer_level_present_flag[i] != 0 {
_ = r.ReadBits8(8)
}
}
return true
}
+2 -2
View File
@@ -12,7 +12,7 @@ import (
"time"
"github.com/AlexxIT/go2rtc/pkg/core"
"github.com/AlexxIT/go2rtc/pkg/h264/avc"
"github.com/AlexxIT/go2rtc/pkg/h264"
"github.com/AlexxIT/go2rtc/pkg/iso"
"github.com/gorilla/websocket"
"github.com/pion/rtp"
@@ -205,7 +205,7 @@ func (c *Client) getTracks() error {
avccLen := binary.BigEndian.Uint32(msg.Data[i:])
data = msg.Data[i+8 : i+int(avccLen)]
codec := avc.ConfigToCodec(data)
codec := h264.ConfigToCodec(data)
media := &core.Media{
Kind: core.KindVideo,
+2 -1
View File
@@ -3,6 +3,7 @@ package magic
import (
"github.com/AlexxIT/go2rtc/pkg/core"
"github.com/AlexxIT/go2rtc/pkg/h264"
"github.com/AlexxIT/go2rtc/pkg/h264/annexb"
"github.com/AlexxIT/go2rtc/pkg/h265"
"github.com/AlexxIT/go2rtc/pkg/mjpeg"
"github.com/pion/rtp"
@@ -42,7 +43,7 @@ func (k *Keyframe) AddTrack(media *core.Media, _ *core.Codec, track *core.Receiv
if !h264.IsKeyframe(packet.Payload) {
return
}
b := h264.AVCtoAnnexB(packet.Payload)
b := annexb.DecodeAVCC(packet.Payload)
k.Fire(b)
}
+1 -1
View File
@@ -86,7 +86,7 @@ func (c *Consumer) AddTrack(media *core.Media, _ *core.Codec, track *core.Receiv
if track.Codec.IsRTP() {
handler.Handler = h264.RTPDepay(track.Codec, handler.Handler)
} else {
handler.Handler = h264.RepairAVC(track.Codec, handler.Handler)
handler.Handler = h264.RepairAVCC(track.Codec, handler.Handler)
}
case core.CodecH265:
+4 -6
View File
@@ -6,9 +6,7 @@ import (
"github.com/AlexxIT/go2rtc/pkg/core"
"github.com/AlexxIT/go2rtc/pkg/h264"
"github.com/AlexxIT/go2rtc/pkg/h264/avc"
"github.com/AlexxIT/go2rtc/pkg/h265"
"github.com/AlexxIT/go2rtc/pkg/h265/hvc"
"github.com/AlexxIT/go2rtc/pkg/iso"
"github.com/pion/rtp"
)
@@ -74,13 +72,13 @@ func (m *Muxer) GetInit(codecs []*core.Codec) ([]byte, error) {
pps = []byte{0x68, 0xce, 0x38, 0x80}
}
s := avc.DecodeSPS(sps)
s := h264.DecodeSPS(sps)
if s == nil {
return nil, errors.New("mp4: can't parse SPS")
}
mv.WriteVideoTrack(
uint32(i+1), codec.Name, codec.ClockRate, s.Width(), s.Heigth(), avc.EncodeConfig(sps, pps),
uint32(i+1), codec.Name, codec.ClockRate, s.Width(), s.Height(), h264.EncodeConfig(sps, pps),
)
case core.CodecH265:
@@ -96,13 +94,13 @@ func (m *Muxer) GetInit(codecs []*core.Codec) ([]byte, error) {
pps = []byte{0x44, 0x01, 0xc0, 0x73, 0xc0, 0x4c, 0x90}
}
s := avc.DecodeSPS(sps)
s := h265.DecodeSPS(sps)
if s == nil {
return nil, errors.New("mp4: can't parse SPS")
}
mv.WriteVideoTrack(
uint32(i+1), codec.Name, codec.ClockRate, s.Width(), s.Heigth(), hvc.EncodeConfig(vps, sps, pps),
uint32(i+1), codec.Name, codec.ClockRate, s.Width(), s.Height(), h265.EncodeConfig(vps, sps, pps),
)
case core.CodecAAC:
+2 -1
View File
@@ -2,6 +2,7 @@ package mp4
import (
"encoding/json"
"github.com/AlexxIT/go2rtc/pkg/core"
"github.com/AlexxIT/go2rtc/pkg/h264"
"github.com/AlexxIT/go2rtc/pkg/h265"
@@ -101,7 +102,7 @@ func (c *Segment) AddTrack(media *core.Media, _ *core.Codec, track *core.Receive
if track.Codec.IsRTP() {
handler.Handler = h264.RTPDepay(track.Codec, handler.Handler)
} else {
handler.Handler = h264.RepairAVC(track.Codec, handler.Handler)
handler.Handler = h264.RepairAVCC(track.Codec, handler.Handler)
}
case core.CodecH265:
+4 -2
View File
@@ -1,11 +1,13 @@
package mpegts
import (
"time"
"github.com/AlexxIT/go2rtc/pkg/core"
"github.com/AlexxIT/go2rtc/pkg/h264"
"github.com/AlexxIT/go2rtc/pkg/h264/annexb"
"github.com/AlexxIT/go2rtc/pkg/h265"
"github.com/pion/rtp"
"time"
)
const (
@@ -113,7 +115,7 @@ func (p *PES) GetPacket() (pkt *rtp.Packet) {
PayloadType: p.StreamType,
Timestamp: ts,
},
Payload: h264.AnnexB2AVC(payload),
Payload: annexb.EncodeToAVCC(payload, false),
}
case StreamTypePCMATapo:
+1 -1
View File
@@ -118,7 +118,7 @@ func (c *Consumer) AddTrack(media *core.Media, _ *core.Codec, track *core.Receiv
if track.Codec.IsRTP() {
handler.Handler = h264.RTPDepay(track.Codec, handler.Handler)
} else {
handler.Handler = h264.RepairAVC(track.Codec, handler.Handler)
handler.Handler = h264.RepairAVCC(track.Codec, handler.Handler)
}
case core.CodecAAC:
+2 -2
View File
@@ -11,7 +11,7 @@ import (
"time"
"github.com/AlexxIT/go2rtc/pkg/core"
"github.com/AlexxIT/go2rtc/pkg/h264"
"github.com/AlexxIT/go2rtc/pkg/h264/annexb"
"github.com/pion/rtp"
)
@@ -103,7 +103,7 @@ func (c *Client) Handle() error {
Header: rtp.Header{
Timestamp: uint32(ts * 90000),
},
Payload: h264.AnnexB2AVC(body),
Payload: annexb.EncodeToAVCC(body, false),
}
video.WriteRTP(pkt)
}
+1 -1
View File
@@ -53,7 +53,7 @@ func (c *Conn) AddTrack(media *core.Media, codec *core.Codec, track *core.Receiv
if track.Codec.IsRTP() {
sender.Handler = h264.RTPDepay(track.Codec, sender.Handler)
} else {
sender.Handler = h264.RepairAVC(track.Codec, sender.Handler)
sender.Handler = h264.RepairAVCC(track.Codec, sender.Handler)
}
case core.CodecH265: