fix: display channel info
This commit is contained in:
parent
bc39a2ad99
commit
ba53d2eeb9
@ -7,14 +7,13 @@ use std::ptr;
|
|||||||
use anyhow::Error;
|
use anyhow::Error;
|
||||||
use ffmpeg_sys_the_third::AVPictureType::AV_PICTURE_TYPE_NONE;
|
use ffmpeg_sys_the_third::AVPictureType::AV_PICTURE_TYPE_NONE;
|
||||||
use ffmpeg_sys_the_third::{
|
use ffmpeg_sys_the_third::{
|
||||||
av_buffer_alloc, av_buffer_ref, av_frame_alloc, av_frame_copy_props, av_frame_free,
|
av_buffer_ref, av_frame_alloc, av_frame_copy_props, av_frame_free, av_hwdevice_ctx_create,
|
||||||
av_hwdevice_ctx_create, av_hwdevice_get_type_name, av_hwframe_transfer_data,
|
av_hwdevice_get_type_name, av_hwframe_transfer_data, avcodec_alloc_context3,
|
||||||
avcodec_alloc_context3, avcodec_find_decoder, avcodec_free_context, avcodec_get_hw_config,
|
avcodec_find_decoder, avcodec_free_context, avcodec_get_hw_config, avcodec_get_name,
|
||||||
avcodec_get_name, avcodec_open2, avcodec_parameters_to_context, avcodec_receive_frame,
|
avcodec_open2, avcodec_parameters_to_context, avcodec_receive_frame, avcodec_send_packet,
|
||||||
avcodec_send_packet, AVCodec, AVCodecContext, AVCodecHWConfig, AVFrame, AVHWDeviceType,
|
AVCodec, AVCodecContext, AVCodecHWConfig, AVFrame, AVHWDeviceType, AVPacket, AVStream, AVERROR,
|
||||||
AVMediaType, AVPacket, AVStream, AVERROR, AVERROR_EOF, AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX,
|
AVERROR_EOF, AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX,
|
||||||
};
|
};
|
||||||
use libc::memcpy;
|
|
||||||
|
|
||||||
pub struct DecoderCodecContext {
|
pub struct DecoderCodecContext {
|
||||||
pub context: *mut AVCodecContext,
|
pub context: *mut AVCodecContext,
|
||||||
@ -204,23 +203,6 @@ impl Decoder {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if let Some(ctx) = self.codecs.get_mut(&stream_index) {
|
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);
|
let mut ret = avcodec_send_packet(ctx.context, pkt);
|
||||||
if ret < 0 {
|
if ret < 0 {
|
||||||
return Err(Error::msg(format!("Failed to decode packet {}", ret)));
|
return Err(Error::msg(format!("Failed to decode packet {}", ret)));
|
||||||
|
23
src/lib.rs
23
src/lib.rs
@ -50,6 +50,29 @@ unsafe fn options_to_dict(options: HashMap<String, String>) -> Result<*mut AVDic
|
|||||||
Ok(dict)
|
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> {
|
fn list_opts(ctx: *mut libc::c_void) -> Result<Vec<String>, Error> {
|
||||||
let mut opt_ptr: *const AVOption = ptr::null_mut();
|
let mut opt_ptr: *const AVOption = ptr::null_mut();
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
use crate::get_ffmpeg_error_msg;
|
|
||||||
use std::mem::transmute;
|
use std::mem::transmute;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
|
@ -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::ffi::CStr;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
use std::intrinsics::transmute;
|
use std::intrinsics::transmute;
|
||||||
@ -55,9 +58,22 @@ impl DemuxerInfo {
|
|||||||
|
|
||||||
impl Display for DemuxerInfo {
|
impl Display for DemuxerInfo {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
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 {
|
for c in &self.channels {
|
||||||
write!(f, "\n{}", c)?;
|
write!(f, "\n {}", c)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -115,15 +131,44 @@ impl StreamInfoChannel {
|
|||||||
impl Display for StreamInfoChannel {
|
impl Display for StreamInfoChannel {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
let codec_name = unsafe { CStr::from_ptr(avcodec_get_name(transmute(self.codec as i32))) };
|
let codec_name = unsafe { CStr::from_ptr(avcodec_get_name(transmute(self.codec as i32))) };
|
||||||
write!(
|
match self.channel_type {
|
||||||
|
StreamChannelType::Video => write!(
|
||||||
f,
|
f,
|
||||||
"{} #{}: codec={},size={}x{},fps={}",
|
"{} #{}: codec={},size={}x{},fps={:.3},pix_fmt={}",
|
||||||
self.channel_type,
|
self.channel_type,
|
||||||
self.index,
|
self.index,
|
||||||
codec_name.to_str().unwrap(),
|
codec_name.to_str().unwrap(),
|
||||||
self.width,
|
self.width,
|
||||||
self.height,
|
self.height,
|
||||||
self.fps
|
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()
|
||||||
|
),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user