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 // Everything about WebPDecBuffer
12 // Author: Skal (pascal.massimino@gmail.com)
18 #include "../utils/utils.h"
20 //------------------------------------------------------------------------------
23 // Number of bytes per pixel for the different color-spaces.
24 static const int kModeBpp
[MODE_LAST
] = {
26 4, 4, 4, 2, // pre-multiplied modes
29 // Check that webp_csp_mode is within the bounds of WEBP_CSP_MODE.
30 // Convert to an integer to handle both the unsigned/signed enum cases
31 // without the need for casting to remove type limit warnings.
32 static int IsValidColorspace(int webp_csp_mode
) {
33 return (webp_csp_mode
>= MODE_RGB
&& webp_csp_mode
< MODE_LAST
);
36 static VP8StatusCode
CheckDecBuffer(const WebPDecBuffer
* const buffer
) {
38 const WEBP_CSP_MODE mode
= buffer
->colorspace
;
39 const int width
= buffer
->width
;
40 const int height
= buffer
->height
;
41 if (!IsValidColorspace(mode
)) {
43 } else if (!WebPIsRGBMode(mode
)) { // YUV checks
44 const WebPYUVABuffer
* const buf
= &buffer
->u
.YUVA
;
45 const uint64_t y_size
= (uint64_t)buf
->y_stride
* height
;
46 const uint64_t u_size
= (uint64_t)buf
->u_stride
* ((height
+ 1) / 2);
47 const uint64_t v_size
= (uint64_t)buf
->v_stride
* ((height
+ 1) / 2);
48 const uint64_t a_size
= (uint64_t)buf
->a_stride
* height
;
49 ok
&= (y_size
<= buf
->y_size
);
50 ok
&= (u_size
<= buf
->u_size
);
51 ok
&= (v_size
<= buf
->v_size
);
52 ok
&= (buf
->y_stride
>= width
);
53 ok
&= (buf
->u_stride
>= (width
+ 1) / 2);
54 ok
&= (buf
->v_stride
>= (width
+ 1) / 2);
55 ok
&= (buf
->y
!= NULL
);
56 ok
&= (buf
->u
!= NULL
);
57 ok
&= (buf
->v
!= NULL
);
58 if (mode
== MODE_YUVA
) {
59 ok
&= (buf
->a_stride
>= width
);
60 ok
&= (a_size
<= buf
->a_size
);
61 ok
&= (buf
->a
!= NULL
);
63 } else { // RGB checks
64 const WebPRGBABuffer
* const buf
= &buffer
->u
.RGBA
;
65 const uint64_t size
= (uint64_t)buf
->stride
* height
;
66 ok
&= (size
<= buf
->size
);
67 ok
&= (buf
->stride
>= width
* kModeBpp
[mode
]);
68 ok
&= (buf
->rgba
!= NULL
);
70 return ok
? VP8_STATUS_OK
: VP8_STATUS_INVALID_PARAM
;
73 static VP8StatusCode
AllocateBuffer(WebPDecBuffer
* const buffer
) {
74 const int w
= buffer
->width
;
75 const int h
= buffer
->height
;
76 const WEBP_CSP_MODE mode
= buffer
->colorspace
;
78 if (w
<= 0 || h
<= 0 || !IsValidColorspace(mode
)) {
79 return VP8_STATUS_INVALID_PARAM
;
82 if (!buffer
->is_external_memory
&& buffer
->private_memory
== NULL
) {
84 int uv_stride
= 0, a_stride
= 0;
85 uint64_t uv_size
= 0, a_size
= 0, total_size
;
86 // We need memory and it hasn't been allocated yet.
87 // => initialize output buffer, now that dimensions are known.
88 const int stride
= w
* kModeBpp
[mode
];
89 const uint64_t size
= (uint64_t)stride
* h
;
91 if (!WebPIsRGBMode(mode
)) {
92 uv_stride
= (w
+ 1) / 2;
93 uv_size
= (uint64_t)uv_stride
* ((h
+ 1) / 2);
94 if (mode
== MODE_YUVA
) {
96 a_size
= (uint64_t)a_stride
* h
;
99 total_size
= size
+ 2 * uv_size
+ a_size
;
101 // Security/sanity checks
102 output
= (uint8_t*)WebPSafeMalloc(total_size
, sizeof(*output
));
103 if (output
== NULL
) {
104 return VP8_STATUS_OUT_OF_MEMORY
;
106 buffer
->private_memory
= output
;
108 if (!WebPIsRGBMode(mode
)) { // YUVA initialization
109 WebPYUVABuffer
* const buf
= &buffer
->u
.YUVA
;
111 buf
->y_stride
= stride
;
112 buf
->y_size
= (size_t)size
;
113 buf
->u
= output
+ size
;
114 buf
->u_stride
= uv_stride
;
115 buf
->u_size
= (size_t)uv_size
;
116 buf
->v
= output
+ size
+ uv_size
;
117 buf
->v_stride
= uv_stride
;
118 buf
->v_size
= (size_t)uv_size
;
119 if (mode
== MODE_YUVA
) {
120 buf
->a
= output
+ size
+ 2 * uv_size
;
122 buf
->a_size
= (size_t)a_size
;
123 buf
->a_stride
= a_stride
;
124 } else { // RGBA initialization
125 WebPRGBABuffer
* const buf
= &buffer
->u
.RGBA
;
127 buf
->stride
= stride
;
128 buf
->size
= (size_t)size
;
131 return CheckDecBuffer(buffer
);
134 VP8StatusCode
WebPAllocateDecBuffer(int w
, int h
,
135 const WebPDecoderOptions
* const options
,
136 WebPDecBuffer
* const out
) {
137 if (out
== NULL
|| w
<= 0 || h
<= 0) {
138 return VP8_STATUS_INVALID_PARAM
;
140 if (options
!= NULL
) { // First, apply options if there is any.
141 if (options
->use_cropping
) {
142 const int cw
= options
->crop_width
;
143 const int ch
= options
->crop_height
;
144 const int x
= options
->crop_left
& ~1;
145 const int y
= options
->crop_top
& ~1;
146 if (x
< 0 || y
< 0 || cw
<= 0 || ch
<= 0 || x
+ cw
> w
|| y
+ ch
> h
) {
147 return VP8_STATUS_INVALID_PARAM
; // out of frame boundary.
152 if (options
->use_scaling
) {
153 if (options
->scaled_width
<= 0 || options
->scaled_height
<= 0) {
154 return VP8_STATUS_INVALID_PARAM
;
156 w
= options
->scaled_width
;
157 h
= options
->scaled_height
;
163 // Then, allocate buffer for real
164 return AllocateBuffer(out
);
167 //------------------------------------------------------------------------------
168 // constructors / destructors
170 int WebPInitDecBufferInternal(WebPDecBuffer
* buffer
, int version
) {
171 if (WEBP_ABI_IS_INCOMPATIBLE(version
, WEBP_DECODER_ABI_VERSION
)) {
172 return 0; // version mismatch
174 if (buffer
== NULL
) return 0;
175 memset(buffer
, 0, sizeof(*buffer
));
179 void WebPFreeDecBuffer(WebPDecBuffer
* buffer
) {
180 if (buffer
!= NULL
) {
181 if (!buffer
->is_external_memory
)
182 free(buffer
->private_memory
);
183 buffer
->private_memory
= NULL
;
187 void WebPCopyDecBuffer(const WebPDecBuffer
* const src
,
188 WebPDecBuffer
* const dst
) {
189 if (src
!= NULL
&& dst
!= NULL
) {
191 if (src
->private_memory
!= NULL
) {
192 dst
->is_external_memory
= 1; // dst buffer doesn't own the memory.
193 dst
->private_memory
= NULL
;
198 // Copy and transfer ownership from src to dst (beware of parameter order!)
199 void WebPGrabDecBuffer(WebPDecBuffer
* const src
, WebPDecBuffer
* const dst
) {
200 if (src
!= NULL
&& dst
!= NULL
) {
202 if (src
->private_memory
!= NULL
) {
203 src
->is_external_memory
= 1; // src relinquishes ownership
204 src
->private_memory
= NULL
;
209 //------------------------------------------------------------------------------