Skip to content

Commit 878d64e

Browse files
committed
Use lock and copy the NSData before recreate the temp demuxer, avoid the extra copy for most cases, and use lock during the demuxer creation to avoid thread-safe issue
1 parent 92e55d4 commit 878d64e

File tree

1 file changed

+23
-33
lines changed

1 file changed

+23
-33
lines changed

SDWebImageWebPCoder/Classes/SDImageWebPCoder.m

Lines changed: 23 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)