feat: setup decoder without streams

This commit is contained in:
2025-06-09 22:49:27 +01:00
parent d79693ddb0
commit 1e67eea9b6

View File

@ -10,16 +10,16 @@ use ffmpeg_sys_the_third::{
av_hwdevice_get_type_name, av_hwdevice_iterate_types, avcodec_alloc_context3, 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_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_open2, avcodec_parameters_to_context, avcodec_receive_frame, avcodec_send_packet,
AVCodec, AVCodecContext, AVCodecHWConfig, AVFrame, AVHWDeviceType, AVPacket, AVStream, AVERROR, AVCodec, AVCodecContext, AVCodecHWConfig, AVCodecID, AVFrame, AVHWDeviceType, AVPacket,
AVERROR_EOF, AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX, AVStream, AVERROR, AVERROR_EOF, AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX,
}; };
use log::trace; use log::trace;
pub struct DecoderCodecContext { pub struct DecoderCodecContext {
pub context: *mut AVCodecContext, pub context: *mut AVCodecContext,
pub codec: *const AVCodec, pub codec: *const AVCodec,
pub stream: *mut AVStream,
pub hw_config: *const AVCodecHWConfig, pub hw_config: *const AVCodecHWConfig,
pub stream_index: i32,
} }
impl DecoderCodecContext { impl DecoderCodecContext {
@ -59,7 +59,7 @@ impl Display for DecoderCodecContext {
write!( write!(
f, f,
"stream={}, codec={}", "stream={}, codec={}",
unsafe { (*self.stream).index }, self.stream_index,
self.codec_name() self.codec_name()
) )
} }
@ -166,12 +166,25 @@ impl Decoder {
"Codec parameters are missing from stream" "Codec parameters are missing from stream"
); );
if let Entry::Vacant(e) = self.codecs.entry((*stream).index) { let ctx = self.setup_decoder_codec((*codec_par).codec_id, (*stream).index, options)?;
let codec = avcodec_find_decoder((*codec_par).codec_id); let ret = avcodec_parameters_to_context(ctx.context, (*stream).codecpar);
bail_ffmpeg!(ret, "Failed to copy codec parameters to context");
Ok(ctx)
}
/// Configure a decoder manually
pub unsafe fn setup_decoder_codec(
&mut self,
codec_id: AVCodecID,
stream_index: i32,
options: Option<HashMap<String, String>>,
) -> Result<&mut DecoderCodecContext, Error> {
if let Entry::Vacant(e) = self.codecs.entry(stream_index) {
let codec = avcodec_find_decoder(codec_id);
if codec.is_null() { if codec.is_null() {
anyhow::bail!( anyhow::bail!(
"Failed to find codec: {}", "Failed to find codec: {}",
rstr!(avcodec_get_name((*codec_par).codec_id)) rstr!(avcodec_get_name(codec_id))
) )
} }
let context = avcodec_alloc_context3(codec); let context = avcodec_alloc_context3(codec);
@ -179,9 +192,7 @@ impl Decoder {
anyhow::bail!("Failed to alloc context") anyhow::bail!("Failed to alloc context")
} }
let mut ret = avcodec_parameters_to_context(context, (*stream).codecpar); let mut ret = 0;
bail_ffmpeg!(ret, "Failed to copy codec parameters to context");
let codec_name = rstr!(avcodec_get_name((*codec).id)); let codec_name = rstr!(avcodec_get_name((*codec).id));
// try use HW decoder // try use HW decoder
let mut hw_config = ptr::null(); let mut hw_config = ptr::null();
@ -226,8 +237,8 @@ impl Decoder {
let ctx = DecoderCodecContext { let ctx = DecoderCodecContext {
context, context,
codec, codec,
stream,
hw_config, hw_config,
stream_index,
}; };
trace!("setup decoder={}", ctx); trace!("setup decoder={}", ctx);
Ok(e.insert(ctx)) Ok(e.insert(ctx))
@ -237,7 +248,7 @@ impl Decoder {
} }
/// Flush all decoders /// Flush all decoders
pub unsafe fn flush(&mut self) -> Result<Vec<(*mut AVFrame, *mut AVStream)>, Error> { pub unsafe fn flush(&mut self) -> Result<Vec<(*mut AVFrame, i32)>, Error> {
let mut pkgs = Vec::new(); let mut pkgs = Vec::new();
for ctx in self.codecs.values_mut() { for ctx in self.codecs.values_mut() {
pkgs.extend(Self::decode_pkt_internal(ctx, ptr::null_mut())?); pkgs.extend(Self::decode_pkt_internal(ctx, ptr::null_mut())?);
@ -248,7 +259,7 @@ impl Decoder {
pub unsafe fn decode_pkt_internal( pub unsafe fn decode_pkt_internal(
ctx: &DecoderCodecContext, ctx: &DecoderCodecContext,
pkt: *mut AVPacket, pkt: *mut AVPacket,
) -> Result<Vec<(*mut AVFrame, *mut AVStream)>, Error> { ) -> Result<Vec<(*mut AVFrame, i32)>, Error> {
let mut ret = avcodec_send_packet(ctx.context, pkt); let mut ret = avcodec_send_packet(ctx.context, pkt);
bail_ffmpeg!(ret, "Failed to decode packet"); bail_ffmpeg!(ret, "Failed to decode packet");
@ -263,7 +274,7 @@ impl Decoder {
} }
return Err(Error::msg(format!("Failed to decode {}", ret))); return Err(Error::msg(format!("Failed to decode {}", ret)));
} }
pkgs.push((frame, ctx.stream)); pkgs.push((frame, ctx.stream_index));
} }
Ok(pkgs) Ok(pkgs)
} }
@ -271,7 +282,7 @@ impl Decoder {
pub unsafe fn decode_pkt( pub unsafe fn decode_pkt(
&mut self, &mut self,
pkt: *mut AVPacket, pkt: *mut AVPacket,
) -> Result<Vec<(*mut AVFrame, *mut AVStream)>, Error> { ) -> Result<Vec<(*mut AVFrame, i32)>, Error> {
if pkt.is_null() { if pkt.is_null() {
return self.flush(); return self.flush();
} }