Search code examples
objective-ccocoaquicktimegrand-central-dispatch

How can I stop QTMovie from freezing the UI of my app?


So I'm trying to take a variable size (anywhere from a few MBs to more than a GB) QTMovie object and use writeToFile:withAttributes: to export it to disk. As this takes a long time and locks up the UI, I decided to put it on a different thread using Grand Central Dispatch.

As far as I can tell, this works perfectly fine, except using writeToFile:withAttributes: still locks up the app. It does export the file, but you can't do anything with the UI until it's finished.

I've looked through all the docs on using multiple threads with QTKit, and various places on Google, but nothing I've tried seems to work.

Following is the code that seems to be having the trouble:

[movie detachFromCurrentThread];

dispatch_queue_t combineQueue = dispatch_queue_create("com.Combinate.movieCombineQueue", NULL);

dispatch_async(combineQueue, ^{

    [QTMovie enterQTKitOnThreadDisablingThreadSafetyProtection];
    [movie attachToCurrentThread];
    [movie writeToFile:filepath withAttributes:exportAttributes];

    [movie detachFromCurrentThread];
    [QTMovie exitQTKitOnThread];

    dispatch_async(dispatch_get_main_queue(), ^{
        [movie attachToCurrentThread];
        [self finishedCombiningAudioFiles:(QTMovie *)movie];
    });

});

dispatch_release(combineQueue);

Solution

  • So I've been trying to do movie writing on a background thread also, and I used the sample code Apple had which is very similar to what you have there, but I found something weird.

    I started trying to see where the breakdown was and I found that

    [movie detachFromCurrentThread]
    

    was actually failing (you can check yourself really fast, it returns a success BOOL.

    I cannot figure out whats stopping QTKit from doing the detach, I've tried setting various attributes and nothing changes that failure to detach. Its a little odd that not detaching doesn't cause any more problems, but for whatever reason it seems to force the rest of the code to keep going on the main thread. It still works when it fails to detach, it just does what you say and freezes up the UI.

    Further probing has given me a fix, if you dive a little deeper into the QuickTime frameworks you can get the function:

     OSErr er = DetachMovieFromCurrentThread([movie quickTimeMovie]);
    

    which actually DOES do a detach for me when the QTKit call fails. Movie is then happily written in the background and UI no longer freezes.

    Hopefully that'll get things moving for you.