diff --git a/musikr/src/main/jni/src/taglib/bridge.rs b/musikr/src/main/jni/src/taglib/bridge.rs index 10c68927b..7ceca1ada 100644 --- a/musikr/src/main/jni/src/taglib/bridge.rs +++ b/musikr/src/main/jni/src/taglib/bridge.rs @@ -27,6 +27,9 @@ mod bridge_impl { include!("taglib/tiostream.h"); include!("taglib/flacpicture.h"); include!("taglib/tbytevector.h"); + include!("taglib/mp4file.h"); + include!("taglib/mp4tag.h"); + include!("taglib/mp4item.h"); include!("shim/iostream_shim.hpp"); include!("shim/file_shim.hpp"); include!("shim/tk_shim.hpp"); @@ -123,6 +126,8 @@ mod bridge_impl { #[namespace = "TagLib::MP4"] #[cxx_name = "File"] type CPPMP4File; + #[cxx_name = "tag"] + fn MP4Tag(self: &CPPMP4File) -> *mut CPPMP4Tag; #[namespace = "TagLib::RIFF::WAV"] #[cxx_name = "File"] diff --git a/musikr/src/main/jni/src/taglib/file.rs b/musikr/src/main/jni/src/taglib/file.rs index e5385d710..fac9a9be2 100644 --- a/musikr/src/main/jni/src/taglib/file.rs +++ b/musikr/src/main/jni/src/taglib/file.rs @@ -2,6 +2,7 @@ use super::audioproperties::AudioProperties; use super::bridge::{self, CPPFile, CPPMPEGFile}; use super::flac::FLACFile; use super::id3v2::ID3v2Tag; +use super::mp4::MP4File; use super::mpeg::MPEGFile; use super::ogg::OpusFile; use super::ogg::VorbisFile; @@ -38,7 +39,7 @@ impl<'file_ref> File<'file_ref> { // This FFI function will be a simple C++ dynamic_cast, which checks if // the file can be cased down to an opus file. If the cast fails, a null // pointer is returned, which will be handled by as_ref's null checking. - bridge::File_asOpus(self.this.ptr_mut() as *mut CPPFile) + bridge::File_asOpus(self.this.ptr_mut()) }; let opus_ref = unsafe { // SAFETY: @@ -59,7 +60,7 @@ impl<'file_ref> File<'file_ref> { // This FFI function will be a simple C++ dynamic_cast, which checks if // the file can be cased down to an opus file. If the cast fails, a null // pointer is returned, which will be handled by as_ref's null checking. - bridge::File_asVorbis(self.this.ptr_mut() as *mut CPPFile) + bridge::File_asVorbis(self.this.ptr_mut()) }; let vorbis_ref = unsafe { // SAFETY: @@ -80,7 +81,7 @@ impl<'file_ref> File<'file_ref> { // This FFI function will be a simple C++ dynamic_cast, which checks if // the file can be cased down to an opus file. If the cast fails, a null // pointer is returned, which will be handled by as_ref's null checking. - bridge::File_asFLAC(self.this.ptr_mut() as *mut CPPFile) + bridge::File_asFLAC(self.this.ptr_mut()) }; let flac_ref = unsafe { // SAFETY: @@ -101,7 +102,7 @@ impl<'file_ref> File<'file_ref> { // This FFI function will be a simple C++ dynamic_cast, which checks if // the file can be cased down to an MPEG file. If the cast fails, a null // pointer is returned, which will be handled by as_ref's null checking. - bridge::File_asMPEG(self.this.ptr_mut() as *mut CPPFile) + bridge::File_asMPEG(self.this.ptr_mut()) }; let mpeg_ref = unsafe { // SAFETY: @@ -115,4 +116,14 @@ impl<'file_ref> File<'file_ref> { let mpeg_this = mpeg_ref.map(|mpeg| unsafe { RefThisMut::new(mpeg) }); mpeg_this.map(|this| MPEGFile::new(this)) } + + pub fn as_mp4(&mut self) -> Option> { + let mp4_file = unsafe { + bridge::File_asMP4(self.this.ptr_mut()) + }; + let mp4_ref = unsafe { mp4_file.as_mut() }; + let mp4_this = mp4_ref.map(|mp4| unsafe { RefThisMut::new(mp4) }); + mp4_this.map(|this| MP4File::new(this)) + } + } diff --git a/musikr/src/main/jni/src/taglib/mod.rs b/musikr/src/main/jni/src/taglib/mod.rs index 701e75956..1f7e5a361 100644 --- a/musikr/src/main/jni/src/taglib/mod.rs +++ b/musikr/src/main/jni/src/taglib/mod.rs @@ -1,5 +1,5 @@ -pub mod bridge; -pub mod this; +mod bridge; +mod this; pub mod iostream; pub mod file_ref; pub mod file; diff --git a/musikr/src/main/jni/src/taglib/mp4.rs b/musikr/src/main/jni/src/taglib/mp4.rs index e68d5c4ee..5cf8a3097 100644 --- a/musikr/src/main/jni/src/taglib/mp4.rs +++ b/musikr/src/main/jni/src/taglib/mp4.rs @@ -1,16 +1,37 @@ pub use super::bridge::CPPMP4Tag; -use super::bridge::{CPPItemMap, ItemMap_to_entries, CPPItemMapEntry, CPPMP4Item, MP4ItemType, CPPIntPair}; +use super::bridge::{CPPFile, CPPIntPair, CPPItemMap, CPPItemMapEntry, CPPMP4File, CPPMP4Item, ItemMap_to_entries, MP4ItemType}; use super::tk; use super::this::{OwnedThis, RefThis, RefThisMut, ThisMut, This}; use std::collections::HashMap; use std::pin::Pin; +pub struct MP4File<'file_ref> { + this: RefThisMut<'file_ref, CPPMP4File>, +} + +impl<'file_ref> MP4File<'file_ref> { + pub fn new(this: RefThisMut<'file_ref, CPPMP4File>) -> Self { + Self { this } + } + + pub fn tag(&self) -> Option> { + let this = self.this.as_ref(); + let tag = unsafe { this.MP4Tag() }; + let tag_ref = unsafe { tag.as_ref() }; + tag_ref.map(|tag| { + // SAFETY: The tag pointer is guaranteed to be valid for the lifetime of self + let tag_this = unsafe { RefThis::new(tag) }; + MP4Tag::new(tag_this) + }) + } +} + pub struct MP4Tag<'file_ref> { - this: RefThisMut<'file_ref, CPPMP4Tag>, + this: RefThis<'file_ref, CPPMP4Tag>, } impl<'file_ref> MP4Tag<'file_ref> { - pub fn new(this: RefThisMut<'file_ref, CPPMP4Tag>) -> Self { + pub fn new(this: RefThis<'file_ref, CPPMP4Tag>) -> Self { Self { this } }