mirror of
https://invent.kde.org/frameworks/kimageformats.git
synced 2025-07-14 02:54:19 -04:00
HEIF plug-in extended to read AVCI format
AVCI is H.264 encapsulated in HEIF container
This commit is contained in:
@ -111,6 +111,12 @@ if (LibHeif_FOUND)
|
|||||||
hej2
|
hej2
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (LibHeif_VERSION VERSION_GREATER_EQUAL "1.19.0")
|
||||||
|
kimageformats_read_tests(FUZZ 4
|
||||||
|
avci
|
||||||
|
)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (LibJXL_FOUND AND LibJXLThreads_FOUND)
|
if (LibJXL_FOUND AND LibJXLThreads_FOUND)
|
||||||
|
BIN
autotests/read/avci/eco_kde_gray.avci
Normal file
BIN
autotests/read/avci/eco_kde_gray.avci
Normal file
Binary file not shown.
BIN
autotests/read/avci/eco_kde_gray.png
Normal file
BIN
autotests/read/avci/eco_kde_gray.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 250 KiB |
@ -23,6 +23,7 @@ bool HEIFHandler::m_plugins_queried = false;
|
|||||||
bool HEIFHandler::m_heif_decoder_available = false;
|
bool HEIFHandler::m_heif_decoder_available = false;
|
||||||
bool HEIFHandler::m_heif_encoder_available = false;
|
bool HEIFHandler::m_heif_encoder_available = false;
|
||||||
bool HEIFHandler::m_hej2_decoder_available = false;
|
bool HEIFHandler::m_hej2_decoder_available = false;
|
||||||
|
bool HEIFHandler::m_avci_decoder_available = false;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
static struct heif_error heifhandler_write_callback(struct heif_context * /* ctx */, const void *data, size_t size, void *userdata)
|
static struct heif_error heifhandler_write_callback(struct heif_context * /* ctx */, const void *data, size_t size, void *userdata)
|
||||||
@ -74,6 +75,11 @@ bool HEIFHandler::canRead() const
|
|||||||
setFormat("hej2");
|
setFormat("hej2");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (HEIFHandler::isSupportedAVCI(header)) {
|
||||||
|
setFormat("avci");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -164,8 +170,15 @@ bool HEIFHandler::write_helper(const QImage &image)
|
|||||||
auto cs = image.colorSpace();
|
auto cs = image.colorSpace();
|
||||||
if (cs.isValid() && cs.colorModel() == QColorSpace::ColorModel::Cmyk && image.format() == QImage::Format_CMYK8888) {
|
if (cs.isValid() && cs.colorModel() == QColorSpace::ColorModel::Cmyk && image.format() == QImage::Format_CMYK8888) {
|
||||||
tmpimage = image.convertedToColorSpace(QColorSpace(QColorSpace::SRgb), tmpformat);
|
tmpimage = image.convertedToColorSpace(QColorSpace(QColorSpace::SRgb), tmpformat);
|
||||||
|
} else if (cs.isValid() && cs.colorModel() == QColorSpace::ColorModel::Gray
|
||||||
|
&& (image.format() == QImage::Format_Grayscale8 || image.format() == QImage::Format_Grayscale16)) {
|
||||||
|
QColorSpace::TransferFunction trc_new = cs.transferFunction();
|
||||||
|
float gamma_new = cs.gamma();
|
||||||
|
if (trc_new == QColorSpace::TransferFunction::Custom) {
|
||||||
|
trc_new = QColorSpace::TransferFunction::SRgb;
|
||||||
}
|
}
|
||||||
else {
|
tmpimage = image.convertedToColorSpace(QColorSpace(QColorSpace::Primaries::SRgb, trc_new, gamma_new), tmpformat);
|
||||||
|
} else {
|
||||||
tmpimage = image.convertToFormat(tmpformat);
|
tmpimage = image.convertToFormat(tmpformat);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@ -380,6 +393,22 @@ bool HEIFHandler::isSupportedHEJ2(const QByteArray &header)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HEIFHandler::isSupportedAVCI(const QByteArray &header)
|
||||||
|
{
|
||||||
|
if (header.size() < 28) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *buffer = header.constData();
|
||||||
|
if (qstrncmp(buffer + 4, "ftyp", 4) == 0) {
|
||||||
|
if (qstrncmp(buffer + 8, "avci", 4) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
QVariant HEIFHandler::option(ImageOption option) const
|
QVariant HEIFHandler::option(ImageOption option) const
|
||||||
{
|
{
|
||||||
if (option == Quality) {
|
if (option == Quality) {
|
||||||
@ -455,7 +484,7 @@ bool HEIFHandler::ensureDecoder()
|
|||||||
}
|
}
|
||||||
|
|
||||||
const QByteArray buffer = device()->readAll();
|
const QByteArray buffer = device()->readAll();
|
||||||
if (!HEIFHandler::isSupportedBMFFType(buffer) && !HEIFHandler::isSupportedHEJ2(buffer)) {
|
if (!HEIFHandler::isSupportedBMFFType(buffer) && !HEIFHandler::isSupportedHEJ2(buffer) && !HEIFHandler::isSupportedAVCI(buffer)) {
|
||||||
m_parseState = ParseHeicError;
|
m_parseState = ParseHeicError;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -808,6 +837,14 @@ bool HEIFHandler::ensureDecoder()
|
|||||||
case 13:
|
case 13:
|
||||||
q_trc = QColorSpace::TransferFunction::SRgb;
|
q_trc = QColorSpace::TransferFunction::SRgb;
|
||||||
break;
|
break;
|
||||||
|
#if (QT_VERSION >= QT_VERSION_CHECK(6, 8, 0))
|
||||||
|
case 16:
|
||||||
|
q_trc = QColorSpace::TransferFunction::St2084;
|
||||||
|
break;
|
||||||
|
case 18:
|
||||||
|
q_trc = QColorSpace::TransferFunction::Hlg;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
qWarning("CICP color_primaries: %d, transfer_characteristics: %d\nThe colorspace is unsupported by this plug-in yet.",
|
qWarning("CICP color_primaries: %d, transfer_characteristics: %d\nThe colorspace is unsupported by this plug-in yet.",
|
||||||
nclx->color_primaries,
|
nclx->color_primaries,
|
||||||
@ -850,61 +887,33 @@ bool HEIFHandler::ensureDecoder()
|
|||||||
|
|
||||||
bool HEIFHandler::isHeifDecoderAvailable()
|
bool HEIFHandler::isHeifDecoderAvailable()
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&getHEIFHandlerMutex());
|
HEIFHandler::queryHeifLib();
|
||||||
|
|
||||||
if (!m_plugins_queried) {
|
|
||||||
#if LIBHEIF_HAVE_VERSION(1, 13, 0)
|
|
||||||
if (m_initialized_count == 0) {
|
|
||||||
heif_init(nullptr);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if LIBHEIF_HAVE_VERSION(1, 13, 0)
|
|
||||||
m_hej2_decoder_available = heif_have_decoder_for_format(heif_compression_JPEG2000);
|
|
||||||
#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;
|
return m_heif_decoder_available;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HEIFHandler::isHeifEncoderAvailable()
|
bool HEIFHandler::isHeifEncoderAvailable()
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&getHEIFHandlerMutex());
|
HEIFHandler::queryHeifLib();
|
||||||
|
|
||||||
if (!m_plugins_queried) {
|
|
||||||
#if LIBHEIF_HAVE_VERSION(1, 13, 0)
|
|
||||||
if (m_initialized_count == 0) {
|
|
||||||
heif_init(nullptr);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if LIBHEIF_HAVE_VERSION(1, 13, 0)
|
|
||||||
m_hej2_decoder_available = heif_have_decoder_for_format(heif_compression_JPEG2000);
|
|
||||||
#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;
|
return m_heif_encoder_available;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HEIFHandler::isHej2DecoderAvailable()
|
bool HEIFHandler::isHej2DecoderAvailable()
|
||||||
|
{
|
||||||
|
HEIFHandler::queryHeifLib();
|
||||||
|
|
||||||
|
return m_hej2_decoder_available;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HEIFHandler::isAVCIDecoderAvailable()
|
||||||
|
{
|
||||||
|
HEIFHandler::queryHeifLib();
|
||||||
|
|
||||||
|
return m_avci_decoder_available;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HEIFHandler::queryHeifLib()
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&getHEIFHandlerMutex());
|
QMutexLocker locker(&getHEIFHandlerMutex());
|
||||||
|
|
||||||
@ -919,6 +928,9 @@ bool HEIFHandler::isHej2DecoderAvailable()
|
|||||||
m_heif_decoder_available = heif_have_decoder_for_format(heif_compression_HEVC);
|
m_heif_decoder_available = heif_have_decoder_for_format(heif_compression_HEVC);
|
||||||
#if LIBHEIF_HAVE_VERSION(1, 13, 0)
|
#if LIBHEIF_HAVE_VERSION(1, 13, 0)
|
||||||
m_hej2_decoder_available = heif_have_decoder_for_format(heif_compression_JPEG2000);
|
m_hej2_decoder_available = heif_have_decoder_for_format(heif_compression_JPEG2000);
|
||||||
|
#endif
|
||||||
|
#if LIBHEIF_HAVE_VERSION(1, 19, 0)
|
||||||
|
m_avci_decoder_available = heif_have_decoder_for_format(heif_compression_AVC);
|
||||||
#endif
|
#endif
|
||||||
m_plugins_queried = true;
|
m_plugins_queried = true;
|
||||||
|
|
||||||
@ -928,8 +940,6 @@ bool HEIFHandler::isHej2DecoderAvailable()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_hej2_decoder_available;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HEIFHandler::startHeifLib()
|
void HEIFHandler::startHeifLib()
|
||||||
@ -989,6 +999,14 @@ QImageIOPlugin::Capabilities HEIFPlugin::capabilities(QIODevice *device, const Q
|
|||||||
return format_cap;
|
return format_cap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (format == "avci") {
|
||||||
|
Capabilities format_cap;
|
||||||
|
if (HEIFHandler::isAVCIDecoderAvailable()) {
|
||||||
|
format_cap |= CanRead;
|
||||||
|
}
|
||||||
|
return format_cap;
|
||||||
|
}
|
||||||
|
|
||||||
if (!format.isEmpty()) {
|
if (!format.isEmpty()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -1000,11 +1018,9 @@ QImageIOPlugin::Capabilities HEIFPlugin::capabilities(QIODevice *device, const Q
|
|||||||
if (device->isReadable()) {
|
if (device->isReadable()) {
|
||||||
const QByteArray header = device->peek(28);
|
const QByteArray header = device->peek(28);
|
||||||
|
|
||||||
if (HEIFHandler::isSupportedBMFFType(header) && HEIFHandler::isHeifDecoderAvailable()) {
|
if ((HEIFHandler::isSupportedBMFFType(header) && HEIFHandler::isHeifDecoderAvailable())
|
||||||
cap |= CanRead;
|
|| (HEIFHandler::isSupportedHEJ2(header) && HEIFHandler::isHej2DecoderAvailable())
|
||||||
}
|
|| (HEIFHandler::isSupportedAVCI(header) && HEIFHandler::isAVCIDecoderAvailable())) {
|
||||||
|
|
||||||
if (HEIFHandler::isSupportedHEJ2(header) && HEIFHandler::isHej2DecoderAvailable()) {
|
|
||||||
cap |= CanRead;
|
cap |= CanRead;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,9 +31,11 @@ public:
|
|||||||
static bool isHeifDecoderAvailable();
|
static bool isHeifDecoderAvailable();
|
||||||
static bool isHeifEncoderAvailable();
|
static bool isHeifEncoderAvailable();
|
||||||
static bool isHej2DecoderAvailable();
|
static bool isHej2DecoderAvailable();
|
||||||
|
static bool isAVCIDecoderAvailable();
|
||||||
|
|
||||||
static bool isSupportedBMFFType(const QByteArray &header);
|
static bool isSupportedBMFFType(const QByteArray &header);
|
||||||
static bool isSupportedHEJ2(const QByteArray &header);
|
static bool isSupportedHEJ2(const QByteArray &header);
|
||||||
|
static bool isSupportedAVCI(const QByteArray &header);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool ensureParsed() const;
|
bool ensureParsed() const;
|
||||||
@ -53,12 +55,14 @@ private:
|
|||||||
|
|
||||||
static void startHeifLib();
|
static void startHeifLib();
|
||||||
static void finishHeifLib();
|
static void finishHeifLib();
|
||||||
|
static void queryHeifLib();
|
||||||
static size_t m_initialized_count;
|
static size_t m_initialized_count;
|
||||||
|
|
||||||
static bool m_plugins_queried;
|
static bool m_plugins_queried;
|
||||||
static bool m_heif_decoder_available;
|
static bool m_heif_decoder_available;
|
||||||
static bool m_heif_encoder_available;
|
static bool m_heif_encoder_available;
|
||||||
static bool m_hej2_decoder_available;
|
static bool m_hej2_decoder_available;
|
||||||
|
static bool m_avci_decoder_available;
|
||||||
|
|
||||||
static QMutex &getHEIFHandlerMutex();
|
static QMutex &getHEIFHandlerMutex();
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user