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"
21 //------------------------------------------------------------------------------
22 // Main YUV<->RGB conversion functions
24 static int EmitYUV(const VP8Io
* const io
, WebPDecParams
* const p
) {
25 WebPDecBuffer
* output
= p
->output
;
26 const WebPYUVABuffer
* const buf
= &output
->u
.YUVA
;
27 uint8_t* const y_dst
= buf
->y
+ io
->mb_y
* buf
->y_stride
;
28 uint8_t* const u_dst
= buf
->u
+ (io
->mb_y
>> 1) * buf
->u_stride
;
29 uint8_t* const v_dst
= buf
->v
+ (io
->mb_y
>> 1) * buf
->v_stride
;
30 const int mb_w
= io
->mb_w
;
31 const int mb_h
= io
->mb_h
;
32 const int uv_w
= (mb_w
+ 1) / 2;
33 const int uv_h
= (mb_h
+ 1) / 2;
35 for (j
= 0; j
< mb_h
; ++j
) {
36 memcpy(y_dst
+ j
* buf
->y_stride
, io
->y
+ j
* io
->y_stride
, mb_w
);
38 for (j
= 0; j
< uv_h
; ++j
) {
39 memcpy(u_dst
+ j
* buf
->u_stride
, io
->u
+ j
* io
->uv_stride
, uv_w
);
40 memcpy(v_dst
+ j
* buf
->v_stride
, io
->v
+ j
* io
->uv_stride
, uv_w
);
45 // Point-sampling U/V sampler.
46 static int EmitSampledRGB(const VP8Io
* const io
, WebPDecParams
* const p
) {
47 WebPDecBuffer
* output
= p
->output
;
48 const WebPRGBABuffer
* const buf
= &output
->u
.RGBA
;
49 uint8_t* dst
= buf
->rgba
+ io
->mb_y
* buf
->stride
;
50 const uint8_t* y_src
= io
->y
;
51 const uint8_t* u_src
= io
->u
;
52 const uint8_t* v_src
= io
->v
;
53 const WebPSampleLinePairFunc sample
= WebPSamplers
[output
->colorspace
];
54 const int mb_w
= io
->mb_w
;
55 const int last
= io
->mb_h
- 1;
57 for (j
= 0; j
< last
; j
+= 2) {
58 sample(y_src
, y_src
+ io
->y_stride
, u_src
, v_src
,
59 dst
, dst
+ buf
->stride
, mb_w
);
60 y_src
+= 2 * io
->y_stride
;
61 u_src
+= io
->uv_stride
;
62 v_src
+= io
->uv_stride
;
63 dst
+= 2 * buf
->stride
;
65 if (j
== last
) { // Just do the last line twice
66 sample(y_src
, y_src
, u_src
, v_src
, dst
, dst
, mb_w
);
71 //------------------------------------------------------------------------------
72 // YUV444 -> RGB conversion
74 #if 0 // TODO(skal): this is for future rescaling.
75 static int EmitRGB(const VP8Io
* const io
, WebPDecParams
* const p
) {
76 WebPDecBuffer
* output
= p
->output
;
77 const WebPRGBABuffer
* const buf
= &output
->u
.RGBA
;
78 uint8_t* dst
= buf
->rgba
+ io
->mb_y
* buf
->stride
;
79 const uint8_t* y_src
= io
->y
;
80 const uint8_t* u_src
= io
->u
;
81 const uint8_t* v_src
= io
->v
;
82 const WebPYUV444Converter convert
= WebPYUV444Converters
[output
->colorspace
];
83 const int mb_w
= io
->mb_w
;
84 const int last
= io
->mb_h
;
86 for (j
= 0; j
< last
; ++j
) {
87 convert(y_src
, u_src
, v_src
, dst
, mb_w
);
88 y_src
+= io
->y_stride
;
89 u_src
+= io
->uv_stride
;
90 v_src
+= io
->uv_stride
;
97 //------------------------------------------------------------------------------
100 #ifdef FANCY_UPSAMPLING
101 static int EmitFancyRGB(const VP8Io
* const io
, WebPDecParams
* const p
) {
102 int num_lines_out
= io
->mb_h
; // a priori guess
103 const WebPRGBABuffer
* const buf
= &p
->output
->u
.RGBA
;
104 uint8_t* dst
= buf
->rgba
+ io
->mb_y
* buf
->stride
;
105 WebPUpsampleLinePairFunc upsample
= WebPUpsamplers
[p
->output
->colorspace
];
106 const uint8_t* cur_y
= io
->y
;
107 const uint8_t* cur_u
= io
->u
;
108 const uint8_t* cur_v
= io
->v
;
109 const uint8_t* top_u
= p
->tmp_u
;
110 const uint8_t* top_v
= p
->tmp_v
;
112 const int y_end
= io
->mb_y
+ io
->mb_h
;
113 const int mb_w
= io
->mb_w
;
114 const int uv_w
= (mb_w
+ 1) / 2;
117 // First line is special cased. We mirror the u/v samples at boundary.
118 upsample(cur_y
, NULL
, cur_u
, cur_v
, cur_u
, cur_v
, dst
, NULL
, mb_w
);
120 // We can finish the left-over line from previous call.
121 upsample(p
->tmp_y
, cur_y
, top_u
, top_v
, cur_u
, cur_v
,
122 dst
- buf
->stride
, dst
, mb_w
);
125 // Loop over each output pairs of row.
126 for (; y
+ 2 < y_end
; y
+= 2) {
129 cur_u
+= io
->uv_stride
;
130 cur_v
+= io
->uv_stride
;
131 dst
+= 2 * buf
->stride
;
132 cur_y
+= 2 * io
->y_stride
;
133 upsample(cur_y
- io
->y_stride
, cur_y
,
134 top_u
, top_v
, cur_u
, cur_v
,
135 dst
- buf
->stride
, dst
, mb_w
);
138 cur_y
+= io
->y_stride
;
139 if (io
->crop_top
+ y_end
< io
->crop_bottom
) {
140 // Save the unfinished samples for next call (as we're not done yet).
141 memcpy(p
->tmp_y
, cur_y
, mb_w
* sizeof(*p
->tmp_y
));
142 memcpy(p
->tmp_u
, cur_u
, uv_w
* sizeof(*p
->tmp_u
));
143 memcpy(p
->tmp_v
, cur_v
, uv_w
* sizeof(*p
->tmp_v
));
144 // The fancy upsampler leaves a row unfinished behind
145 // (except for the very last row)
148 // Process the very last row of even-sized picture
150 upsample(cur_y
, NULL
, cur_u
, cur_v
, cur_u
, cur_v
,
151 dst
+ buf
->stride
, NULL
, mb_w
);
154 return num_lines_out
;
157 #endif /* FANCY_UPSAMPLING */
159 //------------------------------------------------------------------------------
161 static int EmitAlphaYUV(const VP8Io
* const io
, WebPDecParams
* const p
) {
162 const uint8_t* alpha
= io
->a
;
163 const WebPYUVABuffer
* const buf
= &p
->output
->u
.YUVA
;
164 const int mb_w
= io
->mb_w
;
165 const int mb_h
= io
->mb_h
;
166 uint8_t* dst
= buf
->a
+ io
->mb_y
* buf
->a_stride
;
170 for (j
= 0; j
< mb_h
; ++j
) {
171 memcpy(dst
, alpha
, mb_w
* sizeof(*dst
));
173 dst
+= buf
->a_stride
;
175 } else if (buf
->a
!= NULL
) {
176 // the user requested alpha, but there is none, set it to opaque.
177 for (j
= 0; j
< mb_h
; ++j
) {
178 memset(dst
, 0xff, mb_w
* sizeof(*dst
));
179 dst
+= buf
->a_stride
;
185 static int GetAlphaSourceRow(const VP8Io
* const io
,
186 const uint8_t** alpha
, int* const num_rows
) {
187 int start_y
= io
->mb_y
;
188 *num_rows
= io
->mb_h
;
190 // Compensate for the 1-line delay of the fancy upscaler.
191 // This is similar to EmitFancyRGB().
192 if (io
->fancy_upsampling
) {
194 // We don't process the last row yet. It'll be done during the next call.
198 // Fortunately, *alpha data is persistent, so we can go back
199 // one row and finish alpha blending, now that the fancy upscaler
200 // completed the YUV->RGB interpolation.
203 if (io
->crop_top
+ io
->mb_y
+ io
->mb_h
== io
->crop_bottom
) {
204 // If it's the very last call, we process all the remaining rows!
205 *num_rows
= io
->crop_bottom
- io
->crop_top
- start_y
;
211 static int EmitAlphaRGB(const VP8Io
* const io
, WebPDecParams
* const p
) {
212 const uint8_t* alpha
= io
->a
;
214 const int mb_w
= io
->mb_w
;
215 const WEBP_CSP_MODE colorspace
= p
->output
->colorspace
;
216 const int alpha_first
=
217 (colorspace
== MODE_ARGB
|| colorspace
== MODE_Argb
);
218 const WebPRGBABuffer
* const buf
= &p
->output
->u
.RGBA
;
220 const int start_y
= GetAlphaSourceRow(io
, &alpha
, &num_rows
);
221 uint8_t* const base_rgba
= buf
->rgba
+ start_y
* buf
->stride
;
222 uint8_t* dst
= base_rgba
+ (alpha_first
? 0 : 3);
223 uint32_t alpha_mask
= 0xff;
226 for (j
= 0; j
< num_rows
; ++j
) {
227 for (i
= 0; i
< mb_w
; ++i
) {
228 const uint32_t alpha_value
= alpha
[i
];
229 dst
[4 * i
] = alpha_value
;
230 alpha_mask
&= alpha_value
;
235 // alpha_mask is < 0xff if there's non-trivial alpha to premultiply with.
236 if (alpha_mask
!= 0xff && WebPIsPremultipliedMode(colorspace
)) {
237 WebPApplyAlphaMultiply(base_rgba
, alpha_first
,
238 mb_w
, num_rows
, buf
->stride
);
244 static int EmitAlphaRGBA4444(const VP8Io
* const io
, WebPDecParams
* const p
) {
245 const uint8_t* alpha
= io
->a
;
247 const int mb_w
= io
->mb_w
;
248 const WEBP_CSP_MODE colorspace
= p
->output
->colorspace
;
249 const WebPRGBABuffer
* const buf
= &p
->output
->u
.RGBA
;
251 const int start_y
= GetAlphaSourceRow(io
, &alpha
, &num_rows
);
252 uint8_t* const base_rgba
= buf
->rgba
+ start_y
* buf
->stride
;
253 uint8_t* alpha_dst
= base_rgba
+ 1;
254 uint32_t alpha_mask
= 0x0f;
257 for (j
= 0; j
< num_rows
; ++j
) {
258 for (i
= 0; i
< mb_w
; ++i
) {
259 // Fill in the alpha value (converted to 4 bits).
260 const uint32_t alpha_value
= alpha
[i
] >> 4;
261 alpha_dst
[2 * i
] = (alpha_dst
[2 * i
] & 0xf0) | alpha_value
;
262 alpha_mask
&= alpha_value
;
265 alpha_dst
+= buf
->stride
;
267 if (alpha_mask
!= 0x0f && WebPIsPremultipliedMode(colorspace
)) {
268 WebPApplyAlphaMultiply4444(base_rgba
, mb_w
, num_rows
, buf
->stride
);
274 //------------------------------------------------------------------------------
275 // YUV rescaling (no final RGB conversion needed)
277 static int Rescale(const uint8_t* src
, int src_stride
,
278 int new_lines
, WebPRescaler
* const wrk
) {
279 int num_lines_out
= 0;
280 while (new_lines
> 0) { // import new contributions of source rows.
281 const int lines_in
= WebPRescalerImport(wrk
, new_lines
, src
, src_stride
);
282 src
+= lines_in
* src_stride
;
283 new_lines
-= lines_in
;
284 num_lines_out
+= WebPRescalerExport(wrk
); // emit output row(s)
286 return num_lines_out
;
289 static int EmitRescaledYUV(const VP8Io
* const io
, WebPDecParams
* const p
) {
290 const int mb_h
= io
->mb_h
;
291 const int uv_mb_h
= (mb_h
+ 1) >> 1;
292 const int num_lines_out
= Rescale(io
->y
, io
->y_stride
, mb_h
, &p
->scaler_y
);
293 Rescale(io
->u
, io
->uv_stride
, uv_mb_h
, &p
->scaler_u
);
294 Rescale(io
->v
, io
->uv_stride
, uv_mb_h
, &p
->scaler_v
);
295 return num_lines_out
;
298 static int EmitRescaledAlphaYUV(const VP8Io
* const io
, WebPDecParams
* const p
) {
300 Rescale(io
->a
, io
->width
, io
->mb_h
, &p
->scaler_a
);
305 static int InitYUVRescaler(const VP8Io
* const io
, WebPDecParams
* const p
) {
306 const int has_alpha
= WebPIsAlphaMode(p
->output
->colorspace
);
307 const WebPYUVABuffer
* const buf
= &p
->output
->u
.YUVA
;
308 const int out_width
= io
->scaled_width
;
309 const int out_height
= io
->scaled_height
;
310 const int uv_out_width
= (out_width
+ 1) >> 1;
311 const int uv_out_height
= (out_height
+ 1) >> 1;
312 const int uv_in_width
= (io
->mb_w
+ 1) >> 1;
313 const int uv_in_height
= (io
->mb_h
+ 1) >> 1;
314 const size_t work_size
= 2 * out_width
; // scratch memory for luma rescaler
315 const size_t uv_work_size
= 2 * uv_out_width
; // and for each u/v ones
319 tmp_size
= work_size
+ 2 * uv_work_size
;
321 tmp_size
+= work_size
;
323 p
->memory
= calloc(1, tmp_size
* sizeof(*work
));
324 if (p
->memory
== NULL
) {
325 return 0; // memory error
327 work
= (int32_t*)p
->memory
;
328 WebPRescalerInit(&p
->scaler_y
, io
->mb_w
, io
->mb_h
,
329 buf
->y
, out_width
, out_height
, buf
->y_stride
, 1,
330 io
->mb_w
, out_width
, io
->mb_h
, out_height
,
332 WebPRescalerInit(&p
->scaler_u
, uv_in_width
, uv_in_height
,
333 buf
->u
, uv_out_width
, uv_out_height
, buf
->u_stride
, 1,
334 uv_in_width
, uv_out_width
,
335 uv_in_height
, uv_out_height
,
337 WebPRescalerInit(&p
->scaler_v
, uv_in_width
, uv_in_height
,
338 buf
->v
, uv_out_width
, uv_out_height
, buf
->v_stride
, 1,
339 uv_in_width
, uv_out_width
,
340 uv_in_height
, uv_out_height
,
341 work
+ work_size
+ uv_work_size
);
342 p
->emit
= EmitRescaledYUV
;
345 WebPRescalerInit(&p
->scaler_a
, io
->mb_w
, io
->mb_h
,
346 buf
->a
, out_width
, out_height
, buf
->a_stride
, 1,
347 io
->mb_w
, out_width
, io
->mb_h
, out_height
,
348 work
+ work_size
+ 2 * uv_work_size
);
349 p
->emit_alpha
= EmitRescaledAlphaYUV
;
354 //------------------------------------------------------------------------------
357 static int ExportRGB(WebPDecParams
* const p
, int y_pos
) {
358 const WebPYUV444Converter convert
=
359 WebPYUV444Converters
[p
->output
->colorspace
];
360 const WebPRGBABuffer
* const buf
= &p
->output
->u
.RGBA
;
361 uint8_t* dst
= buf
->rgba
+ (p
->last_y
+ y_pos
) * buf
->stride
;
362 int num_lines_out
= 0;
363 // For RGB rescaling, because of the YUV420, current scan position
364 // U/V can be +1/-1 line from the Y one. Hence the double test.
365 while (WebPRescalerHasPendingOutput(&p
->scaler_y
) &&
366 WebPRescalerHasPendingOutput(&p
->scaler_u
)) {
367 assert(p
->last_y
+ y_pos
+ num_lines_out
< p
->output
->height
);
368 assert(p
->scaler_u
.y_accum
== p
->scaler_v
.y_accum
);
369 WebPRescalerExportRow(&p
->scaler_y
);
370 WebPRescalerExportRow(&p
->scaler_u
);
371 WebPRescalerExportRow(&p
->scaler_v
);
372 convert(p
->scaler_y
.dst
, p
->scaler_u
.dst
, p
->scaler_v
.dst
,
373 dst
, p
->scaler_y
.dst_width
);
377 return num_lines_out
;
380 static int EmitRescaledRGB(const VP8Io
* const io
, WebPDecParams
* const p
) {
381 const int mb_h
= io
->mb_h
;
382 const int uv_mb_h
= (mb_h
+ 1) >> 1;
384 int num_lines_out
= 0;
386 const int y_lines_in
=
387 WebPRescalerImport(&p
->scaler_y
, mb_h
- j
,
388 io
->y
+ j
* io
->y_stride
, io
->y_stride
);
389 const int u_lines_in
=
390 WebPRescalerImport(&p
->scaler_u
, uv_mb_h
- uv_j
,
391 io
->u
+ uv_j
* io
->uv_stride
, io
->uv_stride
);
392 const int v_lines_in
=
393 WebPRescalerImport(&p
->scaler_v
, uv_mb_h
- uv_j
,
394 io
->v
+ uv_j
* io
->uv_stride
, io
->uv_stride
);
395 (void)v_lines_in
; // remove a gcc warning
396 assert(u_lines_in
== v_lines_in
);
399 num_lines_out
+= ExportRGB(p
, num_lines_out
);
401 return num_lines_out
;
404 static int ExportAlpha(WebPDecParams
* const p
, int y_pos
) {
405 const WebPRGBABuffer
* const buf
= &p
->output
->u
.RGBA
;
406 uint8_t* const base_rgba
= buf
->rgba
+ (p
->last_y
+ y_pos
) * buf
->stride
;
407 const WEBP_CSP_MODE colorspace
= p
->output
->colorspace
;
408 const int alpha_first
=
409 (colorspace
== MODE_ARGB
|| colorspace
== MODE_Argb
);
410 uint8_t* dst
= base_rgba
+ (alpha_first
? 0 : 3);
411 int num_lines_out
= 0;
412 const int is_premult_alpha
= WebPIsPremultipliedMode(colorspace
);
413 uint32_t alpha_mask
= 0xff;
414 const int width
= p
->scaler_a
.dst_width
;
416 while (WebPRescalerHasPendingOutput(&p
->scaler_a
)) {
418 assert(p
->last_y
+ y_pos
+ num_lines_out
< p
->output
->height
);
419 WebPRescalerExportRow(&p
->scaler_a
);
420 for (i
= 0; i
< width
; ++i
) {
421 const uint32_t alpha_value
= p
->scaler_a
.dst
[i
];
422 dst
[4 * i
] = alpha_value
;
423 alpha_mask
&= alpha_value
;
428 if (is_premult_alpha
&& alpha_mask
!= 0xff) {
429 WebPApplyAlphaMultiply(base_rgba
, alpha_first
,
430 width
, num_lines_out
, buf
->stride
);
432 return num_lines_out
;
435 static int ExportAlphaRGBA4444(WebPDecParams
* const p
, int y_pos
) {
436 const WebPRGBABuffer
* const buf
= &p
->output
->u
.RGBA
;
437 uint8_t* const base_rgba
= buf
->rgba
+ (p
->last_y
+ y_pos
) * buf
->stride
;
438 uint8_t* alpha_dst
= base_rgba
+ 1;
439 int num_lines_out
= 0;
440 const WEBP_CSP_MODE colorspace
= p
->output
->colorspace
;
441 const int width
= p
->scaler_a
.dst_width
;
442 const int is_premult_alpha
= WebPIsPremultipliedMode(colorspace
);
443 uint32_t alpha_mask
= 0x0f;
445 while (WebPRescalerHasPendingOutput(&p
->scaler_a
)) {
447 assert(p
->last_y
+ y_pos
+ num_lines_out
< p
->output
->height
);
448 WebPRescalerExportRow(&p
->scaler_a
);
449 for (i
= 0; i
< width
; ++i
) {
450 // Fill in the alpha value (converted to 4 bits).
451 const uint32_t alpha_value
= p
->scaler_a
.dst
[i
] >> 4;
452 alpha_dst
[2 * i
] = (alpha_dst
[2 * i
] & 0xf0) | alpha_value
;
453 alpha_mask
&= alpha_value
;
455 alpha_dst
+= buf
->stride
;
458 if (is_premult_alpha
&& alpha_mask
!= 0x0f) {
459 WebPApplyAlphaMultiply4444(base_rgba
, width
, num_lines_out
, buf
->stride
);
461 return num_lines_out
;
464 static int EmitRescaledAlphaRGB(const VP8Io
* const io
, WebPDecParams
* const p
) {
466 WebPRescaler
* const scaler
= &p
->scaler_a
;
469 while (j
< io
->mb_h
) {
470 j
+= WebPRescalerImport(scaler
, io
->mb_h
- j
,
471 io
->a
+ j
* io
->width
, io
->width
);
472 pos
+= p
->emit_alpha_row(p
, pos
);
478 static int InitRGBRescaler(const VP8Io
* const io
, WebPDecParams
* const p
) {
479 const int has_alpha
= WebPIsAlphaMode(p
->output
->colorspace
);
480 const int out_width
= io
->scaled_width
;
481 const int out_height
= io
->scaled_height
;
482 const int uv_in_width
= (io
->mb_w
+ 1) >> 1;
483 const int uv_in_height
= (io
->mb_h
+ 1) >> 1;
484 const size_t work_size
= 2 * out_width
; // scratch memory for one rescaler
485 int32_t* work
; // rescalers work area
486 uint8_t* tmp
; // tmp storage for scaled YUV444 samples before RGB conversion
487 size_t tmp_size1
, tmp_size2
;
489 tmp_size1
= 3 * work_size
;
490 tmp_size2
= 3 * out_width
;
492 tmp_size1
+= work_size
;
493 tmp_size2
+= out_width
;
495 p
->memory
= calloc(1, tmp_size1
* sizeof(*work
) + tmp_size2
* sizeof(*tmp
));
496 if (p
->memory
== NULL
) {
497 return 0; // memory error
499 work
= (int32_t*)p
->memory
;
500 tmp
= (uint8_t*)(work
+ tmp_size1
);
501 WebPRescalerInit(&p
->scaler_y
, io
->mb_w
, io
->mb_h
,
502 tmp
+ 0 * out_width
, out_width
, out_height
, 0, 1,
503 io
->mb_w
, out_width
, io
->mb_h
, out_height
,
504 work
+ 0 * work_size
);
505 WebPRescalerInit(&p
->scaler_u
, uv_in_width
, uv_in_height
,
506 tmp
+ 1 * out_width
, out_width
, out_height
, 0, 1,
507 io
->mb_w
, 2 * out_width
, io
->mb_h
, 2 * out_height
,
508 work
+ 1 * work_size
);
509 WebPRescalerInit(&p
->scaler_v
, uv_in_width
, uv_in_height
,
510 tmp
+ 2 * out_width
, out_width
, out_height
, 0, 1,
511 io
->mb_w
, 2 * out_width
, io
->mb_h
, 2 * out_height
,
512 work
+ 2 * work_size
);
513 p
->emit
= EmitRescaledRGB
;
516 WebPRescalerInit(&p
->scaler_a
, io
->mb_w
, io
->mb_h
,
517 tmp
+ 3 * out_width
, out_width
, out_height
, 0, 1,
518 io
->mb_w
, out_width
, io
->mb_h
, out_height
,
519 work
+ 3 * work_size
);
520 p
->emit_alpha
= EmitRescaledAlphaRGB
;
521 if (p
->output
->colorspace
== MODE_RGBA_4444
||
522 p
->output
->colorspace
== MODE_rgbA_4444
) {
523 p
->emit_alpha_row
= ExportAlphaRGBA4444
;
525 p
->emit_alpha_row
= ExportAlpha
;
531 //------------------------------------------------------------------------------
532 // Default custom functions
534 static int CustomSetup(VP8Io
* io
) {
535 WebPDecParams
* const p
= (WebPDecParams
*)io
->opaque
;
536 const WEBP_CSP_MODE colorspace
= p
->output
->colorspace
;
537 const int is_rgb
= WebPIsRGBMode(colorspace
);
538 const int is_alpha
= WebPIsAlphaMode(colorspace
);
542 p
->emit_alpha
= NULL
;
543 p
->emit_alpha_row
= NULL
;
544 if (!WebPIoInitFromOptions(p
->options
, io
, is_alpha
? MODE_YUV
: MODE_YUVA
)) {
548 if (io
->use_scaling
) {
549 const int ok
= is_rgb
? InitRGBRescaler(io
, p
) : InitYUVRescaler(io
, p
);
551 return 0; // memory error
555 p
->emit
= EmitSampledRGB
; // default
556 #ifdef FANCY_UPSAMPLING
557 if (io
->fancy_upsampling
) {
558 const int uv_width
= (io
->mb_w
+ 1) >> 1;
559 p
->memory
= malloc(io
->mb_w
+ 2 * uv_width
);
560 if (p
->memory
== NULL
) {
561 return 0; // memory error.
563 p
->tmp_y
= (uint8_t*)p
->memory
;
564 p
->tmp_u
= p
->tmp_y
+ io
->mb_w
;
565 p
->tmp_v
= p
->tmp_u
+ uv_width
;
566 p
->emit
= EmitFancyRGB
;
567 WebPInitUpsamplers();
573 if (is_alpha
) { // need transparency output
574 if (WebPIsPremultipliedMode(colorspace
)) WebPInitPremultiply();
576 (colorspace
== MODE_RGBA_4444
|| colorspace
== MODE_rgbA_4444
) ?
578 : is_rgb
? EmitAlphaRGB
589 //------------------------------------------------------------------------------
591 static int CustomPut(const VP8Io
* io
) {
592 WebPDecParams
* const p
= (WebPDecParams
*)io
->opaque
;
593 const int mb_w
= io
->mb_w
;
594 const int mb_h
= io
->mb_h
;
596 assert(!(io
->mb_y
& 1));
598 if (mb_w
<= 0 || mb_h
<= 0) {
601 num_lines_out
= p
->emit(io
, p
);
602 if (p
->emit_alpha
!= NULL
) {
603 p
->emit_alpha(io
, p
);
605 p
->last_y
+= num_lines_out
;
609 //------------------------------------------------------------------------------
611 static void CustomTeardown(const VP8Io
* io
) {
612 WebPDecParams
* const p
= (WebPDecParams
*)io
->opaque
;
617 //------------------------------------------------------------------------------
620 void WebPInitCustomIo(WebPDecParams
* const params
, VP8Io
* const io
) {
622 io
->setup
= CustomSetup
;
623 io
->teardown
= CustomTeardown
;
627 //------------------------------------------------------------------------------