Skip to content

Commit

Permalink
Finish populating media info, chapters and program
Browse files Browse the repository at this point in the history
  • Loading branch information
HeavenVolkoff committed Apr 18, 2024
1 parent b51e62a commit 8debe3f
Show file tree
Hide file tree
Showing 6 changed files with 257 additions and 127 deletions.
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ async-trait = "0.1.77"
axum = "=0.6.20"
base64 = "0.21.5"
blake3 = "1.5.0"
chrono = "0.4.31"
chrono = "0.4.38"
clap = "4.4.7"
futures = "0.3.30"
futures-concurrency = "7.4.3"
Expand Down
112 changes: 98 additions & 14 deletions crates/ffmpeg/src/dict.rs
Original file line number Diff line number Diff line change
@@ -1,38 +1,61 @@
use crate::{error::Error, utils::check_error};
use crate::{error::Error, model::MediaMetadata, utils::check_error};

use std::{
ffi::{CStr, CString},
ptr,
};

use chrono::DateTime;
use ffmpeg_sys_next::{
av_dict_free, av_dict_iterate, av_dict_set, AVDictionary, AVDictionaryEntry,
av_dict_free, av_dict_get, av_dict_iterate, av_dict_set, AVDictionary, AVDictionaryEntry,
};

#[derive(Debug)]
pub(crate) struct FFmpegDict(*mut AVDictionary);
pub(crate) struct FFmpegDict {
dict: *mut AVDictionary,
managed: bool,
}

impl FFmpegDict {
pub(crate) fn new(av_dict: Option<*mut AVDictionary>) -> Self {

Check warning on line 20 in crates/ffmpeg/src/dict.rs

View workflow job for this annotation

GitHub Actions / Clippy (ubuntu-20.04)

associated items `new`, `as_mut_ptr`, `get`, `set`, and `remove` are never used

warning: associated items `new`, `as_mut_ptr`, `get`, `set`, and `remove` are never used --> crates/ffmpeg/src/dict.rs:20:16 | 19 | impl FFmpegDict { | --------------- associated items in this implementation 20 | pub(crate) fn new(av_dict: Option<*mut AVDictionary>) -> Self { | ^^^ ... 33 | pub(crate) fn as_mut_ptr(&mut self) -> *mut AVDictionary { | ^^^^^^^^^^ ... 37 | pub(crate) fn get(&self, key: CString) -> Option<String> { | ^^^ ... 47 | pub(crate) fn set(&mut self, key: CString, value: CString) -> Result<(), Error> { | ^^^ ... 56 | pub(crate) fn remove(&mut self, key: CString) -> Result<(), Error> { | ^^^^^^ | = note: `#[warn(dead_code)]` on by default
Self(av_dict.unwrap_or(ptr::null_mut()))
match av_dict {
Some(ptr) => Self {
dict: ptr,
managed: false,
},
None => Self {
dict: ptr::null_mut(),
managed: true,
},
}
}

pub(crate) fn as_mut_ptr(&mut self) -> *mut AVDictionary {
self.0
self.dict
}

pub(crate) fn get(&self, key: CString) -> Option<String> {
let entry = unsafe { av_dict_get(self.dict, key.as_ptr(), ptr::null(), 0) };
if entry.is_null() {
return None;
}

let cstr = unsafe { CStr::from_ptr((*entry).value) };
Some(String::from_utf8_lossy(cstr.to_bytes()).to_string())
}

pub(crate) fn set(&mut self, key: CString, value: CString) -> Result<(), Error> {
check_error(
unsafe { av_dict_set(&mut self.0, key.as_ptr(), value.as_ptr(), 0) },
unsafe { av_dict_set(&mut self.dict, key.as_ptr(), value.as_ptr(), 0) },
"Fail to set dictionary key-value pair",
)?;

Ok(())
}

pub(crate) fn reset(&mut self, key: CString) -> Result<(), Error> {
pub(crate) fn remove(&mut self, key: CString) -> Result<(), Error> {
check_error(
unsafe { av_dict_set(&mut self.0, key.as_ptr(), ptr::null(), 0) },
unsafe { av_dict_set(&mut self.dict, key.as_ptr(), ptr::null(), 0) },
"Fail to set dictionary key-value pair",
)?;

Expand All @@ -42,9 +65,9 @@ impl FFmpegDict {

impl Drop for FFmpegDict {
fn drop(&mut self) {
if !self.0.is_null() {
unsafe { av_dict_free(&mut self.0) };
self.0 = std::ptr::null_mut();
if !self.managed && !self.dict.is_null() {
unsafe { av_dict_free(&mut self.dict) };
self.dict = std::ptr::null_mut();
}
}
}
Expand All @@ -56,7 +79,7 @@ impl<'a> IntoIterator for &'a FFmpegDict {
#[inline]
fn into_iter(self) -> FFmpegDictIter<'a> {
FFmpegDictIter {
dict: self.0,
dict: self.dict,
prev: std::ptr::null(),
_lifetime: std::marker::PhantomData,
}
Expand All @@ -83,8 +106,69 @@ impl<'a> Iterator for FFmpegDictIter<'a> {
let key = unsafe { CStr::from_ptr((*self.prev).key) };
let value = unsafe { CStr::from_ptr((*self.prev).value) };
return Some((
key.to_string_lossy().into_owned(),
value.to_string_lossy().into_owned(),
String::from_utf8_lossy(key.to_bytes()).to_string(),
String::from_utf8_lossy(value.to_bytes()).to_string(),
));
}
}

impl From<FFmpegDict> for MediaMetadata {
fn from(val: FFmpegDict) -> Self {
let mut media_metadata = MediaMetadata::default();

for (key, value) in val.into_iter() {
match key.as_str() {
"album" => media_metadata.album = Some(value.clone()),
"album_artist" => media_metadata.album_artist = Some(value.clone()),
"artist" => media_metadata.artist = Some(value.clone()),
"comment" => media_metadata.comment = Some(value.clone()),
"composer" => media_metadata.composer = Some(value.clone()),
"copyright" => media_metadata.copyright = Some(value.clone()),
"creation_time" => {
if let Ok(creation_time) = DateTime::parse_from_rfc2822(&value) {
media_metadata.creation_time = Some(creation_time.into());
} else if let Ok(creation_time) = DateTime::parse_from_rfc3339(&value) {
media_metadata.creation_time = Some(creation_time.into());
}
}
"date" => {
if let Ok(date) = DateTime::parse_from_rfc2822(&value) {
media_metadata.date = Some(date.into());
} else if let Ok(date) = DateTime::parse_from_rfc3339(&value) {
media_metadata.date = Some(date.into());
}
}
"disc" => {
if let Ok(disc) = value.parse() {
media_metadata.disc = Some(disc);
}
}
"encoder" => media_metadata.encoder = Some(value.clone()),
"encoded_by" => media_metadata.encoded_by = Some(value.clone()),
"filename" => media_metadata.filename = Some(value.clone()),
"genre" => media_metadata.genre = Some(value.clone()),
"language" => media_metadata.language = Some(value.clone()),
"performer" => media_metadata.performer = Some(value.clone()),
"publisher" => media_metadata.publisher = Some(value.clone()),
"service_name" => media_metadata.service_name = Some(value.clone()),
"service_provider" => media_metadata.service_provider = Some(value.clone()),
"title" => media_metadata.title = Some(value.clone()),
"track" => {
if let Ok(track) = value.parse() {
media_metadata.track = Some(track);
}
}
"variant_bitrate" => {
if let Ok(variant_bitrate) = value.parse() {
media_metadata.variant_bitrate = Some(variant_bitrate);
}
}
_ => {
media_metadata.custom.insert(key.clone(), value.clone());
}
}
}

media_metadata
}
}
Loading

0 comments on commit 8debe3f

Please sign in to comment.