ffmpeg-rs-raw/src/decode.rs

282 lines
9.1 KiB
Rust
Raw Normal View History

2024-11-11 14:10:03 +00:00
use crate::{bail_ffmpeg, options_to_dict, rstr, StreamInfo};
2024-11-07 12:48:48 +00:00
use std::collections::hash_map::Entry;
2024-11-05 10:59:12 +00:00
use std::collections::{HashMap, HashSet};
use std::fmt::{Display, Formatter};
2024-10-23 14:48:03 +01:00
use std::ptr;
use anyhow::Error;
use ffmpeg_sys_the_third::{
2024-11-18 12:19:14 +00:00
av_buffer_ref, av_frame_alloc, av_frame_free, av_hwdevice_ctx_create,
av_hwdevice_get_type_name, av_hwdevice_iterate_types, avcodec_alloc_context3,
avcodec_find_decoder, avcodec_free_context, avcodec_get_hw_config, avcodec_get_name,
avcodec_open2, avcodec_parameters_to_context, avcodec_receive_frame, avcodec_send_packet,
AVCodec, AVCodecContext, AVCodecHWConfig, AVFrame, AVHWDeviceType, AVPacket, AVStream, AVERROR,
AVERROR_EOF, AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX,
2024-10-23 14:48:03 +01:00
};
2024-11-07 12:48:48 +00:00
use log::trace;
2024-10-23 14:48:03 +01:00
2024-10-24 12:26:52 +01:00
pub struct DecoderCodecContext {
2024-10-23 14:48:03 +01:00
pub context: *mut AVCodecContext,
pub codec: *const AVCodec,
2024-11-06 15:47:54 +00:00
pub stream: *mut AVStream,
2024-11-05 10:59:12 +00:00
pub hw_config: *const AVCodecHWConfig,
2024-10-23 14:48:03 +01:00
}
2024-10-24 12:26:52 +01:00
impl DecoderCodecContext {
/// Set [AVCodecContext] options
pub fn set_opt(&mut self, options: HashMap<String, String>) -> Result<(), Error> {
crate::set_opts(self.context as *mut libc::c_void, options)
}
pub fn list_opts(&self) -> Result<Vec<String>, Error> {
crate::list_opts(self.context as *mut libc::c_void)
}
2024-11-07 12:48:48 +00:00
/// Get the codec name
pub fn codec_name(&self) -> String {
2024-11-09 15:47:03 +00:00
let codec_name = unsafe { rstr!((*self.codec).name) };
2024-11-07 12:48:48 +00:00
if self.hw_config.is_null() {
2024-11-09 15:47:03 +00:00
codec_name.to_string()
2024-11-07 12:48:48 +00:00
} else {
let hw = unsafe { rstr!(av_hwdevice_get_type_name((*self.hw_config).device_type)) };
format!("{}_{}", codec_name, hw)
}
}
2024-10-24 12:26:52 +01:00
}
impl Drop for DecoderCodecContext {
2024-10-23 14:48:03 +01:00
fn drop(&mut self) {
unsafe {
2024-11-09 15:47:03 +00:00
if !self.context.is_null() {
avcodec_free_context(&mut self.context);
}
2024-10-23 14:48:03 +01:00
}
}
}
2024-11-05 10:59:12 +00:00
impl Display for DecoderCodecContext {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2024-11-07 12:48:48 +00:00
write!(
f,
"stream={}, codec={}",
unsafe { (*self.stream).index },
self.codec_name()
)
2024-11-05 10:59:12 +00:00
}
}
2024-10-23 14:48:03 +01:00
pub struct Decoder {
2024-11-07 12:48:48 +00:00
/// Decoder instances by stream index
2024-10-24 12:26:52 +01:00
codecs: HashMap<i32, DecoderCodecContext>,
2024-11-05 10:59:12 +00:00
/// List of [AVHWDeviceType] which are enabled
hw_decoder_types: Option<HashSet<AVHWDeviceType>>,
2024-10-23 14:48:03 +01:00
}
2024-11-09 15:47:03 +00:00
impl Default for Decoder {
fn default() -> Self {
Self::new()
}
}
2024-10-23 14:48:03 +01:00
impl Decoder {
pub fn new() -> Self {
Self {
codecs: HashMap::new(),
2024-11-05 10:59:12 +00:00
hw_decoder_types: None,
}
}
/// Enable hardware decoding with [hw_type]
pub fn enable_hw_decoder(&mut self, hw_type: AVHWDeviceType) {
if let Some(ref mut t) = self.hw_decoder_types {
t.insert(hw_type);
} else {
let mut hwt = HashSet::new();
hwt.insert(hw_type);
self.hw_decoder_types = Some(hwt);
2024-10-23 14:48:03 +01:00
}
}
2024-11-06 09:34:37 +00:00
/// Enable hardware decoding
pub fn enable_hw_decoder_any(&mut self) {
let mut res = HashSet::new();
let mut hwt = AVHWDeviceType::AV_HWDEVICE_TYPE_NONE;
unsafe {
loop {
hwt = av_hwdevice_iterate_types(hwt);
if hwt == AVHWDeviceType::AV_HWDEVICE_TYPE_NONE {
break;
}
res.insert(hwt);
}
}
self.hw_decoder_types = Some(res);
}
2024-10-24 12:26:52 +01:00
/// Set up a decoder for a given channel
pub fn setup_decoder(
&mut self,
2024-11-11 14:10:03 +00:00
channel: &StreamInfo,
2024-10-24 12:26:52 +01:00
options: Option<HashMap<String, String>>,
) -> Result<&mut DecoderCodecContext, Error> {
unsafe { self.setup_decoder_for_stream(channel.stream, options) }
}
2024-11-07 12:48:48 +00:00
/// Get the codec context of a stream by stream index
pub fn get_decoder(&self, stream: i32) -> Option<&DecoderCodecContext> {
self.codecs.get(&stream)
}
/// List supported hardware decoding for a given codec instance
pub unsafe fn list_supported_hw_accel(
&self,
codec: *const AVCodec,
) -> impl Iterator<Item = AVHWDeviceType> {
let mut hw_config = ptr::null();
let mut i = 0;
let mut ret = Vec::new();
loop {
hw_config = avcodec_get_hw_config(codec, i);
i += 1;
if hw_config.is_null() {
break;
}
let hw_flag = AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX as libc::c_int;
if (*hw_config).methods & hw_flag == hw_flag {
ret.push((*hw_config).device_type);
}
}
ret.into_iter()
}
2024-10-24 12:26:52 +01:00
/// Set up a decoder from an [AVStream]
pub unsafe fn setup_decoder_for_stream(
2024-10-23 14:48:03 +01:00
&mut self,
stream: *mut AVStream,
2024-10-24 12:26:52 +01:00
options: Option<HashMap<String, String>>,
) -> Result<&mut DecoderCodecContext, Error> {
if stream.is_null() {
anyhow::bail!("stream is null");
}
2024-10-23 14:48:03 +01:00
let codec_par = (*stream).codecpar;
assert_ne!(
codec_par,
ptr::null_mut(),
"Codec parameters are missing from stream"
);
2024-11-07 12:48:48 +00:00
if let Entry::Vacant(e) = self.codecs.entry((*stream).index) {
2024-10-23 14:48:03 +01:00
let codec = avcodec_find_decoder((*codec_par).codec_id);
if codec.is_null() {
2024-10-24 12:26:52 +01:00
anyhow::bail!(
2024-10-23 14:48:03 +01:00
"Failed to find codec: {}",
2024-11-06 14:12:45 +00:00
rstr!(avcodec_get_name((*codec_par).codec_id))
2024-10-24 12:26:52 +01:00
)
2024-10-23 14:48:03 +01:00
}
2024-10-24 12:26:52 +01:00
let context = avcodec_alloc_context3(codec);
2024-10-23 14:48:03 +01:00
if context.is_null() {
2024-10-24 12:26:52 +01:00
anyhow::bail!("Failed to alloc context")
2024-10-23 14:48:03 +01:00
}
2024-11-05 10:59:12 +00:00
let mut ret = avcodec_parameters_to_context(context, (*stream).codecpar);
2024-11-09 15:47:03 +00:00
bail_ffmpeg!(ret, "Failed to copy codec parameters to context");
2024-11-05 10:59:12 +00:00
2024-11-06 14:12:45 +00:00
let codec_name = rstr!(avcodec_get_name((*codec).id));
2024-11-05 10:59:12 +00:00
// try use HW decoder
let mut hw_config = ptr::null();
if let Some(ref hw_types) = self.hw_decoder_types {
let mut hw_buf_ref = ptr::null_mut();
let mut i = 0;
loop {
hw_config = avcodec_get_hw_config(codec, i);
i += 1;
if hw_config.is_null() {
break;
}
2024-11-06 14:12:45 +00:00
let hw_name = rstr!(av_hwdevice_get_type_name((*hw_config).device_type));
2024-11-05 10:59:12 +00:00
if !hw_types.contains(&(*hw_config).device_type) {
2024-11-07 12:48:48 +00:00
trace!("skipping hwaccel={}_{}", codec_name, hw_name);
2024-11-05 10:59:12 +00:00
continue;
}
let hw_flag = AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX as libc::c_int;
if (*hw_config).methods & hw_flag == hw_flag {
ret = av_hwdevice_ctx_create(
&mut hw_buf_ref,
(*hw_config).device_type,
ptr::null_mut(),
ptr::null_mut(),
0,
);
2024-11-09 15:47:03 +00:00
bail_ffmpeg!(ret, "Failed to create HW ctx");
2024-11-05 10:59:12 +00:00
(*context).hw_device_ctx = av_buffer_ref(hw_buf_ref);
break;
}
}
2024-10-23 14:48:03 +01:00
}
2024-10-24 12:26:52 +01:00
let mut dict = if let Some(options) = options {
options_to_dict(options)?
} else {
ptr::null_mut()
};
2024-11-05 10:59:12 +00:00
ret = avcodec_open2(context, codec, &mut dict);
2024-11-09 15:47:03 +00:00
bail_ffmpeg!(ret, "Failed to open codec");
2024-11-05 10:59:12 +00:00
2024-11-07 12:48:48 +00:00
let ctx = DecoderCodecContext {
2024-11-05 10:59:12 +00:00
context,
codec,
2024-11-06 15:47:54 +00:00
stream,
2024-11-05 10:59:12 +00:00
hw_config,
2024-11-07 12:48:48 +00:00
};
trace!("setup decoder={}", ctx);
Ok(e.insert(ctx))
2024-10-24 12:26:52 +01:00
} else {
anyhow::bail!("Decoder already setup");
2024-10-23 14:48:03 +01:00
}
2024-10-24 12:26:52 +01:00
}
2024-11-06 15:44:33 +00:00
/// Flush all decoders
2024-11-11 11:31:23 +00:00
pub unsafe fn flush(&mut self) -> Result<Vec<*mut AVFrame>, Error> {
2024-11-06 15:44:33 +00:00
let mut pkgs = Vec::new();
for ctx in self.codecs.values_mut() {
2024-11-11 14:10:03 +00:00
pkgs.extend(Self::decode_pkt_internal(ctx.context, ptr::null_mut())?);
2024-11-06 15:44:33 +00:00
}
Ok(pkgs)
}
pub unsafe fn decode_pkt_internal(
ctx: *mut AVCodecContext,
pkt: *mut AVPacket,
2024-11-11 11:31:23 +00:00
) -> Result<Vec<*mut AVFrame>, Error> {
2024-11-06 15:44:33 +00:00
let mut ret = avcodec_send_packet(ctx, pkt);
2024-11-09 15:47:03 +00:00
bail_ffmpeg!(ret, "Failed to decode packet");
2024-11-06 15:44:33 +00:00
let mut pkgs = Vec::new();
while ret >= 0 {
2024-11-18 12:19:14 +00:00
let mut frame = av_frame_alloc();
2024-11-06 15:44:33 +00:00
ret = avcodec_receive_frame(ctx, frame);
if ret < 0 {
2024-11-18 12:19:14 +00:00
av_frame_free(&mut frame);
2024-11-06 15:44:33 +00:00
if ret == AVERROR_EOF || ret == AVERROR(libc::EAGAIN) {
break;
}
return Err(Error::msg(format!("Failed to decode {}", ret)));
}
2024-11-11 11:31:23 +00:00
pkgs.push(frame);
2024-11-06 15:44:33 +00:00
}
Ok(pkgs)
}
2024-11-11 14:10:03 +00:00
pub unsafe fn decode_pkt(&mut self, pkt: *mut AVPacket) -> Result<Vec<*mut AVFrame>, Error> {
2024-11-06 15:44:33 +00:00
if pkt.is_null() {
return self.flush();
}
2024-11-11 14:10:03 +00:00
if let Some(ctx) = self.codecs.get_mut(&(*pkt).stream_index) {
Self::decode_pkt_internal(ctx.context, pkt)
2024-10-23 14:48:03 +01:00
} else {
Ok(vec![])
}
}
}