Skip to content

Commit 20ab7d2

Browse files
authored
Merge pull request #41 from SDWebImage/performance_avoid_copy_progressive_data_and_use_lock
Fix the potential buffer crash issue during progressive animated webp decoding, and avoid extra copy for partial image data
2 parents 75af1fa + 878d64e commit 20ab7d2

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)