@@ -86,7 +86,6 @@ @implementation SDWebPCoderFrame
8686@implementation SDImageWebPCoder {
8787 WebPIDecoder *_idec;
8888 WebPDemuxer *_demux;
89- WebPData *_webpdata; // Copied for progressive animation demuxer
9089 NSData *_imageData;
9190 CGFloat _scale;
9291 NSUInteger _loopCount;
@@ -114,10 +113,6 @@ - (void)dealloc {
114113 WebPDemuxDelete (_demux);
115114 _demux = NULL ;
116115 }
117- if (_webpdata) {
118- WebPDataClear (_webpdata);
119- _webpdata = NULL ;
120- }
121116 if (_canvas) {
122117 CGContextRelease (_canvas);
123118 _canvas = NULL ;
@@ -305,41 +300,36 @@ - (void)updateIncrementalData:(NSData *)data finished:(BOOL)finished {
305300 if (_finished) {
306301 return ;
307302 }
308- _imageData = data;
309303 _finished = finished;
310- if (!_demux) {
311- VP8StatusCode status = WebPIUpdate (_idec, data.bytes , data.length );
312- if (status == VP8_STATUS_OK || status == VP8_STATUS_SUSPENDED) {
304+ // check whether we can detect Animated WebP or Static WebP, they need different codec (Demuxer or IDecoder)
305+ if (!_hasAnimation) {
306+ _imageData = [data copy ];
307+ VP8StatusCode status = WebPIUpdate (_idec, _imageData.bytes , _imageData.length );
308+ // For Static WebP, all things done.
309+ // For Animated WebP (currently use `VP8_STATUS_UNSUPPORTED_FEATURE` to check), continue to create demuxer
310+ if (status != VP8_STATUS_UNSUPPORTED_FEATURE) {
313311 return ;
314312 }
315- // This case may be Animated WebP progressive decode
316- if (status == VP8_STATUS_UNSUPPORTED_FEATURE) {
317- WebPDemuxState state;
318- WebPData tmpData;
319- WebPDataInit (&tmpData);
320- tmpData.bytes = data.bytes ;
321- tmpData.size = data.length ;
322- // Copy to avoid the NSData dealloc and VP8 internal retain the pointer
323- _webpdata = malloc (sizeof (WebPData));
324- WebPDataCopy (&tmpData, _webpdata);
325- _demux = WebPDemuxPartial (_webpdata, &state);
326- }
327- } else {
328- // libwebp current have no API to update demuxer, so we always delete and recreate demuxer
313+ _hasAnimation = YES ;
314+ }
315+ // libwebp current have no API to update demuxer, so we always delete and recreate demuxer
316+ // Use lock to avoid progressive animation decoding thread safe issue
317+ SD_LOCK (_lock);
318+ if (_demux) {
319+ // next line `_imageData = nil` ARC will release the raw buffer, but need release the demuxer firstly because libwebp don't use retain/release rule
329320 WebPDemuxDelete (_demux);
330321 _demux = NULL ;
331- WebPDemuxState state;
332- WebPData tmpData;
333- WebPDataInit (&tmpData);
334- tmpData.bytes = data.bytes ;
335- tmpData.size = data.length ;
336- // Copy to avoid the NSData dealloc and VP8 internal retain the pointer
337- WebPDataClear (_webpdata);
338- WebPDataCopy (&tmpData, _webpdata);
339- _demux = WebPDemuxPartial (_webpdata, &state);
340322 }
323+ _imageData = [data copy ];
324+ WebPData webpData;
325+ WebPDataInit (&webpData);
326+ webpData.bytes = _imageData.bytes ;
327+ webpData.size = _imageData.length ;
328+ WebPDemuxState state;
329+ _demux = WebPDemuxPartial (&webpData, &state);
330+ SD_UNLOCK (_lock);
341331
342- if (_demux) {
332+ if (_demux && state != WEBP_DEMUX_PARSE_ERROR ) {
343333 [self scanAndCheckFramesValidWithDemuxer: _demux];
344334 }
345335}
0 commit comments