Skip to content

Commit

Permalink
Add relation between MediaInfo and FilePath
Browse files Browse the repository at this point in the history
 - Remove shared properties from MediaInfo and related structs
 - Implement Iterator for FFmpegDict
  • Loading branch information
HeavenVolkoff committed Apr 17, 2024
1 parent 58edd9a commit f79237c
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 38 deletions.
39 changes: 17 additions & 22 deletions core/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,9 @@ model FilePath {
date_modified DateTime?
date_indexed DateTime?
media_info MediaInfo? @relation(fields: [media_info_id], references: [id], onDelete: SetNull)
media_info_id Int?
// key Key? @relation(fields: [key_id], references: [id])
@@unique([location_id, materialized_path, name, extension])
Expand Down Expand Up @@ -270,7 +273,6 @@ model ExifData {
@@map("exif_data")
}

/// @shared(id: object)
model MediaInfo {
id Int @id @default(autoincrement())
Expand All @@ -283,47 +285,46 @@ model MediaInfo {
chapters MediaChapter[]
programs MediaProgram[]
metadata MediaMetadata @relation(fields: [metadata_id], references: [id])
metadata MediaMetadata @relation(fields: [metadata_id], references: [id], onDelete: Cascade)
metadata_id Int @unique
files FilePath[]
@@map("media_info")
}

/// @shared(id: object)
model MediaChapter {
chapter_id Int
start BigInt?
end BigInt?
metadata MediaMetadata @relation(fields: [metadata_id], references: [id])
metadata MediaMetadata @relation(fields: [metadata_id], references: [id], onDelete: Cascade)
metadata_id Int @unique
media_info MediaInfo @relation(fields: [media_info_id], references: [id])
media_info MediaInfo @relation(fields: [media_info_id], references: [id], onDelete: Cascade)
media_info_id Int
@@id(name: "likeId", [media_info_id, chapter_id])
@@map("media_chapter")
}

/// @shared(id: object)
model MediaProgram {
program_id Int
name String?
streams MediaStream[]
metadata MediaMetadata @relation(fields: [metadata_id], references: [id])
metadata MediaMetadata @relation(fields: [metadata_id], references: [id], onDelete: Cascade)
metadata_id Int @unique
media_info MediaInfo @relation(fields: [media_info_id], references: [id])
media_info MediaInfo @relation(fields: [media_info_id], references: [id], onDelete: Cascade)
media_info_id Int
@@id(name: "likeId", [media_info_id, program_id])
@@map("media_program")
}

/// @shared(id: object)
model MediaStream {
stream_id Int
Expand All @@ -335,10 +336,10 @@ model MediaStream {
time_base_real Decimal?
dispositions String?
metadata MediaMetadata @relation(fields: [metadata_id], references: [id])
metadata MediaMetadata @relation(fields: [metadata_id], references: [id], onDelete: Cascade)
metadata_id Int @unique
program MediaProgram @relation(fields: [media_info_id, program_id], references: [media_info_id, program_id])
program MediaProgram @relation(fields: [media_info_id, program_id], references: [media_info_id, program_id], onDelete: Cascade)
program_id Int
media_info_id Int
Expand All @@ -347,7 +348,6 @@ model MediaStream {
@@map("media_stream")
}

/// @shared(id: object)
model MediaCodec {
id Int @id @default(autoincrement())
Expand All @@ -361,7 +361,7 @@ model MediaCodec {
audio_props MediaAudioProps?
subtitle_props MediaSubtitleProps?
codec MediaStream @relation(fields: [media_info_id, program_id, stream_id], references: [media_info_id, program_id, stream_id])
codec MediaStream @relation(fields: [media_info_id, program_id, stream_id], references: [media_info_id, program_id, stream_id], onDelete: Cascade)
stream_id Int
program_id Int
media_info_id Int
Expand All @@ -370,7 +370,6 @@ model MediaCodec {
@@map("media_codec")
}

/// @shared(id: object)
model MediaVideoProps {
id Int @id @default(autoincrement())
Expand All @@ -388,13 +387,12 @@ model MediaVideoProps {
aspect_ratio_Den Int?
properties String
codec MediaCodec @relation(fields: [codec_id], references: [id])
codec MediaCodec @relation(fields: [codec_id], references: [id], onDelete: Cascade)
codec_id Int @unique
@@map("media_video")
}

/// @shared(id: object)
model MediaAudioProps {
id Int @id @default(autoincrement())
Expand All @@ -405,26 +403,24 @@ model MediaAudioProps {
bit_per_sample Int?
channel_layout String?
codec MediaCodec @relation(fields: [codec_id], references: [id])
codec MediaCodec @relation(fields: [codec_id], references: [id], onDelete: Cascade)
codec_id Int @unique
@@map("media_audio")
}

/// @shared(id: object)
model MediaSubtitleProps {
id Int @id @default(autoincrement())
width Int?
height Int?
codec MediaCodec @relation(fields: [codec_id], references: [id])
codec MediaCodec @relation(fields: [codec_id], references: [id], onDelete: Cascade)
codec_id Int @unique
@@map("media_subtitle")
}

/// @shared(id: object)
model MediaMetadata {
id Int @id @default(autoincrement())
Expand Down Expand Up @@ -467,14 +463,13 @@ model MediaMetadata {
@@map("media_metadata")
}

/// @shared(id: object)
model CustomMetadata {
id Int @id @default(autoincrement())
key String?
value String?
media_metadata MediaMetadata @relation(fields: [media_metadata_id], references: [id])
media_metadata MediaMetadata @relation(fields: [media_metadata_id], references: [id], onDelete: Cascade)
media_metadata_id Int @unique
@@map("custom_metadata")
Expand Down
72 changes: 57 additions & 15 deletions crates/ffmpeg/src/dict.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
use crate::{error::Error, utils::check_error};

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

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

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

impl FFmpegDict {
pub(crate) fn new() -> Self {
Self {
data: ptr::null_mut(),
}
pub(crate) fn new(av_dict: Option<*mut AVDictionary>) -> Self {
Self(av_dict.unwrap_or(ptr::null_mut()))
}

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

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

Expand All @@ -31,7 +32,7 @@ impl FFmpegDict {

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

Expand All @@ -41,9 +42,50 @@ impl FFmpegDict {

impl Drop for FFmpegDict {
fn drop(&mut self) {
if !self.data.is_null() {
unsafe { av_dict_free(&mut self.data) };
self.data = std::ptr::null_mut();
if !self.0.is_null() {
unsafe { av_dict_free(&mut self.0) };
self.0 = std::ptr::null_mut();
}
}
}

impl<'a> IntoIterator for &'a FFmpegDict {
type Item = (String, String);
type IntoIter = FFmpegDictIter<'a>;

#[inline]
fn into_iter(self) -> FFmpegDictIter<'a> {
FFmpegDictIter {
dict: self.0,
prev: std::ptr::null(),
_lifetime: std::marker::PhantomData,
}
}
}

pub(crate) struct FFmpegDictIter<'a> {
dict: *mut AVDictionary,
prev: *const AVDictionaryEntry,
_lifetime: std::marker::PhantomData<&'a ()>,
}

impl<'a> Iterator for FFmpegDictIter<'a> {
type Item = (String, String);

fn next(&mut self) -> Option<(String, String)> {
while unsafe {
self.prev = av_dict_iterate(self.dict, self.prev);
self.prev
} != ptr::null()
{
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(),
));
}

None
}
}
2 changes: 1 addition & 1 deletion crates/ffmpeg/src/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub fn probe(filename: impl AsRef<Path>) -> Result<(), Error> {
unsafe { av_log_set_level(AV_LOG_FATAL) };

// Dictionary to store format options
let mut format_opts = FFmpegDict::new();
let mut format_opts = FFmpegDict::new(None);
// Some MPEGTS specific option (copied and pasted from ffprobe)
let scan_all_pmts = CString::new("scan_all_pmts").expect(CSTRING_ERROR_MSG);
format_opts.set(
Expand Down

0 comments on commit f79237c

Please sign in to comment.