anim_decode.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. // Copyright 2015 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. // AnimDecoder implementation.
  11. //
  12. #ifdef HAVE_CONFIG_H
  13. #include "../webp/config.h"
  14. #endif
  15. #include <assert.h>
  16. #include <string.h>
  17. #include "../utils/utils.h"
  18. #include "../webp/decode.h"
  19. #include "../webp/demux.h"
  20. #define NUM_CHANNELS 4
  21. // Channel extraction from a uint32_t representation of a uint8_t RGBA/BGRA
  22. // buffer.
  23. #ifdef WORDS_BIGENDIAN
  24. #define CHANNEL_SHIFT(i) (24 - (i) * 8)
  25. #else
  26. #define CHANNEL_SHIFT(i) ((i) * 8)
  27. #endif
  28. typedef void (*BlendRowFunc)(uint32_t* const, const uint32_t* const, int);
  29. static void BlendPixelRowNonPremult(uint32_t* const src,
  30. const uint32_t* const dst, int num_pixels);
  31. static void BlendPixelRowPremult(uint32_t* const src, const uint32_t* const dst,
  32. int num_pixels);
  33. struct WebPAnimDecoder {
  34. WebPDemuxer* demux_; // Demuxer created from given WebP bitstream.
  35. WebPDecoderConfig config_; // Decoder config.
  36. // Note: we use a pointer to a function blending multiple pixels at a time to
  37. // allow possible inlining of per-pixel blending function.
  38. BlendRowFunc blend_func_; // Pointer to the chose blend row function.
  39. WebPAnimInfo info_; // Global info about the animation.
  40. uint8_t* curr_frame_; // Current canvas (not disposed).
  41. uint8_t* prev_frame_disposed_; // Previous canvas (properly disposed).
  42. int prev_frame_timestamp_; // Previous frame timestamp (milliseconds).
  43. WebPIterator prev_iter_; // Iterator object for previous frame.
  44. int prev_frame_was_keyframe_; // True if previous frame was a keyframe.
  45. int next_frame_; // Index of the next frame to be decoded
  46. // (starting from 1).
  47. };
  48. static void DefaultDecoderOptions(WebPAnimDecoderOptions* const dec_options) {
  49. dec_options->color_mode = MODE_RGBA;
  50. dec_options->use_threads = 0;
  51. }
  52. int WebPAnimDecoderOptionsInitInternal(WebPAnimDecoderOptions* dec_options,
  53. int abi_version) {
  54. if (dec_options == NULL ||
  55. WEBP_ABI_IS_INCOMPATIBLE(abi_version, WEBP_DEMUX_ABI_VERSION)) {
  56. return 0;
  57. }
  58. DefaultDecoderOptions(dec_options);
  59. return 1;
  60. }
  61. static int ApplyDecoderOptions(const WebPAnimDecoderOptions* const dec_options,
  62. WebPAnimDecoder* const dec) {
  63. WEBP_CSP_MODE mode;
  64. WebPDecoderConfig* config = &dec->config_;
  65. assert(dec_options != NULL);
  66. mode = dec_options->color_mode;
  67. if (mode != MODE_RGBA && mode != MODE_BGRA &&
  68. mode != MODE_rgbA && mode != MODE_bgrA) {
  69. return 0;
  70. }
  71. dec->blend_func_ = (mode == MODE_RGBA || mode == MODE_BGRA)
  72. ? &BlendPixelRowNonPremult
  73. : &BlendPixelRowPremult;
  74. WebPInitDecoderConfig(config);
  75. config->output.colorspace = mode;
  76. config->output.is_external_memory = 1;
  77. config->options.use_threads = dec_options->use_threads;
  78. // Note: config->output.u.RGBA is set at the time of decoding each frame.
  79. return 1;
  80. }
  81. WebPAnimDecoder* WebPAnimDecoderNewInternal(
  82. const WebPData* webp_data, const WebPAnimDecoderOptions* dec_options,
  83. int abi_version) {
  84. WebPAnimDecoderOptions options;
  85. WebPAnimDecoder* dec = NULL;
  86. WebPBitstreamFeatures features;
  87. if (webp_data == NULL ||
  88. WEBP_ABI_IS_INCOMPATIBLE(abi_version, WEBP_DEMUX_ABI_VERSION)) {
  89. return NULL;
  90. }
  91. // Validate the bitstream before doing expensive allocations. The demuxer may
  92. // be more tolerant than the decoder.
  93. if (WebPGetFeatures(webp_data->bytes, webp_data->size, &features) !=
  94. VP8_STATUS_OK) {
  95. return NULL;
  96. }
  97. // Note: calloc() so that the pointer members are initialized to NULL.
  98. dec = (WebPAnimDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec));
  99. if (dec == NULL) goto Error;
  100. if (dec_options != NULL) {
  101. options = *dec_options;
  102. } else {
  103. DefaultDecoderOptions(&options);
  104. }
  105. if (!ApplyDecoderOptions(&options, dec)) goto Error;
  106. dec->demux_ = WebPDemux(webp_data);
  107. if (dec->demux_ == NULL) goto Error;
  108. dec->info_.canvas_width = WebPDemuxGetI(dec->demux_, WEBP_FF_CANVAS_WIDTH);
  109. dec->info_.canvas_height = WebPDemuxGetI(dec->demux_, WEBP_FF_CANVAS_HEIGHT);
  110. dec->info_.loop_count = WebPDemuxGetI(dec->demux_, WEBP_FF_LOOP_COUNT);
  111. dec->info_.bgcolor = WebPDemuxGetI(dec->demux_, WEBP_FF_BACKGROUND_COLOR);
  112. dec->info_.frame_count = WebPDemuxGetI(dec->demux_, WEBP_FF_FRAME_COUNT);
  113. // Note: calloc() because we fill frame with zeroes as well.
  114. dec->curr_frame_ = (uint8_t*)WebPSafeCalloc(
  115. dec->info_.canvas_width * NUM_CHANNELS, dec->info_.canvas_height);
  116. if (dec->curr_frame_ == NULL) goto Error;
  117. dec->prev_frame_disposed_ = (uint8_t*)WebPSafeCalloc(
  118. dec->info_.canvas_width * NUM_CHANNELS, dec->info_.canvas_height);
  119. if (dec->prev_frame_disposed_ == NULL) goto Error;
  120. WebPAnimDecoderReset(dec);
  121. return dec;
  122. Error:
  123. WebPAnimDecoderDelete(dec);
  124. return NULL;
  125. }
  126. int WebPAnimDecoderGetInfo(const WebPAnimDecoder* dec, WebPAnimInfo* info) {
  127. if (dec == NULL || info == NULL) return 0;
  128. *info = dec->info_;
  129. return 1;
  130. }
  131. // Returns true if the frame covers the full canvas.
  132. static int IsFullFrame(int width, int height, int canvas_width,
  133. int canvas_height) {
  134. return (width == canvas_width && height == canvas_height);
  135. }
  136. // Clear the canvas to transparent.
  137. static int ZeroFillCanvas(uint8_t* buf, uint32_t canvas_width,
  138. uint32_t canvas_height) {
  139. const uint64_t size =
  140. (uint64_t)canvas_width * canvas_height * NUM_CHANNELS * sizeof(*buf);
  141. if (!CheckSizeOverflow(size)) return 0;
  142. memset(buf, 0, (size_t)size);
  143. return 1;
  144. }
  145. // Clear given frame rectangle to transparent.
  146. static void ZeroFillFrameRect(uint8_t* buf, int buf_stride, int x_offset,
  147. int y_offset, int width, int height) {
  148. int j;
  149. assert(width * NUM_CHANNELS <= buf_stride);
  150. buf += y_offset * buf_stride + x_offset * NUM_CHANNELS;
  151. for (j = 0; j < height; ++j) {
  152. memset(buf, 0, width * NUM_CHANNELS);
  153. buf += buf_stride;
  154. }
  155. }
  156. // Copy width * height pixels from 'src' to 'dst'.
  157. static int CopyCanvas(const uint8_t* src, uint8_t* dst,
  158. uint32_t width, uint32_t height) {
  159. const uint64_t size = (uint64_t)width * height * NUM_CHANNELS;
  160. if (!CheckSizeOverflow(size)) return 0;
  161. assert(src != NULL && dst != NULL);
  162. memcpy(dst, src, (size_t)size);
  163. return 1;
  164. }
  165. // Returns true if the current frame is a key-frame.
  166. static int IsKeyFrame(const WebPIterator* const curr,
  167. const WebPIterator* const prev,
  168. int prev_frame_was_key_frame,
  169. int canvas_width, int canvas_height) {
  170. if (curr->frame_num == 1) {
  171. return 1;
  172. } else if ((!curr->has_alpha || curr->blend_method == WEBP_MUX_NO_BLEND) &&
  173. IsFullFrame(curr->width, curr->height,
  174. canvas_width, canvas_height)) {
  175. return 1;
  176. } else {
  177. return (prev->dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) &&
  178. (IsFullFrame(prev->width, prev->height, canvas_width,
  179. canvas_height) ||
  180. prev_frame_was_key_frame);
  181. }
  182. }
  183. // Blend a single channel of 'src' over 'dst', given their alpha channel values.
  184. // 'src' and 'dst' are assumed to be NOT pre-multiplied by alpha.
  185. static uint8_t BlendChannelNonPremult(uint32_t src, uint8_t src_a,
  186. uint32_t dst, uint8_t dst_a,
  187. uint32_t scale, int shift) {
  188. const uint8_t src_channel = (src >> shift) & 0xff;
  189. const uint8_t dst_channel = (dst >> shift) & 0xff;
  190. const uint32_t blend_unscaled = src_channel * src_a + dst_channel * dst_a;
  191. assert(blend_unscaled < (1ULL << 32) / scale);
  192. return (blend_unscaled * scale) >> CHANNEL_SHIFT(3);
  193. }
  194. // Blend 'src' over 'dst' assuming they are NOT pre-multiplied by alpha.
  195. static uint32_t BlendPixelNonPremult(uint32_t src, uint32_t dst) {
  196. const uint8_t src_a = (src >> CHANNEL_SHIFT(3)) & 0xff;
  197. if (src_a == 0) {
  198. return dst;
  199. } else {
  200. const uint8_t dst_a = (dst >> CHANNEL_SHIFT(3)) & 0xff;
  201. // This is the approximate integer arithmetic for the actual formula:
  202. // dst_factor_a = (dst_a * (255 - src_a)) / 255.
  203. const uint8_t dst_factor_a = (dst_a * (256 - src_a)) >> 8;
  204. const uint8_t blend_a = src_a + dst_factor_a;
  205. const uint32_t scale = (1UL << 24) / blend_a;
  206. const uint8_t blend_r = BlendChannelNonPremult(
  207. src, src_a, dst, dst_factor_a, scale, CHANNEL_SHIFT(0));
  208. const uint8_t blend_g = BlendChannelNonPremult(
  209. src, src_a, dst, dst_factor_a, scale, CHANNEL_SHIFT(1));
  210. const uint8_t blend_b = BlendChannelNonPremult(
  211. src, src_a, dst, dst_factor_a, scale, CHANNEL_SHIFT(2));
  212. assert(src_a + dst_factor_a < 256);
  213. return ((uint32_t)blend_r << CHANNEL_SHIFT(0)) |
  214. ((uint32_t)blend_g << CHANNEL_SHIFT(1)) |
  215. ((uint32_t)blend_b << CHANNEL_SHIFT(2)) |
  216. ((uint32_t)blend_a << CHANNEL_SHIFT(3));
  217. }
  218. }
  219. // Blend 'num_pixels' in 'src' over 'dst' assuming they are NOT pre-multiplied
  220. // by alpha.
  221. static void BlendPixelRowNonPremult(uint32_t* const src,
  222. const uint32_t* const dst, int num_pixels) {
  223. int i;
  224. for (i = 0; i < num_pixels; ++i) {
  225. const uint8_t src_alpha = (src[i] >> CHANNEL_SHIFT(3)) & 0xff;
  226. if (src_alpha != 0xff) {
  227. src[i] = BlendPixelNonPremult(src[i], dst[i]);
  228. }
  229. }
  230. }
  231. // Individually multiply each channel in 'pix' by 'scale'.
  232. static WEBP_INLINE uint32_t ChannelwiseMultiply(uint32_t pix, uint32_t scale) {
  233. uint32_t mask = 0x00FF00FF;
  234. uint32_t rb = ((pix & mask) * scale) >> 8;
  235. uint32_t ag = ((pix >> 8) & mask) * scale;
  236. return (rb & mask) | (ag & ~mask);
  237. }
  238. // Blend 'src' over 'dst' assuming they are pre-multiplied by alpha.
  239. static uint32_t BlendPixelPremult(uint32_t src, uint32_t dst) {
  240. const uint8_t src_a = (src >> CHANNEL_SHIFT(3)) & 0xff;
  241. return src + ChannelwiseMultiply(dst, 256 - src_a);
  242. }
  243. // Blend 'num_pixels' in 'src' over 'dst' assuming they are pre-multiplied by
  244. // alpha.
  245. static void BlendPixelRowPremult(uint32_t* const src, const uint32_t* const dst,
  246. int num_pixels) {
  247. int i;
  248. for (i = 0; i < num_pixels; ++i) {
  249. const uint8_t src_alpha = (src[i] >> CHANNEL_SHIFT(3)) & 0xff;
  250. if (src_alpha != 0xff) {
  251. src[i] = BlendPixelPremult(src[i], dst[i]);
  252. }
  253. }
  254. }
  255. // Returns two ranges (<left, width> pairs) at row 'canvas_y', that belong to
  256. // 'src' but not 'dst'. A point range is empty if the corresponding width is 0.
  257. static void FindBlendRangeAtRow(const WebPIterator* const src,
  258. const WebPIterator* const dst, int canvas_y,
  259. int* const left1, int* const width1,
  260. int* const left2, int* const width2) {
  261. const int src_max_x = src->x_offset + src->width;
  262. const int dst_max_x = dst->x_offset + dst->width;
  263. const int dst_max_y = dst->y_offset + dst->height;
  264. assert(canvas_y >= src->y_offset && canvas_y < (src->y_offset + src->height));
  265. *left1 = -1;
  266. *width1 = 0;
  267. *left2 = -1;
  268. *width2 = 0;
  269. if (canvas_y < dst->y_offset || canvas_y >= dst_max_y ||
  270. src->x_offset >= dst_max_x || src_max_x <= dst->x_offset) {
  271. *left1 = src->x_offset;
  272. *width1 = src->width;
  273. return;
  274. }
  275. if (src->x_offset < dst->x_offset) {
  276. *left1 = src->x_offset;
  277. *width1 = dst->x_offset - src->x_offset;
  278. }
  279. if (src_max_x > dst_max_x) {
  280. *left2 = dst_max_x;
  281. *width2 = src_max_x - dst_max_x;
  282. }
  283. }
  284. int WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
  285. uint8_t** buf_ptr, int* timestamp_ptr) {
  286. WebPIterator iter;
  287. uint32_t width;
  288. uint32_t height;
  289. int is_key_frame;
  290. int timestamp;
  291. BlendRowFunc blend_row;
  292. if (dec == NULL || buf_ptr == NULL || timestamp_ptr == NULL) return 0;
  293. if (!WebPAnimDecoderHasMoreFrames(dec)) return 0;
  294. width = dec->info_.canvas_width;
  295. height = dec->info_.canvas_height;
  296. blend_row = dec->blend_func_;
  297. // Get compressed frame.
  298. if (!WebPDemuxGetFrame(dec->demux_, dec->next_frame_, &iter)) {
  299. return 0;
  300. }
  301. timestamp = dec->prev_frame_timestamp_ + iter.duration;
  302. // Initialize.
  303. is_key_frame = IsKeyFrame(&iter, &dec->prev_iter_,
  304. dec->prev_frame_was_keyframe_, width, height);
  305. if (is_key_frame) {
  306. if (!ZeroFillCanvas(dec->curr_frame_, width, height)) {
  307. goto Error;
  308. }
  309. } else {
  310. if (!CopyCanvas(dec->prev_frame_disposed_, dec->curr_frame_,
  311. width, height)) {
  312. goto Error;
  313. }
  314. }
  315. // Decode.
  316. {
  317. const uint8_t* in = iter.fragment.bytes;
  318. const size_t in_size = iter.fragment.size;
  319. const uint32_t stride = width * NUM_CHANNELS; // at most 25 + 2 bits
  320. const uint64_t out_offset = (uint64_t)iter.y_offset * stride +
  321. (uint64_t)iter.x_offset * NUM_CHANNELS; // 53b
  322. const uint64_t size = (uint64_t)iter.height * stride; // at most 25 + 27b
  323. WebPDecoderConfig* const config = &dec->config_;
  324. WebPRGBABuffer* const buf = &config->output.u.RGBA;
  325. if ((size_t)size != size) goto Error;
  326. buf->stride = (int)stride;
  327. buf->size = (size_t)size;
  328. buf->rgba = dec->curr_frame_ + out_offset;
  329. if (WebPDecode(in, in_size, config) != VP8_STATUS_OK) {
  330. goto Error;
  331. }
  332. }
  333. // During the decoding of current frame, we may have set some pixels to be
  334. // transparent (i.e. alpha < 255). However, the value of each of these
  335. // pixels should have been determined by blending it against the value of
  336. // that pixel in the previous frame if blending method of is WEBP_MUX_BLEND.
  337. if (iter.frame_num > 1 && iter.blend_method == WEBP_MUX_BLEND &&
  338. !is_key_frame) {
  339. if (dec->prev_iter_.dispose_method == WEBP_MUX_DISPOSE_NONE) {
  340. int y;
  341. // Blend transparent pixels with pixels in previous canvas.
  342. for (y = 0; y < iter.height; ++y) {
  343. const size_t offset =
  344. (iter.y_offset + y) * width + iter.x_offset;
  345. blend_row((uint32_t*)dec->curr_frame_ + offset,
  346. (uint32_t*)dec->prev_frame_disposed_ + offset, iter.width);
  347. }
  348. } else {
  349. int y;
  350. assert(dec->prev_iter_.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND);
  351. // We need to blend a transparent pixel with its value just after
  352. // initialization. That is, blend it with:
  353. // * Fully transparent pixel if it belongs to prevRect <-- No-op.
  354. // * The pixel in the previous canvas otherwise <-- Need alpha-blending.
  355. for (y = 0; y < iter.height; ++y) {
  356. const int canvas_y = iter.y_offset + y;
  357. int left1, width1, left2, width2;
  358. FindBlendRangeAtRow(&iter, &dec->prev_iter_, canvas_y, &left1, &width1,
  359. &left2, &width2);
  360. if (width1 > 0) {
  361. const size_t offset1 = canvas_y * width + left1;
  362. blend_row((uint32_t*)dec->curr_frame_ + offset1,
  363. (uint32_t*)dec->prev_frame_disposed_ + offset1, width1);
  364. }
  365. if (width2 > 0) {
  366. const size_t offset2 = canvas_y * width + left2;
  367. blend_row((uint32_t*)dec->curr_frame_ + offset2,
  368. (uint32_t*)dec->prev_frame_disposed_ + offset2, width2);
  369. }
  370. }
  371. }
  372. }
  373. // Update info of the previous frame and dispose it for the next iteration.
  374. dec->prev_frame_timestamp_ = timestamp;
  375. WebPDemuxReleaseIterator(&dec->prev_iter_);
  376. dec->prev_iter_ = iter;
  377. dec->prev_frame_was_keyframe_ = is_key_frame;
  378. CopyCanvas(dec->curr_frame_, dec->prev_frame_disposed_, width, height);
  379. if (dec->prev_iter_.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) {
  380. ZeroFillFrameRect(dec->prev_frame_disposed_, width * NUM_CHANNELS,
  381. dec->prev_iter_.x_offset, dec->prev_iter_.y_offset,
  382. dec->prev_iter_.width, dec->prev_iter_.height);
  383. }
  384. ++dec->next_frame_;
  385. // All OK, fill in the values.
  386. *buf_ptr = dec->curr_frame_;
  387. *timestamp_ptr = timestamp;
  388. return 1;
  389. Error:
  390. WebPDemuxReleaseIterator(&iter);
  391. return 0;
  392. }
  393. int WebPAnimDecoderHasMoreFrames(const WebPAnimDecoder* dec) {
  394. if (dec == NULL) return 0;
  395. return (dec->next_frame_ <= (int)dec->info_.frame_count);
  396. }
  397. void WebPAnimDecoderReset(WebPAnimDecoder* dec) {
  398. if (dec != NULL) {
  399. dec->prev_frame_timestamp_ = 0;
  400. WebPDemuxReleaseIterator(&dec->prev_iter_);
  401. memset(&dec->prev_iter_, 0, sizeof(dec->prev_iter_));
  402. dec->prev_frame_was_keyframe_ = 0;
  403. dec->next_frame_ = 1;
  404. }
  405. }
  406. const WebPDemuxer* WebPAnimDecoderGetDemuxer(const WebPAnimDecoder* dec) {
  407. if (dec == NULL) return NULL;
  408. return dec->demux_;
  409. }
  410. void WebPAnimDecoderDelete(WebPAnimDecoder* dec) {
  411. if (dec != NULL) {
  412. WebPDemuxReleaseIterator(&dec->prev_iter_);
  413. WebPDemuxDelete(dec->demux_);
  414. WebPSafeFree(dec->curr_frame_);
  415. WebPSafeFree(dec->prev_frame_disposed_);
  416. WebPSafeFree(dec);
  417. }
  418. }