1 // Copyright 2011 Google Inc. All Rights Reserved.
3 // Use of this source code is governed by a BSD-style license
4 // that can be found in the COPYING file in the root of the source
5 // tree. An additional intellectual property rights grant can be found
6 // in the file PATENTS. All contributing project authors may
7 // be found in the AUTHORS file in the root of the source tree.
8 // -----------------------------------------------------------------------------
10 // functions for sample output.
12 // Author: Skal (pascal.massimino@gmail.com)
16 #include "../dec/vp8i.h"
18 #include "../dsp/dsp.h"
19 #include "../dsp/yuv.h"
20 #include "../utils/utils.h"
22 //------------------------------------------------------------------------------
23 // Main YUV<->RGB conversion functions
25 static int EmitYUV(const VP8Io
* const io
, WebPDecParams
* const p
) {
26 WebPDecBuffer
* output
= p
->output
;
27 const WebPYUVABuffer
* const buf
= &output
->u
.YUVA
;
28 uint8_t* const y_dst
= buf
->y
+ io
->mb_y
* buf
->y_stride
;
29 uint8_t* const u_dst
= buf
->u
+ (io
->mb_y
>> 1) * buf
->u_stride
;
30 uint8_t* const v_dst
= buf
->v
+ (io
->mb_y
>> 1) * buf
->v_stride
;
31 const int mb_w
= io
->mb_w
;
32 const int mb_h
= io
->mb_h
;
33 const int uv_w
= (mb_w
+ 1) / 2;
34 const int uv_h
= (mb_h
+ 1) / 2;
36 for (j
= 0; j
< mb_h
; ++j
) {
37 memcpy(y_dst
+ j
* buf
->y_stride
, io
->y
+ j
* io
->y_stride
, mb_w
);
39 for (j
= 0; j
< uv_h
; ++j
) {
40 memcpy(u_dst
+ j
* buf
->u_stride
, io
->u
+ j
* io
->uv_stride
, uv_w
);
41 memcpy(v_dst
+ j
* buf
->v_stride
, io
->v
+ j
* io
->uv_stride
, uv_w
);
46 // Point-sampling U/V sampler.
47 static int EmitSampledRGB(const VP8Io
* const io
, WebPDecParams
* const p
) {
48 WebPDecBuffer
* const output
= p
->output
;
49 WebPRGBABuffer
* const buf
= &output
->u
.RGBA
;
50 uint8_t* const dst
= buf
->rgba
+ io
->mb_y
* buf
->stride
;
51 WebPSamplerProcessPlane(io
->y
, io
->y_stride
,
52 io
->u
, io
->v
, io
->uv_stride
,
53 dst
, buf
->stride
, io
->mb_w
, io
->mb_h
,
54 WebPSamplers
[output
->colorspace
]);
58 //------------------------------------------------------------------------------
59 // YUV444 -> RGB conversion
61 #if 0 // TODO(skal): this is for future rescaling.
62 static int EmitRGB(const VP8Io
* const io
, WebPDecParams
* const p
) {
63 WebPDecBuffer
* output
= p
->output
;
64 const WebPRGBABuffer
* const buf
= &output
->u
.RGBA
;
65 uint8_t* dst
= buf
->rgba
+ io
->mb_y
* buf
->stride
;
66 const uint8_t* y_src
= io
->y
;
67 const uint8_t* u_src
= io
->u
;
68 const uint8_t* v_src
= io
->v
;
69 const WebPYUV444Converter convert
= WebPYUV444Converters
[output
->colorspace
];
70 const int mb_w
= io
->mb_w
;
71 const int last
= io
->mb_h
;
73 for (j
= 0; j
< last
; ++j
) {
74 convert(y_src
, u_src
, v_src
, dst
, mb_w
);
75 y_src
+= io
->y_stride
;
76 u_src
+= io
->uv_stride
;
77 v_src
+= io
->uv_stride
;
84 //------------------------------------------------------------------------------
87 #ifdef FANCY_UPSAMPLING
88 static int EmitFancyRGB(const VP8Io
* const io
, WebPDecParams
* const p
) {
89 int num_lines_out
= io
->mb_h
; // a priori guess
90 const WebPRGBABuffer
* const buf
= &p
->output
->u
.RGBA
;
91 uint8_t* dst
= buf
->rgba
+ io
->mb_y
* buf
->stride
;
92 WebPUpsampleLinePairFunc upsample
= WebPUpsamplers
[p
->output
->colorspace
];
93 const uint8_t* cur_y
= io
->y
;
94 const uint8_t* cur_u
= io
->u
;
95 const uint8_t* cur_v
= io
->v
;
96 const uint8_t* top_u
= p
->tmp_u
;
97 const uint8_t* top_v
= p
->tmp_v
;
99 const int y_end
= io
->mb_y
+ io
->mb_h
;
100 const int mb_w
= io
->mb_w
;
101 const int uv_w
= (mb_w
+ 1) / 2;
104 // First line is special cased. We mirror the u/v samples at boundary.
105 upsample(cur_y
, NULL
, cur_u
, cur_v
, cur_u
, cur_v
, dst
, NULL
, mb_w
);
107 // We can finish the left-over line from previous call.
108 upsample(p
->tmp_y
, cur_y
, top_u
, top_v
, cur_u
, cur_v
,
109 dst
- buf
->stride
, dst
, mb_w
);
112 // Loop over each output pairs of row.
113 for (; y
+ 2 < y_end
; y
+= 2) {
116 cur_u
+= io
->uv_stride
;
117 cur_v
+= io
->uv_stride
;
118 dst
+= 2 * buf
->stride
;
119 cur_y
+= 2 * io
->y_stride
;
120 upsample(cur_y
- io
->y_stride
, cur_y
,
121 top_u
, top_v
, cur_u
, cur_v
,
122 dst
- buf
->stride
, dst
, mb_w
);
125 cur_y
+= io
->y_stride
;
126 if (io
->crop_top
+ y_end
< io
->crop_bottom
) {
127 // Save the unfinished samples for next call (as we're not done yet).
128 memcpy(p
->tmp_y
, cur_y
, mb_w
* sizeof(*p
->tmp_y
));
129 memcpy(p
->tmp_u
, cur_u
, uv_w
* sizeof(*p
->tmp_u
));
130 memcpy(p
->tmp_v
, cur_v
, uv_w
* sizeof(*p
->tmp_v
));
131 // The fancy upsampler leaves a row unfinished behind
132 // (except for the very last row)
135 // Process the very last row of even-sized picture
137 upsample(cur_y
, NULL
, cur_u
, cur_v
, cur_u
, cur_v
,
138 dst
+ buf
->stride
, NULL
, mb_w
);
141 return num_lines_out
;
144 #endif /* FANCY_UPSAMPLING */
146 //------------------------------------------------------------------------------
148 static int EmitAlphaYUV(const VP8Io
* const io
, WebPDecParams
* const p
) {
149 const uint8_t* alpha
= io
->a
;
150 const WebPYUVABuffer
* const buf
= &p
->output
->u
.YUVA
;
151 const int mb_w
= io
->mb_w
;
152 const int mb_h
= io
->mb_h
;
153 uint8_t* dst
= buf
->a
+ io
->mb_y
* buf
->a_stride
;
157 for (j
= 0; j
< mb_h
; ++j
) {
158 memcpy(dst
, alpha
, mb_w
* sizeof(*dst
));
160 dst
+= buf
->a_stride
;
162 } else if (buf
->a
!= NULL
) {
163 // the user requested alpha, but there is none, set it to opaque.
164 for (j
= 0; j
< mb_h
; ++j
) {
165 memset(dst
, 0xff, mb_w
* sizeof(*dst
));
166 dst
+= buf
->a_stride
;
172 static int GetAlphaSourceRow(const VP8Io
* const io
,
173 const uint8_t** alpha
, int* const num_rows
) {
174 int start_y
= io
->mb_y
;
175 *num_rows
= io
->mb_h
;
177 // Compensate for the 1-line delay of the fancy upscaler.
178 // This is similar to EmitFancyRGB().
179 if (io
->fancy_upsampling
) {
181 // We don't process the last row yet. It'll be done during the next call.
185 // Fortunately, *alpha data is persistent, so we can go back
186 // one row and finish alpha blending, now that the fancy upscaler
187 // completed the YUV->RGB interpolation.
190 if (io
->crop_top
+ io
->mb_y
+ io
->mb_h
== io
->crop_bottom
) {
191 // If it's the very last call, we process all the remaining rows!
192 *num_rows
= io
->crop_bottom
- io
->crop_top
- start_y
;
198 static int EmitAlphaRGB(const VP8Io
* const io
, WebPDecParams
* const p
) {
199 const uint8_t* alpha
= io
->a
;
201 const int mb_w
= io
->mb_w
;
202 const WEBP_CSP_MODE colorspace
= p
->output
->colorspace
;
203 const int alpha_first
=
204 (colorspace
== MODE_ARGB
|| colorspace
== MODE_Argb
);
205 const WebPRGBABuffer
* const buf
= &p
->output
->u
.RGBA
;
207 const int start_y
= GetAlphaSourceRow(io
, &alpha
, &num_rows
);
208 uint8_t* const base_rgba
= buf
->rgba
+ start_y
* buf
->stride
;
209 uint8_t* dst
= base_rgba
+ (alpha_first
? 0 : 3);
210 uint32_t alpha_mask
= 0xff;
213 for (j
= 0; j
< num_rows
; ++j
) {
214 for (i
= 0; i
< mb_w
; ++i
) {
215 const uint32_t alpha_value
= alpha
[i
];
216 dst
[4 * i
] = alpha_value
;
217 alpha_mask
&= alpha_value
;
222 // alpha_mask is < 0xff if there's non-trivial alpha to premultiply with.
223 if (alpha_mask
!= 0xff && WebPIsPremultipliedMode(colorspace
)) {
224 WebPApplyAlphaMultiply(base_rgba
, alpha_first
,
225 mb_w
, num_rows
, buf
->stride
);
231 static int EmitAlphaRGBA4444(const VP8Io
* const io
, WebPDecParams
* const p
) {
232 const uint8_t* alpha
= io
->a
;
234 const int mb_w
= io
->mb_w
;
235 const WEBP_CSP_MODE colorspace
= p
->output
->colorspace
;
236 const WebPRGBABuffer
* const buf
= &p
->output
->u
.RGBA
;
238 const int start_y
= GetAlphaSourceRow(io
, &alpha
, &num_rows
);
239 uint8_t* const base_rgba
= buf
->rgba
+ start_y
* buf
->stride
;
240 #ifdef WEBP_SWAP_16BIT_CSP
241 uint8_t* alpha_dst
= base_rgba
;
243 uint8_t* alpha_dst
= base_rgba
+ 1;
245 uint32_t alpha_mask
= 0x0f;
248 for (j
= 0; j
< num_rows
; ++j
) {
249 for (i
= 0; i
< mb_w
; ++i
) {
250 // Fill in the alpha value (converted to 4 bits).
251 const uint32_t alpha_value
= alpha
[i
] >> 4;
252 alpha_dst
[2 * i
] = (alpha_dst
[2 * i
] & 0xf0) | alpha_value
;
253 alpha_mask
&= alpha_value
;
256 alpha_dst
+= buf
->stride
;
258 if (alpha_mask
!= 0x0f && WebPIsPremultipliedMode(colorspace
)) {
259 WebPApplyAlphaMultiply4444(base_rgba
, mb_w
, num_rows
, buf
->stride
);
265 //------------------------------------------------------------------------------
266 // YUV rescaling (no final RGB conversion needed)
268 static int Rescale(const uint8_t* src
, int src_stride
,
269 int new_lines
, WebPRescaler
* const wrk
) {
270 int num_lines_out
= 0;
271 while (new_lines
> 0) { // import new contributions of source rows.
272 const int lines_in
= WebPRescalerImport(wrk
, new_lines
, src
, src_stride
);
273 src
+= lines_in
* src_stride
;
274 new_lines
-= lines_in
;
275 num_lines_out
+= WebPRescalerExport(wrk
); // emit output row(s)
277 return num_lines_out
;
280 static int EmitRescaledYUV(const VP8Io
* const io
, WebPDecParams
* const p
) {
281 const int mb_h
= io
->mb_h
;
282 const int uv_mb_h
= (mb_h
+ 1) >> 1;
283 WebPRescaler
* const scaler
= &p
->scaler_y
;
284 int num_lines_out
= 0;
285 if (WebPIsAlphaMode(p
->output
->colorspace
) && io
->a
!= NULL
) {
286 // Before rescaling, we premultiply the luma directly into the io->y
287 // internal buffer. This is OK since these samples are not used for
288 // intra-prediction (the top samples are saved in cache_y_/u_/v_).
289 // But we need to cast the const away, though.
290 WebPMultRows((uint8_t*)io
->y
, io
->y_stride
,
291 io
->a
, io
->width
, io
->mb_w
, mb_h
, 0);
293 num_lines_out
= Rescale(io
->y
, io
->y_stride
, mb_h
, scaler
);
294 Rescale(io
->u
, io
->uv_stride
, uv_mb_h
, &p
->scaler_u
);
295 Rescale(io
->v
, io
->uv_stride
, uv_mb_h
, &p
->scaler_v
);
296 return num_lines_out
;
299 static int EmitRescaledAlphaYUV(const VP8Io
* const io
, WebPDecParams
* const p
) {
301 const WebPYUVABuffer
* const buf
= &p
->output
->u
.YUVA
;
302 uint8_t* dst_y
= buf
->y
+ p
->last_y
* buf
->y_stride
;
303 const uint8_t* src_a
= buf
->a
+ p
->last_y
* buf
->a_stride
;
304 const int num_lines_out
= Rescale(io
->a
, io
->width
, io
->mb_h
, &p
->scaler_a
);
305 if (num_lines_out
> 0) { // unmultiply the Y
306 WebPMultRows(dst_y
, buf
->y_stride
, src_a
, buf
->a_stride
,
307 p
->scaler_a
.dst_width
, num_lines_out
, 1);
313 static int InitYUVRescaler(const VP8Io
* const io
, WebPDecParams
* const p
) {
314 const int has_alpha
= WebPIsAlphaMode(p
->output
->colorspace
);
315 const WebPYUVABuffer
* const buf
= &p
->output
->u
.YUVA
;
316 const int out_width
= io
->scaled_width
;
317 const int out_height
= io
->scaled_height
;
318 const int uv_out_width
= (out_width
+ 1) >> 1;
319 const int uv_out_height
= (out_height
+ 1) >> 1;
320 const int uv_in_width
= (io
->mb_w
+ 1) >> 1;
321 const int uv_in_height
= (io
->mb_h
+ 1) >> 1;
322 const size_t work_size
= 2 * out_width
; // scratch memory for luma rescaler
323 const size_t uv_work_size
= 2 * uv_out_width
; // and for each u/v ones
327 tmp_size
= (work_size
+ 2 * uv_work_size
) * sizeof(*work
);
329 tmp_size
+= work_size
* sizeof(*work
);
331 p
->memory
= WebPSafeCalloc(1ULL, tmp_size
);
332 if (p
->memory
== NULL
) {
333 return 0; // memory error
335 work
= (int32_t*)p
->memory
;
336 WebPRescalerInit(&p
->scaler_y
, io
->mb_w
, io
->mb_h
,
337 buf
->y
, out_width
, out_height
, buf
->y_stride
, 1,
338 io
->mb_w
, out_width
, io
->mb_h
, out_height
,
340 WebPRescalerInit(&p
->scaler_u
, uv_in_width
, uv_in_height
,
341 buf
->u
, uv_out_width
, uv_out_height
, buf
->u_stride
, 1,
342 uv_in_width
, uv_out_width
,
343 uv_in_height
, uv_out_height
,
345 WebPRescalerInit(&p
->scaler_v
, uv_in_width
, uv_in_height
,
346 buf
->v
, uv_out_width
, uv_out_height
, buf
->v_stride
, 1,
347 uv_in_width
, uv_out_width
,
348 uv_in_height
, uv_out_height
,
349 work
+ work_size
+ uv_work_size
);
350 p
->emit
= EmitRescaledYUV
;
353 WebPRescalerInit(&p
->scaler_a
, io
->mb_w
, io
->mb_h
,
354 buf
->a
, out_width
, out_height
, buf
->a_stride
, 1,
355 io
->mb_w
, out_width
, io
->mb_h
, out_height
,
356 work
+ work_size
+ 2 * uv_work_size
);
357 p
->emit_alpha
= EmitRescaledAlphaYUV
;
358 WebPInitAlphaProcessing();
363 //------------------------------------------------------------------------------
366 static int ExportRGB(WebPDecParams
* const p
, int y_pos
) {
367 const WebPYUV444Converter convert
=
368 WebPYUV444Converters
[p
->output
->colorspace
];
369 const WebPRGBABuffer
* const buf
= &p
->output
->u
.RGBA
;
370 uint8_t* dst
= buf
->rgba
+ (p
->last_y
+ y_pos
) * buf
->stride
;
371 int num_lines_out
= 0;
372 // For RGB rescaling, because of the YUV420, current scan position
373 // U/V can be +1/-1 line from the Y one. Hence the double test.
374 while (WebPRescalerHasPendingOutput(&p
->scaler_y
) &&
375 WebPRescalerHasPendingOutput(&p
->scaler_u
)) {
376 assert(p
->last_y
+ y_pos
+ num_lines_out
< p
->output
->height
);
377 assert(p
->scaler_u
.y_accum
== p
->scaler_v
.y_accum
);
378 WebPRescalerExportRow(&p
->scaler_y
, 0);
379 WebPRescalerExportRow(&p
->scaler_u
, 0);
380 WebPRescalerExportRow(&p
->scaler_v
, 0);
381 convert(p
->scaler_y
.dst
, p
->scaler_u
.dst
, p
->scaler_v
.dst
,
382 dst
, p
->scaler_y
.dst_width
);
386 return num_lines_out
;
389 static int EmitRescaledRGB(const VP8Io
* const io
, WebPDecParams
* const p
) {
390 const int mb_h
= io
->mb_h
;
391 const int uv_mb_h
= (mb_h
+ 1) >> 1;
393 int num_lines_out
= 0;
395 const int y_lines_in
=
396 WebPRescalerImport(&p
->scaler_y
, mb_h
- j
,
397 io
->y
+ j
* io
->y_stride
, io
->y_stride
);
398 const int u_lines_in
=
399 WebPRescalerImport(&p
->scaler_u
, uv_mb_h
- uv_j
,
400 io
->u
+ uv_j
* io
->uv_stride
, io
->uv_stride
);
401 const int v_lines_in
=
402 WebPRescalerImport(&p
->scaler_v
, uv_mb_h
- uv_j
,
403 io
->v
+ uv_j
* io
->uv_stride
, io
->uv_stride
);
404 (void)v_lines_in
; // remove a gcc warning
405 assert(u_lines_in
== v_lines_in
);
408 num_lines_out
+= ExportRGB(p
, num_lines_out
);
410 return num_lines_out
;
413 static int ExportAlpha(WebPDecParams
* const p
, int y_pos
) {
414 const WebPRGBABuffer
* const buf
= &p
->output
->u
.RGBA
;
415 uint8_t* const base_rgba
= buf
->rgba
+ (p
->last_y
+ y_pos
) * buf
->stride
;
416 const WEBP_CSP_MODE colorspace
= p
->output
->colorspace
;
417 const int alpha_first
=
418 (colorspace
== MODE_ARGB
|| colorspace
== MODE_Argb
);
419 uint8_t* dst
= base_rgba
+ (alpha_first
? 0 : 3);
420 int num_lines_out
= 0;
421 const int is_premult_alpha
= WebPIsPremultipliedMode(colorspace
);
422 uint32_t alpha_mask
= 0xff;
423 const int width
= p
->scaler_a
.dst_width
;
425 while (WebPRescalerHasPendingOutput(&p
->scaler_a
)) {
427 assert(p
->last_y
+ y_pos
+ num_lines_out
< p
->output
->height
);
428 WebPRescalerExportRow(&p
->scaler_a
, 0);
429 for (i
= 0; i
< width
; ++i
) {
430 const uint32_t alpha_value
= p
->scaler_a
.dst
[i
];
431 dst
[4 * i
] = alpha_value
;
432 alpha_mask
&= alpha_value
;
437 if (is_premult_alpha
&& alpha_mask
!= 0xff) {
438 WebPApplyAlphaMultiply(base_rgba
, alpha_first
,
439 width
, num_lines_out
, buf
->stride
);
441 return num_lines_out
;
444 static int ExportAlphaRGBA4444(WebPDecParams
* const p
, int y_pos
) {
445 const WebPRGBABuffer
* const buf
= &p
->output
->u
.RGBA
;
446 uint8_t* const base_rgba
= buf
->rgba
+ (p
->last_y
+ y_pos
) * buf
->stride
;
447 #ifdef WEBP_SWAP_16BIT_CSP
448 uint8_t* alpha_dst
= base_rgba
;
450 uint8_t* alpha_dst
= base_rgba
+ 1;
452 int num_lines_out
= 0;
453 const WEBP_CSP_MODE colorspace
= p
->output
->colorspace
;
454 const int width
= p
->scaler_a
.dst_width
;
455 const int is_premult_alpha
= WebPIsPremultipliedMode(colorspace
);
456 uint32_t alpha_mask
= 0x0f;
458 while (WebPRescalerHasPendingOutput(&p
->scaler_a
)) {
460 assert(p
->last_y
+ y_pos
+ num_lines_out
< p
->output
->height
);
461 WebPRescalerExportRow(&p
->scaler_a
, 0);
462 for (i
= 0; i
< width
; ++i
) {
463 // Fill in the alpha value (converted to 4 bits).
464 const uint32_t alpha_value
= p
->scaler_a
.dst
[i
] >> 4;
465 alpha_dst
[2 * i
] = (alpha_dst
[2 * i
] & 0xf0) | alpha_value
;
466 alpha_mask
&= alpha_value
;
468 alpha_dst
+= buf
->stride
;
471 if (is_premult_alpha
&& alpha_mask
!= 0x0f) {
472 WebPApplyAlphaMultiply4444(base_rgba
, width
, num_lines_out
, buf
->stride
);
474 return num_lines_out
;
477 static int EmitRescaledAlphaRGB(const VP8Io
* const io
, WebPDecParams
* const p
) {
479 WebPRescaler
* const scaler
= &p
->scaler_a
;
482 while (j
< io
->mb_h
) {
483 j
+= WebPRescalerImport(scaler
, io
->mb_h
- j
,
484 io
->a
+ j
* io
->width
, io
->width
);
485 pos
+= p
->emit_alpha_row(p
, pos
);
491 static int InitRGBRescaler(const VP8Io
* const io
, WebPDecParams
* const p
) {
492 const int has_alpha
= WebPIsAlphaMode(p
->output
->colorspace
);
493 const int out_width
= io
->scaled_width
;
494 const int out_height
= io
->scaled_height
;
495 const int uv_in_width
= (io
->mb_w
+ 1) >> 1;
496 const int uv_in_height
= (io
->mb_h
+ 1) >> 1;
497 const size_t work_size
= 2 * out_width
; // scratch memory for one rescaler
498 int32_t* work
; // rescalers work area
499 uint8_t* tmp
; // tmp storage for scaled YUV444 samples before RGB conversion
500 size_t tmp_size1
, tmp_size2
, total_size
;
502 tmp_size1
= 3 * work_size
;
503 tmp_size2
= 3 * out_width
;
505 tmp_size1
+= work_size
;
506 tmp_size2
+= out_width
;
508 total_size
= tmp_size1
* sizeof(*work
) + tmp_size2
* sizeof(*tmp
);
509 p
->memory
= WebPSafeCalloc(1ULL, total_size
);
510 if (p
->memory
== NULL
) {
511 return 0; // memory error
513 work
= (int32_t*)p
->memory
;
514 tmp
= (uint8_t*)(work
+ tmp_size1
);
515 WebPRescalerInit(&p
->scaler_y
, io
->mb_w
, io
->mb_h
,
516 tmp
+ 0 * out_width
, out_width
, out_height
, 0, 1,
517 io
->mb_w
, out_width
, io
->mb_h
, out_height
,
518 work
+ 0 * work_size
);
519 WebPRescalerInit(&p
->scaler_u
, uv_in_width
, uv_in_height
,
520 tmp
+ 1 * out_width
, out_width
, out_height
, 0, 1,
521 io
->mb_w
, 2 * out_width
, io
->mb_h
, 2 * out_height
,
522 work
+ 1 * work_size
);
523 WebPRescalerInit(&p
->scaler_v
, uv_in_width
, uv_in_height
,
524 tmp
+ 2 * out_width
, out_width
, out_height
, 0, 1,
525 io
->mb_w
, 2 * out_width
, io
->mb_h
, 2 * out_height
,
526 work
+ 2 * work_size
);
527 p
->emit
= EmitRescaledRGB
;
530 WebPRescalerInit(&p
->scaler_a
, io
->mb_w
, io
->mb_h
,
531 tmp
+ 3 * out_width
, out_width
, out_height
, 0, 1,
532 io
->mb_w
, out_width
, io
->mb_h
, out_height
,
533 work
+ 3 * work_size
);
534 p
->emit_alpha
= EmitRescaledAlphaRGB
;
535 if (p
->output
->colorspace
== MODE_RGBA_4444
||
536 p
->output
->colorspace
== MODE_rgbA_4444
) {
537 p
->emit_alpha_row
= ExportAlphaRGBA4444
;
539 p
->emit_alpha_row
= ExportAlpha
;
541 WebPInitAlphaProcessing();
546 //------------------------------------------------------------------------------
547 // Default custom functions
549 static int CustomSetup(VP8Io
* io
) {
550 WebPDecParams
* const p
= (WebPDecParams
*)io
->opaque
;
551 const WEBP_CSP_MODE colorspace
= p
->output
->colorspace
;
552 const int is_rgb
= WebPIsRGBMode(colorspace
);
553 const int is_alpha
= WebPIsAlphaMode(colorspace
);
557 p
->emit_alpha
= NULL
;
558 p
->emit_alpha_row
= NULL
;
559 if (!WebPIoInitFromOptions(p
->options
, io
, is_alpha
? MODE_YUV
: MODE_YUVA
)) {
562 if (is_alpha
&& WebPIsPremultipliedMode(colorspace
)) {
563 WebPInitUpsamplers();
565 if (io
->use_scaling
) {
566 const int ok
= is_rgb
? InitRGBRescaler(io
, p
) : InitYUVRescaler(io
, p
);
568 return 0; // memory error
572 p
->emit
= EmitSampledRGB
; // default
573 if (io
->fancy_upsampling
) {
574 #ifdef FANCY_UPSAMPLING
575 const int uv_width
= (io
->mb_w
+ 1) >> 1;
576 p
->memory
= WebPSafeMalloc(1ULL, (size_t)(io
->mb_w
+ 2 * uv_width
));
577 if (p
->memory
== NULL
) {
578 return 0; // memory error.
580 p
->tmp_y
= (uint8_t*)p
->memory
;
581 p
->tmp_u
= p
->tmp_y
+ io
->mb_w
;
582 p
->tmp_v
= p
->tmp_u
+ uv_width
;
583 p
->emit
= EmitFancyRGB
;
584 WebPInitUpsamplers();
592 if (is_alpha
) { // need transparency output
594 (colorspace
== MODE_RGBA_4444
|| colorspace
== MODE_rgbA_4444
) ?
596 : is_rgb
? EmitAlphaRGB
599 WebPInitAlphaProcessing();
610 //------------------------------------------------------------------------------
612 static int CustomPut(const VP8Io
* io
) {
613 WebPDecParams
* const p
= (WebPDecParams
*)io
->opaque
;
614 const int mb_w
= io
->mb_w
;
615 const int mb_h
= io
->mb_h
;
617 assert(!(io
->mb_y
& 1));
619 if (mb_w
<= 0 || mb_h
<= 0) {
622 num_lines_out
= p
->emit(io
, p
);
623 if (p
->emit_alpha
!= NULL
) {
624 p
->emit_alpha(io
, p
);
626 p
->last_y
+= num_lines_out
;
630 //------------------------------------------------------------------------------
632 static void CustomTeardown(const VP8Io
* io
) {
633 WebPDecParams
* const p
= (WebPDecParams
*)io
->opaque
;
634 WebPSafeFree(p
->memory
);
638 //------------------------------------------------------------------------------
641 void WebPInitCustomIo(WebPDecParams
* const params
, VP8Io
* const io
) {
643 io
->setup
= CustomSetup
;
644 io
->teardown
= CustomTeardown
;
648 //------------------------------------------------------------------------------