musikr: more fine-grained file handling
This commit is contained in:
parent
acee4ddedd
commit
013f25f46f
5 changed files with 176 additions and 126 deletions
|
@ -2,37 +2,37 @@
|
|||
|
||||
namespace taglib_shim {
|
||||
|
||||
// File type checking functions
|
||||
bool File_isMPEG(TagLib::File* file) {
|
||||
return dynamic_cast<TagLib::MPEG::File*>(file) != nullptr;
|
||||
// File conversion functions
|
||||
TagLib::Ogg::Vorbis::File* File_asVorbis(TagLib::File* file) {
|
||||
return dynamic_cast<TagLib::Ogg::Vorbis::File*>(file);
|
||||
}
|
||||
|
||||
bool File_isFLAC(TagLib::File* file) {
|
||||
return dynamic_cast<TagLib::FLAC::File*>(file) != nullptr;
|
||||
TagLib::Ogg::Opus::File* File_asOpus(TagLib::File* file) {
|
||||
return dynamic_cast<TagLib::Ogg::Opus::File*>(file);
|
||||
}
|
||||
|
||||
bool File_isMP4(TagLib::File* file) {
|
||||
return dynamic_cast<TagLib::MP4::File*>(file) != nullptr;
|
||||
TagLib::MPEG::File* File_asMPEG(TagLib::File* file) {
|
||||
return dynamic_cast<TagLib::MPEG::File*>(file);
|
||||
}
|
||||
|
||||
bool File_isOgg(TagLib::File* file) {
|
||||
return dynamic_cast<TagLib::Ogg::File*>(file) != nullptr;
|
||||
TagLib::FLAC::File* File_asFLAC(TagLib::File* file) {
|
||||
return dynamic_cast<TagLib::FLAC::File*>(file);
|
||||
}
|
||||
|
||||
bool File_isOpus(TagLib::File* file) {
|
||||
return dynamic_cast<TagLib::Ogg::Opus::File*>(file) != nullptr;
|
||||
TagLib::MP4::File* File_asMP4(TagLib::File* file) {
|
||||
return dynamic_cast<TagLib::MP4::File*>(file);
|
||||
}
|
||||
|
||||
bool File_isWAV(TagLib::File* file) {
|
||||
return dynamic_cast<TagLib::RIFF::WAV::File*>(file) != nullptr;
|
||||
TagLib::RIFF::WAV::File* File_asWAV(TagLib::File* file) {
|
||||
return dynamic_cast<TagLib::RIFF::WAV::File*>(file);
|
||||
}
|
||||
|
||||
bool File_isWavPack(TagLib::File* file) {
|
||||
return dynamic_cast<TagLib::WavPack::File*>(file) != nullptr;
|
||||
TagLib::WavPack::File* File_asWavPack(TagLib::File* file) {
|
||||
return dynamic_cast<TagLib::WavPack::File*>(file);
|
||||
}
|
||||
|
||||
bool File_isAPE(TagLib::File* file) {
|
||||
return dynamic_cast<TagLib::APE::File*>(file) != nullptr;
|
||||
TagLib::APE::File* File_asAPE(TagLib::File* file) {
|
||||
return dynamic_cast<TagLib::APE::File*>(file);
|
||||
}
|
||||
|
||||
} // namespace taglib_shim
|
|
@ -12,18 +12,18 @@
|
|||
#include <taglib/wavfile.h>
|
||||
#include <taglib/wavpackfile.h>
|
||||
#include <taglib/apefile.h>
|
||||
#include <taglib/vorbisfile.h>
|
||||
|
||||
namespace taglib_shim {
|
||||
|
||||
// File type checking functions
|
||||
bool File_isMPEG(TagLib::File* file);
|
||||
bool File_isFLAC(TagLib::File* file);
|
||||
bool File_isMP4(TagLib::File* file);
|
||||
bool File_isOgg(TagLib::File* file);
|
||||
bool File_isOpus(TagLib::File* file);
|
||||
bool File_isWAV(TagLib::File* file);
|
||||
bool File_isWavPack(TagLib::File* file);
|
||||
bool File_isAPE(TagLib::File* file);
|
||||
|
||||
// File conversion functions
|
||||
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
|
|
@ -28,7 +28,7 @@ pub extern "C" fn Java_org_oxycblt_musikr_metadata_MetadataJNI_openFile<'local>(
|
|||
let file_ref = match FileRef::from_stream(stream) {
|
||||
Some(file_ref) => file_ref,
|
||||
None => {
|
||||
let error = "Failed to create FileRef";
|
||||
let error = "Failed to create File";
|
||||
let error_str = env.new_string(error).expect("Couldn't create error string!");
|
||||
return error_str.into_raw();
|
||||
}
|
||||
|
|
|
@ -3,61 +3,100 @@ pub(crate) mod bindings {
|
|||
unsafe extern "C++" {
|
||||
include!("taglib/taglib.h");
|
||||
include!("taglib/tstring.h");
|
||||
include!("taglib/vorbisfile.h");
|
||||
include!("taglib/xiphcomment.h");
|
||||
include!("shim/iostream_shim.hpp");
|
||||
include!("shim/file_shim.hpp");
|
||||
|
||||
#[namespace = "TagLib"]
|
||||
type FileRef;
|
||||
#[namespace = "TagLib"]
|
||||
type File;
|
||||
#[namespace = "TagLib"]
|
||||
#[cxx_name = "String"]
|
||||
type TagString;
|
||||
#[namespace = "TagLib"]
|
||||
type AudioProperties;
|
||||
|
||||
#[namespace = "taglib_shim"]
|
||||
type RustIOStream;
|
||||
#[namespace = "taglib_shim"]
|
||||
type RustStream;
|
||||
|
||||
// Create a FileRef from an iostream
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn new_rust_iostream(stream: *mut RustStream) -> UniquePtr<RustIOStream>;
|
||||
#[namespace = "taglib_shim"]
|
||||
fn new_FileRef_from_stream(stream: UniquePtr<RustIOStream>) -> UniquePtr<FileRef>;
|
||||
|
||||
// FileRef helper functions
|
||||
fn isNull(self: Pin<&FileRef>) -> bool;
|
||||
fn file(self: Pin<&FileRef>) -> *mut File;
|
||||
|
||||
#[namespace = "taglib_shim"]
|
||||
type RustIOStream;
|
||||
// Create a FileRef from an iostream
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn new_rust_iostream(stream: *mut RustStream) -> UniquePtr<RustIOStream>;
|
||||
|
||||
#[namespace = "taglib_shim"]
|
||||
type RustStream;
|
||||
#[namespace = "taglib_shim"]
|
||||
fn new_FileRef_from_stream(stream: UniquePtr<RustIOStream>) -> UniquePtr<FileRef>;
|
||||
|
||||
#[namespace = "TagLib"]
|
||||
type File;
|
||||
fn audioProperties(self: Pin<&File>) -> *mut AudioProperties;
|
||||
|
||||
// File type checking functions
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn File_isMPEG(file: *mut File) -> bool;
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn File_isFLAC(file: *mut File) -> bool;
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn File_isMP4(file: *mut File) -> bool;
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn File_isOgg(file: *mut File) -> bool;
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn File_isOpus(file: *mut File) -> bool;
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn File_isWAV(file: *mut File) -> bool;
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn File_isWavPack(file: *mut File) -> bool;
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn File_isAPE(file: *mut File) -> bool;
|
||||
|
||||
// AudioProperties methods
|
||||
#[namespace = "TagLib"]
|
||||
type AudioProperties;
|
||||
fn lengthInMilliseconds(self: Pin<&AudioProperties>) -> i32;
|
||||
fn bitrate(self: Pin<&AudioProperties>) -> i32;
|
||||
fn sampleRate(self: Pin<&AudioProperties>) -> i32;
|
||||
fn channels(self: Pin<&AudioProperties>) -> i32;
|
||||
|
||||
// String conversion utilities
|
||||
#[namespace = "TagLib::Ogg::Vorbis"]
|
||||
#[cxx_name = "File"]
|
||||
type VorbisFile;
|
||||
unsafe fn tag(self: Pin<&VorbisFile>) -> *mut XiphComment;
|
||||
|
||||
#[namespace = "TagLib::FLAC"]
|
||||
#[cxx_name = "File"]
|
||||
type FLACFile;
|
||||
|
||||
#[namespace = "TagLib::Ogg::Opus"]
|
||||
#[cxx_name = "File"]
|
||||
type OpusFile;
|
||||
|
||||
#[namespace = "TagLib::Ogg"]
|
||||
type XiphComment;
|
||||
unsafe fn fieldListMap(self: Pin<&XiphComment>) -> &FieldListMap;
|
||||
|
||||
#[namespace = "TagLib::Ogg"]
|
||||
type FieldListMap;
|
||||
|
||||
#[namespace = "TagLib::MPEG"]
|
||||
#[cxx_name = "File"]
|
||||
type MPEGFile;
|
||||
|
||||
|
||||
#[namespace = "TagLib::MP4"]
|
||||
#[cxx_name = "File"]
|
||||
type MP4File;
|
||||
|
||||
#[namespace = "TagLib::RIFF::WAV"]
|
||||
#[cxx_name = "File"]
|
||||
type WAVFile;
|
||||
|
||||
#[namespace = "TagLib::WavPack"]
|
||||
#[cxx_name = "File"]
|
||||
type WavPackFile;
|
||||
|
||||
#[namespace = "TagLib::APE"]
|
||||
#[cxx_name = "File"]
|
||||
type APEFile;
|
||||
|
||||
// File conversion functions
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn File_asVorbis(file: *mut File) -> *mut VorbisFile;
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn File_asOpus(file: *mut File) -> *mut OpusFile;
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn File_asMPEG(file: *mut File) -> *mut MPEGFile;
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn File_asFLAC(file: *mut File) -> *mut FLACFile;
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn File_asMP4(file: *mut File) -> *mut MP4File;
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn File_asWAV(file: *mut File) -> *mut WAVFile;
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn File_asWavPack(file: *mut File) -> *mut WavPackFile;
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn File_asAPE(file: *mut File) -> *mut APEFile;
|
||||
|
||||
#[namespace = "TagLib"]
|
||||
#[cxx_name = "String"]
|
||||
type TagString;
|
||||
#[namespace = "taglib_shim"]
|
||||
unsafe fn toCString(self: Pin<&TagString>, unicode: bool) -> *const c_char;
|
||||
#[namespace = "taglib_shim"]
|
||||
|
|
|
@ -1,20 +1,9 @@
|
|||
mod ffi;
|
||||
mod stream;
|
||||
|
||||
use std::pin::{pin, Pin};
|
||||
|
||||
use cxx::UniquePtr;
|
||||
pub use stream::{RustStream, TagLibStream};
|
||||
use ffi::bindings;
|
||||
|
||||
/// Audio properties of a media file
|
||||
#[derive(Default)]
|
||||
pub struct AudioProperties {
|
||||
pub length_in_milliseconds: i32,
|
||||
pub bitrate_in_kilobits_per_second: i32,
|
||||
pub sample_rate_in_hz: i32,
|
||||
pub number_of_channels: i32,
|
||||
}
|
||||
use std::pin::Pin;
|
||||
pub use stream::{RustStream, TagLibStream};
|
||||
|
||||
pub enum File {
|
||||
Unknown {
|
||||
|
@ -46,29 +35,13 @@ pub enum File {
|
|||
},
|
||||
}
|
||||
|
||||
impl Default for File {
|
||||
fn default() -> Self {
|
||||
File::Unknown {
|
||||
audio_properties: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl File {
|
||||
/// Get the audio properties of the file, if available
|
||||
pub fn audio_properties(&self) -> Option<&AudioProperties> {
|
||||
match self {
|
||||
File::Unknown { audio_properties, .. } |
|
||||
File::MP3 { audio_properties, .. } |
|
||||
File::FLAC { audio_properties, .. } |
|
||||
File::MP4 { audio_properties, .. } |
|
||||
File::OGG { audio_properties, .. } |
|
||||
File::Opus { audio_properties, .. } |
|
||||
File::WAV { audio_properties, .. } |
|
||||
File::WavPack { audio_properties, .. } |
|
||||
File::APE { audio_properties, .. } => audio_properties.as_ref()
|
||||
}
|
||||
}
|
||||
/// Audio properties of a media file
|
||||
#[derive(Default)]
|
||||
pub struct AudioProperties {
|
||||
pub length_in_milliseconds: i32,
|
||||
pub bitrate_in_kilobits_per_second: i32,
|
||||
pub sample_rate_in_hz: i32,
|
||||
pub number_of_channels: i32,
|
||||
}
|
||||
|
||||
// Safe wrapper for FileRef that owns extracted data
|
||||
|
@ -117,25 +90,63 @@ impl FileRef {
|
|||
|
||||
// Determine file type and create appropriate variant
|
||||
let file = unsafe {
|
||||
if ffi::bindings::File_isMPEG(file_ptr) {
|
||||
File::MP3 { audio_properties }
|
||||
} else if ffi::bindings::File_isFLAC(file_ptr) {
|
||||
File::FLAC { audio_properties }
|
||||
} else if ffi::bindings::File_isMP4(file_ptr) {
|
||||
File::MP4 { audio_properties }
|
||||
} else if ffi::bindings::File_isOpus(file_ptr) {
|
||||
File::Opus { audio_properties }
|
||||
} else if ffi::bindings::File_isOgg(file_ptr) {
|
||||
File::OGG { audio_properties }
|
||||
} else if ffi::bindings::File_isWAV(file_ptr) {
|
||||
File::WAV { audio_properties }
|
||||
} else if ffi::bindings::File_isWavPack(file_ptr) {
|
||||
File::WavPack { audio_properties }
|
||||
} else if ffi::bindings::File_isAPE(file_ptr) {
|
||||
File::APE { audio_properties }
|
||||
} else {
|
||||
File::Unknown { audio_properties }
|
||||
let mpeg_file = ffi::bindings::File_asMPEG(file_ptr);
|
||||
if !mpeg_file.is_null() {
|
||||
return Some(FileRef {
|
||||
file: File::MP3 { audio_properties }
|
||||
});
|
||||
}
|
||||
|
||||
let flac_file = ffi::bindings::File_asFLAC(file_ptr);
|
||||
if !flac_file.is_null() {
|
||||
return Some(FileRef {
|
||||
file: File::FLAC { audio_properties }
|
||||
});
|
||||
}
|
||||
|
||||
let mp4_file = ffi::bindings::File_asMP4(file_ptr);
|
||||
if !mp4_file.is_null() {
|
||||
return Some(FileRef {
|
||||
file: File::MP4 { audio_properties }
|
||||
});
|
||||
}
|
||||
|
||||
let wav_file = ffi::bindings::File_asWAV(file_ptr);
|
||||
if !wav_file.is_null() {
|
||||
return Some(FileRef {
|
||||
file: File::WAV { audio_properties }
|
||||
});
|
||||
}
|
||||
|
||||
let wavpack_file = ffi::bindings::File_asWavPack(file_ptr);
|
||||
if !wavpack_file.is_null() {
|
||||
return Some(FileRef {
|
||||
file: File::WavPack { audio_properties }
|
||||
});
|
||||
}
|
||||
|
||||
let ape_file = ffi::bindings::File_asAPE(file_ptr);
|
||||
if !ape_file.is_null() {
|
||||
return Some(FileRef {
|
||||
file: File::APE { audio_properties }
|
||||
});
|
||||
}
|
||||
|
||||
let vorbis_file = ffi::bindings::File_asVorbis(file_ptr);
|
||||
if !vorbis_file.is_null() {
|
||||
return Some(FileRef {
|
||||
file: File::OGG { audio_properties }
|
||||
});
|
||||
}
|
||||
|
||||
let opus_file = ffi::bindings::File_asOpus(file_ptr);
|
||||
if !opus_file.is_null() {
|
||||
return Some(FileRef {
|
||||
file: File::Opus { audio_properties }
|
||||
});
|
||||
}
|
||||
|
||||
File::Unknown { audio_properties }
|
||||
};
|
||||
|
||||
// Clean up C++ objects - they will be dropped when file_ref is dropped
|
||||
|
|
Loading…
Reference in a new issue