nigeltao / qoir

A fast, simple, lossless image file format.
Apache License 2.0
105 stars 5 forks source link

Library version #3

Open YorVeX opened 1 year ago

YorVeX commented 1 year ago

Currently this is only usable from C++. I think QOIR would get a boost in real-world adoption if this would additionally be made available to non C++ developers like me by offering a library version of it with a documented API.

Even more so if binary builds would be offered here too. A DLL for Windows would be the easy part, because that will be immediately compatible to the whole Windows world. And maybe for Linux at least one Ubuntu LTS version build could be a start to get some package maintainers for various distros interested.

I'd be the first to come up with a simple C# interface to get this into the .NET world. Outside of reading C++ code to understand libraries and tools I use I don't have a lot of C++ experience, but at least I already managed to get a DLL compiled with "__declspec(dllexport)" added to the qoir_encode and qoir_decode functions and could verify that these functions actually landed in the resulting DLL.

Part of this GH issue (if anyone decides they actually want to work on it) might be some extra work to make this API more friendly for other languages, e.g. use types that are less C++ specific, more generic and/or more explicit about endianness or whether they are 32 bit vs. 64 and so on. Will check myself now with the DLL I produced how hard or easy it is in the current form to fill the parameters these functions need.

YorVeX commented 1 year ago

My PoC code is working fine utilizing this from C# on Windows, haven't tried Linux yet. I am using this on video data so it has to do a lot of work at 60 frames per second. With my test setup and test video loops CPU usage goes roughly 5% down compared to QOI and compression rate is 5% better than for QOI - which is what the benchmarks here indicated and therefore why I wanted to test a QOIR implementation in the first place, so I am very pleased with the result.

I am wondering whether I should release this as a separate wrapper class in its current state though, as stated above the implementation from C# perspective is not ideal, though also not as bad as I was afraid of in the beginning. The option to specify contextual_malloc_func and contextual_free_func is essential, otherwise e.g. the result buffer couldn't be free'd after it was used. But other libraries solve this by either providing a free() function of their own or allow to hand over pre-allocated buffers in the first place (as is possible with the source and "scratch space" buffers already, but not with the result buffer), which can also help avoid unnecessary allocations by reusing a static buffer or at least buffers from a memory pool, something that becomes relevant when working with a high number of frames per second with a high resolution.

What I did so far is:

This is mostly what C# calls "unsafe" code. It doesn't matter for me because my project already uses lots of that and has no option to avoid that anyway. But if one was to release a real standalone C# wrapper it should probably hide this layer and put another managed code layer on top of it working with Spans to keep performance high while making the code more safe from C# perspective. Before putting effort into this I personally would wish for some adjustments as mentioned here first. Or get a clear statement that this won't happen, at least it would be a better base for any decisions about that.