장면과 분석
색인 생성은 두 층위의 분석 결과를 만듭니다.
- 장면 단위(로컬). 파이프라인은 샷 경계에서 영상을 잘라 타임코드가 붙은 구간으로 나누고, 각 구간을 영상과 오디오를 함께 담은 클립 하나로 분석합니다. 장면에 담긴 모든 값은 해당 클립만 보고 판단할 수 있습니다.
- 영상 단위(글로벌). 요약 모델이 모든 장면의 신호를 순서대로 읽고 영상 전체의 요약, 장르, IAB 레이블, GARM 평가를 만듭니다. 이 값들은 전체 맥락이 필요하므로 장면별로 예측하지 않습니다.
장면이란
장면은 영상 하나에서 연속된 구간입니다. video_id + scene_index(0부터 시작)로 식별하고, 밀리초 단위 start_ms / end_ms로 범위를 정합니다. 장면 경계는 자동 샷 전환 감지로 정해지며, 파이프라인이 구간 길이를 대략 5–30초로 맞춥니다. 검색은 장면 단위로 일치 결과를 반환하고, 광고 브레이크 지점은 장면 경계를 기준으로 합니다.
장면 필드
같은 장면 객체(SceneLite)가 GET /api/v1/videos/{video_id}/scenes, 장면 스트림, 영상 상세의 scenes 배열, 검색 결과(scenes[].scene)에서 반환됩니다. 필드 순서는 캡션 생성의 우선순위 그룹을 따릅니다.
식별자와 시간
idstringrequiredvideo_idstringrequiredscene_indexintegerrequiredstart_ms / end_msintegerrequired의미
captionstring | null시각 정보, 오디오, 화면 속 텍스트를 종합해 무슨 일이 일어나는지 서술한 영어 문장 2–3개입니다. caption 검색 모달리티가 임베딩하는 서술형 설명입니다.
transcriptstring | null오디오 트랙의 발화만 영어로 번역한 텍스트입니다. 말하는 사람이 없으면 비어 있습니다. 영상에 박힌 자막은 여기가 아니라 text_on_screen에 들어갑니다. transcript 검색 모달리티에서 임베딩됩니다.
text_on_screenstring[]화면에 보이는 텍스트(제목, 하단 자막, 박힌 자막, 간판 등)입니다. 원문 언어와 대소문자를 그대로 유지합니다.
actionstring[]클립에서 실제로 보이는 신체 동작 최대 3개입니다. 소문자 snake_case 자유 형식 슬러그(예: kneading_dough)이며 가장 두드러진 동작이 먼저 옵니다. 사람이 보이지 않으면 비어 있습니다.
human_activitystring[]action을 AVA-80 활동 어휘로 매핑한 값입니다. 규칙으로 도출하므로, AVA-80에 대응하는 항목이 없는 동작이 있으면 action보다 짧을 수 있습니다.
분위기와 오디오
valenceinteger | null장면이 전달하는 감정의 극성으로, 1(매우 부정적)부터 5(매우 긍정적)까지입니다. 시청자 반응이 아니라 콘텐츠 자체를 나타냅니다.
arousalinteger | null에너지·활성도로, 1(매우 낮음)부터 5(매우 높음)까지입니다.
music_moodstring | null배경 음악의 성격입니다. calm, energetic, dramatic, playful, melancholic, tense, none 중 하나입니다.
audio_eventsstring[]발화와 음악이 아닌 소리 최대 5개를 snake_case 슬러그로 나타냅니다(applause, laughter, siren, ...).
브랜드 세이프티
garm_categoriesstring[]이 클립에 실제로 묘사된 GARM 브랜드 세이프티 카테고리입니다. 대부분의 장면은 빈 배열입니다. 장면 단위 플래그는 의도적으로 민감하게 잡으며, 최종 관문 역할은 영상 단위 garm_video 평가가 합니다. 분류 체계와 판정을 참고하세요.
엔티티
brandsstring[]명시적으로 보이거나(로고, 화면 속 텍스트, 포장) 언급된 브랜드 이름 최대 5개입니다. 추측하지 않으며 원래 표기를 유지합니다.
product_categories_visiblestring[]화면에 보이는 제품 유형을 나타내는 일반 영어 명사 최대 6개입니다(smartphone, burger, ...).
peoplestring[]화면에 적혀 있거나 언급된 실명만 담습니다. "host" 같은 역할·인구통계 레이블은 쓰지 않으므로 대개 비어 있습니다. 얼굴 인식은 사용하지 않습니다. 데이터 처리를 참고하세요.
locationsstring[]배경을 설명하는 일반 영어 표현 0–2개입니다(indoor cafe, city street). 정확한 주소는 담지 않습니다.
환경과 미디어
weatherstring | null관찰된 날씨 또는 하늘 상태로, 고정 어휘 20개 중 하나입니다. Indoor는 클립이 명백히 건물이나 차량 안일 때만 씁니다. 하늘이 단순히 화면 밖에 있으면 Unknown / Not visible입니다.
keyframe_urlstring | nullclip_urlstring | nullkeyframe_url과 마찬가지로 1시간 동안 유효합니다.장면에는 IAB 카테고리, 장르, GARM 심각도 등급이 없습니다. 이 값들은 영상 단위 필드입니다. 장면별 심각도는 아래 장면 마커의 garm_level이 유일합니다.
장면 마커
영상 상세의 scene_markers는 모든 장면에 대한 가벼운 레코드입니다. 전체 객체를 페이지로 넘겨 보지 않고도 타임라인을 그릴 수 있습니다.
| 필드 | 타입 | 의미 |
|---|---|---|
id, scene_index, start_ms, end_ms | 장면과 같습니다. | |
garm_level | high | medium | low | none | 이 장면에 걸친 가장 높은 브랜드 세이프티 심각도입니다. 기본값은 none입니다. |
garm_categories | string[] | 장면의 GARM 플래그입니다. |
영상 단위 필드
GET /api/v1/videos/{video_id}가 반환합니다. 목록 엔드포인트는 표시된 일부 필드만 반환합니다.
| 필드 | 타입 | 목록 포함 | 의미 |
|---|---|---|---|
summary | string | null | 예 | 영상 전체를 종합한 영어 문장 3–5개입니다. 주제, 서사 흐름, 분위기 변화, 의도를 담으며 장면별 요약 나열이 아닙니다. |
genre | string[] | 예 | 영화·TV 고정 어휘에서 고른 장르 레이블 1–3개이며, 주된 장르가 먼저 옵니다. |
iab_content_leaf | string[] | 예 | 영상의 주제를 IAB Content Taxonomy leaf 레이블로 나타냅니다(최대 5개). |
iab_audience_interest_leaf | string[] | 이 콘텐츠에 맞는 시청자의 IAB Audience Taxonomy 관심사 세그먼트입니다(최대 5개). | |
iab_audience_purchase_intent_leaf | string[] | 그 시청자가 가질 법한 IAB Audience Taxonomy 구매 의도 세그먼트입니다(최대 5개). | |
iab_ad_product_leaf | string[] | 이 콘텐츠 옆에 어울리는 광고의 IAB Ad Product Taxonomy 카테고리입니다(최대 5개). | |
garm_video | GarmEntry[] | 예 | 영상 단위 GARM 평가입니다. 실제로 존재한다고 판단한 카테고리마다 항목 하나이며, 각각 category, level(high | medium | low), reasoning, 선택 항목 time_ranges를 담습니다. |
transcript_coverage | number | null | 영상에서 발화가 차지하는 비율입니다. | |
scene_count | integer | 전체 장면 수입니다. | |
scenes | SceneLite[] | 처음 scene_limit개 장면입니다. | |
scene_markers | SceneMarker[] | 모든 장면의 가벼운 레코드입니다. | |
aggregations | VideoAggregations | null | 아래 집계 값입니다. | |
keyframe_url | string | null | 예(목록 전용) | 영상 카드용 대표 프레임입니다. |
title, duration_ms, source_url, created_at, external_content_id | 일부 | 메타데이터입니다. source_url은 http(s) 출처일 때만 채워집니다. |
수명 주기 필드(status, reason_code, indexed_at, index_trigger, job_id, reindex_run_id)는 영상과 작업에서 다룹니다.
집계
aggregations는 서버에서 모든 장면을 한 번씩 순회해 계산하므로, 페이지를 넘기지 않고도 영상 전체 패널을 얻을 수 있습니다.
| 필드 | 형태 | 원본 장면 필드 |
|---|---|---|
brands | {name, count, scene_indexes[]} | brands |
products | {name, count} | product_categories_visible |
locations | {name, count} | locations |
people | {name, count} | people |
audio_events | {name, count} | audio_events |
music_moods | {mood, count} | music_mood |
text_on_screen | string[] | text_on_screen |
mood_timeline | 장면마다 {scene_index, start_ms, valence, arousal} | valence, arousal |
actions | {name, count} | action |
human_activities | {name, count} | human_activity |
weather_counts | {name, count} | weather(Unknown / Not visible 제외) |
스트리밍 조회와 페이지 조회
- 페이지
- 스트리밍(NDJSON)
GET /api/v1/videos/{video_id}/scenes?offset=&limit=는 ScenesPage를 반환합니다. items, offset, limit(최대 200, 기본값 50), total로 구성됩니다. total에 도달할 때까지 offset을 limit만큼 늘려 가며 조회하세요.
알 수 없는 video_id는 404가 아니라 total: 0인 빈 페이지를 반환합니다. 두 경우를 구분해야 한다면 GET /api/v1/videos/{video_id}로 영상이 있는지 확인하세요.
GET /api/v1/videos/{video_id}/scenes/stream은 분석이 끝날 때마다 한 줄에 JSON 객체 하나씩 보냅니다.
| 줄 | 의미 |
|---|---|
{"event": "scene", "scene": {...}} | 새로 분석된 장면입니다. 페이지 항목과 형태가 같으며, 한 연결 안에서 반복되지 않습니다. |
{"event": "keepalive"} | 유휴 상태 하트비트입니다. 무시하세요. |
{"event": "done", "job_status": "done"} | 색인 생성이 끝났고 연결이 닫힙니다. job_status는 failed일 수도 있고, 색인 작업이 없는 영상이면 null입니다. |
{"event": "timeout"} | 서버의 최대 스트림 시간에 도달했습니다. 다시 연결해 새 스냅숏을 받으세요. |
장면 순서는 scene_index가 아니라 분석이 끝난 순서를 따릅니다. 이미 색인된 영상에 연결하면 모든 장면을 즉시 재전송하고 done으로 닫습니다. 종료 줄 없이 연결이 끊기면 다시 연결하세요. 이미 분석된 장면부터 재전송됩니다. 여기서는 알 수 없는 video_id에 404를 반환합니다.
작업이 running인 동안에는 스트림을 써서 앞선 장면부터 처리를 시작하고, 작업이 done이 된 뒤에는 페이지 조회로 원하는 위치에 접근하세요. 둘 다 같은 장면 객체를 반환합니다.
장면이 나타나는 다른 곳
- 검색:
POST /api/v1/search는 일치한 장면을 영상별로 묶습니다. 각scenes[]항목은 전체 장면 객체를 담은{score, scene}입니다. - 광고 매칭: 브레이크 지점은 장면 경계의
start/end타임스탬프와 함께scene_id를 참조합니다. - 라이브 스트림: 버스트의
scenes[]는 분석된 HLS 세그먼트로, 같은 분석 필드에 세그먼트 메타데이터(segment_index,segment_url,status)가 더해집니다. 라이브를 참고하세요.