I'm attempting to re-encode an input MOV file with changeable frame-rate and clipped in duration, in iOS. At the moment I have an AVAssetWriter setting video properties a bit like this:
NSMutableDictionary* compressionPropertiesDict = [NSMutableDictionary new];
compressionPropertiesDict[AVVideoProfileLevelKey] = AVVideoProfileLevelH264High40;
if(self.fps > 0) {
compressionPropertiesDict[AVVideoAverageNonDroppableFrameRateKey] = [NSNumber numberWithInt:self.fps];
_sessionMgr.videoSettings = @
{
AVVideoCodecKey: AVVideoCodecH264,
AVVideoWidthKey: [NSNumber numberWithFloat:self.outputSize.width],
AVVideoHeightKey: [NSNumber numberWithFloat:self.outputSize.height],
AVVideoCompressionPropertiesKey: compressionPropertiesDict,
};
That comes out at runtime looking like this:
videoSettings =
{
AVVideoCodecKey = avc1;
AVVideoCompressionPropertiesKey = {
AverageNonDroppableFrameRate = 15;
ProfileLevel = "H264_High_4_0";
};
AVVideoHeightKey = 960;
AVVideoWidthKey = 640;
}
At the end of which, I get a crash with NSInvalidArgumentException:
"Compression property AverageNonDroppableFrameRate is not supported for video codec type avc1"
. (In unit tests using the simulator.)
There's only one codec type that's useable in iOS, AVVideoCodecH264 / "avc1" - and I notice other projects have used the AVVideoAverageNonDroppableFrameRateKey
. In fact, I'm using SDAVAssetExportSession and in that codebase I see explicit use of this key. So I would have thought there must be a way to use this key to set frame-rate..?
I've also experimented a bit using AVVideoMaxKeyFrameIntervalKey
instead, but that doesn't change my frame-rate at all...
So, to summarise, can anyone help me with setting a different (always lower) output frame-rate for an iOS AVFoundation-based video conversion? Thanks!
As mentioned in the question, I used SDAVAssetExportSession for ease of video export. I made some small changes to it that enabled me to use that easily to change the framerate.
The main gist is you can change framerate using AVMutableVideoComposition
, setting the frameDuration
property to your desired framerate, and passing this composition object to the AVAssetReaderVideoCompositionOutput
object used in the transcoding.
In SDAVAssetExportSession's buildDefaultVideoComposition
method, I modified it to look a bit like this:
- (AVMutableVideoComposition *)buildDefaultVideoComposition
{
AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition];
AVAssetTrack *videoTrack = [[self.asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
// ...
videoComposition.frameDuration = CMTimeMake(1, myDesiredFramerate);
// ...
That did the trick.