Revenir à une coupure publicitaire ignorée

Sélectionner une plate-forme : HTML5 Android iOS tvOS Roku

En tant qu'éditeur de vidéos, vous pouvez empêcher vos spectateurs de passer vos annonces mid-roll. Lorsqu'un utilisateur passe une coupure publicitaire, vous pouvez le ramener au début de cette coupure, puis le renvoyer à l'emplacement qu'il avait sélectionné une fois la coupure publicitaire terminée. Cette fonctionnalité est appelée "retour rapide".

Par exemple, consultez le diagramme ci-dessous. Votre spectateur regarde une vidéo et décide de passer de 5 à 15 minutes. Cependant, il y a une coupure publicitaire à 10 minutes que vous voulez qu'il regarde avant de pouvoir regarder le contenu qui suit :

Pour afficher cette coupure publicitaire, procédez comme suit :

  1. Vérifiez si l'utilisateur a effectué une recherche qui a passé une coupure publicitaire non visionnée. Si c'est le cas, ramenez-le à la coupure publicitaire.
  2. Une fois la coupure publicitaire terminée, renvoyez-le à sa recherche d'origine.

Sous forme de diagramme, cela se présente comme suit :

Voici comment implémenter ce workflow dans le SDK IMA DAI, comme dans le AdvancedExample.

Empêcher l'utilisateur de passer les annonces non visionnées

Si un utilisateur tente de passer une coupure publicitaire, le lecteur doit détecter le saut et forcer la lecture au début de cette coupure publicitaire spécifique. Pour empêcher l'utilisateur de passer les annonces non visionnées, procédez comme suit :

  1. Lorsque l'utilisateur commence à interagir avec la barre de recherche, enregistrez son temps de lecture actuel.
  2. Une fois que l'utilisateur a terminé sa recherche à un autre moment du flux, identifiez la coupure publicitaire la plus récente située avant ce moment.
  3. Si la coupure publicitaire commence après l'heure de début enregistrée, ce qui indique un saut, et qu'elle n'a pas encore été lue, recherchez le lecteur au début de la coupure publicitaire
  4. Activez un indicateur snapbackMode pour suivre le fait que cette coupure publicitaire a été forcée.

Objective-C

- (IBAction)videoControlsTouchStarted:(id)sender {
  [NSObject cancelPreviousPerformRequestsWithTarget:self
                                            selector:@selector(hideFullscreenControls)
                                              object:self];

  self.currentlySeeking = YES;
  self.seekStartTime = self.contentPlayer.currentTime;
}

- (IBAction)videoControlsTouchEnded:(id)sender {
  if (self.fullscreen) {
    [self startHideControlsTimer];
  }
  self.currentlySeeking = NO;
  if (!self.adPlaying) {
    self.seekEndTime = CMTimeMake(self.progressBar.value, 1);
    IMACuepoint *lastCuepoint =
        [self.streamManager previousCuepointForStreamTime:CMTimeGetSeconds(self.seekEndTime)];
    if (!lastCuepoint.played && (lastCuepoint.startTime > CMTimeGetSeconds(self.seekStartTime))) {
      self.snapbackMode = YES;
      // Add 1 to the seek time to get the keyframe at the start of the ad to be our landing
      // place.
      [self.contentPlayer
          seekToTime:CMTimeMakeWithSeconds(lastCuepoint.startTime + 1, NSEC_PER_SEC)];
    }
  }
}

Swift

@IBAction func progressBarTouchStarted(_ sender: UISlider) {
  guard !isAdPlaying else { return }
  currentlySeeking = true
  seekStartTime = contentPlayer.currentTime().seconds
}

// MARK: Snapback Logic
@IBAction func progressBarTouchEnded(_ sender: UISlider) {
  guard !isAdPlaying else { return }
  if isFullScreen {
    startHideControlsTimer()
  }
  currentlySeeking = false
  seekEndTime = Float64(sender.value)

  guard let streamManager else { return }

  if let lastCuepoint = streamManager.previousCuepoint(forStreamTime: seekEndTime) {
    if !lastCuepoint.isPlayed, lastCuepoint.startTime > seekStartTime {
      logMessage(
        "Snapback to \(String(format: "%.2f", lastCuepoint.startTime)) from \(String(format: "%.2f", seekEndTime))"
      )
      snapbackMode = true
      contentPlayer.seek(
        to: CMTime(seconds: Double(sender.value), preferredTimescale: 1000))
    }
  }
}

Reprendre la recherche d'origine

Une fois la coupure publicitaire forcée terminée, le lecteur redirige l'utilisateur vers le point de contenu souhaité.

Pour reprendre la recherche d'origine de l'utilisateur, procédez comme suit :

  1. Écoutez l'événement AD_BREAK_ENDED dans votre gestionnaire de flux.

  2. Vérifiez si l'indicateur snapbackMode est actif pour vous assurer que ce saut se produit après une vue d'annonce forcée.

  3. S'il est actif, recherchez le lecteur à l'heure de destination enregistrée pour renvoyer l'utilisateur au code temporel souhaité.

L'exemple suivant écoute une coupure publicitaire terminée et renvoie un utilisateur à la recherche d'origine :

Objective-C

case kIMAAdEvent_AD_BREAK_ENDED: {
  [self logMessage:@"Ad break ended"];
  self.adPlaying = NO;
  if (self.snapbackMode) {
    self.snapbackMode = NO;
    if (CMTimeCompare(self.seekEndTime, self.contentPlayer.currentTime)) {
      [self.contentPlayer seekToTime:self.seekEndTime];
    }
  }
  break;
}

Swift

case .AD_BREAK_ENDED:
  logMessage("Ad break ended")
  isAdPlaying = false
  progressBar.isUserInteractionEnabled = true
  if snapbackMode {
    snapbackMode = false
    if contentPlayer.currentTime().seconds < seekEndTime {
      contentPlayer.seek(to: CMTime(seconds: Double(seekEndTime), preferredTimescale: 1000))
    }
  } else if pendingBookmarkSeek, let time = bookmarkStreamTime {
    logMessage(String(format: "AD_BREAK_ENDED: Seeking to bookmark streamTime: %.2f", time))
    imaVideoDisplay.seekStream(toTime: time)
    pendingBookmarkSeek = false
    bookmarkStreamTime = nil
  }
  updatePlayHeadState(isPlaying: self.isContentPlaying)