musikr: add basic mp4 tag
This commit is contained in:
parent
6ef79a9aa5
commit
65d8959bcf
6 changed files with 126 additions and 13 deletions
|
@ -123,6 +123,7 @@ fn main() {
|
||||||
.file("shim/xiph_shim.cpp")
|
.file("shim/xiph_shim.cpp")
|
||||||
.file("shim/id3v1_shim.cpp")
|
.file("shim/id3v1_shim.cpp")
|
||||||
.file("shim/id3v2_shim.cpp")
|
.file("shim/id3v2_shim.cpp")
|
||||||
|
.file("shim/mp4_shim.cpp")
|
||||||
.include(format!("taglib/pkg/{}/include", target))
|
.include(format!("taglib/pkg/{}/include", target))
|
||||||
.include(".") // Add the current directory to include path
|
.include(".") // Add the current directory to include path
|
||||||
.flag_if_supported("-std=c++14");
|
.flag_if_supported("-std=c++14");
|
||||||
|
|
27
musikr/src/main/jni/shim/mp4_shim.cpp
Normal file
27
musikr/src/main/jni/shim/mp4_shim.cpp
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#include "mp4_shim.hpp"
|
||||||
|
#include <taglib/tstring.h>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace taglib_shim {
|
||||||
|
ItemMapEntry::ItemMapEntry(TagLib::String key, TagLib::MP4::Item value)
|
||||||
|
: key_(std::move(key)), value_(std::move(value)) {}
|
||||||
|
|
||||||
|
const TagLib::String& ItemMapEntry::key() const {
|
||||||
|
return key_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TagLib::MP4::Item& ItemMapEntry::value() const {
|
||||||
|
return value_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<std::vector<ItemMapEntry>> ItemMap_to_entries(const TagLib::MP4::ItemMap& map) {
|
||||||
|
auto entries = std::make_unique<std::vector<ItemMapEntry>>();
|
||||||
|
|
||||||
|
for (auto it = map.begin(); it != map.end(); ++it) {
|
||||||
|
entries->emplace_back(it->first, it->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
}
|
22
musikr/src/main/jni/shim/mp4_shim.hpp
Normal file
22
musikr/src/main/jni/shim/mp4_shim.hpp
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <taglib/mp4tag.h>
|
||||||
|
#include <taglib/mp4item.h>
|
||||||
|
#include <taglib/tstring.h>
|
||||||
|
#include "rust/cxx.h"
|
||||||
|
|
||||||
|
namespace taglib_shim {
|
||||||
|
class ItemMapEntry {
|
||||||
|
public:
|
||||||
|
ItemMapEntry(TagLib::String key, TagLib::MP4::Item value);
|
||||||
|
const TagLib::String& key() const;
|
||||||
|
const TagLib::MP4::Item& value() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
TagLib::String key_;
|
||||||
|
TagLib::MP4::Item value_;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<std::vector<ItemMapEntry>> ItemMap_to_entries(const TagLib::MP4::ItemMap& map);
|
||||||
|
}
|
|
@ -34,6 +34,7 @@ mod bridge_impl {
|
||||||
include!("shim/xiph_shim.hpp");
|
include!("shim/xiph_shim.hpp");
|
||||||
include!("shim/id3v2_shim.hpp");
|
include!("shim/id3v2_shim.hpp");
|
||||||
include!("shim/id3v1_shim.hpp");
|
include!("shim/id3v1_shim.hpp");
|
||||||
|
include!("shim/mp4_shim.hpp");
|
||||||
include!("taglib/mpegfile.h");
|
include!("taglib/mpegfile.h");
|
||||||
|
|
||||||
#[namespace = "TagLib"]
|
#[namespace = "TagLib"]
|
||||||
|
@ -45,15 +46,12 @@ mod bridge_impl {
|
||||||
#[cxx_name = "FileRef"]
|
#[cxx_name = "FileRef"]
|
||||||
type CPPFileRef;
|
type CPPFileRef;
|
||||||
unsafe fn new_FileRef(stream: *mut CPPIOStream) -> UniquePtr<CPPFileRef>;
|
unsafe fn new_FileRef(stream: *mut CPPIOStream) -> UniquePtr<CPPFileRef>;
|
||||||
#[cxx_name = "isNull"]
|
|
||||||
fn isNull(self: Pin<&CPPFileRef>) -> bool;
|
fn isNull(self: Pin<&CPPFileRef>) -> bool;
|
||||||
#[cxx_name = "file"]
|
|
||||||
fn file(self: Pin<&CPPFileRef>) -> *mut CPPFile;
|
fn file(self: Pin<&CPPFileRef>) -> *mut CPPFile;
|
||||||
|
|
||||||
#[namespace = "TagLib"]
|
#[namespace = "TagLib"]
|
||||||
#[cxx_name = "File"]
|
#[cxx_name = "File"]
|
||||||
type CPPFile;
|
type CPPFile;
|
||||||
#[cxx_name = "audioProperties"]
|
|
||||||
fn audioProperties(self: Pin<&CPPFile>) -> *mut CppAudioProperties;
|
fn audioProperties(self: Pin<&CPPFile>) -> *mut CppAudioProperties;
|
||||||
#[namespace = "taglib_shim"]
|
#[namespace = "taglib_shim"]
|
||||||
unsafe fn File_asVorbis(file: *mut CPPFile) -> *mut CPPVorbisFile;
|
unsafe fn File_asVorbis(file: *mut CPPFile) -> *mut CPPVorbisFile;
|
||||||
|
@ -71,13 +69,9 @@ mod bridge_impl {
|
||||||
#[namespace = "TagLib"]
|
#[namespace = "TagLib"]
|
||||||
#[cxx_name = "AudioProperties"]
|
#[cxx_name = "AudioProperties"]
|
||||||
type CppAudioProperties;
|
type CppAudioProperties;
|
||||||
#[cxx_name = "lengthInMilliseconds"]
|
|
||||||
fn lengthInMilliseconds(self: Pin<&CppAudioProperties>) -> i32;
|
fn lengthInMilliseconds(self: Pin<&CppAudioProperties>) -> i32;
|
||||||
#[cxx_name = "bitrate"]
|
|
||||||
fn bitrate(self: Pin<&CppAudioProperties>) -> i32;
|
fn bitrate(self: Pin<&CppAudioProperties>) -> i32;
|
||||||
#[cxx_name = "sampleRate"]
|
|
||||||
fn sampleRate(self: Pin<&CppAudioProperties>) -> i32;
|
fn sampleRate(self: Pin<&CppAudioProperties>) -> i32;
|
||||||
#[cxx_name = "channels"]
|
|
||||||
fn channels(self: Pin<&CppAudioProperties>) -> i32;
|
fn channels(self: Pin<&CppAudioProperties>) -> i32;
|
||||||
|
|
||||||
#[namespace = "TagLib::Ogg::Vorbis"]
|
#[namespace = "TagLib::Ogg::Vorbis"]
|
||||||
|
@ -97,7 +91,6 @@ mod bridge_impl {
|
||||||
#[namespace = "TagLib::FLAC"]
|
#[namespace = "TagLib::FLAC"]
|
||||||
#[cxx_name = "File"]
|
#[cxx_name = "File"]
|
||||||
type CPPFLACFile;
|
type CPPFLACFile;
|
||||||
#[cxx_name = "xiphComment"]
|
|
||||||
fn xiphComment(self: Pin<&mut CPPFLACFile>, create: bool) -> *mut CPPXiphComment;
|
fn xiphComment(self: Pin<&mut CPPFLACFile>, create: bool) -> *mut CPPXiphComment;
|
||||||
#[namespace = "taglib_shim"]
|
#[namespace = "taglib_shim"]
|
||||||
fn FLACFile_pictureList(file: Pin<&mut CPPFLACFile>) -> UniquePtr<CPPPictureList>;
|
fn FLACFile_pictureList(file: Pin<&mut CPPFLACFile>) -> UniquePtr<CPPPictureList>;
|
||||||
|
@ -118,7 +111,6 @@ mod bridge_impl {
|
||||||
#[namespace = "TagLib::MPEG"]
|
#[namespace = "TagLib::MPEG"]
|
||||||
#[cxx_name = "File"]
|
#[cxx_name = "File"]
|
||||||
type CPPMPEGFile;
|
type CPPMPEGFile;
|
||||||
#[cxx_name = "ID3v2Tag"]
|
|
||||||
fn ID3v2Tag(self: Pin<&mut CPPMPEGFile>, create: bool) -> *mut CPPID3v2Tag;
|
fn ID3v2Tag(self: Pin<&mut CPPMPEGFile>, create: bool) -> *mut CPPID3v2Tag;
|
||||||
|
|
||||||
#[namespace = "TagLib::MP4"]
|
#[namespace = "TagLib::MP4"]
|
||||||
|
@ -140,7 +132,6 @@ mod bridge_impl {
|
||||||
type CPPXiphComment;
|
type CPPXiphComment;
|
||||||
// Explicit lifecycle definition to state while the Pin is temporary, the CPPFieldListMap
|
// Explicit lifecycle definition to state while the Pin is temporary, the CPPFieldListMap
|
||||||
// ref returned actually has the same lifetime as the CPPXiphComment.
|
// ref returned actually has the same lifetime as the CPPXiphComment.
|
||||||
#[cxx_name = "fieldListMap"]
|
|
||||||
fn fieldListMap<'slf, 'file_ref>(self: Pin<&'slf CPPXiphComment>) -> &'file_ref CPPFieldListMap;
|
fn fieldListMap<'slf, 'file_ref>(self: Pin<&'slf CPPXiphComment>) -> &'file_ref CPPFieldListMap;
|
||||||
|
|
||||||
#[namespace = "TagLib"]
|
#[namespace = "TagLib"]
|
||||||
|
@ -154,9 +145,7 @@ mod bridge_impl {
|
||||||
#[namespace = "taglib_shim"]
|
#[namespace = "taglib_shim"]
|
||||||
#[cxx_name = "FieldListEntry"]
|
#[cxx_name = "FieldListEntry"]
|
||||||
type CPPFieldListEntry;
|
type CPPFieldListEntry;
|
||||||
#[cxx_name = "key"]
|
|
||||||
fn key(self: Pin<&CPPFieldListEntry>) -> &CPPString;
|
fn key(self: Pin<&CPPFieldListEntry>) -> &CPPString;
|
||||||
#[cxx_name = "value"]
|
|
||||||
fn value(self: Pin<&CPPFieldListEntry>) -> &CPPStringList;
|
fn value(self: Pin<&CPPFieldListEntry>) -> &CPPStringList;
|
||||||
|
|
||||||
#[namespace = "TagLib::ID3v2"]
|
#[namespace = "TagLib::ID3v2"]
|
||||||
|
@ -221,7 +210,6 @@ mod bridge_impl {
|
||||||
#[namespace = "TagLib"]
|
#[namespace = "TagLib"]
|
||||||
#[cxx_name = "String"]
|
#[cxx_name = "String"]
|
||||||
type CPPString;
|
type CPPString;
|
||||||
#[cxx_name = "toCString"]
|
|
||||||
fn toCString(self: Pin<&CPPString>, unicode: bool) -> *const c_char;
|
fn toCString(self: Pin<&CPPString>, unicode: bool) -> *const c_char;
|
||||||
|
|
||||||
#[namespace = "TagLib"]
|
#[namespace = "TagLib"]
|
||||||
|
@ -249,6 +237,27 @@ mod bridge_impl {
|
||||||
fn ID3v1Tag_genreIndex(tag: Pin<&CPPID3v1Tag>) -> u32;
|
fn ID3v1Tag_genreIndex(tag: Pin<&CPPID3v1Tag>) -> u32;
|
||||||
fn ID3v1Tag_year(tag: Pin<&CPPID3v1Tag>) -> u32;
|
fn ID3v1Tag_year(tag: Pin<&CPPID3v1Tag>) -> u32;
|
||||||
fn ID3v1Tag_track(tag: Pin<&CPPID3v1Tag>) -> u32;
|
fn ID3v1Tag_track(tag: Pin<&CPPID3v1Tag>) -> u32;
|
||||||
|
|
||||||
|
#[namespace = "TagLib::MP4"]
|
||||||
|
#[cxx_name = "Tag"]
|
||||||
|
type CPPMP4Tag;
|
||||||
|
|
||||||
|
#[namespace = "TagLib::MP4"]
|
||||||
|
#[cxx_name = "ItemMap"]
|
||||||
|
type CPPItemMap;
|
||||||
|
fn itemMap<'slf, 'file_ref>(self: Pin<&'slf CPPMP4Tag>) -> &'file_ref CPPItemMap;
|
||||||
|
fn ItemMap_to_entries(map: Pin<&CPPItemMap>) -> UniquePtr<CxxVector<CPPItemMapEntry>>;
|
||||||
|
|
||||||
|
#[namespace = "taglib_shim"]
|
||||||
|
#[cxx_name = "ItemMapEntry"]
|
||||||
|
type CPPItemMapEntry;
|
||||||
|
fn key(self: Pin<&CPPItemMapEntry>) -> &CPPString;
|
||||||
|
fn value(self: Pin<&CPPItemMapEntry>) -> &CPPMP4Item;
|
||||||
|
|
||||||
|
#[namespace = "TagLib::MP4"]
|
||||||
|
#[cxx_name = "Item"]
|
||||||
|
type CPPMP4Item;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,3 +11,4 @@ pub mod xiph;
|
||||||
pub mod tk;
|
pub mod tk;
|
||||||
pub mod id3v2;
|
pub mod id3v2;
|
||||||
pub mod id3v1;
|
pub mod id3v1;
|
||||||
|
pub mod mp4;
|
||||||
|
|
53
musikr/src/main/jni/src/taglib/mp4.rs
Normal file
53
musikr/src/main/jni/src/taglib/mp4.rs
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
pub use super::bridge::CPPMP4Tag;
|
||||||
|
use super::bridge::{CPPItemMap, ItemMap_to_entries, CPPItemMapEntry};
|
||||||
|
use super::tk;
|
||||||
|
use super::this::{OwnedThis, RefThis, RefThisMut, ThisMut, This};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
pub struct MP4Tag<'file_ref> {
|
||||||
|
this: RefThisMut<'file_ref, CPPMP4Tag>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'file_ref> MP4Tag<'file_ref> {
|
||||||
|
pub fn new(this: RefThisMut<'file_ref, CPPMP4Tag>) -> Self {
|
||||||
|
Self { this }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn item_map<'slf>(&'slf self) -> ItemMap<'file_ref> {
|
||||||
|
let map: &'file_ref CPPItemMap = self.this.pin().itemMap();
|
||||||
|
let map_this = unsafe { RefThis::new(map) };
|
||||||
|
ItemMap::new(map_this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ItemMap<'file_ref> {
|
||||||
|
this: RefThis<'file_ref, CPPItemMap>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'file_ref> ItemMap<'file_ref> {
|
||||||
|
pub fn new(this: RefThis<'file_ref, CPPItemMap>) -> Self {
|
||||||
|
Self { this }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_hashmap(&self) -> HashMap<String, ()> {
|
||||||
|
let cxx_vec = ItemMap_to_entries(self.this.pin());
|
||||||
|
cxx_vec
|
||||||
|
.iter()
|
||||||
|
.map(|property| {
|
||||||
|
// 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 values returned are copied and thus not dependent on the address
|
||||||
|
// of self.
|
||||||
|
let property_pin = unsafe { Pin::new_unchecked(property) };
|
||||||
|
let key_ref = property_pin.key();
|
||||||
|
let key_this = unsafe { RefThis::new(key_ref) };
|
||||||
|
let key = tk::String::new(key_this).to_string();
|
||||||
|
// For now, we're just returning () as a placeholder for MP4::Item
|
||||||
|
(key, ())
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue