server: HW cleanup
This commit is contained in:
parent
fb3f589fd0
commit
084efc28da
4 changed files with 53 additions and 68 deletions
|
@ -35,7 +35,7 @@ fn set_frame_flags(frame: &mut ffmpeg::Frame, force_keyframe: bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_frame(
|
fn create_hardware_frame(
|
||||||
width: u32,
|
width: u32,
|
||||||
height: u32,
|
height: u32,
|
||||||
pixel_format: ffmpeg::format::Pixel,
|
pixel_format: ffmpeg::format::Pixel,
|
||||||
|
@ -90,7 +90,6 @@ fn encoder_thread_main(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
encoder = Some(H264Encoder::new_nvenc(
|
encoder = Some(H264Encoder::new_nvenc(
|
||||||
&dev,
|
&dev,
|
||||||
size.clone(),
|
size.clone(),
|
||||||
|
@ -98,13 +97,6 @@ fn encoder_thread_main(
|
||||||
5 * (1000 * 1000),
|
5 * (1000 * 1000),
|
||||||
)?);
|
)?);
|
||||||
|
|
||||||
|
|
||||||
let mut producer_frame_locked = frame.lock().expect("Couldn't lock producer frame");
|
|
||||||
let mut producer_frame = producer_frame_locked.as_mut().expect("NOOOO");
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
(*producer_frame.as_mut_ptr()).hw_frames_ctx = encoder.as_mut().unwrap().get_hw_context().as_raw_mut();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EncodeThreadInput::ForceKeyframe => {
|
EncodeThreadInput::ForceKeyframe => {
|
||||||
|
@ -126,7 +118,6 @@ fn encoder_thread_main(
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
(*producer_frame.as_mut_ptr()).pts = frame_number as i64;
|
(*producer_frame.as_mut_ptr()).pts = frame_number as i64;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if enc.is_hardware() {
|
if enc.is_hardware() {
|
||||||
|
|
|
@ -6,7 +6,6 @@ use ffmpeg::error::EAGAIN;
|
||||||
|
|
||||||
use ffmpeg::{codec as lavc, packet}; // lavc
|
use ffmpeg::{codec as lavc, packet}; // lavc
|
||||||
|
|
||||||
|
|
||||||
use crate::types::Size;
|
use crate::types::Size;
|
||||||
|
|
||||||
/// this is required for libx264 to like. Work
|
/// this is required for libx264 to like. Work
|
||||||
|
@ -37,12 +36,12 @@ fn create_context_and_set_common_parameters(
|
||||||
video_encoder_context.set_height(size.height);
|
video_encoder_context.set_height(size.height);
|
||||||
video_encoder_context.set_frame_rate(Some(ffmpeg::Rational(1, max_framerate as i32)));
|
video_encoder_context.set_frame_rate(Some(ffmpeg::Rational(1, max_framerate as i32)));
|
||||||
|
|
||||||
video_encoder_context.set_bit_rate(bitrate);
|
video_encoder_context.set_bit_rate(bitrate / 4);
|
||||||
//video_encoder_context.set_max_bit_rate(bitrate);
|
video_encoder_context.set_max_bit_rate(bitrate);
|
||||||
|
|
||||||
// qp TODO:
|
// qp TODO:
|
||||||
video_encoder_context.set_qmax(30);
|
//video_encoder_context.set_qmax(30);
|
||||||
video_encoder_context.set_qmin(35);
|
//video_encoder_context.set_qmin(35);
|
||||||
|
|
||||||
video_encoder_context.set_time_base(ffmpeg::Rational(1, max_framerate as i32).invert());
|
video_encoder_context.set_time_base(ffmpeg::Rational(1, max_framerate as i32).invert());
|
||||||
video_encoder_context.set_format(ffmpeg::format::Pixel::YUV420P);
|
video_encoder_context.set_format(ffmpeg::format::Pixel::YUV420P);
|
||||||
|
@ -71,7 +70,14 @@ pub enum H264Encoder {
|
||||||
|
|
||||||
Nvenc {
|
Nvenc {
|
||||||
encoder: ffmpeg::encoder::video::Encoder,
|
encoder: ffmpeg::encoder::video::Encoder,
|
||||||
hw_context: HwFrameContext,
|
// FIXME: This will be needed if the user wants to encode
|
||||||
|
// frames always stored in GPU memory. For now we let ffmpeg upload
|
||||||
|
// and download frames to the GPU, but at some point
|
||||||
|
// it would be a good idea to have, say,
|
||||||
|
// new_nvenc_hwframe(dev, ...)
|
||||||
|
// new_nvenc_cpuframe(...) (has the same behaviour as current new_nvenc)
|
||||||
|
|
||||||
|
//hw_context: HwFrameContext,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +117,6 @@ impl H264Encoder {
|
||||||
|
|
||||||
dict.set("forced-idr", "1");
|
dict.set("forced-idr", "1");
|
||||||
|
|
||||||
|
|
||||||
let encoder = video_encoder_context
|
let encoder = video_encoder_context
|
||||||
.open_as_with(encoder, dict)
|
.open_as_with(encoder, dict)
|
||||||
.with_context(|| "While opening x264 video codec")?;
|
.with_context(|| "While opening x264 video codec")?;
|
||||||
|
@ -124,33 +129,34 @@ impl H264Encoder {
|
||||||
cuda_device: &CudaDevice,
|
cuda_device: &CudaDevice,
|
||||||
size: Size,
|
size: Size,
|
||||||
max_framerate: u32,
|
max_framerate: u32,
|
||||||
bitrate: usize
|
bitrate: usize,
|
||||||
) -> anyhow::Result<Self> {
|
) -> anyhow::Result<Self> {
|
||||||
let (mut encoder, mut video_encoder_context) =
|
let (mut encoder, mut video_encoder_context) =
|
||||||
create_context_and_set_common_parameters("h264_nvenc", &size, max_framerate, bitrate)
|
create_context_and_set_common_parameters("h264_nvenc", &size, max_framerate, bitrate)
|
||||||
.with_context(|| "while trying to create encoder")?;
|
.with_context(|| "while trying to create encoder")?;
|
||||||
|
|
||||||
|
/*
|
||||||
|
(See FIXMEs above)
|
||||||
|
|
||||||
let cuda_device_context = super::hwdevice::CudaDeviceContextBuilder::new()?
|
let cuda_device_context = super::hwdevice::CudaDeviceContextBuilder::new()?
|
||||||
.set_cuda_context((*cuda_device.cu_primary_ctx()) as *mut _)
|
.set_cuda_context((*cuda_device.cu_primary_ctx()) as *mut _)
|
||||||
.build()
|
.build()
|
||||||
.with_context(|| "while trying to create CUDA device context")?;
|
.with_context(|| "while trying to create CUDA device context")?;
|
||||||
|
|
||||||
let mut hw_frame_context = super::hwframe::HwFrameContextBuilder::new(cuda_device_context)?
|
let mut hw_frame_context = super::hwframe::HwFrameContextBuilder::new(cuda_device_context)?
|
||||||
.set_width(size.width)
|
.set_width(size.width)
|
||||||
.set_height(size.height)
|
.set_height(size.height)
|
||||||
.set_sw_format(ffmpeg::format::Pixel::ZRGB32)
|
.set_sw_format(ffmpeg::format::Pixel::ZRGB32)
|
||||||
.set_format(ffmpeg::format::Pixel::CUDA)
|
.set_format(ffmpeg::format::Pixel::CUDA)
|
||||||
.build()
|
.build()
|
||||||
.with_context(|| "while trying to create CUDA frame context")?;
|
.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::ZRGB32);
|
video_encoder_context.set_format(ffmpeg::format::Pixel::ZRGB32);
|
||||||
|
|
||||||
unsafe {
|
video_encoder_context.set_qmin(38);
|
||||||
//(*video_encoder_context.as_mut_ptr()).hw_frames_ctx = hw_frame_context.as_raw_mut();
|
video_encoder_context.set_qmax(35);
|
||||||
//(*video_encoder_context.as_mut_ptr()).delay = 0;
|
|
||||||
//(*video_encoder_context.as_mut_ptr()).refs = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set h264_nvenc options
|
// set h264_nvenc options
|
||||||
let mut dict = ffmpeg::Dictionary::new();
|
let mut dict = ffmpeg::Dictionary::new();
|
||||||
|
@ -161,19 +167,20 @@ impl H264Encoder {
|
||||||
dict.set("profile", "main");
|
dict.set("profile", "main");
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
dict.set("crf", "43");
|
dict.set("rc", "vbr");
|
||||||
dict.set("crf_max", "48");
|
//dict.set("qp", "45");
|
||||||
|
|
||||||
dict.set("forced-idr", "1");
|
dict.set("forced-idr", "1");
|
||||||
|
|
||||||
// damn you
|
// damn you
|
||||||
dict.set("delay", "0");
|
dict.set("delay", "0");
|
||||||
|
dict.set("zerolatency", "1");
|
||||||
|
|
||||||
let encoder = video_encoder_context
|
let encoder = video_encoder_context
|
||||||
.open_as_with(encoder, dict)
|
.open_as_with(encoder, dict)
|
||||||
.with_context(|| "While opening h264_nvenc video codec")?;
|
.with_context(|| "While opening h264_nvenc video codec")?;
|
||||||
|
|
||||||
Ok(Self::Nvenc { encoder: encoder, hw_context: hw_frame_context })
|
Ok(Self::Nvenc { encoder: encoder })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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,
|
||||||
|
@ -185,12 +192,12 @@ impl H264Encoder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_hw_context(&mut self) -> &mut HwFrameContext {
|
//pub fn get_hw_context(&mut self) -> &mut HwFrameContext {
|
||||||
match self {
|
// match self {
|
||||||
Self::Nvenc { encoder: _, hw_context } => hw_context,
|
// Self::Nvenc { encoder: _, hw_context } => hw_context,
|
||||||
_ => panic!("should not use H264Encoder::get_hw_context() on a Software encoder")
|
// _ => panic!("should not use H264Encoder::get_hw_context() on a Software encoder")
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
||||||
pub fn send_frame(&mut self, frame: &ffmpeg::Frame) {
|
pub fn send_frame(&mut self, frame: &ffmpeg::Frame) {
|
||||||
match self {
|
match self {
|
||||||
|
@ -198,10 +205,7 @@ impl H264Encoder {
|
||||||
encoder.send_frame(frame).unwrap();
|
encoder.send_frame(frame).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::Nvenc {
|
Self::Nvenc { encoder } => {
|
||||||
encoder,
|
|
||||||
hw_context,
|
|
||||||
} => {
|
|
||||||
// Realistically this should be the same right?
|
// Realistically this should be the same right?
|
||||||
encoder.send_frame(frame).unwrap();
|
encoder.send_frame(frame).unwrap();
|
||||||
//todo!("Requires support.");
|
//todo!("Requires support.");
|
||||||
|
@ -215,13 +219,10 @@ impl H264Encoder {
|
||||||
encoder.send_eof().unwrap();
|
encoder.send_eof().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::Nvenc {
|
Self::Nvenc { encoder } => {
|
||||||
encoder,
|
|
||||||
hw_context,
|
|
||||||
} => {
|
|
||||||
// Realistically this should be the same right?
|
// Realistically this should be the same right?
|
||||||
encoder.send_eof().unwrap();
|
encoder.send_eof().unwrap();
|
||||||
// todo!("Requires support.");
|
// todo!("Requires support.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -230,14 +231,7 @@ impl H264Encoder {
|
||||||
return match self {
|
return match self {
|
||||||
Self::Software { encoder } => encoder.receive_packet(packet),
|
Self::Software { encoder } => encoder.receive_packet(packet),
|
||||||
|
|
||||||
Self::Nvenc {
|
Self::Nvenc { encoder } => encoder.receive_packet(packet),
|
||||||
encoder,
|
|
||||||
hw_context,
|
|
||||||
} => {
|
|
||||||
// Realistically this should be the same right?
|
|
||||||
encoder.receive_packet(packet)
|
|
||||||
//todo!("Requires support.");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ impl HwFrameContextBuilder {
|
||||||
pub fn new(mut cuda_device_context: CudaDeviceContext) -> anyhow::Result<Self> {
|
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(anyhow::anyhow!("could not allocate a hwframe"));
|
return Err(anyhow::anyhow!("could not allocate a hwframe context"));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self { cuda_device_context, buffer })
|
Ok(Self { cuda_device_context, buffer })
|
||||||
|
|
|
@ -2,7 +2,7 @@ pub mod encoder_thread;
|
||||||
pub mod h264_encoder;
|
pub mod h264_encoder;
|
||||||
//pub mod lc_muxer;
|
//pub mod lc_muxer;
|
||||||
|
|
||||||
/// Re-export of `ffmpeg_the_third` crate in an infinitely less obtuse name.
|
/// Re-export of `ffmpeg` crate.
|
||||||
pub use ffmpeg as ffmpeg;
|
pub use ffmpeg as ffmpeg;
|
||||||
|
|
||||||
pub mod hwdevice;
|
pub mod hwdevice;
|
||||||
|
|
Loading…
Reference in a new issue