mirror of
				https://invent.kde.org/frameworks/kimageformats.git
				synced 2025-11-03 13:24:20 -05:00 
			
		
		
		
	heif: use heif_init/heif_deinit with libheif 1.13.0+
In recent libheif, application should use heif_init/heif_deinit calls. Unfortunately, these calls are not thread-safe in released 1.13.0 version yet (will be in the future) and HEIFHandler is often created in different threads. So we have to guard their use with a mutex.
This commit is contained in:
		@ -52,6 +52,11 @@ private:
 | 
			
		||||
 | 
			
		||||
} // namespace
 | 
			
		||||
 | 
			
		||||
size_t HEIFHandler::m_initialized_count = 0;
 | 
			
		||||
bool HEIFHandler::m_plugins_queried = false;
 | 
			
		||||
bool HEIFHandler::m_heif_decoder_available = false;
 | 
			
		||||
bool HEIFHandler::m_heif_encoder_available = false;
 | 
			
		||||
 | 
			
		||||
HEIFHandler::HEIFHandler()
 | 
			
		||||
    : m_parseState(ParseHeicNotParsed)
 | 
			
		||||
    , m_quality(100)
 | 
			
		||||
@ -88,6 +93,21 @@ bool HEIFHandler::write(const QImage &image)
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#if LIBHEIF_HAVE_VERSION(1, 13, 0)
 | 
			
		||||
    startHeifLib();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    bool success = write_helper(image);
 | 
			
		||||
 | 
			
		||||
#if LIBHEIF_HAVE_VERSION(1, 13, 0)
 | 
			
		||||
    finishHeifLib();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    return success;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool HEIFHandler::write_helper(const QImage &image)
 | 
			
		||||
{
 | 
			
		||||
    int save_depth; // 8 or 10bit per channel
 | 
			
		||||
    QImage::Format tmpformat; // format for temporary image
 | 
			
		||||
    const bool save_alpha = image.hasAlphaChannel();
 | 
			
		||||
@ -356,8 +376,18 @@ bool HEIFHandler::ensureParsed() const
 | 
			
		||||
 | 
			
		||||
    HEIFHandler *that = const_cast<HEIFHandler *>(this);
 | 
			
		||||
 | 
			
		||||
    return that->ensureDecoder();
 | 
			
		||||
#if LIBHEIF_HAVE_VERSION(1, 13, 0)
 | 
			
		||||
    startHeifLib();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    bool success = that->ensureDecoder();
 | 
			
		||||
 | 
			
		||||
#if LIBHEIF_HAVE_VERSION(1, 13, 0)
 | 
			
		||||
    finishHeifLib();
 | 
			
		||||
#endif
 | 
			
		||||
    return success;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool HEIFHandler::ensureDecoder()
 | 
			
		||||
{
 | 
			
		||||
    if (m_parseState != ParseHeicNotParsed) {
 | 
			
		||||
@ -696,14 +726,100 @@ bool HEIFHandler::ensureDecoder()
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool HEIFHandler::isHeifDecoderAvailable()
 | 
			
		||||
{
 | 
			
		||||
    QMutexLocker locker(&getHEIFHandlerMutex());
 | 
			
		||||
 | 
			
		||||
    if (!m_plugins_queried) {
 | 
			
		||||
#if LIBHEIF_HAVE_VERSION(1, 13, 0)
 | 
			
		||||
        if (m_initialized_count == 0) {
 | 
			
		||||
            heif_init(nullptr);
 | 
			
		||||
        }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
        m_heif_encoder_available = heif_have_encoder_for_format(heif_compression_HEVC);
 | 
			
		||||
        m_heif_decoder_available = heif_have_decoder_for_format(heif_compression_HEVC);
 | 
			
		||||
        m_plugins_queried = true;
 | 
			
		||||
 | 
			
		||||
#if LIBHEIF_HAVE_VERSION(1, 13, 0)
 | 
			
		||||
        if (m_initialized_count == 0) {
 | 
			
		||||
            heif_deinit();
 | 
			
		||||
        }
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return m_heif_decoder_available;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool HEIFHandler::isHeifEncoderAvailable()
 | 
			
		||||
{
 | 
			
		||||
    QMutexLocker locker(&getHEIFHandlerMutex());
 | 
			
		||||
 | 
			
		||||
    if (!m_plugins_queried) {
 | 
			
		||||
#if LIBHEIF_HAVE_VERSION(1, 13, 0)
 | 
			
		||||
        if (m_initialized_count == 0) {
 | 
			
		||||
            heif_init(nullptr);
 | 
			
		||||
        }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
        m_heif_decoder_available = heif_have_decoder_for_format(heif_compression_HEVC);
 | 
			
		||||
        m_heif_encoder_available = heif_have_encoder_for_format(heif_compression_HEVC);
 | 
			
		||||
        m_plugins_queried = true;
 | 
			
		||||
 | 
			
		||||
#if LIBHEIF_HAVE_VERSION(1, 13, 0)
 | 
			
		||||
        if (m_initialized_count == 0) {
 | 
			
		||||
            heif_deinit();
 | 
			
		||||
        }
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return m_heif_encoder_available;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HEIFHandler::startHeifLib()
 | 
			
		||||
{
 | 
			
		||||
#if LIBHEIF_HAVE_VERSION(1, 13, 0)
 | 
			
		||||
    QMutexLocker locker(&getHEIFHandlerMutex());
 | 
			
		||||
 | 
			
		||||
    if (m_initialized_count == 0) {
 | 
			
		||||
        heif_init(nullptr);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    m_initialized_count++;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HEIFHandler::finishHeifLib()
 | 
			
		||||
{
 | 
			
		||||
#if LIBHEIF_HAVE_VERSION(1, 13, 0)
 | 
			
		||||
    QMutexLocker locker(&getHEIFHandlerMutex());
 | 
			
		||||
 | 
			
		||||
    if (m_initialized_count == 0) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    m_initialized_count--;
 | 
			
		||||
    if (m_initialized_count == 0) {
 | 
			
		||||
        heif_deinit();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QMutex &HEIFHandler::getHEIFHandlerMutex()
 | 
			
		||||
{
 | 
			
		||||
    static QMutex heif_handler_mutex;
 | 
			
		||||
    return heif_handler_mutex;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QImageIOPlugin::Capabilities HEIFPlugin::capabilities(QIODevice *device, const QByteArray &format) const
 | 
			
		||||
{
 | 
			
		||||
    if (format == "heif" || format == "heic") {
 | 
			
		||||
        Capabilities format_cap;
 | 
			
		||||
        if (heif_have_decoder_for_format(heif_compression_HEVC)) {
 | 
			
		||||
        if (HEIFHandler::isHeifDecoderAvailable()) {
 | 
			
		||||
            format_cap |= CanRead;
 | 
			
		||||
        }
 | 
			
		||||
        if (heif_have_encoder_for_format(heif_compression_HEVC)) {
 | 
			
		||||
        if (HEIFHandler::isHeifEncoderAvailable()) {
 | 
			
		||||
            format_cap |= CanWrite;
 | 
			
		||||
        }
 | 
			
		||||
        return format_cap;
 | 
			
		||||
@ -716,11 +832,11 @@ QImageIOPlugin::Capabilities HEIFPlugin::capabilities(QIODevice *device, const Q
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Capabilities cap;
 | 
			
		||||
    if (device->isReadable() && HEIFHandler::canRead(device) && heif_have_decoder_for_format(heif_compression_HEVC)) {
 | 
			
		||||
    if (device->isReadable() && HEIFHandler::canRead(device) && HEIFHandler::isHeifDecoderAvailable()) {
 | 
			
		||||
        cap |= CanRead;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (device->isWritable() && heif_have_encoder_for_format(heif_compression_HEVC)) {
 | 
			
		||||
    if (device->isWritable() && HEIFHandler::isHeifEncoderAvailable()) {
 | 
			
		||||
        cap |= CanWrite;
 | 
			
		||||
    }
 | 
			
		||||
    return cap;
 | 
			
		||||
 | 
			
		||||
@ -13,6 +13,7 @@
 | 
			
		||||
#include <QByteArray>
 | 
			
		||||
#include <QImage>
 | 
			
		||||
#include <QImageIOPlugin>
 | 
			
		||||
#include <QMutex>
 | 
			
		||||
 | 
			
		||||
class HEIFHandler : public QImageIOHandler
 | 
			
		||||
{
 | 
			
		||||
@ -29,6 +30,9 @@ public:
 | 
			
		||||
    void setOption(ImageOption option, const QVariant &value) override;
 | 
			
		||||
    bool supportsOption(ImageOption option) const override;
 | 
			
		||||
 | 
			
		||||
    static bool isHeifDecoderAvailable();
 | 
			
		||||
    static bool isHeifEncoderAvailable();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    static bool isSupportedBMFFType(const QByteArray &header);
 | 
			
		||||
    bool ensureParsed() const;
 | 
			
		||||
@ -43,6 +47,18 @@ private:
 | 
			
		||||
    ParseHeicState m_parseState;
 | 
			
		||||
    int m_quality;
 | 
			
		||||
    QImage m_current_image;
 | 
			
		||||
 | 
			
		||||
    bool write_helper(const QImage &image);
 | 
			
		||||
 | 
			
		||||
    static void startHeifLib();
 | 
			
		||||
    static void finishHeifLib();
 | 
			
		||||
    static size_t m_initialized_count;
 | 
			
		||||
 | 
			
		||||
    static bool m_plugins_queried;
 | 
			
		||||
    static bool m_heif_decoder_available;
 | 
			
		||||
    static bool m_heif_encoder_available;
 | 
			
		||||
 | 
			
		||||
    static QMutex &getHEIFHandlerMutex();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class HEIFPlugin : public QImageIOPlugin
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user