Hi,
I've got a major issue with my code when running it on iOS 11 (beta 5 to GM). For some reason the exact same code on iOS 10 works perfectly well, but hangs during deinitialization on iOS 11.
I've tracked down the bug and am able to reproduce it in a very simple sample project (see below). What happens is:
When using the VTDecompressionSession API, I can successfully decode compressed video frames. I then invalidate the session using VTDecompressionSessionInvalidate. However on iOS 11, the invalidation step hangs indefinitely. The problem also arises if I call VTDecompressionSessionWaitForAsynchronousFrames (which I don't need, as I don't decode frames asynchronously).
The bug is 100% reproducible on an iPhone 7 running iOS 11. There is no issue on an iPhone 6s running iOS 10.3.
To solve the problem, I tried using a VTDecompressionOutputCallbackRecord instead of specifying the callback in VTDecompressionSessionDecodeFrameWithOutputHandler. I also tried the various flags: asynchronous decompression, real time playback, temporal processing. Finally, I also tried dispatching invalidation to another queue. This did not change anything.
import AVFoundation
import ************
class VT {
private let asset: AVAsset
private let track: AVAssetTrack
private let reader: AVAssetReader
private let output: AVAssetReaderOutput
init() {
let url = Bundle.main.url(forResource: "video", withExtension: "mp4")!
self.asset = AVAsset(url: url)
self.track = self.asset.tracks(withMediaType: .video).first!
self.reader = try! AVAssetReader(asset: self.asset)
self.output = AVAssetReaderTrackOutput(track: self.track, outputSettings: nil)
self.reader.add(self.output)
}
func startReading() {
self.reader.startReading()
let formatDescription = self.track.formatDescriptions.first! as! CMVideoFormatDescription
var decompressionSession: VTDecompressionSession?
VTDecompressionSessionCreate(nil, formatDescription, nil, nil, nil, &decompressionSession)
print("Reading buffers...")
var i = 0
while let buffer = self.output.copyNextSampleBuffer() {
i += 1
VTDecompressionSessionDecodeFrameWithOutputHandler(decompressionSession!, buffer, [], nil) {
(status, _, imageBuffer, _, _) in
if (status != noErr) { print("Error") }
if (imageBuffer == nil) { print("No image in this buffer.") }
}
}
print("Read \(i) buffers.")
print("Invalidating the session...")
// This hangs on iOS 11.
VTDecompressionSessionInvalidate(decompressionSession!)
// This would also hang.
// VTDecompressionSessionWaitForAsynchronousFrames(decompressionSession!)
// Hence this is printed only on iOS 10.
print("Done.")
}
}
To reproduce the problem, run the sample project on an iPhone 7 running iOS 11 GM, and observe that VTDecompressionSessionInvalidate hangs the execution of the program by pausing the debugger. You can also simply see that "Done.", supposed to be printed after the session invalidation, is never written to the debugger console.
The video I use is encoded on iOS in H264 using AVFoundation (and SDAVAssetExportSession). As it happens on all of the videos I tried (encoded in the same way), it shouldn't be too hard to produce a similar video for testing. However I can provide one if needed.
Is this a known issue? Has there been an API change? Using this somewhat low-level API, I don't understand how come nobody else has had the problem up to now?
Cheers,
Flo