use std::ffi::CStr;
use std::time::Duration;
const AV_TIME_BASE: i64 = 1_000_000;
pub(super) unsafe fn extract_format_info(
ctx: *mut ff_sys::AVFormatContext,
) -> (String, Option<String>, Duration) {
unsafe {
let format = extract_format_name(ctx);
let format_long_name = extract_format_long_name(ctx);
let duration = extract_duration(ctx);
(format, format_long_name, duration)
}
}
unsafe fn extract_format_name(ctx: *mut ff_sys::AVFormatContext) -> String {
unsafe {
let iformat = (*ctx).iformat;
if iformat.is_null() {
return String::from("unknown");
}
let name_ptr = (*iformat).name;
if name_ptr.is_null() {
return String::from("unknown");
}
CStr::from_ptr(name_ptr).to_string_lossy().into_owned()
}
}
unsafe fn extract_format_long_name(ctx: *mut ff_sys::AVFormatContext) -> Option<String> {
unsafe {
let iformat = (*ctx).iformat;
if iformat.is_null() {
return None;
}
let long_name_ptr = (*iformat).long_name;
if long_name_ptr.is_null() {
return None;
}
Some(CStr::from_ptr(long_name_ptr).to_string_lossy().into_owned())
}
}
unsafe fn extract_duration(ctx: *mut ff_sys::AVFormatContext) -> Duration {
let duration_us = unsafe { (*ctx).duration };
if duration_us <= 0 {
return Duration::ZERO;
}
#[expect(clippy::cast_sign_loss, reason = "verified duration_us > 0")]
let secs = (duration_us / AV_TIME_BASE) as u64;
#[expect(clippy::cast_sign_loss, reason = "verified duration_us > 0")]
let micros = (duration_us % AV_TIME_BASE) as u32;
Duration::new(secs, micros * 1000)
}
pub(super) unsafe fn calculate_container_bitrate(
ctx: *mut ff_sys::AVFormatContext,
file_size: u64,
duration: std::time::Duration,
) -> Option<u64> {
let bitrate = unsafe { (*ctx).bit_rate };
if bitrate > 0 {
#[expect(clippy::cast_sign_loss, reason = "verified bitrate > 0")]
return Some(bitrate as u64);
}
let duration_secs = duration.as_secs_f64();
if duration_secs > 0.0 && file_size > 0 {
#[expect(
clippy::cast_precision_loss,
reason = "precision loss acceptable for file size; f64 handles up to 9 PB"
)]
let file_size_f64 = file_size as f64;
#[expect(
clippy::cast_possible_truncation,
reason = "bitrate values are bounded by practical file sizes"
)]
#[expect(
clippy::cast_sign_loss,
reason = "result is always positive since both operands are positive"
)]
let calculated_bitrate = (file_size_f64 * 8.0 / duration_secs) as u64;
Some(calculated_bitrate)
} else {
None
}
}