mirror of
https://review.haiku-os.org/haiku
synced 2025-01-18 12:38:51 +01:00
Translators: Add an AVIF translator
This translator only supports still images for now, and supports both decoding and encoding. Encoding support has been tested only with aom, rav1e doesn’t build on Haiku yet, see https://github.com/haikuports/haikuports/pull/5534 for one of the missing dependencies. Change-Id: I716f4b862ed316b89b227bfed38072d72074201f Reviewed-on: https://review.haiku-os.org/c/haiku/+/3040 Reviewed-by: waddlesplash <waddlesplash@gmail.com> Reviewed-by: Jérôme Duval <jerome.duval@gmail.com> Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org>
This commit is contained in:
parent
6bb8ecb02b
commit
147b47e086
2
Jamfile
2
Jamfile
@ -60,7 +60,7 @@ if $(HAIKU_PACKAGING_ARCHS[2]) {
|
||||
freetype icu libsolv zlib
|
||||
|
||||
regular_image @{
|
||||
ffmpeg glu jasper jpeg libicns libpng16 libwebp mesa
|
||||
ffmpeg glu jasper jpeg libavif libicns libpng16 libwebp mesa
|
||||
}@
|
||||
] ;
|
||||
if $(TARGET_PACKAGING_ARCH) != x86_gcc2 {
|
||||
|
@ -650,6 +650,26 @@ if [ IsPackageAvailable libwebp_devel ] {
|
||||
}
|
||||
|
||||
|
||||
# libavif
|
||||
if [ IsPackageAvailable libavif_devel ] {
|
||||
if $(HAIKU_PACKAGING_ARCH) = x86_64 {
|
||||
ExtractBuildFeatureArchives libavif :
|
||||
file: base libavif
|
||||
runtime: lib
|
||||
file: devel libavif_devel
|
||||
depends: base
|
||||
library: $(developLibDir)/libavif.so.12
|
||||
headers: $(developHeadersDir) $(developHeadersDir)/avif
|
||||
;
|
||||
EnableBuildFeatures libavif ;
|
||||
} else {
|
||||
unavailableBuildFeatures += libavif ;
|
||||
}
|
||||
} else {
|
||||
unavailableBuildFeatures += libavif ;
|
||||
}
|
||||
|
||||
|
||||
# live555
|
||||
if [ IsPackageAvailable live555_devel ] {
|
||||
ExtractBuildFeatureArchives live555 :
|
||||
|
@ -124,6 +124,7 @@ SYSTEM_ADD_ONS_ACCELERANTS += [ FFilterByBuildFeatures
|
||||
] ;
|
||||
|
||||
SYSTEM_ADD_ONS_TRANSLATORS += [ FFilterByBuildFeatures
|
||||
AVIFTranslator@libavif
|
||||
BMPTranslator
|
||||
EXRTranslator@openexr
|
||||
GIFTranslator
|
||||
|
@ -1,5 +1,6 @@
|
||||
SubDir HAIKU_TOP src add-ons translators ;
|
||||
|
||||
SubInclude HAIKU_TOP src add-ons translators avif ;
|
||||
SubInclude HAIKU_TOP src add-ons translators bmp ;
|
||||
SubInclude HAIKU_TOP src add-ons translators exr ;
|
||||
SubInclude HAIKU_TOP src add-ons translators gif ;
|
||||
|
532
src/add-ons/translators/avif/AVIFTranslator.cpp
Normal file
532
src/add-ons/translators/avif/AVIFTranslator.cpp
Normal file
@ -0,0 +1,532 @@
|
||||
/*
|
||||
* Copyright 2021, Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Emmanuel Gil Peyrot
|
||||
*/
|
||||
|
||||
|
||||
#include "AVIFTranslator.h"
|
||||
|
||||
#include <BufferIO.h>
|
||||
#include <Catalog.h>
|
||||
#include <Messenger.h>
|
||||
#include <TranslatorRoster.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "avif/avif.h"
|
||||
|
||||
#include "ConfigView.h"
|
||||
#include "TranslatorSettings.h"
|
||||
|
||||
|
||||
#undef B_TRANSLATION_CONTEXT
|
||||
#define B_TRANSLATION_CONTEXT "AVIFTranslator"
|
||||
|
||||
|
||||
class FreeAllocation {
|
||||
public:
|
||||
FreeAllocation(void* buffer)
|
||||
:
|
||||
fBuffer(buffer)
|
||||
{
|
||||
}
|
||||
|
||||
~FreeAllocation()
|
||||
{
|
||||
free(fBuffer);
|
||||
}
|
||||
|
||||
private:
|
||||
void* fBuffer;
|
||||
};
|
||||
|
||||
|
||||
// The input formats that this translator knows how to read
|
||||
static const translation_format sInputFormats[] = {
|
||||
{
|
||||
AVIF_IMAGE_FORMAT,
|
||||
B_TRANSLATOR_BITMAP,
|
||||
AVIF_IN_QUALITY,
|
||||
AVIF_IN_CAPABILITY,
|
||||
"image/avif",
|
||||
"AV1 Image File Format"
|
||||
},
|
||||
{
|
||||
B_TRANSLATOR_BITMAP,
|
||||
B_TRANSLATOR_BITMAP,
|
||||
BITS_IN_QUALITY,
|
||||
BITS_IN_CAPABILITY,
|
||||
"image/x-be-bitmap",
|
||||
"Be Bitmap Format (AVIFTranslator)"
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
// The output formats that this translator knows how to write
|
||||
static const translation_format sOutputFormats[] = {
|
||||
{
|
||||
AVIF_IMAGE_FORMAT,
|
||||
B_TRANSLATOR_BITMAP,
|
||||
AVIF_OUT_QUALITY,
|
||||
AVIF_OUT_CAPABILITY,
|
||||
"image/avif",
|
||||
"AV1 Image File Format"
|
||||
},
|
||||
{
|
||||
B_TRANSLATOR_BITMAP,
|
||||
B_TRANSLATOR_BITMAP,
|
||||
BITS_OUT_QUALITY,
|
||||
BITS_OUT_CAPABILITY,
|
||||
"image/x-be-bitmap",
|
||||
"Be Bitmap Format (AVIFTranslator)"
|
||||
},
|
||||
};
|
||||
|
||||
// Default settings for the Translator
|
||||
static const TranSetting sDefaultSettings[] = {
|
||||
{ B_TRANSLATOR_EXT_HEADER_ONLY, TRAN_SETTING_BOOL, false },
|
||||
{ B_TRANSLATOR_EXT_DATA_ONLY, TRAN_SETTING_BOOL, false },
|
||||
{ AVIF_SETTING_LOSSLESS, TRAN_SETTING_BOOL, false },
|
||||
{ AVIF_SETTING_PIXEL_FORMAT, TRAN_SETTING_INT32,
|
||||
AVIF_PIXEL_FORMAT_YUV444 },
|
||||
{ AVIF_SETTING_QUALITY, TRAN_SETTING_INT32, 60 },
|
||||
{ AVIF_SETTING_SPEED, TRAN_SETTING_INT32, -1 },
|
||||
{ AVIF_SETTING_TILES_HORIZONTAL, TRAN_SETTING_INT32, 1 },
|
||||
{ AVIF_SETTING_TILES_VERTICAL, TRAN_SETTING_INT32, 1 },
|
||||
};
|
||||
|
||||
const uint32 kNumInputFormats = sizeof(sInputFormats) /
|
||||
sizeof(translation_format);
|
||||
const uint32 kNumOutputFormats = sizeof(sOutputFormats) /
|
||||
sizeof(translation_format);
|
||||
const uint32 kNumDefaultSettings = sizeof(sDefaultSettings) /
|
||||
sizeof(TranSetting);
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
AVIFTranslator::AVIFTranslator()
|
||||
:
|
||||
BaseTranslator(B_TRANSLATE("AVIF images"),
|
||||
B_TRANSLATE("AVIF image translator"),
|
||||
AVIF_TRANSLATOR_VERSION,
|
||||
sInputFormats, kNumInputFormats,
|
||||
sOutputFormats, kNumOutputFormats,
|
||||
"AVIFTranslator_Settings", sDefaultSettings,
|
||||
kNumDefaultSettings, B_TRANSLATOR_BITMAP, AVIF_IMAGE_FORMAT)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
AVIFTranslator::~AVIFTranslator()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AVIFTranslator::DerivedIdentify(BPositionIO* stream,
|
||||
const translation_format* format, BMessage* settings,
|
||||
translator_info* info, uint32 outType)
|
||||
{
|
||||
(void)format;
|
||||
(void)settings;
|
||||
if (!outType)
|
||||
outType = B_TRANSLATOR_BITMAP;
|
||||
if (outType != B_TRANSLATOR_BITMAP)
|
||||
return B_NO_TRANSLATOR;
|
||||
|
||||
// Read header and first chunck bytes...
|
||||
uint32 buf[64];
|
||||
ssize_t size = sizeof(buf);
|
||||
if (stream->Read(buf, size) != size)
|
||||
return B_IO_ERROR;
|
||||
|
||||
// Check it's a valid AVIF format
|
||||
avifROData data;
|
||||
data.data = reinterpret_cast<const uint8_t*>(buf);
|
||||
data.size = static_cast<size_t>(size);
|
||||
if (!avifPeekCompatibleFileType(&data))
|
||||
return B_ILLEGAL_DATA;
|
||||
|
||||
info->type = AVIF_IMAGE_FORMAT;
|
||||
info->group = B_TRANSLATOR_BITMAP;
|
||||
info->quality = AVIF_IN_QUALITY;
|
||||
info->capability = AVIF_IN_CAPABILITY;
|
||||
snprintf(info->name, sizeof(info->name), B_TRANSLATE("AVIF image"));
|
||||
strcpy(info->MIME, "image/avif");
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AVIFTranslator::DerivedTranslate(BPositionIO* stream,
|
||||
const translator_info* info, BMessage* ioExtension, uint32 outType,
|
||||
BPositionIO* target, int32 baseType)
|
||||
{
|
||||
(void)info;
|
||||
if (baseType == 1)
|
||||
// if stream is in bits format
|
||||
return _TranslateFromBits(stream, ioExtension, outType, target);
|
||||
else if (baseType == 0)
|
||||
// if stream is NOT in bits format
|
||||
return _TranslateFromAVIF(stream, ioExtension, outType, target);
|
||||
else
|
||||
// if BaseTranslator dit not properly identify the data as
|
||||
// bits or not bits
|
||||
return B_NO_TRANSLATOR;
|
||||
}
|
||||
|
||||
|
||||
BView*
|
||||
AVIFTranslator::NewConfigView(TranslatorSettings* settings)
|
||||
{
|
||||
return new ConfigView(settings);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AVIFTranslator::_TranslateFromBits(BPositionIO* stream, BMessage* ioExtension,
|
||||
uint32 outType, BPositionIO* target)
|
||||
{
|
||||
// FIXME: This codepath is completely untested for now, due to libavif
|
||||
// being built without any encoder in haikuports.
|
||||
|
||||
(void)ioExtension;
|
||||
if (!outType)
|
||||
outType = AVIF_IMAGE_FORMAT;
|
||||
if (outType != AVIF_IMAGE_FORMAT)
|
||||
return B_NO_TRANSLATOR;
|
||||
|
||||
TranslatorBitmap bitsHeader;
|
||||
status_t status;
|
||||
|
||||
status = identify_bits_header(stream, NULL, &bitsHeader);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
avifPixelFormat format = static_cast<avifPixelFormat>(
|
||||
fSettings->SetGetInt32(AVIF_SETTING_PIXEL_FORMAT));
|
||||
int32 bytesPerPixel;
|
||||
avifRGBFormat rgbFormat;
|
||||
bool isRGB = true;
|
||||
bool ignoreAlpha = false;
|
||||
switch (bitsHeader.colors) {
|
||||
case B_RGB32:
|
||||
rgbFormat = AVIF_RGB_FORMAT_BGRA;
|
||||
ignoreAlpha = true;
|
||||
bytesPerPixel = 4;
|
||||
break;
|
||||
|
||||
case B_RGB32_BIG:
|
||||
rgbFormat = AVIF_RGB_FORMAT_ARGB;
|
||||
ignoreAlpha = true;
|
||||
bytesPerPixel = 4;
|
||||
break;
|
||||
|
||||
case B_RGBA32:
|
||||
rgbFormat = AVIF_RGB_FORMAT_BGRA;
|
||||
bytesPerPixel = 4;
|
||||
break;
|
||||
|
||||
case B_RGBA32_BIG:
|
||||
rgbFormat = AVIF_RGB_FORMAT_ARGB;
|
||||
bytesPerPixel = 4;
|
||||
break;
|
||||
|
||||
case B_RGB24:
|
||||
rgbFormat = AVIF_RGB_FORMAT_BGR;
|
||||
bytesPerPixel = 3;
|
||||
break;
|
||||
|
||||
case B_RGB24_BIG:
|
||||
rgbFormat = AVIF_RGB_FORMAT_RGB;
|
||||
bytesPerPixel = 3;
|
||||
break;
|
||||
|
||||
case B_YCbCr444:
|
||||
bytesPerPixel = 3;
|
||||
isRGB = false;
|
||||
break;
|
||||
|
||||
case B_GRAY8:
|
||||
bytesPerPixel = 1;
|
||||
isRGB = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("ERROR: Colorspace not supported: %d\n",
|
||||
bitsHeader.colors);
|
||||
return B_NO_TRANSLATOR;
|
||||
}
|
||||
|
||||
int width = bitsHeader.bounds.IntegerWidth() + 1;
|
||||
int height = bitsHeader.bounds.IntegerHeight() + 1;
|
||||
int depth = 8;
|
||||
|
||||
avifImage* image = avifImageCreate(width, height, depth, format);
|
||||
image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709;
|
||||
image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SRGB;
|
||||
image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_IDENTITY;
|
||||
|
||||
if (isRGB) {
|
||||
image->yuvRange = AVIF_RANGE_FULL;
|
||||
|
||||
avifRGBImage rgb;
|
||||
avifRGBImageSetDefaults(&rgb, image);
|
||||
rgb.depth = depth;
|
||||
rgb.format = rgbFormat;
|
||||
rgb.ignoreAlpha = ignoreAlpha;
|
||||
int bitsSize = height * bitsHeader.rowBytes;
|
||||
rgb.pixels = static_cast<uint8_t*>(malloc(bitsSize));
|
||||
if (rgb.pixels == NULL)
|
||||
return B_NO_MEMORY;
|
||||
rgb.rowBytes = bitsHeader.rowBytes;
|
||||
|
||||
if (stream->Read(rgb.pixels, bitsSize) != bitsSize) {
|
||||
free(rgb.pixels);
|
||||
return B_IO_ERROR;
|
||||
}
|
||||
|
||||
avifResult conversionResult = avifImageRGBToYUV(image, &rgb);
|
||||
free(rgb.pixels);
|
||||
if (conversionResult != AVIF_RESULT_OK)
|
||||
return B_ERROR;
|
||||
} else if (bytesPerPixel == 3) {
|
||||
// TODO: Investigate moving that to libavif instead, and do so
|
||||
// for other Y'CbCr formats too.
|
||||
//
|
||||
// See also https://github.com/AOMediaCodec/libavif/pull/235
|
||||
assert(bitsHeader.colors == B_YCbCr444);
|
||||
int bitsSize = height * bitsHeader.rowBytes;
|
||||
uint8_t* pixels = static_cast<uint8_t*>(malloc(bitsSize));
|
||||
if (stream->Read(pixels, bitsSize) != bitsSize)
|
||||
return B_IO_ERROR;
|
||||
|
||||
uint8_t* luma = static_cast<uint8_t*>(malloc(bitsSize / 3));
|
||||
uint8_t* cb = static_cast<uint8_t*>(malloc(bitsSize / 3));
|
||||
uint8_t* cr = static_cast<uint8_t*>(malloc(bitsSize / 3));
|
||||
|
||||
for (int i = 0; i < bitsSize / 3; ++i) {
|
||||
luma[i] = pixels[3 * i + 0];
|
||||
cb[i] = pixels[3 * i + 1];
|
||||
cr[i] = pixels[3 * i + 2];
|
||||
}
|
||||
|
||||
image->yuvPlanes[0] = luma;
|
||||
image->yuvPlanes[1] = cb;
|
||||
image->yuvPlanes[2] = cr;
|
||||
|
||||
image->yuvRowBytes[0] = bitsHeader.rowBytes / 3;
|
||||
image->yuvRowBytes[1] = bitsHeader.rowBytes / 3;
|
||||
image->yuvRowBytes[2] = bitsHeader.rowBytes / 3;
|
||||
|
||||
image->yuvRange = AVIF_RANGE_LIMITED;
|
||||
} else {
|
||||
assert(bitsHeader.colors == B_GRAY8);
|
||||
int bitsSize = height * bitsHeader.rowBytes;
|
||||
uint8_t* luma = static_cast<uint8_t*>(malloc(bitsSize));
|
||||
if (stream->Read(luma, bitsSize) != bitsSize)
|
||||
return B_IO_ERROR;
|
||||
|
||||
image->yuvPlanes[0] = luma;
|
||||
image->yuvPlanes[1] = nullptr;
|
||||
image->yuvPlanes[2] = nullptr;
|
||||
|
||||
image->yuvRowBytes[0] = bitsHeader.rowBytes;
|
||||
image->yuvRowBytes[1] = 0;
|
||||
image->yuvRowBytes[2] = 0;
|
||||
}
|
||||
|
||||
avifRWData output = AVIF_DATA_EMPTY;
|
||||
avifEncoder* encoder = avifEncoderCreate();
|
||||
|
||||
system_info info;
|
||||
encoder->maxThreads = (get_system_info(&info) == B_OK) ?
|
||||
info.cpu_count : 1;
|
||||
|
||||
if (fSettings->SetGetBool(AVIF_SETTING_LOSSLESS)) {
|
||||
encoder->minQuantizer = AVIF_QUANTIZER_LOSSLESS;
|
||||
encoder->maxQuantizer = AVIF_QUANTIZER_LOSSLESS;
|
||||
} else {
|
||||
encoder->minQuantizer = encoder->maxQuantizer
|
||||
= fSettings->SetGetInt32(AVIF_SETTING_QUALITY);
|
||||
}
|
||||
encoder->speed = fSettings->SetGetInt32(AVIF_SETTING_SPEED);
|
||||
encoder->tileColsLog2
|
||||
= fSettings->SetGetInt32(AVIF_SETTING_TILES_HORIZONTAL);
|
||||
encoder->tileRowsLog2
|
||||
= fSettings->SetGetInt32(AVIF_SETTING_TILES_VERTICAL);
|
||||
|
||||
avifResult encodeResult = avifEncoderWrite(encoder, image, &output);
|
||||
avifImageDestroy(image);
|
||||
avifEncoderDestroy(encoder);
|
||||
|
||||
if (encodeResult != AVIF_RESULT_OK) {
|
||||
printf("ERROR: Failed to encode: %s\n",
|
||||
avifResultToString(encodeResult));
|
||||
avifRWDataFree(&output);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// output contains a valid .avif file's contents
|
||||
target->Write(output.data, output.size);
|
||||
avifRWDataFree(&output);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AVIFTranslator::_TranslateFromAVIF(BPositionIO* stream, BMessage* ioExtension,
|
||||
uint32 outType, BPositionIO* target)
|
||||
{
|
||||
if (!outType)
|
||||
outType = B_TRANSLATOR_BITMAP;
|
||||
if (outType != B_TRANSLATOR_BITMAP)
|
||||
return B_NO_TRANSLATOR;
|
||||
|
||||
off_t streamLength = 0;
|
||||
stream->GetSize(&streamLength);
|
||||
|
||||
off_t streamSize = stream->Seek(0, SEEK_END);
|
||||
stream->Seek(0, SEEK_SET);
|
||||
|
||||
void* streamData = malloc(streamSize);
|
||||
if (streamData == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
if (stream->Read(streamData, streamSize) != streamSize) {
|
||||
free(streamData);
|
||||
return B_IO_ERROR;
|
||||
}
|
||||
|
||||
avifDecoder* decoder = avifDecoderCreate();
|
||||
if (decoder == NULL) {
|
||||
free(streamData);
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
avifResult setIOMemoryResult = avifDecoderSetIOMemory(decoder,
|
||||
reinterpret_cast<const uint8_t *>(streamData), streamSize);
|
||||
if (setIOMemoryResult != AVIF_RESULT_OK) {
|
||||
free(streamData);
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
avifResult decodeResult = avifDecoderParse(decoder);
|
||||
if (decodeResult != AVIF_RESULT_OK) {
|
||||
free(streamData);
|
||||
return B_ILLEGAL_DATA;
|
||||
}
|
||||
|
||||
// We don’t support animations yet.
|
||||
if (decoder->imageCount != 1) {
|
||||
free(streamData);
|
||||
return B_ILLEGAL_DATA;
|
||||
}
|
||||
|
||||
avifResult nextImageResult = avifDecoderNextImage(decoder);
|
||||
free(streamData);
|
||||
if (nextImageResult != AVIF_RESULT_OK)
|
||||
return B_ILLEGAL_DATA;
|
||||
|
||||
avifImage* image = decoder->image;
|
||||
int width = image->width;
|
||||
int height = image->height;
|
||||
avifRGBFormat format;
|
||||
uint8_t* pixels;
|
||||
uint32_t rowBytes;
|
||||
color_space colors;
|
||||
|
||||
bool convertToRGB = true;
|
||||
if (image->alphaPlane) {
|
||||
format = AVIF_RGB_FORMAT_BGRA;
|
||||
colors = B_RGBA32;
|
||||
} else if (image->yuvFormat == AVIF_PIXEL_FORMAT_YUV400) {
|
||||
colors = B_GRAY8;
|
||||
convertToRGB = false;
|
||||
} else {
|
||||
format = AVIF_RGB_FORMAT_BGR;
|
||||
colors = B_RGB24;
|
||||
}
|
||||
|
||||
if (convertToRGB) {
|
||||
avifRGBImage rgb;
|
||||
avifRGBImageSetDefaults(&rgb, image);
|
||||
rgb.depth = 8;
|
||||
rgb.format = format;
|
||||
|
||||
avifRGBImageAllocatePixels(&rgb);
|
||||
avifResult conversionResult = avifImageYUVToRGB(image, &rgb);
|
||||
if (conversionResult != AVIF_RESULT_OK)
|
||||
return B_ILLEGAL_DATA;
|
||||
|
||||
pixels = rgb.pixels;
|
||||
rowBytes = rgb.rowBytes;
|
||||
} else {
|
||||
// TODO: Add a downsampling (with dithering?) path here, or
|
||||
// alternatively add support for higher bit depth to Haiku
|
||||
// bitmaps, possibly with HDR too.
|
||||
if (image->depth > 8)
|
||||
return B_ILLEGAL_DATA;
|
||||
|
||||
// TODO: Add support for more than just the luma plane.
|
||||
pixels = image->yuvPlanes[0];
|
||||
rowBytes = image->yuvRowBytes[0];
|
||||
}
|
||||
|
||||
uint32 dataSize = rowBytes * height;
|
||||
|
||||
TranslatorBitmap bitmapHeader;
|
||||
bitmapHeader.magic = B_TRANSLATOR_BITMAP;
|
||||
bitmapHeader.bounds.Set(0, 0, width - 1, height - 1);
|
||||
bitmapHeader.rowBytes = rowBytes;
|
||||
bitmapHeader.colors = colors;
|
||||
bitmapHeader.dataSize = dataSize;
|
||||
|
||||
// write out Be's Bitmap header
|
||||
swap_data(B_UINT32_TYPE, &bitmapHeader, sizeof(TranslatorBitmap),
|
||||
B_SWAP_HOST_TO_BENDIAN);
|
||||
ssize_t bytesWritten = target->Write(&bitmapHeader,
|
||||
sizeof(TranslatorBitmap));
|
||||
if (bytesWritten < B_OK)
|
||||
return bytesWritten;
|
||||
|
||||
if ((size_t)bytesWritten != sizeof(TranslatorBitmap))
|
||||
return B_IO_ERROR;
|
||||
|
||||
bool headerOnly = false;
|
||||
if (ioExtension != NULL)
|
||||
ioExtension->FindBool(B_TRANSLATOR_EXT_HEADER_ONLY,
|
||||
&headerOnly);
|
||||
|
||||
if (headerOnly)
|
||||
return B_OK;
|
||||
|
||||
bytesWritten = target->Write(pixels, dataSize);
|
||||
if (bytesWritten < B_OK)
|
||||
return bytesWritten;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
BTranslator*
|
||||
make_nth_translator(int32 n, image_id you, uint32 flags, ...)
|
||||
{
|
||||
(void)you;
|
||||
(void)flags;
|
||||
if (n != 0)
|
||||
return NULL;
|
||||
|
||||
return new AVIFTranslator();
|
||||
}
|
84
src/add-ons/translators/avif/AVIFTranslator.h
Normal file
84
src/add-ons/translators/avif/AVIFTranslator.h
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2021, Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Emmanuel Gil Peyrot
|
||||
*/
|
||||
#ifndef AVIF_TRANSLATOR_H
|
||||
#define AVIF_TRANSLATOR_H
|
||||
|
||||
|
||||
#include <ByteOrder.h>
|
||||
#include <DataIO.h>
|
||||
#include <File.h>
|
||||
#include <fs_attr.h>
|
||||
#include <GraphicsDefs.h>
|
||||
#include <InterfaceDefs.h>
|
||||
#include <TranslationDefs.h>
|
||||
#include <Translator.h>
|
||||
#include <TranslatorFormats.h>
|
||||
|
||||
#include "BaseTranslator.h"
|
||||
|
||||
#define AVIF_TRANSLATOR_VERSION B_TRANSLATION_MAKE_VERSION(0,1,0)
|
||||
#define AVIF_IMAGE_FORMAT 'AVIF'
|
||||
|
||||
#define AVIF_SETTING_LOSSLESS "lossless"
|
||||
#define AVIF_SETTING_PIXEL_FORMAT "pixfmt"
|
||||
#define AVIF_SETTING_QUALITY "quality"
|
||||
#define AVIF_SETTING_SPEED "speed"
|
||||
#define AVIF_SETTING_TILES_HORIZONTAL "htiles"
|
||||
#define AVIF_SETTING_TILES_VERTICAL "vtiles"
|
||||
|
||||
|
||||
#define AVIF_IN_QUALITY 0.90
|
||||
#define AVIF_IN_CAPABILITY 0.90
|
||||
|
||||
#define AVIF_OUT_QUALITY 0.90
|
||||
#define AVIF_OUT_CAPABILITY 0.5
|
||||
|
||||
#define BITS_IN_QUALITY 0.8
|
||||
#define BITS_IN_CAPABILITY 0.6
|
||||
|
||||
#define BITS_OUT_QUALITY 0.5
|
||||
#define BITS_OUT_CAPABILITY 0.4
|
||||
|
||||
|
||||
struct AVIFPicture;
|
||||
|
||||
|
||||
class AVIFTranslator : public BaseTranslator {
|
||||
public:
|
||||
AVIFTranslator();
|
||||
|
||||
virtual status_t DerivedIdentify(BPositionIO* stream,
|
||||
const translation_format* format,
|
||||
BMessage* settings, translator_info* info,
|
||||
uint32 outType);
|
||||
|
||||
virtual status_t DerivedTranslate(BPositionIO* stream,
|
||||
const translator_info* info,
|
||||
BMessage* settings, uint32 outType,
|
||||
BPositionIO* target, int32 baseType);
|
||||
|
||||
virtual BView* NewConfigView(TranslatorSettings* settings);
|
||||
|
||||
protected:
|
||||
virtual ~AVIFTranslator();
|
||||
// this is protected because the object is deleted by the
|
||||
// Release() function instead of being deleted directly by
|
||||
// the user
|
||||
|
||||
private:
|
||||
status_t _TranslateFromBits(BPositionIO* stream,
|
||||
BMessage* settings, uint32 outType,
|
||||
BPositionIO* target);
|
||||
|
||||
status_t _TranslateFromAVIF(BPositionIO* stream,
|
||||
BMessage* settings, uint32 outType,
|
||||
BPositionIO* target);
|
||||
};
|
||||
|
||||
|
||||
#endif // #ifndef AVIF_TRANSLATOR_H
|
15
src/add-ons/translators/avif/AVIFTranslator.rdef
Normal file
15
src/add-ons/translators/avif/AVIFTranslator.rdef
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* AVIFTranslator.rdef
|
||||
*/
|
||||
|
||||
resource app_signature "application/x-vnd.Haiku-AVIFTranslator";
|
||||
|
||||
resource app_version {
|
||||
major = 0,
|
||||
middle = 1,
|
||||
minor = 0,
|
||||
variety = 0,
|
||||
internal = 0,
|
||||
short_info = "0.1.0",
|
||||
long_info = "Haiku AVIFTranslator Add-Ons."
|
||||
};
|
255
src/add-ons/translators/avif/ConfigView.cpp
Normal file
255
src/add-ons/translators/avif/ConfigView.cpp
Normal file
@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Copyright 2021, Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Emmanuel Gil Peyrot
|
||||
*/
|
||||
|
||||
|
||||
#include "ConfigView.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <Catalog.h>
|
||||
#include <CheckBox.h>
|
||||
#include <LayoutBuilder.h>
|
||||
#include <MenuField.h>
|
||||
#include <MenuItem.h>
|
||||
#include <Message.h>
|
||||
#include <PopUpMenu.h>
|
||||
#include <Slider.h>
|
||||
#include <StringView.h>
|
||||
|
||||
#include "avif/avif.h"
|
||||
|
||||
#include "TranslatorSettings.h"
|
||||
#include "AVIFTranslator.h"
|
||||
|
||||
|
||||
#undef B_TRANSLATION_CONTEXT
|
||||
#define B_TRANSLATION_CONTEXT "ConfigView"
|
||||
|
||||
|
||||
static const uint32 kMsgLossless = 'losl';
|
||||
static const uint32 kMsgPixelFormat = 'pfmt';
|
||||
static const uint32 kMsgQuality = 'qlty';
|
||||
static const uint32 kMsgSpeed = 'sped';
|
||||
static const uint32 kMsgTilesHorizontal = 'tilh';
|
||||
static const uint32 kMsgTilesVertical = 'tilv';
|
||||
|
||||
|
||||
ConfigView::ConfigView(TranslatorSettings* settings)
|
||||
:
|
||||
BGroupView(B_TRANSLATE("AVIFTranslator Settings"), B_VERTICAL),
|
||||
fSettings(settings)
|
||||
{
|
||||
SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
|
||||
|
||||
BStringView* title = new BStringView("title",
|
||||
B_TRANSLATE("AVIF image translator"));
|
||||
title->SetFont(be_bold_font);
|
||||
|
||||
char versionString[256];
|
||||
sprintf(versionString, "v%d.%d.%d, %s",
|
||||
static_cast<int>(B_TRANSLATION_MAJOR_VERSION(AVIF_TRANSLATOR_VERSION)),
|
||||
static_cast<int>(B_TRANSLATION_MINOR_VERSION(AVIF_TRANSLATOR_VERSION)),
|
||||
static_cast<int>(B_TRANSLATION_REVISION_VERSION(
|
||||
AVIF_TRANSLATOR_VERSION)),
|
||||
__DATE__);
|
||||
|
||||
BStringView* version = new BStringView("version", versionString);
|
||||
|
||||
BString copyrightsText;
|
||||
BStringView *copyrightView = new BStringView("Copyright",
|
||||
B_TRANSLATE(B_UTF8_COPYRIGHT "2021 Emmanuel Gil Peyrot"));
|
||||
|
||||
BString libavifInfo = B_TRANSLATE(
|
||||
"Based on libavif %version%");
|
||||
libavifInfo.ReplaceAll("%version%", avifVersion());
|
||||
|
||||
BStringView *copyright2View = new BStringView("Copyright2",
|
||||
libavifInfo.String());
|
||||
BStringView *copyright3View = new BStringView("Copyright3",
|
||||
B_TRANSLATE(B_UTF8_COPYRIGHT "2019 Joe Drago. All rights reserved."));
|
||||
|
||||
// output parameters
|
||||
|
||||
fLosslessCheckBox = new BCheckBox("lossless",
|
||||
B_TRANSLATE("Lossless"), new BMessage(kMsgLossless));
|
||||
bool lossless;
|
||||
fSettings->SetGetBool(AVIF_SETTING_LOSSLESS, &lossless);
|
||||
if (lossless)
|
||||
fLosslessCheckBox->SetValue(B_CONTROL_ON);
|
||||
|
||||
fPixelFormatMenu = new BPopUpMenu(B_TRANSLATE("Pixel format"));
|
||||
|
||||
static const avifPixelFormat pixelFormats[4] = {
|
||||
AVIF_PIXEL_FORMAT_YUV444,
|
||||
AVIF_PIXEL_FORMAT_YUV420,
|
||||
AVIF_PIXEL_FORMAT_YUV400,
|
||||
AVIF_PIXEL_FORMAT_YUV422,
|
||||
};
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
BMessage* msg = new BMessage(kMsgPixelFormat);
|
||||
msg->AddInt32("value", pixelFormats[i]);
|
||||
|
||||
BMenuItem* item = new BMenuItem(
|
||||
avifPixelFormatToString(pixelFormats[i]), msg);
|
||||
if (fSettings->SetGetInt32(AVIF_SETTING_PIXEL_FORMAT) == pixelFormats[i])
|
||||
item->SetMarked(true);
|
||||
fPixelFormatMenu->AddItem(item);
|
||||
}
|
||||
|
||||
BMenuField* pixelFormatField = new BMenuField(B_TRANSLATE("Pixel format:"),
|
||||
fPixelFormatMenu);
|
||||
|
||||
rgb_color barColor = { 0, 0, 229, 255 };
|
||||
|
||||
fQualitySlider = new BSlider("quality", B_TRANSLATE("Output quality:"),
|
||||
new BMessage(kMsgQuality), AVIF_QUANTIZER_BEST_QUALITY,
|
||||
AVIF_QUANTIZER_WORST_QUALITY, B_HORIZONTAL, B_BLOCK_THUMB);
|
||||
fQualitySlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
|
||||
fQualitySlider->SetHashMarkCount(8);
|
||||
fQualitySlider->SetLimitLabels(B_TRANSLATE("Best"), B_TRANSLATE("Worst"));
|
||||
fQualitySlider->UseFillColor(true, &barColor);
|
||||
fQualitySlider->SetValue(fSettings->SetGetInt32(AVIF_SETTING_QUALITY));
|
||||
fQualitySlider->SetEnabled(!lossless);
|
||||
|
||||
fSpeedSlider = new BSlider("speed", B_TRANSLATE("Compression speed:"),
|
||||
new BMessage(kMsgSpeed), AVIF_SPEED_SLOWEST,
|
||||
AVIF_SPEED_FASTEST, B_HORIZONTAL, B_BLOCK_THUMB);
|
||||
fSpeedSlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
|
||||
fSpeedSlider->SetHashMarkCount(11);
|
||||
fSpeedSlider->SetLimitLabels(B_TRANSLATE("Slow"),
|
||||
B_TRANSLATE("Faster but worse quality"));
|
||||
fSpeedSlider->UseFillColor(true, &barColor);
|
||||
fSpeedSlider->SetValue(fSettings->SetGetInt32(AVIF_SETTING_SPEED));
|
||||
|
||||
fHTilesSlider = new BSlider("htiles", B_TRANSLATE("Horizontal tiles:"),
|
||||
new BMessage(kMsgTilesHorizontal), 1, 6, B_HORIZONTAL,
|
||||
B_BLOCK_THUMB);
|
||||
fHTilesSlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
|
||||
fHTilesSlider->SetHashMarkCount(6);
|
||||
fHTilesSlider->SetLimitLabels(B_TRANSLATE("1"),
|
||||
B_TRANSLATE("2⁶"));
|
||||
fHTilesSlider->UseFillColor(true, &barColor);
|
||||
fHTilesSlider->SetValue(
|
||||
fSettings->SetGetInt32(AVIF_SETTING_TILES_HORIZONTAL));
|
||||
|
||||
fVTilesSlider = new BSlider("vtiles", B_TRANSLATE("Vertical tiles:"),
|
||||
new BMessage(kMsgTilesVertical), 1, 6, B_HORIZONTAL,
|
||||
B_BLOCK_THUMB);
|
||||
fVTilesSlider->SetHashMarks(B_HASH_MARKS_BOTTOM);
|
||||
fVTilesSlider->SetHashMarkCount(6);
|
||||
fVTilesSlider->SetLimitLabels(B_TRANSLATE("1"),
|
||||
B_TRANSLATE("2⁶"));
|
||||
fVTilesSlider->UseFillColor(true, &barColor);
|
||||
fVTilesSlider->SetValue(
|
||||
fSettings->SetGetInt32(AVIF_SETTING_TILES_VERTICAL));
|
||||
|
||||
// Build the layout
|
||||
BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
|
||||
.SetInsets(B_USE_DEFAULT_SPACING)
|
||||
.Add(title)
|
||||
.Add(version)
|
||||
.Add(copyrightView)
|
||||
.AddGlue()
|
||||
.Add(fLosslessCheckBox)
|
||||
.AddGrid(B_USE_DEFAULT_SPACING, B_USE_SMALL_SPACING)
|
||||
.Add(pixelFormatField->CreateLabelLayoutItem(), 0, 0)
|
||||
.AddGroup(B_HORIZONTAL, 0.0f, 1, 0)
|
||||
.Add(pixelFormatField->CreateMenuBarLayoutItem(), 0.0f)
|
||||
.AddGlue()
|
||||
.End()
|
||||
.End()
|
||||
.Add(fQualitySlider)
|
||||
.Add(fSpeedSlider)
|
||||
.Add(fHTilesSlider)
|
||||
.Add(fVTilesSlider)
|
||||
.AddGlue()
|
||||
.Add(copyright2View)
|
||||
.Add(copyright3View);
|
||||
|
||||
BFont font;
|
||||
GetFont(&font);
|
||||
SetExplicitPreferredSize(BSize((font.Size() * 250) / 12,
|
||||
(font.Size() * 350) / 12));
|
||||
}
|
||||
|
||||
|
||||
ConfigView::~ConfigView()
|
||||
{
|
||||
fSettings->Release();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ConfigView::AttachedToWindow()
|
||||
{
|
||||
BGroupView::AttachedToWindow();
|
||||
|
||||
fQualitySlider->SetTarget(this);
|
||||
fSpeedSlider->SetTarget(this);
|
||||
fHTilesSlider->SetTarget(this);
|
||||
fVTilesSlider->SetTarget(this);
|
||||
|
||||
if (Parent() == NULL && Window()->GetLayout() == NULL) {
|
||||
Window()->SetLayout(new BGroupLayout(B_VERTICAL));
|
||||
Window()->ResizeTo(PreferredSize().Width(),
|
||||
PreferredSize().Height());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ConfigView::MessageReceived(BMessage* message)
|
||||
{
|
||||
struct {
|
||||
const char* name;
|
||||
uint32 what;
|
||||
TranSettingType type;
|
||||
} maps[] = {
|
||||
{ AVIF_SETTING_LOSSLESS, kMsgLossless, TRAN_SETTING_BOOL },
|
||||
{ AVIF_SETTING_PIXEL_FORMAT, kMsgPixelFormat,
|
||||
TRAN_SETTING_INT32 },
|
||||
{ AVIF_SETTING_QUALITY, kMsgQuality, TRAN_SETTING_INT32 },
|
||||
{ AVIF_SETTING_SPEED, kMsgSpeed, TRAN_SETTING_INT32 },
|
||||
{ AVIF_SETTING_TILES_HORIZONTAL, kMsgTilesHorizontal,
|
||||
TRAN_SETTING_INT32 },
|
||||
{ AVIF_SETTING_TILES_VERTICAL, kMsgTilesVertical,
|
||||
TRAN_SETTING_INT32 },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
int i;
|
||||
for (i = 0; maps[i].name != NULL; i++) {
|
||||
if (maps[i].what == message->what)
|
||||
break;
|
||||
}
|
||||
|
||||
if (maps[i].name == NULL) {
|
||||
BGroupView::MessageReceived(message);
|
||||
return;
|
||||
}
|
||||
|
||||
int32 value;
|
||||
if (message->FindInt32("value", &value) == B_OK
|
||||
|| message->FindInt32("be:value", &value) == B_OK) {
|
||||
switch(maps[i].type) {
|
||||
case TRAN_SETTING_BOOL:
|
||||
{
|
||||
bool boolValue = value;
|
||||
fSettings->SetGetBool(maps[i].name, &boolValue);
|
||||
if (maps[i].what == kMsgLossless)
|
||||
fSpeedSlider->SetEnabled(!boolValue);
|
||||
break;
|
||||
}
|
||||
case TRAN_SETTING_INT32:
|
||||
fSettings->SetGetInt32(maps[i].name, &value);
|
||||
break;
|
||||
}
|
||||
fSettings->SaveSettings();
|
||||
}
|
||||
}
|
38
src/add-ons/translators/avif/ConfigView.h
Normal file
38
src/add-ons/translators/avif/ConfigView.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2021, Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Emmanuel Gil Peyrot
|
||||
*/
|
||||
#ifndef CONFIG_VIEW_H
|
||||
#define CONFIG_VIEW_H
|
||||
|
||||
|
||||
#include <GroupView.h>
|
||||
|
||||
class BCheckBox;
|
||||
class BPopUpMenu;
|
||||
class BSlider;
|
||||
class TranslatorSettings;
|
||||
|
||||
class ConfigView : public BGroupView {
|
||||
public:
|
||||
ConfigView(TranslatorSettings* settings);
|
||||
virtual ~ConfigView();
|
||||
|
||||
virtual void AttachedToWindow();
|
||||
virtual void MessageReceived(BMessage *message);
|
||||
|
||||
private:
|
||||
TranslatorSettings* fSettings;
|
||||
BPopUpMenu* fPixelFormatMenu;
|
||||
BCheckBox* fLosslessCheckBox;
|
||||
BSlider* fQualitySlider;
|
||||
BSlider* fSpeedSlider;
|
||||
BSlider* fHTilesSlider;
|
||||
BSlider* fVTilesSlider;
|
||||
};
|
||||
|
||||
|
||||
#endif /* CONFIG_VIEW_H */
|
38
src/add-ons/translators/avif/Jamfile
Normal file
38
src/add-ons/translators/avif/Jamfile
Normal file
@ -0,0 +1,38 @@
|
||||
SubDir HAIKU_TOP src add-ons translators avif ;
|
||||
|
||||
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) shared ] ;
|
||||
|
||||
AddResources AVIFTranslator : AVIFTranslator.rdef ;
|
||||
|
||||
local architectureObject ;
|
||||
for architectureObject in [ MultiArchSubDirSetup ] {
|
||||
on $(architectureObject) {
|
||||
UseBuildFeatureHeaders libavif ;
|
||||
|
||||
Translator [ MultiArchDefaultGristFiles AVIFTranslator ] :
|
||||
|
||||
main.cpp
|
||||
|
||||
AVIFTranslator.cpp
|
||||
ConfigView.cpp
|
||||
|
||||
:
|
||||
be translation [ MultiArchDefaultGristFiles libtranslatorsutils.a ]
|
||||
[ BuildFeatureAttribute libavif : library ]
|
||||
[ TargetLibsupc++ ] localestub
|
||||
: true
|
||||
;
|
||||
|
||||
Includes [ FGristFiles ConfigView.cpp AVIFTranslator.cpp ]
|
||||
: [ BuildFeatureAttribute libavif : headers ] ;
|
||||
}
|
||||
}
|
||||
|
||||
DoCatalogs AVIFTranslator :
|
||||
x-vnd.Haiku-AVIFTranslator
|
||||
:
|
||||
main.cpp
|
||||
ConfigView.cpp
|
||||
AVIFTranslator.cpp
|
||||
;
|
||||
|
31
src/add-ons/translators/avif/main.cpp
Normal file
31
src/add-ons/translators/avif/main.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2021, Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Emmanuel Gil Peyrot
|
||||
*/
|
||||
|
||||
|
||||
#include <Application.h>
|
||||
#include <Catalog.h>
|
||||
|
||||
#include "TranslatorWindow.h"
|
||||
#include "AVIFTranslator.h"
|
||||
|
||||
|
||||
#undef B_TRANSLATION_CONTEXT
|
||||
#define B_TRANSLATION_CONTEXT "main"
|
||||
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
BApplication app("application/x-vnd.Haiku-AVIFTranslator");
|
||||
if (LaunchTranslatorWindow(new AVIFTranslator,
|
||||
B_TRANSLATE("AVIF Settings")) != B_OK)
|
||||
return 1;
|
||||
|
||||
app.Run();
|
||||
return 0;
|
||||
}
|
@ -1398,6 +1398,13 @@ AboutView::_CreateCreditsView()
|
||||
.SetLicense(kBSDThreeClause)
|
||||
.SetURL("http://www.webmproject.org/code/#libwebp_webp_image_library"));
|
||||
|
||||
// libavif
|
||||
_AddPackageCredit(PackageCredit("libavif")
|
||||
.SetCopyright(B_TRANSLATE(COPYRIGHT_STRING
|
||||
"2019 Joe Drago. All rights reserved."))
|
||||
.SetLicense(kBSDThreeClause)
|
||||
.SetURL("https://github.com/AOMediaCodec/libavif"));
|
||||
|
||||
// GTF
|
||||
_AddPackageCredit(PackageCredit("GTF")
|
||||
.SetCopyright(B_TRANSLATE("2001 by Andy Ritger based on the "
|
||||
|
13
src/data/mime_db/image/avif
Normal file
13
src/data/mime_db/image/avif
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
resource(0, "BEOS:TYPE") #'MIMS' "application/x-vnd.Be-meta-mime";
|
||||
|
||||
resource(1, "META:TYPE") "image/avif";
|
||||
|
||||
resource(2, "META:SNIFF_RULE") "0.50 \(\"\\000\\000\\000 ftypavif\"\)";
|
||||
|
||||
resource(3, "META:S:DESC") #'MSDC' "AV1 Image File Format";
|
||||
|
||||
resource(4, "META:EXTENS") message(234) {
|
||||
"extensions" = "avif",
|
||||
"type" = "image/avif"
|
||||
};
|
@ -130,6 +130,9 @@ requires {
|
||||
#ifdef HAIKU_BUILD_FEATURE_%HAIKU_PACKAGING_ARCH%_libpng_ENABLED
|
||||
lib:libpng16
|
||||
#endif
|
||||
#ifdef HAIKU_BUILD_FEATURE_%HAIKU_PACKAGING_ARCH%_libavif_ENABLED
|
||||
lib:libavif >= 12
|
||||
#endif
|
||||
#ifdef HAIKU_BUILD_FEATURE_%HAIKU_PACKAGING_ARCH%_openssl_ENABLED
|
||||
lib:libssl
|
||||
lib:libcrypto
|
||||
|
Loading…
Reference in New Issue
Block a user