154 lines
3.8 KiB
Go
154 lines
3.8 KiB
Go
package h265
|
|
|
|
import (
|
|
"github.com/AlexxIT/go2rtc/pkg/h264"
|
|
"github.com/AlexxIT/go2rtc/pkg/streamer"
|
|
"github.com/deepch/vdk/codec/h265parser"
|
|
"github.com/pion/rtp"
|
|
)
|
|
|
|
func RTPDepay(track *streamer.Track) streamer.WrapperFunc {
|
|
vps, sps, pps := GetParameterSet(track.Codec.FmtpLine)
|
|
|
|
var buffer []byte
|
|
|
|
return func(push streamer.WriterFunc) streamer.WriterFunc {
|
|
return func(packet *rtp.Packet) error {
|
|
nut := (packet.Payload[0] >> 1) & 0x3f
|
|
//fmt.Printf(
|
|
// "[RTP] codec: %s, nalu: %2d, size: %6d, ts: %10d, pt: %2d, ssrc: %d, seq: %d\n",
|
|
// track.Codec.Name, nut, len(packet.Payload), packet.Timestamp,
|
|
// packet.PayloadType, packet.SSRC, packet.SequenceNumber,
|
|
//)
|
|
|
|
switch nut {
|
|
case h265parser.NAL_UNIT_UNSPECIFIED_49:
|
|
data := packet.Payload
|
|
switch data[2] >> 6 {
|
|
case 2: // begin
|
|
buffer = []byte{
|
|
(data[0] & 0x81) | (data[2] & 0x3f << 1), data[1],
|
|
}
|
|
buffer = append(buffer, data[3:]...)
|
|
return nil
|
|
case 0: // continue
|
|
buffer = append(buffer, data[3:]...)
|
|
return nil
|
|
case 1: // end
|
|
packet.Payload = append(buffer, data[3:]...)
|
|
}
|
|
case h265parser.NAL_UNIT_VPS:
|
|
vps = packet.Payload
|
|
return nil
|
|
case h265parser.NAL_UNIT_SPS:
|
|
sps = packet.Payload
|
|
return nil
|
|
case h265parser.NAL_UNIT_PPS:
|
|
pps = packet.Payload
|
|
return nil
|
|
default:
|
|
//panic("not implemented")
|
|
}
|
|
|
|
var clone rtp.Packet
|
|
|
|
nut = (packet.Payload[0] >> 1) & 0x3f
|
|
if nut >= h265parser.NAL_UNIT_CODED_SLICE_BLA_W_LP && nut <= h265parser.NAL_UNIT_CODED_SLICE_CRA {
|
|
clone = *packet
|
|
clone.Version = h264.RTPPacketVersionAVC
|
|
clone.Payload = h264.EncodeAVC(vps)
|
|
if err := push(&clone); err != nil {
|
|
return err
|
|
}
|
|
|
|
clone = *packet
|
|
clone.Version = h264.RTPPacketVersionAVC
|
|
clone.Payload = h264.EncodeAVC(sps)
|
|
if err := push(&clone); err != nil {
|
|
return err
|
|
}
|
|
|
|
clone = *packet
|
|
clone.Version = h264.RTPPacketVersionAVC
|
|
clone.Payload = h264.EncodeAVC(pps)
|
|
if err := push(&clone); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
clone = *packet
|
|
clone.Version = h264.RTPPacketVersionAVC
|
|
clone.Payload = h264.EncodeAVC(packet.Payload)
|
|
|
|
return push(&clone)
|
|
}
|
|
}
|
|
}
|
|
|
|
// SafariPay - generate Safari friendly payload for H265
|
|
func SafariPay(mtu uint16) streamer.WrapperFunc {
|
|
sequencer := rtp.NewRandomSequencer()
|
|
size := int(mtu - 12) // rtp.Header size
|
|
|
|
var buffer []byte
|
|
|
|
return func(push streamer.WriterFunc) streamer.WriterFunc {
|
|
return func(packet *rtp.Packet) error {
|
|
if packet.Version != h264.RTPPacketVersionAVC {
|
|
return push(packet)
|
|
}
|
|
|
|
data := packet.Payload
|
|
data[0] = 0
|
|
data[1] = 0
|
|
data[2] = 0
|
|
data[3] = 1
|
|
|
|
var start byte
|
|
|
|
nut := (data[4] >> 1) & 0b111111
|
|
//fmt.Printf("[H265] nut: %2d, size: %6d, data: %16x\n", nut, len(data), data[4:20])
|
|
switch {
|
|
case nut >= h265parser.NAL_UNIT_VPS && nut <= h265parser.NAL_UNIT_PPS:
|
|
buffer = append(buffer, data...)
|
|
return nil
|
|
case nut >= h265parser.NAL_UNIT_CODED_SLICE_BLA_W_LP && nut <= h265parser.NAL_UNIT_CODED_SLICE_CRA:
|
|
buffer = append([]byte{3}, buffer...)
|
|
data = append(buffer, data...)
|
|
start = 1
|
|
default:
|
|
data = append([]byte{2}, data...)
|
|
start = 0
|
|
}
|
|
|
|
for len(data) > size {
|
|
clone := rtp.Packet{
|
|
Header: rtp.Header{
|
|
Version: 2,
|
|
Marker: false,
|
|
SequenceNumber: sequencer.NextSequenceNumber(),
|
|
Timestamp: packet.Timestamp,
|
|
},
|
|
Payload: data[:size],
|
|
}
|
|
if err := push(&clone); err != nil {
|
|
return err
|
|
}
|
|
|
|
data = append([]byte{start}, data[size:]...)
|
|
}
|
|
|
|
clone := rtp.Packet{
|
|
Header: rtp.Header{
|
|
Version: 2,
|
|
Marker: true,
|
|
SequenceNumber: sequencer.NextSequenceNumber(),
|
|
Timestamp: packet.Timestamp,
|
|
},
|
|
Payload: data,
|
|
}
|
|
return push(&clone)
|
|
}
|
|
}
|
|
}
|