server/video: hook up new ctor for nvenc
This commit is contained in:
parent
a901365656
commit
807ce84be7
5 changed files with 68 additions and 10 deletions
|
@ -23,7 +23,7 @@ ffmpeg = { version = "7.0.0", package = "ffmpeg-next" }
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
serde = "1.0.209"
|
serde = "1.0.209"
|
||||||
serde_json = "1.0.128"
|
serde_json = "1.0.128"
|
||||||
cudarc = "0.12.1"
|
cudarc = { version = "0.12.1", features = [ "cuda-11050" ] }
|
||||||
|
|
||||||
|
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
|
|
|
@ -76,6 +76,7 @@ fn encoder_thread_main(
|
||||||
let mut sws = None;
|
let mut sws = None;
|
||||||
|
|
||||||
let mut yuv_frame = None;
|
let mut yuv_frame = None;
|
||||||
|
//let mut hw_frame = None;
|
||||||
|
|
||||||
let mut frame_number = 0usize;
|
let mut frame_number = 0usize;
|
||||||
let mut force_keyframe = false;
|
let mut force_keyframe = false;
|
||||||
|
@ -140,10 +141,15 @@ fn encoder_thread_main(
|
||||||
(*mut_yuv_frame.as_mut_ptr()).pts = frame_number as i64;
|
(*mut_yuv_frame.as_mut_ptr()).pts = frame_number as i64;
|
||||||
}
|
}
|
||||||
|
|
||||||
enc.send_frame(mut_yuv_frame);
|
if enc.is_hardware() {
|
||||||
|
|
||||||
enc.receive_packet(&mut packet)
|
} else {
|
||||||
.expect("failed to recv packet");
|
|
||||||
|
enc.send_frame(mut_yuv_frame);
|
||||||
|
|
||||||
|
enc.receive_packet(&mut packet)
|
||||||
|
.expect("failed to recv packet");
|
||||||
|
}
|
||||||
|
|
||||||
// If a packet was recieved dump it
|
// If a packet was recieved dump it
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use super::ffmpeg;
|
use super::ffmpeg;
|
||||||
use super::hwframe::HwFrameContext;
|
use super::hwframe::HwFrameContext;
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
|
use cudarc::driver::CudaDevice;
|
||||||
use ffmpeg::error::EAGAIN;
|
use ffmpeg::error::EAGAIN;
|
||||||
|
|
||||||
use ffmpeg::{codec as lavc, packet}; // lavc
|
use ffmpeg::{codec as lavc, packet}; // lavc
|
||||||
|
@ -22,7 +23,7 @@ pub fn create_context_from_codec(codec: ffmpeg::Codec) -> Result<lavc::Context,
|
||||||
|
|
||||||
fn create_context_and_set_common_parameters(
|
fn create_context_and_set_common_parameters(
|
||||||
codec: &str,
|
codec: &str,
|
||||||
size: Size,
|
size: &Size,
|
||||||
max_framerate: u32,
|
max_framerate: u32,
|
||||||
bitrate: usize,
|
bitrate: usize,
|
||||||
) -> anyhow::Result<(ffmpeg::Codec, ffmpeg::encoder::video::Video)> {
|
) -> anyhow::Result<(ffmpeg::Codec, ffmpeg::encoder::video::Video)> {
|
||||||
|
@ -77,7 +78,7 @@ impl H264Encoder {
|
||||||
pub fn new_software(size: Size, max_framerate: u32, bitrate: usize) -> anyhow::Result<Self> {
|
pub fn new_software(size: Size, max_framerate: u32, bitrate: usize) -> anyhow::Result<Self> {
|
||||||
// Create the libx264 context
|
// Create the libx264 context
|
||||||
let (encoder, mut video_encoder_context) =
|
let (encoder, mut video_encoder_context) =
|
||||||
create_context_and_set_common_parameters("libx264", size, max_framerate, bitrate)?;
|
create_context_and_set_common_parameters("libx264", &size, max_framerate, bitrate)?;
|
||||||
|
|
||||||
video_encoder_context.set_format(ffmpeg::format::Pixel::YUV420P);
|
video_encoder_context.set_format(ffmpeg::format::Pixel::YUV420P);
|
||||||
|
|
||||||
|
@ -116,6 +117,57 @@ impl H264Encoder {
|
||||||
Ok(Self::Software { encoder: encoder })
|
Ok(Self::Software { encoder: encoder })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new hardware encoder.
|
||||||
|
pub fn new_nvenc(
|
||||||
|
cuda_device: &CudaDevice,
|
||||||
|
size: Size,
|
||||||
|
max_framerate: u32,
|
||||||
|
bitrate: usize
|
||||||
|
) -> anyhow::Result<Self> {
|
||||||
|
let (mut encoder, mut video_encoder_context) =
|
||||||
|
create_context_and_set_common_parameters("h264_nvenc", &size, max_framerate, bitrate)
|
||||||
|
.with_context(|| "while trying to create encoder")?;
|
||||||
|
|
||||||
|
let cuda_device_context = super::hwdevice::CudaDeviceContextBuilder::new()?
|
||||||
|
.set_cuda_context((*cuda_device.cu_primary_ctx()) as *mut _)
|
||||||
|
.build()
|
||||||
|
.with_context(|| "while trying to create CUDA device context")?;
|
||||||
|
|
||||||
|
let mut hw_frame_context = super::hwframe::HwFrameContextBuilder::new(cuda_device_context)?
|
||||||
|
.set_width(size.width)
|
||||||
|
.set_height(size.height)
|
||||||
|
.set_sw_format(ffmpeg::format::Pixel::YUV420P)
|
||||||
|
.set_format(ffmpeg::format::Pixel::CUDA)
|
||||||
|
.build()
|
||||||
|
.with_context(|| "while trying to create CUDA frame context")?;
|
||||||
|
|
||||||
|
// lol you do not need unsafe code to set this my guy.
|
||||||
|
video_encoder_context.set_format(ffmpeg::format::Pixel::CUDA);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
(*video_encoder_context.as_mut_ptr()).hw_frames_ctx = hw_frame_context.as_raw_mut();
|
||||||
|
(*video_encoder_context.as_mut_ptr()).delay = 0;
|
||||||
|
(*video_encoder_context.as_mut_ptr()).refs = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set h264_nvenc options
|
||||||
|
let mut dict = ffmpeg::Dictionary::new();
|
||||||
|
|
||||||
|
dict.set("profile", "main");
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
dict.set("crf", "43");
|
||||||
|
dict.set("crf_max", "48");
|
||||||
|
|
||||||
|
dict.set("forced-idr", "1");
|
||||||
|
|
||||||
|
let encoder = video_encoder_context
|
||||||
|
.open_as_with(encoder, dict)
|
||||||
|
.with_context(|| "While opening h264_nvenc video codec")?;
|
||||||
|
|
||||||
|
Ok(Self::Nvenc { encoder: encoder, hw_context: hw_frame_context })
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: It's a bit pointless to have this have a mut borrow,
|
// FIXME: It's a bit pointless to have this have a mut borrow,
|
||||||
// but you'll probably have a mutable borrow on this already..
|
// but you'll probably have a mutable borrow on this already..
|
||||||
pub fn is_hardware(&mut self) -> bool {
|
pub fn is_hardware(&mut self) -> bool {
|
||||||
|
|
|
@ -35,10 +35,10 @@ pub struct CudaDeviceContextBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CudaDeviceContextBuilder {
|
impl CudaDeviceContextBuilder {
|
||||||
pub fn new() -> Result<Self, String> {
|
pub fn new() -> anyhow::Result<Self> {
|
||||||
let buffer = unsafe { ffmpeg::sys::av_hwdevice_ctx_alloc(ffmpeg::sys::AVHWDeviceType::AV_HWDEVICE_TYPE_CUDA) };
|
let buffer = unsafe { ffmpeg::sys::av_hwdevice_ctx_alloc(ffmpeg::sys::AVHWDeviceType::AV_HWDEVICE_TYPE_CUDA) };
|
||||||
if buffer.is_null() {
|
if buffer.is_null() {
|
||||||
return Err("could not allocate a hwdevice".to_string());
|
return Err(anyhow::anyhow!("could not allocate a hwdevice".to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self { buffer })
|
Ok(Self { buffer })
|
||||||
|
|
|
@ -41,10 +41,10 @@ pub struct HwFrameContextBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HwFrameContextBuilder {
|
impl HwFrameContextBuilder {
|
||||||
pub fn new(mut cuda_device_context: CudaDeviceContext) -> Result<Self, String> {
|
pub fn new(mut cuda_device_context: CudaDeviceContext) -> anyhow::Result<Self> {
|
||||||
let buffer = unsafe { ffmpeg::sys::av_hwframe_ctx_alloc(cuda_device_context.as_raw_mut()) };
|
let buffer = unsafe { ffmpeg::sys::av_hwframe_ctx_alloc(cuda_device_context.as_raw_mut()) };
|
||||||
if buffer.is_null() {
|
if buffer.is_null() {
|
||||||
return Err("could not allocate a hwframe".to_string());
|
return Err(anyhow::anyhow!("could not allocate a hwframe"));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self { cuda_device_context, buffer })
|
Ok(Self { cuda_device_context, buffer })
|
||||||
|
|
Loading…
Reference in a new issue