feat: setup decoder without streams
This commit is contained in:
@ -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();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user