-
Notifications
You must be signed in to change notification settings - Fork 278
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pull Request to integrate read only HEIF support in Exiv2 using libheif #1044
Conversation
Why are you including libheif in this? |
See my comments in #318... |
Codecov Report
@@ Coverage Diff @@
## master #1044 +/- ##
==========================================
- Coverage 71.24% 71.24% -0.01%
==========================================
Files 148 148
Lines 19457 19456 -1
==========================================
- Hits 13862 13861 -1
Misses 5595 5595
Continue to review full report at Codecov.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the contribution!
In general it looks good to me, but as I mentioned before, I do not like the idea of adding source code to an external library inside our repository. The main reason for that is that we could not upgrade easily to more recent versions of the library by just requiring a more recent version of it.
I will work during the next days in a conan recipe for this project so that we can consume the library easily. I expect to come back with some feedback, at the latest, this Sunday.
src/CMakeLists.txt
Outdated
@@ -10,6 +10,7 @@ include(CMakePackageConfigHelpers) | |||
|
|||
include_directories(${CMAKE_CURRENT_BINARY_DIR}) | |||
|
|||
include(libheif/LibHeifRules.cmake) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really appreciate the contribution but I am against including the libheif source code into the Exiv2 repository.
Since we have a good support for handling external dependencies via conan for all the platforms and compilers, I propose to create a conan package for libheif that could be consumed by Exiv2 or other projects. We already have an old version of XMP inside our repository and we offer the opportunity of updating to newer version of XMP via conan.
This is going to be a rainy weekend in my city, so I offer my help to take care of that 😸
// ***************************************************************************** | ||
|
||
// included header files | ||
#include "image_int.hpp" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other image headers such as jp2image.hpp
include the header image.hpp
where the class Image
is defined. When opening this file in an IDE, I get lot of errors from the clang static analyser regarding files not found.
Furthermore, It looks like this file should be named heifimage.hpp
without the _int
suffix , and be moved to the folder include/exiv2
in order to be deployed together with the other supported file format headers.
throw(Error(kerInvalidSettingForImage, "Image comment", "HEIF")); | ||
} // HeifImage::setComment | ||
|
||
void HeifImage::readMetadata() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[suggestion] This function has almost 200 LoC. Would it be possible to extract some blocks of code into separated private methods or functions?
CHECK_INCLUDE_FILE(unistd.h HAVE_UNISTD_H) | ||
|
||
if(HAVE_INTTYPES_H) | ||
add_definitions(-DHAVE_INTTYPES_H) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned previously I am against adding libheif directly in our repository. Another argument for that is that this cmake file is adding definitions and include directories globally to the project (instead of doing so to a specific target or source files).
src/heifimage_int.hpp
Outdated
@@ -26,8 +26,6 @@ | |||
*/ | |||
#pragma once | |||
|
|||
#include <libheif/heif.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am definitely against bundling yet another library into exiv2's code base: we already bundle the xmpsdk and an INI parser. Also, if we bundle libheif, then we'll make packaging exiv2 extremely painful, as libheif is considered a no-go for many Linux distributions (you won't find it in Fedora for legal reasons and they got a dedicated legal team...). By bundling it, packagers will have to manually remove libheif, which is not a nice thing to do from our side.
Other general comments:
- commit f46967d is already on master, no need to include it here
- please drop the merge commits and rebase+squash the
polish
commits - please restore the original history from @1div0's branch, so that his edits are visible
- there is a lot of changes in
po/nl.po
that look completely unrelated to this PR, please consider to resubmit them in a different PR or drop them - no tests at all
// Read Exif chunk. | ||
|
||
size_t data_size = heif_image_handle_get_metadata_size(handle, dataIds[i]); | ||
uint8_t* const data = (uint8_t*) alloca(data_size); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please never ever use alloca
, not even in plain C projects.
|
||
} | ||
|
||
heif_image_handle_release(handle); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So unless this function returns cleanly, we get a leak?
|
||
} // HeifImage::readMetadata | ||
|
||
void HeifImage::printStructure(std::ostream& /*out*/, PrintStructureOption /*option*/, int /*depth*/) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the point of this function beside just throwing exceptions? If that's the point, then please rename it.
|
||
} // HeifImage::writeMetadata | ||
|
||
void HeifImage::doWriteMetadata(BasicIo& outIo) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[question] Do I understand it correctly that all this function does is write the HEIF header?
#ifdef EXIV2_DEBUG_MESSAGES | ||
std::cout << "Exiv2::HeifImage::isHeifType() = " << matched << std::endl; | ||
#endif | ||
if (!advance || !matched) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So if advance
is true
and there is a match, you'd still seek back. Is that intended?
(data[2] << 8) | | ||
data[3]) + 4; | ||
|
||
if (data_size > (size_t)skip) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (data_size > (size_t)skip) | |
if (data_size > static_cast<size_t>(skip)) |
int skip = ((data[0] << 24) | | ||
(data[1] << 16) | | ||
(data[2] << 8) | | ||
data[3]) + 4; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This addition can overflow. Also, please add a sanity check for skip
, this value can be anything.
std::cerr << "Exiv2::HeifImage:: HEIF exif container found with size:" << data_size - skip << std::endl; | ||
#endif | ||
|
||
// hexdump (std::cerr, data, data_size); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// hexdump (std::cerr, data, data_size); |
if ( | ||
(std::string(heif_image_handle_get_metadata_type(handle, dataIds[i])) == std::string("mime")) && | ||
(std::string(heif_image_handle_get_metadata_content_type(handle, dataIds[i])) == std::string("application/rdf+xml")) | ||
) | ||
{ | ||
// Read Xmp chunk. | ||
|
||
size_t data_size = heif_image_handle_get_metadata_size(handle, dataIds[i]); | ||
uint8_t* const data = (uint8_t*) alloca(data_size); | ||
err = heif_image_handle_get_metadata(handle, dataIds[i], data); | ||
|
||
if (err.code) | ||
{ | ||
#ifdef EXIV2_DEBUG_MESSAGES | ||
std::cerr << "Exiv2::HeifImage::readMetadata: " << err.message << std::endl; | ||
#endif | ||
throw Error(kerFailedToReadImageData); | ||
} | ||
|
||
#ifdef EXIV2_DEBUG_MESSAGES | ||
std::cerr << "Exiv2::HeifImage:: HEIF Xmp container found with size:" << data_size << std::endl; | ||
#endif | ||
|
||
xmpPacket_.assign(reinterpret_cast<char *>(data), data_size); | ||
std::string::size_type idx = xmpPacket_.find_first_of('<'); | ||
|
||
if (idx != std::string::npos && idx > 0) | ||
{ | ||
#ifndef SUPPRESS_WARNINGS | ||
EXV_WARNING << "Removing " << static_cast<uint32_t>(idx) | ||
<< " characters from the beginning of the Xmp packet" << std::endl; | ||
#endif | ||
xmpPacket_ = xmpPacket_.substr(idx); | ||
} | ||
|
||
if (xmpPacket_.size() > 0 && XmpParser::decode(xmpData_, xmpPacket_)) | ||
{ | ||
#ifndef SUPPRESS_WARNINGS | ||
EXV_WARNING << "Failed to decode Xmp metadata." << std::endl; | ||
#endif | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[suggestion] This section bears quite some similarities to the previous and the following one. I'd consider refactoring it to remove the duplication.
First piece of work in progress to improve the libheif CMake code, so that we can generate a clean conan recipe for it: strukturag/libheif#168 |
The first versions of the conan package are available here: Please, let me know if you want to give it a try by yourself or if you need my help to incorporate these changes. |
@cgilles Do you plan to work on this further? |
We are kind of blocked here until the changes I proposed in libheif are merged (It seems that the maintainers of the project have been a bit idle the last weeks): Afterwards, I will need to revisit the conan package I wrote for that. |
FYI: I've fixed libheif and 1.6.1 works correctly, however HEIF is a patent minefield. |
HEIF may be a patent minefield however that doesn't mean that reading the metadata from HEIF involves patents. I believe the file-format is ISOBMFF (ISO Base Media File Format ISO/IEC 14496-12). Reading ISOBMFF cannot involve patent infringement. Decoding the embedded data blocks could involve patents, however metadata blocks (Exif, IPTC, ICC and XMP) are also public standards which do not involve patents. I'm unclear about the libraries being linked by Exiv2 to undertake reading the file. Providing support to use another library cannot be a patent infringement by Exiv2. The dependent library may infringe patents (for example, to decode compressed data), however providing support in Exiv2 to link that library is not a patent infringement. |
Using libheif is fine, but none of the Linux distributions will package it and thus exiv2 wont have support for HEIF files. Which isn't that bad, as image viewer wont have support either :-) I'm pushing for AVIF as this is much more likely the next image codec to be widely used. Even Apple joined AOMedia. |
Linux Mageia7 : libheif is present de facto... |
I'd love if it were like that, but unfortunately law is not that simple :( I've been told that if you even modify your own library to link against a library that infringes patents, you're putting yourself at risk. So while libheif claims that they don't infringe patents, that hasn't been verified by a lawyer and by supporting linking against it, we risk getting removed from Linux distros that are more restrictive with respect to licensing (Fedora, Debian, openSUSE, etc.) |
You're right. Exiv2 could be booted out the distros and we don't want that to happen. If we had our own code to read ISOBMFF we would avoid HEIF patent issues. It's possible we already have code for another format (eg JP2) that only needs a little tweak. |
A small addition to an MP4 parser gives you HEIF support |
A general solution would be better as it can be use with AVIF too. So if you have a MP4 parser already and could extend it, then you can support HEIF and AVIF without linking in more libraries. |
When I investigated CR3 (about 2 years ago), I discovered a GitHub repos for isobmffdump by pyke359. His code is short and to the point. https://github.com/pyke369/isobmffdump I invited him to join Team Exiv2 with the following reply: pyke369/isobmffdump#1 (comment)
Here it's in action on some HEIF sample files:
I believe the Exif, XMP, ICC and IPTC data blocks are stored in the mdat box/atom. The file IMG1.HEIC has Exif metadata (including GPS data) which I can see with Preview.app on the Mac. The GPS data is Lausanne, Switzerland. Curious, eh, @piponazo ? I can see the Exif data with my file dump utility:
So it's buried in the mdat that starts at 4374 (of length 848580). I don't think we're far off being able to extract the Exif data and parse it in Exiv2. I'm stuck in a hotel in Sydney, Australia and it's raining hard outside (60mm today). Maybe I'll investigate this while I'm stuck. |
@clanmills nJoy your trip. Flown by A380? |
Singapore Boeing 777 LHR->SIN->SYD. Will visit Tuan and family in Singapore on the return. Tuan was a GSoC Student with Exiv2 in 2013. We may have to isolate ourselves when we get home because of this virus. |
@cgilles We will do further work on this PR and will adopt a new approach to HEIF. #1066 The Exiv2 v0.27.3 is on track to ship on 2020-06-30. Exiv2 v0.27.3 RC1 will ship on 2020-04-30 and is expected to include support for HEIF. |
Topic: Exiv2 and ISOBMFF Support Join Zoom Meeting Meeting ID: 821 3673 0279 |
Ey @clanmills , did you organise that meeting with more people? Honestly I did not follow up the discussion about the topic but I would like to hear more about it. If I am not riding my bike that day I will try to show up in the meeting 😉 |
Thanks @piponazo. The meeting is open to anybody who shows up. I've put the invitation on every issue involving ISOBMFF and HEIF. I decided to cancel #1066 in response to criticism from both @D4N and @phako. The subject has not gone away. The only feedback I've had about Exiv2 v0.27.3 RCs are dozens of emails every day asking "what is the legal problem with reading ISOBMFF?". |
See my progress described in bug #318
Best
Gilles Caulier