O ApsaraVideo Player SDK permite adicionar, analisar e renderizar fluxos de legendas externas nos formatos WebVTT, SRT e ASS, além de fluxos de legendas incorporados em arquivos M3U8. Este tópico aborda a implementação para Android e iOS.
Para obter o código completo e detalhes de implementação, consulte o projeto API-Example e siga suas melhores práticas.
Veja o source do módulo ExternalSubtitle nos projetos API-Example-Android e API-Example-iOS.
Limites
Apenas arquivos de legenda externa nos formatos WebVTT, SRT e ASS são suportados.
Exemplo de renderização
Para empacotar fluxos de legendas para renderização, consulte Melhores práticas para transcodificação e empacotamento de múltiplas legendas.
Implementação principal no Android
Renderizar legendas externas
-
Importe as bibliotecas de dependência.
import com.aliyun.subtitle.SubTitleBase; import com.cicada.player.utils.webVtt.VttSubtitleView; import com.aliyun.player.IPlayer; -
Defina a visualize de exibição.
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); -
Configure os callbacks.
// 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); } }); -
Limpe a visualize de exibição após o player executar a operação
prepare/moveTo/moveToNext/moveToPrev.source = getSource(someParams); // pseudocode mVideoListPlayer.moveTo(mCurrentUUID + ""); if (vttSubtitleView != null) { vttSubtitleView.clearAll(); } if (!source.getExtSubtitleUrl().isEmpty()) { mCurrentExtSubtitle = source.getExtSubtitleUrl(); // Get the external subtitle URL. } -
Adicione o arquivo de legenda quando o callback
onPrepareddo player for invocado.// Currently, you can call addExtSubtitle only after the player's onPrepared callback is invoked. mVideoListPlayer.addExtSubtitle(mCurrentExtSubtitle);
Renderizar legendas empacotadas em M3U8
Não renderize legendas empacotadas em M3U8 e legendas externas simultaneamente.
-
Importe as bibliotecas de dependência.
import com.aliyun.subtitle.SubTitleBase; import com.cicada.player.utils.webVtt.VttSubtitleView; import com.aliyun.player.IPlayer; -
Defina a visualize de exibição.
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); -
Configure os callbacks.
// 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); } }); -
Limpe a visualize de exibição após o player executar a operação
prepare/moveTo/moveToNext/moveToPrev.source = getSource(someParams); // pseudocode mVideoListPlayer.moveTo(mCurrentUUID + ""); if (vttSubtitleView != null) { vttSubtitleView.clearAll(); } if (!source.getExtSubtitleUrl().isEmpty()) { mCurrentExtSubtitle = source.getExtSubtitleUrl(); // Get the external subtitle URL. } -
Configure o callback
onTrackReadypara obter as informações do subfluxo.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 } } } }); -
Chame
selectTrackpara alternar a faixa de legenda quando o callbackonPrepareddo player for invocado.// index is the TrackIndex of the target subtitle stream. mAliPlayer.selectTrack(index);
Implementação principal no iOS
Renderizar legendas externas
-
Configure o callback.
/** @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]; } -
Adicione o arquivo de legenda quando o callback
onPrepareddo player for invocado.if (self.currentModel.extSubtitleUrl != Nil) { [self.listPlayer addExtSubtitle:self.currentModel.extSubtitleUrl]; }
Renderizar legendas empacotadas em M3U8
Não renderize legendas empacotadas em M3U8 e legendas externas simultaneamente.
-
Configure o callback.
/** @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]; } -
Configure o callback
onTrackReadypara obter as informações do subfluxo.- (void)onTrackReady:(AliPlayer*)player info:(NSArray<AVPTrackInfo*>*)info { // } -
Chame
selectTrackpara alternar a faixa de legenda quando o callbackprepare donedo player for invocado.// index is the TrackIndex of the target subtitle stream. [self.player selectTrack:index];
Implementar renderização personalizada com base em fluxos WebVTT
O ApsaraVideo Player analisa e renderiza fluxos WebVTT padrão tanto no Android quanto no iOS. O player lê estilos CSS para produzir uma renderização de legendas unificada entre plataformas e suporta múltiplos estilos de texto em um único arquivo. Isso é útil para distinguir diálogos de personagens, enfatizar conteúdo importante e criar efeitos visuais especiais.
O exemplo a seguir mostra a estrutura de um arquivo WebVTT:
REGION: Defina a área de exibição.
STYLE: Defina o estilo da fonte. O primeiro item é o estilo padrão.
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
...
Para aplicar um estilo a um segmento de texto específico, utilize a seguinte sintaxe:
<v.font1>I have nothing to say</v.font1>