StreamLive와 StreamPackage로 SSAI 구성하기
Tencent Cloud의 Stream 시리즈에서 SSAI를 구현하려면 StreamLive와 StreamPackage가 각각 다른 역할을 맡습니다. StreamLive는 SCTE-35 신호를 처리하고 출력에 광고 마커를 심는 역할을 맡고, StreamPackage는 그 마커를 바탕으로 매니페스트를 조작하고 광고를 삽입하는 역할을 맡습니다.
들어가기 전에
Tencent Cloud에서는 StreamLive가 인코딩+SCTE-35 처리, StreamPackage가 패키징+오리진+SSAI를 겸합니다. 별도의 독립 SSAI 서비스는 없고, StreamPackage 안에 SSAI 기능이 내장되어 있습니다.
이 글에서는 StreamLive와 StreamPackage 콘솔의 SSAI 관련 옵션을 하나하나 뜯어봅니다.
StreamLive의 SCTE-35 처리
입력 측: SCTE-35 수신
StreamLive는 MPEG-2 TS 기반 입력(RTP_PUSH, UDP_PUSH, SRT_PUSH)에서 SCTE-35 메시지를 수신할 수 있습니다.
| 입력 타입 | SCTE-35 지원 | 비고 |
|---|---|---|
| RTP_PUSH | ✓ | TS 내 전용 PID로 전달 |
| UDP_PUSH | ✓ | 동일 |
| SRT_PUSH | ✓ | TS over SRT |
| RTMP_PUSH | △ | AMF Data Tag로 제한적 전달 |
| HLS_PULL | △ | 매니페스트 태그 기반 |
풀 스펙 SCTE-35를 쓰려면 TS 기반 입력이 필수입니다. RTMP로 AMF에 광고 마커를 실어 보내는 것도 가능하긴 하지만, splice_insert의 모든 필드를 담기엔 AMF가 좁습니다.
출력 측: SCTE-35 패스스루와 Ad Marker 설정
StreamLive 채널의 Output Group 설정에서 SCTE-35를 어떻게 처리할지 결정합니다.
콘솔 경로:
StreamLive Console → Channels → [채널 선택] → Output Groups → [Output Group 선택] → Output SettingsSCTE-35 관련 옵션:
| 옵션 | 값 | 설명 |
|---|---|---|
| Scte35 Source | SEGMENTS / MANIFEST | SCTE-35를 세그먼트 안에 넣을지, 매니페스트 태그로 넣을지 |
| Ad Marker Type | NONE / SCTE35_ENHANCED / ELEMENTAL / ADOBE | HLS 출력 시 Ad Marker를 어떤 형태로 변환할지 |
| Passthrough | ON / OFF | 입력의 SCTE-35 바이너리를 그대로 출력에 전달 |
Ad Marker Type 상세:
| 타입 | 출력 형태 | 설명 |
|---|---|---|
NONE | 마커 없음 | SCTE-35를 출력에 포함하지 않음 |
SCTE35_ENHANCED | #EXT-X-DATERANGE | Apple 권장 표준. SCTE-35 바이너리를 DATERANGE에 삽입 |
ELEMENTAL | #EXT-X-CUE-OUT / #EXT-X-CUE-IN | 업계 관행. 비표준이지만 호환성 높음 |
ADOBE | #EXT-X-CUE | Adobe Primetime 호환 형태 |
출력 타입이 HLS_STREAM_PACKAGE 또는 DASH_STREAM_PACKAGE일 때, SCTE-35 정보가 StreamPackage로 전달되어 SSAI의 트리거가 됩니다.
StreamLive 채널 생성 시 전체 SCTE-35 관련 설정 흐름
1. Input 생성: TS 기반 프로토콜 선택 (SRT_PUSH 권장)
2. Channel 생성:
- Input Attachment: 위 Input 연결
- Output Group 추가: Type = HLS_STREAM_PACKAGE
- Output Settings:
- Scte35 Source: SEGMENTS
- Ad Marker: SCTE35_ENHANCED
- Segment Duration: 6s
- Segment Prefix: live/channel_001 ← StreamPackage에서 경로로 사용됨
3. Channel StartSegment Prefix
Output Settings에서 Segment Prefix는 StreamPackage가 세그먼트를 식별하는 경로 prefix입니다.
Segment Prefix: live/event_001/main
→ 생성되는 세그먼트 경로:
live/event_001/main/segment_00001.ts
live/event_001/main/segment_00002.ts
...이 prefix가 StreamPackage의 Input URL과 매칭되어야 스트림이 연결됩니다.
StreamPackage의 SSAI 기능
StreamPackage 콘솔은 크게 네 가지 관리 영역으로 나뉩니다:
StreamPackage Console
├── Channel Management
│ ├── Channel (입력 수신 + Endpoint 관리)
│ └── Endpoint (출력 프로토콜 + SSAI 설정)
├── Content Source
│ └── VOD 소재 등록 (Slate, Ad 소재)
├── Linear Assembly
│ ├── Channel Assembly (FAST 채널)
│ ├── Program (편성 단위)
│ └── Schedule (편성표)
└── SSAI Configuration
├── Ad Insertion (ADS 연동)
├── Slate Management
└── Session / PersonalizationChannel 생성
콘솔 경로:
StreamPackage Console → Channel Management → Create Channel옵션:
| 필드 | 설명 |
|---|---|
| Channel Name | 채널 식별자 |
| Input Protocol | HLS / DASH (StreamLive Output과 매칭) |
| Input URL | 자동 생성됨. StreamLive의 Output Destination에 이 URL을 넣어야 함 |
| Description | 설명 |
채널 생성 후 Input URL이 발급됩니다:
https://ap-singapore.streampackage.tencentcloud.com/v1/channels/{channel_id}/ingest이 URL을 StreamLive의 Output Group → Destination에 설정합니다.
Endpoint 설정
Endpoint는 시청자에게 나가는 출구입니다. 하나의 Channel에 여러 Endpoint를 붙일 수 있습니다.
콘솔 경로:
Channel Management → [채널 선택] → Endpoints → Create Endpoint기본 옵션:
| 필드 | 값 | 설명 |
|---|---|---|
| Endpoint Name | 식별자 | |
| Endpoint Type | HLS / DASH / CMAF | 출력 프로토콜 |
| Segment Duration | 초 | 세그먼트 길이. 본편과 동일하게 유지 |
| Playlist Window | 초 | 매니페스트에 유지할 세그먼트 시간 |
| SSAI | ENABLED / DISABLED | 이 Endpoint에 SSAI 적용 여부 |
하나의 채널에 "SSAI ON Endpoint"와 "SSAI OFF Endpoint"를 동시에 운영할 수 있습니다. 무료 티어(광고 있음)와 유료 티어(광고 없음)를 같은 소스에서 분기할 때 유용합니다.
SSAI 활성화 시 추가 옵션:
| 필드 | 설명 |
|---|---|
| Ad Decision Server URL | ADS 엔드포인트 |
| Slate Source | Avail을 채우지 못했을 때 보여줄 대기 콘텐츠 |
| Personalization Threshold | 개인화 응답 대기 시간 (ms) |
| Live Pre-roll | 세션 시작 시 프리롤 활성화 여부 |
| Avail Suppression | DVR 구간에서 광고 억제 정책 |
| Segment Prefix Override | SSAI 세그먼트 URL prefix 커스터마이징 |
| CDN Configuration | CSS CDN 연동 설정 |
Session Initialization
클라이언트가 재생을 시작할 때 SSAI 세션을 생성하는 과정.
요청:
curl -X POST "https://ap-singapore.streampackage.tencentcloud.com/v1/sessions" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{
"channel_id": "ch_abc123",
"endpoint_id": "ep_def456",
"player_params": {
"device_type": "mobile",
"os": "iOS",
"app_version": "3.2.1",
"user_segment": "premium",
"geo": "KR"
},
"ad_params": {
"iu": "/1234/sports/live",
"cust_params": "genre=sports&team=seoul"
}
}'응답:
{
"session_id": "sess_789xyz",
"manifest_url": "https://ap-singapore.streampackage.tencentcloud.com/v1/sessions/sess_789xyz/manifest.m3u8",
"tracking_url": "https://ap-singapore.streampackage.tencentcloud.com/v1/sessions/sess_789xyz/tracking",
"expires_at": "2026-06-01T12:00:00Z"
}| 응답 필드 | 설명 |
|---|---|
session_id | 세션 고유 ID. 이후 모든 요청에 포함됨 |
manifest_url | 이 세션 전용 매니페스트 URL. 여기에 개인화된 광고가 삽입됨 |
tracking_url | Client-Side Beacon 발사 시 사용할 트래킹 엔드포인트 |
expires_at | 세션 만료 시각. 만료 후 새 세션 필요 |
클라이언트는 manifest_url로 재생을 시작합니다. 이 URL로 오는 매니페스트에는 해당 세션의 ADS 결과가 반영된 광고 세그먼트가 포함됩니다.
player_params → ADS 호출 시 전달:
Session Init에서 전달된 player_params와 ad_params는 StreamPackage가 ADS를 호출할 때 URL 매크로로 치환됩니다:
ADS URL 템플릿:
https://ads.example.com/vast?device=[player_params.device_type]&geo=[player_params.geo]&iu=[ad_params.iu]&cust_params=[ad_params.cust_params]
실제 호출:
https://ads.example.com/vast?device=mobile&geo=KR&iu=/1234/sports/live&cust_params=genre%3Dsports%26team%3DseoulAd Decision Server (ADS) 설정
콘솔 경로:
Endpoint → SSAI Configuration → Ad Decision Server옵션:
| 필드 | 설명 |
|---|---|
| ADS URL | Ad Decision Server 엔드포인트. 매크로 변수 포함 가능 |
| VAST Version | 지원 VAST 버전 (2.0 / 3.0 / 4.x) |
| Timeout | ADS 응답 대기 시간 (ms). 기본 3000ms |
| Fill Policy | ADS 실패/타임아웃 시 처리: SLATE / CONTENT (본편 유지) |
| Max Ad Duration | 단일 광고 최대 길이. 초과 시 자름 |
ADS URL 매크로 변수:
| 변수 | 설명 |
|---|---|
[session.id] | SSAI 세션 ID |
[avail.duration] | SCTE-35 Avail 길이 (초) |
[avail.start_time] | Avail 시작 시각 |
[player_params.*] | Session Init에서 전달된 커스텀 파라미터 |
[ad_params.*] | Session Init에서 전달된 광고 파라미터 |
[scte35.binary] | SCTE-35 원본 바이너리 (hex) |
[random] | 캐시 버스팅용 랜덤 값 |
예시 ADS URL:
https://pubads.g.doubleclick.net/gampad/ads?iu=[ad_params.iu]&sz=640x480&impl=s&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1&correlator=[random]&cust_params=[ad_params.cust_params]&vad_type=linear&vpos=preroll&pod_dur=[avail.duration]Slate Management (대기 화면)
Avail을 광고로 채우지 못했을 때 보여줄 Slate 설정.
콘솔 경로:
StreamPackage Console → Content Source → Create Source → Type: Slate옵션:
| 필드 | 설명 |
|---|---|
| Slate Name | 식별자 |
| Source URL | 사전 트랜스코딩된 Slate HLS/DASH URL |
| Duration | Slate 콘텐츠 길이 (루프 재생됨) |
Slate는 반드시 본편과 동일한 스펙(코덱, 해상도, 세그먼트 길이)으로 사전 준비해야 합니다. 포맷 불일치 시 전환 순간에 디코더 리셋이 발생합니다.
#### Slate 소재를 Content Source로 등록
curl -X POST "https://ap-singapore.streampackage.tencentcloud.com/v1/content-sources" \
-H "Authorization: Bearer $TOKEN" \
-d '{
"name": "default-slate",
"type": "SLATE",
"hls_source": {
"url": "https://assets.example.com/slate/playlist.m3u8"
},
"description": "Default slate - Coming back soon"
}'Content Source (콘텐츠 소스)
Content Source는 두 가지 용도로 사용됩니다:
| 용도 | 설명 |
|---|---|
| Slate | 광고 미충전 시 대기 화면 |
| VOD Asset | Channel Assembly(FAST 채널)에서 사용할 VOD 콘텐츠 |
VOD Content Source 등록:
curl -X POST "https://ap-singapore.streampackage.tencentcloud.com/v1/content-sources" \
-H "Authorization: Bearer $TOKEN" \
-d '{
"name": "movie-001",
"type": "VOD",
"hls_source": {
"url": "https://vod.example.com/movies/001/master.m3u8"
},
"dash_source": {
"url": "https://vod.example.com/movies/001/manifest.mpd"
},
"duration_seconds": 5400
}'옵션:
| 필드 | 설명 |
|---|---|
| Source Type | SLATE / VOD |
| HLS Source URL | HLS 매니페스트 URL |
| DASH Source URL | DASH MPD URL (선택) |
| Duration | 콘텐츠 길이 (초) |
| SCTE Markers | VOD 내 SCTE-35 마커 위치 (Mid-roll 지점) |
Avail Suppression (광고 구간 억제)
특정 조건에서 광고 삽입을 하지 않도록 억제.
콘솔 경로:
Endpoint → SSAI Configuration → Avail Suppression옵션:
| 필드 | 값 | 설명 |
|---|---|---|
| Mode | OFF | 억제 안 함. 모든 Avail에 광고 삽입 |
BEHIND_LIVE_EDGE | DVR 구간(라이브 엣지 뒤)에서는 광고 미삽입 | |
AFTER_LIVE_EDGE | 미래 예약된 광고를 억제 | |
| Fill Policy | SLATE / CONTENT_PASSTHROUGH | 억제된 구간을 Slate로 채울지, 본편을 그대로 흘릴지 |
BEHIND_LIVE_EDGE 시나리오: 라이브 시청 시에는 광고를 보여주지만, DVR로 되감아 볼 때는 광고 없이 본편만 재생합니다. "라이브 때 못 본 사람은 광고 안 보고 본편만 보게 해준다"는 정책입니다.
Live Pre-roll
시청자가 스트림에 처음 접속할 때 본편 시작 전에 광고를 삽입.
옵션:
| 필드 | 설명 |
|---|---|
| Enable | ON / OFF |
| Max Duration | 프리롤 최대 길이 (초). 보통 15~30초 |
| ADS URL | 프리롤 전용 ADS (메인 ADS와 다를 수 있음) |
| Timeout | 프리롤 ADS 응답 대기 (ms). 초과 시 바로 본편 시작 |
SCTE-35 마커가 없어도 동작합니다. 세션 시작 시점에 무조건 ADS를 호출해서 프리롤 광고를 가져옵니다.
시청자 접속 → Session Init → Pre-roll ADS 호출 → 광고 15초 → 본편 라이브 엣지 합류Personalization (개인화)
옵션:
| 필드 | 설명 |
|---|---|
| Dynamic Variables | Session Init에서 전달받는 커스텀 변수 정의 |
| CDN Token Auth | CDN 인증 토큰을 세그먼트 URL에 포함할지 |
| Bumper | 광고 전후에 삽입할 범퍼 URL |
| Bumper Duration | 범퍼 길이 (초) |
Bumper는 "광고 후 돌아옵니다" 또는 브랜드 로고 애니메이션 같은 짧은 클립입니다. Avail 시작/끝에 자동 삽입됩니다.
CSS CDN 연동
StreamPackage의 Endpoint URL을 CSS CDN의 Pull Domain Origin으로 설정하면 CDN 배포가 연동됩니다.
연동 구조:
StreamPackage Endpoint URL
↓ (Origin)
CSS Pull Domain (CDN 배포)
↓
시청자설정 방법:
- StreamPackage Endpoint 생성 후 Endpoint URL 확인:
https://ap-singapore.streampackage.tencentcloud.com/v1/sessions/{session_id}/manifest.m3u8- CSS Console → Domain Management → Pull Domain → Origin Configuration:
Origin Type: Custom Origin
Origin URL: StreamPackage Endpoint URL
Protocol: HTTPS- 시청자는 CSS Pull Domain으로 접근:
https://pull.example.com/live/manifest.m3u8?session_id=xxxSegment Prefix와 CDN 경로:
StreamLive에서 설정한 Segment Prefix가 CDN URL 경로에 그대로 반영됩니다:
StreamLive Segment Prefix: live/sports/main
→ CDN URL: https://pull.example.com/live/sports/main/segment_001.tsSSAI가 활성화된 세션에서는 광고 세그먼트도 동일한 도메인/경로 패턴으로 프록시되므로, 클라이언트나 광고 차단기가 구분할 수 없습니다:
본편: https://pull.example.com/v1/sessions/sess_001/live/seg_098.ts
광고: https://pull.example.com/v1/sessions/sess_001/live/seg_099.ts ← 실제로는 광고Tracking & Beacon
StreamPackage의 SSAI에서 Beacon(광고 추적) 처리 방식:
Server-Side Tracking (기본):
StreamPackage가 광고 재생 시점을 추적해서 직접 Beacon을 발사:
광고 세그먼트 시작 → impression beacon fire
25% 재생 → firstQuartile beacon fire
50% 재생 → midpoint beacon fire
...Client-Side Tracking (선택):
Session Init 응답에 포함된 tracking_url로 클라이언트가 직접 Beacon을 발사하는 방식도 지원합니다:
#### 클라이언트가 광고 재생 진행률을 보고
curl -X POST "https://ap-singapore.streampackage.tencentcloud.com/v1/sessions/sess_789xyz/tracking" \
-d '{
"event": "impression",
"ad_id": "ad_001",
"timestamp": "2026-06-01T10:30:00Z"
}'Channel Assembly (FAST 채널)
라이브 소스 없이 VOD 콘텐츠를 편성해 24시간 라이브처럼 돌리는 기능.
콘솔 경로:
StreamPackage Console → Linear Assembly → Create Channel Assembly구성 요소:
| 개념 | 설명 |
|---|---|
| Linear Channel | 편성표 기반으로 운영되는 가상 라이브 채널 |
| Program | 편성표의 단위. 시작 시간 + Content Source |
| Schedule | Program의 시간순 나열 |
| Filler | Schedule에 빈 시간이 있을 때 채울 콘텐츠 |
| Ad Break | Program 사이 또는 VOD 내 SCTE-35 마커 지점에 삽입되는 광고 구간 |
Schedule 생성 예시:
curl -X POST "https://ap-singapore.streampackage.tencentcloud.com/v1/linear-assemblies/{assembly_id}/schedules" \
-H "Authorization: Bearer $TOKEN" \
-d '{
"programs": [
{
"content_source_id": "cs_movie_001",
"start_time": "2026-06-01T10:00:00Z",
"ad_breaks": [
{"offset_ms": 600000, "duration_seconds": 60},
{"offset_ms": 1800000, "duration_seconds": 30}
]
},
{
"content_source_id": "cs_movie_002",
"start_time": "2026-06-01T11:30:00Z",
"ad_breaks": [
{"offset_ms": 900000, "duration_seconds": 60}
]
}
],
"filler_source_id": "cs_filler_default"
}'Channel Assembly에도 SSAI를 적용할 수 있습니다. ad_breaks에 정의된 지점에서 ADS를 호출해 광고를 삽입합니다.
전체 흐름 정리
인코더: SCTE-35 삽입
↓ TS (SRT_PUSH)
[StreamLive Channel]
- SCTE-35 감지
- Ad Marker: SCTE35_ENHANCED (EXT-X-DATERANGE)
- Segment Prefix: live/sports/main
- Output: HLS_STREAM_PACKAGE → StreamPackage Input URL
↓
[StreamPackage Channel]
- Input: StreamLive Output 수신
- Endpoint (SSAI=ENABLED):
- SCTE-35 → Avail 생성
- ADS 호출 (player_params 매크로 치환)
- VAST 응답 파싱 → Creative URL 추출
- 매니페스트에 광고 세그먼트 Stitch
- Beacon Fire (impression, quartile, complete)
↓
[CSS CDN]
- Pull Domain Origin = StreamPackage Endpoint URL
- 세션별 매니페스트 캐시 (개인화 때문에 bypass 또는 짧은 TTL)
↓
[시청자: 본편+광고 seamless 스트림]주의사항
- 세그먼트 스펙 일치: StreamLive의 트랜스코딩 출력과 광고 소재의 코덱/해상도/세그먼트 길이가 일치해야 함. 불일치 시 전환 순간 버퍼링.
- ADS 타임아웃: 라이브에서 ADS가 3초 안에 응답 안 하면 Slate가 나갑니다. ADS 서버 레이턴시를 사전에 테스트.
- CDN 캐시 정책: SSAI 매니페스트는 세션별로 다르므로 CDN에서 매니페스트를 캐시하면 안 됩니다(또는 세션 ID별 캐시 키 분리).
- Segment Prefix 정합성: StreamLive Segment Prefix와 StreamPackage의 입력 경로가 불일치하면 세그먼트를 못 찾습니다.
- Slate 준비 필수: ADS 실패 시 검은 화면이 나가는 건 방송 사고입니다. Slate는 반드시 사전 준비.
마치며
StreamLive + StreamPackage 조합에서 SSAI는 "StreamLive가 SCTE-35를 넘기고, StreamPackage가 매니페스트를 조작해서 광고를 심는" 구조입니다. Session Init으로 개인화 파라미터를 받고, ADS를 호출하고, VAST를 파싱해서 Creative를 Stitch하고, Beacon을 쏘는 전체 사이클이 StreamPackage 안에서 돌아갑니다.
콘솔 옵션을 하나하나 보면 결국 "누구에게(Session/Personalization), 어디에(Avail/SCTE-35), 무엇을(ADS/VAST), 어떻게(Endpoint/CDN)" 넣을지를 정하는 일입니다. 광고는 곧 돈이고, 이 파이프라인이 1초라도 죽으면 그 시간의 광고 매출이 0이 됩니다. Slate 준비, ADS 타임아웃 설정, CDN 캐시 정책 — "광고가 실패했을 때의 대비"가 실제 운영에서는 광고 삽입 자체보다 더 중요할 때가 많습니다.
참고 자료
- Tencent Cloud StreamLive: https://www.tencentcloud.com/document/product/1048
- Tencent Cloud StreamPackage: https://www.tencentcloud.com/document/product/1063