Add captions
On Android, captions can be added by using TimedText inside a MediaPlayer. The code example below shows a basic example.
kotlin
val player = MediaPlayer.create(this, R.raw.video)
val mimeType = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
MediaFormat.MIMETYPE_TEXT_SUBRIP
} else {
MediaPlayer.MEDIA_MIMETYPE_TEXT_SUBRIP
}
try {
player.addTimedTextSource("/assets/appt.srt", mimeType)
player.trackInfo.forEachIndexed { index, trackInfo ->
if (trackInfo.trackType == TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT) {
player.selectTrack(index)
return@forEachIndexed
}
}
player.setOnTimedTextListener(this)
player.start()
} catch (e: Exception) {
e.printStackTrace()
} In Jetpack Compose, captions can be added by using TimedText inside a MediaPlayer. The code example below shows a basic example.
kotlin
val context = LocalContext.current
var mediaPlayer by remember { mutableStateOf<MediaPlayer?>(null) }
var error by remember { mutableStateOf<String?>(null) }
DisposableEffect(Unit) {
// Create a MediaPlayer instance and set up timed text
val player = MediaPlayer.create(context, R.raw.video)
try {
val mimeType = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
MediaFormat.MIMETYPE_TEXT_SUBRIP
} else {
MediaPlayer.MEDIA_MIMETYPE_TEXT_SUBRIP
}
player.addTimedTextSource("/assets/appt.srt", mimeType)
player.trackInfo.forEachIndexed { index, trackInfo ->
if (trackInfo.trackType == MediaPlayer.TrackInfo.MEDIA_TRACK_TYPE_TIMEDTEXT) {
player.selectTrack(index)
return@forEachIndexed
}
}
player.setOnTimedTextListener { _, timedText ->
// Handle timed text display here
}
player.start()
} catch (e: Exception) {
e.printStackTrace()
error = e.message
}
mediaPlayer = player
onDispose {
player.release()
mediaPlayer = null
}
} On iOS, AVPlayer offers support to add captions. Users can automatically turn on subtitles via System Preferences.
The code example below shows a basic implementation of adding captions.
swift
// Create a mutable composition
let videoComposition = AVMutableComposition()
// Add video track
guard let videoTrack = videoComposition.addMutableTrack(
withMediaType: .video,
preferredTrackID: kCMPersistentTrackID_Invalid
) else {
return
}
guard let videoUrl = Bundle.main.url(forResource: "Appt", withExtension: "mp4") else {
return
}
let videoAsset = AVURLAsset.init(url: videoUrl)
try await videoTrack.insertTimeRange(
CMTimeRangeMake(start: .zero, duration: videoAsset.load(.duration)),
of: videoAsset.loadTracks(withMediaType: .video)[0],
at: .zero
)
// Add captions track
guard let captionsUrl = Bundle.main.url(
forResource: "Appt",
withExtension: ".vtt"
) else {
return
}
guard let captionsTrack = videoComposition.addMutableTrack(
withMediaType: .text,
preferredTrackID: kCMPersistentTrackID_Invalid
) else {
return
}
let captionsAsset = AVURLAsset(url: captionsUrl)
try? await captionsTrack.insertTimeRange(
CMTimeRangeMake(start: .zero, duration: videoAsset.load(.duration)),
of: captionsAsset.loadTracks(withMediaType: .text)[0],
at: .zero
) In SwiftUI, AVPlayer offers support to add captions. Users can automatically turn on subtitles via System Preferences.
The code example below shows a basic implementation of adding captions.
swift
// Create a mutable composition
let videoComposition = AVMutableComposition()
// Add video track
guard let videoTrack = videoComposition.addMutableTrack(
withMediaType: .video,
preferredTrackID: kCMPersistentTrackID_Invalid
) else {
return
}
guard let videoUrl = Bundle.main.url(forResource: "Appt", withExtension: "mp4") else {
return
}
let videoAsset = AVURLAsset.init(url: videoUrl)
try await videoTrack.insertTimeRange(
CMTimeRangeMake(start: .zero, duration: videoAsset.load(.duration)),
of: videoAsset.loadTracks(withMediaType: .video)[0],
at: .zero
)
// Add captions track
guard let captionsUrl = Bundle.main.url(
forResource: "Appt",
withExtension: ".vtt"
) else {
return
}
guard let captionsTrack = videoComposition.addMutableTrack(
withMediaType: .text,
preferredTrackID: kCMPersistentTrackID_Invalid
) else {
return
}
let captionsAsset = AVURLAsset(url: captionsUrl)
try? await captionsTrack.insertTimeRange(
CMTimeRangeMake(start: .zero, duration: videoAsset.load(.duration)),
of: captionsAsset.loadTracks(withMediaType: .text)[0],
at: .zero
) With Flutter, the video_player package has support for the SubRip and WebVTT formats for captions. These files will be parsed to a ClosedCaptionFile that can be interpreted by the video_player package.
One way to implement this would be to load the video file and the captions and add these to the VideoPlayerController. The implementation below shows how this is achieved in the video_player example implementation. A full implementation can be found in the GitHub repository of video_player.
dart
late VideoPlayerController _controller;
Future<ClosedCaptionFile> _loadCaptions() async {
final String fileContents = await DefaultAssetBundle.of(context)
.loadString('/assets/appt.vtt');
return WebVTTCaptionFile(
fileContents); // For vtt files, use WebVTTCaptionFile
}
@override
void initState() {
super.initState();
_controller = VideoPlayerController.asset(
'/assets/appt.mp4',
closedCaptionFile: _loadCaptions(),
);
_controller.addListener(() {
setState(() {});
});
_controller.initialize();
}
@override
Widget build(BuildContext context) {
return Stack(
alignment: Alignment.bottomCenter,
children: <Widget>[
VideoPlayer(_controller),
ClosedCaption(text: _controller.value.caption.text),
VideoProgressIndicator(_controller, allowScrubbing: true),
],
);
} In React Native, you can use the React-Native-Video package to add captions in .vtt, .ttml and .srt formats. It is advised to use .vtt as it is supported on both Android and iOS.
jsx
import { TextTrackType, Video } from 'react-native-video';
<Video
textTracks={[
{
title: "English CC",
language: "en",
type: TextTrackType.VTT,
uri: "https://appt.org/subtitles/en.vtt"
},
{
title: "Spanish Subtitles",
language: "es",
type: TextTrackType.SRT,
uri: require('https://appt.org/subtitles/es.srt')
}
]}
/> In MAUI, you can use MediaElement to embed videos. Unfortunately, there is no built-in support to add captions.
xml
<toolkit:MediaElement
x:Name="mediaElement"
WidthRequest="400"
HeightRequest="300"
ShouldLoopPlayback="True"
Source="embed://videos/appt.mp4"/>
<Button
x:Name="mediaButton"
Text="Click me"
SemanticProperties.Hint="Pauses or resumes the video"
Clicked="OnMediaButtonClicked"
HorizontalOptions="Center" /> csharp
private void OnMediaButtonClicked(object sender, EventArgs e)
{
if (mediaElement.CurrentState == CommunityToolkit.Maui.Core.Primitives.MediaElementState.Paused)
mediaElement.Play();
else
mediaElement.Pause();
SetButtonSemantics();
}
private void SetButtonSemantics()
{
var description = mediaElement.CurrentState == CommunityToolkit.Maui.Core.Primitives.MediaElementState.Paused ? "Resume video" : "Pause video";
SemanticProperties.SetDescription(mediaButton, description);
SemanticScreenReader.Announce(description);
} On Xamarin, you can use MediaElement to embed videos. Unfortunately, there is no built-in support to add captions.
csharp
Not available, contribute!