webp.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836
  1. // Copyright 2010 Google Inc. All Rights Reserved.
  2. //
  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. // -----------------------------------------------------------------------------
  9. //
  10. // Main decoding functions for WEBP images.
  11. //
  12. // Author: Skal (pascal.massimino@gmail.com)
  13. #include <stdlib.h>
  14. #include "./vp8i.h"
  15. #include "./vp8li.h"
  16. #include "./webpi.h"
  17. #include "../webp/mux_types.h" // ALPHA_FLAG
  18. //------------------------------------------------------------------------------
  19. // RIFF layout is:
  20. // Offset tag
  21. // 0...3 "RIFF" 4-byte tag
  22. // 4...7 size of image data (including metadata) starting at offset 8
  23. // 8...11 "WEBP" our form-type signature
  24. // The RIFF container (12 bytes) is followed by appropriate chunks:
  25. // 12..15 "VP8 ": 4-bytes tags, signaling the use of VP8 video format
  26. // 16..19 size of the raw VP8 image data, starting at offset 20
  27. // 20.... the VP8 bytes
  28. // Or,
  29. // 12..15 "VP8L": 4-bytes tags, signaling the use of VP8L lossless format
  30. // 16..19 size of the raw VP8L image data, starting at offset 20
  31. // 20.... the VP8L bytes
  32. // Or,
  33. // 12..15 "VP8X": 4-bytes tags, describing the extended-VP8 chunk.
  34. // 16..19 size of the VP8X chunk starting at offset 20.
  35. // 20..23 VP8X flags bit-map corresponding to the chunk-types present.
  36. // 24..26 Width of the Canvas Image.
  37. // 27..29 Height of the Canvas Image.
  38. // There can be extra chunks after the "VP8X" chunk (ICCP, FRGM, ANMF, VP8,
  39. // VP8L, XMP, EXIF ...)
  40. // All sizes are in little-endian order.
  41. // Note: chunk data size must be padded to multiple of 2 when written.
  42. static WEBP_INLINE uint32_t get_le24(const uint8_t* const data) {
  43. return data[0] | (data[1] << 8) | (data[2] << 16);
  44. }
  45. static WEBP_INLINE uint32_t get_le32(const uint8_t* const data) {
  46. return (uint32_t)get_le24(data) | (data[3] << 24);
  47. }
  48. // Validates the RIFF container (if detected) and skips over it.
  49. // If a RIFF container is detected, returns:
  50. // VP8_STATUS_BITSTREAM_ERROR for invalid header,
  51. // VP8_STATUS_NOT_ENOUGH_DATA for truncated data if have_all_data is true,
  52. // and VP8_STATUS_OK otherwise.
  53. // In case there are not enough bytes (partial RIFF container), return 0 for
  54. // *riff_size. Else return the RIFF size extracted from the header.
  55. static VP8StatusCode ParseRIFF(const uint8_t** const data,
  56. size_t* const data_size, int have_all_data,
  57. size_t* const riff_size) {
  58. assert(data != NULL);
  59. assert(data_size != NULL);
  60. assert(riff_size != NULL);
  61. *riff_size = 0; // Default: no RIFF present.
  62. if (*data_size >= RIFF_HEADER_SIZE && !memcmp(*data, "RIFF", TAG_SIZE)) {
  63. if (memcmp(*data + 8, "WEBP", TAG_SIZE)) {
  64. return VP8_STATUS_BITSTREAM_ERROR; // Wrong image file signature.
  65. } else {
  66. const uint32_t size = get_le32(*data + TAG_SIZE);
  67. // Check that we have at least one chunk (i.e "WEBP" + "VP8?nnnn").
  68. if (size < TAG_SIZE + CHUNK_HEADER_SIZE) {
  69. return VP8_STATUS_BITSTREAM_ERROR;
  70. }
  71. if (size > MAX_CHUNK_PAYLOAD) {
  72. return VP8_STATUS_BITSTREAM_ERROR;
  73. }
  74. if (have_all_data && (size > *data_size - CHUNK_HEADER_SIZE)) {
  75. return VP8_STATUS_NOT_ENOUGH_DATA; // Truncated bitstream.
  76. }
  77. // We have a RIFF container. Skip it.
  78. *riff_size = size;
  79. *data += RIFF_HEADER_SIZE;
  80. *data_size -= RIFF_HEADER_SIZE;
  81. }
  82. }
  83. return VP8_STATUS_OK;
  84. }
  85. // Validates the VP8X header and skips over it.
  86. // Returns VP8_STATUS_BITSTREAM_ERROR for invalid VP8X header,
  87. // VP8_STATUS_NOT_ENOUGH_DATA in case of insufficient data, and
  88. // VP8_STATUS_OK otherwise.
  89. // If a VP8X chunk is found, found_vp8x is set to true and *width_ptr,
  90. // *height_ptr and *flags_ptr are set to the corresponding values extracted
  91. // from the VP8X chunk.
  92. static VP8StatusCode ParseVP8X(const uint8_t** const data,
  93. size_t* const data_size,
  94. int* const found_vp8x,
  95. int* const width_ptr, int* const height_ptr,
  96. uint32_t* const flags_ptr) {
  97. const uint32_t vp8x_size = CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE;
  98. assert(data != NULL);
  99. assert(data_size != NULL);
  100. assert(found_vp8x != NULL);
  101. *found_vp8x = 0;
  102. if (*data_size < CHUNK_HEADER_SIZE) {
  103. return VP8_STATUS_NOT_ENOUGH_DATA; // Insufficient data.
  104. }
  105. if (!memcmp(*data, "VP8X", TAG_SIZE)) {
  106. int width, height;
  107. uint32_t flags;
  108. const uint32_t chunk_size = get_le32(*data + TAG_SIZE);
  109. if (chunk_size != VP8X_CHUNK_SIZE) {
  110. return VP8_STATUS_BITSTREAM_ERROR; // Wrong chunk size.
  111. }
  112. // Verify if enough data is available to validate the VP8X chunk.
  113. if (*data_size < vp8x_size) {
  114. return VP8_STATUS_NOT_ENOUGH_DATA; // Insufficient data.
  115. }
  116. flags = get_le32(*data + 8);
  117. width = 1 + get_le24(*data + 12);
  118. height = 1 + get_le24(*data + 15);
  119. if (width * (uint64_t)height >= MAX_IMAGE_AREA) {
  120. return VP8_STATUS_BITSTREAM_ERROR; // image is too large
  121. }
  122. if (flags_ptr != NULL) *flags_ptr = flags;
  123. if (width_ptr != NULL) *width_ptr = width;
  124. if (height_ptr != NULL) *height_ptr = height;
  125. // Skip over VP8X header bytes.
  126. *data += vp8x_size;
  127. *data_size -= vp8x_size;
  128. *found_vp8x = 1;
  129. }
  130. return VP8_STATUS_OK;
  131. }
  132. // Skips to the next VP8/VP8L chunk header in the data given the size of the
  133. // RIFF chunk 'riff_size'.
  134. // Returns VP8_STATUS_BITSTREAM_ERROR if any invalid chunk size is encountered,
  135. // VP8_STATUS_NOT_ENOUGH_DATA in case of insufficient data, and
  136. // VP8_STATUS_OK otherwise.
  137. // If an alpha chunk is found, *alpha_data and *alpha_size are set
  138. // appropriately.
  139. static VP8StatusCode ParseOptionalChunks(const uint8_t** const data,
  140. size_t* const data_size,
  141. size_t const riff_size,
  142. const uint8_t** const alpha_data,
  143. size_t* const alpha_size) {
  144. const uint8_t* buf;
  145. size_t buf_size;
  146. uint32_t total_size = TAG_SIZE + // "WEBP".
  147. CHUNK_HEADER_SIZE + // "VP8Xnnnn".
  148. VP8X_CHUNK_SIZE; // data.
  149. assert(data != NULL);
  150. assert(data_size != NULL);
  151. buf = *data;
  152. buf_size = *data_size;
  153. assert(alpha_data != NULL);
  154. assert(alpha_size != NULL);
  155. *alpha_data = NULL;
  156. *alpha_size = 0;
  157. while (1) {
  158. uint32_t chunk_size;
  159. uint32_t disk_chunk_size; // chunk_size with padding
  160. *data = buf;
  161. *data_size = buf_size;
  162. if (buf_size < CHUNK_HEADER_SIZE) { // Insufficient data.
  163. return VP8_STATUS_NOT_ENOUGH_DATA;
  164. }
  165. chunk_size = get_le32(buf + TAG_SIZE);
  166. if (chunk_size > MAX_CHUNK_PAYLOAD) {
  167. return VP8_STATUS_BITSTREAM_ERROR; // Not a valid chunk size.
  168. }
  169. // For odd-sized chunk-payload, there's one byte padding at the end.
  170. disk_chunk_size = (CHUNK_HEADER_SIZE + chunk_size + 1) & ~1;
  171. total_size += disk_chunk_size;
  172. // Check that total bytes skipped so far does not exceed riff_size.
  173. if (riff_size > 0 && (total_size > riff_size)) {
  174. return VP8_STATUS_BITSTREAM_ERROR; // Not a valid chunk size.
  175. }
  176. // Start of a (possibly incomplete) VP8/VP8L chunk implies that we have
  177. // parsed all the optional chunks.
  178. // Note: This check must occur before the check 'buf_size < disk_chunk_size'
  179. // below to allow incomplete VP8/VP8L chunks.
  180. if (!memcmp(buf, "VP8 ", TAG_SIZE) ||
  181. !memcmp(buf, "VP8L", TAG_SIZE)) {
  182. return VP8_STATUS_OK;
  183. }
  184. if (buf_size < disk_chunk_size) { // Insufficient data.
  185. return VP8_STATUS_NOT_ENOUGH_DATA;
  186. }
  187. if (!memcmp(buf, "ALPH", TAG_SIZE)) { // A valid ALPH header.
  188. *alpha_data = buf + CHUNK_HEADER_SIZE;
  189. *alpha_size = chunk_size;
  190. }
  191. // We have a full and valid chunk; skip it.
  192. buf += disk_chunk_size;
  193. buf_size -= disk_chunk_size;
  194. }
  195. }
  196. // Validates the VP8/VP8L Header ("VP8 nnnn" or "VP8L nnnn") and skips over it.
  197. // Returns VP8_STATUS_BITSTREAM_ERROR for invalid (chunk larger than
  198. // riff_size) VP8/VP8L header,
  199. // VP8_STATUS_NOT_ENOUGH_DATA in case of insufficient data, and
  200. // VP8_STATUS_OK otherwise.
  201. // If a VP8/VP8L chunk is found, *chunk_size is set to the total number of bytes
  202. // extracted from the VP8/VP8L chunk header.
  203. // The flag '*is_lossless' is set to 1 in case of VP8L chunk / raw VP8L data.
  204. static VP8StatusCode ParseVP8Header(const uint8_t** const data_ptr,
  205. size_t* const data_size, int have_all_data,
  206. size_t riff_size, size_t* const chunk_size,
  207. int* const is_lossless) {
  208. const uint8_t* const data = *data_ptr;
  209. const int is_vp8 = !memcmp(data, "VP8 ", TAG_SIZE);
  210. const int is_vp8l = !memcmp(data, "VP8L", TAG_SIZE);
  211. const uint32_t minimal_size =
  212. TAG_SIZE + CHUNK_HEADER_SIZE; // "WEBP" + "VP8 nnnn" OR
  213. // "WEBP" + "VP8Lnnnn"
  214. assert(data != NULL);
  215. assert(data_size != NULL);
  216. assert(chunk_size != NULL);
  217. assert(is_lossless != NULL);
  218. if (*data_size < CHUNK_HEADER_SIZE) {
  219. return VP8_STATUS_NOT_ENOUGH_DATA; // Insufficient data.
  220. }
  221. if (is_vp8 || is_vp8l) {
  222. // Bitstream contains VP8/VP8L header.
  223. const uint32_t size = get_le32(data + TAG_SIZE);
  224. if ((riff_size >= minimal_size) && (size > riff_size - minimal_size)) {
  225. return VP8_STATUS_BITSTREAM_ERROR; // Inconsistent size information.
  226. }
  227. if (have_all_data && (size > *data_size - CHUNK_HEADER_SIZE)) {
  228. return VP8_STATUS_NOT_ENOUGH_DATA; // Truncated bitstream.
  229. }
  230. // Skip over CHUNK_HEADER_SIZE bytes from VP8/VP8L Header.
  231. *chunk_size = size;
  232. *data_ptr += CHUNK_HEADER_SIZE;
  233. *data_size -= CHUNK_HEADER_SIZE;
  234. *is_lossless = is_vp8l;
  235. } else {
  236. // Raw VP8/VP8L bitstream (no header).
  237. *is_lossless = VP8LCheckSignature(data, *data_size);
  238. *chunk_size = *data_size;
  239. }
  240. return VP8_STATUS_OK;
  241. }
  242. //------------------------------------------------------------------------------
  243. // Fetch '*width', '*height', '*has_alpha' and fill out 'headers' based on
  244. // 'data'. All the output parameters may be NULL. If 'headers' is NULL only the
  245. // minimal amount will be read to fetch the remaining parameters.
  246. // If 'headers' is non-NULL this function will attempt to locate both alpha
  247. // data (with or without a VP8X chunk) and the bitstream chunk (VP8/VP8L).
  248. // Note: The following chunk sequences (before the raw VP8/VP8L data) are
  249. // considered valid by this function:
  250. // RIFF + VP8(L)
  251. // RIFF + VP8X + (optional chunks) + VP8(L)
  252. // ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose.
  253. // VP8(L) <-- Not a valid WebP format: only allowed for internal purpose.
  254. static VP8StatusCode ParseHeadersInternal(const uint8_t* data,
  255. size_t data_size,
  256. int* const width,
  257. int* const height,
  258. int* const has_alpha,
  259. int* const has_animation,
  260. int* const format,
  261. WebPHeaderStructure* const headers) {
  262. int canvas_width = 0;
  263. int canvas_height = 0;
  264. int image_width = 0;
  265. int image_height = 0;
  266. int found_riff = 0;
  267. int found_vp8x = 0;
  268. int animation_present = 0;
  269. int fragments_present = 0;
  270. const int have_all_data = (headers != NULL) ? headers->have_all_data : 0;
  271. VP8StatusCode status;
  272. WebPHeaderStructure hdrs;
  273. if (data == NULL || data_size < RIFF_HEADER_SIZE) {
  274. return VP8_STATUS_NOT_ENOUGH_DATA;
  275. }
  276. memset(&hdrs, 0, sizeof(hdrs));
  277. hdrs.data = data;
  278. hdrs.data_size = data_size;
  279. // Skip over RIFF header.
  280. status = ParseRIFF(&data, &data_size, have_all_data, &hdrs.riff_size);
  281. if (status != VP8_STATUS_OK) {
  282. return status; // Wrong RIFF header / insufficient data.
  283. }
  284. found_riff = (hdrs.riff_size > 0);
  285. // Skip over VP8X.
  286. {
  287. uint32_t flags = 0;
  288. status = ParseVP8X(&data, &data_size, &found_vp8x,
  289. &canvas_width, &canvas_height, &flags);
  290. if (status != VP8_STATUS_OK) {
  291. return status; // Wrong VP8X / insufficient data.
  292. }
  293. animation_present = !!(flags & ANIMATION_FLAG);
  294. fragments_present = !!(flags & FRAGMENTS_FLAG);
  295. if (!found_riff && found_vp8x) {
  296. // Note: This restriction may be removed in the future, if it becomes
  297. // necessary to send VP8X chunk to the decoder.
  298. return VP8_STATUS_BITSTREAM_ERROR;
  299. }
  300. if (has_alpha != NULL) *has_alpha = !!(flags & ALPHA_FLAG);
  301. if (has_animation != NULL) *has_animation = animation_present;
  302. if (format != NULL) *format = 0; // default = undefined
  303. image_width = canvas_width;
  304. image_height = canvas_height;
  305. if (found_vp8x && (animation_present || fragments_present) &&
  306. headers == NULL) {
  307. status = VP8_STATUS_OK;
  308. goto ReturnWidthHeight; // Just return features from VP8X header.
  309. }
  310. }
  311. if (data_size < TAG_SIZE) {
  312. status = VP8_STATUS_NOT_ENOUGH_DATA;
  313. goto ReturnWidthHeight;
  314. }
  315. // Skip over optional chunks if data started with "RIFF + VP8X" or "ALPH".
  316. if ((found_riff && found_vp8x) ||
  317. (!found_riff && !found_vp8x && !memcmp(data, "ALPH", TAG_SIZE))) {
  318. status = ParseOptionalChunks(&data, &data_size, hdrs.riff_size,
  319. &hdrs.alpha_data, &hdrs.alpha_data_size);
  320. if (status != VP8_STATUS_OK) {
  321. goto ReturnWidthHeight; // Invalid chunk size / insufficient data.
  322. }
  323. }
  324. // Skip over VP8/VP8L header.
  325. status = ParseVP8Header(&data, &data_size, have_all_data, hdrs.riff_size,
  326. &hdrs.compressed_size, &hdrs.is_lossless);
  327. if (status != VP8_STATUS_OK) {
  328. goto ReturnWidthHeight; // Wrong VP8/VP8L chunk-header / insufficient data.
  329. }
  330. if (hdrs.compressed_size > MAX_CHUNK_PAYLOAD) {
  331. return VP8_STATUS_BITSTREAM_ERROR;
  332. }
  333. if (format != NULL && !(animation_present || fragments_present)) {
  334. *format = hdrs.is_lossless ? 2 : 1;
  335. }
  336. if (!hdrs.is_lossless) {
  337. if (data_size < VP8_FRAME_HEADER_SIZE) {
  338. status = VP8_STATUS_NOT_ENOUGH_DATA;
  339. goto ReturnWidthHeight;
  340. }
  341. // Validates raw VP8 data.
  342. if (!VP8GetInfo(data, data_size, (uint32_t)hdrs.compressed_size,
  343. &image_width, &image_height)) {
  344. return VP8_STATUS_BITSTREAM_ERROR;
  345. }
  346. } else {
  347. if (data_size < VP8L_FRAME_HEADER_SIZE) {
  348. status = VP8_STATUS_NOT_ENOUGH_DATA;
  349. goto ReturnWidthHeight;
  350. }
  351. // Validates raw VP8L data.
  352. if (!VP8LGetInfo(data, data_size, &image_width, &image_height, has_alpha)) {
  353. return VP8_STATUS_BITSTREAM_ERROR;
  354. }
  355. }
  356. // Validates image size coherency.
  357. if (found_vp8x) {
  358. if (canvas_width != image_width || canvas_height != image_height) {
  359. return VP8_STATUS_BITSTREAM_ERROR;
  360. }
  361. }
  362. if (headers != NULL) {
  363. *headers = hdrs;
  364. headers->offset = data - headers->data;
  365. assert((uint64_t)(data - headers->data) < MAX_CHUNK_PAYLOAD);
  366. assert(headers->offset == headers->data_size - data_size);
  367. }
  368. ReturnWidthHeight:
  369. if (status == VP8_STATUS_OK ||
  370. (status == VP8_STATUS_NOT_ENOUGH_DATA && found_vp8x && headers == NULL)) {
  371. if (has_alpha != NULL) {
  372. // If the data did not contain a VP8X/VP8L chunk the only definitive way
  373. // to set this is by looking for alpha data (from an ALPH chunk).
  374. *has_alpha |= (hdrs.alpha_data != NULL);
  375. }
  376. if (width != NULL) *width = image_width;
  377. if (height != NULL) *height = image_height;
  378. return VP8_STATUS_OK;
  379. } else {
  380. return status;
  381. }
  382. }
  383. VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers) {
  384. VP8StatusCode status;
  385. int has_animation = 0;
  386. assert(headers != NULL);
  387. // fill out headers, ignore width/height/has_alpha.
  388. status = ParseHeadersInternal(headers->data, headers->data_size,
  389. NULL, NULL, NULL, &has_animation,
  390. NULL, headers);
  391. if (status == VP8_STATUS_OK || status == VP8_STATUS_NOT_ENOUGH_DATA) {
  392. // TODO(jzern): full support of animation frames will require API additions.
  393. if (has_animation) {
  394. status = VP8_STATUS_UNSUPPORTED_FEATURE;
  395. }
  396. }
  397. return status;
  398. }
  399. //------------------------------------------------------------------------------
  400. // WebPDecParams
  401. void WebPResetDecParams(WebPDecParams* const params) {
  402. if (params != NULL) {
  403. memset(params, 0, sizeof(*params));
  404. }
  405. }
  406. //------------------------------------------------------------------------------
  407. // "Into" decoding variants
  408. // Main flow
  409. static VP8StatusCode DecodeInto(const uint8_t* const data, size_t data_size,
  410. WebPDecParams* const params) {
  411. VP8StatusCode status;
  412. VP8Io io;
  413. WebPHeaderStructure headers;
  414. headers.data = data;
  415. headers.data_size = data_size;
  416. headers.have_all_data = 1;
  417. status = WebPParseHeaders(&headers); // Process Pre-VP8 chunks.
  418. if (status != VP8_STATUS_OK) {
  419. return status;
  420. }
  421. assert(params != NULL);
  422. VP8InitIo(&io);
  423. io.data = headers.data + headers.offset;
  424. io.data_size = headers.data_size - headers.offset;
  425. WebPInitCustomIo(params, &io); // Plug the I/O functions.
  426. if (!headers.is_lossless) {
  427. VP8Decoder* const dec = VP8New();
  428. if (dec == NULL) {
  429. return VP8_STATUS_OUT_OF_MEMORY;
  430. }
  431. dec->alpha_data_ = headers.alpha_data;
  432. dec->alpha_data_size_ = headers.alpha_data_size;
  433. // Decode bitstream header, update io->width/io->height.
  434. if (!VP8GetHeaders(dec, &io)) {
  435. status = dec->status_; // An error occurred. Grab error status.
  436. } else {
  437. // Allocate/check output buffers.
  438. status = WebPAllocateDecBuffer(io.width, io.height, params->options,
  439. params->output);
  440. if (status == VP8_STATUS_OK) { // Decode
  441. // This change must be done before calling VP8Decode()
  442. dec->mt_method_ = VP8GetThreadMethod(params->options, &headers,
  443. io.width, io.height);
  444. VP8InitDithering(params->options, dec);
  445. if (!VP8Decode(dec, &io)) {
  446. status = dec->status_;
  447. }
  448. }
  449. }
  450. VP8Delete(dec);
  451. } else {
  452. VP8LDecoder* const dec = VP8LNew();
  453. if (dec == NULL) {
  454. return VP8_STATUS_OUT_OF_MEMORY;
  455. }
  456. if (!VP8LDecodeHeader(dec, &io)) {
  457. status = dec->status_; // An error occurred. Grab error status.
  458. } else {
  459. // Allocate/check output buffers.
  460. status = WebPAllocateDecBuffer(io.width, io.height, params->options,
  461. params->output);
  462. if (status == VP8_STATUS_OK) { // Decode
  463. if (!VP8LDecodeImage(dec)) {
  464. status = dec->status_;
  465. }
  466. }
  467. }
  468. VP8LDelete(dec);
  469. }
  470. if (status != VP8_STATUS_OK) {
  471. WebPFreeDecBuffer(params->output);
  472. }
  473. #if WEBP_DECODER_ABI_VERSION > 0x0203
  474. if (params->options != NULL && params->options->flip) {
  475. status = WebPFlipBuffer(params->output);
  476. }
  477. #endif
  478. return status;
  479. }
  480. // Helpers
  481. static uint8_t* DecodeIntoRGBABuffer(WEBP_CSP_MODE colorspace,
  482. const uint8_t* const data,
  483. size_t data_size,
  484. uint8_t* const rgba,
  485. int stride, size_t size) {
  486. WebPDecParams params;
  487. WebPDecBuffer buf;
  488. if (rgba == NULL) {
  489. return NULL;
  490. }
  491. WebPInitDecBuffer(&buf);
  492. WebPResetDecParams(&params);
  493. params.output = &buf;
  494. buf.colorspace = colorspace;
  495. buf.u.RGBA.rgba = rgba;
  496. buf.u.RGBA.stride = stride;
  497. buf.u.RGBA.size = size;
  498. buf.is_external_memory = 1;
  499. if (DecodeInto(data, data_size, &params) != VP8_STATUS_OK) {
  500. return NULL;
  501. }
  502. return rgba;
  503. }
  504. uint8_t* WebPDecodeRGBInto(const uint8_t* data, size_t data_size,
  505. uint8_t* output, size_t size, int stride) {
  506. return DecodeIntoRGBABuffer(MODE_RGB, data, data_size, output, stride, size);
  507. }
  508. uint8_t* WebPDecodeRGBAInto(const uint8_t* data, size_t data_size,
  509. uint8_t* output, size_t size, int stride) {
  510. return DecodeIntoRGBABuffer(MODE_rgbA, data, data_size, output, stride, size);
  511. }
  512. uint8_t* WebPDecodeARGBInto(const uint8_t* data, size_t data_size,
  513. uint8_t* output, size_t size, int stride) {
  514. return DecodeIntoRGBABuffer(MODE_ARGB, data, data_size, output, stride, size);
  515. }
  516. uint8_t* WebPDecodeBGRInto(const uint8_t* data, size_t data_size,
  517. uint8_t* output, size_t size, int stride) {
  518. return DecodeIntoRGBABuffer(MODE_BGR, data, data_size, output, stride, size);
  519. }
  520. uint8_t* WebPDecodeBGRAInto(const uint8_t* data, size_t data_size,
  521. uint8_t* output, size_t size, int stride) {
  522. return DecodeIntoRGBABuffer(MODE_BGRA, data, data_size, output, stride, size);
  523. }
  524. uint8_t* WebPDecodeYUVInto(const uint8_t* data, size_t data_size,
  525. uint8_t* luma, size_t luma_size, int luma_stride,
  526. uint8_t* u, size_t u_size, int u_stride,
  527. uint8_t* v, size_t v_size, int v_stride) {
  528. WebPDecParams params;
  529. WebPDecBuffer output;
  530. if (luma == NULL) return NULL;
  531. WebPInitDecBuffer(&output);
  532. WebPResetDecParams(&params);
  533. params.output = &output;
  534. output.colorspace = MODE_YUV;
  535. output.u.YUVA.y = luma;
  536. output.u.YUVA.y_stride = luma_stride;
  537. output.u.YUVA.y_size = luma_size;
  538. output.u.YUVA.u = u;
  539. output.u.YUVA.u_stride = u_stride;
  540. output.u.YUVA.u_size = u_size;
  541. output.u.YUVA.v = v;
  542. output.u.YUVA.v_stride = v_stride;
  543. output.u.YUVA.v_size = v_size;
  544. output.is_external_memory = 1;
  545. if (DecodeInto(data, data_size, &params) != VP8_STATUS_OK) {
  546. return NULL;
  547. }
  548. return luma;
  549. }
  550. //------------------------------------------------------------------------------
  551. static uint8_t* Decode(WEBP_CSP_MODE mode, const uint8_t* const data,
  552. size_t data_size, int* const width, int* const height,
  553. WebPDecBuffer* const keep_info) {
  554. WebPDecParams params;
  555. WebPDecBuffer output;
  556. WebPInitDecBuffer(&output);
  557. WebPResetDecParams(&params);
  558. params.output = &output;
  559. output.colorspace = mode;
  560. // Retrieve (and report back) the required dimensions from bitstream.
  561. if (!WebPGetInfo(data, data_size, &output.width, &output.height)) {
  562. return NULL;
  563. }
  564. if (width != NULL) *width = output.width;
  565. if (height != NULL) *height = output.height;
  566. // Decode
  567. if (DecodeInto(data, data_size, &params) != VP8_STATUS_OK) {
  568. return NULL;
  569. }
  570. if (keep_info != NULL) { // keep track of the side-info
  571. WebPCopyDecBuffer(&output, keep_info);
  572. }
  573. // return decoded samples (don't clear 'output'!)
  574. return WebPIsRGBMode(mode) ? output.u.RGBA.rgba : output.u.YUVA.y;
  575. }
  576. uint8_t* WebPDecodeRGB(const uint8_t* data, size_t data_size,
  577. int* width, int* height) {
  578. return Decode(MODE_RGB, data, data_size, width, height, NULL);
  579. }
  580. uint8_t* WebPDecodeRGBA(const uint8_t* data, size_t data_size,
  581. int* width, int* height) {
  582. return Decode(MODE_RGBA, data, data_size, width, height, NULL);
  583. }
  584. uint8_t* WebPDecodeARGB(const uint8_t* data, size_t data_size,
  585. int* width, int* height) {
  586. return Decode(MODE_ARGB, data, data_size, width, height, NULL);
  587. }
  588. uint8_t* WebPDecodeBGR(const uint8_t* data, size_t data_size,
  589. int* width, int* height) {
  590. return Decode(MODE_BGR, data, data_size, width, height, NULL);
  591. }
  592. uint8_t* WebPDecodeBGRA(const uint8_t* data, size_t data_size,
  593. int* width, int* height) {
  594. return Decode(MODE_BGRA, data, data_size, width, height, NULL);
  595. }
  596. uint8_t* WebPDecodeYUV(const uint8_t* data, size_t data_size,
  597. int* width, int* height, uint8_t** u, uint8_t** v,
  598. int* stride, int* uv_stride) {
  599. WebPDecBuffer output; // only to preserve the side-infos
  600. uint8_t* const out = Decode(MODE_YUV, data, data_size,
  601. width, height, &output);
  602. if (out != NULL) {
  603. const WebPYUVABuffer* const buf = &output.u.YUVA;
  604. *u = buf->u;
  605. *v = buf->v;
  606. *stride = buf->y_stride;
  607. *uv_stride = buf->u_stride;
  608. assert(buf->u_stride == buf->v_stride);
  609. }
  610. return out;
  611. }
  612. static void DefaultFeatures(WebPBitstreamFeatures* const features) {
  613. assert(features != NULL);
  614. memset(features, 0, sizeof(*features));
  615. }
  616. static VP8StatusCode GetFeatures(const uint8_t* const data, size_t data_size,
  617. WebPBitstreamFeatures* const features) {
  618. if (features == NULL || data == NULL) {
  619. return VP8_STATUS_INVALID_PARAM;
  620. }
  621. DefaultFeatures(features);
  622. // Only parse enough of the data to retrieve the features.
  623. return ParseHeadersInternal(data, data_size,
  624. &features->width, &features->height,
  625. &features->has_alpha, &features->has_animation,
  626. &features->format, NULL);
  627. }
  628. //------------------------------------------------------------------------------
  629. // WebPGetInfo()
  630. int WebPGetInfo(const uint8_t* data, size_t data_size,
  631. int* width, int* height) {
  632. WebPBitstreamFeatures features;
  633. if (GetFeatures(data, data_size, &features) != VP8_STATUS_OK) {
  634. return 0;
  635. }
  636. if (width != NULL) {
  637. *width = features.width;
  638. }
  639. if (height != NULL) {
  640. *height = features.height;
  641. }
  642. return 1;
  643. }
  644. //------------------------------------------------------------------------------
  645. // Advance decoding API
  646. int WebPInitDecoderConfigInternal(WebPDecoderConfig* config,
  647. int version) {
  648. if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) {
  649. return 0; // version mismatch
  650. }
  651. if (config == NULL) {
  652. return 0;
  653. }
  654. memset(config, 0, sizeof(*config));
  655. DefaultFeatures(&config->input);
  656. WebPInitDecBuffer(&config->output);
  657. return 1;
  658. }
  659. VP8StatusCode WebPGetFeaturesInternal(const uint8_t* data, size_t data_size,
  660. WebPBitstreamFeatures* features,
  661. int version) {
  662. if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) {
  663. return VP8_STATUS_INVALID_PARAM; // version mismatch
  664. }
  665. if (features == NULL) {
  666. return VP8_STATUS_INVALID_PARAM;
  667. }
  668. return GetFeatures(data, data_size, features);
  669. }
  670. VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size,
  671. WebPDecoderConfig* config) {
  672. WebPDecParams params;
  673. VP8StatusCode status;
  674. if (config == NULL) {
  675. return VP8_STATUS_INVALID_PARAM;
  676. }
  677. status = GetFeatures(data, data_size, &config->input);
  678. if (status != VP8_STATUS_OK) {
  679. if (status == VP8_STATUS_NOT_ENOUGH_DATA) {
  680. return VP8_STATUS_BITSTREAM_ERROR; // Not-enough-data treated as error.
  681. }
  682. return status;
  683. }
  684. WebPResetDecParams(&params);
  685. params.output = &config->output;
  686. params.options = &config->options;
  687. status = DecodeInto(data, data_size, &params);
  688. return status;
  689. }
  690. //------------------------------------------------------------------------------
  691. // Cropping and rescaling.
  692. int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
  693. VP8Io* const io, WEBP_CSP_MODE src_colorspace) {
  694. const int W = io->width;
  695. const int H = io->height;
  696. int x = 0, y = 0, w = W, h = H;
  697. // Cropping
  698. io->use_cropping = (options != NULL) && (options->use_cropping > 0);
  699. if (io->use_cropping) {
  700. w = options->crop_width;
  701. h = options->crop_height;
  702. x = options->crop_left;
  703. y = options->crop_top;
  704. if (!WebPIsRGBMode(src_colorspace)) { // only snap for YUV420
  705. x &= ~1;
  706. y &= ~1;
  707. }
  708. if (x < 0 || y < 0 || w <= 0 || h <= 0 || x + w > W || y + h > H) {
  709. return 0; // out of frame boundary error
  710. }
  711. }
  712. io->crop_left = x;
  713. io->crop_top = y;
  714. io->crop_right = x + w;
  715. io->crop_bottom = y + h;
  716. io->mb_w = w;
  717. io->mb_h = h;
  718. // Scaling
  719. io->use_scaling = (options != NULL) && (options->use_scaling > 0);
  720. if (io->use_scaling) {
  721. if (options->scaled_width <= 0 || options->scaled_height <= 0) {
  722. return 0;
  723. }
  724. io->scaled_width = options->scaled_width;
  725. io->scaled_height = options->scaled_height;
  726. }
  727. // Filter
  728. io->bypass_filtering = options && options->bypass_filtering;
  729. // Fancy upsampler
  730. #ifdef FANCY_UPSAMPLING
  731. io->fancy_upsampling = (options == NULL) || (!options->no_fancy_upsampling);
  732. #endif
  733. if (io->use_scaling) {
  734. // disable filter (only for large downscaling ratio).
  735. io->bypass_filtering = (io->scaled_width < W * 3 / 4) &&
  736. (io->scaled_height < H * 3 / 4);
  737. io->fancy_upsampling = 0;
  738. }
  739. return 1;
  740. }
  741. //------------------------------------------------------------------------------