티스토리 뷰
안녕하세요. 이번에 동영상 스트리밍 관련 앱 (like 틱톡, 릴스, 인스타 스토리)을 만들다가 정보가 너무 없거나 잘못된 게 많아서 직접 개발하며 알게 된 것들을 소개해보려고 합니다.
음 먼저 HLS라는건 동영상 스트리밍을 위한 Http Live Streaming의 약자로, 이름에서 알 수 있듯이 범용적인 http를 통해 비디오를 전송하는 비디오 스트리밍 프로토콜입니다.
애플에서 개발했지만 안드로이드나 타 서비스에서도 사용 가능합니다.
숏폼 동영상 플랫폼을 개발하기로 했는데, 숏폼 동영상이라는 특성상 연속적으로 기다림 없이 빠르게 재생을 해야 될 필요가 있었고 HLS는 네트워크 상황에 따라 스트리밍 중 비디오 품질을 조정하는 기능이 있어서 네트워크 상황이 나빠도 끊김 없이 연속적인 재생이 가능했기 때문에 해당 프로토콜로 개발을 하게 되었습니다.
스트리밍 자체는 뭔가 asset 같은걸 다운로드할 필요도 없고, 캐싱을 할 필요도 없기 때문에 앱에서 업로드한 동영상을 서버에서 m3u8 파일로 전환하여(m3u8은 미디어 파일의 위치를 나타내는 일종의 텍스트 파일) 텍스트를 내려주면(ex: ********.m3u8) 앱에서는 해당 텍스트를 URL 객체로 변환하여 AVPlayer에 넣어주기만 하면 스트리밍 재생이 가능합니다.
하지만 이렇게 구현할 경우 아래와 같이 기본적인 AVPlayer에서 동영상이 재생되게 됩니다.
우리가 원하는 앱은 이렇게 동영상만을 보여주는 것이 아니라 프로필을 표시한다던가 좋아요 버튼을 넣는다던가 제목을 넣는 등의 여러 가지 UI 또는 UX가 적용되어야 하기 때문에 이런 식으로 구현해서는 안 되겠죠?
이럴 때 동영상의 영역을 지정해서 딱 그 부분에서만 나올 수 있게, 그 외 나머지 부분에는 custom 한 UI 오브젝트들이 들어갈 수 있게 만들어 주는 것이 AVPlayerLayer입니다.
제가 만든 앱은 이것저것 엮여있는 게 많아서 전체적으로 상세하게 설명하려면 글이 너무 길어질 것 같아 핵심적인 부분만 언급하겠습니다.
1. 동영상이 재생될 영역을 잡기 위해 UIView를 상속한 CustomView를 만들고 해당 layer를 playerLayer로 변경한다.
2. 변경한 playerLayer에 동영상을 재생할 AVPlayer를 넣어준다.
3. play() 시킨다.
우선 동영상을 재생할 부분을 UIView로 영역을 잡아줍니다.
UIView에 class를 CustomVideoView로 지정해주고 지금부터 만들어보겠습니다.
class CustomVideoView: UIView {
override class var layerClass: AnyClass {
return AVPlayerLayer.self
}
}
UIView의 layerClass를 오버라이드 해서 뷰의 레이어를 AVPlayerLayer로 변경해줍니다.
var playerLayer: AVPlayerLayer {
let layer = layer as! AVPlayerLayer
layer.videoGravity = .resizeAspectFill
return layer
}
var player: AVPlayer? {
get {
return playerLayer.player
}
set {
playerLayer.player = newValue
}
}
연산 프로퍼티를 통해 현재 layer를 가져와 AVPlayerLayer로 캐스팅 후 반환하는 변수, 현재 PlayerLayer의 player를 새로 대입된 플레이어로 설정하는 변수를 선언합니다.
videoGravity는 영상의 비율을 결정하는 변수입니다.
이렇게 만든 CustomVideoView를 가지고, 저 같은 경우는 컬렉션 뷰를 사용하여 여러개의 동영상을 각각 하나의 셀에 대입을 했기 때문에 Cell을 만들고 안의 UI를 구성했습니다.(위의 스샷을 참고해주세요)
CustomVideoPlayer의 아웃렛 변수를 playerView라는 이름으로 셀에 선언해주고, 컬렉션뷰 델리게이트에서 셀을 구성할 때에
let playerItem = AVPlayerItem(url: videoUrl)
playerItem.preferredForwardBufferDuration = TimeInterval(1.0)
cell.playerView.player = AVPlayer(playerItem: playerItem)
cell.playerView.player?.play()
videoUrl(*******.m3u8)을 통해 AVPlayerItem을 만들어주고 해당 아이템으로 플레이어를 만들어 셀에 있는 플레이어에 넣어주고 플레이시키면 동영상이 재생됩니다.
playerItem의 preferredForwardBufferDuration는 스트리밍 재생을 하기 전에 최소 몇 초의 데이터를 받아올지 설정하는 변수인데, 0으로 설정하면 임의로 값이 설정되고 저는 1초만큼만 받아오면 바로 재생하도록 설정하였습니다.
이렇게 하면 간단하게 커스텀한 화면에서 동영상이 재생됩니다.
저처럼 컬렉션 뷰로 각 영상을 셀로 만들어 구현할 경우 필요에 맞게 화면 전환이나 반복 재생 같은 추가 처리 또한 가능합니다.
'iOS' 카테고리의 다른 글
[RxSwift] MVVM 구현을 위한 Input Output 패턴 (0) | 2022.09.16 |
---|---|
[iOS] RequestInterceptor를 이용한 JWT 인증 구현 (0) | 2021.12.02 |
[iOS] NSCache를 이용한 이미지 캐싱 (0) | 2021.07.12 |
iOS 아키텍처 패턴 MVVM (0) | 2021.06.22 |
[iOS] 비동기 API 호출 UnitTest 하는법 (0) | 2021.06.21 |
- Total
- Today
- Yesterday
- 앱개발 디자인패턴
- ios 이미지캐싱
- ios 패턴
- ios cache
- UserDefaultKey
- ios expectation
- UserDefaults
- NSCache
- 연산프로퍼티
- api호출 unittest
- UserDefault
- 비동기 유닛테스트
- @propertyWrapper
- 프로퍼티래퍼
- ios 디자인패턴
- SWIFT
- inputoutput패턴
- MVVM패턴
- ios 캐시
- rxswift안쓰고
- ios memory
- swift cache
- ios 캐시메모리
- 아키텍처패턴
- swift 캐싱
- swift mvvm
- ios 유닛테스트
- ios image caching
- wrappedValue
- rxswift 없이
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |