TLDR
- Bitmovin’s Live Encoder now connects to Syncwords for real time auto-dubbing and subtitling.
- One live input, multiple audio languages, multiple WebVtt subtitle tracks.
- Subtitles in production for German, English, French, Italian, Portuguese, and Spanish.
- Started as a hackathon project, now a working part of Bitmovin’s Live Encoding product.
Multi-language output for a live stream means new audio and subtitle streams, manifest changes to signal them, and a translation and dubbing pipeline running in real time, not a toggle in an encoder config. Picking one language and living with it is the easy path, but it leaves viewers who don’t speak that language choosing between watching without understanding or waiting for a translated recap later. Now the picture is changing, every viewer hearing a dubbed audio track and reading subtitles in their own language, generated automatically as the event happens. No translation booth, no subtitle operators standing by, no delay.
In this blog, I’ll go into why multi-language live streaming is a harder problem than it looks, how we connected Bitmovin’s Live Encoder to Syncwords’ automated translation and dubbing service, and where DVB-subs and DVB-teletext language support stands today.
The problem we were solving
Live content is where language barriers hit hardest. Same-language captioning is common, and in the US and EU it’s often legally required, FCC rules mandate captions for most broadcast television under the CVAA, and the EU’s Audiovisual Media Services Directive pushes member states toward similar obligations. But a live event in a second or third language is a different problem, and one the law generally doesn’t touch.
Viewers who don’t speak the broadcast’s primary language are typically left to a translated recap after the fact, if one exists at all, or a broadcaster limits its own reach by defaulting to a single language rather than staffing live translators for every market. That’s an accessibility gap as much as a distribution one, since it decides who gets to follow an event as it happens instead of catching up later. There’s no post-production window to translate and dub a recording ahead of release, so the options come down to staffing live translators per language or skipping multi-language coverage.
What we built
We wanted to know how much of that gap we could close without needing a live translation team standing by for every event, so we connected Bitmovin’s Live Encoder directly to Syncwords over SRT, which handles translation, dubbing, and subtitling in real time and hands the results back as additional audio and subtitle streams. It started as a hackathon project, and DVB-subs output is now live in production for the six languages listed above.
Here’s what the integration adds to Bitmovin’s Live Encoder.
- Multiple audio streams, one per translated language.
- Multiple subtitle streams, output as WebVtt or IMSC TTML.
- A direct SRT connection into Syncwords for automated translation and dubbing.
- Manifests (HLS and DASH) that carry all of it in a single live output.
How the pieces fit together
The core of the setup is an SRT input pointed at Syncwords, configured in CALLER mode against their host and port.
inputs:
srt:
my-srt-input:
properties:
name: Syncwords SRT input
mode: CALLER
host: services.syncwords.com
port: 30033One detail worth flagging if you are setting this up yourself. Depending on how your Syncwords account is configured, you may need to switch the SRT mode from LISTENER to PULL on their side for the full integration to work end to end. The template above configures four audio streams and four subtitle streams as an example, and everything downstream is just a matter of repeating the same pattern per language. A complete, end-to-end reference template is below.
Selecting the input audio and subtitle streams
Before an audio or subtitle stream can be encoded, Bitmovin’s Live Encoder needs to know which stream on the SRT input to use. The original hackathon version selected a fixed position on the input, POSITION_ABSOLUTE with a numeric index. That works, but it’s brittle, the position has to match the exact order Syncwords sends streams in, and any change on their side breaks the mapping silently.
We’ve since moved to selectionMode: AUTO paired with a condition on the stream’s LANGUAGE attribute, which selects the correct stream by language instead of position. It’s less error-prone and easier to configure, especially as the number of languages grows.
audio-stream-eng:
properties:
inputStreams:
– inputId: $/inputs/srt/my-srt-input
inputPath: /
selectionMode: AUTO
position: 0
codecConfigId: $/configurations/audio/aac/48khz-codec-config
conditions:
type: CONDITION
attribute: LANGUAGE
operator: ==
value: engThe same pattern applies to subtitle streams, shown in the next section.
Configuring multi-audio streams
Adding additional audio languages is straightforward. Each language gets its own DASH adaptation set with a language tag and a label, pointing at its own fmp4 muxing.
audio:
audio-adaptation-set-eng:
properties:
lang: en
labels:
– value: english audio
representations:
fmp4:
eng-audio-representation:
properties:
type: TIMELINE
encodingId: $/encodings/main-encoding
muxingId: $/encodings/main-encoding/muxings/fmp4/audio-fmp4-muxing-eng
segmentPath: “dash/audio/eng/”Repeat this block for each additional language, swapping the language code, label, and muxing reference. The main thing to get right is keeping a separate DASH adaptation set per language rather than trying to reuse one.
Configuring DVB-subs
Subtitles come in through the same SRT input as a dedicated subtitle stream. As with audio, we select it by a language condition rather than a fixed position.
inputStreams:
subtitles:
dvbSubtitle:
dvb-sub-input-stream-eng:
properties:
inputId: $/inputs/srt/my-srt-input
inputPath: /
subtilte-stream-eng:
properties:
inputStreams:
– inputStreamId: $/encodings/main-encoding/inputStreams/subtitles/dvbSubtitle/dvb-sub-input-stream-eng
selectionMode: AUTO
position: 0
codecConfigId: $/configurations/subtitles/webvtt/webvtt-codec-config
conditions:
type: CONDITION
attribute: LANGUAGE
operator: ==
value: engThis needs to be added for each DVB-subs language you want to support.
That input stream then feeds a WebVTT codec configuration and a chunkedText muxing.
subtitles:
webvtt:
webvtt-codec-config:
properties:
appendOptionalZeroHour: true
chunkedText:
chunked-text-muxing-eng:
properties:
streams:
– streamId: $/encodings/main-encoding/streams/subtilte-stream-eng
segmentLength: 3.84
segmentNaming: “seg_%number%.vtt”
outputs:
– outputId: “{{outputId}}”
outputPath: “content/{{name}}/subtitles/vtt/eng”
acl:
– permission: PUBLIC_READ
streamConditionsMode: DROP_MUXING
startOffset: 10The startOffset: 10 matters more than it looks. WebVTT timing gets converted into MPEG-TS timestamps for HLS, and without an offset those timestamps land 10 seconds behind the actual playback position, since that’s the default offset already applied to the video and audio TS muxings. Native HLS players don’t always compensate for that gap on their own, so the subtitle muxing needs the same offset to stay in sync with the rest of the stream.
The complete encoding template
Here’s everything from this post combined into one working template, video, six audio languages, six DVB-subs languages selected by condition, HLS and DASH manifests. Swap in your own SRT credentials and it’s ready to run.
metadata:
type: LIVE
name: Live Translation with Syncwords
inputs:
srt:
my-srt-input:
properties:
name: Syncwords SRT input
mode: CALLER
host: services.syncwords.com
port: 30033
configurations:
video:
h264:
1920-codec-config:
properties:
width: 1920
bitrate: 1000000
rate: 25
presetConfiguration: LIVE_LOW_LATENCY
1024-codec-config:
properties:
width: 1024
bitrate: 500000
rate: 25
presetConfiguration: LIVE_LOW_LATENCY
audio:
aac:
48khz-codec-config:
properties:
bitrate: 128000
rate: 48000.0
subtitles:
webvtt:
webvtt-codec-config:
properties:
appendOptionalZeroHour: true
encodings:
main-encoding:
properties:
name: “{{name}}”
cloudRegion: GOOGLE_EUROPE_WEST_1
inputStreams:
subtitles:
dvbSubtitle:
dvb-sub-input-stream-deu:
properties:
inputId: $/inputs/srt/my-srt-input
inputPath: /
dvb-sub-input-stream-eng:
properties:
inputId: $/inputs/srt/my-srt-input
inputPath: /
dvb-sub-input-stream-fra:
properties:
inputId: $/inputs/srt/my-srt-input
inputPath: /
dvb-sub-input-stream-ita:
properties:
inputId: $/inputs/srt/my-srt-input
inputPath: /
dvb-sub-input-stream-por:
properties:
inputId: $/inputs/srt/my-srt-input
inputPath: /
dvb-sub-input-stream-spa:
properties:
inputId: $/inputs/srt/my-srt-input
inputPath: /
streams:
1920-h264-stream:
properties:
inputStreams:
– inputId: $/inputs/srt/my-srt-input
inputPath: /
selectionMode: AUTO
codecConfigId: $/configurations/video/h264/1920-codec-config
1024-h264-stream:
properties:
inputStreams:
– inputId: $/inputs/srt/my-srt-input
inputPath: /
selectionMode: AUTO
codecConfigId: $/configurations/video/h264/1024-codec-config
audio-stream-deu:
properties:
inputStreams:
– inputId: $/inputs/srt/my-srt-input
inputPath: /
selectionMode: AUTO
position: 0
codecConfigId: $/configurations/audio/aac/48khz-codec-config
conditions:
type: CONDITION
attribute: LANGUAGE
operator: ==
value: deu
audio-stream-eng:
properties:
inputStreams:
– inputId: $/inputs/srt/my-srt-input
inputPath: /
selectionMode: AUTO
position: 0
codecConfigId: $/configurations/audio/aac/48khz-codec-config
conditions:
type: CONDITION
attribute: LANGUAGE
operator: ==
value: eng
audio-stream-fra:
properties:
inputStreams:
– inputId: $/inputs/srt/my-srt-input
inputPath: /
selectionMode: AUTO
position: 0
codecConfigId: $/configurations/audio/aac/48khz-codec-config
conditions:
type: CONDITION
attribute: LANGUAGE
operator: ==
value: fra
audio-stream-ita:
properties:
inputStreams:
– inputId: $/inputs/srt/my-srt-input
inputPath: /
selectionMode: AUTO
position: 0
codecConfigId: $/configurations/audio/aac/48khz-codec-config
conditions:
type: CONDITION
attribute: LANGUAGE
operator: ==
value: ita
audio-stream-por:
properties:
inputStreams:
– inputId: $/inputs/srt/my-srt-input
inputPath: /
selectionMode: AUTO
position: 0
codecConfigId: $/configurations/audio/aac/48khz-codec-config
conditions:
type: CONDITION
attribute: LANGUAGE
operator: ==
value: por
audio-stream-spa:
properties:
inputStreams:
– inputId: $/inputs/srt/my-srt-input
inputPath: /
selectionMode: AUTO
position: 0
codecConfigId: $/configurations/audio/aac/48khz-codec-config
conditions:
type: CONDITION
attribute: LANGUAGE
operator: ==
value: spa
subtilte-stream-deu:
properties:
inputStreams:
– inputStreamId: $/encodings/main-encoding/inputStreams/subtitles/dvbSubtitle/dvb-sub-input-stream-deu
selectionMode: AUTO
position: 0
codecConfigId: $/configurations/subtitles/webvtt/webvtt-codec-config
conditions:
type: CONDITION
attribute: LANGUAGE
operator: ==
value: deu
subtilte-stream-eng:
properties:
inputStreams:
– inputStreamId: $/encodings/main-encoding/inputStreams/subtitles/dvbSubtitle/dvb-sub-input-stream-eng
selectionMode: AUTO
position: 0
codecConfigId: $/configurations/subtitles/webvtt/webvtt-codec-config
conditions:
type: CONDITION
attribute: LANGUAGE
operator: ==
value: eng
subtilte-stream-fra:
properties:
inputStreams:
– inputStreamId: $/encodings/main-encoding/inputStreams/subtitles/dvbSubtitle/dvb-sub-input-stream-fra
selectionMode: AUTO
position: 0
codecConfigId: $/configurations/subtitles/webvtt/webvtt-codec-config
conditions:
type: CONDITION
attribute: LANGUAGE
operator: ==
value: fra
subtilte-stream-ita:
properties:
inputStreams:
– inputStreamId: $/encodings/main-encoding/inputStreams/subtitles/dvbSubtitle/dvb-sub-input-stream-ita
selectionMode: AUTO
position: 0
codecConfigId: $/configurations/subtitles/webvtt/webvtt-codec-config
conditions:
type: CONDITION
attribute: LANGUAGE
operator: ==
value: ita
subtilte-stream-por:
properties:
inputStreams:
– inputStreamId: $/encodings/main-encoding/inputStreams/subtitles/dvbSubtitle/dvb-sub-input-stream-por
selectionMode: AUTO
position: 0
codecConfigId: $/configurations/subtitles/webvtt/webvtt-codec-config
conditions:
type: CONDITION
attribute: LANGUAGE
operator: ==
value: por
subtilte-stream-spa:
properties:
inputStreams:
– inputStreamId: $/encodings/main-encoding/inputStreams/subtitles/dvbSubtitle/dvb-sub-input-stream-spa
selectionMode: AUTO
position: 0
codecConfigId: $/configurations/subtitles/webvtt/webvtt-codec-config
conditions:
type: CONDITION
attribute: LANGUAGE
operator: ==
value: spa
muxings:
fmp4:
1920-fmp4-muxing-h264:
properties:
streams:
– streamId: $/encodings/main-encoding/streams/1920-h264-stream
outputs:
– outputId: “{{outputId}}”
outputPath: “content/{{name}}/dash/video/h264/1920/”
acl:
– permission: PUBLIC_READ
segmentLength: 3.84
segmentNaming: “seg_%number%.m4s”
1024-fmp4-muxing-h264:
properties:
streams:
– streamId: $/encodings/main-encoding/streams/1024-h264-stream
outputs:
– outputId: “{{outputId}}”
outputPath: “content/{{name}}/dash/video/h264/1024/”
acl:
– permission: PUBLIC_READ
segmentLength: 3.84
segmentNaming: “seg_%number%.m4s”
audio-fmp4-muxing-deu:
properties:
streams:
– streamId: $/encodings/main-encoding/streams/audio-stream-deu
outputs:
– outputId: “{{outputId}}”
outputPath: “content/{{name}}/dash/audio/deu/”
acl:
– permission: PUBLIC_READ
segmentLength: 3.84
segmentNaming: “seg_%number%.m4s”
audio-fmp4-muxing-eng:
properties:
streams:
– streamId: $/encodings/main-encoding/streams/audio-stream-eng
outputs:
– outputId: “{{outputId}}”
outputPath: “content/{{name}}/dash/audio/eng/”
acl:
– permission: PUBLIC_READ
segmentLength: 3.84
segmentNaming: “seg_%number%.m4s”
audio-fmp4-muxing-fra:
properties:
streams:
– streamId: $/encodings/main-encoding/streams/audio-stream-fra
outputs:
– outputId: “{{outputId}}”
outputPath: “content/{{name}}/dash/audio/fra/”
acl:
– permission: PUBLIC_READ
segmentLength: 3.84
segmentNaming: “seg_%number%.m4s”
audio-fmp4-muxing-ita:
properties:
streams:
– streamId: $/encodings/main-encoding/streams/audio-stream-ita
outputs:
– outputId: “{{outputId}}”
outputPath: “content/{{name}}/dash/audio/ita/”
acl:
– permission: PUBLIC_READ
segmentLength: 3.84
segmentNaming: “seg_%number%.m4s”
audio-fmp4-muxing-por:
properties:
streams:
– streamId: $/encodings/main-encoding/streams/audio-stream-por
outputs:
– outputId: “{{outputId}}”
outputPath: “content/{{name}}/dash/audio/por/”
acl:
– permission: PUBLIC_READ
segmentLength: 3.84
segmentNaming: “seg_%number%.m4s”
audio-fmp4-muxing-spa:
properties:
streams:
– streamId: $/encodings/main-encoding/streams/audio-stream-spa
outputs:
– outputId: “{{outputId}}”
outputPath: “content/{{name}}/dash/audio/spa/”
acl:
– permission: PUBLIC_READ
segmentLength: 3.84
segmentNaming: “seg_%number%.m4s”
chunkedText:
chunked-text-muxing-deu:
properties:
streams:
– streamId: $/encodings/main-encoding/streams/subtilte-stream-deu
segmentLength: 3.84
segmentNaming: “seg_%number%.vtt”
outputs:
– outputId: “{{outputId}}”
outputPath: “content/{{name}}/subtitles/vtt/deu”
acl:
– permission: PUBLIC_READ
streamConditionsMode: DROP_MUXING
startOffset: 10
chunked-text-muxing-eng:
properties:
streams:
– streamId: $/encodings/main-encoding/streams/subtilte-stream-eng
segmentLength: 3.84
segmentNaming: “seg_%number%.vtt”
outputs:
– outputId: “{{outputId}}”
outputPath: “content/{{name}}/subtitles/vtt/eng”
acl:
– permission: PUBLIC_READ
streamConditionsMode: DROP_MUXING
startOffset: 10
chunked-text-muxing-fra:
properties:
streams:
– streamId: $/encodings/main-encoding/streams/subtilte-stream-fra
segmentLength: 3.84
segmentNaming: “seg_%number%.vtt”
outputs:
– outputId: “{{outputId}}”
outputPath: “content/{{name}}/subtitles/vtt/fra”
acl:
– permission: PUBLIC_READ
streamConditionsMode: DROP_MUXING
startOffset: 10
chunked-text-muxing-ita:
properties:
streams:
– streamId: $/encodings/main-encoding/streams/subtilte-stream-ita
segmentLength: 3.84
segmentNaming: “seg_%number%.vtt”
outputs:
– outputId: “{{outputId}}”
outputPath: “content/{{name}}/subtitles/vtt/ita”
acl:
– permission: PUBLIC_READ
streamConditionsMode: DROP_MUXING
startOffset: 10
chunked-text-muxing-por:
properties:
streams:
– streamId: $/encodings/main-encoding/streams/subtilte-stream-por
segmentLength: 3.84
segmentNaming: “seg_%number%.vtt”
outputs:
– outputId: “{{outputId}}”
outputPath: “content/{{name}}/subtitles/vtt/por”
acl:
– permission: PUBLIC_READ
streamConditionsMode: DROP_MUXING
startOffset: 10
chunked-text-muxing-spa:
properties:
streams:
– streamId: $/encodings/main-encoding/streams/subtilte-stream-spa
segmentLength: 3.84
segmentNaming: “seg_%number%.vtt”
outputs:
– outputId: “{{outputId}}”
outputPath: “content/{{name}}/subtitles/vtt/spa”
acl:
– permission: PUBLIC_READ
streamConditionsMode: DROP_MUXING
startOffset: 10
live:
start:
properties:
streamKey: my-stream-key
manifestGenerator: V2
autoShutdownConfiguration:
streamTimeoutMinutes: 180
bytesReadTimeoutSeconds: 300
hlsManifests:
– manifestId: $/manifests/hls/defaultapi/main-hls-manifest
timeshift: 120
liveEdgeOffset: 3.84
insertProgramDateTime: true
dashManifests:
– manifestId: $/manifests/dash/timeline-dash-manifest
timeshift: 120
liveEdgeOffset: 3.84
manifests:
hls:
defaultapi:
main-hls-manifest:
properties:
name: Main HLS Manifest
manifestName: main.m3u8
encodingId: $/encodings/main-encoding
outputs:
– outputId: “{{outputId}}”
outputPath: “content/{{name}}/”
acl:
– permission: PUBLIC_READ
dash:
timeline-dash-manifest:
properties:
name: Timeline Dash Manifest
manifestName: stream.mpd
outputs:
– outputId: “{{outputId}}”
outputPath: “content/{{name}}/”
acl:
– permission: PUBLIC_READ
periods:
period-1:
properties:
start: 0
adaptationsets:
video:
video-adaptation-set:
properties:
labels:
– value: video adaptation set
representations:
fmp4:
1920-representation:
properties:
type: TIMELINE
encodingId: $/encodings/main-encoding
muxingId: $/encodings/main-encoding/muxings/fmp4/1920-fmp4-muxing-h264
segmentPath: “dash/video/h264/1920/”
1024-representation:
properties:
type: TIMELINE
encodingId: $/encodings/main-encoding
muxingId: $/encodings/main-encoding/muxings/fmp4/1024-fmp4-muxing-h264
segmentPath: “dash/video/h264/1024/”
audio:
audio-adaptation-set-deu:
properties:
lang: deu
labels:
– value: german audio
representations:
fmp4:
deu-audio-representation:
properties:
type: TIMELINE
encodingId: $/encodings/main-encoding
muxingId: $/encodings/main-encoding/muxings/fmp4/audio-fmp4-muxing-deu
segmentPath: “dash/audio/deu/”
audio-adaptation-set-eng:
properties:
lang: en
labels:
– value: english audio
representations:
fmp4:
eng-audio-representation:
properties:
type: TIMELINE
encodingId: $/encodings/main-encoding
muxingId: $/encodings/main-encoding/muxings/fmp4/audio-fmp4-muxing-eng
segmentPath: “dash/audio/eng/”
audio-adaptation-set-fra:
properties:
lang: fra
labels:
– value: french audio
representations:
fmp4:
fra-audio-representation:
properties:
type: TIMELINE
encodingId: $/encodings/main-encoding
muxingId: $/encodings/main-encoding/muxings/fmp4/audio-fmp4-muxing-fra
segmentPath: “dash/audio/fra/”
audio-adaptation-set-ita:
properties:
lang: ita
labels:
– value: italian audio
representations:
fmp4:
ita-audio-representation:
properties:
type: TIMELINE
encodingId: $/encodings/main-encoding
muxingId: $/encodings/main-encoding/muxings/fmp4/audio-fmp4-muxing-ita
segmentPath: “dash/audio/ita/”
audio-adaptation-set-por:
properties:
lang: por
labels:
– value: portuguese audio
representations:
fmp4:
por-audio-representation:
properties:
type: TIMELINE
encodingId: $/encodings/main-encoding
muxingId: $/encodings/main-encoding/muxings/fmp4/audio-fmp4-muxing-por
segmentPath: “dash/audio/por/”
audio-adaptation-set-spa:
properties:
lang: spa
labels:
– value: spanish audio
representations:
fmp4:
spa-audio-representation:
properties:
type: TIMELINE
encodingId: $/encodings/main-encoding
muxingId: $/encodings/main-encoding/muxings/fmp4/audio-fmp4-muxing-spa
segmentPath: “dash/audio/spa/”Setting up Syncwords
The Syncwords setup wizard is genuinely easy to work through. A few things we picked up along the way.
- Cloned Voice. For translated audio, this option does a good job of imitating the original speaker’s voice rather than dropping in a generic voiceover.
- SRT pull clients. Their official documentation says only one pull client is supported, but their team confirmed on a call that it actually handles up to 10, useful to know if you are fanning out to multiple encoders.
- Output formats. Bitmovin currently supports DVB-subs. DVB-teletext decoding support is still in development.
- DVB-subs. Picture based rather than text based, so any character set is supported at the source. We OCR them back into text with Tesseract to produce WebVTT, and in production today we only have language models installed for German, English, French, Italian, Portuguese, and Spanish. That’s the current limit on which DVB-subs languages are supported end to end. OCR accuracy also varies with source image quality and font, so it’s worth spot-checking output for a given feed rather than assuming perfect transcription.
Results
Here’s what the output looks like in practice. A default HLS manifest with four audio languages and four subtitle tracks attached.
#EXTM3U
#EXT-X-INDEPENDENT-SEGMENTS
#EXT-X-VERSION:6
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=”AUDIO”,NAME=”audio_0.m3u8″,LANGUAGE=”en”,URI=”audio_0.m3u8″
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=”AUDIO”,NAME=”audio_1.m3u8″,LANGUAGE=”de”,URI=”audio_1.m3u8″
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=”AUDIO”,NAME=”audio_2.m3u8″,LANGUAGE=”fr”,URI=”audio_2.m3u8″
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=”AUDIO”,NAME=”audio_3.m3u8″,LANGUAGE=”es”,URI=”audio_3.m3u8″
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=”SUBTITLES”,NAME=”subtitle_0.m3u8″,LANGUAGE=”en”,URI=”subtitle_0.m3u8″
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=”SUBTITLES”,NAME=”subtitle_1.m3u8″,LANGUAGE=”de”,URI=”subtitle_1.m3u8″
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=”SUBTITLES”,NAME=”subtitle_2.m3u8″,LANGUAGE=”fr”,URI=”subtitle_2.m3u8″
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=”SUBTITLES”,NAME=”subtitle_3.m3u8″,LANGUAGE=”es”,URI=”subtitle_3.m3u8″
#EXT-X-STREAM-INF:BANDWIDTH=628000,CODECS=”avc1.64001F,mp4a.40.2″,RESOLUTION=1024×576,AUDIO=”AUDIO”,SUBTITLES=”SUBTITLES”,FRAME-RATE=25.0
video_0.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1128000,CODECS=”avc1.640028,mp4a.40.2″,RESOLUTION=1920×1080,AUDIO=”AUDIO”,SUBTITLES=”SUBTITLES”,FRAME-RATE=25.0
video_1.m3u8
You can see a live player demo and the underlying HLS and DASH endpoints from our proof of concept run, which we’re happy to share with anyone who wants to see it working end to end. If you want to try switching between the multiple audio and subtitle tracks yourself, our test stream demo lets you do exactly that.
What’s next
A few things are still on our list. We want to add support for side-loading additional Tesseract language models, so DVB-subs support can grow past the current six languages without waiting on a full release. We’re also looking at automatic audio and subtitle stream selection and passthrough, extending PerTitle Streams to cover audio and subtitle tracks, and adding DVB-TTML as an additional subtitle output format.
Want to try multi-language live streaming yourself? Sign up for a trial of Bitmovin’s Live Encoder and start testing.