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 {
|
namespace taglib_shim {
|
||||||
|
|
||||||
// File type checking functions
|
// File conversion functions
|
||||||
bool File_isMPEG(TagLib::File* file) {
|
TagLib::Ogg::Vorbis::File* File_asVorbis(TagLib::File* file) {
|
||||||
return dynamic_cast<TagLib::MPEG::File*>(file) != nullptr;
|
return dynamic_cast<TagLib::Ogg::Vorbis::File*>(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool File_isFLAC(TagLib::File* file) {
|
TagLib::Ogg::Opus::File* File_asOpus(TagLib::File* file) {
|
||||||
return dynamic_cast<TagLib::FLAC::File*>(file) != nullptr;
|
return dynamic_cast<TagLib::Ogg::Opus::File*>(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool File_isMP4(TagLib::File* file) {
|
TagLib::MPEG::File* File_asMPEG(TagLib::File* file) {
|
||||||
return dynamic_cast<TagLib::MP4::File*>(file) != nullptr;
|
return dynamic_cast<TagLib::MPEG::File*>(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool File_isOgg(TagLib::File* file) {
|
TagLib::FLAC::File* File_asFLAC(TagLib::File* file) {
|
||||||
return dynamic_cast<TagLib::Ogg::File*>(file) != nullptr;
|
return dynamic_cast<TagLib::FLAC::File*>(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool File_isOpus(TagLib::File* file) {
|
TagLib::MP4::File* File_asMP4(TagLib::File* file) {
|
||||||
return dynamic_cast<TagLib::Ogg::Opus::File*>(file) != nullptr;
|
return dynamic_cast<TagLib::MP4::File*>(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool File_isWAV(TagLib::File* file) {
|
TagLib::RIFF::WAV::File* File_asWAV(TagLib::File* file) {
|
||||||
return dynamic_cast<TagLib::RIFF::WAV::File*>(file) != nullptr;
|
return dynamic_cast<TagLib::RIFF::WAV::File*>(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool File_isWavPack(TagLib::File* file) {
|
TagLib::WavPack::File* File_asWavPack(TagLib::File* file) {
|
||||||
return dynamic_cast<TagLib::WavPack::File*>(file) != nullptr;
|
return dynamic_cast<TagLib::WavPack::File*>(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool File_isAPE(TagLib::File* file) {
|
TagLib::APE::File* File_asAPE(TagLib::File* file) {
|
||||||
return dynamic_cast<TagLib::APE::File*>(file) != nullptr;
|
return dynamic_cast<TagLib::APE::File*>(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace taglib_shim
|
} // namespace taglib_shim
|
|
@ -12,18 +12,18 @@
|
||||||
#include <taglib/wavfile.h>
|
#include <taglib/wavfile.h>
|
||||||
#include <taglib/wavpackfile.h>
|
#include <taglib/wavpackfile.h>
|
||||||
#include <taglib/apefile.h>
|
#include <taglib/apefile.h>
|
||||||
|
#include <taglib/vorbisfile.h>
|
||||||
|
|
||||||
namespace taglib_shim {
|
namespace taglib_shim {
|
||||||
|
|
||||||
// File type checking functions
|
// File conversion functions
|
||||||
bool File_isMPEG(TagLib::File* file);
|
TagLib::Ogg::Vorbis::File* File_asVorbis(TagLib::File* file);
|
||||||
bool File_isFLAC(TagLib::File* file);
|
TagLib::Ogg::Opus::File* File_asOpus(TagLib::File* file);
|
||||||
bool File_isMP4(TagLib::File* file);
|
TagLib::MPEG::File* File_asMPEG(TagLib::File* file);
|
||||||
bool File_isOgg(TagLib::File* file);
|
TagLib::FLAC::File* File_asFLAC(TagLib::File* file);
|
||||||
bool File_isOpus(TagLib::File* file);
|
TagLib::MP4::File* File_asMP4(TagLib::File* file);
|
||||||
bool File_isWAV(TagLib::File* file);
|
TagLib::RIFF::WAV::File* File_asWAV(TagLib::File* file);
|
||||||
bool File_isWavPack(TagLib::File* file);
|
TagLib::WavPack::File* File_asWavPack(TagLib::File* file);
|
||||||
bool File_isAPE(TagLib::File* file);
|
TagLib::APE::File* File_asAPE(TagLib::File* file);
|
||||||
|
|
||||||
|
|
||||||
} // namespace taglib_shim
|
} // 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) {
|
let file_ref = match FileRef::from_stream(stream) {
|
||||||
Some(file_ref) => file_ref,
|
Some(file_ref) => file_ref,
|
||||||
None => {
|
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!");
|
let error_str = env.new_string(error).expect("Couldn't create error string!");
|
||||||
return error_str.into_raw();
|
return error_str.into_raw();
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,61 +3,100 @@ pub(crate) mod bindings {
|
||||||
unsafe extern "C++" {
|
unsafe extern "C++" {
|
||||||
include!("taglib/taglib.h");
|
include!("taglib/taglib.h");
|
||||||
include!("taglib/tstring.h");
|
include!("taglib/tstring.h");
|
||||||
|
include!("taglib/vorbisfile.h");
|
||||||
|
include!("taglib/xiphcomment.h");
|
||||||
include!("shim/iostream_shim.hpp");
|
include!("shim/iostream_shim.hpp");
|
||||||
include!("shim/file_shim.hpp");
|
include!("shim/file_shim.hpp");
|
||||||
|
|
||||||
#[namespace = "TagLib"]
|
#[namespace = "TagLib"]
|
||||||
type FileRef;
|
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 isNull(self: Pin<&FileRef>) -> bool;
|
||||||
fn file(self: Pin<&FileRef>) -> *mut File;
|
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;
|
fn audioProperties(self: Pin<&File>) -> *mut AudioProperties;
|
||||||
|
|
||||||
// File type checking functions
|
#[namespace = "TagLib"]
|
||||||
#[namespace = "taglib_shim"]
|
type AudioProperties;
|
||||||
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
|
|
||||||
fn lengthInMilliseconds(self: Pin<&AudioProperties>) -> i32;
|
fn lengthInMilliseconds(self: Pin<&AudioProperties>) -> i32;
|
||||||
fn bitrate(self: Pin<&AudioProperties>) -> i32;
|
fn bitrate(self: Pin<&AudioProperties>) -> i32;
|
||||||
fn sampleRate(self: Pin<&AudioProperties>) -> i32;
|
fn sampleRate(self: Pin<&AudioProperties>) -> i32;
|
||||||
fn channels(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"]
|
#[namespace = "taglib_shim"]
|
||||||
unsafe fn toCString(self: Pin<&TagString>, unicode: bool) -> *const c_char;
|
unsafe fn toCString(self: Pin<&TagString>, unicode: bool) -> *const c_char;
|
||||||
#[namespace = "taglib_shim"]
|
#[namespace = "taglib_shim"]
|
||||||
|
|
|
@ -1,20 +1,9 @@
|
||||||
mod ffi;
|
mod ffi;
|
||||||
mod stream;
|
mod stream;
|
||||||
|
|
||||||
use std::pin::{pin, Pin};
|
|
||||||
|
|
||||||
use cxx::UniquePtr;
|
|
||||||
pub use stream::{RustStream, TagLibStream};
|
|
||||||
use ffi::bindings;
|
use ffi::bindings;
|
||||||
|
use std::pin::Pin;
|
||||||
/// Audio properties of a media file
|
pub use stream::{RustStream, TagLibStream};
|
||||||
#[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,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum File {
|
pub enum File {
|
||||||
Unknown {
|
Unknown {
|
||||||
|
@ -46,29 +35,13 @@ pub enum File {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for File {
|
/// Audio properties of a media file
|
||||||
fn default() -> Self {
|
#[derive(Default)]
|
||||||
File::Unknown {
|
pub struct AudioProperties {
|
||||||
audio_properties: None,
|
pub length_in_milliseconds: i32,
|
||||||
}
|
pub bitrate_in_kilobits_per_second: i32,
|
||||||
}
|
pub sample_rate_in_hz: i32,
|
||||||
}
|
pub number_of_channels: i32,
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Safe wrapper for FileRef that owns extracted data
|
// Safe wrapper for FileRef that owns extracted data
|
||||||
|
@ -117,25 +90,63 @@ impl FileRef {
|
||||||
|
|
||||||
// Determine file type and create appropriate variant
|
// Determine file type and create appropriate variant
|
||||||
let file = unsafe {
|
let file = unsafe {
|
||||||
if ffi::bindings::File_isMPEG(file_ptr) {
|
let mpeg_file = ffi::bindings::File_asMPEG(file_ptr);
|
||||||
File::MP3 { audio_properties }
|
if !mpeg_file.is_null() {
|
||||||
} else if ffi::bindings::File_isFLAC(file_ptr) {
|
return Some(FileRef {
|
||||||
File::FLAC { audio_properties }
|
file: File::MP3 { 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 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
|
// Clean up C++ objects - they will be dropped when file_ref is dropped
|
||||||
|
|
Loading…
Reference in a new issue