use ffmpeg_next::format;
pub fn get_duration_us(input: impl Into<String>) -> Result<i64, ffmpeg_next::Error> {
let format_context = format::input(&input.into())?;
let duration = format_context.duration();
Ok(duration)
}
pub fn get_format(input: impl Into<String>) -> Result<String, ffmpeg_next::Error> {
let format_context = format::input(&input.into())?;
Ok(format_context.format().name().to_string())
}
pub fn get_metadata(input: impl Into<String>) -> Result<Vec<(String, String)>, ffmpeg_next::Error> {
let format_context = format::input(&input.into())?;
Ok(format_context
.metadata()
.iter()
.map(|(k, v)| (k.to_string(), v.to_string()))
.collect())
}
pub fn get_chapter_metadata(
input: impl Into<String>,
chapter_index: usize,
) -> Result<Vec<(String, String)>, ffmpeg_next::Error> {
let format_context = format::input(&input.into())?;
let chapter = format_context
.chapter(chapter_index)
.ok_or(ffmpeg_next::Error::InvalidData)?;
Ok(chapter
.metadata()
.iter()
.map(|(k, v)| (k.to_string(), v.to_string()))
.collect())
}
pub fn get_stream_metadata(
input: impl Into<String>,
stream_index: usize,
) -> Result<Vec<(String, String)>, ffmpeg_next::Error> {
let format_context = format::input(&input.into())?;
let stream = format_context
.stream(stream_index)
.ok_or(ffmpeg_next::Error::StreamNotFound)?;
Ok(stream
.metadata()
.iter()
.map(|(k, v)| (k.to_string(), v.to_string()))
.collect())
}
#[cfg(test)]
mod tests {
use super::*;
use std::path::Path;
const TEST_VIDEO_PATH: &str = "test.mp4";
fn require_test_asset() {
assert!(
Path::new(TEST_VIDEO_PATH).exists(),
"Expected '{}' to exist in the repo root for container_info tests",
TEST_VIDEO_PATH
);
}
#[test]
fn test_get_chapter_metadata_returns_invalid_when_missing() {
require_test_asset();
let result = get_chapter_metadata(TEST_VIDEO_PATH, 0);
assert!(matches!(result, Err(ffmpeg_next::Error::InvalidData)));
}
#[test]
fn test_get_chapter_metadata_invalid_index() {
require_test_asset();
let result = get_chapter_metadata(TEST_VIDEO_PATH, 999);
assert!(matches!(result, Err(ffmpeg_next::Error::InvalidData)));
}
#[test]
fn test_get_stream_metadata_video_stream() {
require_test_asset();
let metadata = get_stream_metadata(TEST_VIDEO_PATH, 0).unwrap();
assert!(!metadata.is_empty());
}
#[test]
fn test_get_stream_metadata_audio_stream() {
require_test_asset();
let metadata = get_stream_metadata(TEST_VIDEO_PATH, 1).unwrap();
assert!(!metadata.is_empty());
}
#[test]
fn test_get_stream_metadata_invalid_index() {
require_test_asset();
let result = get_stream_metadata(TEST_VIDEO_PATH, 999);
assert!(matches!(result, Err(ffmpeg_next::Error::StreamNotFound)));
}
#[test]
fn test_get_metadata_returns_global_entries() {
require_test_asset();
let metadata = get_metadata(TEST_VIDEO_PATH).unwrap();
assert!(!metadata.is_empty());
}
}