xref: /haiku/src/add-ons/translators/avif/AVIFTranslator.cpp (revision 147b47e086545e69669779a5a738465852b3125e)
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