Adding Preroll Video to Your Channel

In this tutorial, we are going to develop a chunk of BrightScript code that can be used to display preroll ads in a Roku channel. To do this, we will use roVideoScreen, roVideoPlayer, and roImageCanvas, all of which are documented in the Component Reference document in the Roku SDK

The goal of adding preroll video to a channel can be broken down into two tasks. First, we need to play two pieces of video content back to back as a single video experience. Second, we need to disable trick-play during the first of those two pieces of content so the user is not able to skip the preroll and jump directly to the main content. The main content should have a traditional trick-play experience consistent with most other channels.

First, let’s define the two pieces of content by building a content-meta-data structure for each of them. A content-meta-data is just a roAssociativeArray with some specific attributes used to represent a given piece of content. The only thing we need to know about the preroll video is the format it’s in and the URL to the asset, so its content-meta-data will be a lot more sparse than the main content’s. In most projects this would be done by making an API call to your cloud service and parsing the result, but for demonstration purposes, we’ll just hardcode it:

preroll = {
    streamFormat: "mp4"
    stream: {
      url:  "http://www.archive.org/download/kelloggs_variety_pak/kelloggs_variety_pak_512kb.mp4"
    }
  }

content ={
    title:        "TEDTalks : David Brooks: The social animal"
    sdPosterURL:  "http://images.ted.com/images/ted/78e8d94d1d2a81cd182e0626dc8e96a43c88d760_132x99.jpg"
    hdPosterURL:  "http://images.ted.com/images/ted/78e8d94d1d2a81cd182e0626dc8e96a43c88d760_132x99.jpg"
    description:  "Tapping into the findings of his latest book, NYTimes columnist David Brooks unpacks new insights into human nature from the cognitive sciences -- insights with massive implications for economics and politics as well as our own self-knowledge. In a talk full of humor, he shows how you can't hope to understand humans as separate individuals making choices based on their conscious awareness."
    contentType:  "episode"
    streamFormat: "mp4"
    stream: {
      url:  "http://video.ted.com/talks/podcast/DavidBrooks_2011.mp4"
    }
  }

Now we need to play these two pieces of content back to back. Here is a very simple subroutine that uses roVideoScreen to play a video. If you have been experimenting with the sample code in the Roku SDK, you have probably seen subroutines similar to this.

sub ShowVideoScreen(video)
  port = CreateObject("roMessagePort")
  screen = CreateObject("roVideoScreen")
  screen.SetMessagePort(port)
  screen.SetContent(video)

  screen.Show()

  while true
    msg = wait(0, port)

    if type(msg) = "roVideoScreenEvent"
      if msg.isScreenClosed()
        exit while
      end if
    end if
  end while

  screen.Close()
end sub

Given this subroutine, you might be tempted to do something like this:

ShowVideoScreen(preroll)
ShowVideoScreen(content)

That will work. The preroll video will play and then the content video will play, but there are a few problems.

  • Trick play will not be disabled during the preroll
  • There may be a moment between the time when the preroll stops playing and when the content starts playing that the previous UI screen becomes visible for a fraction of a second
  • If the user exits playback during the preroll, the main content will begin playing immediately. The desired behavior would be for the video experience to end and the previous UI screen to become visible

To prevent the underlying UI from flickering into view between videos, we can simply display a blank roImageCanvas before playing the videos. During that moment after the first video ends and before the second video starts, the previous screen will still become visible for a moment, but it will be a blank screen, which makes for a more seamless transition between videos and a more pleasant experience for your users.

The other two problems can be solved by using the roVideoPlayer component to play the preroll content. roVideoPlayer is a much more manual video playback mechanism than roVideoScreen. By default, it has no trick play modes and no buffer screen. These features must be added manually in BrightScript. The lack of trick play is exactly what we want, but we will have to draw our own buffer screen and handle any up or back remote key presses manually. We will do all this by building a new function for playing preroll content. This function should not only play a piece of content with trick play disabled, it should also return a value that indicates whether or not the user terminated playback by pressing up or back. We will use this return value to decide whether we should play the main content or return the user to the previous UI screen.

function ShowPreRoll(video)
  ' a true result indicates that playback finished without user intervention
  ' a false result indicates that the user pressed UP or BACK to terminate playback
  result = true
  canvas = CreateObject("roImageCanvas")
  player = CreateObject("roVideoPlayer")
  port = CreateObject("roMessagePort")

  canvas.SetMessagePort(port)
  ' build a very simple buffer screen for our preroll video
  canvas.SetLayer(0, { text: "Your program will begin after this message" })
  canvas.Show()

  ' be sure to use the same message port for both the canvas and the player
  ' so we can receive events from both
  player.SetMessagePort(port)
  player.SetDestinationRect(canvas.GetCanvasRect())
  player.AddContent(video)

  player.Play()

  ' start our event loop
  while true
    ' wait for an event
    msg = wait(0, canvas.GetMessagePort())

    if type(msg) = "roVideoPlayerEvent"
      if msg.isFullResult()
        ' the video played to the end without user intervention
        exit while
      else if isRequestFailed()
        ' something went wrong with playback, but the user did not intervene
        exit while
      else if msg.isStatusMessage()
        if msg.GetMessage() = "start of play"
          ' once the video starts, clear out the canvas so it doesn't cover the video
          canvas.SetLayer(0, { color: "#00000000", CompositionMode: "Source" })
          canvas.Show()
        end if
      end if
    else if type(msg) = "roImageCanvasEvent"
      if msg.isRemoteKeyPressed()
        index = msg.GetIndex()
        if index = 0 or index = 2
          ' the user pressed UP or BACK to terminate playback
          result = false
          exit while
        end if
      end if
    end if
  end while

  player.Stop()
  canvas.Close()

  return result
end function

Now we have all the pieces necessary to build our video experience. Here’s how it all comes together:

' create and display a blank roImageCanvas to prevent the
' underlying UI from flickering between videos
canvas = CreateObject("roImageCanvas")
canvas.SetLayer(0, "#000000")
canvas.Show()

' play the preroll video with trick play disabled
if ShowPreroll(preroll)
  ' only play the main content if the preroll completed without user intervention
  ShowVideoScreen(content)
end if

' close the blank canvas and return the user to the previous UI screen
canvas.Close()
This entry was posted in Uncategorized. Bookmark the permalink.
  • Tom

    Great tutorial! Now what can we do with it? Are there any pre-roll ad networks that support Roku channels?

    Tom P.

    • Bensan George

      I have gotten it to work using OpenX ads

      • http://twitter.com/DeAuthThis DeAuthThis

        Would you tell me how?

  • Anonymous

    If you email partners@roku.com we can provide sample code that helps with this, specifically with VAST-compatible ad networks.

  • Tom

    Thanks for the info :-). Looking forward to hearing from “partners”.

  • Andrew

    Your event loop has a minor error…

    else if isRequestFailed()

    should be changed to…

    else if msg.isRequestFailed()

  • http://www.InstantRokuChannel.com/ Scott

    I had a conversation with a rep from Yume a few weeks ago. Basically Yume wants to pre-approve any channel that they provide ads for (understandable, but do all video ad providers require this?) and they were not interested in getting involved in any channels with a small number of subscribers. I got the general impression that he felt I was wasting his time. In the end, the rep promised to provide me with an NDA to sign and access to integration code, but then never followed up or replied to any subsequent attempts to email him.

  • http://www.facebook.com/app.builderz App Builderz

    I am having the hardest time with implementing the above “preroll” code … is there a full example located anywhere or how can I go about getting a example emailed to me?

  • Cherri alfred

    Hello, I am a newbie to Roku development… could you please mail me the entire source code for preroll ad?