From 86b04eaeadab19f45d46958219f0a6780669c381 Mon Sep 17 00:00:00 2001 From: Alexander Capehart Date: Wed, 12 Feb 2025 21:37:50 -0700 Subject: [PATCH] musikr: add flac file --- musikr/src/main/jni/shim/file_shim.cpp | 37 ++++++------ musikr/src/main/jni/shim/file_shim.hpp | 18 +++--- musikr/src/main/jni/src/taglib/ffi.rs | 78 +++++++++++++++++++------- musikr/src/main/jni/src/taglib/mod.rs | 8 +++ 4 files changed, 91 insertions(+), 50 deletions(-) diff --git a/musikr/src/main/jni/shim/file_shim.cpp b/musikr/src/main/jni/shim/file_shim.cpp index 549852a46..f9f293341 100644 --- a/musikr/src/main/jni/shim/file_shim.cpp +++ b/musikr/src/main/jni/shim/file_shim.cpp @@ -3,49 +3,44 @@ namespace taglib_shim { - const TagLib::Ogg::File *File_asOgg(const TagLib::File *file) + TagLib::Ogg::Vorbis::File *File_asVorbis(TagLib::File *file) { - return dynamic_cast(file); + return dynamic_cast(file); } - const TagLib::Ogg::Vorbis::File *File_asVorbis(const TagLib::File *file) + TagLib::Ogg::Opus::File *File_asOpus(TagLib::File *file) { - return dynamic_cast(file); + return dynamic_cast(file); } - const TagLib::Ogg::Opus::File *File_asOpus(const TagLib::File *file) + TagLib::MPEG::File *File_asMPEG(TagLib::File *file) { - return dynamic_cast(file); + return dynamic_cast(file); } - const TagLib::MPEG::File *File_asMPEG(const TagLib::File *file) + TagLib::FLAC::File *File_asFLAC(TagLib::File *file) { - return dynamic_cast(file); + return dynamic_cast(file); } - const TagLib::FLAC::File *File_asFLAC(const TagLib::File *file) + TagLib::MP4::File *File_asMP4(TagLib::File *file) { - return dynamic_cast(file); + return dynamic_cast(file); } - const TagLib::MP4::File *File_asMP4(const TagLib::File *file) + TagLib::RIFF::WAV::File *File_asWAV(TagLib::File *file) { - return dynamic_cast(file); + return dynamic_cast(file); } - const TagLib::RIFF::WAV::File *File_asWAV(const TagLib::File *file) + TagLib::WavPack::File *File_asWavPack(TagLib::File *file) { - return dynamic_cast(file); + return dynamic_cast(file); } - const TagLib::WavPack::File *File_asWavPack(const TagLib::File *file) + TagLib::APE::File *File_asAPE(TagLib::File *file) { - return dynamic_cast(file); - } - - const TagLib::APE::File *File_asAPE(const TagLib::File *file) - { - return dynamic_cast(file); + return dynamic_cast(file); } } // namespace taglib_shim \ No newline at end of file diff --git a/musikr/src/main/jni/shim/file_shim.hpp b/musikr/src/main/jni/shim/file_shim.hpp index aa7cba3bd..3b81ba16d 100644 --- a/musikr/src/main/jni/shim/file_shim.hpp +++ b/musikr/src/main/jni/shim/file_shim.hpp @@ -17,15 +17,13 @@ namespace taglib_shim { - // File conversion functions - const TagLib::Ogg::File *File_asOgg(const TagLib::File *file); - const TagLib::Ogg::Vorbis::File *File_asVorbis(const TagLib::File *file); - const TagLib::Ogg::Opus::File *File_asOpus(const TagLib::File *file); - const TagLib::MPEG::File *File_asMPEG(const TagLib::File *file); - const TagLib::FLAC::File *File_asFLAC(const TagLib::File *file); - const TagLib::MP4::File *File_asMP4(const TagLib::File *file); - const TagLib::RIFF::WAV::File *File_asWAV(const TagLib::File *file); - const TagLib::WavPack::File *File_asWavPack(const TagLib::File *file); - const TagLib::APE::File *File_asAPE(const TagLib::File *file); + TagLib::Ogg::Vorbis::File *File_asVorbis(TagLib::File *file); + TagLib::Ogg::Opus::File *File_asOpus(TagLib::File *file); + TagLib::MPEG::File *File_asMPEG(TagLib::File *file); + TagLib::FLAC::File *File_asFLAC(TagLib::File *file); + TagLib::MP4::File *File_asMP4(TagLib::File *file); + TagLib::RIFF::WAV::File *File_asWAV(TagLib::File *file); + TagLib::WavPack::File *File_asWavPack(TagLib::File *file); + TagLib::APE::File *File_asAPE(TagLib::File *file); } // namespace taglib_shim \ No newline at end of file diff --git a/musikr/src/main/jni/src/taglib/ffi.rs b/musikr/src/main/jni/src/taglib/ffi.rs index 2303ec09b..2ab1df0d7 100644 --- a/musikr/src/main/jni/src/taglib/ffi.rs +++ b/musikr/src/main/jni/src/taglib/ffi.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; use std::ffi::CStr; -use std::pin::Pin; +use std::pin::{pin, Pin}; use std::string::ToString; #[cxx::bridge] @@ -74,6 +74,9 @@ pub(crate) mod bindings { #[namespace = "TagLib::FLAC"] #[cxx_name = "File"] type FLACFile; + #[cxx_name = "xiphComment"] + unsafe fn flacThisXiphComment(self: Pin<&mut FLACFile>, create: bool) -> *mut XiphComment; + #[namespace = "TagLib::MPEG"] #[cxx_name = "File"] type MPEGFile; @@ -94,25 +97,22 @@ pub(crate) mod bindings { #[cxx_name = "File"] type APEFile; - // File conversion functions #[namespace = "taglib_shim"] - unsafe fn File_asOgg(file: *const BaseFile) -> *const OggFile; + unsafe fn File_asVorbis(file: *mut BaseFile) -> *mut VorbisFile; #[namespace = "taglib_shim"] - unsafe fn File_asVorbis(file: *const BaseFile) -> *const VorbisFile; + unsafe fn File_asOpus(file: *mut BaseFile) -> *mut OpusFile; #[namespace = "taglib_shim"] - unsafe fn File_asOpus(file: *const BaseFile) -> *const OpusFile; + unsafe fn File_asMPEG(file: *mut BaseFile) -> *mut MPEGFile; #[namespace = "taglib_shim"] - unsafe fn File_asMPEG(file: *const BaseFile) -> *const MPEGFile; + unsafe fn File_asFLAC(file: *mut BaseFile) -> *mut FLACFile; #[namespace = "taglib_shim"] - unsafe fn File_asFLAC(file: *const BaseFile) -> *const FLACFile; + unsafe fn File_asMP4(file: *mut BaseFile) -> *mut MP4File; #[namespace = "taglib_shim"] - unsafe fn File_asMP4(file: *const BaseFile) -> *const MP4File; + unsafe fn File_asWAV(file: *mut BaseFile) -> *mut WAVFile; #[namespace = "taglib_shim"] - unsafe fn File_asWAV(file: *const BaseFile) -> *const WAVFile; + unsafe fn File_asWavPack(file: *mut BaseFile) -> *mut WavPackFile; #[namespace = "taglib_shim"] - unsafe fn File_asWavPack(file: *const BaseFile) -> *const WavPackFile; - #[namespace = "taglib_shim"] - unsafe fn File_asAPE(file: *const BaseFile) -> *const APEFile; + unsafe fn File_asAPE(file: *mut BaseFile) -> *mut APEFile; #[namespace = "TagLib"] type SimplePropertyMap; @@ -143,7 +143,7 @@ pub(crate) mod bindings { } impl bindings::FileRef { - pub fn file_or(&self) -> Option<&bindings::BaseFile> { + pub fn file_or(&self) -> Option<&mut bindings::BaseFile> { let file = unsafe { // SAFETY: // - This pin is only used in this unsafe scope. @@ -168,7 +168,7 @@ impl bindings::FileRef { // - This points to a C++FFI type ensured to be valid by cxx's codegen. // - There are no datapaths that will yield any mutable pointers or references // to this, ensuring that it will not be mutated as per the aliasing rules. - file.as_ref() + file.as_mut() }) } } @@ -196,8 +196,8 @@ impl bindings::BaseFile { } } - pub fn as_opus(&self) -> Option<&bindings::OpusFile> { - let ptr_self = self as *const Self; + pub fn as_opus(&mut self) -> Option<&mut bindings::OpusFile> { + let ptr_self = self as *mut Self; let opus_file = unsafe { // SAFETY: // This FFI function will be a simple C++ dynamic_cast, which checks if @@ -212,12 +212,12 @@ impl bindings::BaseFile { // - This points to a C++FFI type ensured to be valid by cxx's codegen. // - There are no datapaths that will yield any mutable pointers or references // to this, ensuring that it will not be mutated as per the aliasing rules. - opus_file.as_ref() + opus_file.as_mut() } } - pub fn as_vorbis(&self) -> Option<&bindings::VorbisFile> { - let ptr_self = self as *const Self; + pub fn as_vorbis(&mut self) -> Option<&bindings::VorbisFile> { + let ptr_self = self as *mut Self; let vorbis_file = unsafe { // SAFETY: // This FFI function will be a simple C++ dynamic_cast, which checks if @@ -235,6 +235,26 @@ impl bindings::BaseFile { vorbis_file.as_ref() } } + + pub fn as_flac(&mut self) -> Option<&mut bindings::FLACFile> { + let ptr_self = self as *mut Self; + let flac_file = unsafe { + // SAFETY: + // 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. + bindings::File_asFLAC(ptr_self) + }; + unsafe { + // SAFETY: + // - This points to a C++ FFI type ensured to be aligned by cxx's codegen. + // - The null-safe version is being used. + // - This points to a C++FFI type ensured to be valid by cxx's codegen. + // - There are no datapaths that will yield any mutable pointers or references + // to this, ensuring that it will not be mutated as per the aliasing rules. + flac_file.as_mut() + } + } } impl bindings::AudioProperties { @@ -325,6 +345,26 @@ impl bindings::VorbisFile { } } +impl bindings::FLACFile { + pub fn xiph_comments(&mut self) -> Option<&bindings::XiphComment> { + let tag = unsafe { + // SAFETY: + // - This pin is only used in this unsafe scope. + // - The pin is used as a C++ this pointer in the ffi call, which does + // not change address by C++ semantics. + // - The value is a pointer that does not depend on the address of self. + let this = Pin::new_unchecked(self); + // SAFETY: This is a C++ FFI function ensured to call correctly. + this.flacThisXiphComment(false) + }; + unsafe { + // SAFETY: This pointer is a valid type, and can only used and accessed + // via this function and thus cannot be mutated, satisfying the aliasing rules. + tag.as_ref() + } + } +} + impl bindings::XiphComment { pub fn field_list_map(&self) -> &bindings::SimplePropertyMap { unsafe { diff --git a/musikr/src/main/jni/src/taglib/mod.rs b/musikr/src/main/jni/src/taglib/mod.rs index 41fe95181..71a7671ec 100644 --- a/musikr/src/main/jni/src/taglib/mod.rs +++ b/musikr/src/main/jni/src/taglib/mod.rs @@ -99,6 +99,14 @@ impl FileRef { audio_properties, xiph_comments, }) + } else if let Some(flac_file) = file.as_flac() { + let xiph_comments = flac_file + .xiph_comments() + .map(|comments| comments.field_list_map().to_hashmap()); + Some(File::FLAC { + audio_properties, + xiph_comments, + }) } else { Some(File::Unknown { audio_properties }) }