From 53af16da2a22030947802a0746dd8102f09e9757 Mon Sep 17 00:00:00 2001 From: Antoine Rozenknop Date: Tue, 21 Jan 2020 16:08:29 +0100 Subject: [PATCH 1/3] param_w_string.unwrap() was shorter than param_w_string.unwrap().as_raw() --- src/convenience_api.rs | 2 +- src/ffi.rs | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/convenience_api.rs b/src/convenience_api.rs index 1c5bd23..61c1d9d 100644 --- a/src/convenience_api.rs +++ b/src/convenience_api.rs @@ -229,7 +229,7 @@ mod tests { assert_eq!(Duration::from_millis(5568), mw.duration().unwrap()); assert_eq!("MPEG-4", mw.format().unwrap()); assert_eq!("Base Media / Version 2", mw.format_profile().unwrap()); - assert_eq!("MPEG-4", mw.codec().unwrap()); + assert!(mw.codec().is_err(), "Codec should be empty"); assert_eq!(551194, mw.overall_bit_rate().unwrap()); assert_eq!("HandBrake 0.9.4 2009112300", mw.writing_application().unwrap()); assert_eq!(160, mw.headersize().unwrap()); diff --git a/src/ffi.rs b/src/ffi.rs index 154f052..a339a73 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -114,12 +114,11 @@ impl MediaInfo { if param_w_string.is_err(){ return Err(MediaInfoError::RustToCStringError); } if value_w_string.is_err(){ return Err(MediaInfoError::RustToCStringError); } - let param_ptr = param_w_string.unwrap().as_raw(); - let value_ptr = value_w_string.unwrap().as_raw(); - // TODO(erick): Do we need to free this memory? I could not // find this information on the documentation. - let result_ptr = MediaInfo_Option(self.handle, param_ptr, value_ptr); + let result_ptr = MediaInfo_Option(self.handle, + param_w_string.unwrap().as_raw(), + value_w_string.unwrap().as_raw()); let result_c_string = CWcharString::from_raw_to_c_string(result_ptr); if result_c_string.is_err() { return Err(MediaInfoError::CToRustError); } @@ -165,12 +164,11 @@ impl MediaInfo { let param_w_string = CWcharString::from_str(parameter); if param_w_string.is_err(){ return Err(MediaInfoError::RustToCStringError); } - let param_ptr = param_w_string.unwrap().as_raw(); - // TODO(erick): Do we need to free this memory? I could not // find this information on the documentation. let result_ptr = MediaInfo_Get(self.handle, info_stream.c_compatible(), - stream_number as size_t, param_ptr, + stream_number as size_t, + param_w_string.unwrap().as_raw(), info_kind.c_compatible(), search_kind.c_compatible()); let result_c_string = CWcharString::from_raw_to_c_string(result_ptr); From b1374d1767d82f3d5580caf84100bcea23706824 Mon Sep 17 00:00:00 2001 From: Tristam MacDonald Date: Thu, 5 Sep 2024 17:41:56 +0200 Subject: [PATCH 2/3] upgrade dependencies --- Cargo.toml | 8 ++-- src/convenience_api.rs | 77 +++++++++++++++++++++-------------- src/ffi.rs | 6 +-- src/streams.rs | 91 ++++++++++++++++++++++++++---------------- 4 files changed, 111 insertions(+), 71 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2d9067b..a921704 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,9 +14,9 @@ exclude = [ ] [dependencies] -libc = "0.1" -delegate = "0.1" -chrono = "0.3" +libc = "0.2" +delegate = "0.13" +chrono = "0.4" [build-dependencies.pkg-config] -version = "0.3.9" +version = "0.3" diff --git a/src/convenience_api.rs b/src/convenience_api.rs index 61c1d9d..6094760 100644 --- a/src/convenience_api.rs +++ b/src/convenience_api.rs @@ -1,11 +1,12 @@ use ffi::{MediaInfo, MediaInfoResult, MediaInfoStream}; -use streams::{GeneralStream, VideoStream, AudioStream, ImageStream, MenuStream, OtherStream, TextStream}; +use streams::{ + AudioStream, GeneralStream, ImageStream, MenuStream, OtherStream, TextStream, VideoStream, +}; -use chrono::{UTC, DateTime}; -use std::rc::Rc; -use std::cell::RefCell; +use chrono::{DateTime, Utc}; use std::path::Path; -use std::time::Duration; +use std::rc::Rc; +use std::{cell::RefCell, time::Duration}; pub struct MediaInfoWrapper { general_stream: GeneralStream, @@ -48,16 +49,20 @@ impl MediaInfoWrapper { Ok(r) => { self.wrap_streams(); Ok(r) - }, + } Err(r) => Err(r), } } - pub fn open_data(&mut self, data: &[u8]) -> Result<(), String>{ + pub fn open_data(&mut self, data: &[u8]) -> Result<(), String> { let data_len = data.len(); - if data_len == 0 { return Err("Data length is 0".to_string()); } + if data_len == 0 { + return Err("Data length is 0".to_string()); + } - self.handle.borrow_mut().open_buffer_init(data_len as u64, 0); + self.handle + .borrow_mut() + .open_buffer_init(data_len as u64, 0); let continue_result = self.handle.borrow_mut().open_buffer_continue(data); let finalize_result = self.handle.borrow_mut().open_buffer_finalize(); @@ -94,9 +99,9 @@ impl MediaInfoWrapper { index: i, handler: Rc::clone(&self.handle), }); - }; + } self.video_streams = Some(streams); - }, + } MediaInfoStream::Audio => { let mut streams = Vec::new(); for i in 0..self.handle.borrow_mut().count_get(stype) { @@ -105,9 +110,9 @@ impl MediaInfoWrapper { index: i, handler: Rc::clone(&self.handle), }); - }; + } self.audio_streams = Some(streams); - }, + } MediaInfoStream::Text => { let mut streams = Vec::new(); for i in 0..self.handle.borrow_mut().count_get(stype) { @@ -116,9 +121,9 @@ impl MediaInfoWrapper { index: i, handler: Rc::clone(&self.handle), }); - }; + } self.text_streams = Some(streams); - }, + } MediaInfoStream::Other => { let mut streams = Vec::new(); for i in 0..self.handle.borrow_mut().count_get(stype) { @@ -127,9 +132,9 @@ impl MediaInfoWrapper { index: i, handler: Rc::clone(&self.handle), }); - }; + } self.other_streams = Some(streams); - }, + } MediaInfoStream::Image => { let mut streams = Vec::new(); for i in 0..self.handle.borrow_mut().count_get(stype) { @@ -138,9 +143,9 @@ impl MediaInfoWrapper { index: i, handler: Rc::clone(&self.handle), }); - }; + } self.image_streams = Some(streams); - }, + } MediaInfoStream::Menu => { let mut streams = Vec::new(); for i in 0..self.handle.borrow_mut().count_get(stype) { @@ -149,9 +154,9 @@ impl MediaInfoWrapper { index: i, handler: Rc::clone(&self.handle), }); - }; + } self.menu_streams = Some(streams); - }, + } _ => continue, } } @@ -182,7 +187,7 @@ impl MediaInfoWrapper { } delegate! { - target self.general_stream { + to self.general_stream { pub fn codec_id(&self) -> MediaInfoResult; pub fn duration(&self) -> MediaInfoResult; pub fn format(&self) -> MediaInfoResult; @@ -195,10 +200,10 @@ impl MediaInfoWrapper { pub fn datasize(&self) -> MediaInfoResult; pub fn footersize(&self) -> MediaInfoResult; pub fn encoded_library(&self) -> MediaInfoResult; - pub fn mastered_date(&self) -> MediaInfoResult>; - pub fn tagged_date(&self) -> MediaInfoResult>; - pub fn encoded_date(&self) -> MediaInfoResult>; - pub fn last_modification_date(&self) -> MediaInfoResult>; + pub fn mastered_date(&self) -> MediaInfoResult>; + pub fn tagged_date(&self) -> MediaInfoResult>; + pub fn encoded_date(&self) -> MediaInfoResult>; + pub fn last_modification_date(&self) -> MediaInfoResult>; pub fn artist(&self) -> MediaInfoResult; pub fn performer(&self) -> MediaInfoResult; pub fn title(&self) -> MediaInfoResult; @@ -213,9 +218,9 @@ impl MediaInfoWrapper { #[cfg(test)] mod tests { use super::*; - use std::path::PathBuf; use chrono::NaiveDate; use std::fs; + use std::path::PathBuf; #[test] fn can_retrieve_general_information() { @@ -231,11 +236,22 @@ mod tests { assert_eq!("Base Media / Version 2", mw.format_profile().unwrap()); assert!(mw.codec().is_err(), "Codec should be empty"); assert_eq!(551194, mw.overall_bit_rate().unwrap()); - assert_eq!("HandBrake 0.9.4 2009112300", mw.writing_application().unwrap()); + assert_eq!( + "HandBrake 0.9.4 2009112300", + mw.writing_application().unwrap() + ); assert_eq!(160, mw.headersize().unwrap()); assert_eq!(379880, mw.datasize().unwrap()); assert_eq!(3591, mw.footersize().unwrap()); - assert_eq!(DateTime::::from_utc(NaiveDate::from_ymd(2010, 3, 20).and_hms(21, 29, 12), UTC), mw.tagged_date().unwrap()); + assert_eq!( + DateTime::::from_naive_utc_and_offset( + NaiveDate::from_ymd_opt(2010, 3, 20) + .and_then(|d| d.and_hms_opt(21, 29, 12)) + .unwrap(), + Utc + ), + mw.tagged_date().unwrap() + ); mw.close(); } @@ -245,7 +261,8 @@ mod tests { let filename = sample_path.join("sample.mp4"); let mut mw = MediaInfoWrapper::new(); let contents = fs::read(filename).expect("File not found."); - mw.open_data(contents.as_slice()).expect("Could not read from buffer."); + mw.open_data(contents.as_slice()) + .expect("Could not read from buffer."); assert_eq!("mp42", mw.codec_id().unwrap()); } diff --git a/src/ffi.rs b/src/ffi.rs index a339a73..15c7ae8 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -5,8 +5,8 @@ use ::c_w_string::CWcharString; use std::ffi::CString; use std::path::Path; -type uint64 = libc::uint64_t; -type uint8 = libc::uint8_t; +type uint64 = u64; +type uint8 = u8; type size_t = libc::size_t; type wchar = libc::wchar_t; type c_char = libc::c_char; @@ -197,7 +197,7 @@ impl MediaInfo { let bytes_ptr = &data[0] as *const uint8; let result = MediaInfo_Open_Buffer_Continue(self.handle, bytes_ptr, - data.len() as uint64); + data.len() as size_t); result as usize } } diff --git a/src/streams.rs b/src/streams.rs index ce93461..ba9f915 100644 --- a/src/streams.rs +++ b/src/streams.rs @@ -1,8 +1,8 @@ -use ffi::{MediaInfo, MediaInfoInfo, MediaInfoResult, MediaInfoError, MediaInfoStream}; -use chrono::{UTC, DateTime, NaiveDateTime}; +use chrono::{DateTime, NaiveDateTime, Utc}; +use ffi::{MediaInfo, MediaInfoError, MediaInfoInfo, MediaInfoResult, MediaInfoStream}; -use std::rc::Rc; use std::cell::RefCell; +use std::rc::Rc; use std::time::Duration; macro_rules! stream_struct { @@ -12,7 +12,7 @@ macro_rules! stream_struct { pub index: usize, pub handler: Rc>, } - } + }; } macro_rules! base_stream_implement { @@ -30,57 +30,75 @@ macro_rules! base_stream_implement { Some(&self.handler) } } - } + }; } macro_rules! mediainfo_attr { - ($meth_name: ident, $attr_name: tt) => ( + ($meth_name: ident, $attr_name: tt) => { pub fn $meth_name(&self) -> MediaInfoResult { match self.handler() { - Some(rc) => rc.borrow_mut().get(self.stream_type(), self.index(), $attr_name, MediaInfoInfo::Text, MediaInfoInfo::Name), - None => Err(MediaInfoError::NoDataOpenError) + Some(rc) => rc.borrow_mut().get( + self.stream_type(), + self.index(), + $attr_name, + MediaInfoInfo::Text, + MediaInfoInfo::Name, + ), + None => Err(MediaInfoError::NoDataOpenError), } } - ) + }; } macro_rules! mediainfo_date { - ($meth_name: ident, $attr_name: tt) => ( - pub fn $meth_name(&self) -> MediaInfoResult> { + ($meth_name: ident, $attr_name: tt) => { + pub fn $meth_name(&self) -> MediaInfoResult> { match self.handler() { - Some(rc) => { - self.result_to_date(rc.borrow_mut().get(self.stream_type(), self.index(), $attr_name, MediaInfoInfo::Text, MediaInfoInfo::Name)) - }, + Some(rc) => self.result_to_date(rc.borrow_mut().get( + self.stream_type(), + self.index(), + $attr_name, + MediaInfoInfo::Text, + MediaInfoInfo::Name, + )), None => Err(MediaInfoError::NoDataOpenError), } } - ) + }; } macro_rules! mediainfo_i64 { - ($meth_name: ident, $attr_name: tt) => ( + ($meth_name: ident, $attr_name: tt) => { pub fn $meth_name(&self) -> MediaInfoResult { match self.handler() { - Some(rc) => { - self.result_to_i64(rc.borrow_mut().get(self.stream_type(), self.index(), $attr_name, MediaInfoInfo::Text, MediaInfoInfo::Name)) - }, + Some(rc) => self.result_to_i64(rc.borrow_mut().get( + self.stream_type(), + self.index(), + $attr_name, + MediaInfoInfo::Text, + MediaInfoInfo::Name, + )), None => Err(MediaInfoError::NoDataOpenError), } } - ) + }; } macro_rules! mediainfo_duration { - ($meth_name: ident, $attr_name: tt) => ( + ($meth_name: ident, $attr_name: tt) => { pub fn $meth_name(&self) -> MediaInfoResult { match self.handler() { - Some(rc) => { - self.result_to_duration(rc.borrow_mut().get(self.stream_type(), self.index(), $attr_name, MediaInfoInfo::Text, MediaInfoInfo::Name)) - }, + Some(rc) => self.result_to_duration(rc.borrow_mut().get( + self.stream_type(), + self.index(), + $attr_name, + MediaInfoInfo::Text, + MediaInfoInfo::Name, + )), None => Err(MediaInfoError::NoDataOpenError), } } - ) + }; } pub struct GeneralStream { @@ -96,7 +114,7 @@ pub trait BaseStream { fn result_to_duration(&self, result: MediaInfoResult) -> MediaInfoResult { match result?.parse::() { Ok(x) => Ok(Duration::from_millis(x)), - Err(_) =>Err(MediaInfoError::NonNumericResultError), + Err(_) => Err(MediaInfoError::NonNumericResultError), } } @@ -107,9 +125,14 @@ pub trait BaseStream { } } - fn result_to_date(&self, result: MediaInfoResult) -> MediaInfoResult> { - match NaiveDateTime::parse_from_str(&result?, "UTC %Y-%m-%d %H:%M:%S") { - Ok(x) => Ok(DateTime::::from_utc(x, UTC)), + fn result_to_date(&self, result: MediaInfoResult) -> MediaInfoResult> { + let input = &result?; + println!("input {input:?}"); + + let naive = NaiveDateTime::parse_from_str(input, "%Y-%m-%d %H:%M:%S UTC"); + println!("naive {naive:?}"); + match naive { + Ok(x) => Ok(DateTime::::from_naive_utc_and_offset(x, Utc)), Err(_) => Err(MediaInfoError::NonNumericResultError), } } @@ -173,7 +196,7 @@ impl GeneralStream { mediainfo_date!(tagged_date, "Tagged_Date"); pub fn writing_application(&self) -> MediaInfoResult { - match self.encoded_application() { + match self.encoded_application() { Ok(x) => Ok(x), Err(_) => self.encoded_application_string(), } @@ -191,7 +214,7 @@ impl VideoStream { pub fn cbr(&self) -> bool { match self.bit_rate_mode() { Ok(x) => x == "Constant", - Err(_) => false + Err(_) => false, } } @@ -205,7 +228,7 @@ impl VideoStream { pub fn interlaced(&self) -> bool { match self.scan_type() { Ok(x) => x == "Interlaced", - Err(_) => false + Err(_) => false, } } @@ -283,14 +306,14 @@ impl AudioStream { pub fn stereo(&self) -> bool { match self.channels() { Ok(x) => x == 2, - Err(_) => false + Err(_) => false, } } pub fn mono(&self) -> bool { match self.channels() { Ok(x) => x == 1, - Err(_) => false + Err(_) => false, } } From cf6e5b3c586e7d79ec5cab9199ca3c9ccd7a074f Mon Sep 17 00:00:00 2001 From: Tristam MacDonald Date: Tue, 17 Jun 2025 18:06:05 +0200 Subject: [PATCH 3/3] Add option and inform to convenience wrapper --- examples/convenience_api.rs | 9 ++++++--- examples/inform.rs | 14 +++++++++++--- src/convenience_api.rs | 8 ++++++++ 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/examples/convenience_api.rs b/examples/convenience_api.rs index 09cffc1..5349b4b 100644 --- a/examples/convenience_api.rs +++ b/examples/convenience_api.rs @@ -1,11 +1,11 @@ extern crate mediainfo; use mediainfo::MediaInfoWrapper; -use std::path::PathBuf; +use std::{env::current_dir, path::PathBuf}; fn main() { let mut media_info = MediaInfoWrapper::new(); - let sample_path = PathBuf::from("../samples"); + let sample_path = PathBuf::from("samples"); let extnames = ["mp3", "m4a", "flac"]; for ext in extnames.iter() { @@ -13,7 +13,10 @@ fn main() { media_info.open(&filename).expect("It should open the file."); println!("Filename: {}", filename.to_str().as_ref().unwrap()); - println!("{}\n", media_info.codec().unwrap()); + println!("{:?}\n", media_info.duration().unwrap()); + + let _ = media_info.option("output", "JSON"); + println!("{}\n", media_info.inform().unwrap()); media_info.close(); } diff --git a/examples/inform.rs b/examples/inform.rs index 578ff45..1fe905b 100644 --- a/examples/inform.rs +++ b/examples/inform.rs @@ -5,16 +5,24 @@ use std::path::PathBuf; fn main() { let mut media_info = MediaInfo::new(); - let sample_path = PathBuf::from("../samples"); + + let sample_path = PathBuf::from("samples"); let extnames = ["mp3", "m4a", "flac"]; for ext in extnames.iter() { let filename = sample_path.join(format!("sample.{}", ext)); - media_info.open(&filename).expect("It should open the file."); - println!("Filename: {}", filename.to_str().as_ref().unwrap()); + media_info + .open(&filename) + .expect("It should open the file."); + + let result = media_info.option("output", "JSON"); + println!("option result: {:?}", result); + println!("{}\n", media_info.inform().unwrap()); + // println!("Filename: {}", filename.to_str().as_ref().unwrap()); + media_info.close(); } } diff --git a/src/convenience_api.rs b/src/convenience_api.rs index 6094760..520182f 100644 --- a/src/convenience_api.rs +++ b/src/convenience_api.rs @@ -75,6 +75,14 @@ impl MediaInfoWrapper { Ok(()) } + pub fn option(&mut self, parameter: &str, value: &str) -> MediaInfoResult { + self.handle.borrow_mut().option(parameter, value) + } + + pub fn inform(&mut self) -> MediaInfoResult { + self.handle.borrow_mut().inform() + } + pub fn close(&mut self) { self.general_stream.handler = None; self.video_streams = None;