iOSプログラミング with Swift 2


2016.06.25: created by

Swiftで動画を撮影し保存する(AVFoundation 経由)

AVFoundation フレームワークを使って動画を撮影し、保存する例です。 録画途中でのプレビューもon/off できます。

  1. Xcode を起動して "Create a new Xcode project" で "Single View Application" として新しいプロジェクトを開きます。 ここではプロジェクト名を SwiftAVFMovie としています。



  2. プロジェクトの最初に表示される画面は、ウィンドウの左側に表示されている "Show the project navigator" アイコンをクリックしても表示されます。 "General" -> "Linked Frameworks and Libraries" ->"+"ボタン を押して Add で AVFoundation.framework を追加します。









  3. Main.storyboard 上に Button を 3 個配置し、表示を"Record", "Stop", "Preview" にそれぞれ変えておきます。 さらにLabel を1個配置します。



  4. Button と Image View をそれぞれ ViewController.swift 内の関数や変数と connectします。
  5. Button "Record"Action (Touch Up Inside)tapRecord 関数
    Button "Stop"Action (Touch Up Inside)tapStop 関数
    Button "Preview"Action (Touch Up Inside)tapPreview 関数
    LabelOutletmyLabel変数



  6. ViewController.swift を変更します。
  7. 動画の撮影と録画に関するコードを赤い文字で、 録画中にプレビューを背景全体に表示するコードをマゼンタ色の文字で示しています。

    ViewController.swiftに追加するコード(赤字部分とマゼンタ字部分)
    import UIKit
    import AVFoundation
    
    class ViewController: UIViewController,AVCaptureFileOutputRecordingDelegate {
    
        var session: AVCaptureSession!
        var videoDevice: AVCaptureDevice!
        var audioDevice: AVCaptureDevice!
        var videoInput: AVCaptureDeviceInput!
        var audioInput: AVCaptureDeviceInput!
        var fileOutput: AVCaptureMovieFileOutput!
        var filePath: String!
        
        var previewFlag: Bool = false;
        var previewLayer: AVCaptureVideoPreviewLayer!
    
        @IBOutlet weak var myLabel: UILabel!
        
        @IBAction func tapRecord(sender: AnyObject) {
            print("recording started")
            myLabel.text = "recording started"
            filePath = NSHomeDirectory() + "/Documents/test.mp4"
            let fileURL: NSURL = NSURL(fileURLWithPath: filePath)
           
            session.startRunning()
            fileOutput.startRecordingToOutputFileURL(fileURL, recordingDelegate: self)
        }
        @IBAction func tapStop(sender: AnyObject) {
            fileOutput.stopRecording()
            session.stopRunning()
            UISaveVideoAtPathToSavedPhotosAlbum(filePath, self, #selector(ViewController.video(_:didFinishSavingWithError:contextInfo:)), nil)
        }
    
        @IBAction func tapPreview(sender: AnyObject) {
            if previewFlag {
               previewLayer.removeFromSuperlayer()
            } else {
                view.layer.insertSublayer(previewLayer,atIndex:0)
            }
            previewFlag = !previewFlag
        }
        
        func captureOutput(captureOutput: AVCaptureFileOutput, didFinishRecordingToOutputFileAtURL outputFile: NSURL, fromConnections connections: [AnyObject]!,error: NSError) {
            print("recording finished")
            myLabel.text = "recording finished"
        }
        
        func video(videoPath: String, didFinishSavingWithError error: NSError!, contextInfo: UnsafeMutablePointer) {
            if (error != nil) {
                print("video saving fails")
                myLabel.text = "video saving fails"
            } else {
                print("video saving success")
                myLabel.text = "video saving success"
            }
        }
        
        func prepareVideo() {
            session = AVCaptureSession()
            session.sessionPreset = AVCaptureSessionPresetHigh
            let devices = AVCaptureDevice.devices()
            for device in devices {
                if (device.position == AVCaptureDevicePosition.Back) {
                    videoDevice = device as! AVCaptureDevice
                }
            }
            audioDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeAudio)
            do {
                videoInput = try AVCaptureDeviceInput(device: videoDevice)
                if (session.canAddInput(videoInput)) {
                    session.addInput(videoInput)
                } else {
                    print("cannot add video input to session")
                }
                audioInput = try AVCaptureDeviceInput(device: audioDevice)
                if (session.canAddInput(audioInput)) {
                    session.addInput(audioInput)
                } else {
                    print("cannot add audio input to session")
                }
                fileOutput = AVCaptureMovieFileOutput()
                if (session.canAddOutput(fileOutput)) {
                    session.addOutput(fileOutput)
                } else {
                    print("cannot add file output to session")
                }
                
                // preview background
                previewLayer = AVCaptureVideoPreviewLayer(session: session)!
                previewLayer.frame = view.bounds
                previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
                
            } catch let error as NSError {
                print("cannot use camera \(error)")
            }
        }
        
        override func viewDidLoad() {
            super.viewDidLoad()
            prepareVideo()
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
        }
    
    }
    
  8. 実行すると、カメラへのアクセス許可を求めてきます。 許可した上で Record ボタンを押すと録画が開始されます(ラベルにrecording startedと表示されます)。 録画の途中で Previeww ボタンを押すと、背景にビデオカメラで撮影中の画像をリアルタイムで表示するかどうか選択できます。 Stopボタンを押すと撮影は終了し(ラベルの表示は recording finished), しばらく時間が経過すると録画ファイルがアルバムに保存されます(ラベルの表示は "video saving success" または "video saving fails" )。
    -> ->
  9. サンプルのプロジェクトはこちら。(Xcode 7.3.1版)


http://karel.tsuda.ac.jp