Skip to content

Commit

Permalink
Create 240821_HLS,_AVAssetResourceLoaderDelegate.md
Browse files Browse the repository at this point in the history
  • Loading branch information
leeari95 committed Aug 20, 2024
1 parent 57ac0d2 commit 0616c68
Showing 1 changed file with 229 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
# 240821 HLS, AVAssetResourceLoaderDelegate


์ŠคํŠธ๋ฆฌ๋ฐ ๋˜๊ณ  ์žˆ๋Š” ๋ฐฉ์†ก์ด ์ข…๋ฃŒ๋˜์—ˆ๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ์ธ์ง€ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•.


8์›” 21์ผ (์ˆ˜)


# ํ•™์Šต๋‚ด์šฉ

์ŠคํŠธ๋ฆฌ๋ฐ ์ค‘์ธ ๋ฐฉ์†ก์˜ ์ข…๋ฃŒ ์—ฌ๋ถ€๋ฅผ ์–ด๋–ป๊ฒŒ ํŒ๋‹จํ•  ์ˆ˜ ์žˆ์„๊นŒ?
์ผ๋‹จ HLS๋Š” ๋ญ”์ง€ ์ž˜... ๋ชจ๋ฅด๊ฒ ๋‹ค. ์•Œ์•„๋ณด์ž!

## HLS(HTTP Live Streaming)

* Apple์ด ๊ฐœ๋ฐœํ•œ ์ŠคํŠธ๋ฆฌ๋ฐ ํ”„๋กœํ† ์ฝœ
* ๋น„๋””์˜ค์™€ ์˜ค๋””์˜ค ์ฝ˜ํ…์ธ ๋ฅผ ์ธํ„ฐ๋„ท์„ ํ†ตํ•ด ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ „์†กํ•˜๊ธฐ ์œ„ํ•ด ์„ค๊ณ„๋˜์—ˆ์Œ.
* HLS๋Š” ํŠนํžˆ ๋Œ€๊ทœ๋ชจ ์‹œ์ฒญ์ž๋“ค์—๊ฒŒ ์•ˆ์ •์ ์ธ ์ŠคํŠธ๋ฆฌ๋ฐ ์„œ๋น„์Šค๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋„๋ก ์ตœ์ ํ™”๋˜์–ด ์žˆ์œผ๋ฉฐ ๋„คํŠธ์›Œํฌ ํ™˜๊ฒฝ์ด ๋‹ค์–‘ํ•  ๋•Œ์—๋„ ์œ ์—ฐํ•˜๊ฒŒ ๋™์ž‘ํ•จ.
* ํ˜„์žฌ ๋Œ€๋ถ€๋ถ„์˜ ํ”Œ๋žซํผ์—์„œ ์ง€์›๋˜๋ฉฐ, ํŠนํžˆ iOS, macOS ๊ธฐ๊ธฐ์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ง€์›ํ•จ.

### HLS ์ž‘๋™ ์›๋ฆฌ

* ๋ฏธ๋””์–ด ํŒŒ์ผ ๋ถ„ํ• 
* ์›๋ณธ ๋น„๋””์˜ค ํŒŒ์ผ์€ ์งง์€ ์กฐ๊ฐ(segment)์œผ๋กœ ๋ถ„ํ• ๋œ๋‹ค.
* ๊ฐ ์กฐ๊ฐ์€ ๋…๋ฆฝ์ ์ธ MPEG-TS(Transport Stream)ํŒŒ์ผ๋กœ ์ €์žฅ๋˜๋ฉฐ, ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์–ด๋–ค ์ˆœ์„œ๋กœ๋“  ์กฐ๊ฐ์„ ์š”์ฒญํ•˜๊ณ  ์žฌ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.
* ํ”Œ๋ ˆ์ด ๋ฆฌ์ŠคํŠธ ์ƒ์„ฑ
* HLS๋Š” ๋ฏธ๋””์–ด ์„ธ๊ทธ๋จผํŠธ๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด `m3u8` ํ™•์žฅ์ž๋ฅผ ๊ฐ€์ง„ ํ…์ŠคํŠธ ํŒŒ์ผ์ธ ํ”Œ๋ ˆ์ด ๋ฆฌ์ŠคํŠธ ํŒŒ์ผ์„ ์‚ฌ์šฉํ•œ๋‹ค.
* ์ด ํŒŒ์ผ์€ ์„ธ๊ทธ๋จผํŠธ์˜ URL๊ณผ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ํฌํ•จํ•˜๋ฉฐ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์–ด๋–ค ์„ธ๊ทธ๋จผํŠธ๋ฅผ ์žฌ์ƒํ• ์ง€ ๊ฒฐ์ •ํ•  ๋•Œ ์ฐธ๊ณ ํ•œ๋‹ค.
* ํด๋ผ์ด์–ธํŠธ ์š”์ฒญ
* ํด๋ผ์ด์–ธํŠธ(๋ธŒ๋ผ์šฐ์ € ๋˜๋Š” ์•ฑ)๋Š” ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ ํŒŒ์ผ์„ ๋‹ค์šด๋กœ๋“œํ•˜๊ณ  ๋ฏธ๋””์–ด ์„ธ๊ทธ๋จผํŠธ์˜ URL์„ ์ถ”์ถœํ•œ ํ›„ ์ˆœ์ฐจ์ ์œผ๋กœ ์„ธ๊ทธ๋จผํŠธ๋ฅผ ์š”์ฒญํ•˜์—ฌ ์žฌ์ƒํ•œ๋‹ค.
* ํด๋ผ์ด์–ธํŠธ๋Š” ๋„คํŠธ์›Œํฌ ์ƒํƒœ์— ๋”ฐ๋ผ ์ ์ ˆํ•œ ๋น„ํŠธ๋ ˆ์ดํŠธ์™€ ์ŠคํŠธ๋ฆผ์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋‹ค.
* ์‹ค์‹œ๊ฐ„ ์ ์šฉ
* ๋„คํŠธ์›Œํฌ ์กฐ๊ฑด์— ๋”ฐ๋ผ ํด๋ผ์ด์–ธํŠธ๋Š” ์ž๋™์œผ๋กœ ๋‹ค๋ฅธ ๋น„ํŠธ๋ ˆ์ดํŠธ์™€ ์ŠคํŠธ๋ฆผ์œผ๋กœ ์ „ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค.
* ๋„คํŠธ์›Œํฌ ์†๋„๊ฐ€ ๋Š๋ ค์ง€๋ฉด ํด๋ผ์ด์–ธํŠธ๋Š” ๋” ๋‚ฎ์€ ๋น„ํŠธ๋ ˆ์ดํŠธ์˜ ์ŠคํŠธ๋ฆผ์„ ์„ ํƒํ•˜์—ฌ ๋ฒ„ํผ๋ง์„ ์ตœ์†Œํ™”ํ•œ๋‹ค.


## HLS ๊ตฌ์กฐ

#### ๋ฏธ๋””์–ด ์„ธ๊ทธ๋จผํŠธ

๋ฏธ๋””์–ด ํŒŒ์ผ์€ ์ผ์ •ํ•œ ๊ธธ์ด์˜ ์„ธ๊ทธ๋จผํŠธ๋กœ ๋ถ„ํ• ํ•˜๋ฉฐ ๊ฐ ์„ธ๊ทธ๋จผํŠธ๋Š” ๋…๋ฆฝ์ ์œผ๋กœ ์ธ์ฝ”๋”ฉ๋˜์–ด ์žˆ๊ณ  ํด๋ผ์ด์–ธํŠธ๋Š” ์ด๋ฅผ ๊ฐœ๋ณ„์ ์œผ๋กœ ๋‹ค์šด๋กœ๋“œํ•˜๊ณ  ์žฌ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

* MPEG-TS (Transport Stream): HLS์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ฏธ๋””์–ด ํŒŒ์ผ ํฌ๋งท์œผ๋กœ, ๊ฐ๊ฐ์˜ ์„ธ๊ทธ๋จผํŠธ๋Š” ๋…๋ฆฝ์ ์ธ MPEG-TS ํŒŒ์ผ์ด๋‹ค. ์ด ํŒŒ์ผ ํฌ๋งท์€ ๋‚ฎ์€ ์˜ค๋ฒ„ํ—ค๋“œ์™€ ์‹ค์‹œ๊ฐ„ ์ „์†ก์— ์ ํ•ฉํ•˜๋‹ค.

#### ์žฌ์ƒ ๋ชฉ๋ก (playlist)

* .m3u8 ํŒŒ์ผ (ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ ํŒŒ์ผ): ์„ธ๊ทธ๋จผํŠธ์˜ ์œ„์น˜์™€ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ์„ค๋ช…ํ•˜๋Š” ํ…์ŠคํŠธ ํŒŒ์ผ์ด๋‹ค. ์ด ํŒŒ์ผ์€ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์–ด๋–ค ๋ฏธ๋””์–ด ํŒŒ์ผ์„ ์žฌ์ƒํ• ์ง€ ๊ฒฐ์ •ํ•˜๋Š” ๋ฐ ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•œ๋‹ค.

์žฌ์ƒ ๋ชฉ๋ก์˜ ์ข…๋ฅ˜๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค:

* Master Playlist: ์—ฌ๋Ÿฌ ๋ฒ„์ „(์˜ˆ: ๋‹ค์–‘ํ•œ ๋น„ํŠธ๋ ˆ์ดํŠธ, ํ•ด์ƒ๋„)์˜ ์ŠคํŠธ๋ฆผ์„ ์ œ๊ณตํ•  ๋•Œ ์‚ฌ์šฉ๋˜๋ฉฐ, ๊ฐ ์ŠคํŠธ๋ฆผ์˜ ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ ํŒŒ์ผ์— ๋Œ€ํ•œ ์ฐธ์กฐ๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.
* Media Playlist: ๊ฐ ๊ฐœ๋ณ„ ์ŠคํŠธ๋ฆผ(ํŠน์ • ๋น„ํŠธ๋ ˆ์ดํŠธ์™€ ํ•ด์ƒ๋„)์— ๋Œ€ํ•œ ์„ธ๊ทธ๋จผํŠธ ๋ฆฌ์ŠคํŠธ๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.

```m3u8
// ๋งˆ์Šคํ„ฐ ํ”Œ๋ ˆ์ด ๋ฆฌ์ŠคํŠธ ์˜ˆ์‹œ
#EXTM3U
#EXT-X-STREAM-INF:BANDWIDTH=1280000,RESOLUTION=640x360,CODECS="avc1.420029,mp4a.40.2"
http://example.com/low.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2560000,RESOLUTION=1280x720
http://example.com/mid.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=5120000,RESOLUTION=1920x1080
http://example.com/high.m3u8
```

```m3u8
// ๋ฏธ๋””์–ด ํ”Œ๋ ˆ์ด ๋ฆฌ์ŠคํŠธ ์˜ˆ์‹œ
#EXTM3U
#EXT-X-TARGETDURATION:10
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10.0,
http://example.com/segment0.ts
#EXTINF:10.0,
http://example.com/segment1.ts
#EXTINF:10.0,
http://example.com/segment2.ts
#EXTINF:10.0,
http://example.com/segment3.ts
#EXT-X-ENDLIST
```

### ํ”Œ๋ ˆ์ด ๋ฆฌ์ŠคํŠธ ํƒœ๊ทธ

* `#EXTM3U`: ํŒŒ์ผ์˜ ์‹œ์ž‘์„ ๋‚˜ํƒ€๋‚ด๋Š” ํƒœ๊ทธ.
* `#EXT-X-STREAM-INF`: ์ŠคํŠธ๋ฆผ ์ •๋ณด(๋น„ํŠธ๋ ˆ์ดํŠธ, ํ•ด์ƒ๋„ ๋“ฑ)๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ํƒœ๊ทธ.
* `#EXTINF`: ๊ฐ ์„ธ๊ทธ๋จผํŠธ์˜ ๊ธธ์ด๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ํƒœ๊ทธ.
* `#EXT-X-ENDLIST`: ์žฌ์ƒ ๋ชฉ๋ก์˜ ๋์„ ๋‚˜ํƒ€๋‚ด๋Š” ํƒœ๊ทธ.
* `BANDWIDTH`: ์ŠคํŠธ๋ฆผ์˜ ํ‰๊ท  ๋น„ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๋‚˜ํƒ€๋ƒ„(๋‹จ์œ„: bps)
* `RESOLUTION`: ๋น„๋””์˜ค ํ•ด์ƒ๋„
* `CODECS`: ๋น„๋””์˜ค์™€ ์˜ค๋””์˜ค ํŠธ๋ž™์˜ ์ฝ”๋ฑ์„ ๋ช…์‹œ.
* `#EXT-X-TARGETDURATION`: ๊ฐ ์„ธ๊ทธ๋จผํŠธ์˜ ์ตœ๋Œ€ ๊ธธ์ด๋ฅผ ์ง€์ •ํ•œ๋‹ค(์ดˆ ๋‹จ์œ„).
* `#EXT-X-VERSION`: ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ ํŒŒ์ผ์˜ HLS ๋ฒ„์ „
* `#EXT-X-MEDIA-SEQUENCE`: ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ์—์„œ ์ฒซ ๋ฒˆ์งธ ์„ธ๊ทธ๋จผํŠธ์˜ ์‹œํ€€์Šค ๋ฒˆํ˜ธ๋ฅผ ์ง€์ •ํ•œ๋‹ค.

์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ์ฝ”๋ฑ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค:

| **์†์„ฑ** | **avc1.420029, mp4a.40.2** | **avc1.4d401f, mp4a.40.2** |
|------------------------|----------------------------------------------------|-----------------------------------------------------|
| **๋น„๋””์˜ค ์ฝ”๋ฑ** | H.264/AVC | H.264/AVC |
| **๋น„๋””์˜ค ํ”„๋กœํŒŒ์ผ** | Baseline Profile (`42`) | Main Profile (`4d`) |
| **๋น„๋””์˜ค ๋ ˆ๋ฒจ** | Level 4.1 (`29`) | Level 3.1 (`1f`) |
| **์˜ค๋””์˜ค ์ฝ”๋ฑ** | MPEG-4 AAC (`mp4a`) | MPEG-4 AAC (`mp4a`) |
| **์˜ค๋””์˜ค ํ”„๋กœํŒŒ์ผ** | AAC LC (Low Complexity) (`40.2`) | AAC LC (Low Complexity) (`40.2`) |
| **์‚ฌ์šฉ ์‚ฌ๋ก€** | ์ €์ „๋ ฅ, ์ €๋Œ€์—ญํญ ์žฅ์น˜์— ์ ํ•ฉ (๋ชจ๋ฐ”์ผ ๊ธฐ๊ธฐ ๋“ฑ) | ๊ณ ํ™”์งˆ, ๊ณ ํ•ด์ƒ๋„ ๋น„๋””์˜ค ์žฌ์ƒ์— ์ ํ•ฉ (๋ฐ์Šคํฌํ†ฑ, TV ๋“ฑ)|

## HLS ์žฅ์ ๊ณผ ๋‹จ์ 

* ์žฅ์ 
* ๋Œ€๋ถ€๋ถ„์˜ ๊ธฐ๊ธฐ์™€ ๋ธŒ๋ผ์šฐ์ €์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ง€์›๋œ๋‹ค.
* ๋„คํŠธ์›Œํฌ ์ƒํƒœ์— ๋”ฐ๋ผ ์ŠคํŠธ๋ฆผ์˜ ๋น„ํŠธ๋ ˆ์ดํŠธ๋ฅผ ์ž๋™ ์กฐ์ ˆํ•˜๋ฉฐ ๋Š๊น€ ์—†์ด ์ŠคํŠธ๋ฆฌ๋ฐ์„ ์ฆ๊ธธ ์ˆ˜ ์žˆ๋‹ค.
* HLS๋Š” ์ฝ˜ํ…์ธ ๋ฅผ ์ž‘์€ ์„ธ๊ทธ๋จผํŠธ๋กœ ๋‚˜๋ˆ„์–ด ์ „์†กํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์„œ๋ฒ„๋Š” ๋‹ค์ˆ˜์˜ ํด๋ผ์ด์–ธํŠธ์— ํšจ๊ณผ์ ์œผ๋กœ ์ŠคํŠธ๋ฆผ์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋‹ค. ๋˜ํ•œ, CDN(Content Delivery Network)๊ณผ ์‰ฝ๊ฒŒ ํ†ตํ•ฉ๋˜์–ด ๋Œ€๊ทœ๋ชจ ๋ฐฐํฌ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.
* HLS๋Š” DRM(Digital Rights Management)๊ณผ ์•”ํ˜ธํ™”๋ฅผ ์ง€์›ํ•˜์—ฌ ์ฝ˜ํ…์ธ ๋ฅผ ๋ณดํ˜ธํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, Apple์˜ FairPlay ์ŠคํŠธ๋ฆฌ๋ฐ ๊ธฐ์ˆ ์„ ํ†ตํ•ด ๋น„๋””์˜ค ์ฝ˜ํ…์ธ ๋ฅผ ๋ณดํ˜ธํ•  ์ˆ˜ ์žˆ๋‹ค.
* ๋‹จ์ 
* HLS๋Š” ์„ธ๊ทธ๋จผํŠธ๋ฅผ ๋‹ค์šด๋กœ๋“œํ•˜๊ณ  ์žฌ์ƒํ•˜๋Š” ๋ฐฉ์‹์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ผ์ด๋ธŒ ์ŠคํŠธ๋ฆฌ๋ฐ์˜ ๊ฒฝ์šฐ ์ง€์—ฐ์‹œ๊ฐ„์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. ์„ธ๊ทธ๋จผํŠธ์˜ ๊ธธ์ด๊ฐ€ ๊ธธ์ˆ˜๋ก ์ง€์—ฐ ์‹œ๊ฐ„์ด ๋” ๊ธธ์–ด์งˆ ์ˆ˜ ์žˆ๋‹ค.
* ์ดˆ๊ธฐ ์žฌ์ƒ ์‹œ ์—ฌ๋Ÿฌ ์„ธ๊ทธ๋จผํŠธ๋ฅผ ๋ฏธ๋ฆฌ ๋กœ๋“œํ•ด์•ผ ํ•˜๋ฏ€๋กœ, ๋‹ค๋ฅธ ์ŠคํŠธ๋ฆฌ๋ฐ ํ”„๋กœํ† ์ฝœ์— ๋น„ํ•ด ์ดˆ๊ธฐ ๋ฒ„ํผ๋ง ์‹œ๊ฐ„์ด ๊ธธ์–ด์งˆ ์ˆ˜ ์žˆ๋‹ค.
* HLS๋Š” Apple์ด ๊ฐœ๋ฐœํ•œ ๊ธฐ์ˆ ๋กœ Apple ์ƒํƒœ๊ณ„์—์„œ์˜ ์ง€์›์ด ๊ฐ•๋ ฅํ•˜์ง€๋งŒ ์ผ๋ถ€ ํ”Œ๋žซํผ์—์„œ๋Š” ๋‹ค๋ฅธ ์ŠคํŠธ๋ฆฌ๋ฐ ํ”„๋กœํ† ์ฝœ(DASH)์ด ๋” ์„ ํ˜ธ๋  ์ˆ˜ ์žˆ๋‹ค.


#

์—ฌ๊ธฐ๊นŒ์ง€ HLS์— ๋Œ€ํ•ด์„œ ํ•œ๋ฒˆ ๊ฐ„๋‹จํžˆ ์•Œ์•„๋ณด์•˜๋‹ค.
๊ทธ๋ ‡๋‹ค๋ฉด iOS์—์„œ HLS๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์ŠคํŠธ๋ฆฌ๋ฐ์˜ ์ข…๋ฃŒ ์‹œ์ ์„ ๊ฐ์ง€ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์ž.

## ํƒœ๊ทธ๋ฅผ ํ™œ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•

HLS์—์„œ `m3u8` ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ์˜ ๋งˆ์ง€๋ง‰์— `#EXT-X-ENDLIST` ํƒœ๊ทธ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ๋Š” ๊ฒฝ์šฐ ์ŠคํŠธ๋ฆผ์ด ๋๋‚ฌ์Œ์„ ๋‚˜ํƒ€๋‚ผ ์ˆ˜ ์žˆ๋‹ค.

## HTTP ์ƒํƒœ ์ฝ”๋“œ ํ™œ์šฉํ•˜๊ธฐ

HLS ์ŠคํŠธ๋ฆฌ๋ฐ์—์„œ ์„œ๋ฒ„๊ฐ€ ๋ผ์ด๋ธŒ ์ŠคํŠธ๋ฆฌ๋ฐ์˜ ์ข…๋ฃŒ๋ฅผ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์•Œ๋ฆฌ๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜๋‹ค.

์ŠคํŠธ๋ฆฌ๋ฐ์ด ์ข…๋ฃŒ๋˜๋ฉด HTTP ์ƒํƒœ ์ฝ”๋“œ(์˜ˆ: 404, 410)์„ ๋ฐ˜ํ™˜ํ•˜์—ฌ ์ŠคํŠธ๋ฆฌ๋ฐ์ด ๋”์ด์ƒ ์ œ๊ณต๋˜์ง€ ์•Š์Œ์„ ์•Œ๋ ค์ค„ ์ˆ˜ ์žˆ๋‹ค.

์ŠคํŠธ๋ฆฌ๋ฐ์ด ์ข…๋ฃŒ๋˜๋ฉด ์„œ๋ฒ„๊ฐ€ ๋”์ด์ƒ ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ๋ฅผ ์ œ๊ณตํ•˜์ง€ ์•Š์œผ๋ฉฐ, ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์š”์ฒญ์„ ๋ณด๋‚ผ๋•Œ 404 ์˜ค๋ฅ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ๋œ๋‹ค.

## AVAssetResourceLoaderDelegate ์‚ฌ์šฉ

iOS์—์„œ ์œ„์™€ ๊ฐ™์ด ํƒœ๊ทธ๋‚˜ HTTP ์ƒํƒœ ์ฝ”๋“œ๋ฅผ ํ™œ์šฉํ•ด ๋ผ์ด๋ธŒ ์ŠคํŠธ๋ฆผ์ด ์ข…๋ฃŒ๋จ์„ ๊ฐ์ง€ํ•˜๋ ค๋ฉด AVPlayer์™€ ๊ด€๋ จ๋œ ๋„คํŠธ์›Œํฌ ์š”์ฒญ์„ ๋ชจ๋‹ˆํ„ฐ๋งํ•ด์•ผ ํ•œ๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ AVPlayer๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ ๋„คํŠธ์›Œํฌ ์š”์ฒญ์„ ๊ด€๋ฆฌํ•˜๋ฏ€๋กœ ์ง์ ‘์ ์œผ๋กœ HTTP ์ƒํƒœ ์ฝ”๋“œ๋ฅผ ํ™•์ธํ•˜๋Š” ๊ฒƒ์€ ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์ง€๋งŒ, AVAssetResourceLoaderDelegate๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋„คํŠธ์›Œํฌ ์š”์ฒญ์„ ๊ฐ€๋กœ์ฑ„๊ณ  HTTP ์‘๋‹ต์„ ๋ถ„์„ํ•  ์ˆ˜ ์žˆ๋‹ค.

์•„๋ž˜๋Š” ๊ตฌํ˜„ ์˜ˆ์‹œ์ด๋‹ค:

```swift
class StreamResourceLoaderDelegate: NSObject, AVAssetResourceLoaderDelegate {

func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool {

guard let url = loadingRequest.request.url else {
return false
}

// ํ”Œ๋ ˆ์ด๋ฆฌ์ŠคํŠธ ํŒŒ์ผ์„ ์š”์ฒญํ•˜๋Š” ๊ฒฝ์šฐ์—๋งŒ ์ฒ˜๋ฆฌ
if url.absoluteString.hasSuffix(".m3u8") {
let request = URLRequest(url: url)

let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let httpResponse = response as? HTTPURLResponse {
// HTTP ์ƒํƒœ ์ฝ”๋“œ ํ™•์ธ
if httpResponse.statusCode == 404 || httpResponse.statusCode == 410 {
print("Stream has ended with status code: \(httpResponse.statusCode)")
// ์—ฌ๊ธฐ์„œ ์ŠคํŠธ๋ฆฌ๋ฐ ์ข…๋ฃŒ๋ฅผ ์ฒ˜๋ฆฌ
loadingRequest.finishLoading(with: URLError(.badServerResponse))
} else if let data = data {
// ์ •์ƒ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์‹ ํ•œ ๊ฒฝ์šฐ
// ์—ฌ๊ธฐ์„œ ํƒœ๊ทธ๋ฅผ ๋ถ„์„ํ•ด๋ณผ ์ˆ˜ ์žˆ๋‹ค.
loadingRequest.dataRequest?.respond(with: data)
loadingRequest.finishLoading()
}
} else if let error = error {
// ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ ์ฒ˜๋ฆฌ
print("Error loading resource: \(error)")
loadingRequest.finishLoading(with: error)
}
}
task.resume()

return true
}

return false
}
}

```


์ดํ›„ AVURLAssets์„ ์ƒ์„ฑํ•  ๋•Œ `resourceLoader.delegate`๋ฅผ ์„ค์ •ํ•˜์—ฌ ๋ชจ๋“  ๋ฆฌ์†Œ์Šค ๋กœ๋”ฉ ์š”์ฒญ์ด ํ•ด๋‹น delegate๋ฅผ ํ†ตํ•ด ์ฒ˜๋ฆฌ๋˜๋„๋ก ํ•œ๋‹ค.

```swift
// ์ŠคํŠธ๋ฆฌ๋ฐ URL ์„ค์ • (https๋ฅผ customscheme์œผ๋กœ ๋ณ€๊ฒฝ)
guard let url = URL(string: "https://example.com/live/playlist.m3u8") else { return }

// URL์˜ ์Šคํ‚ด์„ "customscheme"์œผ๋กœ ๋ณ€๊ฒฝ
var components = URLComponents(url: url, resolvingAgainstBaseURL: false)
components?.scheme = "customscheme"

guard let customSchemeURL = components?.url else { return }

// AVURLAsset ์ƒ์„ฑ ๋ฐ delegate ์„ค์ •
let asset = AVURLAsset(url: customSchemeURL)
asset.resourceLoader.setDelegate(resourceLoaderDelegate, queue: DispatchQueue.main)

// AVPlayerItem ์ƒ์„ฑ
let playerItem = AVPlayerItem(asset: asset)
```

์—ฌ๊ธฐ์„œ ์Šคํ‚ด์„ ์ž„์˜๋กœ ๋ณ€๊ฒฝํ•˜๊ณ  ์žˆ๋Š”๋ฐ, ๊ทธ ์ด์œ ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค:

* `http`, `https` ์Šคํ‚ด์„ ์‚ฌ์šฉํ•˜๋ฉด `AVPlayer`, `AVURLAsset`์ด ์‹œ์Šคํ…œ์˜ ํ‘œ์ค€ ๋„คํŠธ์›Œํฌ ์Šคํƒ์„ ํ†ตํ•ด ๋ฆฌ์†Œ์Šค๋ฅผ ๋กœ๋“œํ•œ๋‹ค.
* ์ฆ‰ `AVAssetResourceLoaderDelegate`๊ฐ€ ๊ฐœ์ž…ํ•˜์ง€ ์•Š๊ณ  ์‹œ์Šคํ…œ์ด ์ง์ ‘ URL ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.
* `AVAssetResourceLoaderDelegate`๋Š” ์ฃผ๋กœ ๋น„ํ‘œ์ค€ ์Šคํ‚ด์ด๋‚˜ DRM ๋ณดํ˜ธ๋œ ์ฝ˜ํ…์ธ ์ฒ˜๋Ÿผ ์‹œ์Šคํ…œ์ด ๊ธฐ๋ณธ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š๋Š” ๋ฆฌ์†Œ์Šค ๋กœ๋”ฉ์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„๋˜์—ˆ๋‹ค.

๋”ฐ๋ผ์„œ `http`, `https` ์Šคํ‚ด์„ ์‚ฌ์šฉํ•˜๋ฉด `AVFoundation`์ด ๋„คํŠธ์›Œํฌ ์š”์ฒญ์„ ์ง์ ‘ ์ฒ˜๋ฆฌํ•˜๋ฏ€๋กœ, ์ปค์Šคํ…€ ์Šคํ‚ด์„ ํ†ตํ•ด `AVAssetResourceLoaderDelegate`๋ฅผ ํ†ตํ•ด ๋„คํŠธ์›Œํฌ ์š”์ฒญ์„ ๊ฐ€๋กœ์ฑ„๊ฑฐ๋‚˜ ์ฒ˜๋ฆฌํ•˜๋„๋ก ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

---


# ์ฐธ๊ณ  ๋งํฌ

- [https://developer.apple.com/documentation/avfoundation/avassetresourceloaderdelegate](https://developer.apple.com/documentation/avfoundation/avassetresourceloaderdelegate)
- [https://developer.apple.com/documentation/http-live-streaming](https://developer.apple.com/documentation/http-live-streaming)
- [https://developer.apple.com/documentation/http-live-streaming/live-playlist-sliding-window-construction](https://developer.apple.com/documentation/http-live-streaming/live-playlist-sliding-window-construction)
- [https://developer.apple.com/documentation/http-live-streaming/video-on-demand-playlist-construction](https://developer.apple.com/documentation/http-live-streaming/video-on-demand-playlist-construction)

0 comments on commit 0616c68

Please sign in to comment.