hw: add draft rockchip-mpp hw video encoding

This commit is contained in:
Artem
2024-11-19 22:08:12 +01:00
parent c5f77df6b0
commit fc2273d40b
9 changed files with 429 additions and 32 deletions

View File

@@ -5,7 +5,6 @@ import (
"rkkvm/external/ffmpeg"
"rkkvm/http/middleware"
"rkkvm/http/reqrsp"
"time"
"github.com/gin-gonic/gin"
log "github.com/sirupsen/logrus"
@@ -71,14 +70,14 @@ func SetScreen(c *gin.Context) {
})
return
}
log.Debug("Stopping ffmpeg SetScreen")
ffmpeg.Stop()
time.Sleep(100 * time.Millisecond)
ffmpeg.ApplyOptions()
log.Debug("Starting ffmpeg SetScreen")
ffmpeg.Start()
/*
log.Debug("Stopping ffmpeg SetScreen")
ffmpeg.Stop()
time.Sleep(100 * time.Millisecond)
ffmpeg.ApplyOptions()
log.Debug("Starting ffmpeg SetScreen")
ffmpeg.Start()
*/
log.Debugf("update screen: %+v", req)
c.JSON(http.StatusOK, reqrsp.NanoKVMRsp{
Msg: reqrsp.MsgSuccess,

View File

@@ -26,11 +26,6 @@ func initUDPListener(host string, port int) (*net.UDPConn, error) {
}
func InitListener(host string, port int, aPort int) (*RTC, error) {
vl, err := initUDPListener(host, port)
if err != nil {
return nil, err
}
al, err := initUDPListener(host, aPort)
if err != nil {
return nil, err
@@ -40,16 +35,13 @@ func InitListener(host string, port int, aPort int) (*RTC, error) {
switch config.Get().Video.Codec {
case config.StreamSourceH264:
mimeType = webrtc.MimeTypeH264
case config.StreamSourceHevc: // WebRTC currently has no official support for H265
mimeType = webrtc.MimeTypeH265
default:
return nil, ErrWebRTCParam("unknown video codec: %s", config.Get().Video.Codec)
}
video, _ := webrtc.NewTrackLocalStaticRTP(webrtc.RTPCodecCapability{MimeType: mimeType}, "video", "rkkvm")
video, _ := webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{MimeType: mimeType}, "video", "rkkvm")
audio, _ := webrtc.NewTrackLocalStaticRTP(webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeOpus}, "audio", "rkkvm")
rtc = &RTC{
videoListener: vl,
audioListener: al,
peers: make(map[string]*webrtc.PeerConnection),
videoTrack: video,

View File

@@ -4,13 +4,15 @@ import (
"errors"
"fmt"
"net"
"rkkvm/external/ffmpeg"
"rkkvm/external/mpp"
"sync"
"time"
"github.com/google/uuid"
log "github.com/sirupsen/logrus"
"github.com/pion/webrtc/v4"
"github.com/pion/webrtc/v4/pkg/media"
)
var rtc *RTC
@@ -27,9 +29,8 @@ var ErrPeerClosedConn = ErrWebRTCParam("peer closed conn")
type RTC struct {
peers map[string]*webrtc.PeerConnection
videoListener *net.UDPConn
audioListener *net.UDPConn
videoTrack *webrtc.TrackLocalStaticRTP
videoTrack *webrtc.TrackLocalStaticSample
audioTrack *webrtc.TrackLocalStaticRTP
m sync.Mutex
}
@@ -38,10 +39,10 @@ func (r *RTC) AddPeer(p *webrtc.PeerConnection, offer webrtc.SessionDescription)
peerID := uuid.New().String()
r.m.Lock()
r.peers[peerID] = p
if len(r.peers) == 1 {
/*if len(r.peers) == 1 {
ffmpeg.GetFFmpeg().Start()
log.Info("FFmpeg process started")
}
}*/
r.m.Unlock()
p.OnConnectionStateChange(func(connState webrtc.PeerConnectionState) {
@@ -49,10 +50,10 @@ func (r *RTC) AddPeer(p *webrtc.PeerConnection, offer webrtc.SessionDescription)
r.m.Lock()
defer r.m.Unlock()
delete(r.peers, peerID)
if len(r.peers) == 0 {
/*if len(r.peers) == 0 {
ffmpeg.GetFFmpeg().Stop()
log.Info("No clients anymore, stop ffmpeg process")
}
}*/
p.Close()
peers := make([]string, 0, len(r.peers))
@@ -93,7 +94,42 @@ func (r *RTC) AddPeer(p *webrtc.PeerConnection, offer webrtc.SessionDescription)
}
func (r *RTC) VideoListenerRead() {
listenerRead(r.videoListener, r.videoTrack)
duration := time.Second / time.Duration(60)
ticker := time.NewTicker(duration)
defer ticker.Stop()
// Retrieve SPS and PPS once at the start
sps, err := mpp.GetSPS()
if err != nil {
log.Fatalf("Failed to retrieve SPS: %v", err)
}
firstFrame := true
for {
select {
case <-ticker.C:
frame, err := mpp.GetInstance().CaptureAndEncode()
if err != nil {
log.Errorf("failed to capture frame: %v", err)
continue
}
// If this is the first frame or an IDR frame, prepend SPS and PPS
if firstFrame || isIDRFrame(frame) {
firstFrame = false
frame = append(sps, frame...)
}
sample := media.Sample{
Data: frame,
Duration: duration,
}
err = r.videoTrack.WriteSample(sample)
if err != nil {
log.Errorf("failed to write sample: %v", err)
}
}
}
}
func (r *RTC) AudioListenerRead() {
@@ -101,7 +137,6 @@ func (r *RTC) AudioListenerRead() {
}
func (r *RTC) Close() error {
r.videoListener.Close()
r.audioListener.Close()
return nil
@@ -146,3 +181,16 @@ func processRTCP(rtpSender *webrtc.RTPSender) {
}
}()
}
func isIDRFrame(frame []byte) bool {
// Check for NAL unit type 5 (IDR)
for i := 0; i < len(frame)-4; i++ {
if frame[i] == 0x00 && frame[i+1] == 0x00 && frame[i+2] == 0x00 && frame[i+3] == 0x01 {
nalType := frame[i+4] & 0x1F
if nalType == 5 { // IDR frame
return true
}
}
}
return false
}