ExoPlayer는 클라이언트 측 광고 삽입과 서버 측 광고 삽입에 모두 사용할 수 있습니다.
클라이언트 측 광고 삽입
클라이언트 측 광고 삽입에서는 플레이어가 콘텐츠 재생과 광고 재생 간에 전환할 때 서로 다른 URL의 미디어 로드 간에 전환합니다. 광고에 관한 정보는 XML VAST 또는 VMAP 광고 태그와 같이 미디어와 별도로 로드됩니다. 여기에는 콘텐츠 시작을 기준으로 한 광고 큐 위치, 실제 광고 미디어 URI, 특정 광고의 건너뛰기 가능 여부와 같은 메타데이터가 포함될 수 있습니다.
클라이언트 측 광고 삽입에 ExoPlayer의 AdsMediaSource
를 사용하는 경우 플레이어에 재생할 광고에 관한 정보가 있습니다. 이렇게 하면 다음과 같은 몇 가지 장점이 있습니다.
- 플레이어는 API를 사용하여 광고와 관련된 메타데이터와 기능을 노출할 수 있습니다.
- ExoPlayer UI 구성요소는 광고 위치의 마커를 자동으로 표시하고 광고 재생 여부에 따라 동작을 변경할 수 있습니다.
- 내부적으로 플레이어는 광고와 콘텐츠 간의 전환에서 일관된 버퍼를 유지할 수 있습니다.
이 설정에서 플레이어가 광고와 콘텐츠 간의 전환을 처리합니다. 즉, 앱이 광고와 콘텐츠를 위한 별도의 여러 백그라운드/포그라운드 플레이어를 제어하지 않아도 됩니다.
클라이언트 측 광고 삽입에 사용할 콘텐츠 동영상과 광고 태그를 준비할 때 광고는 플레이어가 원활하게 콘텐츠 재생을 다시 시작할 수 있도록 콘텐츠 동영상의 동기화 샘플 (키프레임)에 배치하는 것이 이상적입니다.
선언적 광고 지원
MediaItem
를 빌드할 때 광고 태그 URI를 지정할 수 있습니다.
Kotlin
val mediaItem = MediaItem.Builder() .setUri(videoUri) .setAdsConfiguration(MediaItem.AdsConfiguration.Builder(adTagUri).build()) .build()
자바
MediaItem mediaItem = new MediaItem.Builder() .setUri(videoUri) .setAdsConfiguration( new MediaItem.AdsConfiguration.Builder(adTagUri).build()) .build();
광고 태그를 지정하는 미디어 항목에 대한 플레이어 지원을 사용 설정하려면 플레이어를 만들 때 AdsLoader.Provider
및 AdViewProvider
로 구성된 DefaultMediaSourceFactory
를 빌드하고 삽입해야 합니다.
Kotlin
val mediaSourceFactory: MediaSource.Factory = DefaultMediaSourceFactory(context).setLocalAdInsertionComponents(adsLoaderProvider, playerView) val player = ExoPlayer.Builder(context).setMediaSourceFactory(mediaSourceFactory).build()
자바
MediaSource.Factory mediaSourceFactory = new DefaultMediaSourceFactory(context) .setLocalAdInsertionComponents(adsLoaderProvider, /* adViewProvider= */ playerView); ExoPlayer player = new ExoPlayer.Builder(context).setMediaSourceFactory(mediaSourceFactory).build();
내부적으로 DefaultMediaSourceFactory
는 콘텐츠 미디어 소스를 AdsMediaSource
에 래핑합니다. AdsMediaSource
는 AdsLoader.Provider
에서 AdsLoader
를 가져와서 미디어 항목의 광고 태그에 정의된 대로 광고를 삽입하는 데 사용합니다.
ExoPlayer의 PlayerView
는 AdViewProvider
를 구현합니다. ExoPlayer IMA 라이브러리는 아래에 설명된 대로 사용하기 쉬운 AdsLoader
를 제공합니다.
광고가 있는 재생목록
여러 미디어 항목이 포함된 재생목록을 재생할 때 기본 동작은 미디어 ID, 콘텐츠 URI, 광고 태그 URI 조합마다 광고 태그를 요청하고 광고 재생 상태를 한 번씩 저장하는 것입니다. 즉, 광고 태그 URI가 일치하더라도 고유한 미디어 ID 또는 콘텐츠 URI가 있는 광고가 있는 모든 미디어 항목의 광고가 사용자에게 표시됩니다. 미디어 항목이 반복되면 사용자에게 해당 광고가 한 번만 표시됩니다. 광고 재생 상태는 광고가 재생되었는지 저장하므로 광고가 처음 발생한 후에는 건너뜁니다.
객체 동등성에 따라 지정된 미디어 항목의 광고 재생 상태가 연결되는 불투명한 광고 식별자를 전달하여 이 동작을 맞춤설정할 수 있습니다. 다음은 광고 태그 URI를 광고 식별자로 전달하여 광고 재생 상태가 미디어 ID와 광고 태그 URI의 조합이 아닌 광고 태그 URI에만 연결된 예입니다. 이렇게 하면 광고가 한 번만 로드되고 사용자가 재생목록을 처음부터 끝까지 재생할 때 두 번째 항목에 광고가 표시되지 않습니다.
Kotlin
// Build the media items, passing the same ads identifier for both items, // which means they share ad playback state so ads play only once. val firstItem = MediaItem.Builder() .setUri(firstVideoUri) .setAdsConfiguration(MediaItem.AdsConfiguration.Builder(adTagUri).setAdsId(adTagUri).build()) .build() val secondItem = MediaItem.Builder() .setUri(secondVideoUri) .setAdsConfiguration(MediaItem.AdsConfiguration.Builder(adTagUri).setAdsId(adTagUri).build()) .build() player.addMediaItem(firstItem) player.addMediaItem(secondItem)
자바
// Build the media items, passing the same ads identifier for both items, // which means they share ad playback state so ads play only once. MediaItem firstItem = new MediaItem.Builder() .setUri(firstVideoUri) .setAdsConfiguration( new MediaItem.AdsConfiguration.Builder(adTagUri).setAdsId(adTagUri).build()) .build(); MediaItem secondItem = new MediaItem.Builder() .setUri(secondVideoUri) .setAdsConfiguration( new MediaItem.AdsConfiguration.Builder(adTagUri).setAdsId(adTagUri).build()) .build(); player.addMediaItem(firstItem); player.addMediaItem(secondItem);
ExoPlayer IMA 라이브러리
ExoPlayer IMA 라이브러리는 ImaAdsLoader
를 제공하므로 클라이언트 측 광고 삽입을 앱에 쉽게 통합할 수 있습니다. VAST/VMAP 광고 삽입을 지원하기 위해 클라이언트 측 IMA SDK의 기능을 래핑합니다. 백그라운드 처리 및 재생 재개를 처리하는 방법을 비롯하여 라이브러리를 사용하는 방법에 관한 안내는 리드미를 참고하세요.
데모 애플리케이션은 IMA 라이브러리를 사용하며 샘플 목록에 여러 샘플 VAST/VMAP 광고 태그를 포함합니다.
UI 고려사항
PlayerView
는 기본적으로 광고 재생 중에 전송 컨트롤을 숨기지만 앱은 setControllerHideDuringAds
를 호출하여 이 동작을 전환할 수 있습니다. IMA SDK는 광고가 재생되는 동안 플레이어 상단에
추가 보기(예: '추가 정보' 링크 및 건너뛰기 버튼(해당하는 경우))를
표시합니다.
IMA SDK는 플레이어 위에 렌더링된 애플리케이션 제공 뷰로 광고가 가려지는지 보고할 수 있습니다. 재생을 제어하는 데 필수적인 뷰를 오버레이해야 하는 앱은 이러한 뷰를 조회가능성 계산에서 생략할 수 있도록 IMA SDK에 등록해야 합니다. PlayerView
를 AdViewProvider
로 사용하면 컨트롤 오버레이가 자동으로 등록됩니다. 맞춤 플레이어 UI를 사용하는 앱은 AdViewProvider.getAdOverlayInfos
에서 오버레이 뷰를 반환하여 등록해야 합니다.
오버레이 뷰에 관한 자세한 내용은 IMA SDK의 Open Measurement를 참고하세요.
컴패니언 광고
일부 광고 태그에는 앱 UI의 '자리'에 표시될 수 있는 추가 컴패니언 광고가 포함되어 있습니다. 이러한 슬롯은 ImaAdsLoader.Builder.setCompanionAdSlots(slots)
를 통해 전달할 수 있습니다. 자세한 내용은 컴패니언 광고 추가를 참고하세요.
독립형 광고
IMA SDK는 독립형 광고를 단독으로 재생하기 위한 것이 아니라 미디어 콘텐츠에 광고를 삽입하기 위해 설계되었습니다. 따라서 IMA 라이브러리에서는 독립형 광고의 재생이 지원되지 않습니다. 이 사용 사례에서는 대신 Google 모바일 광고 SDK를 사용하는 것이 좋습니다.
서드 파티 광고 SDK 사용
서드 파티 광고 SDK를 통해 광고를 로드해야 하는 경우 ExoPlayer 통합을 이미 제공하는지 확인하는 것이 좋습니다. 그렇지 않은 경우 서드 파티 광고 SDK를 래핑하는 맞춤 AdsLoader
를 구현하는 것이 좋습니다. 위에서 설명한 AdsMediaSource
의 이점을 제공하기 때문입니다.
ImaAdsLoader
는 예시 구현 역할을 합니다.
또는 ExoPlayer의 재생목록 지원을 사용하여 광고 및 콘텐츠 클립의 시퀀스를 빌드할 수 있습니다.
Kotlin
// A pre-roll ad. val preRollAd = MediaItem.fromUri(preRollAdUri) // The start of the content. val contentStart = MediaItem.Builder() .setUri(contentUri) .setClippingConfiguration(ClippingConfiguration.Builder().setEndPositionMs(120000).build()) .build() // A mid-roll ad. val midRollAd = MediaItem.fromUri(midRollAdUri) // The rest of the content val contentEnd = MediaItem.Builder() .setUri(contentUri) .setClippingConfiguration(ClippingConfiguration.Builder().setStartPositionMs(120000).build()) .build() // Build the playlist. player.addMediaItem(preRollAd) player.addMediaItem(contentStart) player.addMediaItem(midRollAd) player.addMediaItem(contentEnd)
자바
// A pre-roll ad. MediaItem preRollAd = MediaItem.fromUri(preRollAdUri); // The start of the content. MediaItem contentStart = new MediaItem.Builder() .setUri(contentUri) .setClippingConfiguration( new ClippingConfiguration.Builder().setEndPositionMs(120_000).build()) .build(); // A mid-roll ad. MediaItem midRollAd = MediaItem.fromUri(midRollAdUri); // The rest of the content MediaItem contentEnd = new MediaItem.Builder() .setUri(contentUri) .setClippingConfiguration( new ClippingConfiguration.Builder().setStartPositionMs(120_000).build()) .build(); // Build the playlist. player.addMediaItem(preRollAd); player.addMediaItem(contentStart); player.addMediaItem(midRollAd); player.addMediaItem(contentEnd);
서버 측 광고 삽입
서버 측 광고 삽입(동적 광고 삽입(DAI)이라고도 함)에서는 미디어 스트림에 광고와 콘텐츠가 모두 포함됩니다. DASH 매니페스트는 콘텐츠와 광고 세그먼트를 모두 별도의 기간으로 가리킬 수 있습니다. HLS의 경우 재생목록에 광고 통합에 관한 Apple 문서를 참고하세요.
서버 측 광고 삽입을 사용하는 경우 클라이언트는 스트리밍을 꿰매기 위해 미디어 URL을 동적으로 확인해야 할 수 있고, UI에 광고 오버레이를 표시해야 할 수도 있으며, 광고 SDK 또는 광고 서버에 이벤트를 보고해야 할 수도 있습니다.
ExoPlayer의 DefaultMediaSourceFactory
는 이러한 모든 작업을 ssai://
스키마를 사용하여 URI의 서버 측 광고 삽입 MediaSource
에 위임할 수 있습니다.
Kotlin
val player = ExoPlayer.Builder(context) .setMediaSourceFactory( DefaultMediaSourceFactory(context).setServerSideAdInsertionMediaSourceFactory(ssaiFactory) ) .build()
자바
Player player = new ExoPlayer.Builder(context) .setMediaSourceFactory( new DefaultMediaSourceFactory(context) .setServerSideAdInsertionMediaSourceFactory(ssaiFactory)) .build();
ExoPlayer IMA 라이브러리
ExoPlayer IMA 라이브러리는 ImaServerSideAdInsertionMediaSource
를 제공하므로 앱에서 IMA의 서버 측 삽입 광고 스트림과 쉽게 통합할 수 있습니다. Android용 IMA DAI SDK의 기능을 래핑하고 제공된 광고 메타데이터를 플레이어에 완전히 통합합니다. 예를 들어 이를 통해 Player.isPlayingAd()
와 같은 메서드를 사용하고, 콘텐츠-광고 전환을 리슨하고, 플레이어가 이미 재생된 광고 건너뛰기와 같은 광고 재생 로직을 처리하도록 할 수 있습니다.
이 클래스를 사용하려면 ImaServerSideAdInsertionMediaSource.AdsLoader
및 ImaServerSideAdInsertionMediaSource.Factory
를 설정하고 플레이어에 연결해야 합니다.
Kotlin
// MediaSource.Factory to load the actual media stream. val defaultMediaSourceFactory = DefaultMediaSourceFactory(context) // AdsLoader that can be reused for multiple playbacks. val adsLoader = ImaServerSideAdInsertionMediaSource.AdsLoader.Builder(context, adViewProvider).build() // MediaSource.Factory to create the ad sources for the current player. val adsMediaSourceFactory = ImaServerSideAdInsertionMediaSource.Factory(adsLoader, defaultMediaSourceFactory) // Configure DefaultMediaSourceFactory to create both IMA DAI sources and // regular media sources. If you just play IMA DAI streams, you can also use // adsMediaSourceFactory directly. defaultMediaSourceFactory.setServerSideAdInsertionMediaSourceFactory(adsMediaSourceFactory) // Set the MediaSource.Factory on the Player. val player = ExoPlayer.Builder(context).setMediaSourceFactory(defaultMediaSourceFactory).build() // Set the player on the AdsLoader adsLoader.setPlayer(player)
자바
// MediaSource.Factory to load the actual media stream. DefaultMediaSourceFactory defaultMediaSourceFactory = new DefaultMediaSourceFactory(context); // AdsLoader that can be reused for multiple playbacks. ImaServerSideAdInsertionMediaSource.AdsLoader adsLoader = new ImaServerSideAdInsertionMediaSource.AdsLoader.Builder(context, adViewProvider).build(); // MediaSource.Factory to create the ad sources for the current player. ImaServerSideAdInsertionMediaSource.Factory adsMediaSourceFactory = new ImaServerSideAdInsertionMediaSource.Factory(adsLoader, defaultMediaSourceFactory); // Configure DefaultMediaSourceFactory to create both IMA DAI sources and // regular media sources. If you just play IMA DAI streams, you can also use // adsMediaSourceFactory directly. defaultMediaSourceFactory.setServerSideAdInsertionMediaSourceFactory(adsMediaSourceFactory); // Set the MediaSource.Factory on the Player. Player player = new ExoPlayer.Builder(context).setMediaSourceFactory(defaultMediaSourceFactory).build(); // Set the player on the AdsLoader adsLoader.setPlayer(player);
ImaServerSideAdInsertionUriBuilder
로 URL을 빌드하여 IMA 애셋 키 또는 콘텐츠 소스 ID 및 동영상 ID를 로드합니다.
Kotlin
val ssaiUri = ImaServerSideAdInsertionUriBuilder() .setAssetKey(assetKey) .setFormat(C.CONTENT_TYPE_HLS) .build() player.setMediaItem(MediaItem.fromUri(ssaiUri))
자바
Uri ssaiUri = new ImaServerSideAdInsertionUriBuilder() .setAssetKey(assetKey) .setFormat(C.CONTENT_TYPE_HLS) .build(); player.setMediaItem(MediaItem.fromUri(ssaiUri));
마지막으로 광고 로더가 더 이상 사용되지 않으면 해제합니다.
Kotlin
adsLoader.release()
자바
adsLoader.release();
UI 고려사항
서버 측 광고 삽입에도 클라이언트 측 광고 삽입과 동일한 UI 고려사항이 적용됩니다.
컴패니언 광고
일부 광고 태그에는 앱 UI의 '자리'에 표시될 수 있는 추가 컴패니언 광고가 포함되어 있습니다. 이러한 슬롯은 ImaServerSideAdInsertionMediaSource.AdsLoader.Builder.setCompanionAdSlots(slots)
를 통해 전달할 수 있습니다.
자세한 내용은 컴패니언 광고 추가를 참고하세요.
서드 파티 광고 SDK 사용
서드 파티 광고 SDK를 사용하여 광고를 로드해야 하는 경우 ExoPlayer 통합이 이미 제공되는지 확인하는 것이 좋습니다. 그렇지 않은 경우 ImaServerSideAdInsertionMediaSource
와 유사한 ssai://
스키마가 있는 URI를 허용하는 맞춤 MediaSource
를 제공하는 것이 좋습니다.
광고 구조를 만드는 실제 로직은 스트림 MediaSource
를 래핑하고 사용자가 광고 메타데이터를 나타내는 AdPlaybackState
를 설정하고 업데이트할 수 있는 범용 ServerSideAdInsertionMediaSource
에 위임할 수 있습니다.
서버 측에서 삽입된 광고 스트림에는 플레이어에게 광고 메타데이터를 알리는 시간 표시 이벤트가 포함되는 경우가 많습니다. ExoPlayer에서 지원되는 타임스탬프 메타데이터 형식에 관한 자세한 내용은 지원되는 형식을 참고하세요. 맞춤 광고 SDK MediaSource
구현은 Player.Listener.onMetadata
를 사용하여 플레이어의 시간 표시 메타데이터 이벤트를 수신할 수 있습니다.