Skip to content

Instantly share code, notes, and snippets.

@KentarouKanno
Last active June 16, 2018 16:10
Show Gist options
  • Save KentarouKanno/62d739d190aee3b0e6d2fd8f11680965 to your computer and use it in GitHub Desktop.
Save KentarouKanno/62d739d190aee3b0e6d2fd8f11680965 to your computer and use it in GitHub Desktop.
AVFoundation

AVFoundation

★ バンドル内の.mp3ファイルを再生する

import AVFoundation

// インスタンス変数として保持する
var player: AVAudioPlayer!

if let url = Bundle.main.url(forResource: "cat", withExtension: "mp3") {
    do {
        player = try AVAudioPlayer(contentsOf: url)
        player.play()
    } catch {
        print("エラー")
    }
}

★ バンドル内の.mp4ファイルを再生する

import UIKit
import AVFoundation

class ViewController: UIViewController {
    
    var playerItem: AVPlayerItem?
    var videoPlayer: AVPlayer?
    var playerLayer: AVPlayerLayer?
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        play()
    }

    func play() {
        
        if let path = Bundle.main.path(forResource: "sample", ofType: "mp4") {
            let fileURL = NSURL(fileURLWithPath: path)
            let avAsset = AVAsset(url: fileURL as URL)
            
            playerItem = AVPlayerItem(asset: avAsset)
            
            videoPlayer = AVPlayer(playerItem: playerItem)
            
            playerLayer = AVPlayerLayer(player: videoPlayer)
            playerLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
            
            playerLayer?.frame = view.bounds
            view.layer.addSublayer(playerLayer!)
            
            videoPlayer?.play()
            videoPlayer?.rate = 2.0
        }
    }
    
    // Rateを変更
    @IBAction func valueChanged(_ sender: UISlider) {
        videoPlayer?.rate = sender.value
    }
}

Camera

★ UIViewの上にガメラ画像を表示する
※ボタン押下でカメラロールに保存

参考URL: iOS10カスタムカメラ - Swift 3

import UIKit
import AVFoundation

class ViewController: UIViewController, AVCapturePhotoCaptureDelegate {
    // カメラの映像をここに表示
    @IBOutlet weak var cameraView: UIView!
    
    var captureSesssion: AVCaptureSession!
    var stillImageOutput: AVCapturePhotoOutput?
    var previewLayer: AVCaptureVideoPreviewLayer?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        cameraView.layer.borderColor = UIColor.gray.cgColor
        cameraView.layer.borderWidth = 1.0
        cameraView.layer.cornerRadius = 5
        cameraView.layer.masksToBounds = true
    }
    
    // ボタンを押した時呼ばれる
    @IBAction func takeIt(_ sender: AnyObject) {
        // フラッシュとかカメラの細かな設定
        let settingsForMonitoring = AVCapturePhotoSettings()
        settingsForMonitoring.flashMode = .auto
        settingsForMonitoring.isAutoStillImageStabilizationEnabled = true
        settingsForMonitoring.isHighResolutionPhotoEnabled = false
        // シャッターを切る
        stillImageOutput?.capturePhoto(with: settingsForMonitoring, delegate: self)
    }
    
    override func viewWillAppear(_ animated: Bool) {
        
        captureSesssion = AVCaptureSession()
        stillImageOutput = AVCapturePhotoOutput()
        
        captureSesssion.sessionPreset = AVCaptureSessionPreset1920x1080 // 解像度の設定
        
        let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
        
        do {
            let input = try AVCaptureDeviceInput(device: device)
            
            // 入力
            if captureSesssion.canAddInput(input) {
                captureSesssion.addInput(input)
                
                // 出力
                if (captureSesssion.canAddOutput(stillImageOutput)) {
                    captureSesssion.addOutput(stillImageOutput)
                    captureSesssion.startRunning() // カメラ起動
                    
                    previewLayer = AVCaptureVideoPreviewLayer(session: captureSesssion)
                    previewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill // AspectFill
                    previewLayer?.connection.videoOrientation = AVCaptureVideoOrientation.portrait // カメラの向き
                    
                    cameraView.layer.addSublayer(previewLayer!)
                    
                    // ビューのサイズの調整
                    previewLayer?.position = CGPoint(x: self.cameraView.frame.width / 2, y: self.cameraView.frame.height / 2)
                    previewLayer?.bounds = cameraView.frame
                }
            }
        }
        catch {
            print(error)
        }
    }
    
    // デリゲート。カメラで撮影が完了した後呼ばれる。JPEG形式でフォトライブラリに保存。
    func capture(_ captureOutput: AVCapturePhotoOutput, didFinishProcessingPhotoSampleBuffer photoSampleBuffer: CMSampleBuffer?, previewPhotoSampleBuffer: CMSampleBuffer?, resolvedSettings: AVCaptureResolvedPhotoSettings, bracketSettings: AVCaptureBracketedStillImageSettings?, error: Error?) {
        
        if let photoSampleBuffer = photoSampleBuffer {
            // JPEG形式で画像データを取得
            let photoData = AVCapturePhotoOutput.jpegPhotoDataRepresentation(forJPEGSampleBuffer: photoSampleBuffer, previewPhotoSampleBuffer: previewPhotoSampleBuffer)
            let image = UIImage(data: photoData!)
            
            // フォトライブラリに保存
            UIImageWriteToSavedPhotosAlbum(image!, nil, nil, nil)
        }
    }
}

カメラロール、カメラ許可plistに記述する

<key>NSCameraUsageDescription</key>
<string>Camera許可メッセージ</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Photo Library許可メッセージ</string>

★ カメラのフラッシュを点灯させる

func toggleFlash() {
    if let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo) {
        if (device.hasTorch) {
            do {
                try device.lockForConfiguration()
                if (device.torchMode == AVCaptureTorchMode.on) {
                    device.torchMode = AVCaptureTorchMode.off
                } else {
                    do {
                        try device.setTorchModeOnWithLevel(1.0)
                    } catch {
                        print(error)
                    }
                }
                device.unlockForConfiguration()
            } catch {
                print(error)
            }
        }
    }
}
import UIKit
import AVFoundation
import Photos

extension UIViewController:AVCapturePhotoCaptureDelegate {
    //映像をキャプチャする
    public func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
        //データを取り出す
        guard let photoData = photo.fileDataRepresentation() else {
            return
        }
        //Dataから写真イメージを作る
        if let stillImage = UIImage(data: photoData) {
            //移動先のビューコントローラーを参照する
            let nextVC = self.storyboard?.instantiateViewController(withIdentifier: "preview")as! previewViewController
            //トランジションの映像効果を指定する
            //            nextVC?.modalTransitionStyle = .flipHorizontal
            nextVC.image = stillImage
            //シーンを移動する
            present(nextVC, animated: true, completion: nil)
        }
    }
}

class ViewController: UIViewController {
    
    @IBOutlet weak var previewView: UIView!
    @IBOutlet weak var shutterButton: UIButton!
    
    var previewLayer: AVCaptureVideoPreviewLayer!
    // インスタンスの作成
    var session = AVCaptureSession()
    var photoOutputObj = AVCapturePhotoOutput()
    // 通知センターを作る
    let notification = NotificationCenter.default
    // プライバシーと入出力のステータス
    var authStatus:AuthorizedStatus = .authorized
    var inOutStatus:InputOutputStatus = .ready
    // 認証のステータス
    enum AuthorizedStatus {
        case authorized
        case notAuthorized
        case failed
    }
    // 入出力のステータス
    enum InputOutputStatus {
        case ready
        case notReady
        case failed
    }
    
    // ビューが表示された直後に実行
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        // セッション実行中ならば中断する
        guard !session.isRunning else {
            return
        }
        // カメラのプライバシー認証確認
        cameraAuth()
        // 入出力の設定
        setupInputOutput()
        // カメラの準備ができているかどうか
        if (authStatus == .authorized)&&(inOutStatus == .ready){
            // プレビューレイヤの設定
            setPreviewLayer()
            // セッション開始
            session.startRunning()
            shutterButton.isEnabled = true
        } else {
            // アラートを出す
            showAlert(appName: "カメラ")
        }
    }
    
    // シャッターボタンで実行する
    @IBAction func takePhoto(_ sender: Any) {
        if (authStatus == .authorized)&&(inOutStatus == .ready){
            let captureSetting = AVCapturePhotoSettings()
            captureSetting.flashMode = .auto
            captureSetting.isAutoStillImageStabilizationEnabled = true
            captureSetting.isHighResolutionPhotoEnabled = false
            // キャプチャのイメージ処理はデリゲートに任せる
            photoOutputObj.capturePhoto(with: captureSetting, delegate: self)
        } else {
            // カメラの利用を許可しなかったにも関わらずボタンをタップした(初回起動時のみ)
            showAlert(appName: "カメラ")
        }
    }
    
    // カメラのプライバシー認証確認
    func cameraAuth(){
        let status = AVCaptureDevice.authorizationStatus(for: AVMediaType.video)
        switch status {
        case .notDetermined:
            // 初回起動時
            AVCaptureDevice.requestAccess(for: AVMediaType.video,
                                          completionHandler: { [unowned self] authorized in
                                            print("初回", authorized.description)
                                            if authorized {
                                                self.authStatus = .authorized
                                            } else {
                                                self.authStatus = .notAuthorized
                                            }})
        case .restricted, .denied:
            authStatus = .notAuthorized
        case .authorized:
            authStatus = .authorized
        }
    }
    
    // 入出力の設定
    func setupInputOutput(){
        //解像度の指定
        session.sessionPreset = AVCaptureSession.Preset.photo
        // 入力の設定
        do {
            //デバイスの取得
            let device = AVCaptureDevice.default(
                AVCaptureDevice.DeviceType.builtInWideAngleCamera,
                for: AVMediaType.video, // ビデオ入力
                position: AVCaptureDevice.Position.back) // バックカメラ
            
            // 入力元
            let input = try AVCaptureDeviceInput(device: device!)
            if session.canAddInput(input){
                session.addInput(input)
            } else {
                print("セッションに入力を追加できなかった")
                return
            }
        } catch  let error as NSError {
            print("カメラがない \(error)")
            return
        }
        
        // 出力の設定
        if session.canAddOutput(photoOutputObj) {
            session.addOutput(photoOutputObj)
        } else {
            print("セッションに出力を追加できなかった")
            return
        }
    }
    
    // UIInterfaceOrientation -> AVCaptureVideoOrientationにConvert
    func convertUIOrientation2VideoOrientation(f: () -> UIInterfaceOrientation) -> AVCaptureVideoOrientation? {
        let v = f()
        switch v {
        case UIInterfaceOrientation.unknown: return nil
        default:
            return ([
                .portrait: .portrait,
                .portraitUpsideDown: .portraitUpsideDown,
                .landscapeLeft: .landscapeLeft,
                .landscapeRight: .landscapeRight
                ])[v]
        }
    }
    
    func appOrientation() -> UIInterfaceOrientation {
        return UIApplication.shared.statusBarOrientation
    }
    
    // プレビューレイヤの設定
    func setPreviewLayer(){
        // プレビューレイヤを作る
        previewLayer = AVCaptureVideoPreviewLayer(session: session)
        previewLayer.frame = view.bounds
        previewLayer.masksToBounds = true
        previewLayer.videoGravity = AVLayerVideoGravity.resizeAspect
        if let orientation = self.convertUIOrientation2VideoOrientation(f: { return self.appOrientation() } ) {
            previewLayer.connection?.videoOrientation = orientation
        }
        // previewViewに追加する
        previewView.layer.addSublayer(previewLayer)
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        
        if let previewLayer = previewLayer {
            previewLayer.frame = view.bounds
        }
    }
    
    // 画面の回転にも対応したい時は viewWillTransitionToSize で同じく向きを教える。
    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)
        
        coordinator.animate(
            alongsideTransition: nil,
            completion: {(UIViewControllerTransitionCoordinatorContext) in
                //画面の回転後に向きを教える。
                if let orientation = self.convertUIOrientation2VideoOrientation(f: {return self.appOrientation()}) {
                    self.previewLayer.connection?.videoOrientation = orientation
                }
        }
        )
    }
    
    // プライバシー認証のアラートを表示する
    func showAlert(appName:String){
        let aTitle = appName + "のプライバシー認証"
        let aMessage = "設定>プライバシー>" + appName + "で利用を許可してください。"
        let alert = UIAlertController(title: aTitle, message: aMessage, preferredStyle: .alert)
        // OKボタン(何も実行しない)
        alert.addAction(
            UIAlertAction(title: "OK",style: .default,handler: nil)
        )
        // 設定を開くボタン
        alert.addAction(
            UIAlertAction(
                title: "設定を開く",style: .default,
                handler:  { action in
                    UIApplication.shared.open(URL(string: UIApplicationOpenSettingsURLString)!, options: [:], completionHandler: nil)
            })
        )
        // アラートを表示する
        self.present(alert, animated: false, completion:nil)
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment