Repository navigation
Question about compile & usage on iOS/macOS platform #16
Description
Hello. I'm a iOS developer and recently I'm build a iOS-library which integrate libheif to a third-party lib SDWebImageHEIFCoder. Which support HEIF/HEIC decoding in old version iOS/macOS firmware. (Since iOS 11 & macOS 10.13 support HEIC natively)
But since I'm not an expert in image processing field, here are some questions I faced during the development. Some questions may be silly and I hope this will not bother someone :)
Readme
It seems some part of Readme is out-of-date.
heif_context_new_heicthis API is not available now. Maybe we can update the demo code about encoding ?frame-parallelbranch described in the compile part seems out-of-date. I try this branch of libde265 but this can't compile with themasterbranch of libheif or latest v1.1.0 tag. So I then use the latest v1.0.3 tag of libde265 with v1.1.0 libheif tag to compile to iOS/macOS platform.
Compile
I find that your're also the maintainer of libde265, So I put the question here.
To compile to iOS platform, I'm using Cmake with ios-cmake. For macOS, just using the official Cmake. All of following problem is about Cmake compile issue. (Not using autoconf)
- libde265
masterbranch or latest tag can not compile with the build-in config. It seems this APImemalignis not availble on macOS & iOS platform.
I solve this by passing -DHAVE_POSIX_MEMALIGN flag to Cmake to use posix_memalign instead. However, since Cmake support feature detect, maybe this flag can be automatically config instead of manual set?
- libde265
masterbranch or latest tag can not compile with the build-in config. It seems the SSE4.1 detect cause some issue. See the log here:
[ 34%] Building CXX object libde265/x86/CMakeFiles/x86_sse.dir/sse-motion.cc.o
/Users/lizhuoli/Documents/GitHub/libde265/libde265/x86/sse-motion.cc:746:29: error:
always_inline function '_mm_packus_epi32' requires target feature
'sse4.1', but would be inlined into function
'ff_hevc_weighted_pred_avg_8_sse4' that is compiled without support for
'sse4.1'
r0 = _mm_packus_epi32(r0, r2);
^
/Users/lizhuoli/Documents/GitHub/libde265/libde265/x86/sse-motion.cc:747:29: error:
always_inline function '_mm_packus_epi32' requires target feature
'sse4.1', but would be inlined into function
'ff_hevc_weighted_pred_avg_8_sse4' that is compiled without support for
'sse4.1'
r1 = _mm_packus_epi32(r1, r3);
I solve this by passing -DDISABLE_SSE flag to Cmake to disable it. However, since ARM64 support SSE4.1, I guess this is not a good solution.
Usage
After I compile the binary for iOS & macOS platform and start using libheif. Though I can successfully run the demo and see the HEIF image decoding works. But there are some question I want to know.
-
Does libheif support progressive/Incremental image decoding ? Because my lib is a plugin to an image loading system, which support rendering partial image during large image download.
-
libheif's this encoding API
heif_context_writeseems a little wired. I think this may be some misunderstanding from me but libheif library (See the code comments below). I use this API to write the encoded heif data to a memory representation but not file.
static struct heif_error WriteImageData(struct heif_context* ctx,
const void* data, size_t size, void* userdata) {
__autoreleasing NSData **imageData = (__autoreleasing NSData **)userdata;
NSCParameterAssert(imageData);
heif_error error;
if (!data) {
// Can this rgba data be NULL ?
// And how can I get the error information about this because there are no public API or input arg to grab the error information
error.code = heif_error_Encoder_plugin_error;
return error;
}
*imageData = [NSData dataWithBytes:data length:size];
error.code = heif_error_Ok;
return error;
}
// test code
void test() {
NSData *data;
heif_writer *writer;
writer->writer_api_version = 1;
writer->write = WriteImageData; // This is a function pointer
error = heif_context_write(ctx, writer, &data);
}
Activity
[-]Question about compile & usage[/-][+]Question about compile & usage on iOS/macOS platform[/+]dreampiggy commentedon May 9, 2018
Another question. After I try to integrate the libx265 and libheif to support HEIF encoding, I find a really strange issue about this
heif_image_add_planeAPI.It looks like
heif_image_add_planewill modify some memory outside addreess and cause issue. This demo code show the result. After that line of function call, a external variable (not related to libheif all of class) was modified.The two preview of image (Xcode's feature to view the debug image) show that the original
CGImageRefinternal storage was modified by the heif function call.Before:
After:
farindk commentedon May 9, 2018
Concerning your invalid memory access. My guess is that it is because of this line:
heif_image_add_plane(img, heif_channel_interleaved, width, height, 24);When the image has an alpha channel, you should allocate 32 bits per pixel instead of only 24.
Concerning
No, ARM64 does not support SSE. SSE is Intel x86 only. You are mixing this up with ARM64's NEON.
Currently, it does not. Maybe I will add this later at least for tiled images, but we first have to see if there is a real need for it.
Basically, you are doing things right. 'data' will never be null, so you can skip that test. However, you will have to take care that the write-callback can be called several times for an image.
Actually, the 'frame-parallel' branch is the newer branch, which will become libde265 version 2. The API is not stable yet, however. libheif should also understand the version 2 API, but it might be that I broke things a bit since I am still making changes to libde265 version 2.
PS: I will take care of the other issues later.
dreampiggy commentedon May 9, 2018
@farindk Thanks for your reply. I'll try to figure out the encoding issue again. (Maybe I need to use 4 planar channel with R/G/B/A instead of that
heif_channel_interleaved).I recently find this libheif repo and want to have a try. It seems that this repo is still during quick development. I'll follow the changes for it. :)
farindk commentedon May 9, 2018
heif_channel_interleavedis ok, you just have to adjust the number of bits like this:heif_image_add_plane(image, heif_channel_interleaved, width, height, has_alpha ? 32 : 24);dreampiggy commentedon May 9, 2018
@farindk Actually...The previous code I use
bitsPerPixel(For non-alpha is 24) to feedbit_deptharg. However, that still no luck.Here I grab the internal bitmap data stored in CGImageRef, run again and using lldb to print the result. After that function call (using Step Over), the bitmap data was modified. (See the output in the bottom right of Xcode). Quite strange....That
uint8_t *rgbaorCGImageRefvariable even not been passed to any function call of libheif.farindk commentedon May 9, 2018
You can try using an address sanitizer tool (e.g., valgrind, ...) to check where the memory is actually modified.
dreampiggy commentedon May 9, 2018
It seems that
std::vector's resize cause this issue ? (I update my project to use the source code instead of compiled framework)After
resizewas called, the original imageRef's internal bitmap vector from the call stack was modified...dreampiggy commentedon May 9, 2018
OK...I got it works. After I convert the original image to RGB888/RGBA8888 before call
heif_image_add_plane, and test again. It now works...And there are no memory address issue. Though this is a little strange. 😅And one interesting thing, during my experience, I found that there are no ways to manual add R/G/B/A 4 planar to do HEIC encoding. Because of current HEVC only support YCbCr420, and it will try to convert RGBA to YCbCr. However, during convert, it does not check
heif_channel_R, but only assumeheif_channel_interleaved. Like this:dreampiggy commentedon May 9, 2018
But however, thanks for your reply. Now I can successful decoding/encoding HEIC in macOS & iOS platform without the dependency of Apple :)
dreampiggy commentedon May 10, 2018
And maybe another small question. Is there any public API to detect the current registered decoder/encoder plugin ? Sometime I need to check whether specify type is availble and then to provide the image data to decode.
farindk commentedon May 10, 2018
You can list all encoders with heif_context_get_encoder_descriptors().
There is currently no way to check the available decoder codecs, you will simply get a heif_suberror_Unsupported_codec error when you try to decode an image that is not supported.
I am not sure whether it makes sense to provide such an API for the decoder, since you would have to parse the HEIF file yourself to see what format is used and ask libheif for decoder support.
If you have a convincing use-case for that, I might reconsider, though.
farindk commentedon May 22, 2018
Updated the example code.
heif_context_new_heicis not required anymore.Any further point that from here that needs taken care of? Otherwise, I will close this issue.
BTW: in the future, please open a separate thread for each issue. That is much easier to track.
dreampiggy commentedon May 23, 2018
@farindk Thanks for your reply. Now the above questions has been solved. I'll close this issue :)
parcool commentedon Jul 24, 2023
@dreampiggy Hello, I'm encountering many issues while compiling and cannot successfully compile. My source code, toolchain, Xcode SDK, and macOS system are all up-to-date. I'm really at a loss on how to proceed with the compilation. Could you please share your compilation parameters with me? Thank you.
dreampiggy commentedon Jul 25, 2023
Just be stupid and use my intergration with Xcode : https://github.com/SDWebImage/libheif-Xcode
This use C implementation on macOS x86_64, NEON on arm64, it's fast enough.
parcool commentedon Jul 25, 2023
@dreampiggy Thank you for your response, but it seems the link you provided is for an iOS project? What I have here is a pure C++ project. The ultimate goal is to modify it and export it as an iOS dynamic library, and I'm not sure how to use it.
dreampiggy commentedon Jul 25, 2023
It's not only iOS.
It's macOS iOS tvOS watchOS or even visionOS, all Apple OS
You can just open that and compile to binary ( change the MACHO_LIB_TYPE to statclib if you need) and then integrate to you other project.
parcool commentedon Jul 25, 2023
@dreampiggy First of all, thank you! I am not an iOS developer, and I am not familiar with Xcode either. I followed your instructions to clone and try to compile the project, but encountered an error. Additionally, what is

MACHO_LIB_TYPE? I couldn't find this string throughout the entire project. This is the error pic:dreampiggy commentedon Jul 25, 2023
MACH_O_TYPEtypo, by default it build dynamic lib, if you don't need static lib ignore this : https://stackoverflow.com/questions/13082149/in-xcode-project-target-build-settings-what-is-mach-o-typeparcool commentedon Jul 26, 2023
@dreampiggy Thank you for your patient response. When building the necessary base project libde265, I have already modified the 'Mach-O Type' as you suggested, but the result is still a framework instead of the .a static library. Is there any other special setting needed? Additionally, if the .a library is successfully built, how can I use it in libheif-Xcode ?

This is my build result pic:
dreampiggy commentedon Jul 26, 2023
Framework is
Package Way, not about how MachO binary is.Means:
You see that the MachO binary in .framework you can just rename it into
libXXX.a, then use it.You can even use
file XXX.framework/XXXcommand to check the binary formatparcool commentedon Jul 26, 2023
@dreampiggy You're welcome! I'm glad you learned something new.
dreampiggy commentedon Jul 26, 2023
Because libheif
dependencylibde265, right ?Now come to
Package Managerproblem, which is used to maintain the dependency.That Xcodeproj, use Carthage as default package manager. You can also use Swift Package Manager as well.
For example, in Carthage, you do actuall this on your App repo (not even libheif or libde265), for example, I has a https://github.com/SDWebImage/SDWebImageHEIFCoder/blob/master/Cartfile
Cartfile, contains the version you wantcarthage build, if you care about iOS only, runcarthage build --platform iOS.frameworkwill inside theCarthage/Buildfolder, you will seelibheif.framework, liblibde265.framework. But it's dynamic frameworklibXXX.a), you need some magic like here: https://github.com/Carthage/Carthage/blob/master/Documentation/StaticFrameworks.mdYou see this
MACH_O_TYPE = staticlibdo what's magic changesdreampiggy commentedon Jul 26, 2023
And another way, use Swift Package Manager as replacement. Note Swift Package Manager
Always use staticlib, no dynamic lib support...WTFJust see what I did on shell terminal, re-produce this by yourself:
dreampiggy commentedon Jul 26, 2023
Or be stupid, you can double click on that
libheif-Xcoderepo'sPackage.swiftThen change the destination to
Any iOS device, click Project -> ArchiveThe binary (not ar archive yet, but simple MachO Object file) is under temp folder, you can found it in Log, like here:

To create ar archive from MachO Object file, use
libtoolparcool commentedon Jul 26, 2023
@dreampiggy Thank you so much for your beginner-friendly guidance. I've successfully compiled it. Thanks again! Best wishes~~
farindk commentedon Jul 26, 2023
@dreampiggy Thanks for helping out.