티스토리 뷰
2023.01.17 - [iOS개발/Swift 기본] - Swift 커스텀 동영상 플레이어 만들기
Swift 커스텀 동영상 플레이어 만들기
2023.01.13 - [iOS개발/Swift 기본] - Swift 기본 기능으로 동영상 플레이하기 Swift 기본 기능으로 동영상 플레이하기 이번에는 동영상에 대해 올려볼까 합니다. 이번편은 iOS에서 기본적으로 사용할 수
world-of-larooly.tistory.com
이 포스트는 전체 코드만 올려드립니다.
자세한 내용은 위를 참고해주세요.
extension AVPlayer{
var isPlaying: Bool {
return rate != 0 && error == nil
}
}
import Foundation
import UIKit
import AVFoundation
import AVKit
class CustomPlayerViewController : UIViewController {
@IBOutlet weak var totalBtnsView: UIView! // 전체 UIView
@IBOutlet weak var timeLineSlider: UISlider! // 시간 표시줄
@IBOutlet weak var timeLineLbl: UILabel! // 00:00 / 00:00
@IBOutlet weak var playBtn: UIButton! // 재생버튼
@IBOutlet weak var speedDisplayLbl: UILabel! // x n 배속
var moviePlayer : AVPlayer? // 비디오 재생 장치
let videoBackView = UIView() // 비디오가 재생되는 뷰
var UItimer : Timer? // UI 사라지는 시간 측정
var timeObserver : Any? // 영상 시간 조절기
var speedMode = 2 // 속도단계 표시기
override func viewDidLoad() {
super.viewDidLoad()
self.setVideoAnotherView()
self.setStartUIStatus() // 시작시 UI설정
}
func setStartUIStatus(){// 시작시 어색한 UI 미리 수정
totalBtnsView.isHidden = true // 처음 시작시 안보이게
timeLineLbl.text = "00:00 / 00:00"
timeLineSlider.value = 0.0
self.setSpeedModeWithLevel(level: 2) // 1배속 시작
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.setVideoView(url: self.getSavedVideoUrl())
self.resetUITimer()
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.toggleUIControls))
self.view.addGestureRecognizer(tapGesture)
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask{
return .landscape // 화면이 자동 회전하도록
}
@IBAction func closeViewAction(_ sender: Any) {
self.moviePlayer?.pause()
self.moviePlayer = nil
self.dismiss(animated: true)
}
func getSavedVideoUrl() -> URL {// 미리 저장된 영상 가져오기
var savedViedoUrl = URL(fileURLWithPath: Bundle.main.path(forResource: "BigBuckBunny", ofType: "mp4")!)
return savedViedoUrl
}
func getNetworkVideoUrl() -> URL {// 네트워크에서 영상 가져오기
return URL(string: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4")!
}
func setVideoView(url : URL){
moviePlayer = AVPlayer(url: url)
let playerLayer = AVPlayerLayer(player: moviePlayer)
playerLayer.frame = videoBackView.frame;
videoBackView.layer.addSublayer(playerLayer)
moviePlayer?.play()
setPlayBtnImage()
let interval = CMTime(seconds: 0.01, preferredTimescale: CMTimeScale(NSEC_PER_SEC))
timeObserver = moviePlayer?.addPeriodicTimeObserver(forInterval: interval, queue: DispatchQueue.main, using: { elapsedTime in
self.updateVideoPlayerSlider()
})
}
func setVideoAnotherView() {// 바탕 뷰 만들기
videoBackView.backgroundColor = UIColor.purple
videoBackView.translatesAutoresizingMaskIntoConstraints = false
let topConstraint = NSLayoutConstraint(item: videoBackView, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1, constant: 0)
let bottomConstraint = NSLayoutConstraint(item: videoBackView, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: 0)
let leadingConstraint = NSLayoutConstraint(item: videoBackView, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1, constant: 0)
let trailingConstraint = NSLayoutConstraint(item: videoBackView, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: 0)
view.addSubview(videoBackView)
view.sendSubviewToBack(videoBackView)
view.addConstraints([topConstraint, bottomConstraint, leadingConstraint, trailingConstraint])
}
//MARK: UI 타이머
func resetUITimer(){
UItimer?.invalidate()
UItimer = Timer.scheduledTimer(timeInterval: 5.0, target: self, selector: #selector(hideUIControls), userInfo: nil, repeats: false)
}
@objc func hideUIControls(){
totalBtnsView.isHidden = true
}
@objc func toggleUIControls(){
totalBtnsView.isHidden = !totalBtnsView.isHidden
self.resetUITimer()
}
//MARK: 영상이 진행되는 동안 할일
func updateVideoPlayerSlider() {// 타임라인에 연결할 함수입니다.
guard let currentTime = moviePlayer?.currentTime() else { return }
let currentTimeInSeconds = CMTimeGetSeconds(currentTime)
timeLineSlider.value = Float(currentTimeInSeconds)
if let currentItem = moviePlayer?.currentItem {
let duration = currentItem.duration
if (CMTIME_IS_INVALID(duration)) {
return;
}
let currentTime = currentItem.currentTime()
timeLineSlider.value = Float(CMTimeGetSeconds(currentTime) / CMTimeGetSeconds(duration))
}
self.setTimeLabel() // 시간 표시하기
}
func setTimeLabel(){
if(getVideoTotalTime() != nil && getVideoCurrentTime() != nil){
timeLineLbl.text = getVideoCurrentTime()! + " / " + getVideoTotalTime()!
}else{
timeLineLbl.text = "00:00 / 00:00"
}
}
func getVideoTotalTime() -> String? {// 전체시간 가져오기
let urlValue = self.getSavedVideoUrl()
let asset: AVAsset = AVAsset(url: urlValue)
let minute = Int(floor(asset.duration.seconds / 60))
let second = Int(asset.duration.seconds) % 60
return setTimeString(times: minute) + ":" + setTimeString(times: second)
}
func getVideoCurrentTime() -> String? {//현재 재생된 시간 가져오기
guard let timeValue = moviePlayer?.currentItem?.currentTime() else {return nil}
let minute = Int(floor(timeValue.seconds / 60))
let second = Int(timeValue.seconds) % 60
return setTimeString(times: minute) + ":" + setTimeString(times: second)
}
func setTimeString(times : Int) -> String {
if(times < 10){
return "0"+String(times)
}else{
return String(times)
}
}
//MARK: Slider 터치시
@IBAction func timeLineValueChanged(_ sender: Any) {
moviePlayer?.pause() // 일단 정지
guard let duration = moviePlayer?.currentItem?.duration else { return }
let value = Float64(timeLineSlider.value) * CMTimeGetSeconds(duration)
let seekTime = CMTime(value: CMTimeValue(value), timescale: 1)
moviePlayer?.seek(to: seekTime, completionHandler: {okay in
self.moviePlayer?.play() // 해당시간대로 이동이 가능하면 다시 플레이 시작
self.setPlayBtnImage()
self.setSpeedModeWithLevel(level: self.speedMode)
})
return
}
//MARK: play 여부에 따른 버튼 이미지 변화
@IBAction func clickPlayAction(_ sender: Any) {
if((self.moviePlayer?.isPlaying) ?? false){
self.moviePlayer?.pause()
}else{// 영상 정지시
self.moviePlayer?.play()
self.setSpeedModeWithLevel(level: self.speedMode)
}
self.setPlayBtnImage()
}
func setPlayBtnImage(){// 영상 플레이시
if((self.moviePlayer?.isPlaying) ?? false){
self.playBtn.setImage(UIImage(systemName: "pause.fill"), for: .normal)
}else{// 영상 정지시
self.playBtn.setImage(UIImage(systemName: "play.fill"), for: .normal)
}
}
//MARK: 영상 10초 전후 이동
@IBAction func goPlusVideoAction(_ sender: Any) {
self.setActionMoveSeconds(goSecond: 10.0)
}
@IBAction func goMinusVideoAction(_ sender: Any) {
self.setActionMoveSeconds(goSecond: -10.0)
}
func setActionMoveSeconds(goSecond : Double){
self.moviePlayer?.pause()
guard let currentTime = self.moviePlayer?.currentTime() else { return }
let currentTimeInSecondsMove = CMTimeGetSeconds(currentTime).advanced(by: goSecond) // 시간 계산
let seekTime = CMTime(value: CMTimeValue(currentTimeInSecondsMove), timescale: 1)
self.moviePlayer?.seek(to: seekTime, completionHandler: {okay in
self.moviePlayer?.play()
self.setPlayBtnImage()
self.setSpeedModeWithLevel(level: self.speedMode)
})
}
//MARK: 스피드 모드 제어
@IBAction func clickSpeedAction(_ sender: Any) {
switch speedMode{
case 1:
self.setSpeedModeWithLevel(level: 2)
case 2:
self.setSpeedModeWithLevel(level: 3)
case 3:
self.setSpeedModeWithLevel(level: 1)
default:
break
}
}
func setSpeedModeWithLevel(level: Int){
switch level{
case 1: // 0.5 배속
speedMode = 1
speedDisplayLbl.text = "x 0.5 배속"
self.moviePlayer?.playImmediately(atRate: 0.5)
break
case 2: // 1 배속
speedMode = 2
speedDisplayLbl.text = "x 1.0 배속"
self.moviePlayer?.playImmediately(atRate: 1.0)
break
case 3: // 2 배속
speedMode = 3
speedDisplayLbl.text = "x 2.0 배속"
self.moviePlayer?.playImmediately(atRate: 2.0)
break
default:
break
}
}
}
생각보다 많이 안 길죠?
오늘도 파이팅입니다.
'iOS개발 > Swift 기본' 카테고리의 다른 글
Swift 원형(Circle) progress 를 만들어보자 (0) | 2023.02.01 |
---|---|
Swift 키보드 이벤트 및 대응하기 (0) | 2023.01.27 |
Swift 커스텀 동영상 플레이어 만들기 (0) | 2023.01.17 |
Swift 기본 기능으로 동영상 플레이하기 (0) | 2023.01.13 |
Swift Data 저장하기 (Temp / Doc) + 확인하기 (0) | 2023.01.11 |
댓글