Tous les produits
Search
Centre de documentation

ApsaraVideo VOD:How to add external subtitles

Dernière mise à jour :Aug 10, 2026

Le SDK ApsaraVideo Player prend en charge l'ajout, l'analyse et le rendu de flux de sous-titres externes aux formats WebVTT, SRT et ASS, ainsi que les flux de sous-titres intégrés dans les fichiers M3U8. Cette rubrique décrit l'implémentation sur Android et iOS.

Important

Pour obtenir le code complet et les détails d'implémentation, reportez-vous au projet API-Example et suivez ses bonnes pratiques.

Consultez le code source du module ExternalSubtitle dans les projets API-Example-Android et API-Example-iOS.

Limites

  • Seuls les fichiers de sous-titres externes aux formats WebVTT, SRT et ASS sont pris en charge.

Exemple de rendu

Pour empaqueter les flux de sous-titres en vue de leur rendu, consultez Bonnes pratiques pour le transcodage et l'empaquetage multi-sous-titres.

Implémentation clé sur Android

Rendre les sous-titres externes

  1. Importez les bibliothèques de dépendance.

    import com.aliyun.subtitle.SubTitleBase;
    import com.cicada.player.utils.webVtt.VttSubtitleView;
    import com.aliyun.player.IPlayer;
  2. Définissez la vue d'affichage.

    vttSubtitleView = new VttSubtitleView(getContext());
    vttSubtitleView.setId(R.id.cicada_player_vtt_subtitle);
    
    // Set the display position of the subtitles. Add them to the center of the layout.
    FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
            FrameLayout.LayoutParams.WRAP_CONTENT,
            FrameLayout.LayoutParams.WRAP_CONTENT
    );
    params.gravity = Gravity.CENTER; // Add to the center of the layout.
    
    // Add the VTT subtitle view to the root layout view.
    mRootFrameLayout.addView(mVttSubtitleView, params);
  3. Définissez les écouteurs.

    // In the following example, mVideoListPlayer is a listPlayer. The process is the same if you use aliPlayer.
    // 1. Set OnSubtitleDisplayListener.
    mVideoListPlayer.setOnSubtitleDisplayListener(new IPlayer.OnSubtitleDisplayListener() {
        @Override
        public void onSubtitleExtAdded(int trackIndex, String url) {
          // Because we are only testing the addition of a single VTT file, select the subtitle track directly after the VTT file is added.
            mVideoListPlayer.selectExtSubtitle(trackIndex, true);
        }
    
        @Override
        public void onSubtitleShow(int trackIndex, long id, String data) {
            if (vttSubtitleView != null) {
                vttSubtitleView.show(id, data);
            }
        }
    
        @Override
        public void onSubtitleHide(int trackIndex, long id) {
            if (vttSubtitleView != null) {
                vttSubtitleView.dismiss(id);
            }
        }
    
        @Override
        public void onSubtitleHeader(int trackIndex, String header) {
            if (vttSubtitleView != null) {
                vttSubtitleView.setVttHeader(header);
            }
        }
    });
    
    // 2. Set VideoSizeChangedListener. This is a required step. The data must be passed back to vttSubtitleView.
    mVideoListPlayer.setOnVideoSizeChangedListener(new IPlayer.OnVideoSizeChangedListener() {
        @Override
        public void onVideoSizeChanged(int width, int height) {
            int viewWidth = getWidth();
            int viewHeight = getHeight();
            IPlayer.ScaleMode mode = mVideoListPlayer.getScaleMode();
            SubTitleBase.VideoDimensions videoDimensions = SubTitleBase.getVideoDimensionsWhenRenderChanged(width, height, viewWidth, viewHeight, mode);
            vttSubtitleView.setVideoRenderSize(videoDimensions.videoDisplayWidth, videoDimensions.videoDisplayHeight);
        }
    });
  4. Après l'exécution de l'opération prepare/moveTo/moveToNext/moveToPrev par le lecteur, effacez la vue d'affichage.

    source = getSource(someParams); // pseudocode
    
    mVideoListPlayer.moveTo(mCurrentUUID + "");
    if (vttSubtitleView != null) {
        vttSubtitleView.clearAll();
    }
    
    if (!source.getExtSubtitleUrl().isEmpty()) {
        mCurrentExtSubtitle = source.getExtSubtitleUrl(); // Get the external subtitle URL.
    }
  5. Une fois le rappel onPrepared du lecteur déclenché, ajoutez le fichier de sous-titres.

    // Currently, you can call addExtSubtitle only after the player's onPrepared callback is invoked.
    mVideoListPlayer.addExtSubtitle(mCurrentExtSubtitle);

Rendre les sous-titres empaquetés au format M3U8

Important

Ne rendez pas simultanément les sous-titres empaquetés au format M3U8 et les sous-titres externes.

  1. Importez les bibliothèques de dépendance.

    import com.aliyun.subtitle.SubTitleBase;
    import com.cicada.player.utils.webVtt.VttSubtitleView;
    import com.aliyun.player.IPlayer;
  2. Définissez la vue d'affichage.

    vttSubtitleView = new VttSubtitleView(getContext());
    vttSubtitleView.setId(R.id.cicada_player_vtt_subtitle);
    
    // Set the display position of the subtitles. Add them to the center of the layout.
    FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
            FrameLayout.LayoutParams.WRAP_CONTENT,
            FrameLayout.LayoutParams.WRAP_CONTENT
    );
    params.gravity = Gravity.CENTER; // Add to the center of the layout.
    
    // Add the VTT subtitle view to the root layout view.
    mRootFrameLayout.addView(mVttSubtitleView, params);
  3. Définissez les écouteurs.

    // In the following example, mVideoListPlayer is a listPlayer. The process is the same if you use aliPlayer.
    // 1. Set OnSubtitleDisplayListener.
    mVideoListPlayer.setOnSubtitleDisplayListener(new IPlayer.OnSubtitleDisplayListener() {
        @Override
        public void onSubtitleExtAdded(int trackIndex, String url) {
          // Because we are only testing the addition of a single VTT file, select the subtitle track directly after the VTT file is added.
            mVideoListPlayer.selectExtSubtitle(trackIndex, true);
        }
    
        @Override
        public void onSubtitleShow(int trackIndex, long id, String data) {
            if (vttSubtitleView != null) {
                vttSubtitleView.show(id, data);
            }
        }
    
        @Override
        public void onSubtitleHide(int trackIndex, long id) {
            if (vttSubtitleView != null) {
                vttSubtitleView.dismiss(id);
            }
        }
    
        @Override
        public void onSubtitleHeader(int trackIndex, String header) {
            if (vttSubtitleView != null) {
                vttSubtitleView.setVttHeader(header);
            }
        }
    });
    
    // 2. Set VideoSizeChangedListener. This is a required step. The data must be passed back to vttSubtitleView.
    mVideoListPlayer.setOnVideoSizeChangedListener(new IPlayer.OnVideoSizeChangedListener() {
        @Override
        public void onVideoSizeChanged(int width, int height) {
            int viewWidth = getWidth();
            int viewHeight = getHeight();
            IPlayer.ScaleMode mode = mVideoListPlayer.getScaleMode();
            SubTitleBase.VideoDimensions videoDimensions = SubTitleBase.getVideoDimensionsWhenRenderChanged(width, height, viewWidth, viewHeight, mode);
            vttSubtitleView.setVideoRenderSize(videoDimensions.videoDisplayWidth, videoDimensions.videoDisplayHeight);
        }
    });
  4. Après l'exécution de l'opération prepare/moveTo/moveToNext/moveToPrev par le lecteur, effacez la vue d'affichage.

    source = getSource(someParams); // pseudocode
    
    mVideoListPlayer.moveTo(mCurrentUUID + "");
    if (vttSubtitleView != null) {
        vttSubtitleView.clearAll();
    }
    
    if (!source.getExtSubtitleUrl().isEmpty()) {
        mCurrentExtSubtitle = source.getExtSubtitleUrl(); // Get the external subtitle URL.
    }
  5. Définissez le rappel onTrackReady pour récupérer les informations sur les sous-flux.

    mAliPlayer.setOnTrackReadyListener(new IPlayer.OnTrackReadyListener() {
        @Override
        public void onTrackReady(MediaInfo mediaInfo) {
            List<TrackInfo>  trackInfos = mediaInfo.getTrackInfos();
            for (TrackInfo trackInfo : trackInfos) {
                if (trackInfo.getType() == TrackInfo.Type.TYPE_SUBTITLE) {
                // TODO 
                }
            }
        }
    });
  6. Une fois le rappel onPrepared du lecteur déclenché, appelez selectTrack pour changer de piste de sous-titres.

    // index is the TrackIndex of the target subtitle stream.
    mAliPlayer.selectTrack(index);

Implémentation clé sur iOS

Rendre les sous-titres externes

  1. Définissez le rappel.

    /**
     @brief An external subtitle is added.
     @param player The player pointer.
     @param trackIndex The index of the subtitle track to be displayed.
     @param URL The subtitle URL.
     */
    - (void)onSubtitleExtAdded:(AliPlayer*)player trackIndex:(int)trackIndex URL:(NSString *)URL {
        NSLog(@"onSubtitleExtAdded: %@, trackIndex: %d", URL, trackIndex);
        [self.listPlayer selectExtSubtitle:trackIndex enable:YES];
    }
  2. Une fois le rappel onPrepared du lecteur déclenché, ajoutez le fichier de sous-titres.

    if (self.currentModel.extSubtitleUrl != Nil) {
        [self.listPlayer addExtSubtitle:self.currentModel.extSubtitleUrl];
    }

Rendre les sous-titres empaquetés au format M3U8

Important

Ne rendez pas simultanément les sous-titres empaquetés au format M3U8 et les sous-titres externes.

  1. Définissez le rappel.

    /**
     @brief An external subtitle is added.
     @param player The player pointer.
     @param trackIndex The index of the subtitle track to be displayed.
     @param URL The subtitle URL.
     */
    - (void)onSubtitleExtAdded:(AliPlayer*)player trackIndex:(int)trackIndex URL:(NSString *)URL {
        NSLog(@"onSubtitleExtAdded: %@, trackIndex: %d", URL, trackIndex);
        [self.listPlayer selectExtSubtitle:trackIndex enable:YES];
    }
  2. Définissez le rappel onTrackReady pour récupérer les informations sur les sous-flux.

    - (void)onTrackReady:(AliPlayer*)player info:(NSArray<AVPTrackInfo*>*)info {
      //
    }
  3. Une fois le rappel prepare done du lecteur déclenché, appelez selectTrack pour changer de piste de sous-titres.

    // index is the TrackIndex of the target subtitle stream.
    [self.player selectTrack:index];

Implémenter un rendu personnalisé basé sur les flux WebVTT

ApsaraVideo Player analyse et rend les flux WebVTT standard sur Android et iOS. Le lecteur lit les styles CSS pour produire un rendu uniforme des sous-titres sur toutes les plateformes et prend en charge plusieurs styles de texte dans un seul fichier, ce qui s'avère utile pour distinguer les dialogues des personnages, mettre en évidence le contenu clé et créer des effets visuels spéciaux.

L'exemple suivant montre la structure d'un fichier WebVTT :

  • REGION : définit la zone d'affichage.

  • STYLE : définit le style de police. Le premier élément correspond au style par défaut.

WEBVTT

REGION
id:bottom
width:70.000000%
lines:3
viewportanchor:15.000000%,95.000000%
regionanchor:0.000000%,100.000000%
scroll:up

STYLE
::cue {
  color: white;
  font-size: 70%;
  font-family: Noto Sans;
  font-weight: bold;
  background-color: rgba(0, 0, 0, 0.2);
}
::cue(.font1) {
  color: rgba(255, 255, 255, 1);
  font-weight: bold;
  font-family: Noto Sans;
  outline-width: 3px;
  outline-color: rgba(0, 0, 0, 1);
}
::cue(.font2) {
  color: rgba(252, 255, 101, 1);
  font-style: bold;
  font-family: Noto Sans;
  outline-width: 3px;
  outline-color: rgba(0, 0, 0, 1);
}
::cue(.font3) {
  color: rgba(255, 191  23, 1);
  font-style: bold;
  font-family: Noto Sans;
  outline-width: 3px;
  outline-color: rgba(183, 28, 28, 1);
}

00:00:00.200 --> 00:00:01.800 region:bottom align:center
Defendant Bo Hanshi

00:00:01.800 --> 00:00:03.200 region:bottom align:center
Do you have anything else to say

00:00:04.100 --> 00:00:04.800 region:bottom align:center
I

00:00:11.200 --> 00:00:12.200 region:bottom align:center
<v.font1>I have nothing to say</v.font1>

00:00:14.500 --> 00:00:16.200 region:bottom align:center
Defendant Bo Hanshi

...

Pour appliquer un style à un segment de texte spécifique, utilisez la syntaxe suivante :

<v.font1>I have nothing to say</v.font1>