5

I have a project that currently uses the H.264 encoder to record video on iOS. I wanted to try using the new HEVC encoder in iOS 11 to reduce file sizes, but have found that using the HEVC encoder causes file sizes to balloon enormously. Here's a project on GitHub that shows the issue - it simultaneously writes frames from the camera to files using the H.264 and H.265 (HEVC) encoders, and the resulting file sizes are printed to the console.

The AVFoundation classes are setup like this:

class VideoWriter {
    var avAssetWriterInput: AVAssetWriterInput
    var avAssetWriter: AVassetWriter
    init() {
        if #available(iOS 11.0, *) {
            avAssetWriterInput = AVAssetWriterInput(mediaType: AVMediaType.video, outputSettings: [AVVideoCodecKey:AVVideoCodecType.hevc, AVVideoHeightKey:720, AVVideoWidthKey:1280])
        }
        avAssetWriterInput.expectsMediaDataInRealTime = true
        do {
            let url = directory.appendingPathComponent(UUID.init().uuidString.appending(".hevc"))
            avAssetWriter = try AVAssetWriter(url: url, fileType: AVFileType.mp4)
            avAssetWriter.add(avAssetWriterInput)
            avAssetWriter.movieFragmentInterval = kCMTimeInvalid
        } catch {
            fatalError("Could not initialize AVAssetWriter \(error)")
        }
    }
...

and then frames are written like this:

    func write(sampleBuffer buffer: CMSampleBuffer) {
        if avAssetWriter.status == AVAssetWriterStatus.unknown {
            avAssetWriter.startWriting()
            avAssetWriter.startSession(atSourceTime: CMSampleBufferGetPresentationTimeStamp(buffer))
         }
        if avAssetWriterInput.isReadyForMoreMediaData {
            avAssetWriterInput.append(buffer)
        }
    }

as they come in to the AVCaptureVideoDataOutputSampleBufferDelegate. At the qualities I'm recording (720p or 1080p) the file size of an HEVC-encoded video should be 40-60% of an identical H.264-encoded video, and I am seeing this when I use the default camera app on iOS, but when I use AVAssetWriter as above (or in the project linked above) I'm seeing file sizes be about three times larger with HEVC than with H.264. Either I am doing something wrong or the HEVC encoder is not working properly. Am I missing something or is there a workaround to get HEVC working through AVFoundation?

jpetrichsr
  • 247
  • 2
  • 11

2 Answers2

2

Have you tried to specify the bitrate, etc.? As below:

NSUInteger bitrate = 50 * 1024 * 1024;  // 50 Mbps
NSUInteger keyFrameInterval = 30;
NSString *videoProfile = AVVideoProfileLevelH264HighAutoLevel;
NSString *codec = AVVideoCodecH264;
if (@available(iOS 11, *)) {
    videoProfile = (NSString *)kVTProfileLevel_HEVC_Main_AutoLevel;
    codec = AVVideoCodecTypeHEVC;
}

NSDictionary *codecSettings = @{AVVideoAverageBitRateKey: @(bitrate),
                              AVVideoMaxKeyFrameIntervalKey: @(keyFrameInterval),
                              AVVideoProfileLevelKey: videoProfile};
NSDictionary *videoSettings = @{AVVideoCodecKey: codec,
                              AVVideoCompressionPropertiesKey: codecSettings,
                              AVVideoWidthKey: @((NSInteger)resolution.width),
                              AVVideoHeightKey: @((NSInteger)resolution.height)};

AVAssetWriterInput *videoWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:videoSettings];
...

As far as I understand, with the same bitrate, the file size should be the same for H264 and HEVC, but the quality of the HEVC should be better.

kovaloid
  • 56
  • 5
  • I got a response from Apple along similar lines. Apparently the default bitrate for H.264 is 5mbit and HEVC is 30mbit. I will report back and accept your answer if I try this out and it works! – jpetrichsr Feb 02 '18 at 14:12
  • @jpetrichsr i wish i would have discovered this sooner. The difference in defaults is outrageous. You wouldn't assume that simply changing a codec flag would cause completely wild outcomes in the *opposite* direction you're anticipating. I could see the same output size being reasonable by bumping the bitrate to take advantage of h265, but this can really burn you if you aren't paying close attention. – Ryan Romanchuk Nov 14 '18 at 22:57
  • Hello everybody, I am trying this same thing (except in Swift) and the weird thing is that when using h.264 I can get a specific video file (1 minute) down to 10MB while with hevc no matter how low I put the bitrate, it won't go lower than 19MB. With h.264, it goes down to 6MB and after that the bitrate doesn't decrease the file size anymore. With hevc / h.265 this just happens way, way earlier. Any way around it? – unixb0y Aug 26 '19 at 15:55
  • @unixb0y did you get any further with this? I am experiencing the same issue – skeg0 Sep 22 '21 at 13:09
  • @skeg0 nope I dont think so :/ – unixb0y Sep 22 '21 at 14:03
1

Use exportSession.fileLengthLimit = 1048576 * 10 //10 MB

10MB is hard coded number. Use according to your required bitrate.

Kumar
  • 1,882
  • 2
  • 27
  • 44