Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(17)

Side by Side Diff: third_party/libwebp/demux/demux.c

Issue 22802020: libwebp: upstream animation cherry-picks (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2012 Google Inc. All Rights Reserved. 1 // Copyright 2012 Google Inc. All Rights Reserved.
2 // 2 //
3 // Use of this source code is governed by a BSD-style license 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 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 5 // tree. An additional intellectual property rights grant can be found
6 // in the file PATENTS. All contributing project authors may 6 // in the file PATENTS. All contributing project authors may
7 // be found in the AUTHORS file in the root of the source tree. 7 // be found in the AUTHORS file in the root of the source tree.
8 // ----------------------------------------------------------------------------- 8 // -----------------------------------------------------------------------------
9 // 9 //
10 // WebP container demux. 10 // WebP container demux.
(...skipping 29 matching lines...) Expand all
40 } MemBuffer; 40 } MemBuffer;
41 41
42 typedef struct { 42 typedef struct {
43 size_t offset_; 43 size_t offset_;
44 size_t size_; 44 size_t size_;
45 } ChunkData; 45 } ChunkData;
46 46
47 typedef struct Frame { 47 typedef struct Frame {
48 int x_offset_, y_offset_; 48 int x_offset_, y_offset_;
49 int width_, height_; 49 int width_, height_;
50 int has_alpha_;
50 int duration_; 51 int duration_;
51 WebPMuxAnimDispose dispose_method_; 52 WebPMuxAnimDispose dispose_method_;
53 WebPMuxAnimBlend blend_method_;
52 int is_fragment_; // this is a frame fragment (and not a full frame). 54 int is_fragment_; // this is a frame fragment (and not a full frame).
53 int frame_num_; // the referent frame number for use in assembling fragments. 55 int frame_num_; // the referent frame number for use in assembling fragments.
54 int complete_; // img_components_ contains a full image. 56 int complete_; // img_components_ contains a full image.
55 ChunkData img_components_[2]; // 0=VP8{,L} 1=ALPH 57 ChunkData img_components_[2]; // 0=VP8{,L} 1=ALPH
56 struct Frame* next_; 58 struct Frame* next_;
57 } Frame; 59 } Frame;
58 60
59 typedef struct Chunk { 61 typedef struct Chunk {
60 ChunkData data_; 62 ChunkData data_;
61 struct Chunk* next_; 63 struct Chunk* next_;
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
189 const Frame* const last_frame = *dmux->frames_tail_; 191 const Frame* const last_frame = *dmux->frames_tail_;
190 if (last_frame != NULL && !last_frame->complete_) return 0; 192 if (last_frame != NULL && !last_frame->complete_) return 0;
191 193
192 *dmux->frames_tail_ = frame; 194 *dmux->frames_tail_ = frame;
193 frame->next_ = NULL; 195 frame->next_ = NULL;
194 dmux->frames_tail_ = &frame->next_; 196 dmux->frames_tail_ = &frame->next_;
195 return 1; 197 return 1;
196 } 198 }
197 199
198 // Store image bearing chunks to 'frame'. 200 // Store image bearing chunks to 'frame'.
199 // If 'has_vp8l_alpha' is not NULL, it will be set to true if the frame is a
200 // lossless image with alpha.
201 static ParseStatus StoreFrame(int frame_num, uint32_t min_size, 201 static ParseStatus StoreFrame(int frame_num, uint32_t min_size,
202 MemBuffer* const mem, Frame* const frame, 202 MemBuffer* const mem, Frame* const frame) {
203 int* const has_vp8l_alpha) {
204 int alpha_chunks = 0; 203 int alpha_chunks = 0;
205 int image_chunks = 0; 204 int image_chunks = 0;
206 int done = (MemDataSize(mem) < min_size); 205 int done = (MemDataSize(mem) < min_size);
207 ParseStatus status = PARSE_OK; 206 ParseStatus status = PARSE_OK;
208 207
209 if (has_vp8l_alpha != NULL) *has_vp8l_alpha = 0; // Default.
210
211 if (done) return PARSE_NEED_MORE_DATA; 208 if (done) return PARSE_NEED_MORE_DATA;
212 209
213 do { 210 do {
214 const size_t chunk_start_offset = mem->start_; 211 const size_t chunk_start_offset = mem->start_;
215 const uint32_t fourcc = ReadLE32(mem); 212 const uint32_t fourcc = ReadLE32(mem);
216 const uint32_t payload_size = ReadLE32(mem); 213 const uint32_t payload_size = ReadLE32(mem);
217 const uint32_t payload_size_padded = payload_size + (payload_size & 1); 214 const uint32_t payload_size_padded = payload_size + (payload_size & 1);
218 const size_t payload_available = (payload_size_padded > MemDataSize(mem)) 215 const size_t payload_available = (payload_size_padded > MemDataSize(mem))
219 ? MemDataSize(mem) : payload_size_padded; 216 ? MemDataSize(mem) : payload_size_padded;
220 const size_t chunk_size = CHUNK_HEADER_SIZE + payload_available; 217 const size_t chunk_size = CHUNK_HEADER_SIZE + payload_available;
221 218
222 if (payload_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR; 219 if (payload_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR;
223 if (SizeIsInvalid(mem, payload_size_padded)) return PARSE_ERROR; 220 if (SizeIsInvalid(mem, payload_size_padded)) return PARSE_ERROR;
224 if (payload_size_padded > MemDataSize(mem)) status = PARSE_NEED_MORE_DATA; 221 if (payload_size_padded > MemDataSize(mem)) status = PARSE_NEED_MORE_DATA;
225 222
226 switch (fourcc) { 223 switch (fourcc) {
227 case MKFOURCC('A', 'L', 'P', 'H'): 224 case MKFOURCC('A', 'L', 'P', 'H'):
228 if (alpha_chunks == 0) { 225 if (alpha_chunks == 0) {
229 ++alpha_chunks; 226 ++alpha_chunks;
230 frame->img_components_[1].offset_ = chunk_start_offset; 227 frame->img_components_[1].offset_ = chunk_start_offset;
231 frame->img_components_[1].size_ = chunk_size; 228 frame->img_components_[1].size_ = chunk_size;
229 frame->has_alpha_ = 1;
232 frame->frame_num_ = frame_num; 230 frame->frame_num_ = frame_num;
233 Skip(mem, payload_available); 231 Skip(mem, payload_available);
234 } else { 232 } else {
235 goto Done; 233 goto Done;
236 } 234 }
237 break; 235 break;
238 case MKFOURCC('V', 'P', '8', 'L'): 236 case MKFOURCC('V', 'P', '8', 'L'):
239 if (alpha_chunks > 0) return PARSE_ERROR; // VP8L has its own alpha 237 if (alpha_chunks > 0) return PARSE_ERROR; // VP8L has its own alpha
240 // fall through 238 // fall through
241 case MKFOURCC('V', 'P', '8', ' '): 239 case MKFOURCC('V', 'P', '8', ' '):
242 if (image_chunks == 0) { 240 if (image_chunks == 0) {
243 // Extract the bitstream features, tolerating failures when the data 241 // Extract the bitstream features, tolerating failures when the data
244 // is incomplete. 242 // is incomplete.
245 WebPBitstreamFeatures features; 243 WebPBitstreamFeatures features;
246 const VP8StatusCode vp8_status = 244 const VP8StatusCode vp8_status =
247 WebPGetFeatures(mem->buf_ + chunk_start_offset, chunk_size, 245 WebPGetFeatures(mem->buf_ + chunk_start_offset, chunk_size,
248 &features); 246 &features);
249 if (status == PARSE_NEED_MORE_DATA && 247 if (status == PARSE_NEED_MORE_DATA &&
250 vp8_status == VP8_STATUS_NOT_ENOUGH_DATA) { 248 vp8_status == VP8_STATUS_NOT_ENOUGH_DATA) {
251 return PARSE_NEED_MORE_DATA; 249 return PARSE_NEED_MORE_DATA;
252 } else if (vp8_status != VP8_STATUS_OK) { 250 } else if (vp8_status != VP8_STATUS_OK) {
253 // We have enough data, and yet WebPGetFeatures() failed. 251 // We have enough data, and yet WebPGetFeatures() failed.
254 return PARSE_ERROR; 252 return PARSE_ERROR;
255 } 253 }
256 ++image_chunks; 254 ++image_chunks;
257 frame->img_components_[0].offset_ = chunk_start_offset; 255 frame->img_components_[0].offset_ = chunk_start_offset;
258 frame->img_components_[0].size_ = chunk_size; 256 frame->img_components_[0].size_ = chunk_size;
259 frame->width_ = features.width; 257 frame->width_ = features.width;
260 frame->height_ = features.height; 258 frame->height_ = features.height;
261 if (has_vp8l_alpha != NULL) *has_vp8l_alpha = features.has_alpha; 259 frame->has_alpha_ |= features.has_alpha;
fbarchard 2013/08/21 02:00:13 if you dont check the pointer, to enable alpha, th
urvang (Google) 2013/08/21 02:16:51 Nope. StoreFrame() is a static method, so 'frame'
262 frame->frame_num_ = frame_num; 260 frame->frame_num_ = frame_num;
263 frame->complete_ = (status == PARSE_OK); 261 frame->complete_ = (status == PARSE_OK);
264 Skip(mem, payload_available); 262 Skip(mem, payload_available);
265 } else { 263 } else {
266 goto Done; 264 goto Done;
267 } 265 }
268 break; 266 break;
269 Done: 267 Done:
270 default: 268 default:
271 // Restore fourcc/size when moving up one level in parsing. 269 // Restore fourcc/size when moving up one level in parsing.
(...skipping 27 matching lines...) Expand all
299 return (*frame == NULL) ? PARSE_ERROR : PARSE_OK; 297 return (*frame == NULL) ? PARSE_ERROR : PARSE_OK;
300 } 298 }
301 299
302 // Parse a 'ANMF' chunk and any image bearing chunks that immediately follow. 300 // Parse a 'ANMF' chunk and any image bearing chunks that immediately follow.
303 // 'frame_chunk_size' is the previously validated, padded chunk size. 301 // 'frame_chunk_size' is the previously validated, padded chunk size.
304 static ParseStatus ParseAnimationFrame( 302 static ParseStatus ParseAnimationFrame(
305 WebPDemuxer* const dmux, uint32_t frame_chunk_size) { 303 WebPDemuxer* const dmux, uint32_t frame_chunk_size) {
306 const int has_frames = !!(dmux->feature_flags_ & ANIMATION_FLAG); 304 const int has_frames = !!(dmux->feature_flags_ & ANIMATION_FLAG);
307 const uint32_t anmf_payload_size = frame_chunk_size - ANMF_CHUNK_SIZE; 305 const uint32_t anmf_payload_size = frame_chunk_size - ANMF_CHUNK_SIZE;
308 int added_frame = 0; 306 int added_frame = 0;
307 int bits;
309 MemBuffer* const mem = &dmux->mem_; 308 MemBuffer* const mem = &dmux->mem_;
310 Frame* frame; 309 Frame* frame;
311 ParseStatus status = 310 ParseStatus status =
312 NewFrame(mem, ANMF_CHUNK_SIZE, frame_chunk_size, &frame); 311 NewFrame(mem, ANMF_CHUNK_SIZE, frame_chunk_size, &frame);
313 if (status != PARSE_OK) return status; 312 if (status != PARSE_OK) return status;
314 313
315 frame->x_offset_ = 2 * ReadLE24s(mem); 314 frame->x_offset_ = 2 * ReadLE24s(mem);
316 frame->y_offset_ = 2 * ReadLE24s(mem); 315 frame->y_offset_ = 2 * ReadLE24s(mem);
317 frame->width_ = 1 + ReadLE24s(mem); 316 frame->width_ = 1 + ReadLE24s(mem);
318 frame->height_ = 1 + ReadLE24s(mem); 317 frame->height_ = 1 + ReadLE24s(mem);
319 frame->duration_ = ReadLE24s(mem); 318 frame->duration_ = ReadLE24s(mem);
320 frame->dispose_method_ = (WebPMuxAnimDispose)(ReadByte(mem) & 1); 319 bits = ReadByte(mem);
320 frame->dispose_method_ =
321 (bits & 1) ? WEBP_MUX_DISPOSE_BACKGROUND : WEBP_MUX_DISPOSE_NONE;
322 frame->blend_method_ = (bits & 2) ? WEBP_MUX_NO_BLEND : WEBP_MUX_BLEND;
321 if (frame->width_ * (uint64_t)frame->height_ >= MAX_IMAGE_AREA) { 323 if (frame->width_ * (uint64_t)frame->height_ >= MAX_IMAGE_AREA) {
322 free(frame); 324 free(frame);
323 return PARSE_ERROR; 325 return PARSE_ERROR;
324 } 326 }
325 327
326 // Store a frame only if the animation flag is set there is some data for 328 // Store a frame only if the animation flag is set there is some data for
327 // this frame is available. 329 // this frame is available.
328 status = StoreFrame(dmux->num_frames_ + 1, anmf_payload_size, mem, frame, 330 status = StoreFrame(dmux->num_frames_ + 1, anmf_payload_size, mem, frame);
329 NULL);
330 if (status != PARSE_ERROR && has_frames && frame->frame_num_ > 0) { 331 if (status != PARSE_ERROR && has_frames && frame->frame_num_ > 0) {
331 added_frame = AddFrame(dmux, frame); 332 added_frame = AddFrame(dmux, frame);
332 if (added_frame) { 333 if (added_frame) {
333 ++dmux->num_frames_; 334 ++dmux->num_frames_;
334 } else { 335 } else {
335 status = PARSE_ERROR; 336 status = PARSE_ERROR;
336 } 337 }
337 } 338 }
338 339
339 if (!added_frame) free(frame); 340 if (!added_frame) free(frame);
(...skipping 14 matching lines...) Expand all
354 ParseStatus status = 355 ParseStatus status =
355 NewFrame(mem, FRGM_CHUNK_SIZE, fragment_chunk_size, &frame); 356 NewFrame(mem, FRGM_CHUNK_SIZE, fragment_chunk_size, &frame);
356 if (status != PARSE_OK) return status; 357 if (status != PARSE_OK) return status;
357 358
358 frame->is_fragment_ = 1; 359 frame->is_fragment_ = 1;
359 frame->x_offset_ = 2 * ReadLE24s(mem); 360 frame->x_offset_ = 2 * ReadLE24s(mem);
360 frame->y_offset_ = 2 * ReadLE24s(mem); 361 frame->y_offset_ = 2 * ReadLE24s(mem);
361 362
362 // Store a fragment only if the fragments flag is set there is some data for 363 // Store a fragment only if the fragments flag is set there is some data for
363 // this fragment is available. 364 // this fragment is available.
364 status = StoreFrame(frame_num, frgm_payload_size, mem, frame, NULL); 365 status = StoreFrame(frame_num, frgm_payload_size, mem, frame);
365 if (status != PARSE_ERROR && has_fragments && frame->frame_num_ > 0) { 366 if (status != PARSE_ERROR && has_fragments && frame->frame_num_ > 0) {
366 added_fragment = AddFrame(dmux, frame); 367 added_fragment = AddFrame(dmux, frame);
367 if (!added_fragment) { 368 if (!added_fragment) {
368 status = PARSE_ERROR; 369 status = PARSE_ERROR;
369 } else { 370 } else {
370 dmux->num_frames_ = 1; 371 dmux->num_frames_ = 1;
371 } 372 }
372 } 373 }
373 374
374 if (!added_fragment) free(frame); 375 if (!added_fragment) free(frame);
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
417 418
418 Skip(mem, RIFF_HEADER_SIZE); 419 Skip(mem, RIFF_HEADER_SIZE);
419 return 1; 420 return 1;
420 } 421 }
421 422
422 static ParseStatus ParseSingleImage(WebPDemuxer* const dmux) { 423 static ParseStatus ParseSingleImage(WebPDemuxer* const dmux) {
423 const size_t min_size = CHUNK_HEADER_SIZE; 424 const size_t min_size = CHUNK_HEADER_SIZE;
424 MemBuffer* const mem = &dmux->mem_; 425 MemBuffer* const mem = &dmux->mem_;
425 Frame* frame; 426 Frame* frame;
426 ParseStatus status; 427 ParseStatus status;
427 int has_vp8l_alpha = 0; // Frame contains a lossless image with alpha.
428 428
429 if (dmux->frames_ != NULL) return PARSE_ERROR; 429 if (dmux->frames_ != NULL) return PARSE_ERROR;
430 if (SizeIsInvalid(mem, min_size)) return PARSE_ERROR; 430 if (SizeIsInvalid(mem, min_size)) return PARSE_ERROR;
431 if (MemDataSize(mem) < min_size) return PARSE_NEED_MORE_DATA; 431 if (MemDataSize(mem) < min_size) return PARSE_NEED_MORE_DATA;
432 432
433 frame = (Frame*)calloc(1, sizeof(*frame)); 433 frame = (Frame*)calloc(1, sizeof(*frame));
434 if (frame == NULL) return PARSE_ERROR; 434 if (frame == NULL) return PARSE_ERROR;
435 435
436 // For the single image case we allow parsing of a partial frame, but we need 436 // For the single image case we allow parsing of a partial frame, but we need
437 // at least CHUNK_HEADER_SIZE for parsing. 437 // at least CHUNK_HEADER_SIZE for parsing.
438 status = StoreFrame(1, CHUNK_HEADER_SIZE, &dmux->mem_, frame, 438 status = StoreFrame(1, CHUNK_HEADER_SIZE, &dmux->mem_, frame);
439 &has_vp8l_alpha);
440 if (status != PARSE_ERROR) { 439 if (status != PARSE_ERROR) {
441 const int has_alpha = !!(dmux->feature_flags_ & ALPHA_FLAG); 440 const int has_alpha = !!(dmux->feature_flags_ & ALPHA_FLAG);
442 // Clear any alpha when the alpha flag is missing. 441 // Clear any alpha when the alpha flag is missing.
443 if (!has_alpha && frame->img_components_[1].size_ > 0) { 442 if (!has_alpha && frame->img_components_[1].size_ > 0) {
444 frame->img_components_[1].offset_ = 0; 443 frame->img_components_[1].offset_ = 0;
445 frame->img_components_[1].size_ = 0; 444 frame->img_components_[1].size_ = 0;
445 frame->has_alpha_ = 0;
446 } 446 }
447 447
448 // Use the frame width/height as the canvas values for non-vp8x files. 448 // Use the frame width/height as the canvas values for non-vp8x files.
449 // Also, set ALPHA_FLAG if this is a lossless image with alpha. 449 // Also, set ALPHA_FLAG if this is a lossless image with alpha.
450 if (!dmux->is_ext_format_ && frame->width_ > 0 && frame->height_ > 0) { 450 if (!dmux->is_ext_format_ && frame->width_ > 0 && frame->height_ > 0) {
451 dmux->state_ = WEBP_DEMUX_PARSED_HEADER; 451 dmux->state_ = WEBP_DEMUX_PARSED_HEADER;
452 dmux->canvas_width_ = frame->width_; 452 dmux->canvas_width_ = frame->width_;
453 dmux->canvas_height_ = frame->height_; 453 dmux->canvas_height_ = frame->height_;
454 dmux->feature_flags_ |= has_vp8l_alpha ? ALPHA_FLAG : 0; 454 dmux->feature_flags_ |= frame->has_alpha_ ? ALPHA_FLAG : 0;
455 } 455 }
456 AddFrame(dmux, frame); 456 AddFrame(dmux, frame);
457 dmux->num_frames_ = 1; 457 dmux->num_frames_ = 1;
458 } else { 458 } else {
459 free(frame); 459 free(frame);
460 } 460 }
461 461
462 return status; 462 return status;
463 } 463 }
464 464
(...skipping 364 matching lines...) Expand 10 before | Expand all | Expand 10 after
829 assert(first_frame != NULL); 829 assert(first_frame != NULL);
830 830
831 iter->frame_num = first_frame->frame_num_; 831 iter->frame_num = first_frame->frame_num_;
832 iter->num_frames = dmux->num_frames_; 832 iter->num_frames = dmux->num_frames_;
833 iter->fragment_num = fragment_num; 833 iter->fragment_num = fragment_num;
834 iter->num_fragments = num_fragments; 834 iter->num_fragments = num_fragments;
835 iter->x_offset = fragment->x_offset_; 835 iter->x_offset = fragment->x_offset_;
836 iter->y_offset = fragment->y_offset_; 836 iter->y_offset = fragment->y_offset_;
837 iter->width = fragment->width_; 837 iter->width = fragment->width_;
838 iter->height = fragment->height_; 838 iter->height = fragment->height_;
839 iter->has_alpha = fragment->has_alpha_;
839 iter->duration = fragment->duration_; 840 iter->duration = fragment->duration_;
840 iter->dispose_method = fragment->dispose_method_; 841 iter->dispose_method = fragment->dispose_method_;
842 iter->blend_method = fragment->blend_method_;
841 iter->complete = fragment->complete_; 843 iter->complete = fragment->complete_;
842 iter->fragment.bytes = payload; 844 iter->fragment.bytes = payload;
843 iter->fragment.size = payload_size; 845 iter->fragment.size = payload_size;
844 // TODO(jzern): adjust offsets for 'FRGM's embedded in 'ANMF's 846 // TODO(jzern): adjust offsets for 'FRGM's embedded in 'ANMF's
845 return 1; 847 return 1;
846 } 848 }
847 849
848 static int SetFrame(int frame_num, WebPIterator* const iter) { 850 static int SetFrame(int frame_num, WebPIterator* const iter) {
849 const Frame* frame; 851 const Frame* frame;
850 const WebPDemuxer* const dmux = (WebPDemuxer*)iter->private_; 852 const WebPDemuxer* const dmux = (WebPDemuxer*)iter->private_;
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
969 return 0; 971 return 0;
970 } 972 }
971 973
972 void WebPDemuxReleaseChunkIterator(WebPChunkIterator* iter) { 974 void WebPDemuxReleaseChunkIterator(WebPChunkIterator* iter) {
973 (void)iter; 975 (void)iter;
974 } 976 }
975 977
976 #if defined(__cplusplus) || defined(c_plusplus) 978 #if defined(__cplusplus) || defined(c_plusplus)
977 } // extern "C" 979 } // extern "C"
978 #endif 980 #endif
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698