728x90
[출처]
목표
- 비디오 선택 후 재생
- 비디오 녹화 후 저장
- 비디오 합치기
기본화면구성
- 버튼3개
- stackview 로 그냥 감쌈
- vertical, horizontal center
재생할 비디오 목록에서 선택
import AVKit
import MobileCoreServices
- AVKit: AVPlayer에 접근할 수 있음(선택된 비디오 재생)
- MobileCoreService: kUTTypeMovie 와 같은 predefined constants 가 있다. (나중에 쓰임)
extension ViewController : UIImagePickerControllerDelegate {
}
extension ViewController : UINavigationControllerDelegate {
}
- ImagePicker delegate 와 navigation controller delegate를 추가시킨다.
- Image Picker를 사용해 갤러리에 있는 비디오를 선택할 것이다.(이름은 image picker 이지만 video 도 가능)
VideoHelper class 를 만들어 준다.
import MobileCoreServices
import UIKit
enum VideoHelper {
static func startMediaBrowser(
delegate: UIViewController & UINavigationControllerDelegate & UIImagePickerControllerDelegate,
sourceType: UIImagePickerController.SourceType
) {
guard UIImagePickerController.isSourceTypeAvailable(sourceType)
else { return }
let mediaUI = UIImagePickerController()
mediaUI.sourceType = sourceType
mediaUI.mediaTypes = [kUTTypeMovie as String]
mediaUI.allowsEditing = true
mediaUI.delegate = delegate
delegate.present(mediaUI, animated: true, completion: nil)
}
}
actionSelectAndPlay 버튼에 startMediaBrowser 메서드를 구현해 준다.
//
// ViewController.swift
// AVFoundationPractice
//
// Created by TaeHyeong Kim on 2020/08/30.
// Copyright © 2020 TaeHyeong Kim. All rights reserved.
//
import UIKit
import AVKit
import MobileCoreServices
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
@IBAction func actionSelectAndPlay(_ sender: Any) {
VideoHelper.startMediaBrowser(delegate: self, sourceType: .savedPhotosAlbum)
}
@IBAction func actionRecordAndSave(_ sender: Any) {
}
@IBAction func actionMerge(_ sender: Any) {
}
}
extension ViewController : UIImagePickerControllerDelegate {
}
extension ViewController : UINavigationControllerDelegate {
}
- 헬퍼 클래스의 startMediaBroswer는 image picker를 열며 self 에 있는 delegate를 통해 이벤트를 전달할 것 이다.
비디오를 선택한 다음 어떻게 처리할지 구현
UIImagePickerControllerDelegate 에 imagePickerController 함수를 구현한다.
extension ViewController : UIImagePickerControllerDelegate {
func imagePickerController(
_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]
) {
// 1
guard
let mediaType = info[UIImagePickerController.InfoKey.mediaType] as? String,
mediaType == (kUTTypeMovie as String),
let url = info[UIImagePickerController.InfoKey.mediaURL] as? URL
else { return }
// 2
dismiss(animated: true) {
//3
let player = AVPlayer(url: url)
let vcPlayer = AVPlayerViewController()
vcPlayer.player = player
self.present(vcPlayer, animated: true, completion: nil)
}
}
}
- 비디오 선택이 끝나면 (didFinishPickingMediaWithInfo) 미디어 타입과 파일의 url을 가지고 온다.
- 작업이 성공하면 원래 picker 창은 닫고 (dismiss) 해당 비디오를 AVPlayer를 통해 플레이어에서 보여준다. (present)
카메라로 동영상 촬영하기 (에뮬에서는 sourceType .camera는 실행안됨)
record and save 버튼에 startMediaBrowser 를 구현하는데 sourceType 은 .camera로 한다.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
@IBAction func actionSelectAndPlay(_ sender: Any) {
VideoHelper.startMediaBrowser(delegate: self, sourceType: .savedPhotosAlbum)
}
@IBAction func actionRecordAndSave(_ sender: Any) {
VideoHelper.startMediaBrowser(delegate: self, sourceType: .camera)
}
@IBAction func actionMerge(_ sender: Any) {
}
}
동영상 촬영 후 포토앨범에 저장하기
비디오를 선택하면 UIImagePickerControllerDelegate 가 호출된다. 해당 delegaate 에 아래의 코드를 작성한다.
그런데 photoLibrary 와 Camera 에 따라 다르게 처리할거니 switch 를 통해 분기처리한다.
extension ViewController : UIImagePickerControllerDelegate {
func imagePickerController(
_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]
) {
switch picker.sourceType {
case .photoLibrary:
// 1
guard
let mediaType = info[UIImagePickerController.InfoKey.mediaType] as? String,
mediaType == (kUTTypeMovie as String),
let url = info[UIImagePickerController.InfoKey.mediaURL] as? URL
else { return }
// 2
dismiss(animated: true) {
//3
let player = AVPlayer(url: url)
let vcPlayer = AVPlayerViewController()
vcPlayer.player = player
self.present(vcPlayer, animated: true, completion: nil)
}
case .camera:
dismiss(animated: true, completion: nil)
guard
let mediaType = info[UIImagePickerController.InfoKey.mediaType] as? String,
mediaType == (kUTTypeMovie as String),
// 1
let url = info[UIImagePickerController.InfoKey.mediaURL] as? URL,
// 2
UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(url.path)
else { return }
// 3
UISaveVideoAtPathToSavedPhotosAlbum(
url.path,
self,
#selector(video(_:didFinishSavingWithError:contextInfo:)),
nil)
default:
break
}
}
}
- 추가된 .camera 코드를 보면 카메라로 비디오가 녹화되고 비슷하게 해당 파일 url을 받는다. 그 파일을 PhotosAlbum에 저장한다.
- photoAlbum 에 저장되면 해당 비디오를 가지고 selector 에 지정된 함수를 실행한다.
동영상 포토엘범에 저장한 후 저장완료 띄우기
@objc func video(
_ videoPath: String,
didFinishSavingWithError error: Error?,
contextInfo info: AnyObject
) {
let title = (error == nil) ? "Success" : "Error"
let message = (error == nil) ? "Video was saved" : "Video failed to save"
let alert = UIAlertController(
title: title,
message: message,
preferredStyle: .alert)
alert.addAction(UIAlertAction(
title: "OK",
style: UIAlertAction.Style.cancel,
handler: nil))
present(alert, animated: true, completion: nil)
}
두개의 비디오와 음악 합치기
비디오와 음악은 AVAsset으로 변수에 할당할 수 있다.
합칠 음악과 비디오 2개의 변수를 추가한다.
var firstAsset: AVAsset?
var secondAsset: AVAsset?
var audioAsset: AVAsset?
그리고 각각 pick 할 버튼을 만들어 준다.
- picker 에서 비디오를 가져오는 메서드를 구현하고
- 가져온 비디오를 구분하기 위해 처음 선택된 비디오를 firstAsset 에 두번째 비디오를 secondAsset 에 할당한다.
지금까지 전체코드
//
// ViewController.swift
// AVFoundationPractice
//
// Created by TaeHyeong Kim on 2020/08/30.
// Copyright © 2020 TaeHyeong Kim. All rights reserved.
//
import UIKit
import AVKit
import MobileCoreServices
import MediaPlayer
import Photos
class ViewController: UIViewController {
var firstAsset: AVAsset?
var secondAsset: AVAsset?
var audioAsset: AVAsset?
var loadingAssetOne = false
var mergingVideo = false
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
@IBAction func actionSelectAndPlay(_ sender: Any) {
VideoHelper.startMediaBrowser(delegate: self, sourceType: .savedPhotosAlbum)
mergingVideo = false
}
@IBAction func actionRecordAndSave(_ sender: Any) {
VideoHelper.startMediaBrowser(delegate: self, sourceType: .camera)
}
@IBAction func actionMerge(_ sender: Any) {
}
@IBAction func actionLoadVid1(_ sender: Any) {
mergingVideo = true
VideoHelper.startMediaBrowser(delegate: self, sourceType: .savedPhotosAlbum)
}
@IBAction func actionLoadVid2(_ sender: Any) {
mergingVideo = true
VideoHelper.startMediaBrowser(delegate: self, sourceType: .savedPhotosAlbum)
}
@IBAction func actionLoadMusic(_ sender: Any) {
let mediaPickerController = MPMediaPickerController(mediaTypes: .any)
mediaPickerController.delegate = self
mediaPickerController.prompt = "Select Audio"
present(mediaPickerController, animated: true, completion: nil)
}
@objc func video(
_ videoPath: String,
didFinishSavingWithError error: Error?,
contextInfo info: AnyObject
) {
let title = (error == nil) ? "Success" : "Error"
let message = (error == nil) ? "Video was saved" : "Video failed to save"
let alert = UIAlertController(
title: title,
message: message,
preferredStyle: .alert)
alert.addAction(UIAlertAction(
title: "OK",
style: UIAlertAction.Style.cancel,
handler: nil))
present(alert, animated: true, completion: nil)
}
}
extension ViewController : UIImagePickerControllerDelegate {
func imagePickerController(
_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]
) {
switch picker.sourceType {
case .savedPhotosAlbum:
if mergingVideo {
dismiss(animated: true, completion: nil)
guard let mediaType = info[UIImagePickerController.InfoKey.mediaType] as? String,
mediaType == (kUTTypeMovie as String),
let url = info[UIImagePickerController.InfoKey.mediaURL] as? URL
else { return }
let avAsset = AVAsset(url: url)
var message = ""
if loadingAssetOne {
message = "Video one loaded"
firstAsset = avAsset
} else {
message = "Video two loaded"
secondAsset = avAsset
}
let alert = UIAlertController(
title: "Asset Loaded",
message: message,
preferredStyle: .alert)
alert.addAction(UIAlertAction(
title: "OK",
style: UIAlertAction.Style.cancel,
handler: nil))
present(alert, animated: true, completion: nil)
}else{
// 1
guard
let mediaType = info[UIImagePickerController.InfoKey.mediaType] as? String,
mediaType == (kUTTypeMovie as String),
let url = info[UIImagePickerController.InfoKey.mediaURL] as? URL
else { return }
// 2
dismiss(animated: true) {
//3
let player = AVPlayer(url: url)
let vcPlayer = AVPlayerViewController()
vcPlayer.player = player
self.present(vcPlayer, animated: true, completion: nil)
}
}
case .camera:
dismiss(animated: true, completion: nil)
guard
let mediaType = info[UIImagePickerController.InfoKey.mediaType] as? String,
mediaType == (kUTTypeMovie as String),
// 1
let url = info[UIImagePickerController.InfoKey.mediaURL] as? URL,
// 2
UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(url.path)
else { return }
// 3
UISaveVideoAtPathToSavedPhotosAlbum(
url.path,
self,
#selector(video(_:didFinishSavingWithError:contextInfo:)),
nil)
default:
break
}
}
}
extension ViewController : UINavigationControllerDelegate {
}
오디오 파일 선택하는 코드 구현
import MediaPlayer
@IBAction func actionLoadMusic(_ sender: Any) {
let mediaPickerController = MPMediaPickerController(mediaTypes: .any)
mediaPickerController.delegate = self
mediaPickerController.prompt = "Select Audio"
present(mediaPickerController, animated: true, completion: nil)
}
extension ViewController: MPMediaPickerControllerDelegate {
}
오디오 파일 선택 후 동작 delegate 에 구현
extension ViewController: MPMediaPickerControllerDelegate {
func mediaPicker(
_ mediaPicker: MPMediaPickerController,
didPickMediaItems mediaItemCollection: MPMediaItemCollection
) {
// 1
dismiss(animated: true) {
// 2
let selectedSongs = mediaItemCollection.items
guard let song = selectedSongs.first else { return }
// 3
let title: String
let message: String
if let url = song.value(forProperty: MPMediaItemPropertyAssetURL) as? URL {
self.audioAsset = AVAsset(url: url)
title = "Asset Loaded"
message = "Audio Loaded"
} else {
self.audioAsset = nil
title = "Asset Not Available"
message = "Audio Not Loaded"
}
// 4
let alert = UIAlertController(
title: title,
message: message,
preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
func mediaPickerDidCancel(_ mediaPicker: MPMediaPickerController) {
// 5
dismiss(animated: true, completion: nil)
}
}
이제 비디오 2개와 오디오 파일 1개 선택해서 불러오는 것 까지 했다.
다음 포스팅에서 합쳐보는걸로
728x90
'iOS' 카테고리의 다른 글
🎥 iOS 비디오에 Overlay와 Animation 추가하기 (0) | 2020.09.02 |
---|---|
🎥 iOS 비디오 재생, 녹화, 병합 튜토리얼 (2) (0) | 2020.09.01 |
iOS 영상편집 앱 개발을 위한 레퍼런스 모음 (0) | 2020.08.30 |
iOS 앱 이름 한국어 설정 (4) | 2020.08.29 |
[Alamofire_5] 이미지 업로드 예제 코드 (0) | 2020.08.28 |
댓글