Swift - How to Record Video in Mp4 Format with Uiimagepickercontroller

Swift - How to record video in MP4 format with UIImagePickerController?

Here is some code that you can use to convert the recorded video into MP4:

func encodeVideo(videoURL: NSURL)  {
let avAsset = AVURLAsset(URL: videoURL, options: nil)

var startDate = NSDate()

//Create Export session
exportSession = AVAssetExportSession(asset: avAsset, presetName: AVAssetExportPresetPassthrough)

// exportSession = AVAssetExportSession(asset: composition, presetName: mp4Quality)
//Creating temp path to save the converted video

let documentsDirectory = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0]
let myDocumentPath = NSURL(fileURLWithPath: documentsDirectory).URLByAppendingPathComponent("temp.mp4").absoluteString
let url = NSURL(fileURLWithPath: myDocumentPath)

let documentsDirectory2 = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0] as NSURL

let filePath = documentsDirectory2.URLByAppendingPathComponent("rendered-Video.mp4")
deleteFile(filePath)

//Check if the file already exists then remove the previous file
if NSFileManager.defaultManager().fileExistsAtPath(myDocumentPath) {
do {
try NSFileManager.defaultManager().removeItemAtPath(myDocumentPath)
}
catch let error {
print(error)
}
}

url

exportSession!.outputURL = filePath
exportSession!.outputFileType = AVFileTypeMPEG4
exportSession!.shouldOptimizeForNetworkUse = true
var start = CMTimeMakeWithSeconds(0.0, 0)
var range = CMTimeRangeMake(start, avAsset.duration)
exportSession.timeRange = range

exportSession!.exportAsynchronouslyWithCompletionHandler({() -> Void in
switch self.exportSession!.status {
case .Failed:
print("%@",self.exportSession?.error)
case .Cancelled:
print("Export canceled")
case .Completed:
//Video conversion finished
var endDate = NSDate()

var time = endDate.timeIntervalSinceDate(startDate)
print(time)
print("Successful!")
print(self.exportSession.outputURL)

default:
break
}

})

}

func deleteFile(filePath:NSURL) {
guard NSFileManager.defaultManager().fileExistsAtPath(filePath.path!) else {
return
}

do {
try NSFileManager.defaultManager().removeItemAtPath(filePath.path!)
}catch{
fatalError("Unable to delete file: \(error) : \(__FUNCTION__).")
}
}

Source: https://stackoverflow.com/a/39329155/4786204

How do I encode iOS videos as .mp4 from UIImagePickerController so that Android devices can play them?

var exportSession: AVAssetExportSession!

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
picker.dismiss(animated: true, completion: nil)

guard let videoURL = (info[UIImagePickerController.InfoKey.mediaURL] as? URL) else { return }
encodeVideo(videoURL)
}

func encodeVideo(_ videoURL: URL) {
let avAsset = AVURLAsset(url: videoURL, options: nil)

//Create Export session
exportSession = AVAssetExportSession(asset: avAsset, presetName: AVAssetExportPresetPassthrough)

let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] as URL
let filePath = documentsDirectory.appendingPathComponent("rendered-Video.mp4")
deleteFile(filePath)

exportSession!.outputURL = filePath
exportSession!.outputFileType = AVFileType.mp4
exportSession!.shouldOptimizeForNetworkUse = true
let start = CMTimeMakeWithSeconds(0.0, preferredTimescale: 0)
let range = CMTimeRangeMake(start: start, duration: avAsset.duration)
exportSession.timeRange = range

exportSession!.exportAsynchronously(completionHandler: {() -> Void in
DispatchQueue.main.async {
Utility.stopActivityIndicator()

switch self.exportSession!.status {
case .failed:
self.view.makeToast(self.exportSession?.error?.localizedDescription ?? "")
case .cancelled:
self.view.makeToast("Export canceled")
case .completed:
if let url = self.exportSession.outputURL {
//Rendered Video URL
}
default:
break
}
}
})
}

Delete File function:

func deleteFile(_ filePath: URL) {
guard FileManager.default.fileExists(atPath: filePath.path) else {
return
}

do {
try FileManager.default.removeItem(atPath: filePath.path)
} catch {
fatalError("Unable to delete file: \(error) : \(#function).")
}
}

Don't forget to import AVFoundation

Hope that will help!

Record, save and/or convert video in mp4 format?

You are doing right thing.. Now you need to convert this mov file to mp4 as below.

NSString *mediaType = [info objectForKey: UIImagePickerControllerMediaType];
NSString *videoPath1 = @"";
if (CFStringCompare ((__bridge_retained CFStringRef) mediaType, kUTTypeMovie, 0) == kCFCompareEqualTo)
{
if (UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(moviePath))
{
NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *moviePath = [[info objectForKey:UIImagePickerControllerMediaURL] path];
videoPath1 =[NSString stringWithFormat:@"%@/xyz.mov",docDir];
NSURL *videoURL = [info objectForKey:UIImagePickerControllerMediaURL];
NSData *videoData = [NSData dataWithContentsOfURL:videoURL];
[videoData writeToFile:videoPath1 atomically:NO];
// UISaveVideoAtPathToSavedPhotosAlbum(moviePath, self, nil, nil);
}
}

AVURLAsset *avAsset = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:videoPath1] options:nil];
NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:avAsset];

if ([compatiblePresets containsObject:AVAssetExportPresetLowQuality])
{
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc]initWithAsset:avAsset presetName:AVAssetExportPresetPassthrough];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
videoPath = [NSString stringWithFormat:@"%@/xyz.mp4", [paths objectAtIndex:0]];
exportSession.outputURL = [NSURL fileURLWithPath:videoPath];
NSLog(@"videopath of your mp4 file = %@",videoPath); // PATH OF YOUR .mp4 FILE
exportSession.outputFileType = AVFileTypeMPEG4;

// CMTime start = CMTimeMakeWithSeconds(1.0, 600);
// CMTime duration = CMTimeMakeWithSeconds(3.0, 600);
// CMTimeRange range = CMTimeRangeMake(start, duration);
// exportSession.timeRange = range;
// UNCOMMENT ABOVE LINES FOR CROP VIDEO
[exportSession exportAsynchronouslyWithCompletionHandler:^{

switch ([exportSession status]) {

case AVAssetExportSessionStatusFailed:
NSLog(@"Export failed: %@", [[exportSession error] localizedDescription]);

break;

case AVAssetExportSessionStatusCancelled:

NSLog(@"Export canceled");

break;

default:

break;

}
UISaveVideoAtPathToSavedPhotosAlbum(videoPath, self, nil, nil);
[exportSession release];

}];

}
[nextScreenButton setTitle:@"ПРОДЪЛЖИ" forState:UIControlStateNormal];
[self dismissViewControllerAnimated:YES completion:nil];

AVFoundation record video in MP4 format

I am currently unaware of how to do it in foundation classes, but you can certainly do it using AVAssetWriter look for option outputFileType and shouldOptimizeForNetworkUse.

How can i record an mp4 video in mpeg4 container with AVCaptureSession with swift (IOS 8)

First things first: This may not be the best solution, but this is a complete solution.

The code below captures video and audio with AvCaptureSession and converts it into mpeg4 with AvExportSession. There is also zoom in, zoom out and switch camera functionality and permission checking. You can record in 480p or 720p. You can also set minimum and maximum frame rates to create smaller videos. Hope this helps as a complete guide.

Note: There are keys to add to info.plist to ask for camera and photos library permission:

<key>NSCameraUsageDescription</key>
<string>Yo, this is a cam app.</string>

<key>NSPhotoLibraryUsageDescription</key>
<string>Yo, i need to access your photos.</string>

<key>NSMicrophoneUsageDescription</key>
<string>Yo, i can't hear you</string>

And the code:

import UIKit
import Photos
import AVFoundation

class VideoAct: UIViewController, AVCaptureFileOutputRecordingDelegate
{
let captureSession : AVCaptureSession = AVCaptureSession()
var captureDevice : AVCaptureDevice!
var microphone : AVCaptureDevice!
var previewLayer : AVCaptureVideoPreviewLayer!
let videoFileOutput : AVCaptureMovieFileOutput = AVCaptureMovieFileOutput()
var duration : Int = 30
var v_path : URL = URL(fileURLWithPath: "")
var my_timer : Timer = Timer()
var cameraFront : Bool = false
var cameras_number : Int = 0
var max_zoom : CGFloat = 76
var devices : [AVCaptureDevice] = []
var captureInput : AVCaptureDeviceInput = AVCaptureDeviceInput()
var micInput : AVCaptureDeviceInput = AVCaptureDeviceInput()

@IBOutlet weak var cameraView: UIView!

override func viewDidLoad()
{
super.viewDidLoad()
if (check_permissions())
{
initialize()
}
else
{
AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeVideo, completionHandler: { (granted) in
if (granted)
{
self.initialize()
}
else
{
self.dismiss(animated: true, completion: nil)
}
})
}
}

func check_permissions() -> Bool
{
return AVCaptureDevice.authorizationStatus(forMediaType: AVMediaTypeVideo) == AVAuthorizationStatus.authorized
}

@available(iOS 4.0, *)
func capture(_ captureOutput: AVCaptureFileOutput!, didFinishRecordingToOutputFileAt outputFileURL: URL!, fromConnections connections: [Any]!, error: Error!)
{
//you can implement stopvideoaction here if you want
}

func initialize()
{
let directory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
v_path = directory.appendingPathComponent("temp_video.mp4")
// we just set the extension .mp4 but
// actually it is a mov file with QT container !! May not play in Android devices.
// it will be ceonverted
self.duration = 30
devices = AVCaptureDevice.devices() as! [AVCaptureDevice]
for device in devices
{
if (device.hasMediaType(AVMediaTypeVideo))
{
if (device.position == AVCaptureDevicePosition.back)
{
captureDevice = device as AVCaptureDevice
}
if (device.position == AVCaptureDevicePosition.front)
{
cameras_number = 2
}
}
if (device.hasMediaType(AVMediaTypeAudio))
{
microphone = device as AVCaptureDevice
}
}
if (cameras_number == 1)
{
//only 1 camera available
btnSwitchCamera.isHidden = true
}
if captureDevice != nil
{
beginSession()
}
max_zoom = captureDevice.activeFormat.videoMaxZoomFactor
}

func beginSession()
{
if (captureSession.isRunning)
{
captureSession.stopRunning()
}
do
{
try captureInput = AVCaptureDeviceInput(device: captureDevice)
try micInput = AVCaptureDeviceInput(device: microphone)
try captureDevice.lockForConfiguration()
}
catch
{
print("errorrrrrrrrrrr \(error)")
}
// beginconfig before adding input and setting settings
captureSession.beginConfiguration()
captureSession.addInput(captureInput)
captureSession.addInput(micInput)
previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
previewLayer.connection.videoOrientation = AVCaptureVideoOrientation.init(rawValue: UIDevice.current.orientation.rawValue)!
if (previewLayer.connection.isVideoStabilizationSupported)
{
previewLayer.connection.preferredVideoStabilizationMode = AVCaptureVideoStabilizationMode.auto
}
if (captureDevice.isSmoothAutoFocusSupported)
{
captureDevice.isSmoothAutoFocusEnabled = false
}
if (captureDevice.isFocusModeSupported(AVCaptureFocusMode.continuousAutoFocus))
{
captureDevice.focusMode = .continuousAutoFocus
}
set_preview_size_thing()
set_quality_thing()
if (captureDevice.isLowLightBoostSupported)
{
captureDevice.automaticallyEnablesLowLightBoostWhenAvailable = true
}
if (cameraView.layer.sublayers?[0] is AVCaptureVideoPreviewLayer)
{
//to prevent previewlayers stacking on every camera switch
cameraView.layer.sublayers?.remove(at: 0)
}
cameraView.layer.insertSublayer(previewLayer, at: 0)
previewLayer?.frame = cameraView.layer.frame
captureSession.commitConfiguration()
captureSession.startRunning()
}

func duration_thing()
{
// there is a textview to write remaining time left
self.duration = self.duration - 1
timerTextView.text = "remaining seconds: \(self.duration)"
timerTextView.sizeToFit()
if (self.duration == 0)
{
my_timer.invalidate()
stopVideoAction()
}
}

func switch_cam()
{
captureSession.removeInput(captureInput)
captureSession.removeInput(micInput)
cameraFront = !cameraFront
// capturedevice will be locked again
captureDevice.unlockForConfiguration()
for device in devices
{
if (device.hasMediaType(AVMediaTypeVideo))
{
if (device.position == AVCaptureDevicePosition.back && !cameraFront)
{
captureDevice = device as AVCaptureDevice
}
else if (device.position == AVCaptureDevicePosition.front && cameraFront)
{
captureDevice = device as AVCaptureDevice
}
}
}
beginSession()
}

func zoom_in()
{
// 10x zoom would be enough
if (captureDevice.videoZoomFactor * 1.5 < 10)
{
captureDevice.videoZoomFactor = captureDevice.videoZoomFactor * 1.5
}
else
{
captureDevice.videoZoomFactor = 10
}
}

func zoom_out()
{
if (captureDevice.videoZoomFactor * 0.67 > 1)
{
captureDevice.videoZoomFactor = captureDevice.videoZoomFactor * 0.67
}
else
{
captureDevice.videoZoomFactor = 1
}
}

func set_quality_thing()
{
// there is a switch in the screen (30-30 fps high quality or 15-23 fps normal quality)
// you may not have to do this because export session also has some presets and a property called “optimizefornetwork” or something. But it would be better to make sure the output file is not huge with unnecessary 90 fps video
captureDevice.activeVideoMinFrameDuration = CMTimeMake(1, switch_quality.isOn ? 30 : 15)
captureDevice.activeVideoMaxFrameDuration = CMTimeMake(1, switch_quality.isOn ? 30 : 23)
}

func set_preview_size_thing()
{
//there is a switch for resolution (720p or 480p)
captureSession.sessionPreset = switch_res.isOn ? AVCaptureSessionPreset1280x720 : AVCaptureSessionPreset640x480
//this for loop is probably unnecessary and ridiculous but you can make sure you are using the right format
for some_format in captureDevice.formats as! [AVCaptureDeviceFormat]
{
let some_desc : String = String(describing: some_format)
if (switch_res.isOn)
{
if (some_desc.contains("1280x") && some_desc.contains("720") && some_desc.contains("420v") && some_desc.contains("30 fps"))
{
captureDevice.activeFormat = some_format
break
}
}
else
{
if (some_desc.contains("640x") && some_desc.contains("480") && some_desc.contains("420v"))
{
captureDevice.activeFormat = some_format
break
}
}
}
}

func takeVideoAction()
{
// movieFragmentInterval is important !! or you may end up with a video without audio
videoFileOutput.movieFragmentInterval = kCMTimeInvalid
captureSession.addOutput(videoFileOutput)
(videoFileOutput.connections.first as! AVCaptureConnection).videoOrientation = returnedOrientation()
videoFileOutput.maxRecordedDuration = CMTime(seconds: Double(self.duration), preferredTimescale: 1)
videoFileOutput.startRecording(toOutputFileURL: v_path, recordingDelegate: self)
//timer will tell the remaining time
my_timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(duration_thing), userInfo: nil, repeats: true)
}

func stopVideoAction()
{
captureDevice.unlockForConfiguration()
videoFileOutput.stopRecording()
captureSession.stopRunning()
// turn temp_video into an .mpeg4 (mp4) video
let directory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
let avAsset = AVURLAsset(url: v_path, options: nil)
// there are other presets than AVAssetExportPresetPassthrough
let exportSession = AVAssetExportSession(asset: avAsset, presetName: AVAssetExportPresetPassthrough)!
exportSession.outputURL = directory.appendingPathComponent("main_video.mp4")
// now it is actually in an mpeg4 container
exportSession.outputFileType = AVFileTypeMPEG4
let start = CMTimeMakeWithSeconds(0.0, 0)
let range = CMTimeRangeMake(start, avAsset.duration)
exportSession.timeRange = range
exportSession.exportAsynchronously(completionHandler: {
if (exportSession.status == AVAssetExportSessionStatus.completed)
{
// you don’t need temp video after exporting main_video
do
{
try FileManager.default.removeItem(atPath: self.v_path.path)
}
catch
{
}
// v_path is now points to mp4 main_video
self.v_path = directory.appendingPathComponent("main_video.mp4")
self.performSegue(withIdentifier: "ShareVideoController", sender: nil)
}
})
}

func btn_capture_click_listener()
{
if (videoFileOutput.isRecording)
{
stopVideoAction()
}
else
{
takeVideoAction()
}
}

func returnedOrientation() -> AVCaptureVideoOrientation
{
var videoOrientation: AVCaptureVideoOrientation!
let orientation = UIDevice.current.orientation
switch orientation
{
case .landscapeLeft:
videoOrientation = .landscapeRight
case .landscapeRight:
videoOrientation = .landscapeLeft
default:
videoOrientation = .landscapeLeft
}
return videoOrientation
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
if (segue.identifier == "ShareVideoController")
{
//to make it visible in the camera roll (main_video.mp4)
PHPhotoLibrary.shared().performChanges({PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: self.v_path)}) { completed, error in}
let destVC : ShareVideoController = segue.destination as! ShareVideoController
// use the path in other screen to upload it or whatever
destVC.videoFilePath = v_path
// bla bla
}
}

override var supportedInterfaceOrientations: UIInterfaceOrientationMask
{
// screen will always be in landscape (remove this override if you want)
return .landscape
}
}

Using Swift to record and playback video and sending the video to a server

to record a video:

func startCaptureVideoBlogFromViewController(viewcontroller: UIViewController, withDelegate delegate: protocol<UIImagePickerControllerDelegate, UINavigationControllerDelegate>) -> Bool{

if (UIImagePickerController.isSourceTypeAvailable(.Camera) == false) {

return false
}

let cameraController = UIImagePickerController()
cameraController.sourceType = .Camera
cameraController.mediaTypes = [kUTTypeMovie as String]
cameraController.allowsEditing = false
cameraController.delegate = delegate

presentViewController(cameraController, animated: true, completion: nil)

return true

}


Related Topics



Leave a reply



Submit