fix: display channel info

This commit is contained in:
kieran 2024-11-05 13:57:13 +00:00
parent bc39a2ad99
commit ba53d2eeb9
No known key found for this signature in database
GPG Key ID: DE71CEB3925BE941
4 changed files with 87 additions and 38 deletions

View File

@ -7,14 +7,13 @@ use std::ptr;
use anyhow::Error;
use ffmpeg_sys_the_third::AVPictureType::AV_PICTURE_TYPE_NONE;
use ffmpeg_sys_the_third::{
av_buffer_alloc, av_buffer_ref, av_frame_alloc, av_frame_copy_props, av_frame_free,
av_hwdevice_ctx_create, av_hwdevice_get_type_name, av_hwframe_transfer_data,
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,
AVMediaType, AVPacket, AVStream, AVERROR, AVERROR_EOF, AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX,
av_buffer_ref, av_frame_alloc, av_frame_copy_props, av_frame_free, av_hwdevice_ctx_create,
av_hwdevice_get_type_name, av_hwframe_transfer_data, 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,
};
use libc::memcpy;
pub struct DecoderCodecContext {
pub context: *mut AVCodecContext,
@ -204,23 +203,6 @@ impl Decoder {
);
if let Some(ctx) = self.codecs.get_mut(&stream_index) {
// subtitles don't need decoding, create a frame from the pkt data
if (*ctx.codec).type_ == AVMediaType::AVMEDIA_TYPE_SUBTITLE {
let frame = av_frame_alloc();
(*frame).pts = (*pkt).pts;
(*frame).pkt_dts = (*pkt).dts;
(*frame).duration = (*pkt).duration;
(*frame).buf[0] = av_buffer_alloc((*pkt).size as usize);
(*frame).data[0] = (*(*frame).buf[0]).data;
(*frame).linesize[0] = (*pkt).size;
memcpy(
(*frame).data[0] as *mut libc::c_void,
(*pkt).data as *const libc::c_void,
(*pkt).size as usize,
);
return Ok(vec![(frame, stream)]);
}
let mut ret = avcodec_send_packet(ctx.context, pkt);
if ret < 0 {
return Err(Error::msg(format!("Failed to decode packet {}", ret)));

View File

@ -50,6 +50,29 @@ unsafe fn options_to_dict(options: HashMap<String, String>) -> Result<*mut AVDic
Ok(dict)
}
/// Format seconds value into human-readable string
pub fn format_time(secs: f32) -> String {
const MIN: f32 = 60.0;
const HR: f32 = MIN * 60.0;
if secs >= HR {
format!(
"{:0>2.0}h {:0>2.0}m {:0>2.0}s",
(secs / HR).floor(),
((secs % HR) / MIN).floor(),
(secs % MIN).floor()
)
} else if secs >= MIN {
format!(
"{:0>2.0}m {:0>2.0}s",
(secs / MIN).floor(),
(secs % MIN).floor()
)
} else {
format!("{:0>2.2}s", secs)
}
}
fn list_opts(ctx: *mut libc::c_void) -> Result<Vec<String>, Error> {
let mut opt_ptr: *const AVOption = ptr::null_mut();

View File

@ -1,4 +1,3 @@
use crate::get_ffmpeg_error_msg;
use std::mem::transmute;
use std::ptr;

View File

@ -1,4 +1,7 @@
use ffmpeg_sys_the_third::{avcodec_get_name, AVMediaType, AVStream};
use crate::format_time;
use ffmpeg_sys_the_third::{
av_get_pix_fmt_name, av_get_sample_fmt_name, avcodec_get_name, AVMediaType, AVStream,
};
use std::ffi::CStr;
use std::fmt::{Display, Formatter};
use std::intrinsics::transmute;
@ -55,9 +58,22 @@ impl DemuxerInfo {
impl Display for DemuxerInfo {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "Demuxer Info:")?;
let bitrate_str = if self.bitrate > 1_000_000 {
format!("{}M", self.bitrate / 1_000_000)
} else if self.bitrate > 1_000 {
format!("{}k", self.bitrate / 1_000)
} else {
self.bitrate.to_string()
};
write!(
f,
"Demuxer Info: duration={}, bitrate={}k",
format_time(self.duration),
bitrate_str
)?;
for c in &self.channels {
write!(f, "\n{}", c)?;
write!(f, "\n {}", c)?;
}
Ok(())
}
@ -115,15 +131,44 @@ impl StreamInfoChannel {
impl Display for StreamInfoChannel {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let codec_name = unsafe { CStr::from_ptr(avcodec_get_name(transmute(self.codec as i32))) };
write!(
f,
"{} #{}: codec={},size={}x{},fps={}",
self.channel_type,
self.index,
codec_name.to_str().unwrap(),
self.width,
self.height,
self.fps
)
match self.channel_type {
StreamChannelType::Video => write!(
f,
"{} #{}: codec={},size={}x{},fps={:.3},pix_fmt={}",
self.channel_type,
self.index,
codec_name.to_str().unwrap(),
self.width,
self.height,
self.fps,
unsafe {
CStr::from_ptr(av_get_pix_fmt_name(transmute(self.format as libc::c_int)))
}
.to_str()
.unwrap(),
),
StreamChannelType::Audio => write!(
f,
"{} #{}: codec={},format={},sample_rate={}",
self.channel_type,
self.index,
codec_name.to_str().unwrap(),
unsafe {
CStr::from_ptr(av_get_sample_fmt_name(transmute(
self.format as libc::c_int,
)))
}
.to_str()
.unwrap(),
self.sample_rate,
),
StreamChannelType::Subtitle => write!(
f,
"{} #{}: codec={}",
self.channel_type,
self.index,
codec_name.to_str().unwrap()
),
}
}
}