From cbbec08db62996dbde658f78a31b4e0fe59a2570 Mon Sep 17 00:00:00 2001 From: lifegpc Date: Fri, 13 May 2022 15:25:27 +0800 Subject: [PATCH] Update exif module --- avdict/CMakeLists.txt | 1 + build.rs | 1 + exif/exif.h | 9 +++- exif/src/exif.cpp | 40 +++++++++++++--- exif/src/exif_priv.h | 5 ++ src/exif.rs | 109 +++++++++++++++++++++++++++++++++--------- src/ext/rawhandle.rs | 14 ++++++ ugoira/CMakeLists.txt | 1 + 8 files changed, 149 insertions(+), 31 deletions(-) diff --git a/avdict/CMakeLists.txt b/avdict/CMakeLists.txt index f409c13..84842b0 100644 --- a/avdict/CMakeLists.txt +++ b/avdict/CMakeLists.txt @@ -13,6 +13,7 @@ include(GetLinkLibraries) find_package(AVUTIL REQUIRED) add_library(avdict STATIC avdict.h src/avdict.c) +include_directories("${AVUTIL_INCLUDE_DIRS}") target_link_libraries(avdict AVUTIL::AVUTIL) target_compile_definitions(avdict PRIVATE -DBUILD_AVDICT) diff --git a/build.rs b/build.rs index 176ca9d..f49541f 100644 --- a/build.rs +++ b/build.rs @@ -136,6 +136,7 @@ fn main() { // Tell cargo to invalidate the built crate whenever any of the // included header files changed. .parse_callbacks(Box::new(bindgen::CargoCallbacks)) + .no_copy("ExifDataRef") // Finish the builder and generate the bindings. .generate() // Unwrap the Result and panic on failure. diff --git a/exif/exif.h b/exif/exif.h index e4614a6..cbbe478 100644 --- a/exif/exif.h +++ b/exif/exif.h @@ -15,6 +15,8 @@ typedef struct ExifValue ExifValue; typedef struct ExifData ExifData; ///
typedef struct ExifDatum ExifDatum; +///
+typedef struct ExifDataRef ExifDataRef; #if defined _WIN32 && defined WIN32_DLL #if BUILD_DLL #define EXIF_API __declspec(dllexport) @@ -26,6 +28,7 @@ typedef struct ExifDatum ExifDatum; #endif EXIF_API ExifImage* create_exif_image(const char* path); +EXIF_API const ExifDataRef* exif_image_get_exif_data(ExifImage* image); EXIF_API int exif_image_set_exif_data(ExifImage* image, ExifData* data); EXIF_API int exif_image_write_metadata(ExifImage* image); EXIF_API void free_exif_image(ExifImage* img); @@ -54,8 +57,10 @@ EXIF_API int64_t exif_value_to_int64(ExifValue* value, long i); EXIF_API ExifData* exif_data_new(); EXIF_API int exif_data_add(ExifData* d, ExifKey* key, ExifValue* value); EXIF_API int exif_data_clear(ExifData* d); -EXIF_API int exif_data_is_empty(ExifData* d); -EXIF_API long exif_data_get_count(ExifData* d); +EXIF_API const ExifDataRef* exif_data_get_ref(ExifData* d); +EXIF_API ExifData* exif_data_ref_clone(ExifDataRef* d); +EXIF_API int exif_data_ref_is_empty(ExifDataRef* d); +EXIF_API long exif_data_ref_get_count(ExifDataRef* d); EXIF_API void exif_free_value(ExifValue* value); EXIF_API void exif_free_data(ExifData* d); EXIF_API void exif_free_datum(ExifDatum* d); diff --git a/exif/src/exif.cpp b/exif/src/exif.cpp index d7338a8..707917c 100644 --- a/exif/src/exif.cpp +++ b/exif/src/exif.cpp @@ -24,6 +24,12 @@ end: return nullptr; } +const ExifDataRef* exif_image_get_exif_data(ExifImage* image) { + if (!image || !image->image) return nullptr; + image->exif_data_ref.data = &image->image->exifData(); + return &image->exif_data_ref; +} + int exif_image_set_exif_data(ExifImage* image, ExifData* data) { if (!image || !data) return 1; image->image->setExifData(data->data); @@ -230,14 +236,36 @@ int exif_data_clear(ExifData* d) { return 1; } -int exif_data_is_empty(ExifData* d) { - if (!d) return -1; - return d->data.empty() ? 1 : 0; +const ExifDataRef* exif_data_get_ref(ExifData* d) { + if (!d) return nullptr; + d->ref.data = &d->data; + return &d->ref; } -long exif_data_get_count(ExifData* d) { - if (!d) return -1; - return d->data.count(); +ExifData* exif_data_ref_clone(ExifDataRef* d) { + if (!d || !d->data) return nullptr; + auto n = new ExifData; + if (!n) return nullptr; + try { + for (auto i = d->data->begin(); i != d->data->end(); ++i) { + n->data.add(*i); + } + } catch (std::exception& e) { + printf("%s\n", e.what()); + delete n; + return nullptr; + } + return n; +} + +int exif_data_ref_is_empty(ExifDataRef* d) { + if (!d || !d->data) return -1; + return d->data->empty() ? 1 : 0; +} + +long exif_data_ref_get_count(ExifDataRef* d) { + if (!d || !d->data) return -1; + return d->data->count(); } void exif_free_value(ExifValue* value) { diff --git a/exif/src/exif_priv.h b/exif/src/exif_priv.h index 296684e..67789e9 100644 --- a/exif/src/exif_priv.h +++ b/exif/src/exif_priv.h @@ -1,8 +1,12 @@ #ifndef _EXIF_EXIF_PRIV_H #define _EXIF_EXIF_PRIV_H #include "exiv2/exiv2.hpp" +typedef struct ExifDataRef { + const Exiv2::ExifData* data = nullptr; +} ExifDataRef; typedef struct ExifImage { Exiv2::Image::UniquePtr image; + ExifDataRef exif_data_ref; } ExifImage; typedef struct ExifKey { Exiv2::ExifKey* key = nullptr; @@ -12,6 +16,7 @@ typedef struct ExifValue { } ExifValue; typedef struct ExifData { Exiv2::ExifData data; + ExifDataRef ref; } ExifData; typedef struct ExifDatum { Exiv2::Exifdatum* data; diff --git a/src/exif.rs b/src/exif.rs index 8fc9362..c20cc65 100644 --- a/src/exif.rs +++ b/src/exif.rs @@ -1,7 +1,12 @@ use crate::_exif; +use crate::_exif::ExifDataRef; +use crate::ext::rawhandle::FromRawHandle; use crate::ext::rawhandle::ToRawHandle; use c_fixed_string::CFixedStr; use int_enum::IntEnum; +use std::borrow::Borrow; +use std::borrow::ToOwned; +use std::clone::Clone; use std::convert::TryFrom; use std::ffi::CStr; use std::ffi::CString; @@ -10,6 +15,7 @@ use std::ffi::OsStr; use std::fs::copy; #[cfg(test)] use std::fs::create_dir; +use std::ops::Deref; use std::ops::Drop; use std::os::raw::c_long; use std::path::Path; @@ -500,6 +506,10 @@ impl ExifData { Ok(Self { data: d }) } + pub unsafe fn from_raw_pointer(data: *mut _exif::ExifData) -> Self { + Self { data } + } + /// Add a data from the supplied key and value pair. /// No duplicate checks are performed, i.e., it is possible to add multiple metadata with the same key. pub fn add(&mut self, key: &ExifKey, value: &ExifValue) -> Result<(), ()> { @@ -529,32 +539,18 @@ impl ExifData { Ok(()) } } +} - /// Get the number of metadata entries. - pub fn count(&self) -> Option { - if self.data.is_null() { - return None; - } - let r = unsafe { _exif::exif_data_get_count(self.data) }; - if r == -1 { - return None; - } - Some(r as usize) +impl Borrow for ExifData { + fn borrow(&self) -> &ExifDataRef { + self.deref() } +} - /// Return true if there is no Exif metadata. - pub fn empty(&self) -> Option { - if self.data.is_null() { - return None; - } - let r = unsafe { _exif::exif_data_is_empty(self.data) }; - if r == -1 { - None - } else if r == 0 { - Some(false) - } else { - Some(true) - } +impl Deref for ExifData { + type Target = ExifDataRef; + fn deref(&self) -> &Self::Target { + unsafe { ExifDataRef::from_const_handle(_exif::exif_data_get_ref(self.to_raw_handle())) } } } @@ -572,6 +568,61 @@ impl ToRawHandle<_exif::ExifData> for ExifData { } } +#[allow(dead_code)] +impl ExifDataRef { + /// Get the number of metadata entries. + pub fn count(&self) -> Option { + let data = unsafe { self.to_raw_handle() }; + if data.is_null() { + return None; + } + let r = unsafe { _exif::exif_data_ref_get_count(data) }; + if r == -1 { + return None; + } + Some(r as usize) + } + /// Return true if there is no Exif metadata. + pub fn empty(&self) -> Option { + let data = unsafe { self.to_raw_handle() }; + if data.is_null() { + return None; + } + let r = unsafe { _exif::exif_data_ref_is_empty(data) }; + if r == -1 { + None + } else if r == 0 { + Some(false) + } else { + Some(true) + } + } +} + +impl ToOwned for ExifDataRef { + type Owned = ExifData; + fn to_owned(&self) -> Self::Owned { + let o = unsafe { self.to_raw_handle() }; + if o.is_null() { + return ExifData::new().unwrap(); + } + let r = unsafe { _exif::exif_data_ref_clone(o) }; + if r.is_null() { + panic!("Failed to convert ExifDataRef to ExifData."); + } + unsafe { ExifData::from_raw_pointer(r) } + } +} + +impl ToRawHandle for ExifDataRef { + unsafe fn to_raw_handle(&self) -> *mut ExifDataRef { + self.to_const_handle() as *mut ExifDataRef + } + unsafe fn to_const_handle(&self) -> *const ExifDataRef { + self + } +} + pub struct ExifImage { img: *mut _exif::ExifImage, } @@ -600,6 +651,17 @@ impl ExifImage { Ok(Self { img: f }) } + pub fn exif_data(&self) -> Option<&ExifDataRef> { + if self.img.is_null() { + return None; + } + let d = unsafe { _exif::exif_image_get_exif_data(self.img) }; + if d.is_null() { + return None; + } + unsafe { Some(ExifDataRef::from_const_handle(d)) } + } + pub fn set_exif_data(&mut self, data: &ExifData) -> Result<(), ()> { if self.img.is_null() { return Err(()); @@ -715,6 +777,7 @@ fn test_exif_image() { { let mut img = ExifImage::new(target).unwrap(); img.set_exif_data(&d).unwrap(); + assert_eq!(img.exif_data().unwrap().count(), Some(1)); img.write_metadata().unwrap(); } } diff --git a/src/ext/rawhandle.rs b/src/ext/rawhandle.rs index 41d3f67..c4e8dd0 100644 --- a/src/ext/rawhandle.rs +++ b/src/ext/rawhandle.rs @@ -8,3 +8,17 @@ pub trait ToRawHandle { self.to_raw_handle() as *const T } } + +pub trait FromRawHandle { + unsafe fn from_raw_handle<'a>(ptr: *mut T) -> &'a mut Self; + unsafe fn from_const_handle<'a>(ptr: *const T) -> &'a Self; +} + +impl FromRawHandle for T { + unsafe fn from_raw_handle<'a>(ptr: *mut T) -> &'a mut Self { + &mut *(ptr) + } + unsafe fn from_const_handle<'a>(ptr: *const Self) -> &'a Self { + &*(ptr) + } +} diff --git a/ugoira/CMakeLists.txt b/ugoira/CMakeLists.txt index d7586eb..44cdce5 100644 --- a/ugoira/CMakeLists.txt +++ b/ugoira/CMakeLists.txt @@ -40,6 +40,7 @@ src/ugoira.c include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../utils") include_directories("${CMAKE_CURRENT_BINARY_DIR}") +include_directories("${AVUTIL_INCLUDE_DIRS}") add_library(ugoira STATIC "${UGOIRA_FILES}") target_link_libraries(ugoira AVUTIL::AVUTIL AVFORMAT::AVFORMAT AVCODEC::AVCODEC SWSCALE::SWSCALE LIBZIP::LIBZIP ${UTILS_TARGET})