6

I have an app that uses a UIImagePickerController object to get a video file for sharing.

I'm setting the media types (picker.mediaTypes = [kUTTypeMovie as String]) and using the field UIImagePickerControllerMediaURL to fetch either the video details. This works properly and there are no issues when all devices are either H.264 live encoding, or when all devices are H.265 live decoding.

The issue is that I need to support devices which cannot playback H.265 content. I would like to take the "create a single compatible file" route. How can I tell UIImagePickerController to give me a H.264 video regardless of recording device's capabilities?

Ezekiel
  • 2,383
  • 3
  • 19
  • 30
  • Good question. But if you're on a device that doesn't support H.265, why is there H.265 content on it? Was it copied from another device, or downloaded that way? – NRitH Aug 03 '17 at 19:25
  • This is between multiple devices. Meaning recording on a supported device, the recording doesn't work on another device. – Ezekiel Aug 03 '17 at 19:34
  • `videoExportPreset` is the only way to set export presets I think. You can use the already available ones (https://developer.apple.com/documentation/avfoundation/avassetexportsession?changes=latest_minor#relationships) or create new ones (https://stackoverflow.com/a/3742212/2124535). E.g: *Export Preset Names for QuickTime Files of a Given Size*: `The export will not scale the video up from a smaller size. Video is compressed using H.264; audio is compressed using AAC...` (fixed wrong var name) – nathan Aug 03 '17 at 19:47
  • Nathan, I've tried to implement that: `picker.videoExportPreset = AVAssetExportPreset3840x2160` however the file created is still marked as an HEVC video file. – Ezekiel Aug 03 '17 at 20:04
  • Weird, there shouldn't be any change in behavior for old presets, that's why they added the HEVC ones :S – nathan Aug 03 '17 at 20:08
  • Agreed, looks like a bug. I'll file a report and update this ticket if I receive any response. – Ezekiel Aug 03 '17 at 20:10
  • If you target ios 10 or 9, does the same behavior happen? – solenoid Aug 04 '17 at 03:16
  • Neither iOS 10 nor iOS 9 support H.265, and they do not have the `videoExportPreset` field – Ezekiel Aug 04 '17 at 03:21

1 Answers1

1

This is what worked for me. I used an AVAssetExportSession to get a H.265 video exported in H.264 format.

Maybe the above solution would work by choosing AVAssetExportPresetHighestQuality as the videoExportPreset property to UIImagePickerController. The bonus of my approach is iOS 9/10 compatibility. And maybe a snappier UI because you can do the export on a background thread.

I can't use UIImagePickerController because the same picker workflow in my app allows the user to select multiples, so I'm using CTAssetsPickerController, which requires the use of PHAsset for the returned media objects.

Ezekiel and nathan's discussion led me to this solution, so sharing it here.

PHAsset *phasset = <fetched-asset>;
NSURL *assetURL = <where-to-store-exported-asset>;

if(PHAssetMediaTypeVideo == phasset.mediaType) {
    [[PHImageManager defaultManager] requestAVAssetForVideo: phasset
        options: nil resultHandler:^(AVAsset * _Nullable avasset, AVAudioMix * _Nullable audioMix, NSDictionary * _Nullable info) {
        AVAssetExportSession *exportSession =
            [AVAssetExportSession exportSessionWithAsset: avasset presetName: AVAssetExportPresetHighestQuality];
        exportSession.outputURL = assetURL;
        exportSession.outputFileType = AVFileTypeMPEG4;
        [exportSession exportAsynchronouslyWithCompletionHandler:^{
            if(exportSession.status == AVAssetExportSessionStatusCompleted) {
                //
                // success!
                //
            }
        }];
    }];
}
CodeWriter23
  • 317
  • 3
  • 10
  • @ParthDabhi just verified, recorded on-device H.265 on iOS 12.0, 12.1.2 and this code gave me H.264 videos. Also verified the video I used when coding this was recorded on Sept. 12, 5 days before iOS 12 release, so I was using 11.4.1 at that time, and the video in iCloud is H.265 and the export from my app to my service is H.264. [shrugs] Maybe re-check your methodology / if your code is the same as mine... – CodeWriter23 Dec 21 '18 at 10:13
  • Yes I had tested with multiple devices and ios version it's working but not working for one of my client using iPhone X(iPhone10,6) on iOS 11.2.5. – Parth Dabhi Dec 25 '18 at 09:15
  • Sorry I don't have devices that have older versions of iOS. I did test in the simulator, 11.2 (15C107) worked, 11.1 (15B87) did not, and perhaps there is a clue there... the call to exportAsynchronouslyWithCompletionHandler returned with exportSession.status set to AVAssetExportSessionStatusFailed and error set to nil. Sorry that's all the help I can provide. Thanks for the heads up. – CodeWriter23 Dec 25 '18 at 11:20
  • One more thing, I suggest you might want to consider suggesting that your customer upgrade iOS on their device. 11.2.5 has a RCE via WiFi exploit. – CodeWriter23 Dec 25 '18 at 11:22
  • 1, Result exportSession.status is a success but video codec is still HEVC in a result it's not playable to most of the browser. – Parth Dabhi Dec 25 '18 at 11:45
  • 1
    2, Sure, but we can't force them to update.t we can inform about RCE. Better is we make sure we do a solution that works for all, in result I used SDAVAssetExportSession and it worked. – Parth Dabhi Dec 25 '18 at 11:49