Skip to main content

Video Advertisements

A video ad (InStream Video Ad) is an advertisement form that is inserted before, during, or after the video content playback.

This page is a usage guide to GfpVideoAdScheduleManager (VSM), a video schedule manager for calling pre/during/post advertisements.

The Player in which the video advertisement will be played is injected with the Player used by the service.

Please refer to player settings.


[Step 1] Add Dependency

dependencies {
implementation(platform("com.naver.gfpsdk:nam-bom:8.1.0"))
implementation("com.naver.gfpsdk:nam-core")
implementation("com.naver.gfpsdk:nam-ndavideo") // Naver InStream ads extension
}

[Step 2] Add ViewGroup that can contain Player layout

To display a video ad, a ViewGroup for the section where the video advertisement and the main video can be played must be added to the Activity or Fragment layout where the advertisement will be displayed.

In the example below, a video ad declared a Layout in the RelativeLayout ViewGroup with the ID video_ad_container.

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<RelativeLayout
android:id="@+id/video_ad_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="#000000"
app:layout_constraintDimensionRatio="16:9"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

[Step 3] Create a layout to include the Player and advertising UI

Declare a layout to contain the Player (AdVideoPlayer must be implemented) and the advertising UI that is required to play video ads.

Below is an example of a layout that includes a frame layout with a player and advertising UI.

The created ad_video_player and ad_ui_container will be used in the creator of the ad loader, GfpVideoAdScheduleManager.

Let’s name the xml file created below as video_ad_exoplayer_layout.xml.

The outer_text_ad_container is the section used for reminder advertisements which is used in SMR advertisements. It will be set separately as follows.

videoAdScheduleManager.setOuterRemindTextAdViewContainer(outerTextAdContainer);

However, it will not be used in this sample.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<com.naver.gfpsdk.adssample.video.SampleExoPlayerView
android:id="@+id/ad_video_player"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true" />

<FrameLayout
android:id="@+id/ad_ui_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />

<FrameLayout
android:id="@+id/outer_text_ad_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</RelativeLayout>

[Step 4] Create AdParam and VideoAdScheduleParam

Configure advertising parameters (AdParam) and schedule parameters (VideoAdScheduleParam) for video ad requests.

4-1. AdParam

Refer to the ad request information to create AdParam for the ad request.

Unlike other advertisements, Ad Unit ID is not a required value. However, video-related parameters will be required. Please refer to the video-related parameters on the ‘AdParam’ information page above.

info

When configuring AdParam, the setAdUnitId setting is not required. If set, it will be ignored.

4-2 VideoAdScheduleParam
  • Content length (contentDuration)

A required input value. The schedule operates only if it is entered accurately in seconds.

  • Schedule ID(adScheduleId)

A required value that must be informed in advance by a NAM manager.

  • Set schedule policy(setAdSchedulePolicy)

Pre/during/post advertisements can be selectively excluded.

As an additional value, each schedule ID has a policy set by the NAM Admin.

Although it is set by the Admin, it is used when the service wants it to be off.

  • (For live content) Content starting point(setContentStartOffset)

The advertising schedule offset is adjusted based on the content start time.

val adParam = AdParam.Builder()
.build()

val contentDuration = 653L // content duration with seconds
val adScheduleId = "NDP_ADSCHDL" // like a Ad Unit ID, need to get from GFP Admin
val pre = true
val mid = false // no ad in middle
val post = true

val videoAdScheduleParam = VideoAdScheduleParam.Builder(adScheduleId)
.setDuration(contentDuration)
.setAdSchedulePolicy(pre, mid, post)
.setAdNoticeDurationSec(5)
.build()
4-3 Set video advertising options

Set video ad options through GfpVideoAdScheduleManager setVideoAdOptions()

The support for bitrateKbps, videoLoadTimeout(ms), and hls can be set in GfpVideoAdOptions.

  • By default, hls is not supported.

    (Only supports video/mp4)

  • BitrateKbps determines the ad quality.

    The default value is -1. The advertisement is played with auto-play for IMA and with the lowest resolution (if HLS is not supported) for NAVER ads.

  • videoLoadTimeout generates an error if the actual playback does not occur until the specified time after the playback start request.

    The default is 5 seconds (5000ms)

val videoAdOptions = GfpVideoAdOptions().apply {
supportedStreamingHLS = false
bitrateKbps = -1
videoLoadTimeout = 5000
}

videoAdManager.setVideoAdOptions(videoAdOptions)

[Step 5] Create GfpVideoAdScheduleManager

Create GfpVideoAdScheduleManager for calling video ads.

Transmit the advertising parameters (AdParam) and schedule parameters (VideoAdScheduleParam) set above to the GfpVideoAdScheduleManager creator.

Additionally, inflate the layout created above. Then, add it to the video_ad_container created to include the player layout.

Please refer to the ad loading below for an example.


[Step 6] Receive schedule events

Video advertisement schedule events can be received through the VideoAdScheduleListener interface.

Since an event is processed per the video advertisement schedule, the start/end of the content must be processed through the corresponding listener when the advertisement starts/ends.

info

Once the ad is loaded, the video will pause. When processing an error in the advertisement video, it must be processed so that the video plays.

videoAdScheduleManager.setAdScheduleListener(object: VideoAdScheduleListener {
override fun onScheduleLoaded(schedule: VideoScheduleResponse) {
// ad schedule is loaded
}

override fun onContentResumeRequest() {
// time to resume the content (not an ad)
}

override fun onContentPauseRequest() {
// time to pause the content
}

override fun onScheduleCompleted() {
// every ad on scedule are finished
}

override fun onError(error: GfpError) {
// schedule request is failed
}
})

[Step 7] Receiving advertising events

Events about the life cycle of a video ad (loading, playback preparation, playback, preparation for non-linear ads, click, completion of playback, and error) can be received through the VideoAdListener interface.

videoAdScheduleManager.setAdListener(object: VideoAdListener {
override fun onAdLoaded(ad: GfpVideoAd) {
// single ad loaded successfully
}

override fun onAdStartReady(ad: GfpVideoAd) {
// need to play ad
}

override fun onAdStarted(ad: GfpVideoAd) {
// ad is started
}

override fun onAdNonLinearStartReady(ad: GfpVideoAd) {
// time to show non-linear ad
}

override fun onAdClicked(ad: GfpVideoAd) {
// ad is clicked
}

override fun onAdCompleted(ad: GfpVideoAd) {
// ad is finished
}

override fun onError(ad: GfpVideoAd, error: GfpError) {
// load/play error
}
})
7-1. About Quality of Experience (QOE)

Detailed events related to video ad playback can be received through setQoeListener of GfpVideoAdScheduleManager.

videoAdManager.setQoeListener(object: GfpVideoAdQoeListener {
override fun onAdLoaded(info: GfpVideoAdQoeInfo) {
Log.d("MainActivity", String.format("GfpVideoAdQoeListener.onAdLoaded \tinfo:\n\t\tplacement: %s\n\t\tprovider: %s \n\t\tmedia_h: %d\n\t\tmedia_w: %d \n\t\tcurrent time: %f\n\t\tduration: %f\n\t\toffset: %f",
info.placementType,
info.provider,
info.mediaHeight,
info.mediaWidth,
info.currentTime,
info.duration,
info.skipOffset
))
}

override fun onAdStarted(info: GfpVideoAdQoeInfo) {
Log.d("MainActivity", "GfpVideoAdQoeListener.onAdStarted")
}

override fun onAdPaused(info: GfpVideoAdQoeInfo) {
Log.d("MainActivity", "GfpVideoAdQoeListener.onAdPaused")
}

override fun onAdSkipped(info: GfpVideoAdQoeInfo) {
Log.d("MainActivity", "GfpVideoAdQoeListener.onAdSkipped")
}

override fun onAdResumed(info: GfpVideoAdQoeInfo) {
Log.d("MainActivity", "GfpVideoAdQoeListener.onAdResumed")
}

override fun onAdClicked(info: GfpVideoAdQoeInfo) {
Log.d("MainActivity", "GfpVideoAdQoeListener.onAdClicked")
}

override fun onAdCompleted(info: GfpVideoAdQoeInfo) {
Log.d("MainActivity", "GfpVideoAdQoeListener.onAdCompleted")
}

override fun onError(error: GfpError) {
Log.d("MainActivity", "GfpVideoAdQoeListener.onError")
}
})

[Step 8] Timeout settings

Set a timeout for each ad request through GfpVideoAdScheduleManager.

If a separate timeout is not set through the GfpVideoAdScheduleManager object, the default value will be the global settings of SdkProperties (default: 60 seconds).

If the setting is not selected, the default value will use the global settings (Default: 60 seconds) through SdkProperties.

videoAdScheduleManager.setGfpVideoProperties(GfpVideoProperties(60_000L, null))

[Step 9] Loading advertisement (Sample)

Advertisements can be loaded once the settings for GfpVideoAdScheduleManager have been completed.
The following is an example of how to load an advertisement in the onCreate() method of Activity.

package ...

import ...

class MainActivity : AppCompatActivity() {
private lateinit var playerContainer: RelativeLayout
private lateinit var adVideoPlayer: AdVideoPlayer
private lateinit var videoAdScheduleManager: GfpVideoAdScheduleManager

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

playerContainer = findViewById(R.id.video_ad_container)

// When using VSM, setAdUnitId is not needed.
val adParam = AdParam.Builder().build()

// do inflate video_ad_exoplayer_layout
val playerLayout = layoutInflater.inflate(R.layout.video_ad_exoplayer_layout, null, false)

// Sample player for test
val exoPlayerView = playerLayout.findViewById<SampleExoPlayerView>(R.id.ad_video_player)
val adUiContainer = playerLayout.findViewById<FrameLayout>(R.id.ad_ui_container)

// assume that SampleExoPlayerView has AdVideoPlayer
adVideoPlayer = exoPlayerView.createAdVideoPlayer("YOUR_CONTENTS_URL")

// Schedule Param setting
val contentDuration: Long = ***L // content duration with seconds
val adScheduleId = "VIDEO_AD_SCHEDULE_ID"
val videoAdScheduleParam = VideoAdScheduleParam.Builder(adScheduleId)
.setDuration(contentDuration)
.setAdSchedulePolicy(true, false, true)
.setAdNoticeDurationSec(5)
.build()

// create manager
videoAdScheduleManager = GfpVideoAdScheduleManager(
this,
videoAdScheduleParam,
adParam,
adVideoPlayer,
adUiContainer
)

val videoAdOptions = GfpVideoAdOptions()
videoAdOptions.setSupportedStreamingHLS(true)
videoAdScheduleManager.setVideoAdOptions(videoAdOptions)

/**
* if you need the QOE
videoAdScheduleManager.setQoeListener(object: GfpVideoAdQoeListener {
override fun onAdLoaded(info: GfpVideoAdQoeInfo) {
...
}
...
})
*/

videoAdScheduleManager.setAdScheduleListener(object: VideoAdScheduleListener {
override fun onScheduleLoaded(schedule: VideoScheduleResponse) {
Log.d("MainActivity", String.format("onScheduleLoaded - AdBreak size: %d", schedule.adBreaks.size))
}

override fun onContentResumeRequest() {
Log.d("MainActivity", "play the content")
// 본 영상 재생
if (exoPlayerView.isPlaying.not()) {
exoPlayerView.resumeContentsRequest()
}
}

override fun onContentPauseRequest() {
Log.d("MainActivity", "pause the content")
exoPlayerView.pauseContentsRequest()
}

override fun onScheduleCompleted() {
Log.d("MainActivity", "all ads are finished in schedule")
if (exoPlayerView.isPlaying.not()) {
exoPlayerView.resumeContentsRequest()
}
}

override fun onError(gfpError: GfpError) {
Log.d("MainActivity", "schedule load is failed Error: $gfpError")
if (exoPlayerView.isPlaying.not()) {
exoPlayerView.resumeContentsRequest()
}
}
})

videoAdScheduleManager.setAdListener(object: VideoAdListener {
override fun onAdLoaded(ad: GfpVideoAd) {
// NonLinearAdInfo nonLinearAdInfo = ad.getNonLinearAdInfo();
// can check the remind
Log.d("MainActivity", "onAdLoaded()\tResponseInfo: ${ad.responseInfo}")
}

override fun onAdStartReady(ad: GfpVideoAd) {
ad.start(true) // have to call this
Log.d("MainActivity", "time to start ad")
}

override fun onAdNonLinearStartReady(ad: GfpVideoAd) {
Log.d("MainActivity", "show the Non Linear")
ad.showNonLinearAd(GfpNonLinearAdView.ContainerType.INNER)
}

override fun onAdStarted(ad: GfpVideoAd) {
Log.d("MainActivity", "ad is started")
}

override fun onAdClicked(ad: GfpVideoAd) {
Log.d("MainActivity", "ad is clicked")
}

override fun onAdCompleted(ad: GfpVideoAd) {
Log.d("MainActivity", "ad is finished")

// 본 영상 재생
if (exoPlayerView.isPlaying.not()) {
exoPlayerView.resumeContentsRequest()
}
}

override fun onError(ad: GfpVideoAd, error: GfpError) {
Log.e("MainActivity", "error\t" +
String.format(
"code[%d] subCode[%s] message[%s] responseInfo[%s]",
error.errorCode,
error.errorSubCode,
error.errorMessage,
ad.responseInfo.toString()
)
)

if (!exoPlayerView.isPlaying) {
exoPlayerView.resumeContentsRequest()
}
}
})

playerContainer.addView(playerLayout)
videoAdScheduleManager.load()
}

override fun onPause() {
super.onPause()
if (::videoAdScheduleManager.isInitialized) {
videoAdScheduleManager.pause()
}
}

override fun onResume() {
super.onResume()
if (::videoAdScheduleManager.isInitialized) {
videoAdScheduleManager.resume()
}
}

override fun onDestroy() {
super.onDestroy()

if (::videoAdScheduleManager.isInitialized) {
videoAdScheduleManager.destroy()
}
}
}

[Step 10] Advertisement removal

If all advertisements registered in the schedule have terminated or exited the advertisement screen, the schedule manager must be removed to ensure that the advertisements are disposed of properly.
The removal of the schedule manager can be done by calling destroy() provided by GfpVideoAdScheduleManager as shown below.

if (::videoAdScheduleManager.isInitialized) {
videoAdScheduleManager.destroy()
}