Reputation: 81
Hi I have been trying to figure out how to implement movie looping in GPUImage2, but have been unsuccessful so far. The MovieInput class in GPUImage2 uses AVAssetReader to playback the movie files, so I researched ways to loop AVAssetReader. I found this question on StackOverFlow dealing with this topic. AVFoundation to reproduce a video loop
The best answer was "AVAssetReader doesn't support seeking or restarting, it is essentially a sequential decoder. You have to create a new AVAssetReader object to read the same samples again."
I tried to figure out how to connect the old assetReader to a new one one and I was not very successful and it crashed every time.
I was recommended to try something like this, but I am not exactly sure how to write the function generateAssetReader.
public func start() {
self.assetReader = generateAssetReader(asset: asset, readAudio: readAudio, videoOutputSettings: videoOutputSettings, audioOutputSettings: audioOutputSettings)
asset.loadValuesAsynchronously(forKeys:["tracks"], completionHandler:{
DispatchQueue.global(priority:DispatchQueue.GlobalQueuePriority.default).async(execute: {
guard (self.asset.statusOfValue(forKey: "tracks", error:nil) == .loaded) else { return }
guard self.assetReader.startReading() else {
print("Couldn't start reading")
return
}
var readerVideoTrackOutput:AVAssetReaderOutput? = nil;
for output in self.assetReader.outputs {
if(output.mediaType == AVMediaTypeVideo) {
readerVideoTrackOutput = output;
}
}
while (self.assetReader.status == .reading) {
self.readNextVideoFrame(from:readerVideoTrackOutput!)
}
if assetReader.status == .completed {
assetReader.cancelReading()
self.assetReader = nil
if self.loop {
self.start()
} else {
self.endProcessing()
}
}
}
Would anyone have a clue into solving this looping problem? This is a link to entire code of the MovieInput class. https://github.com/BradLarson/GPUImage2/blob/master/framework/Source/iOS/MovieInput.swift
Upvotes: 0
Views: 2288
Reputation: 81
I found the answer in case anyone is wondering.
public func createReader() -> AVAssetReader
{
var assetRead:AVAssetReader!
do{
assetRead = try AVAssetReader.init(asset: self.asset)
let outputSettings:[String:AnyObject] = [(kCVPixelBufferPixelFormatTypeKey as String):NSNumber(value:Int32(kCVPixelFormatType_420YpCbCr8BiPlanarFullRange))]
let readerVideoTrackOutput = AVAssetReaderTrackOutput(track:self.asset.tracks(withMediaType: AVMediaTypeVideo)[0], outputSettings:outputSettings)
readerVideoTrackOutput.alwaysCopiesSampleData = false
assetRead.add(readerVideoTrackOutput)
}catch{
}
return assetRead
}
public func start() {
self.assetReader = createReader()
asset.loadValuesAsynchronously(forKeys:["tracks"], completionHandler:{
DispatchQueue.global(priority:DispatchQueue.GlobalQueuePriority.default).async(execute: {
guard (self.asset.statusOfValue(forKey: "tracks", error:nil) == .loaded) else { return }
guard self.assetReader.startReading() else {
print("Couldn't start reading")
return
}
var readerVideoTrackOutput:AVAssetReaderOutput? = nil;
for output in self.assetReader.outputs {
if(output.mediaType == AVMediaTypeVideo) {
readerVideoTrackOutput = output;
}
}
while (self.assetReader.status == .reading) {
self.readNextVideoFrame(from:readerVideoTrackOutput!)
}
if (self.assetReader.status == .completed) {
self.assetReader.cancelReading()
if (self.loop) {
// TODO: Restart movie processing
self.start()
} else {
self.endProcessing()
}
}
})
})
}
Upvotes: 1