musikr: add mp4 item bindings
This commit is contained in:
parent
608082a49f
commit
2c03cf8fed
8 changed files with 361 additions and 11 deletions
|
@ -24,4 +24,62 @@ namespace taglib_shim {
|
|||
|
||||
return entries;
|
||||
}
|
||||
|
||||
IntPair::IntPair(int first, int second)
|
||||
: first_(first), second_(second) {}
|
||||
|
||||
int IntPair::first() const {
|
||||
return first_;
|
||||
}
|
||||
|
||||
int IntPair::second() const {
|
||||
return second_;
|
||||
}
|
||||
|
||||
CoverArt::CoverArt(TagLib::MP4::CoverArt::Format format, const TagLib::ByteVector& data)
|
||||
: art_(format, data) {}
|
||||
|
||||
uint32_t CoverArt::format() const {
|
||||
return static_cast<uint32_t>(art_.format());
|
||||
}
|
||||
|
||||
std::unique_ptr<TagLib::ByteVector> CoverArt::data() const {
|
||||
return std::make_unique<TagLib::ByteVector>(art_.data());
|
||||
}
|
||||
|
||||
CoverArtList::CoverArtList(const TagLib::MP4::CoverArtList& list)
|
||||
: list_(list) {}
|
||||
|
||||
std::unique_ptr<std::vector<CoverArt>> CoverArtList::to_vector() const {
|
||||
auto vec = std::make_unique<std::vector<CoverArt>>();
|
||||
for (const auto& item : list_) {
|
||||
vec->emplace_back(item.format(), item.data());
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
unsigned int Item_type(const TagLib::MP4::Item& item) {
|
||||
return static_cast<unsigned int>(item.type());
|
||||
}
|
||||
|
||||
std::unique_ptr<IntPair> Item_toIntPair(const TagLib::MP4::Item& item) {
|
||||
auto pair = item.toIntPair();
|
||||
return std::make_unique<IntPair>(pair.first, pair.second);
|
||||
}
|
||||
|
||||
std::unique_ptr<TagLib::StringList> Item_toStringList(const TagLib::MP4::Item& item) {
|
||||
return std::make_unique<TagLib::StringList>(item.toStringList());
|
||||
}
|
||||
|
||||
std::unique_ptr<TagLib::ByteVectorList> Item_toByteVectorList(const TagLib::MP4::Item& item) {
|
||||
return std::make_unique<TagLib::ByteVectorList>(item.toByteVectorList());
|
||||
}
|
||||
|
||||
std::unique_ptr<CoverArtList> Item_toCoverArtList(const TagLib::MP4::Item& item) {
|
||||
return std::make_unique<CoverArtList>(item.toCoverArtList());
|
||||
}
|
||||
|
||||
int64_t Item_toLongLong(const TagLib::MP4::Item& item) {
|
||||
return item.toLongLong();
|
||||
}
|
||||
}
|
|
@ -19,4 +19,41 @@ namespace taglib_shim {
|
|||
};
|
||||
|
||||
std::unique_ptr<std::vector<ItemMapEntry>> ItemMap_to_entries(const TagLib::MP4::ItemMap& map);
|
||||
|
||||
class IntPair {
|
||||
public:
|
||||
IntPair(int first, int second);
|
||||
int first() const;
|
||||
int second() const;
|
||||
|
||||
private:
|
||||
int first_;
|
||||
int second_;
|
||||
};
|
||||
|
||||
class CoverArt {
|
||||
public:
|
||||
CoverArt(TagLib::MP4::CoverArt::Format format, const TagLib::ByteVector& data);
|
||||
uint32_t format() const;
|
||||
std::unique_ptr<TagLib::ByteVector> data() const;
|
||||
|
||||
private:
|
||||
TagLib::MP4::CoverArt art_;
|
||||
};
|
||||
|
||||
class CoverArtList {
|
||||
public:
|
||||
CoverArtList(const TagLib::MP4::CoverArtList& list);
|
||||
std::unique_ptr<std::vector<CoverArt>> to_vector() const;
|
||||
|
||||
private:
|
||||
TagLib::MP4::CoverArtList list_;
|
||||
};
|
||||
|
||||
unsigned int Item_type(const TagLib::MP4::Item& item);
|
||||
std::unique_ptr<IntPair> Item_toIntPair(const TagLib::MP4::Item& item);
|
||||
std::unique_ptr<TagLib::StringList> Item_toStringList(const TagLib::MP4::Item& item);
|
||||
std::unique_ptr<TagLib::ByteVectorList> Item_toByteVectorList(const TagLib::MP4::Item& item);
|
||||
std::unique_ptr<CoverArtList> Item_toCoverArtList(const TagLib::MP4::Item& item);
|
||||
int64_t Item_toLongLong(const TagLib::MP4::Item& item);
|
||||
}
|
|
@ -32,4 +32,14 @@ namespace taglib_shim
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<std::vector<TagLib::ByteVector>> ByteVectorList_to_vector(const TagLib::ByteVectorList &list)
|
||||
{
|
||||
std::unique_ptr<std::vector<TagLib::ByteVector>> result = std::make_unique<std::vector<TagLib::ByteVector>>();
|
||||
for (const auto &vec : list)
|
||||
{
|
||||
result->push_back(vec);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,4 +30,6 @@ namespace taglib_shim
|
|||
|
||||
std::unique_ptr<std::vector<Property>> SimplePropertyMap_to_vector(const TagLib::SimplePropertyMap &map);
|
||||
std::unique_ptr<std::vector<TagLib::String>> StringList_to_vector(const TagLib::StringList &list);
|
||||
|
||||
std::unique_ptr<std::vector<TagLib::ByteVector>> ByteVectorList_to_vector(const TagLib::ByteVectorList &list);
|
||||
}
|
|
@ -220,6 +220,12 @@ mod bridge_impl {
|
|||
string_list: Pin<&CPPStringList>,
|
||||
) -> UniquePtr<CxxVector<CPPString>>;
|
||||
|
||||
#[namespace = "TagLib"]
|
||||
#[cxx_name = "ByteVectorList"]
|
||||
type CPPByteVectorList;
|
||||
#[namespace = "taglib_shim"]
|
||||
fn ByteVectorList_to_vector(list: Pin<&CPPByteVectorList>) -> UniquePtr<CxxVector<CPPByteVector>>;
|
||||
|
||||
#[namespace = "TagLib"]
|
||||
#[cxx_name = "ByteVector"]
|
||||
type CPPByteVector;
|
||||
|
@ -251,13 +257,78 @@ mod bridge_impl {
|
|||
#[namespace = "taglib_shim"]
|
||||
#[cxx_name = "ItemMapEntry"]
|
||||
type CPPItemMapEntry;
|
||||
fn key(self: Pin<&CPPItemMapEntry>) -> &CPPString;
|
||||
fn value(self: Pin<&CPPItemMapEntry>) -> &CPPMP4Item;
|
||||
fn key<'slf, 'file_ref>(self: Pin<&'slf CPPItemMapEntry>) -> &'file_ref CPPString;
|
||||
fn value<'slf, 'file_ref>(self: Pin<&'slf CPPItemMapEntry>) -> &'file_ref CPPMP4Item;
|
||||
|
||||
#[namespace = "TagLib::MP4"]
|
||||
#[cxx_name = "Item"]
|
||||
type CPPMP4Item;
|
||||
fn isValid(self: Pin<&CPPMP4Item>) -> bool;
|
||||
fn toBool(self: Pin<&CPPMP4Item>) -> bool;
|
||||
fn toInt(self: Pin<&CPPMP4Item>) -> i32;
|
||||
fn toByte(self: Pin<&CPPMP4Item>) -> u8;
|
||||
fn toUInt(self: Pin<&CPPMP4Item>) -> u32;
|
||||
|
||||
fn Item_type(item: Pin<&CPPMP4Item>) -> u32;
|
||||
#[namespace = "taglib_shim"]
|
||||
fn Item_toIntPair(item: Pin<&CPPMP4Item>) -> UniquePtr<CPPIntPair>;
|
||||
#[namespace = "taglib_shim"]
|
||||
fn Item_toStringList(item: Pin<&CPPMP4Item>) -> UniquePtr<CPPStringList>;
|
||||
#[namespace = "taglib_shim"]
|
||||
fn Item_toByteVectorList(item: Pin<&CPPMP4Item>) -> UniquePtr<CPPByteVectorList>;
|
||||
#[namespace = "taglib_shim"]
|
||||
fn Item_toCoverArtList(item: Pin<&CPPMP4Item>) -> UniquePtr<CPPCoverArtList>;
|
||||
#[namespace = "taglib_shim"]
|
||||
fn Item_toLongLong(item: Pin<&CPPMP4Item>) -> i64;
|
||||
|
||||
#[namespace = "taglib_shim"]
|
||||
#[cxx_name = "IntPair"]
|
||||
type CPPIntPair;
|
||||
fn first(self: Pin<&CPPIntPair>) -> i32;
|
||||
fn second(self: Pin<&CPPIntPair>) -> i32;
|
||||
|
||||
#[namespace = "taglib_shim"]
|
||||
#[cxx_name = "CoverArtList"]
|
||||
type CPPCoverArtList;
|
||||
fn to_vector(self: Pin<&CPPCoverArtList>) -> UniquePtr<CxxVector<CPPCoverArt>>;
|
||||
|
||||
#[namespace = "taglib_shim"]
|
||||
#[cxx_name = "CoverArt"]
|
||||
type CPPCoverArt;
|
||||
fn format(self: Pin<&CPPCoverArt>) -> u32;
|
||||
fn data(self: Pin<&CPPCoverArt>) -> UniquePtr<CPPByteVector>;
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum MP4ItemType {
|
||||
Void,
|
||||
Bool,
|
||||
Int,
|
||||
IntPair,
|
||||
Byte,
|
||||
UInt,
|
||||
LongLong,
|
||||
StringList,
|
||||
ByteVectorList,
|
||||
CoverArtList,
|
||||
}
|
||||
|
||||
impl MP4ItemType {
|
||||
pub fn from_u32(value: u32) -> Option<Self> {
|
||||
match value {
|
||||
0 => Some(Self::Void),
|
||||
1 => Some(Self::Bool),
|
||||
2 => Some(Self::Int),
|
||||
3 => Some(Self::IntPair),
|
||||
4 => Some(Self::Byte),
|
||||
5 => Some(Self::UInt),
|
||||
6 => Some(Self::LongLong),
|
||||
7 => Some(Self::StringList),
|
||||
8 => Some(Self::ByteVectorList),
|
||||
9 => Some(Self::CoverArtList),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -54,7 +54,6 @@ impl<'io_stream> DynIOStream<'io_stream> {
|
|||
pub fn write(&mut self, data: &[u8]) {
|
||||
self.0.write_all(data).unwrap();
|
||||
}
|
||||
|
||||
pub fn seek(&mut self, offset: i64, whence: i32) {
|
||||
let pos = match whence {
|
||||
0 => SeekFrom::Start(offset as u64),
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
pub use super::bridge::CPPMP4Tag;
|
||||
use super::bridge::{CPPItemMap, ItemMap_to_entries, CPPItemMapEntry};
|
||||
use super::bridge::{CPPItemMap, ItemMap_to_entries, CPPItemMapEntry, CPPMP4Item, MP4ItemType, CPPIntPair};
|
||||
use super::tk;
|
||||
use super::this::{OwnedThis, RefThis, RefThisMut, ThisMut, This};
|
||||
use std::collections::HashMap;
|
||||
|
@ -30,10 +30,10 @@ impl<'file_ref> ItemMap<'file_ref> {
|
|||
Self { this }
|
||||
}
|
||||
|
||||
pub fn to_hashmap(&self) -> HashMap<String, ()> {
|
||||
pub fn to_hashmap(&self) -> HashMap<String, MP4Item<'file_ref>> {
|
||||
let cxx_vec = ItemMap_to_entries(self.this.pin());
|
||||
cxx_vec
|
||||
.iter()
|
||||
let vec: Vec<(String, MP4Item<'file_ref>)> =
|
||||
cxx_vec.iter()
|
||||
.map(|property| {
|
||||
// SAFETY:
|
||||
// - This pin is only used in this unsafe scope.
|
||||
|
@ -45,9 +45,158 @@ impl<'file_ref> ItemMap<'file_ref> {
|
|||
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, ())
|
||||
|
||||
let value_ref = property_pin.value();
|
||||
let value_this = unsafe { RefThis::new(value_ref) };
|
||||
let value = MP4Item::new(value_this);
|
||||
|
||||
(key, value)
|
||||
})
|
||||
.collect();
|
||||
|
||||
HashMap::from_iter(vec)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MP4Item<'file_ref> {
|
||||
this: RefThis<'file_ref, CPPMP4Item>,
|
||||
}
|
||||
|
||||
impl<'file_ref> MP4Item<'file_ref> {
|
||||
pub fn new(this: RefThis<'file_ref, CPPMP4Item>) -> Self {
|
||||
Self { this }
|
||||
}
|
||||
|
||||
pub fn data(&self) -> Option<MP4Data<'file_ref>> {
|
||||
if !self.this.pin().isValid() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let item_type = MP4ItemType::from_u32(super::bridge::Item_type(self.this.pin()));
|
||||
item_type.and_then(|item_type| match item_type {
|
||||
MP4ItemType::Void => Some(MP4Data::Void),
|
||||
MP4ItemType::Bool => Some(MP4Data::Bool(self.this.pin().toBool())),
|
||||
MP4ItemType::Int => Some(MP4Data::Int(self.this.pin().toInt())),
|
||||
MP4ItemType::IntPair => {
|
||||
let pair = super::bridge::Item_toIntPair(self.this.pin());
|
||||
let pair_this = unsafe { OwnedThis::new(pair) };
|
||||
pair_this.map(|this| MP4Data::IntPair(IntPair::new(this)))
|
||||
},
|
||||
MP4ItemType::Byte => Some(MP4Data::Byte(self.this.pin().toByte())),
|
||||
MP4ItemType::UInt => Some(MP4Data::UInt(self.this.pin().toUInt())),
|
||||
MP4ItemType::LongLong => Some(MP4Data::LongLong(super::bridge::Item_toLongLong(self.this.pin()))),
|
||||
MP4ItemType::StringList => {
|
||||
let string_list = super::bridge::Item_toStringList(self.this.pin());
|
||||
let string_list_this = unsafe { OwnedThis::new(string_list) };
|
||||
string_list_this.map(|this| MP4Data::StringList(tk::StringList::new(this)))
|
||||
},
|
||||
MP4ItemType::ByteVectorList => {
|
||||
let byte_vector_list = super::bridge::Item_toByteVectorList(self.this.pin());
|
||||
let byte_vector_list_this = unsafe { OwnedThis::new(byte_vector_list) };
|
||||
byte_vector_list_this.map(|this| MP4Data::ByteVectorList(tk::ByteVectorList::new(this)))
|
||||
},
|
||||
MP4ItemType::CoverArtList => {
|
||||
let cover_art_list = super::bridge::Item_toCoverArtList(self.this.pin());
|
||||
let cover_art_list_this = unsafe { OwnedThis::new(cover_art_list) };
|
||||
cover_art_list_this.map(|this| MP4Data::CoverArtList(CoverArtList::new(this)))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CoverArtList<'file_ref> {
|
||||
this: OwnedThis<'file_ref, super::bridge::CPPCoverArtList>,
|
||||
}
|
||||
|
||||
impl<'file_ref> CoverArtList<'file_ref> {
|
||||
pub fn new(this: OwnedThis<'file_ref, super::bridge::CPPCoverArtList>) -> Self {
|
||||
Self { this }
|
||||
}
|
||||
|
||||
pub fn to_vec(&self) -> Vec<CoverArt> {
|
||||
let cover_arts = self.this.pin().to_vector();
|
||||
cover_arts
|
||||
.iter()
|
||||
.map(|ca| {
|
||||
let ca_pin = unsafe { Pin::new_unchecked(ca) };
|
||||
let format = CoverArtFormat::from_u32(ca_pin.format());
|
||||
let data = ca_pin.data();
|
||||
let data_this = unsafe { RefThis::new(&*data) };
|
||||
let data = tk::ByteVector::new(data_this).to_vec();
|
||||
CoverArt { format, data }
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IntPair<'file_ref> {
|
||||
this: OwnedThis<'file_ref, CPPIntPair>,
|
||||
}
|
||||
|
||||
impl<'file_ref> IntPair<'file_ref> {
|
||||
pub fn new(this: OwnedThis<'file_ref, CPPIntPair>) -> Self {
|
||||
Self { this }
|
||||
}
|
||||
|
||||
pub fn to_tuple(&self) -> Option<(i32, i32)> {
|
||||
let this = self.this.pin();
|
||||
let first = this.first();
|
||||
let second = this.second();
|
||||
Some((first, second))
|
||||
}
|
||||
}
|
||||
|
||||
pub enum MP4Data<'file_ref> {
|
||||
Void,
|
||||
Bool(bool),
|
||||
Int(i32),
|
||||
Byte(u8),
|
||||
UInt(u32),
|
||||
LongLong(i64),
|
||||
IntPair(IntPair<'file_ref>),
|
||||
StringList(tk::OwnedStringList<'file_ref>),
|
||||
ByteVectorList(tk::OwnedByteVectorList<'file_ref>),
|
||||
CoverArtList(CoverArtList<'file_ref>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct CoverArt {
|
||||
format: CoverArtFormat,
|
||||
data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl CoverArt {
|
||||
pub fn new(format: CoverArtFormat, data: Vec<u8>) -> Self {
|
||||
Self { format, data }
|
||||
}
|
||||
|
||||
pub fn format(&self) -> CoverArtFormat {
|
||||
self.format
|
||||
}
|
||||
|
||||
pub fn data(&self) -> &[u8] {
|
||||
&self.data
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum CoverArtFormat {
|
||||
Unknown,
|
||||
BMP,
|
||||
JPEG,
|
||||
GIF,
|
||||
PNG,
|
||||
}
|
||||
|
||||
impl CoverArtFormat {
|
||||
fn from_u32(value: u32) -> Self {
|
||||
match value {
|
||||
0 => CoverArtFormat::Unknown,
|
||||
1 => CoverArtFormat::BMP,
|
||||
2 => CoverArtFormat::JPEG,
|
||||
3 => CoverArtFormat::GIF,
|
||||
4 => CoverArtFormat::PNG,
|
||||
_ => CoverArtFormat::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use super::bridge::{self, CPPByteVector, CPPString, CPPStringList};
|
||||
use super::bridge::{self, CPPByteVector, CPPByteVectorList, CPPString, CPPStringList};
|
||||
use super::this::{RefThis, RefThisMut, This, OwnedThis};
|
||||
use cxx::{memory::UniquePtrTarget, UniquePtr};
|
||||
use std::marker::PhantomData;
|
||||
|
@ -94,3 +94,27 @@ impl<'file_ref, T: This<'file_ref, CPPByteVector>> ByteVector<'file_ref, T> {
|
|||
pub type OwnedByteVector<'file_ref> = ByteVector<'file_ref, OwnedThis<'file_ref, CPPByteVector>>;
|
||||
pub type RefByteVector<'file_ref> = ByteVector<'file_ref, RefThis<'file_ref, CPPByteVector>>;
|
||||
pub type RefByteVectorMut<'file_ref> = ByteVector<'file_ref, RefThisMut<'file_ref, CPPByteVector>>;
|
||||
|
||||
pub struct ByteVectorList<'file_ref, T: This<'file_ref, CPPByteVectorList>> {
|
||||
_data: PhantomData<&'file_ref CPPByteVectorList>,
|
||||
this: T,
|
||||
}
|
||||
|
||||
impl<'file_ref, T: This<'file_ref, CPPByteVectorList>> ByteVectorList<'file_ref, T> {
|
||||
pub(super) fn new(this: T) -> Self {
|
||||
Self { _data: PhantomData, this }
|
||||
}
|
||||
|
||||
pub fn to_vec(&self) -> Vec<Vec<u8>> {
|
||||
let cxx_values = bridge::ByteVectorList_to_vector(self.this.pin());
|
||||
cxx_values
|
||||
.iter()
|
||||
.map(|value| ByteVector::new(unsafe { RefThis::new(value) }).to_vec())
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
pub type OwnedByteVectorList<'file_ref> = ByteVectorList<'file_ref, OwnedThis<'file_ref, CPPByteVectorList>>;
|
||||
pub type RefByteVectorList<'file_ref> = ByteVectorList<'file_ref, RefThis<'file_ref, CPPByteVectorList>>;
|
||||
pub type RefByteVectorListMut<'file_ref> = ByteVectorList<'file_ref, RefThisMut<'file_ref, CPPByteVectorList>>;
|
||||
|
||||
|
|
Loading…
Reference in a new issue