Overview
The Video SDK supports inserting subtitle tracks into MPEG transport stream outputs, including file output and network delivery over UDP or SRT. Subtitles are generated from text subtitle files (ASS or SRT) and can be encoded as bitmap DVB subtitles, as DVB Teletext, or as both in the same output.
Note: Subtitle insertion may require the Closed Caption plugin license.
For ASS/SRT-to-DVB subtitle transcoding, use an x64 application and x64 SDK components. Check that your installed SDK build includes the Arabic and Hebrew encoding support described below. Character-set settings affect text encoded as dvbtxt; they do not change subtitle packets that are copied without re-encoding.
Subtitle output types
| Output type | Writer codec | Kind | Notes |
|---|---|---|---|
| DVB subtitles | subtitle::codec='dvbsub' |
Bitmap | Supports rendering options such as background, outline and alpha values. |
| DVB Teletext subtitles | subtitle::codec='dvbtxt' |
Text | Formatting may be limited by the Teletext output format. Character sets and the page layout are configured in step 5. |
The same output can contain both subtitle output types at the same time. For example, one subtitle track can be encoded as DVB Teletext with subtitle::codec='dvbtxt', while another subtitle track can be encoded as bitmap DVB subtitles with subtitle.1::codec='dvbsub'.
Input subtitle formats
| Format | When to use |
|---|---|
.ass |
Recommended when the formatting should be stored in the subtitle file itself. ASS files support text formatting through the ASS style header. The sample includes an example.ass file and loads it by default. |
.srt |
Plain subtitle text. The formatting is configured with the writer properties (step 4). |
The reader loads subtitle files directly through the external_subtitle property. Multiple subtitle tracks can be attached to the reader at the same time. Each subtitle track can be assigned its own stream ID, output codec, and language metadata.
Ready-to-use samples
The workflow of this article is implemented in the Subtitle Conversion Sample. It plays a source file or a playlist, loads ASS and SRT subtitle tracks (or lets you create and edit them), shows the subtitle style and writes MPEG-TS with bitmap DVB subtitles or DVB Teletext to a file, UDP or SRT. Each subtitle track has its own stream ID, PID, language and, for Teletext, the page number and the data identifier. Subtitles that are created while the stream is running are inserted by the Subtitle Generation Sample, see How to Insert DVB Subtitles and DVB Teletext On the Fly During Live Output.
| SDK | Sample | Folder |
|---|---|---|
| MFormats | Sample Subtitle Conversion | C:\Program Files (x86)\Medialooks\MFormats SDK\Samples\C#\Sample Subtitle Conversion |
| MPlatform | Subtitle Conversion Sample | C:\Program Files (x86)\Medialooks\MPlatform SDK\Samples Basic\C#\Subtitle Conversion Sample |
The Subtitle Conversion Sample replaces the Subtitle Insertion Sample of the earlier SDK versions.
How to generate and insert subtitle tracks
The subtitle insertion process consists of the following steps:
| Step | What you do | Main properties |
|---|---|---|
| 1 | Prepare or generate subtitle tracks in .ass or .srt format. |
- |
| 2 | Attach one or more subtitle files directly to the reader and assign a stream ID to each track. |
external_subtitle, external_subtitle.stream_id, experimental.out_subtitle_packets
|
| 3 | Configure the writer subtitle codec, stream ID and language metadata. |
subtitle::codec, subtitle::stream_id, subtitle::metadata::language
|
| 4 | Optionally configure the subtitle formatting. |
subtitle::font, subtitle::font_size, subtitle::outline and others |
| 5 | Optionally configure the Teletext character sets, the Teletext layout and the DVB subtitle type. |
subtitle::teletext_primary_charset, subtitle::teletext_bottom_row, subtitle::subtitling_type
|
| 6 | Start the writer and play or process the source (see the MPlatform and MFormats examples). | - |
1. Prepare ASS or SRT subtitle files
The sample can load existing .ass or .srt subtitle files. It can also generate temporary subtitle files from the subtitle editor UI.
ASS is the default subtitle format because it allows the sample to store text formatting in the subtitle file header.
ASS generation example
string subFile = Path.Combine(Path.GetTempPath(), "temp_subtitle_track_0.ass");
File.WriteAllText(
subFile,
AssSubtitleHelper.BuildAss(
track.Subtitles,
styleSettings,
"DVB Subtitle Inserter"));
SRT generation example
string subFile = Path.Combine(Path.GetTempPath(), "temp_subtitle_track_0.srt");
using var writer = new StreamWriter(subFile);
foreach (var subtitle in track.Subtitles)
{
writer.WriteLine(subtitle.Index);
writer.WriteLine($"{subtitle.StartTime} --> {subtitle.EndTime}");
writer.WriteLine(subtitle.Text);
writer.WriteLine();
}
The generated subtitle file is then passed directly to the reader. No VobSub conversion is required. If a subtitle file contains non-Latin text, save it in UTF-8.
2. Attach subtitle files to the reader
Subtitle files are attached by setting the reader properties below. For a single subtitle track, use external_subtitle.
| Property | Description |
|---|---|
external_subtitle |
Path to the .ass or .srt file of the first subtitle track. |
external_subtitle.stream_id |
Stream ID of the first subtitle track. The writer uses it to find this track. |
external_subtitle.N, external_subtitle.stream_id.N
|
Path and stream ID of the subtitle track with the index N (1, 2, ...). |
experimental.out_subtitle_packets |
Set to 2 to pass the subtitle packets of the attached tracks to the writer. See the modes. |
external_subtitle_track, external_subtitle_track.N
|
Which subtitle track of the attached file to use. The default is 0, the first track. -1 disables the file, all uses every subtitle track, a list such as 0,1 uses the listed tracks. A single .ass or .srt file has one track, so the default is what you need. |
subtitle_track |
Subtitle track selection. The examples use 0. |
external_process |
The examples set it to false. |
loop |
Set to true to play the source again and again. The sample adds loop=true to the reader configuration when the loop option (Loop playlist in the Conversion sample, Loop source in the Generation sample) is on. |
One subtitle track
string subtitleFile = @"C:\Subtitles\example.ass";
string readerConfig =
"subtitle_track=0 experimental.out_subtitle_packets=2 external_process=false " +
$"external_subtitle='{subtitleFile}'";
Several subtitle tracks
For multiple subtitle tracks, use indexed external_subtitle properties. Each subtitle track can also be assigned a stream ID with external_subtitle.stream_id.
string subPath1 = @"C:\Subtitles\english.ass";
string subPath2 = @"C:\Subtitles\greek.ass";
string readerConfig =
"external_process=false subtitle_track=0 experimental.out_subtitle_packets=2 " +
"external_subtitle.stream_id=117 " +
$"external_subtitle='{subPath1}' " +
"external_subtitle.stream_id.1=118 " +
$"external_subtitle.1='{subPath2}'";
The stream ID connects a specific reader subtitle track to the corresponding writer subtitle configuration. For example, the subtitle track assigned to external_subtitle.stream_id=117 can later be configured in the writer with subtitle::stream_id=117.
Modes of experimental.out_subtitle_packets
| Value | Subtitles on the picture | Packets for the writer | Use |
|---|---|---|---|
0 (default) |
Yes, the subtitle is decoded and shown in the video | No | Playback with subtitles (see Displaying DVB subtitles/teletext from transport stream) |
1 |
Yes | Yes | The subtitle is written to the output and is also drawn on the video frames |
2 |
No | Yes | Insertion of subtitle tracks into the output, as in this article |
The value 2 is the one to use for the insertion: the subtitle goes into the output as a separate subtitle stream and is not burned into the picture. With 1 the viewer sees the text twice, once from the video and once from the subtitle track.
Several files are attached with the indexes external_subtitle, external_subtitle.1, external_subtitle.2 and so on. The indexes have to be consecutive: the list ends at the first index that is empty, so the file external_subtitle.3 after a missing external_subtitle.2 is ignored. A file that cannot be opened is skipped and the next index is still read.
3. Configure writer subtitle tracks
The writer configuration defines how each subtitle track should be encoded in the output stream.
| Property | Description |
|---|---|
subtitle::codec |
dvbsub encodes the track as bitmap DVB subtitles, dvbtxt encodes it as DVB Teletext subtitles. |
subtitle::stream_id |
Stream ID of the reader subtitle track that this writer track encodes (see external_subtitle.stream_id). |
subtitle::metadata::language |
Language of the track as a three-letter code, for example eng or ell. For DVB Teletext, this also selects the character set when no primary override is supplied. See Teletext languages for the recognized mappings. Use mul for multiple languages and configure the character sets when needed (see step 5). |
subtitle::pid |
The PID of the subtitle stream in the MPEG transport stream, for example subtitle::pid=117. The PID has to be 16 or more. If another stream of the output already uses the PID, the writer takes the next free one. The sample uses the stream ID when no PID is set. |
Multiple subtitle tracks are configured with indexed subtitle properties. The index in the reader and writer property names is the same:
| Track | Reader: file | Reader: stream ID | Writer: codec | Writer: stream ID | Writer: language |
|---|---|---|---|---|---|
| First | external_subtitle |
external_subtitle.stream_id |
subtitle::codec |
subtitle::stream_id |
subtitle::metadata::language |
| Second | external_subtitle.1 |
external_subtitle.stream_id.1 |
subtitle.1::codec |
subtitle.1::stream_id |
subtitle.1::metadata::language |
| Track N | external_subtitle.N |
external_subtitle.stream_id.N |
subtitle.N::codec |
subtitle.N::stream_id |
subtitle.N::metadata::language |
Use dvbsub when the output track should be encoded as bitmap DVB subtitles:
subtitle::codec='dvbsub'
Use dvbtxt when the output track should be encoded as DVB Teletext subtitles:
subtitle::codec='dvbtxt'
Single bitmap DVB subtitle track
format='mpegts'
video::codec='libopenh264'
audio::codec='aac'
video::b='5M'
mux_buffers=0
subtitle::codec='dvbsub'
subtitle::stream_id=117
subtitle::metadata::language='eng'
video::maxrate='5M'
program::title='Medialooks DVB subtitles test'
Single DVB Teletext subtitle track
format='mpegts'
video::codec='libopenh264'
audio::codec='aac'
video::b='5M'
mux_buffers=0
subtitle::codec='dvbtxt'
subtitle::stream_id=117
subtitle::metadata::language='eng'
video::maxrate='5M'
program::title='Medialooks DVB Teletext test'
Two subtitle tracks
In the example below, the first subtitle track is written as DVB Teletext and the second subtitle track is written as bitmap DVB subtitles.
format='mpegts'
video::codec='libopenh264'
audio::codec='aac'
video::b='5M'
mux_buffers=0
subtitle::codec='dvbtxt'
subtitle::stream_id=117
subtitle::metadata::language='eng'
subtitle.1::codec='dvbsub'
subtitle.1::stream_id=118
subtitle.1::metadata::language='ell'
video::maxrate='5M'
program::title='Medialooks subtitle test'
4. Configure subtitle formatting in the writer
Basic subtitle text formatting can also be configured directly in the writer configuration. These properties are useful for common styling options such as font, font size, colors, background, and outline.
Formatting support depends on the selected subtitle output type. Bitmap DVB subtitles can use rendering options such as background, outline, and alpha values. DVB Teletext subtitle formatting may be limited by the Teletext output format.
| Property | Value | Example | Notes |
|---|---|---|---|
subtitle::font |
Font name | 'Arial' |
|
subtitle::font_size |
Font size | 26 |
|
subtitle::font_color |
Color as a hex value | 'FFFFFF' |
|
subtitle::background |
true or false
|
true |
|
subtitle::background_color |
Color as a hex value | '000000' |
|
subtitle::background_alpha |
Alpha value | 128 |
|
subtitle::outline |
true or false
|
true |
|
subtitle::outline_color |
Color as a hex value | '000000' |
|
subtitle::outline_thickness |
Outline thickness | 2 |
|
subtitle::outline_alpha |
Alpha value | 255 |
For bitmap DVB subtitles. |
format='mpegts'
video::codec='libopenh264'
audio::codec='aac'
video::b='5M'
mux_buffers=0
subtitle::codec='dvbsub'
subtitle::stream_id=117
subtitle::metadata::language='eng'
subtitle::font='Arial'
subtitle::font_size=26
subtitle::font_color='FFFFFF'
subtitle::background=true
subtitle::background_color='000000'
subtitle::background_alpha=128
subtitle::outline=true
subtitle::outline_color='000000'
subtitle::outline_thickness=2
subtitle::outline_alpha=255
video::maxrate='5M'
program::title='Medialooks subtitle test'
For indexed subtitle tracks, use the same indexed prefix as for other subtitle properties. For example, formatting for the second subtitle track can be set with subtitle.1::font, subtitle.1::font_size, and subtitle.1::font_color.
subtitle.1::codec='dvbsub'
subtitle.1::stream_id=118
subtitle.1::metadata::language='ell'
subtitle.1::font='Arial'
subtitle.1::font_size=26
subtitle.1::font_color='FFFFFF'
subtitle.1::outline=true
subtitle.1::outline_color='000000'
subtitle.1::outline_thickness=2
ASS headers are still supported and are useful when custom formatting is required in the subtitle file itself. For standard output formatting, the writer subtitle formatting properties can be used directly in the encoder configuration.
5. Advanced options
These options are optional. They apply to DVB Teletext (dvbtxt) or to DVB subtitles (dvbsub), as shown in the table. For indexed tracks, use the indexed prefix, for example subtitle.1::teletext_bottom_row.
All entries in this table are configurable writer settings, not read-only statistics. Include them in the configuration passed to MWriter.WriterNameSet or MFWriter.WriterSet, before processing subtitle packets. Close and reopen the writer when changing the character-set configuration.
| Property | Applies to | Description |
|---|---|---|
subtitle::teletext_primary_charset |
dvbtxt |
The primary character set: latin, cyrillic_russian_bulgarian, arabic or hebrew. Other values are invalid and prevent subtitle encoder initialization. An explicit value overrides the character set selected from subtitle::metadata::language, while the language metadata remains unchanged. If omitted, the encoder uses the language mappings in Teletext languages. If the language is empty or mul and neither character-set override is set, it detects the dominant supported alphabet from the first subtitle containing supported letters, with Latin used before detection. For an empty or mul language with only the secondary set explicitly, the initial primary fallback is cyrillic_russian_bulgarian when the secondary is latin, and latin otherwise. If the detected primary matches the explicit secondary, the encoder replaces it with that fallback to keep the sets different. Once resolved, the primary stays fixed until the encoder is recreated. |
subtitle::teletext_secondary_charset |
dvbtxt |
The secondary character set, with the same four possible values as the primary setting. If omitted, the encoder can add Latin when the primary set is not latin, or Russian/Bulgarian Cyrillic when the primary is latin, as needed by the cue text. Configure both properties for other supported pairs. If both sets are explicit, they must be different; invalid values or identical explicit sets prevent subtitle encoder initialization. |
subtitle::teletext_bottom_row |
dvbtxt |
The bottom row of the Teletext page that the subtitle text uses, from 1 to 23. The subtitle block keeps its height of up to three lines and ends at this row. Without the property, the subtitles use the rows 21 to 23. One line is placed in the last row, two lines in the last two rows, and so on; more than three lines are cut to the last three. |
subtitle::page_number |
dvbtxt |
The Teletext subtitle page, a decimal number from 100 to 899. The default is 888. A value outside this range prevents subtitle encoder initialization. This is a page number, not the reader stream ID or the output PID. |
subtitle::data_identifier |
dvbtxt |
The data identifier byte at the start of the Teletext data. The default value is 0x10. |
subtitle::subtitling_type |
dvbsub |
The subtitling type byte of the DVB subtitle descriptor in the PMT, for example 0x24 or 0x25. If subtitle::metadata::language contains several languages separated by commas, a descriptor with the same type is written for each language. For compatibility, subtitle::data_identifier works as an alias of this property when the codec is dvbsub. If you set both, subtitle::subtitling_type is used. |
subtitle::default_font |
dvbsub |
The default font used to render the bitmap DVB subtitles, for example 'Times New Roman'. |
subtitle::canvas_width, subtitle::canvas_height
|
dvbsub |
Optional width and height of the canvas on which the bitmap DVB subtitles are rendered, for example subtitle::canvas_height=576. |
Example: one Teletext track with Latin and Cyrillic text, with the subtitles on the rows 11 to 13:
format='mpegts' mux_buffers=0
subtitle::codec='dvbtxt'
subtitle::stream_id=117
subtitle::metadata::language='mul'
subtitle::teletext_primary_charset='latin'
subtitle::teletext_secondary_charset='cyrillic_russian_bulgarian'
subtitle::teletext_bottom_row=13
video::codec='libopenh264'
video::maxrate='5M'
audio::codec='aac'
Example: one bitmap DVB subtitle track with the subtitling type, the default font and the canvas height set:
format='mpegts' mux_buffers=0
subtitle::codec='dvbsub'
subtitle::stream_id=76
subtitle::metadata::language='eng'
subtitle::subtitling_type=0x24
subtitle::default_font='Times New Roman'
subtitle::canvas_height=576
video::codec='libopenh264'
video::maxrate='5M'
audio::codec='aac'
Teletext languages, Arabic and Hebrew
For an Arabic track, set subtitle::metadata::language='ara'; for Hebrew, use 'heb'. Without an explicit primary override, these values select the Arabic and Hebrew character sets respectively.
The table below describes the confirmed language-to-character-set mappings when teletext_primary_charset is omitted. It is a selection reference, not a promise that every Unicode character in a language is representable. The code spellings shown are the ones recognized for these mappings. If the metadata contains a comma-separated language list, its first language determines the primary character set.
| Language metadata | Language | Selected character set |
|---|---|---|
ara |
Arabic | Arabic G0 |
heb |
Hebrew | Hebrew G0 |
cze, slo
|
Czech, Slovak | Latin Czech/Slovak national subset |
hun, fin
|
Hungarian, Finnish | Latin Swedish/Finnish/Hungarian national subset |
est |
Estonian | Latin Estonian national subset |
lav, lit
|
Latvian, Lithuanian | Latin Latvian/Lithuanian national subset |
pol |
Polish | Latin Polish national subset |
tur |
Turkish | Latin Turkish national subset |
smi |
Saami | Latin Serbian/Croatian/Slovenian national subset |
srp, mac
|
Serbian, Macedonian | Serbian/Croatian Cyrillic G0 |
rus, bul
|
Russian, Bulgarian | Russian/Bulgarian Cyrillic G0 |
ukr, bel
|
Ukrainian, Belarusian | Ukrainian Cyrillic G0 |
gre |
Greek | Greek G0 |
Empty or mul
|
Unspecified or multiple languages | With neither character-set override set, detects the dominant Latin, Russian/Bulgarian Cyrillic, Arabic or Hebrew alphabet from the first cue containing supported letters; Latin is used before detection. An explicit secondary changes the initial fallback and can replace a matching detected primary, as described in step 5. For example, with no primary override and teletext_secondary_charset='latin', Hello мир selects Russian/Bulgarian Cyrillic as primary even though Latin letters dominate. |
| Other nonempty codes | For example eng
|
Latin fallback. Setting a language code does not add a character set for an unsupported script. |
Use the appropriate language mapping for national subsets and Greek. Automatic detection with mul does not select every language-specific set. The four values accepted by the explicit primary and secondary properties remain latin, cyrillic_russian_bulgarian, arabic and hebrew; do not use the descriptive table names as property values.
Supply Arabic and Hebrew text in its normal logical reading order. The encoder applies right-to-left visual ordering and Arabic letter shaping. Mixed Latin words and numbers are handled during this conversion; do not reverse the input string yourself.
Teletext has a limited character repertoire. Arabic combining marks, including vowel marks, are removed during encoding. The available character sets do not cover Hindi, Tamil, Telugu, Thai, Japanese, Chinese or Korean. When Teletext cannot represent your text, choose subtitle::codec='dvbsub' and use a font that contains the required glyphs.
Example: separate Arabic and Hebrew tracks
Save arabic.srt and hebrew.srt in UTF-8, with normal SRT cue timings. Include representative text such as مرحبا VLC 2026 and שלום VLC 2026. The following configuration attaches the two files and lets their language metadata select the Teletext character sets:
string arabicFile = @"C:\Subtitles\arabic.srt";
string hebrewFile = @"C:\Subtitles\hebrew.srt";
string readerConfig =
"external_process=false subtitle_track=0 experimental.out_subtitle_packets=2 " +
"external_subtitle.stream_id=117 " +
$"external_subtitle='{arabicFile}' " +
"external_subtitle.stream_id.1=118 " +
$"external_subtitle.1='{hebrewFile}'";
string writerConfig =
"format='mpegts' mux_buffers=0 " +
"video::codec='libopenh264' video::b='5M' video::maxrate='5M' audio::codec='aac' " +
"subtitle::codec='dvbtxt' subtitle::stream_id=117 subtitle::metadata::language='ara' " +
"subtitle.1::codec='dvbtxt' subtitle.1::stream_id=118 subtitle.1::metadata::language='heb'";
Use these strings in the MPlatform or MFormats processing pattern below. Each reader stream ID must match its writer track. If you need to fix an Arabic/Latin pair explicitly, add subtitle::teletext_primary_charset='arabic' subtitle::teletext_secondary_charset='latin' to the first track's writer configuration.
MPlatform full example
The following example opens a source file, attaches two external subtitle tracks, configures the writer, and starts subtitle insertion.
string sourceFile = @"C:\Media\input.ts";
string outputUrl = @"C:\Media\output.ts";
string subPath1 = @"C:\Subtitles\english.ass";
string subPath2 = @"C:\Subtitles\greek.ass";
string readerConfig =
"external_process=false subtitle_track=0 experimental.out_subtitle_packets=2 " +
"external_subtitle.stream_id=117 " +
$"external_subtitle='{subPath1}' " +
"external_subtitle.stream_id.1=118 " +
$"external_subtitle.1='{subPath2}'";
string writerConfig =
"format='mpegts' video::codec='libopenh264' audio::codec='aac' " +
"video::b='5M' mux_buffers=0 " +
"subtitle::codec='dvbtxt' subtitle::stream_id=117 subtitle::metadata::language='eng' " +
"subtitle::font='Arial' subtitle::font_size=26 subtitle::font_color='FFFFFF' " +
"subtitle.1::codec='dvbsub' subtitle.1::stream_id=118 subtitle.1::metadata::language='ell' " +
"subtitle.1::font='Arial' subtitle.1::font_size=26 subtitle.1::font_color='FFFFFF' " +
"subtitle.1::outline=true subtitle.1::outline_color='000000' subtitle.1::outline_thickness=2 " +
"video::maxrate='5M' program::title='Medialooks subtitle test'";
MFileClass file = null;
MWriterClass writer = null;
try
{
file = new MFileClass();
writer = new MWriterClass();
file.FileNameSet(sourceFile, readerConfig);
writer.WriterNameSet(outputUrl, writerConfig);
writer.ObjectStart(file);
file.FilePlayStart();
// Keep the application running while the source is being processed.
}
finally
{
if (writer != null)
Marshal.ReleaseComObject(writer);
if (file != null)
Marshal.ReleaseComObject(file);
}
MFormats full example
In MFormats SDK, read frames from MFReader and pass them to MFWriter. The example below shows the main processing pattern.
string sourceFile = @"C:\Media\input.ts";
string outputUrl = @"C:\Media\output.ts";
string subPath1 = @"C:\Subtitles\english.ass";
string subPath2 = @"C:\Subtitles\greek.ass";
string readerConfig =
"external_process=false subtitle_track=0 experimental.out_subtitle_packets=2 " +
"external_subtitle.stream_id=117 " +
$"external_subtitle='{subPath1}' " +
"external_subtitle.stream_id.1=118 " +
$"external_subtitle.1='{subPath2}'";
string writerConfig =
"format='mpegts' video::codec='libopenh264' audio::codec='aac' " +
"video::b='5M' mux_buffers=0 " +
"subtitle::codec='dvbtxt' subtitle::stream_id=117 subtitle::metadata::language='eng' " +
"subtitle::font='Arial' subtitle::font_size=26 subtitle::font_color='FFFFFF' " +
"subtitle.1::codec='dvbsub' subtitle.1::stream_id=118 subtitle.1::metadata::language='ell' " +
"subtitle.1::font='Arial' subtitle.1::font_size=26 subtitle.1::font_color='FFFFFF' " +
"subtitle.1::outline=true subtitle.1::outline_color='000000' subtitle.1::outline_thickness=2 " +
"video::maxrate='5M' program::title='Medialooks subtitle test'";
MFReaderClass reader = null;
MFWriterClass writer = null;
try
{
reader = new MFReaderClass();
writer = new MFWriterClass();
reader.ReaderOpen(sourceFile, readerConfig);
writer.WriterSet(outputUrl, 1, writerConfig);
while (true)
{
MFFrame frame = null;
try
{
reader.SourceFrameGet(-1, out frame, "");
if (frame == null)
break;
writer.ReceiverFramePut(frame, -1, ""); // -1: wait until the writer accepts the frame
}
finally
{
if (frame != null)
Marshal.ReleaseComObject(frame);
}
}
reader.ReaderClose();
}
finally
{
if (writer != null)
Marshal.ReleaseComObject(writer);
if (reader != null)
Marshal.ReleaseComObject(reader);
}
Output to UDP
For a file or an SRT output the examples above use format='mpegts'. For a udp:// output the Subtitle Conversion Sample and the Subtitle Generation Sample change the writer configuration: they replace format='mpegts' with format='dvb' and add protocol='udp://'. The subtitle properties stay the same:
format='dvb' protocol='udp://' mux_buffers=0
subtitle::codec='dvbtxt' subtitle::stream_id=117 subtitle::metadata::language='eng'
video::codec='libopenh264' video::maxrate='5M' audio::codec='aac'
The output URL is, for example, udp://239.0.0.1:7777. The sample proposes udp://0.0.0.0:7777 and srt://0.0.0.0:7777?mode=caller as the defaults of the two output types.
If the output has no subtitles
| Check | What to do |
|---|---|
| Subtitle packets from the reader | Set experimental.out_subtitle_packets=2 in the reader properties. |
| Stream IDs | The external_subtitle.stream_id value must be the same as subtitle::stream_id of the writer track (and with the same index for the other tracks). |
| Non-Latin text | Save the subtitle file in UTF-8. For Teletext, check the language and the character sets in step 5. For Arabic and Hebrew, use ara and heb or the appropriate explicit override. Check the actual cue text, shaped letters, Latin words and digit order on the target receiver; a correct language label alone is insufficient. See Teletext languages for character limitations. |
| Missing or invalid subtitle file | If an external subtitle file cannot be loaded, the other streams of the output are still muxed. Check the path in external_subtitle. |
| Picture and subtitle track at the same time | The subtitle text is drawn on the video and written as a subtitle track when experimental.out_subtitle_packets=1. Use 2 to get the track only. |
| The second or the third file is ignored | The indexes of external_subtitle have to be consecutive (external_subtitle, .1, .2). The list stops at the first empty index. |
ReceiverFramePut returns 0x800705B4 (MFormats SDK) |
The writer did not accept the frame in the given time. Pass -1 as the wait time, as in the example, so the call waits for the encoder instead of failing at once. |
WriterSet returns 0x8007070C (MFormats SDK) |
The strict check of the configuration, config.auto_check=true, does not accept the subtitle:: options. Do not enable it for a writer with subtitle tracks. The same configuration without the property is accepted. |
| License | Subtitle insertion may require the Closed Caption plugin license. |
ASS subtitle formatting
ASS subtitles support text formatting through the ASS style header. The sample exposes the main ASS formatting options in the UI. Color values can be entered manually as hex values or selected through the built-in WPF color picker.
| Where to configure the formatting | When to use |
|---|---|
ASS style header (the [V4+ Styles] section of the .ass file) |
When the formatting should be stored directly in the subtitle file, or when custom ASS styling is required. |
Writer properties (subtitle::font and others, step 4) |
For standard output formatting, with .ass and .srt files. |
The user can configure the following settings in the sample. They are written into the ASS [V4+ Styles] section:
| Setting | ASS style field |
|---|---|
| Font family | Fontname |
| Font size | Fontsize |
| Text color | PrimaryColour |
| Outline color | OutlineColour |
| Shadow/background color | BackColour |
| Bold, italic, underline |
Bold, Italic, Underline
|
| Outline size | Outline |
| Shadow size | Shadow |
| Subtitle alignment | Alignment |
| Left, right and bottom margins |
MarginL, MarginR, MarginV
|
[Script Info]
ScriptType: v4.00+
WrapStyle: 0
ScaledBorderAndShadow: yes
YCbCr Matrix: TV.709
PlayResX: 1920
PlayResY: 1080
[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
Style: Default,Arial,26,&H00FFFFFF,&H00FFFFFF,&H00000000,&H80000000,0,0,0,0,100,100,0,0,1,2,1,2,20,20,20,1
[Events]
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
Dialogue: 0,0:00:00.00,0:00:02.50,Default,,0,0,0,,Welcome to the Example ASS Subtitle File!
When an ASS file is loaded, the sample reads the Default style from the ASS header and applies it to the formatting UI and preview.
ASS style generation example
public class SubtitleStyleSettings
{
public string FontName { get; set; } = "Arial";
public float FontSize { get; set; } = 26f;
public string PrimaryColor { get; set; } = "#FFFFFF";
public string OutlineColor { get; set; } = "#000000";
public string BackColor { get; set; } = "#000000";
public bool Bold { get; set; }
public bool Italic { get; set; }
public bool Underline { get; set; }
public int Outline { get; set; } = 2;
public int Shadow { get; set; } = 1;
public int Alignment { get; set; } = 2;
public int LeftMargin { get; set; } = 20;
public int RightMargin { get; set; } = 20;
public int BottomMargin { get; set; } = 20;
}
After completing these steps, the output transport stream can contain embedded bitmap DVB subtitles, DVB Teletext subtitles, or both, depending on the writer subtitle codec configuration.
See also
Still have questions?
Tell us what didn’t work or what you’d like clarified.