Voltar para um intervalo de anúncio ignorado

Selecione a plataforma: HTML5 Android iOS tvOS Roku

Como editor de vídeo, talvez você queira impedir que os espectadores avancem os anúncios intermediários. Quando um usuário pula um intervalo de anúncio, você pode levá-lo de volta ao início desse intervalo de anúncio e, em seguida, retornar ao ponto do vídeo buscado pelo usuário após a conclusão do intervalo de anúncio. Esse recurso é chamado de "snapback".

Por exemplo, confira o diagrama abaixo. O espectador está assistindo um vídeo e decide buscar do minuto 5 ao minuto 15. No entanto, há um intervalo de anúncio aos 10 minutos que você quer que eles assistam antes de poderem assistir o conteúdo depois disso:

Para mostrar esse intervalo de anúncio, siga estas etapas:

  1. Verifique se o usuário fez uma busca que pulou um intervalo de anúncio não assistido e, em caso afirmativo, retorne ao intervalo de anúncio.
  2. Depois que o intervalo de anúncio terminar, retorne ao ponto original.

Em um diagrama, isso fica assim:

Confira como implementar esse fluxo de trabalho no SDK do IMA DAI, como feito no AdvancedExample.

Evitar pular anúncios não assistidos

Se um usuário tentar pular um intervalo de anúncio, o player precisa detectar o pulo e forçar a reprodução para o início desse intervalo específico. Para evitar que os anúncios não assistidos sejam pulados, faça o seguinte:

  1. Quando o usuário começa a interagir com a barra de busca, registre o tempo de reprodução atual.
  2. Depois que o usuário terminar de buscar um horário diferente no stream, identifique o intervalo de anúncio mais recente localizado antes desse horário.
  3. Se o intervalo de anúncio começar depois do horário de início gravado, indicando uma ação de pular, e ainda não tiver sido reproduzido, avance o player para o início do intervalo de anúncio.
  4. Ative uma flag snapbackMode para rastrear que esse intervalo de anúncio foi forçado.

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))
    }
  }
}

Retomar a busca original

Depois que o intervalo de anúncio forçado terminar, o player vai levar o usuário ao ponto de conteúdo desejado.

Para retomar a busca original do usuário, faça o seguinte:

  1. Aguarde o evento AD_BREAK_ENDED no gerenciador de streams.

  2. Verifique se a flag snapbackMode está ativa para garantir que esse salto ocorra após uma visualização forçada de anúncio.

  3. Se estiver ativo, procure o player no tempo de destino salvo para retornar o usuário ao carimbo de data/hora pretendido.

O exemplo a seguir detecta um intervalo de anúncio concluído e retorna um usuário para a busca original:

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)