SSAI는 광고를 서버 측에서 본편 스트림에 합성해 클라이언트에 내려보내는 기술입니다. 클라이언트 입장에서는 본편과 광고가 하나의 끊김 없는 스트림으로 보입니다. 광고 차단기를 우회할 수 있고, 버퍼링 없는 매끄러운 전환이 핵심 장점입니다.


들어가기 전에

광고 삽입은 크게 두 방식으로 나뉩니다.

방식동작 위치장점단점
CSAI (Client-Side)플레이어구현 간단, 개인화 쉬움, Beacon 직접 발사광고차단기에 취약, 버퍼링 발생
SSAI (Server-Side)오리진/매니페스트 서버광고차단 우회, seamless 전환서버 복잡도 증가, Beacon 처리 까다로움

CSAI는 플레이어가 광고 SDK를 로딩해서 별도 스트림을 재생하는 구조입니다. 문제는 광고와 본편 전환 시 버퍼링이 생기고, 광고 차단기가 SDK 자체를 막아버리면 매출이 사라진다는 점입니다.

SSAI는 이 문제를 서버에서 해결합니다. 매니페스트 조작(Manifest Manipulation) 방식으로 본편 세그먼트 사이에 광고 세그먼트를 끼워 넣습니다. 클라이언트는 하나의 연속된 스트림으로 인식하기 때문에 차단할 수 없습니다.


SSAI 동작 흐름

SSAI 동작 흐름

핵심 구성요소:

구성요소역할
SCTE-35 마커"여기서 광고 넣어라"는 신호. Avail의 트리거
Avail광고가 삽입될 수 있는 구간. Duration 정보 포함
Ad Decision Server (ADS)VAST/VMAP 요청을 받아 광고 Creative를 반환
Manifest Manipulator매니페스트를 세션별로 조작해 광고 세그먼트를 삽입
Ad Conditioning광고 소재를 본편과 동일 스펙으로 맞추는 전처리
Beacon/Tracking광고 노출, 재생 진행률을 ADS에 보고

VAST: 광고 결정의 표준 프로토콜

VAST는 IAB가 정한 비디오 광고 서빙 표준입니다. SSAI 서버가 ADS에 "광고 줘"라고 요청하면, ADS가 VAST XML로 응답합니다.

VAST 요청

SSAI 서버가 ADS를 호출할 때 전달하는 정보:

GET https://ads.example.com/vast?
    duration=30
    &session_id=abc123
    &device=mobile
    &geo=KR
    &content_id=show_001
    &ip=203.0.113.1
파라미터설명
durationAvail 길이 (초). SCTE-35에서 추출
session_idSSAI 세션 식별자
device디바이스 타입 (mobile, ctv, desktop)
geo시청자 지역
content_id현재 콘텐츠 식별자
ip시청자 IP (개인화 타게팅용)

VAST 응답 구조

<VAST version="4.2">
  <Ad id="ad_001" sequence="1">
    <InLine>
      <AdSystem>ExampleAdServer</AdSystem>
      <AdTitle>Coca-Cola Summer</AdTitle>
      <Impression>></Impression>
      <Creatives>
        <Creative>
          <Linear>
            <Duration>00:00:15</Duration>
            <TrackingEvents>
              <Tracking event="start">></Tracking>
              <Tracking event="firstQuartile">></Tracking>
              <Tracking event="midpoint">></Tracking>
              <Tracking event="thirdQuartile">></Tracking>
              <Tracking event="complete">></Tracking>
            </TrackingEvents>
            <MediaFiles>
              <MediaFile delivery="progressive" type="video/mp4"
                         width="1920" height="1080" bitrate="5000">
                >
              </MediaFile>
              <MediaFile delivery="progressive" type="video/mp4"
                         width="1280" height="720" bitrate="2500">
                >
              </MediaFile>
            </MediaFiles>
          </Linear>
        </Creative>
      </Creatives>
    </InLine>
  </Ad>
</VAST>

VAST 핵심 요소

요소설명
<Ad sequence>광고 Pod 내 재생 순서
<Impression>광고 노출 시 호출할 URL (Beacon)
<Duration>광고 길이
<TrackingEvents>재생 진행률별 Beacon URL
<MediaFiles>실제 광고 Creative 미디어 URL (해상도/비트레이트별)
<Error>에러 발생 시 보고할 URL

VMAP (Video Multiple Ad Playlist)

VAST가 "광고 하나"의 응답이라면, VMAP은 "전체 타임라인에서 어디에 광고를 넣을지"를 정의합니다:

<vmap:VMAP version="1.0">
  <vmap:AdBreak timeOffset="start" breakType="linear">
    <!-- Pre-roll -->
    <vmap:AdSource><vmap:VASTAdData>...</vmap:VASTAdData></vmap:AdSource>
  </vmap:AdBreak>
  <vmap:AdBreak timeOffset="00:10:00" breakType="linear">
    <!-- Mid-roll at 10분 -->
    <vmap:AdSource><vmap:VASTAdData>...</vmap:VASTAdData></vmap:AdSource>
  </vmap:AdBreak>
  <vmap:AdBreak timeOffset="end" breakType="linear">
    <!-- Post-roll -->
    <vmap:AdSource><vmap:VASTAdData>...</vmap:VASTAdData></vmap:AdSource>
  </vmap:AdBreak>
</vmap:VMAP>
timeOffset의미
startPre-roll (콘텐츠 시작 전)
HH:MM:SSMid-roll (특정 시점)
endPost-roll (콘텐츠 끝난 후)
#N%퍼센트 기반 (콘텐츠의 N% 지점)

Avail: 광고가 들어갈 수 있는 구간

Avail은 SCTE-35 Cue-Out ~ Cue-In 사이의 구간을 말합니다. SSAI 서버는 Avail이 감지되면 ADS를 호출해서 그 구간을 광고로 채웁니다.

Avail 채우기 로직

Avail Duration: 60초

ADS 응답:
  Ad 1: 15초
  Ad 2: 30초
  Ad 3: 15초
  ─────────
  합계: 60초 (정확히 채움) ✓

Avail을 정확히 채우지 못하는 경우:

상황처리
광고 합계 < Avail 길이남는 구간에 Slate(대기 화면) 삽입
광고 합계 > Avail 길이마지막 광고를 잘라내거나 제외
ADS 응답 없음 / 타임아웃전체를 Slate로 채움
ADS가 빈 VAST 반환Avail Suppression 정책에 따라 본편 유지 또는 Slate

Avail을 채우지 못하면 검은 화면이 나가는 게 최악의 시나리오입니다. 그래서 Slate(브랜딩 화면, "잠시 후 돌아옵니다" 등)는 SSAI에서 필수 구성요소입니다.


Beacon: 광고 추적과 보고

SSAI에서 가장 까다로운 부분이 Beacon(트래킹 픽셀) 처리입니다. CSAI는 플레이어가 직접 Beacon을 쏘지만, SSAI에서는 클라이언트가 "이게 광고인지 모르니까" Beacon을 직접 쏠 수 없습니다.

Beacon Fire 방식

방식동작장단점
Server-Side BeaconSSAI 서버가 직접 Beacon 호출구현 단순. 하지만 클라이언트 실제 재생 여부 모름
Client-Side Beacon (Sidecar)SSAI가 Beacon URL을 클라이언트에게 전달, 클라이언트가 직접 발사정확한 viewability. 구현 복잡
HybridImpression은 서버, Quartile은 클라이언트실무에서 가장 흔한 조합

Tracking Events (VAST 표준)

이벤트발사 시점설명
impression광고 첫 프레임 노출과금 기준. 가장 중요
start재생 시작impression과 동시 또는 직후
firstQuartile25% 재생
midpoint50% 재생
thirdQuartile75% 재생
complete100% 재생완시청 여부 확인
skip사용자가 스킵SSAI에서는 보통 스킵 불가
pause / resume일시정지/재개
mute / unmute음소거 전환
error재생 실패

Server-Side Beacon의 한계

서버가 Beacon을 쏘면 "광고가 실제로 재생됐는지"를 보장할 수 없습니다. 클라이언트가 세그먼트를 다운로드만 하고 재생하지 않았을 수도 있고, 유저가 탭을 내렸을 수도 있습니다.

이 문제 때문에 IAB의 Open Measurement SDK(OM SDK)가 등장했습니다. 클라이언트에 측정 스크립트를 삽입해서 실제 viewability(화면에 보이는지, 소리가 나오는지)를 검증합니다.

광고주 입장에서 "impression 찍혔는데 진짜 봤는지 모르겠다"는 SSAI의 태생적 약점입니다. OM SDK 연동이 안 되면 프리미엄 광고주가 SSAI 인벤토리를 기피할 수 있습니다. 이건 기술 문제가 아니라 비즈니스 문제입니다.


SCTE-35: 광고 신호의 표준

SCTE-35는 방송/스트리밍에서 광고 구간을 알리는 표준 신호입니다.

핵심 메시지 타입

메시지역할
splice_insert특정 시점에 광고 삽입/복귀를 지시
time_signal시간 기반 이벤트 신호. segmentation_descriptor와 조합
splice_nullKeepalive. "아직 여기 있다"는 의미

splice_insert 구조

splice_insert() {
  splice_event_id          // 이벤트 고유 ID
  splice_event_cancel      // 이전 이벤트 취소 여부
  out_of_network_indicator // 1=Cue-Out, 0=Cue-In
  splice_immediate_flag    // 즉시 실행 여부
  splice_time {
    pts_time              // 실행할 PTS 시점
  }
  break_duration {
    duration              // Avail 길이 (90kHz 단위)
  }
  unique_program_id        // 프로그램 식별자
  avail_num               // Avail 번호
  avails_expected         // 총 예상 Avail 수
}

segmentation_descriptor (time_signal과 조합)

time_signal + segmentation_descriptor로 더 풍부한 메타데이터를 전달할 수 있습니다:

segmentation_type_id의미
0x22Break Start (광고 시작)
0x23Break End (광고 종료)
0x30Provider Ad Start
0x31Provider Ad End
0x34Distributor Ad Start
0x35Distributor Ad End
0x40Unscheduled Event Start
0x41Unscheduled Event End

Cue-Out / Cue-In

SCTE-35의 핵심 동작:

본편 ──── [Cue-Out] ──── 광고 구간 (Avail) ──── [Cue-In] ──── 본편
              │                                      │
              └─ splice_insert(out=1, duration=60s)   └─ splice_insert(out=0)

전송 방식

입력SCTE-35 전달 방법
MPEG-2 TS (RTP/UDP/SRT)TS 내 전용 PID. 가장 표준적
RTMPAMF Data Tag로 전달 (제한적)
HLS 입력EXT-X-DATERANGE 또는 EXT-X-CUE-OUT 태그

HLS에서의 광고 신호: EXT-X-DATERANGE

HLS 환경에서 SCTE-35 정보를 클라이언트까지 전달하는 표준 방법은 EXT-X-DATERANGE 태그입니다.

#EXT-X-DATERANGE:ID="splice-6FFFFFF0",START-DATE="2026-06-01T10:30:00.000Z",PLANNED-DURATION=60.0,SCTE35-OUT=0xFC3025000000000000FFF00506FE...
#EXTINF:6.006,
segment_100.ts
#EXTINF:6.006,
segment_101.ts
...
#EXT-X-DATERANGE:ID="splice-6FFFFFF0",START-DATE="2026-06-01T10:30:00.000Z",END-DATE="2026-06-01T10:31:00.000Z",DURATION=60.0,SCTE35-IN=0xFC301...

주요 속성:

속성설명
ID광고 구간 고유 식별자. splice_event_id에 대응
START-DATE광고 시작 시각 (ISO 8601)
DURATION확정된 광고 구간 길이 (초)
PLANNED-DURATION예상 길이 (아직 Cue-In 안 온 경우)
SCTE35-OUTCue-Out SCTE-35 바이너리 (Base64 또는 Hex)
SCTE35-INCue-In SCTE-35 바이너리
END-DATE광고 종료 시각
CLASS이벤트 분류 (예: com.apple.hls.interstitial)

Apple은 EXT-X-DATERANGE로 광고를 시그널링하는 방식을 권장합니다. 구형 #EXT-X-CUE-OUT:DURATION=30 / #EXT-X-CUE-IN 태그도 업계에서 관행적으로 쓰이지만, 이건 비표준이고 Apple 규격에 정의되지 않은 벤더 확장입니다.


DASH에서의 광고 신호: Period와 Event

Multi-Period 방식

광고 구간을 별도 Period로 분리합니다:

<MPD type="dynamic" availabilityStartTime="2026-06-01T10:00:00Z">
  <Period id="content-1" start="PT0S" duration="PT10M">
    <AdaptationSet mimeType="video/mp4">
      <Representation bandwidth="5000000">
        <SegmentTemplate media="content_$Number$.m4s" startNumber="1" duration="180000" timescale="90000"/>
      </Representation>
    </AdaptationSet>
  </Period>
  
  <Period id="ad-break-1" start="PT10M" duration="PT60S">
    <!-- 광고 세그먼트: SSAI가 삽입 -->
    <AdaptationSet mimeType="video/mp4">
      <Representation bandwidth="5000000">
        <SegmentTemplate media="ad_$Number$.m4s" startNumber="1" duration="180000" timescale="90000"/>
      </Representation>
    </AdaptationSet>
  </Period>
  
  <Period id="content-2" start="PT11M">
    <!-- 본편 이어서 -->
  </Period>
</MPD>

EventStream 방식

Period 내에서 EventStream으로 SCTE-35 신호를 전달합니다:

<Period>
  <EventStream schemeIdUri="urn:scte:scte35:2013:xml" timescale="90000">
    <Event presentationTime="54000000" duration="5400000" id="1">
      <Signal xmlns="http://www.scte.org/schemas/35/2016">
        <SpliceInfoSection>
          <SpliceInsert spliceEventId="1" outOfNetworkIndicator="true">
            <BreakDuration autoReturn="true" duration="5400000"/>
          </SpliceInsert>
        </SpliceInfoSection>
      </Signal>
    </Event>
  </EventStream>
</Period>
방식장점단점
Multi-Period광고/본편 분리 명확, 세그먼트 독립MPD 갱신 필요, Period 전환 시 디코더 리셋 가능
EventStreamMPD 구조 불변, 인밴드 시그널링클라이언트 구현 복잡, SSAI 처리 까다로움

SSAI에서 Manifest Manipulation

SSAI의 실체는 세션별 매니페스트 조작입니다. 같은 스트림을 보는 시청자 A와 B에게 다른 광고를 보여주려면, 각각 다른 매니페스트를 내려줘야 합니다.

세션 기반 동작

1. 클라이언트 → Session Init (player params 포함)
2. SSAI 서버 → 세션 ID + 세션별 매니페스트 URL 반환
3. 클라이언트 → 세션별 URL로 매니페스트 요청
4. SSAI 서버 → 해당 세션의 ADS 결과가 반영된 조작된 매니페스트 반환
5. 클라이언트 → 세그먼트 요청 (광고 세그먼트도 동일 URL 패턴)
6. SSAI 서버 → 광고 세그먼트를 본편과 동일한 도메인/경로로 프록시
원본 매니페스트:
  seg_098.ts → seg_099.ts → [Avail: 30s] → seg_105.ts → ...

시청자 A의 매니페스트:
  seg_098.ts → seg_099.ts → /session/A/ad/coca_001.ts → /session/A/ad/coca_002.ts → seg_105.ts

시청자 B의 매니페스트:
  seg_098.ts → seg_099.ts → /session/B/ad/samsung_001.ts → /session/B/ad/samsung_002.ts → seg_105.ts

URL 패턴이 본편과 동일한 도메인을 쓰므로 광고 차단기가 구분할 수 없습니다.


Ad Conditioning (광고 소재 전처리)

SSAI가 seamless하려면 광고 소재가 본편과 동일한 포맷이어야 합니다:

  • 같은 코덱 (H.264, H.265)
  • 같은 해상도 래더 (1080p, 720p, 480p — 본편 ABR과 1:1 대응)
  • 같은 세그먼트 길이 (본편이 6초면 광고도 6초 단위)
  • 같은 프레임레이트 (29.97fps, 30fps 등)
  • 같은 오디오 코덱/샘플레이트 (AAC 48kHz)
  • 같은 GOP 구조 (IDR 간격)

이 전처리를 "Ad Conditioning" 또는 "Ad Transcoding"이라 부릅니다. 스펙이 안 맞으면:

  • 디코더 리셋 → 화면 깜빡임/버퍼링
  • ABR 스위칭 실패
  • 오디오 팝/클릭 노이즈
  • 타임스탬프 불연속 → 플레이어 오류

실무에서 이 부분이 가장 까다롭습니다. 광고주가 던져주는 소재는 제각각이고, 이걸 모든 ABR 래더에 맞춰 미리 트랜스코딩해둬야 합니다. SSAI 도입 프로젝트에서 시간의 60%가 Ad Conditioning 파이프라인 구축에 들어가는 경우도 흔합니다.


Ad Pod: 여러 광고 연속 재생

하나의 Avail에 여러 광고가 들어가는 것을 Ad Pod이라 합니다.

Avail (60초)
├── Ad 1: 15초 (Coca-Cola)    ← sequence="1"
├── Ad 2: 30초 (Samsung)      ← sequence="2"
└── Ad 3: 15초 (Hyundai)      ← sequence="3"

VAST 응답에서 <Ad sequence="N">으로 재생 순서가 지정됩니다. SSAI 서버는 이 순서대로 세그먼트를 매니페스트에 배치합니다.

Pod 내에서 개별 광고의 Beacon은 독립적으로 발사됩니다 — Ad 1의 complete이 찍혀야 Ad 2의 impression이 유효합니다.


마치며

SSAI의 핵심을 정리하면 다음과 같습니다.

신호 계층:

  • SCTE-35 → Avail 생성 (어디에 광고를 넣을지)
  • VAST/VMAP → 어떤 광고를 넣을지 (Creative, Duration, Tracking)
  • Beacon → 광고가 실제로 재생됐는지 보고

처리 계층:

  • Manifest Manipulation → 세션별 매니페스트 조작
  • Ad Conditioning → 광고 소재를 본편 포맷에 맞춤
  • Segment Stitching → 본편과 광고 세그먼트를 하나의 스트림으로 합성

비즈니스 현실:

  • Impression Beacon이 돈입니다. Beacon이 안 찍히면 광고비를 받을 수 없습니다.
  • Viewability 검증(OM SDK)이 안 되면 프리미엄 광고주가 기피합니다.
  • Avail을 못 채우면(Slate 노출) 해당 구간 매출이 0입니다.

결국 SSAI는 "기술적으로 seamless한 전환"만큼이나 "비즈니스적으로 Beacon이 정확히 찍히는 것"이 중요합니다. 광고 기술의 핵심은 항상 돈의 추적입니다.

참고 자료