Adds support WebRTC + H265 to Safari
This commit is contained in:
@@ -36,3 +36,4 @@ H.264/high | avc1.6400xx | FFmpeg superfast
|
|||||||
- [AVC levels](https://en.wikipedia.org/wiki/Advanced_Video_Coding#Levels)
|
- [AVC levels](https://en.wikipedia.org/wiki/Advanced_Video_Coding#Levels)
|
||||||
- [AVC profiles table](https://developer.mozilla.org/ru/docs/Web/Media/Formats/codecs_parameter)
|
- [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)
|
- [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/)
|
||||||
|
|||||||
+66
-4
@@ -21,10 +21,6 @@ func RTPDepay(track *streamer.Track) streamer.WrapperFunc {
|
|||||||
//)
|
//)
|
||||||
|
|
||||||
switch naluType {
|
switch naluType {
|
||||||
case h265parser.NAL_UNIT_CODED_SLICE_TRAIL_R:
|
|
||||||
case h265parser.NAL_UNIT_VPS:
|
|
||||||
case h265parser.NAL_UNIT_SPS:
|
|
||||||
case h265parser.NAL_UNIT_PPS:
|
|
||||||
case h265parser.NAL_UNIT_UNSPECIFIED_49:
|
case h265parser.NAL_UNIT_UNSPECIFIED_49:
|
||||||
data := packet.Payload
|
data := packet.Payload
|
||||||
switch data[2] >> 6 {
|
switch data[2] >> 6 {
|
||||||
@@ -55,3 +51,69 @@ func RTPDepay(track *streamer.Track) streamer.WrapperFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
switch nut {
|
||||||
|
case h265parser.NAL_UNIT_VPS, h265parser.NAL_UNIT_SPS, h265parser.NAL_UNIT_PPS:
|
||||||
|
buffer = append(buffer, data...)
|
||||||
|
return nil
|
||||||
|
case h265parser.NAL_UNIT_CODED_SLICE_IDR_W_RADL:
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -59,7 +59,6 @@ func (c *Conn) Init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("TODO: webrtc ontrack %+v\n", remote)
|
fmt.Printf("TODO: webrtc ontrack %+v\n", remote)
|
||||||
fmt.Printf("TODO: webrtc ontrack %#v\n", remote)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// OK connection:
|
// OK connection:
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package webrtc
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/AlexxIT/go2rtc/pkg/h264"
|
"github.com/AlexxIT/go2rtc/pkg/h264"
|
||||||
|
"github.com/AlexxIT/go2rtc/pkg/h265"
|
||||||
"github.com/AlexxIT/go2rtc/pkg/streamer"
|
"github.com/AlexxIT/go2rtc/pkg/streamer"
|
||||||
"github.com/pion/rtp"
|
"github.com/pion/rtp"
|
||||||
"github.com/pion/webrtc/v3"
|
"github.com/pion/webrtc/v3"
|
||||||
@@ -51,7 +52,8 @@ func (c *Conn) AddTrack(media *streamer.Media, track *streamer.Track) *streamer.
|
|||||||
return trackLocal.WriteRTP(packet)
|
return trackLocal.WriteRTP(packet)
|
||||||
}
|
}
|
||||||
|
|
||||||
if codec.Name == streamer.CodecH264 {
|
switch codec.Name {
|
||||||
|
case streamer.CodecH264:
|
||||||
wrapper := h264.RTPPay(1200)
|
wrapper := h264.RTPPay(1200)
|
||||||
push = wrapper(push)
|
push = wrapper(push)
|
||||||
|
|
||||||
@@ -61,6 +63,15 @@ func (c *Conn) AddTrack(media *streamer.Media, track *streamer.Track) *streamer.
|
|||||||
wrapper = h264.RTPDepay(track)
|
wrapper = h264.RTPDepay(track)
|
||||||
}
|
}
|
||||||
push = wrapper(push)
|
push = wrapper(push)
|
||||||
|
|
||||||
|
case streamer.CodecH265:
|
||||||
|
// SafariPay because it is the only browser in the world
|
||||||
|
// that supports WebRTC + H265
|
||||||
|
wrapper := h265.SafariPay(1200)
|
||||||
|
push = wrapper(push)
|
||||||
|
|
||||||
|
wrapper = h265.RTPDepay(track)
|
||||||
|
push = wrapper(push)
|
||||||
}
|
}
|
||||||
|
|
||||||
track = track.Bind(push)
|
track = track.Bind(push)
|
||||||
Reference in New Issue
Block a user