Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

H265 support #117

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 22 additions & 36 deletions server/internal/gst/gst.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ func CreateRTMPPipeline(pipelineDevice string, pipelineDisplay string, pipelineS
func CreateAppPipeline(codecName string, pipelineDevice string, pipelineSrc string, fps int, bitrate uint) (*Pipeline, error) {
pipelineStr := " ! appsink name=appsink"

// if using custom pipeline
if pipelineSrc != "" {
pipelineStr = fmt.Sprintf(pipelineSrc+pipelineStr, pipelineDevice)
return CreatePipeline(pipelineStr)
}

switch codecName {
case "VP8":
// https://gstreamer.freedesktop.org/documentation/vpx/vp8enc.html?gi-language=c
Expand All @@ -91,11 +97,7 @@ func CreateAppPipeline(codecName string, pipelineDevice string, pipelineSrc stri
return nil, err
}

if pipelineSrc != "" {
pipelineStr = fmt.Sprintf(pipelineSrc+pipelineStr, pipelineDevice)
} else {
pipelineStr = fmt.Sprintf(videoSrc+"vp8enc target-bitrate=%d cpu-used=4 end-usage=cbr threads=4 deadline=1 undershoot=95 buffer-size=%d buffer-initial-size=%d buffer-optimal-size=%d keyframe-max-dist=180 min-quantizer=3 max-quantizer=40"+pipelineStr, pipelineDevice, fps, bitrate*1000, bitrate*6, bitrate*4, bitrate*5)
}
pipelineStr = fmt.Sprintf(videoSrc+"vp8enc target-bitrate=%d cpu-used=4 end-usage=cbr threads=4 deadline=1 undershoot=95 buffer-size=%d buffer-initial-size=%d buffer-optimal-size=%d keyframe-max-dist=180 min-quantizer=3 max-quantizer=40"+pipelineStr, pipelineDevice, fps, bitrate*1000, bitrate*6, bitrate*4, bitrate*5)
case "VP9":
// https://gstreamer.freedesktop.org/documentation/vpx/vp9enc.html?gi-language=c
// gstreamer1.0-plugins-good
Expand All @@ -104,22 +106,12 @@ func CreateAppPipeline(codecName string, pipelineDevice string, pipelineSrc stri
return nil, err
}

// Causes panic! not sure why...
if pipelineSrc != "" {
pipelineStr = fmt.Sprintf(pipelineSrc+pipelineStr, pipelineDevice)
} else {
pipelineStr = fmt.Sprintf(videoSrc+"vp9enc target-bitrate=%d cpu-used=-5 threads=4 deadline=1 keyframe-max-dist=30 auto-alt-ref=true"+pipelineStr, pipelineDevice, fps, bitrate*1000)
}
pipelineStr = fmt.Sprintf(videoSrc+"vp9enc target-bitrate=%d cpu-used=-5 threads=4 deadline=1 keyframe-max-dist=30 auto-alt-ref=true"+pipelineStr, pipelineDevice, fps, bitrate*1000)
case "H264":
if err := CheckPlugins([]string{"ximagesrc"}); err != nil {
return nil, err
}

if pipelineSrc != "" {
pipelineStr = fmt.Sprintf(pipelineSrc+pipelineStr, pipelineDevice)
break
}

// https://gstreamer.freedesktop.org/documentation/openh264/openh264enc.html?gi-language=c#openh264enc
// gstreamer1.0-plugins-bad
// openh264enc multi-thread=4 complexity=high bitrate=3072000 max-bitrate=4096000
Expand All @@ -139,7 +131,17 @@ func CreateAppPipeline(codecName string, pipelineDevice string, pipelineSrc stri
if bitrate > 1000 {
vbvbuf = bitrate
}

pipelineStr = fmt.Sprintf(videoSrc+"video/x-raw,format=NV12 ! x264enc threads=4 bitrate=%d key-int-max=60 vbv-buf-capacity=%d byte-stream=true tune=zerolatency speed-preset=veryfast ! video/x-h264,stream-format=byte-stream"+pipelineStr, pipelineDevice, fps, bitrate, vbvbuf)
case "H265":
// https://gstreamer.freedesktop.org/documentation/vpx/vp9enc.html?gi-language=c
// gstreamer1.0-plugins-good
// vp9enc
if err := CheckPlugins([]string{"ximagesrc", "x265"}); err != nil {
return nil, err
}

pipelineStr = fmt.Sprintf(videoSrc+"x265enc bitrate=%d key-int-max=60 tune=zerolatency speed-preset=veryfast ! video/x-h265,stream-format=byte-stream"+pipelineStr, pipelineDevice, fps, bitrate)
case "Opus":
// https://gstreamer.freedesktop.org/documentation/opus/opusenc.html
// gstreamer1.0-plugins-base
Expand All @@ -148,11 +150,7 @@ func CreateAppPipeline(codecName string, pipelineDevice string, pipelineSrc stri
return nil, err
}

if pipelineSrc != "" {
pipelineStr = fmt.Sprintf(pipelineSrc+pipelineStr, pipelineDevice)
} else {
pipelineStr = fmt.Sprintf(audioSrc+"opusenc bitrate=%d"+pipelineStr, pipelineDevice, bitrate*1000)
}
pipelineStr = fmt.Sprintf(audioSrc+"opusenc bitrate=%d"+pipelineStr, pipelineDevice, bitrate*1000)
case "G722":
// https://gstreamer.freedesktop.org/documentation/libav/avenc_g722.html?gi-language=c
// gstreamer1.0-libav
Expand All @@ -161,11 +159,7 @@ func CreateAppPipeline(codecName string, pipelineDevice string, pipelineSrc stri
return nil, err
}

if pipelineSrc != "" {
pipelineStr = fmt.Sprintf(pipelineSrc+pipelineStr, pipelineDevice)
} else {
pipelineStr = fmt.Sprintf(audioSrc+"avenc_g722 bitrate=%d"+pipelineStr, pipelineDevice, bitrate*1000)
}
pipelineStr = fmt.Sprintf(audioSrc+"avenc_g722 bitrate=%d"+pipelineStr, pipelineDevice, bitrate*1000)
case "PCMU":
// https://gstreamer.freedesktop.org/documentation/mulaw/mulawenc.html?gi-language=c
// gstreamer1.0-plugins-good
Expand All @@ -174,11 +168,7 @@ func CreateAppPipeline(codecName string, pipelineDevice string, pipelineSrc stri
return nil, err
}

if pipelineSrc != "" {
pipelineStr = fmt.Sprintf(pipelineSrc+pipelineStr, pipelineDevice)
} else {
pipelineStr = fmt.Sprintf(audioSrc+"audio/x-raw, rate=8000 ! mulawenc"+pipelineStr, pipelineDevice)
}
pipelineStr = fmt.Sprintf(audioSrc+"audio/x-raw, rate=8000 ! mulawenc"+pipelineStr, pipelineDevice)
case "PCMA":
// https://gstreamer.freedesktop.org/documentation/alaw/alawenc.html?gi-language=c
// gstreamer1.0-plugins-good
Expand All @@ -187,11 +177,7 @@ func CreateAppPipeline(codecName string, pipelineDevice string, pipelineSrc stri
return nil, err
}

if pipelineSrc != "" {
pipelineStr = fmt.Sprintf(pipelineSrc+pipelineStr, pipelineDevice)
} else {
pipelineStr = fmt.Sprintf(audioSrc+"audio/x-raw, rate=8000 ! alawenc"+pipelineStr, pipelineDevice)
}
pipelineStr = fmt.Sprintf(audioSrc+"audio/x-raw, rate=8000 ! alawenc"+pipelineStr, pipelineDevice)
default:
return nil, fmt.Errorf("unknown codec %s", codecName)
}
Expand Down
7 changes: 7 additions & 0 deletions server/internal/types/config/remote.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ func (Remote) Init(cmd *cobra.Command) error {
return err
}

cmd.PersistentFlags().Bool("h265", false, "use H265 video codec")
if err := viper.BindPFlag("h265", cmd.PersistentFlags().Lookup("h265")); err != nil {
return err
}

// audio codecs
cmd.PersistentFlags().Bool("opus", false, "use Opus audio codec")
if err := viper.BindPFlag("opus", cmd.PersistentFlags().Lookup("opus")); err != nil {
Expand Down Expand Up @@ -112,6 +117,8 @@ func (s *Remote) Set() {
videoCodec = "VP9"
} else if viper.GetBool("h264") {
videoCodec = "H264"
} else if viper.GetBool("h265") {
videoCodec = "H265"
}

audioCodec := "Opus"
Expand Down
4 changes: 4 additions & 0 deletions server/internal/webrtc/webrtc.go
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,10 @@ func (manager *WebRTCManager) createTrack(codecName string) (*webrtc.TrackLocalS
case "H264":
codec = webrtc.RTPCodecParameters{RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeH264, ClockRate: 90000, Channels: 0, SDPFmtpLine: "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f", RTCPFeedback: fb}, PayloadType: 102}
id = "video"
case "H265":
// TODO: Fix this (correct payload type and SDPFmtpLine if needed).
codec = webrtc.RTPCodecParameters{RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: "video/H265", ClockRate: 90000, Channels: 0, SDPFmtpLine: "", RTCPFeedback: fb}, PayloadType: 0}
id = "video"
case "Opus":
codec = webrtc.RTPCodecParameters{RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeOpus, ClockRate: 48000, Channels: 2, SDPFmtpLine: "", RTCPFeedback: fb}, PayloadType: 111}
id = "audio"
Expand Down