GithubHelp home page GithubHelp logo

Comments (5)

koudelka avatar koudelka commented on June 10, 2024

I toyed around with the implementation below, using a dispatch group, it worked really well up until I hit the problem of collecting the frames in-order. I tried using NSMutableArray's insertObject:atIndex:, but it has some really weird behavior when you insert out of order (which I think would be necessary for multi-threaded operation).


+ (id)imageWithData:(NSData *)data
{
    CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)(data), NULL);
    if (!imageSource) {
        return nil;
    }
    NSUInteger numberOfFrames = CGImageSourceGetCount(imageSource);
    if (!UTTypeConformsTo(CGImageSourceGetType(imageSource), kUTTypeGIF) || numberOfFrames == 1) {
        CFRelease(imageSource);
        return [UIImage imageWithData:data];
    }

    NSDictionary *imageProperties = CFBridgingRelease(CGImageSourceCopyProperties(imageSource, NULL));
    NSDictionary *GIFProperties = [imageProperties objectForKey:(NSString *)kCGImagePropertyGIFDictionary];

    OLImage *animatedImage = [[OLImage  alloc] init];
    animatedImage.images = [NSMutableArray arrayWithCapacity:numberOfFrames];
    animatedImage.frameDurations = (NSTimeInterval *) malloc(numberOfFrames  * sizeof(NSTimeInterval));
    animatedImage.totalDuration = 0.0f;
    animatedImage.loopCount = [GIFProperties[(NSString *)kCGImagePropertyGIFLoopCount] unsignedIntegerValue];

    dispatch_group_t dispatch_group = dispatch_group_create();

    for (NSUInteger i = 0; i < numberOfFrames; ++i)
        dispatch_group_async(dispatch_group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            //Implement as Browsers do, to ensure UX.
            //See: http://nullsleep.tumblr.com/post/16524517190/animated-gif-minimum-frame-delay-browser-compatibility
            //See also: http://blogs.msdn.com/b/ieinternals/archive/2010/06/08/animated-gifs-slow-down-to-under-20-frames-per-second.aspx
            double proposedFrameDuration = CGImageSourceGetGifFrameDelay(imageSource, i);
#ifndef OLExactGIFRepresentation
            proposedFrameDuration = (proposedFrameDuration >= 0.02) ? proposedFrameDuration : 0.10f;
#endif
            animatedImage.frameDurations[i] = proposedFrameDuration;
            CGImageRef theImage = CGImageSourceCreateImageAtIndex(imageSource, i, NULL);
            [animatedImage.images insertObject:[UIImage imageWithCGImage:theImage] atIndex:i];
            CFRelease(theImage);
            animatedImage.totalDuration += animatedImage.frameDurations[i];
      });

    dispatch_group_wait(dispatch_group, DISPATCH_TIME_FOREVER);

    CFRelease(imageSource);
    return animatedImage;
}

Using just addObject: (and not caring about frame ordering), I was seeing about a 10% speedup, but it varied quite a bit. I suspect that the amount of work per dispatch is low enough that the overhead eats into the gains. A better solution might be to dispatch a certain percentage of frames instead (but that still leaves the ordering problem).

from olimageview.

koudelka avatar koudelka commented on June 10, 2024

So I've fixed the weirdness with insertObject:atIndex: by sticking a null in its place and removing it later. But this solution is slower that the single-threaded one. :(

+ (id)imageWithData:(NSData *)data
{
    CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)(data), NULL);
    if (!imageSource) {
        return nil;
    }
    NSUInteger numberOfFrames = CGImageSourceGetCount(imageSource);
    if (!UTTypeConformsTo(CGImageSourceGetType(imageSource), kUTTypeGIF) || numberOfFrames == 1) {
        CFRelease(imageSource);
        return [UIImage imageWithData:data];
    }

    NSDictionary *imageProperties = CFBridgingRelease(CGImageSourceCopyProperties(imageSource, NULL));
    NSDictionary *GIFProperties = [imageProperties objectForKey:(NSString *)kCGImagePropertyGIFDictionary];

    OLImage *animatedImage = [[OLImage  alloc] init];
    animatedImage.images = [NSMutableArray arrayWithCapacity:numberOfFrames];
    animatedImage.frameDurations = (NSTimeInterval *) malloc(numberOfFrames  * sizeof(NSTimeInterval));
    animatedImage.totalDuration = 0.0f;
    animatedImage.loopCount = [GIFProperties[(NSString *)kCGImagePropertyGIFLoopCount] unsignedIntegerValue];

    dispatch_group_t dispatch_group = dispatch_group_create();

    for (NSUInteger i = 0; i < numberOfFrames; ++i)
        [animatedImage.images addObject:[NSNull null]];

    for (NSUInteger i = 0; i < numberOfFrames; ++i)
        dispatch_group_async(dispatch_group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            //Implement as Browsers do, to ensure UX.
            //See: http://nullsleep.tumblr.com/post/16524517190/animated-gif-minimum-frame-delay-browser-compatibility
            //See also: http://blogs.msdn.com/b/ieinternals/archive/2010/06/08/animated-gifs-slow-down-to-under-20-frames-per-second.aspx
            double proposedFrameDuration = CGImageSourceGetGifFrameDelay(imageSource, i);
#ifndef OLExactGIFRepresentation
            proposedFrameDuration = (proposedFrameDuration >= 0.02) ? proposedFrameDuration : 0.10f;
#endif
            animatedImage.frameDurations[i] = proposedFrameDuration;
            CGImageRef theImage = CGImageSourceCreateImageAtIndex(imageSource, i, NULL);
            [animatedImage.images replaceObjectAtIndex:i withObject:[UIImage imageWithCGImage:theImage]];
            CFRelease(theImage);
            animatedImage.totalDuration += animatedImage.frameDurations[i];
      });

    dispatch_group_wait(dispatch_group, DISPATCH_TIME_FOREVER);

    CFRelease(imageSource);
    return animatedImage;
}

from olimageview.

dtorres avatar dtorres commented on June 10, 2024

Hey Michael,
Awesome that you took a look at this but is a hard for me to identify your improvements if you post your changes here.

Can you create a fork a commit the changes there so it's easier for me to read it and help you on it
And also it will be easier to merge the changes after 👍

from olimageview.

koudelka avatar koudelka commented on June 10, 2024

Hey Diego,

You can check out the changes on my fork, in the "multithreaded" branch: https://github.com/koudelka/OLImageView/commits/multithreaded

I didn't submit a pull request as it looks like my solution is actually slower than the singlethread solution. The dispatch overhead seems to be greater than the savings of having multiple threads decode the frames. :(

from olimageview.

dtorres avatar dtorres commented on June 10, 2024

Since multithreading seems slower than the current solution, i'm closing this for now.
Would be nice to reevaluate in the future

from olimageview.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.