Video Export Project
I am working on a project that will process videos taken with the camera or pulled from the Photo Library and export them to MP4 format, reducing the dimensions and bit rate.
As part of this process I am using the code for SDAVAssetExportSession that is a AVAssetExportSession drop-in replacement with customizable audio and video settings.
I make use of an instance of AVAssetReaderVideoCompositionOutput that is added to AVAssetReader in SDAVAssetExportSession.m. I set the videoComposition property of the former instance to a composition that allows me to set the render size and some appropriate transforms for scaling, etc. (CGAffineTransform).
Hang in the simulator
I noticed that when certain videos were processed, the simulator would hang. I tracked this down to the copyNextSampleBuffer method of AVAssetReaderOutput. The hang occurred on all the types of iPhone models that I tried (iPhone 4S through iPhone 6). It did not occur on a real device.
It isn’t clear exactly which characteristics of the video are triggering the hang. Some videos are processed correctly on the simulator and others cause the hang. I have seen this occur with both .MOV and .AVI formats. Those videos causing the hang do so consistently.
I am using Xcode Version: 6.0.1 (6A317) with a deployment target of iOS 8.0.
Narrowing it down
I wanted to rule out any issue with the video composition that I was using. I found that the bug was still present when I used a composition generated by the AVMutableVideoComposition class method videoCompositionWithPropertiesOfAsset:. This method generates its own properties for frameDuration, renderSize etc. based on the AVAsset provided to it.
I also tried replacing AVAssetReaderVideoCompositionOutput with an instance of AVAssetReaderTrackOutput (both are subclasses of AVAssetReaderOutput). When using AVAssetReaderTrackOutput the bug does not present itself.
Example project and bug report
I have created a project to show the issue on GitHub. The project bundles a video that shows the bug. I’ve also bundled a second video in the project that works correctly and can be enabled with simple edits at the start of the export method in ViewController.m.
A bug report has also been filed with Apple.
A user on GitHub proposed a workaround.
In SDAVAssetExportSession.m change:
self.videoOutput = [AVAssetReaderVideoCompositionOutput assetReaderVideoCompositionOutputWithVideoTracks:videoTracks videoSettings:nil];
self.videoOutput = [AVAssetReaderVideoCompositionOutput assetReaderVideoCompositionOutputWithVideoTracks:[videoTracks arrayByAddingObjectsFromArray:videoTracks] videoSettings:nil];
The explanation was:
“If an asset has two tracks—say an audio track and a video track— and the video track has a trackID of 2, the simulator works fine. On other hand, if the video track’s trackID is 1, the simulator hangs at copyNextSampleBuffer. Duplicating the video tracks we pass to AVAssetReaderVideoCompositionOutput appears to work around this issue.”