anim_decode.c 16 KB

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