1*147b47e0SEmmanuel Gil Peyrot /*
2*147b47e0SEmmanuel Gil Peyrot * Copyright 2021, Haiku, Inc. All rights reserved.
3*147b47e0SEmmanuel Gil Peyrot * Distributed under the terms of the MIT License.
4*147b47e0SEmmanuel Gil Peyrot *
5*147b47e0SEmmanuel Gil Peyrot * Authors:
6*147b47e0SEmmanuel Gil Peyrot * Emmanuel Gil Peyrot
7*147b47e0SEmmanuel Gil Peyrot */
8*147b47e0SEmmanuel Gil Peyrot
9*147b47e0SEmmanuel Gil Peyrot
10*147b47e0SEmmanuel Gil Peyrot #include "AVIFTranslator.h"
11*147b47e0SEmmanuel Gil Peyrot
12*147b47e0SEmmanuel Gil Peyrot #include <BufferIO.h>
13*147b47e0SEmmanuel Gil Peyrot #include <Catalog.h>
14*147b47e0SEmmanuel Gil Peyrot #include <Messenger.h>
15*147b47e0SEmmanuel Gil Peyrot #include <TranslatorRoster.h>
16*147b47e0SEmmanuel Gil Peyrot
17*147b47e0SEmmanuel Gil Peyrot #include <assert.h>
18*147b47e0SEmmanuel Gil Peyrot #include <stdio.h>
19*147b47e0SEmmanuel Gil Peyrot #include <stdlib.h>
20*147b47e0SEmmanuel Gil Peyrot #include <string.h>
21*147b47e0SEmmanuel Gil Peyrot
22*147b47e0SEmmanuel Gil Peyrot #include "avif/avif.h"
23*147b47e0SEmmanuel Gil Peyrot
24*147b47e0SEmmanuel Gil Peyrot #include "ConfigView.h"
25*147b47e0SEmmanuel Gil Peyrot #include "TranslatorSettings.h"
26*147b47e0SEmmanuel Gil Peyrot
27*147b47e0SEmmanuel Gil Peyrot
28*147b47e0SEmmanuel Gil Peyrot #undef B_TRANSLATION_CONTEXT
29*147b47e0SEmmanuel Gil Peyrot #define B_TRANSLATION_CONTEXT "AVIFTranslator"
30*147b47e0SEmmanuel Gil Peyrot
31*147b47e0SEmmanuel Gil Peyrot
32*147b47e0SEmmanuel Gil Peyrot class FreeAllocation {
33*147b47e0SEmmanuel Gil Peyrot public:
FreeAllocation(void * buffer)34*147b47e0SEmmanuel Gil Peyrot FreeAllocation(void* buffer)
35*147b47e0SEmmanuel Gil Peyrot :
36*147b47e0SEmmanuel Gil Peyrot fBuffer(buffer)
37*147b47e0SEmmanuel Gil Peyrot {
38*147b47e0SEmmanuel Gil Peyrot }
39*147b47e0SEmmanuel Gil Peyrot
~FreeAllocation()40*147b47e0SEmmanuel Gil Peyrot ~FreeAllocation()
41*147b47e0SEmmanuel Gil Peyrot {
42*147b47e0SEmmanuel Gil Peyrot free(fBuffer);
43*147b47e0SEmmanuel Gil Peyrot }
44*147b47e0SEmmanuel Gil Peyrot
45*147b47e0SEmmanuel Gil Peyrot private:
46*147b47e0SEmmanuel Gil Peyrot void* fBuffer;
47*147b47e0SEmmanuel Gil Peyrot };
48*147b47e0SEmmanuel Gil Peyrot
49*147b47e0SEmmanuel Gil Peyrot
50*147b47e0SEmmanuel Gil Peyrot // The input formats that this translator knows how to read
51*147b47e0SEmmanuel Gil Peyrot static const translation_format sInputFormats[] = {
52*147b47e0SEmmanuel Gil Peyrot {
53*147b47e0SEmmanuel Gil Peyrot AVIF_IMAGE_FORMAT,
54*147b47e0SEmmanuel Gil Peyrot B_TRANSLATOR_BITMAP,
55*147b47e0SEmmanuel Gil Peyrot AVIF_IN_QUALITY,
56*147b47e0SEmmanuel Gil Peyrot AVIF_IN_CAPABILITY,
57*147b47e0SEmmanuel Gil Peyrot "image/avif",
58*147b47e0SEmmanuel Gil Peyrot "AV1 Image File Format"
59*147b47e0SEmmanuel Gil Peyrot },
60*147b47e0SEmmanuel Gil Peyrot {
61*147b47e0SEmmanuel Gil Peyrot B_TRANSLATOR_BITMAP,
62*147b47e0SEmmanuel Gil Peyrot B_TRANSLATOR_BITMAP,
63*147b47e0SEmmanuel Gil Peyrot BITS_IN_QUALITY,
64*147b47e0SEmmanuel Gil Peyrot BITS_IN_CAPABILITY,
65*147b47e0SEmmanuel Gil Peyrot "image/x-be-bitmap",
66*147b47e0SEmmanuel Gil Peyrot "Be Bitmap Format (AVIFTranslator)"
67*147b47e0SEmmanuel Gil Peyrot },
68*147b47e0SEmmanuel Gil Peyrot };
69*147b47e0SEmmanuel Gil Peyrot
70*147b47e0SEmmanuel Gil Peyrot
71*147b47e0SEmmanuel Gil Peyrot // The output formats that this translator knows how to write
72*147b47e0SEmmanuel Gil Peyrot static const translation_format sOutputFormats[] = {
73*147b47e0SEmmanuel Gil Peyrot {
74*147b47e0SEmmanuel Gil Peyrot AVIF_IMAGE_FORMAT,
75*147b47e0SEmmanuel Gil Peyrot B_TRANSLATOR_BITMAP,
76*147b47e0SEmmanuel Gil Peyrot AVIF_OUT_QUALITY,
77*147b47e0SEmmanuel Gil Peyrot AVIF_OUT_CAPABILITY,
78*147b47e0SEmmanuel Gil Peyrot "image/avif",
79*147b47e0SEmmanuel Gil Peyrot "AV1 Image File Format"
80*147b47e0SEmmanuel Gil Peyrot },
81*147b47e0SEmmanuel Gil Peyrot {
82*147b47e0SEmmanuel Gil Peyrot B_TRANSLATOR_BITMAP,
83*147b47e0SEmmanuel Gil Peyrot B_TRANSLATOR_BITMAP,
84*147b47e0SEmmanuel Gil Peyrot BITS_OUT_QUALITY,
85*147b47e0SEmmanuel Gil Peyrot BITS_OUT_CAPABILITY,
86*147b47e0SEmmanuel Gil Peyrot "image/x-be-bitmap",
87*147b47e0SEmmanuel Gil Peyrot "Be Bitmap Format (AVIFTranslator)"
88*147b47e0SEmmanuel Gil Peyrot },
89*147b47e0SEmmanuel Gil Peyrot };
90*147b47e0SEmmanuel Gil Peyrot
91*147b47e0SEmmanuel Gil Peyrot // Default settings for the Translator
92*147b47e0SEmmanuel Gil Peyrot static const TranSetting sDefaultSettings[] = {
93*147b47e0SEmmanuel Gil Peyrot { B_TRANSLATOR_EXT_HEADER_ONLY, TRAN_SETTING_BOOL, false },
94*147b47e0SEmmanuel Gil Peyrot { B_TRANSLATOR_EXT_DATA_ONLY, TRAN_SETTING_BOOL, false },
95*147b47e0SEmmanuel Gil Peyrot { AVIF_SETTING_LOSSLESS, TRAN_SETTING_BOOL, false },
96*147b47e0SEmmanuel Gil Peyrot { AVIF_SETTING_PIXEL_FORMAT, TRAN_SETTING_INT32,
97*147b47e0SEmmanuel Gil Peyrot AVIF_PIXEL_FORMAT_YUV444 },
98*147b47e0SEmmanuel Gil Peyrot { AVIF_SETTING_QUALITY, TRAN_SETTING_INT32, 60 },
99*147b47e0SEmmanuel Gil Peyrot { AVIF_SETTING_SPEED, TRAN_SETTING_INT32, -1 },
100*147b47e0SEmmanuel Gil Peyrot { AVIF_SETTING_TILES_HORIZONTAL, TRAN_SETTING_INT32, 1 },
101*147b47e0SEmmanuel Gil Peyrot { AVIF_SETTING_TILES_VERTICAL, TRAN_SETTING_INT32, 1 },
102*147b47e0SEmmanuel Gil Peyrot };
103*147b47e0SEmmanuel Gil Peyrot
104*147b47e0SEmmanuel Gil Peyrot const uint32 kNumInputFormats = sizeof(sInputFormats) /
105*147b47e0SEmmanuel Gil Peyrot sizeof(translation_format);
106*147b47e0SEmmanuel Gil Peyrot const uint32 kNumOutputFormats = sizeof(sOutputFormats) /
107*147b47e0SEmmanuel Gil Peyrot sizeof(translation_format);
108*147b47e0SEmmanuel Gil Peyrot const uint32 kNumDefaultSettings = sizeof(sDefaultSettings) /
109*147b47e0SEmmanuel Gil Peyrot sizeof(TranSetting);
110*147b47e0SEmmanuel Gil Peyrot
111*147b47e0SEmmanuel Gil Peyrot
112*147b47e0SEmmanuel Gil Peyrot // #pragma mark -
113*147b47e0SEmmanuel Gil Peyrot
114*147b47e0SEmmanuel Gil Peyrot
AVIFTranslator()115*147b47e0SEmmanuel Gil Peyrot AVIFTranslator::AVIFTranslator()
116*147b47e0SEmmanuel Gil Peyrot :
117*147b47e0SEmmanuel Gil Peyrot BaseTranslator(B_TRANSLATE("AVIF images"),
118*147b47e0SEmmanuel Gil Peyrot B_TRANSLATE("AVIF image translator"),
119*147b47e0SEmmanuel Gil Peyrot AVIF_TRANSLATOR_VERSION,
120*147b47e0SEmmanuel Gil Peyrot sInputFormats, kNumInputFormats,
121*147b47e0SEmmanuel Gil Peyrot sOutputFormats, kNumOutputFormats,
122*147b47e0SEmmanuel Gil Peyrot "AVIFTranslator_Settings", sDefaultSettings,
123*147b47e0SEmmanuel Gil Peyrot kNumDefaultSettings, B_TRANSLATOR_BITMAP, AVIF_IMAGE_FORMAT)
124*147b47e0SEmmanuel Gil Peyrot {
125*147b47e0SEmmanuel Gil Peyrot }
126*147b47e0SEmmanuel Gil Peyrot
127*147b47e0SEmmanuel Gil Peyrot
~AVIFTranslator()128*147b47e0SEmmanuel Gil Peyrot AVIFTranslator::~AVIFTranslator()
129*147b47e0SEmmanuel Gil Peyrot {
130*147b47e0SEmmanuel Gil Peyrot }
131*147b47e0SEmmanuel Gil Peyrot
132*147b47e0SEmmanuel Gil Peyrot
133*147b47e0SEmmanuel Gil Peyrot status_t
DerivedIdentify(BPositionIO * stream,const translation_format * format,BMessage * settings,translator_info * info,uint32 outType)134*147b47e0SEmmanuel Gil Peyrot AVIFTranslator::DerivedIdentify(BPositionIO* stream,
135*147b47e0SEmmanuel Gil Peyrot const translation_format* format, BMessage* settings,
136*147b47e0SEmmanuel Gil Peyrot translator_info* info, uint32 outType)
137*147b47e0SEmmanuel Gil Peyrot {
138*147b47e0SEmmanuel Gil Peyrot (void)format;
139*147b47e0SEmmanuel Gil Peyrot (void)settings;
140*147b47e0SEmmanuel Gil Peyrot if (!outType)
141*147b47e0SEmmanuel Gil Peyrot outType = B_TRANSLATOR_BITMAP;
142*147b47e0SEmmanuel Gil Peyrot if (outType != B_TRANSLATOR_BITMAP)
143*147b47e0SEmmanuel Gil Peyrot return B_NO_TRANSLATOR;
144*147b47e0SEmmanuel Gil Peyrot
145*147b47e0SEmmanuel Gil Peyrot // Read header and first chunck bytes...
146*147b47e0SEmmanuel Gil Peyrot uint32 buf[64];
147*147b47e0SEmmanuel Gil Peyrot ssize_t size = sizeof(buf);
148*147b47e0SEmmanuel Gil Peyrot if (stream->Read(buf, size) != size)
149*147b47e0SEmmanuel Gil Peyrot return B_IO_ERROR;
150*147b47e0SEmmanuel Gil Peyrot
151*147b47e0SEmmanuel Gil Peyrot // Check it's a valid AVIF format
152*147b47e0SEmmanuel Gil Peyrot avifROData data;
153*147b47e0SEmmanuel Gil Peyrot data.data = reinterpret_cast<const uint8_t*>(buf);
154*147b47e0SEmmanuel Gil Peyrot data.size = static_cast<size_t>(size);
155*147b47e0SEmmanuel Gil Peyrot if (!avifPeekCompatibleFileType(&data))
156*147b47e0SEmmanuel Gil Peyrot return B_ILLEGAL_DATA;
157*147b47e0SEmmanuel Gil Peyrot
158*147b47e0SEmmanuel Gil Peyrot info->type = AVIF_IMAGE_FORMAT;
159*147b47e0SEmmanuel Gil Peyrot info->group = B_TRANSLATOR_BITMAP;
160*147b47e0SEmmanuel Gil Peyrot info->quality = AVIF_IN_QUALITY;
161*147b47e0SEmmanuel Gil Peyrot info->capability = AVIF_IN_CAPABILITY;
162*147b47e0SEmmanuel Gil Peyrot snprintf(info->name, sizeof(info->name), B_TRANSLATE("AVIF image"));
163*147b47e0SEmmanuel Gil Peyrot strcpy(info->MIME, "image/avif");
164*147b47e0SEmmanuel Gil Peyrot
165*147b47e0SEmmanuel Gil Peyrot return B_OK;
166*147b47e0SEmmanuel Gil Peyrot }
167*147b47e0SEmmanuel Gil Peyrot
168*147b47e0SEmmanuel Gil Peyrot
169*147b47e0SEmmanuel Gil Peyrot status_t
DerivedTranslate(BPositionIO * stream,const translator_info * info,BMessage * ioExtension,uint32 outType,BPositionIO * target,int32 baseType)170*147b47e0SEmmanuel Gil Peyrot AVIFTranslator::DerivedTranslate(BPositionIO* stream,
171*147b47e0SEmmanuel Gil Peyrot const translator_info* info, BMessage* ioExtension, uint32 outType,
172*147b47e0SEmmanuel Gil Peyrot BPositionIO* target, int32 baseType)
173*147b47e0SEmmanuel Gil Peyrot {
174*147b47e0SEmmanuel Gil Peyrot (void)info;
175*147b47e0SEmmanuel Gil Peyrot if (baseType == 1)
176*147b47e0SEmmanuel Gil Peyrot // if stream is in bits format
177*147b47e0SEmmanuel Gil Peyrot return _TranslateFromBits(stream, ioExtension, outType, target);
178*147b47e0SEmmanuel Gil Peyrot else if (baseType == 0)
179*147b47e0SEmmanuel Gil Peyrot // if stream is NOT in bits format
180*147b47e0SEmmanuel Gil Peyrot return _TranslateFromAVIF(stream, ioExtension, outType, target);
181*147b47e0SEmmanuel Gil Peyrot else
182*147b47e0SEmmanuel Gil Peyrot // if BaseTranslator dit not properly identify the data as
183*147b47e0SEmmanuel Gil Peyrot // bits or not bits
184*147b47e0SEmmanuel Gil Peyrot return B_NO_TRANSLATOR;
185*147b47e0SEmmanuel Gil Peyrot }
186*147b47e0SEmmanuel Gil Peyrot
187*147b47e0SEmmanuel Gil Peyrot
188*147b47e0SEmmanuel Gil Peyrot BView*
NewConfigView(TranslatorSettings * settings)189*147b47e0SEmmanuel Gil Peyrot AVIFTranslator::NewConfigView(TranslatorSettings* settings)
190*147b47e0SEmmanuel Gil Peyrot {
191*147b47e0SEmmanuel Gil Peyrot return new ConfigView(settings);
192*147b47e0SEmmanuel Gil Peyrot }
193*147b47e0SEmmanuel Gil Peyrot
194*147b47e0SEmmanuel Gil Peyrot
195*147b47e0SEmmanuel Gil Peyrot status_t
_TranslateFromBits(BPositionIO * stream,BMessage * ioExtension,uint32 outType,BPositionIO * target)196*147b47e0SEmmanuel Gil Peyrot AVIFTranslator::_TranslateFromBits(BPositionIO* stream, BMessage* ioExtension,
197*147b47e0SEmmanuel Gil Peyrot uint32 outType, BPositionIO* target)
198*147b47e0SEmmanuel Gil Peyrot {
199*147b47e0SEmmanuel Gil Peyrot // FIXME: This codepath is completely untested for now, due to libavif
200*147b47e0SEmmanuel Gil Peyrot // being built without any encoder in haikuports.
201*147b47e0SEmmanuel Gil Peyrot
202*147b47e0SEmmanuel Gil Peyrot (void)ioExtension;
203*147b47e0SEmmanuel Gil Peyrot if (!outType)
204*147b47e0SEmmanuel Gil Peyrot outType = AVIF_IMAGE_FORMAT;
205*147b47e0SEmmanuel Gil Peyrot if (outType != AVIF_IMAGE_FORMAT)
206*147b47e0SEmmanuel Gil Peyrot return B_NO_TRANSLATOR;
207*147b47e0SEmmanuel Gil Peyrot
208*147b47e0SEmmanuel Gil Peyrot TranslatorBitmap bitsHeader;
209*147b47e0SEmmanuel Gil Peyrot status_t status;
210*147b47e0SEmmanuel Gil Peyrot
211*147b47e0SEmmanuel Gil Peyrot status = identify_bits_header(stream, NULL, &bitsHeader);
212*147b47e0SEmmanuel Gil Peyrot if (status != B_OK)
213*147b47e0SEmmanuel Gil Peyrot return status;
214*147b47e0SEmmanuel Gil Peyrot
215*147b47e0SEmmanuel Gil Peyrot avifPixelFormat format = static_cast<avifPixelFormat>(
216*147b47e0SEmmanuel Gil Peyrot fSettings->SetGetInt32(AVIF_SETTING_PIXEL_FORMAT));
217*147b47e0SEmmanuel Gil Peyrot int32 bytesPerPixel;
218*147b47e0SEmmanuel Gil Peyrot avifRGBFormat rgbFormat;
219*147b47e0SEmmanuel Gil Peyrot bool isRGB = true;
220*147b47e0SEmmanuel Gil Peyrot bool ignoreAlpha = false;
221*147b47e0SEmmanuel Gil Peyrot switch (bitsHeader.colors) {
222*147b47e0SEmmanuel Gil Peyrot case B_RGB32:
223*147b47e0SEmmanuel Gil Peyrot rgbFormat = AVIF_RGB_FORMAT_BGRA;
224*147b47e0SEmmanuel Gil Peyrot ignoreAlpha = true;
225*147b47e0SEmmanuel Gil Peyrot bytesPerPixel = 4;
226*147b47e0SEmmanuel Gil Peyrot break;
227*147b47e0SEmmanuel Gil Peyrot
228*147b47e0SEmmanuel Gil Peyrot case B_RGB32_BIG:
229*147b47e0SEmmanuel Gil Peyrot rgbFormat = AVIF_RGB_FORMAT_ARGB;
230*147b47e0SEmmanuel Gil Peyrot ignoreAlpha = true;
231*147b47e0SEmmanuel Gil Peyrot bytesPerPixel = 4;
232*147b47e0SEmmanuel Gil Peyrot break;
233*147b47e0SEmmanuel Gil Peyrot
234*147b47e0SEmmanuel Gil Peyrot case B_RGBA32:
235*147b47e0SEmmanuel Gil Peyrot rgbFormat = AVIF_RGB_FORMAT_BGRA;
236*147b47e0SEmmanuel Gil Peyrot bytesPerPixel = 4;
237*147b47e0SEmmanuel Gil Peyrot break;
238*147b47e0SEmmanuel Gil Peyrot
239*147b47e0SEmmanuel Gil Peyrot case B_RGBA32_BIG:
240*147b47e0SEmmanuel Gil Peyrot rgbFormat = AVIF_RGB_FORMAT_ARGB;
241*147b47e0SEmmanuel Gil Peyrot bytesPerPixel = 4;
242*147b47e0SEmmanuel Gil Peyrot break;
243*147b47e0SEmmanuel Gil Peyrot
244*147b47e0SEmmanuel Gil Peyrot case B_RGB24:
245*147b47e0SEmmanuel Gil Peyrot rgbFormat = AVIF_RGB_FORMAT_BGR;
246*147b47e0SEmmanuel Gil Peyrot bytesPerPixel = 3;
247*147b47e0SEmmanuel Gil Peyrot break;
248*147b47e0SEmmanuel Gil Peyrot
249*147b47e0SEmmanuel Gil Peyrot case B_RGB24_BIG:
250*147b47e0SEmmanuel Gil Peyrot rgbFormat = AVIF_RGB_FORMAT_RGB;
251*147b47e0SEmmanuel Gil Peyrot bytesPerPixel = 3;
252*147b47e0SEmmanuel Gil Peyrot break;
253*147b47e0SEmmanuel Gil Peyrot
254*147b47e0SEmmanuel Gil Peyrot case B_YCbCr444:
255*147b47e0SEmmanuel Gil Peyrot bytesPerPixel = 3;
256*147b47e0SEmmanuel Gil Peyrot isRGB = false;
257*147b47e0SEmmanuel Gil Peyrot break;
258*147b47e0SEmmanuel Gil Peyrot
259*147b47e0SEmmanuel Gil Peyrot case B_GRAY8:
260*147b47e0SEmmanuel Gil Peyrot bytesPerPixel = 1;
261*147b47e0SEmmanuel Gil Peyrot isRGB = false;
262*147b47e0SEmmanuel Gil Peyrot break;
263*147b47e0SEmmanuel Gil Peyrot
264*147b47e0SEmmanuel Gil Peyrot default:
265*147b47e0SEmmanuel Gil Peyrot printf("ERROR: Colorspace not supported: %d\n",
266*147b47e0SEmmanuel Gil Peyrot bitsHeader.colors);
267*147b47e0SEmmanuel Gil Peyrot return B_NO_TRANSLATOR;
268*147b47e0SEmmanuel Gil Peyrot }
269*147b47e0SEmmanuel Gil Peyrot
270*147b47e0SEmmanuel Gil Peyrot int width = bitsHeader.bounds.IntegerWidth() + 1;
271*147b47e0SEmmanuel Gil Peyrot int height = bitsHeader.bounds.IntegerHeight() + 1;
272*147b47e0SEmmanuel Gil Peyrot int depth = 8;
273*147b47e0SEmmanuel Gil Peyrot
274*147b47e0SEmmanuel Gil Peyrot avifImage* image = avifImageCreate(width, height, depth, format);
275*147b47e0SEmmanuel Gil Peyrot image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709;
276*147b47e0SEmmanuel Gil Peyrot image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SRGB;
277*147b47e0SEmmanuel Gil Peyrot image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_IDENTITY;
278*147b47e0SEmmanuel Gil Peyrot
279*147b47e0SEmmanuel Gil Peyrot if (isRGB) {
280*147b47e0SEmmanuel Gil Peyrot image->yuvRange = AVIF_RANGE_FULL;
281*147b47e0SEmmanuel Gil Peyrot
282*147b47e0SEmmanuel Gil Peyrot avifRGBImage rgb;
283*147b47e0SEmmanuel Gil Peyrot avifRGBImageSetDefaults(&rgb, image);
284*147b47e0SEmmanuel Gil Peyrot rgb.depth = depth;
285*147b47e0SEmmanuel Gil Peyrot rgb.format = rgbFormat;
286*147b47e0SEmmanuel Gil Peyrot rgb.ignoreAlpha = ignoreAlpha;
287*147b47e0SEmmanuel Gil Peyrot int bitsSize = height * bitsHeader.rowBytes;
288*147b47e0SEmmanuel Gil Peyrot rgb.pixels = static_cast<uint8_t*>(malloc(bitsSize));
289*147b47e0SEmmanuel Gil Peyrot if (rgb.pixels == NULL)
290*147b47e0SEmmanuel Gil Peyrot return B_NO_MEMORY;
291*147b47e0SEmmanuel Gil Peyrot rgb.rowBytes = bitsHeader.rowBytes;
292*147b47e0SEmmanuel Gil Peyrot
293*147b47e0SEmmanuel Gil Peyrot if (stream->Read(rgb.pixels, bitsSize) != bitsSize) {
294*147b47e0SEmmanuel Gil Peyrot free(rgb.pixels);
295*147b47e0SEmmanuel Gil Peyrot return B_IO_ERROR;
296*147b47e0SEmmanuel Gil Peyrot }
297*147b47e0SEmmanuel Gil Peyrot
298*147b47e0SEmmanuel Gil Peyrot avifResult conversionResult = avifImageRGBToYUV(image, &rgb);
299*147b47e0SEmmanuel Gil Peyrot free(rgb.pixels);
300*147b47e0SEmmanuel Gil Peyrot if (conversionResult != AVIF_RESULT_OK)
301*147b47e0SEmmanuel Gil Peyrot return B_ERROR;
302*147b47e0SEmmanuel Gil Peyrot } else if (bytesPerPixel == 3) {
303*147b47e0SEmmanuel Gil Peyrot // TODO: Investigate moving that to libavif instead, and do so
304*147b47e0SEmmanuel Gil Peyrot // for other Y'CbCr formats too.
305*147b47e0SEmmanuel Gil Peyrot //
306*147b47e0SEmmanuel Gil Peyrot // See also https://github.com/AOMediaCodec/libavif/pull/235
307*147b47e0SEmmanuel Gil Peyrot assert(bitsHeader.colors == B_YCbCr444);
308*147b47e0SEmmanuel Gil Peyrot int bitsSize = height * bitsHeader.rowBytes;
309*147b47e0SEmmanuel Gil Peyrot uint8_t* pixels = static_cast<uint8_t*>(malloc(bitsSize));
310*147b47e0SEmmanuel Gil Peyrot if (stream->Read(pixels, bitsSize) != bitsSize)
311*147b47e0SEmmanuel Gil Peyrot return B_IO_ERROR;
312*147b47e0SEmmanuel Gil Peyrot
313*147b47e0SEmmanuel Gil Peyrot uint8_t* luma = static_cast<uint8_t*>(malloc(bitsSize / 3));
314*147b47e0SEmmanuel Gil Peyrot uint8_t* cb = static_cast<uint8_t*>(malloc(bitsSize / 3));
315*147b47e0SEmmanuel Gil Peyrot uint8_t* cr = static_cast<uint8_t*>(malloc(bitsSize / 3));
316*147b47e0SEmmanuel Gil Peyrot
317*147b47e0SEmmanuel Gil Peyrot for (int i = 0; i < bitsSize / 3; ++i) {
318*147b47e0SEmmanuel Gil Peyrot luma[i] = pixels[3 * i + 0];
319*147b47e0SEmmanuel Gil Peyrot cb[i] = pixels[3 * i + 1];
320*147b47e0SEmmanuel Gil Peyrot cr[i] = pixels[3 * i + 2];
321*147b47e0SEmmanuel Gil Peyrot }
322*147b47e0SEmmanuel Gil Peyrot
323*147b47e0SEmmanuel Gil Peyrot image->yuvPlanes[0] = luma;
324*147b47e0SEmmanuel Gil Peyrot image->yuvPlanes[1] = cb;
325*147b47e0SEmmanuel Gil Peyrot image->yuvPlanes[2] = cr;
326*147b47e0SEmmanuel Gil Peyrot
327*147b47e0SEmmanuel Gil Peyrot image->yuvRowBytes[0] = bitsHeader.rowBytes / 3;
328*147b47e0SEmmanuel Gil Peyrot image->yuvRowBytes[1] = bitsHeader.rowBytes / 3;
329*147b47e0SEmmanuel Gil Peyrot image->yuvRowBytes[2] = bitsHeader.rowBytes / 3;
330*147b47e0SEmmanuel Gil Peyrot
331*147b47e0SEmmanuel Gil Peyrot image->yuvRange = AVIF_RANGE_LIMITED;
332*147b47e0SEmmanuel Gil Peyrot } else {
333*147b47e0SEmmanuel Gil Peyrot assert(bitsHeader.colors == B_GRAY8);
334*147b47e0SEmmanuel Gil Peyrot int bitsSize = height * bitsHeader.rowBytes;
335*147b47e0SEmmanuel Gil Peyrot uint8_t* luma = static_cast<uint8_t*>(malloc(bitsSize));
336*147b47e0SEmmanuel Gil Peyrot if (stream->Read(luma, bitsSize) != bitsSize)
337*147b47e0SEmmanuel Gil Peyrot return B_IO_ERROR;
338*147b47e0SEmmanuel Gil Peyrot
339*147b47e0SEmmanuel Gil Peyrot image->yuvPlanes[0] = luma;
340*147b47e0SEmmanuel Gil Peyrot image->yuvPlanes[1] = nullptr;
341*147b47e0SEmmanuel Gil Peyrot image->yuvPlanes[2] = nullptr;
342*147b47e0SEmmanuel Gil Peyrot
343*147b47e0SEmmanuel Gil Peyrot image->yuvRowBytes[0] = bitsHeader.rowBytes;
344*147b47e0SEmmanuel Gil Peyrot image->yuvRowBytes[1] = 0;
345*147b47e0SEmmanuel Gil Peyrot image->yuvRowBytes[2] = 0;
346*147b47e0SEmmanuel Gil Peyrot }
347*147b47e0SEmmanuel Gil Peyrot
348*147b47e0SEmmanuel Gil Peyrot avifRWData output = AVIF_DATA_EMPTY;
349*147b47e0SEmmanuel Gil Peyrot avifEncoder* encoder = avifEncoderCreate();
350*147b47e0SEmmanuel Gil Peyrot
351*147b47e0SEmmanuel Gil Peyrot system_info info;
352*147b47e0SEmmanuel Gil Peyrot encoder->maxThreads = (get_system_info(&info) == B_OK) ?
353*147b47e0SEmmanuel Gil Peyrot info.cpu_count : 1;
354*147b47e0SEmmanuel Gil Peyrot
355*147b47e0SEmmanuel Gil Peyrot if (fSettings->SetGetBool(AVIF_SETTING_LOSSLESS)) {
356*147b47e0SEmmanuel Gil Peyrot encoder->minQuantizer = AVIF_QUANTIZER_LOSSLESS;
357*147b47e0SEmmanuel Gil Peyrot encoder->maxQuantizer = AVIF_QUANTIZER_LOSSLESS;
358*147b47e0SEmmanuel Gil Peyrot } else {
359*147b47e0SEmmanuel Gil Peyrot encoder->minQuantizer = encoder->maxQuantizer
360*147b47e0SEmmanuel Gil Peyrot = fSettings->SetGetInt32(AVIF_SETTING_QUALITY);
361*147b47e0SEmmanuel Gil Peyrot }
362*147b47e0SEmmanuel Gil Peyrot encoder->speed = fSettings->SetGetInt32(AVIF_SETTING_SPEED);
363*147b47e0SEmmanuel Gil Peyrot encoder->tileColsLog2
364*147b47e0SEmmanuel Gil Peyrot = fSettings->SetGetInt32(AVIF_SETTING_TILES_HORIZONTAL);
365*147b47e0SEmmanuel Gil Peyrot encoder->tileRowsLog2
366*147b47e0SEmmanuel Gil Peyrot = fSettings->SetGetInt32(AVIF_SETTING_TILES_VERTICAL);
367*147b47e0SEmmanuel Gil Peyrot
368*147b47e0SEmmanuel Gil Peyrot avifResult encodeResult = avifEncoderWrite(encoder, image, &output);
369*147b47e0SEmmanuel Gil Peyrot avifImageDestroy(image);
370*147b47e0SEmmanuel Gil Peyrot avifEncoderDestroy(encoder);
371*147b47e0SEmmanuel Gil Peyrot
372*147b47e0SEmmanuel Gil Peyrot if (encodeResult != AVIF_RESULT_OK) {
373*147b47e0SEmmanuel Gil Peyrot printf("ERROR: Failed to encode: %s\n",
374*147b47e0SEmmanuel Gil Peyrot avifResultToString(encodeResult));
375*147b47e0SEmmanuel Gil Peyrot avifRWDataFree(&output);
376*147b47e0SEmmanuel Gil Peyrot return B_ERROR;
377*147b47e0SEmmanuel Gil Peyrot }
378*147b47e0SEmmanuel Gil Peyrot
379*147b47e0SEmmanuel Gil Peyrot // output contains a valid .avif file's contents
380*147b47e0SEmmanuel Gil Peyrot target->Write(output.data, output.size);
381*147b47e0SEmmanuel Gil Peyrot avifRWDataFree(&output);
382*147b47e0SEmmanuel Gil Peyrot return B_OK;
383*147b47e0SEmmanuel Gil Peyrot }
384*147b47e0SEmmanuel Gil Peyrot
385*147b47e0SEmmanuel Gil Peyrot
386*147b47e0SEmmanuel Gil Peyrot status_t
_TranslateFromAVIF(BPositionIO * stream,BMessage * ioExtension,uint32 outType,BPositionIO * target)387*147b47e0SEmmanuel Gil Peyrot AVIFTranslator::_TranslateFromAVIF(BPositionIO* stream, BMessage* ioExtension,
388*147b47e0SEmmanuel Gil Peyrot uint32 outType, BPositionIO* target)
389*147b47e0SEmmanuel Gil Peyrot {
390*147b47e0SEmmanuel Gil Peyrot if (!outType)
391*147b47e0SEmmanuel Gil Peyrot outType = B_TRANSLATOR_BITMAP;
392*147b47e0SEmmanuel Gil Peyrot if (outType != B_TRANSLATOR_BITMAP)
393*147b47e0SEmmanuel Gil Peyrot return B_NO_TRANSLATOR;
394*147b47e0SEmmanuel Gil Peyrot
395*147b47e0SEmmanuel Gil Peyrot off_t streamLength = 0;
396*147b47e0SEmmanuel Gil Peyrot stream->GetSize(&streamLength);
397*147b47e0SEmmanuel Gil Peyrot
398*147b47e0SEmmanuel Gil Peyrot off_t streamSize = stream->Seek(0, SEEK_END);
399*147b47e0SEmmanuel Gil Peyrot stream->Seek(0, SEEK_SET);
400*147b47e0SEmmanuel Gil Peyrot
401*147b47e0SEmmanuel Gil Peyrot void* streamData = malloc(streamSize);
402*147b47e0SEmmanuel Gil Peyrot if (streamData == NULL)
403*147b47e0SEmmanuel Gil Peyrot return B_NO_MEMORY;
404*147b47e0SEmmanuel Gil Peyrot
405*147b47e0SEmmanuel Gil Peyrot if (stream->Read(streamData, streamSize) != streamSize) {
406*147b47e0SEmmanuel Gil Peyrot free(streamData);
407*147b47e0SEmmanuel Gil Peyrot return B_IO_ERROR;
408*147b47e0SEmmanuel Gil Peyrot }
409*147b47e0SEmmanuel Gil Peyrot
410*147b47e0SEmmanuel Gil Peyrot avifDecoder* decoder = avifDecoderCreate();
411*147b47e0SEmmanuel Gil Peyrot if (decoder == NULL) {
412*147b47e0SEmmanuel Gil Peyrot free(streamData);
413*147b47e0SEmmanuel Gil Peyrot return B_NO_MEMORY;
414*147b47e0SEmmanuel Gil Peyrot }
415*147b47e0SEmmanuel Gil Peyrot
416*147b47e0SEmmanuel Gil Peyrot avifResult setIOMemoryResult = avifDecoderSetIOMemory(decoder,
417*147b47e0SEmmanuel Gil Peyrot reinterpret_cast<const uint8_t *>(streamData), streamSize);
418*147b47e0SEmmanuel Gil Peyrot if (setIOMemoryResult != AVIF_RESULT_OK) {
419*147b47e0SEmmanuel Gil Peyrot free(streamData);
420*147b47e0SEmmanuel Gil Peyrot return B_NO_MEMORY;
421*147b47e0SEmmanuel Gil Peyrot }
422*147b47e0SEmmanuel Gil Peyrot
423*147b47e0SEmmanuel Gil Peyrot avifResult decodeResult = avifDecoderParse(decoder);
424*147b47e0SEmmanuel Gil Peyrot if (decodeResult != AVIF_RESULT_OK) {
425*147b47e0SEmmanuel Gil Peyrot free(streamData);
426*147b47e0SEmmanuel Gil Peyrot return B_ILLEGAL_DATA;
427*147b47e0SEmmanuel Gil Peyrot }
428*147b47e0SEmmanuel Gil Peyrot
429*147b47e0SEmmanuel Gil Peyrot // We don’t support animations yet.
430*147b47e0SEmmanuel Gil Peyrot if (decoder->imageCount != 1) {
431*147b47e0SEmmanuel Gil Peyrot free(streamData);
432*147b47e0SEmmanuel Gil Peyrot return B_ILLEGAL_DATA;
433*147b47e0SEmmanuel Gil Peyrot }
434*147b47e0SEmmanuel Gil Peyrot
435*147b47e0SEmmanuel Gil Peyrot avifResult nextImageResult = avifDecoderNextImage(decoder);
436*147b47e0SEmmanuel Gil Peyrot free(streamData);
437*147b47e0SEmmanuel Gil Peyrot if (nextImageResult != AVIF_RESULT_OK)
438*147b47e0SEmmanuel Gil Peyrot return B_ILLEGAL_DATA;
439*147b47e0SEmmanuel Gil Peyrot
440*147b47e0SEmmanuel Gil Peyrot avifImage* image = decoder->image;
441*147b47e0SEmmanuel Gil Peyrot int width = image->width;
442*147b47e0SEmmanuel Gil Peyrot int height = image->height;
443*147b47e0SEmmanuel Gil Peyrot avifRGBFormat format;
444*147b47e0SEmmanuel Gil Peyrot uint8_t* pixels;
445*147b47e0SEmmanuel Gil Peyrot uint32_t rowBytes;
446*147b47e0SEmmanuel Gil Peyrot color_space colors;
447*147b47e0SEmmanuel Gil Peyrot
448*147b47e0SEmmanuel Gil Peyrot bool convertToRGB = true;
449*147b47e0SEmmanuel Gil Peyrot if (image->alphaPlane) {
450*147b47e0SEmmanuel Gil Peyrot format = AVIF_RGB_FORMAT_BGRA;
451*147b47e0SEmmanuel Gil Peyrot colors = B_RGBA32;
452*147b47e0SEmmanuel Gil Peyrot } else if (image->yuvFormat == AVIF_PIXEL_FORMAT_YUV400) {
453*147b47e0SEmmanuel Gil Peyrot colors = B_GRAY8;
454*147b47e0SEmmanuel Gil Peyrot convertToRGB = false;
455*147b47e0SEmmanuel Gil Peyrot } else {
456*147b47e0SEmmanuel Gil Peyrot format = AVIF_RGB_FORMAT_BGR;
457*147b47e0SEmmanuel Gil Peyrot colors = B_RGB24;
458*147b47e0SEmmanuel Gil Peyrot }
459*147b47e0SEmmanuel Gil Peyrot
460*147b47e0SEmmanuel Gil Peyrot if (convertToRGB) {
461*147b47e0SEmmanuel Gil Peyrot avifRGBImage rgb;
462*147b47e0SEmmanuel Gil Peyrot avifRGBImageSetDefaults(&rgb, image);
463*147b47e0SEmmanuel Gil Peyrot rgb.depth = 8;
464*147b47e0SEmmanuel Gil Peyrot rgb.format = format;
465*147b47e0SEmmanuel Gil Peyrot
466*147b47e0SEmmanuel Gil Peyrot avifRGBImageAllocatePixels(&rgb);
467*147b47e0SEmmanuel Gil Peyrot avifResult conversionResult = avifImageYUVToRGB(image, &rgb);
468*147b47e0SEmmanuel Gil Peyrot if (conversionResult != AVIF_RESULT_OK)
469*147b47e0SEmmanuel Gil Peyrot return B_ILLEGAL_DATA;
470*147b47e0SEmmanuel Gil Peyrot
471*147b47e0SEmmanuel Gil Peyrot pixels = rgb.pixels;
472*147b47e0SEmmanuel Gil Peyrot rowBytes = rgb.rowBytes;
473*147b47e0SEmmanuel Gil Peyrot } else {
474*147b47e0SEmmanuel Gil Peyrot // TODO: Add a downsampling (with dithering?) path here, or
475*147b47e0SEmmanuel Gil Peyrot // alternatively add support for higher bit depth to Haiku
476*147b47e0SEmmanuel Gil Peyrot // bitmaps, possibly with HDR too.
477*147b47e0SEmmanuel Gil Peyrot if (image->depth > 8)
478*147b47e0SEmmanuel Gil Peyrot return B_ILLEGAL_DATA;
479*147b47e0SEmmanuel Gil Peyrot
480*147b47e0SEmmanuel Gil Peyrot // TODO: Add support for more than just the luma plane.
481*147b47e0SEmmanuel Gil Peyrot pixels = image->yuvPlanes[0];
482*147b47e0SEmmanuel Gil Peyrot rowBytes = image->yuvRowBytes[0];
483*147b47e0SEmmanuel Gil Peyrot }
484*147b47e0SEmmanuel Gil Peyrot
485*147b47e0SEmmanuel Gil Peyrot uint32 dataSize = rowBytes * height;
486*147b47e0SEmmanuel Gil Peyrot
487*147b47e0SEmmanuel Gil Peyrot TranslatorBitmap bitmapHeader;
488*147b47e0SEmmanuel Gil Peyrot bitmapHeader.magic = B_TRANSLATOR_BITMAP;
489*147b47e0SEmmanuel Gil Peyrot bitmapHeader.bounds.Set(0, 0, width - 1, height - 1);
490*147b47e0SEmmanuel Gil Peyrot bitmapHeader.rowBytes = rowBytes;
491*147b47e0SEmmanuel Gil Peyrot bitmapHeader.colors = colors;
492*147b47e0SEmmanuel Gil Peyrot bitmapHeader.dataSize = dataSize;
493*147b47e0SEmmanuel Gil Peyrot
494*147b47e0SEmmanuel Gil Peyrot // write out Be's Bitmap header
495*147b47e0SEmmanuel Gil Peyrot swap_data(B_UINT32_TYPE, &bitmapHeader, sizeof(TranslatorBitmap),
496*147b47e0SEmmanuel Gil Peyrot B_SWAP_HOST_TO_BENDIAN);
497*147b47e0SEmmanuel Gil Peyrot ssize_t bytesWritten = target->Write(&bitmapHeader,
498*147b47e0SEmmanuel Gil Peyrot sizeof(TranslatorBitmap));
499*147b47e0SEmmanuel Gil Peyrot if (bytesWritten < B_OK)
500*147b47e0SEmmanuel Gil Peyrot return bytesWritten;
501*147b47e0SEmmanuel Gil Peyrot
502*147b47e0SEmmanuel Gil Peyrot if ((size_t)bytesWritten != sizeof(TranslatorBitmap))
503*147b47e0SEmmanuel Gil Peyrot return B_IO_ERROR;
504*147b47e0SEmmanuel Gil Peyrot
505*147b47e0SEmmanuel Gil Peyrot bool headerOnly = false;
506*147b47e0SEmmanuel Gil Peyrot if (ioExtension != NULL)
507*147b47e0SEmmanuel Gil Peyrot ioExtension->FindBool(B_TRANSLATOR_EXT_HEADER_ONLY,
508*147b47e0SEmmanuel Gil Peyrot &headerOnly);
509*147b47e0SEmmanuel Gil Peyrot
510*147b47e0SEmmanuel Gil Peyrot if (headerOnly)
511*147b47e0SEmmanuel Gil Peyrot return B_OK;
512*147b47e0SEmmanuel Gil Peyrot
513*147b47e0SEmmanuel Gil Peyrot bytesWritten = target->Write(pixels, dataSize);
514*147b47e0SEmmanuel Gil Peyrot if (bytesWritten < B_OK)
515*147b47e0SEmmanuel Gil Peyrot return bytesWritten;
516*147b47e0SEmmanuel Gil Peyrot return B_OK;
517*147b47e0SEmmanuel Gil Peyrot }
518*147b47e0SEmmanuel Gil Peyrot
519*147b47e0SEmmanuel Gil Peyrot
520*147b47e0SEmmanuel Gil Peyrot // #pragma mark -
521*147b47e0SEmmanuel Gil Peyrot
522*147b47e0SEmmanuel Gil Peyrot
523*147b47e0SEmmanuel Gil Peyrot BTranslator*
make_nth_translator(int32 n,image_id you,uint32 flags,...)524*147b47e0SEmmanuel Gil Peyrot make_nth_translator(int32 n, image_id you, uint32 flags, ...)
525*147b47e0SEmmanuel Gil Peyrot {
526*147b47e0SEmmanuel Gil Peyrot (void)you;
527*147b47e0SEmmanuel Gil Peyrot (void)flags;
528*147b47e0SEmmanuel Gil Peyrot if (n != 0)
529*147b47e0SEmmanuel Gil Peyrot return NULL;
530*147b47e0SEmmanuel Gil Peyrot
531*147b47e0SEmmanuel Gil Peyrot return new AVIFTranslator();
532*147b47e0SEmmanuel Gil Peyrot }
533