[vlc-commits] [Git][videolan/vlc][master] 10 commits: es_format: add b_forced flag to subs_format_t
Felix Paul Kühne (@fkuehne)
gitlab at videolan.org
Mon Jun 29 12:53:10 UTC 2026
Felix Paul Kühne pushed to branch master at VideoLAN / VLC
Commits:
d01d4aaf by Felix Paul Kühne at 2026-06-29T14:42:45+02:00
es_format: add b_forced flag to subs_format_t
- - - - -
f6324486 by Janek Krüger at 2026-06-29T14:42:45+02:00
spudec: only show forced subtitles on a forced track
Co-authored-by: Saifelden Mohamed Ismail <saifeldenmi at gmail.com>
- - - - -
3fe8dc8d by Janek Krüger at 2026-06-29T14:42:45+02:00
avcodec: only show forced subtitles on a forced track (pgssub)
Co-authored-by: Saifelden Mohamed Ismail <saifeldenmi at gmail.com>
- - - - -
698e0c3c by Felix Paul Kühne at 2026-06-29T14:42:45+02:00
dvdnav/dvdread: expose DVD audio/subtitle code_extension as track description
Co-authored-by: Saifelden Mohamed Ismail <saifeldenmi at gmail.com>
- - - - -
7f47e56b by Felix Paul Kühne at 2026-06-29T14:42:45+02:00
dvdnav/dvdread: mark forced-caption SPU tracks as forced
Co-authored-by: Saifelden Mohamed Ismail <saifeldenmi at gmail.com>
- - - - -
87f3b9c4 by Felix Paul Kühne at 2026-06-29T14:42:45+02:00
mp4: simplify forced SPU handling
The flag previously lived duplicated on track_config_t and mp4_track_t.
With b_forced on es_format_t, this is redundant.
The auto-default behavior for forced tx3g tracks is preserved.
- - - - -
7e242296 by Saifelden Mohamed Ismail at 2026-06-29T14:42:45+02:00
dvdread: describe tracks from code_extension
- - - - -
05224f0e by Saifelden Mohamed Ismail at 2026-06-29T14:42:45+02:00
dvdread: treat forced-caption subtitles as forced
- - - - -
77774232 by Saifelden Mohamed Ismail at 2026-06-29T14:42:45+02:00
dvdnav: ignore the hidden flag when matching the active subtitle
- - - - -
60e4617d by Saifelden Mohamed Ismail at 2026-06-29T14:42:45+02:00
dvdnav: show forced subtitles when the subpicture stream is hidden
- - - - -
15 changed files:
- include/vlc_es.h
- modules/access/Makefile.am
- + modules/access/dvd_description.h
- modules/access/dvdnav.c
- modules/access/dvdread.c
- modules/access/dvdread.h
- modules/access/dvdread_video.c
- modules/codec/avcodec/subtitle.c
- modules/codec/spudec/parse.c
- modules/codec/spudec/spudec.c
- modules/codec/spudec/spudec.h
- modules/demux/mp4/essetup.c
- modules/demux/mp4/mp4.c
- modules/demux/mp4/mp4.h
- po/POTFILES.in
Changes:
=====================================
include/vlc_es.h
=====================================
@@ -580,6 +580,9 @@ struct subs_format_t
/* Reorder depth of transport video, -1 for no reordering */
int i_reorder_depth;
} cc;
+
+ /* track marked as forced */
+ bool b_forced;
};
/**
=====================================
modules/access/Makefile.am
=====================================
@@ -279,7 +279,7 @@ endif
EXTRA_LTLIBRARIES += libvcd_plugin.la
access_PLUGINS += $(LTLIBvcd)
-libdvdnav_plugin_la_SOURCES = access/disc_helper.h access/dvdnav.c demux/mpeg/ps.h demux/mpeg/pes.h
+libdvdnav_plugin_la_SOURCES = access/disc_helper.h access/dvd_description.h access/dvdnav.c demux/mpeg/ps.h demux/mpeg/pes.h
libdvdnav_plugin_la_CFLAGS = $(AM_CFLAGS) $(DVDNAV_CFLAGS)
libdvdnav_plugin_la_LIBADD = $(DVDNAV_LIBS)
libdvdnav_plugin_la_LDFLAGS = $(AM_LDFLAGS) $(access_RPATH)
@@ -289,7 +289,7 @@ endif
access_PLUGINS += $(LTLIBdvdnav)
EXTRA_LTLIBRARIES += libdvdnav_plugin.la
-libdvdread_plugin_la_SOURCES = access/disc_helper.h access/dvdread.h access/dvdread.c access/dvdread_video.c access/dvdread_audio.c access/dvdread_vr.c demux/mpeg/ps.h demux/mpeg/pes.h \
+libdvdread_plugin_la_SOURCES = access/disc_helper.h access/dvd_description.h access/dvdread.h access/dvdread.c access/dvdread_video.c access/dvdread_audio.c access/dvdread_vr.c demux/mpeg/ps.h demux/mpeg/pes.h \
demux/moving_avg.h demux/timestamps_filter.h
libdvdread_plugin_la_CFLAGS = $(AM_CFLAGS) $(DVDREAD_CFLAGS)
libdvdread_plugin_la_LIBADD = $(DVDREAD_LIBS)
=====================================
modules/access/dvd_description.h
=====================================
@@ -0,0 +1,61 @@
+/*****************************************************************************
+ * dvd_description.h: DVD audio/subtitle code_extension description tables
+ *****************************************************************************
+ * Copyright (C) 2026 VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#include <dvdread/version.h>
+
+/**
+ * DVD audio track code_extension values as defined in the DVD-Video spec.
+ * Maps audio_attr_t.code_extension to translatable description strings.
+ */
+static const char *const dvd_audio_code_ext[] = {
+ /* 0 unspecified */ NULL,
+ /* 1 normal */ NULL,
+ /* 2 */ N_("Audio for visually impaired"),
+ /* 3 */ N_("Director's comments"),
+ /* 4 */ N_("Alternate director's comments"),
+};
+
+/* older libdvdread does not have this enum yet */
+#if DVDREAD_VERSION < DVDREAD_VERSION_CODE(7, 1, 0)
+# define DVD_SUBP_CODE_EXT_FORCED 9
+#endif
+
+/**
+ * DVD subtitle track code_extension values as defined in the DVD-Video spec.
+ * Maps subp_attr_t.code_extension to translatable description strings.
+ */
+static const char *const dvd_spu_code_ext[] = {
+ /* 0 unspecified */ NULL,
+ /* 1 normal */ NULL,
+ /* 2 */ N_("Large"),
+ /* 3 */ N_("For children"),
+ /* 4 */ NULL,
+ /* 5 */ N_("Closed caption"),
+ /* 6 */ N_("Closed caption (large)"),
+ /* 7 */ N_("Closed caption (children)"),
+ /* 8 */ NULL,
+ /* 9 */ N_("Forced caption"),
+ /* 10 */ NULL,
+ /* 11 */ NULL,
+ /* 12 */ NULL,
+ /* 13 */ N_("Director's comments"),
+ /* 14 */ N_("Director's comments (large)"),
+ /* 15 */ N_("Director's comments (children)"),
+};
=====================================
modules/access/dvdnav.c
=====================================
@@ -65,6 +65,7 @@ dvdnav_status_t dvdnav_jump_to_sector_by_time(dvdnav_t *, uint64_t, int32_t);
#include "../demux/timestamps_filter.h"
#include "disc_helper.h"
+#include "dvd_description.h"
/*****************************************************************************
* Module descriptor
@@ -80,6 +81,10 @@ dvdnav_status_t dvdnav_jump_to_sector_by_time(dvdnav_t *, uint64_t, int32_t);
#define LANGUAGE_DEFAULT ("en")
+/* dvdnav_get_active_spu_stream sets this bit when subtitles are hidden
+ and only forced captions should show */
+#define DVDNAV_SPU_HIDDEN 0x80
+
static int AccessDemuxOpen ( vlc_object_t * );
static void Close( vlc_object_t * );
@@ -1675,6 +1680,17 @@ static void ESNew( demux_t *p_demux, int i_id )
{
b_select = true;
}
+
+ /* Audio track description from code_extension */
+ audio_attr_t audio_attr;
+ if( dvdnav_get_audio_attr( p_sys->dvdnav, i_audio, &audio_attr )
+ == DVDNAV_STATUS_OK )
+ {
+ if( audio_attr.code_extension < ARRAY_SIZE(dvd_audio_code_ext)
+ && dvd_audio_code_ext[audio_attr.code_extension] )
+ tk->fmt.psz_description =
+ strdup( vlc_gettext( dvd_audio_code_ext[audio_attr.code_extension] ) );
+ }
}
}
else if( tk->fmt.i_cat == SPU_ES )
@@ -1682,6 +1698,20 @@ static void ESNew( demux_t *p_demux, int i_id )
int32_t i_title, i_part;
i_lang = dvdnav_spu_stream_to_lang( p_sys->dvdnav, i_id&0x1f );
+ /* Subtitle track description from code_extension */
+ subp_attr_t subp_attr;
+ if( dvdnav_get_spu_attr( p_sys->dvdnav, i_id&0x1f, &subp_attr )
+ == DVDNAV_STATUS_OK )
+ {
+ if( subp_attr.code_extension < ARRAY_SIZE(dvd_spu_code_ext)
+ && dvd_spu_code_ext[subp_attr.code_extension] )
+ tk->fmt.psz_description =
+ strdup( vlc_gettext( dvd_spu_code_ext[subp_attr.code_extension] ) );
+
+ if( subp_attr.code_extension == DVD_SUBP_CODE_EXT_FORCED )
+ tk->fmt.subs.b_forced = true;
+ }
+
/* Palette */
tk->fmt.subs.spu.b_palette = true;
static_assert(sizeof(tk->fmt.subs.spu.palette) == sizeof(p_sys->clut),
@@ -1689,11 +1719,14 @@ static void ESNew( demux_t *p_demux, int i_id )
memcpy( tk->fmt.subs.spu.palette, p_sys->clut, sizeof( p_sys->clut ) );
/* We select only when we are not in the menu */
+ int i_active_spu = dvdnav_get_active_spu_stream( p_sys->dvdnav );
if( dvdnav_current_title_info( p_sys->dvdnav, &i_title, &i_part ) == DVDNAV_STATUS_OK &&
- i_title > 0 &&
- dvdnav_get_active_spu_stream( p_sys->dvdnav ) == (i_id&0x1f) )
+ i_title > 0 && i_active_spu != -1 &&
+ (i_active_spu & 0x1f) == (i_id&0x1f) )
{
b_select = true;
+ if( i_active_spu & DVDNAV_SPU_HIDDEN )
+ tk->fmt.subs.b_forced = true;
}
}
=====================================
modules/access/dvdread.c
=====================================
@@ -48,6 +48,7 @@
#include <vlc_input.h>
#include <vlc_charset.h>
#include "disc_helper.h"
+#include "dvd_description.h"
/*****************************************************************************
@@ -860,7 +861,7 @@ static int DemuxBlock( demux_t *p_demux, const uint8_t *p, int len )
if( !tk->b_configured )
{
- DvdReadESNew( p_demux, i_id, 0 );
+ DvdReadESNew( p_demux, i_id, 0, 0 );
}
if( tk->es &&
!ps_pkt_parse_pes( VLC_OBJECT(p_demux), p_pkt, tk->i_skip ) )
@@ -914,7 +915,7 @@ static int DemuxBlock( demux_t *p_demux, const uint8_t *p, int len )
/*****************************************************************************
* ESNew: register a new elementary stream
*****************************************************************************/
-void DvdReadESNew( demux_t *p_demux, int i_id, int i_lang )
+void DvdReadESNew( demux_t *p_demux, int i_id, int i_lang, int i_code_ext )
{
demux_sys_t *p_sys = p_demux->p_sys;
ps_track_t *tk = &p_sys->tk[ps_id_to_tk(i_id)];
@@ -966,6 +967,11 @@ void DvdReadESNew( demux_t *p_demux, int i_id, int i_lang )
#endif
if( psz_language[0] ) tk->fmt.psz_language = strdup( psz_language );
+
+ if( (size_t) i_code_ext < ARRAY_SIZE(dvd_audio_code_ext)
+ && dvd_audio_code_ext[i_code_ext] )
+ tk->fmt.psz_description =
+ strdup( vlc_gettext( dvd_audio_code_ext[i_code_ext] ) );
}
else if( tk->fmt.i_cat == SPU_ES )
{
@@ -976,6 +982,14 @@ void DvdReadESNew( demux_t *p_demux, int i_id, int i_lang )
memcpy( tk->fmt.subs.spu.palette, p_sys->clut, sizeof( p_sys->clut ) );
if( psz_language[0] ) tk->fmt.psz_language = strdup( psz_language );
+
+ if( (size_t) i_code_ext < ARRAY_SIZE(dvd_spu_code_ext)
+ && dvd_spu_code_ext[i_code_ext] )
+ tk->fmt.psz_description =
+ strdup( vlc_gettext( dvd_spu_code_ext[i_code_ext] ) );
+
+ if( i_code_ext == DVD_SUBP_CODE_EXT_FORCED )
+ tk->fmt.subs.b_forced = true;
}
tk->es = es_out_Add( p_demux->out, &tk->fmt );
=====================================
modules/access/dvdread.h
=====================================
@@ -190,7 +190,7 @@ int OpenAudio( vlc_object_t * );
uint32_t DvdVRGetProgramSectorSpan( const demux_sys_t *, const vobu_map_t * );
#endif
-void DvdReadESNew( demux_t *p_demux, int i_id, int i_lang );
+void DvdReadESNew( demux_t *p_demux, int i_id, int i_lang, int i_code_ext );
void DvdReadHandleDSI( demux_t *p_demux, uint8_t *p_data );
extern const dvdread_ops_t DvdReadVideoOps;
=====================================
modules/access/dvdread_video.c
=====================================
@@ -678,7 +678,7 @@ static int DvdReadSetArea( demux_t *p_demux, int i_title, int i_chapter,
/* TODO: re-add angles */
- DvdReadESNew( p_demux, 0xe0, 0 ); /* Video, FIXME ? */
+ DvdReadESNew( p_demux, 0xe0, 0, 0 ); /* Video, FIXME ? */
const video_attr_t *p_attr = &p_vts->vtsi_mat->vts_video_attr;
int i_video_height = p_attr->video_format != 0 ? 576 : 480;
int i_video_width;
@@ -752,7 +752,9 @@ static int DvdReadSetArea( demux_t *p_demux, int i_title, int i_chapter,
}
DvdReadESNew( p_demux, i_id, p_sys->p_vts_file->vtsi_mat->
- vts_audio_attr[i - 1].lang_code );
+ vts_audio_attr[i - 1].lang_code,
+ p_sys->p_vts_file->vtsi_mat->
+ vts_audio_attr[i - 1].code_extension );
}
}
@@ -798,7 +800,9 @@ static int DvdReadSetArea( demux_t *p_demux, int i_title, int i_chapter,
i_id = (0x20 + i_position) | PS_PACKET_ID_MASK_VOB;
DvdReadESNew( p_demux, i_id, p_sys->p_vts_file->vtsi_mat->
- vts_subp_attr[i - 1].lang_code );
+ vts_subp_attr[i - 1].lang_code,
+ p_sys->p_vts_file->vtsi_mat->
+ vts_subp_attr[i - 1].code_extension );
}
}
=====================================
modules/codec/avcodec/subtitle.c
=====================================
@@ -34,6 +34,7 @@
#include <libavcodec/avcodec.h>
#include <libavutil/mem.h>
+#include <libavutil/opt.h>
#include "avcodec.h"
@@ -65,6 +66,11 @@ int InitSubtitleDec(vlc_object_t *obj)
/* */
switch (codec->id) {
case AV_CODEC_ID_HDMV_PGS_SUBTITLE:
+ /* a track marked forced shows only its forced captions */
+ if (dec->fmt_in->subs.b_forced) {
+ av_opt_set_int(context->priv_data, "forced_subs_only", 1, 0);
+ }
+ break;
case AV_CODEC_ID_XSUB:
case AV_CODEC_ID_DVB_SUBTITLE:
break;
=====================================
modules/codec/spudec/parse.c
=====================================
@@ -47,6 +47,7 @@ typedef struct
vlc_tick_t i_stop;
bool b_ephemer;
bool b_subtitle;
+ bool b_forced;
} spu_properties_t;
typedef struct
@@ -390,6 +391,7 @@ static int ParseControlSeq( decoder_t *p_dec, vlc_tick_t i_pts,
spu_properties.i_start = VLC_TICK_INVALID;
spu_properties.i_stop = VLC_TICK_INVALID;
spu_properties.b_subtitle = true;
+ spu_properties.b_forced = false;
for( i_index = 4 + p_sys->i_rle_size; i_index < p_sys->i_spu_size ; )
{
@@ -434,6 +436,7 @@ static int ParseControlSeq( decoder_t *p_dec, vlc_tick_t i_pts,
* works around non displayable (offset by few ms)
* spu menu over still frame in SPU_Select */
spu_properties.b_subtitle = false;
+ spu_properties.b_forced = true;
i_index += 1;
break;
@@ -569,7 +572,7 @@ static int ParseControlSeq( decoder_t *p_dec, vlc_tick_t i_pts,
i_index += 1;
if( Validate( p_dec, i_index, i_cur_seq, i_next_seq,
- &spu_data, &spu_properties ) == VLC_SUCCESS )
+ &spu_data, &spu_properties ) == VLC_SUCCESS && (!p_sys->b_forcedonly || spu_properties.b_forced))
OutputPicture( p_dec, &spu_data, &spu_properties, pf_queue );
break;
=====================================
modules/codec/spudec/spudec.c
=====================================
@@ -81,6 +81,8 @@ static int OpenCommon( vlc_object_t *p_this, bool b_packetizer )
p_sys->b_packetizer = b_packetizer;
p_sys->b_disabletrans = var_InheritBool( p_dec, "dvdsub-transparency" );
+ /* a track marked forced shows only its forced captions */
+ p_sys->b_forcedonly = p_dec->fmt_in->subs.b_forced;
p_sys->i_spu_size = 0;
p_sys->buffer = NULL;
p_sys->buffer_size = 0;
=====================================
modules/codec/spudec/spudec.h
=====================================
@@ -26,6 +26,7 @@ typedef struct
{
bool b_packetizer;
bool b_disabletrans;
+ bool b_forcedonly;
vlc_tick_t i_pts;
unsigned int i_spu_size;
=====================================
modules/demux/mp4/essetup.c
=====================================
@@ -1417,7 +1417,8 @@ int SetupSpuES( demux_t *p_demux, const mp4_track_t *p_track,
if( p_text->i_data > 4 && GetDWBE(p_text->p_data) & 0xC0000000 )
{
p_fmt->i_priority = ES_PRIORITY_SELECTABLE_MIN + 1;
- p_cfg->b_forced_spu = true;
+ p_fmt->subs.b_forced = true;
+ p_fmt->psz_description = strdup( _("Forced caption") );
}
CopyExtradata( p_text->p_data, p_text->i_data, p_fmt );
=====================================
modules/demux/mp4/mp4.c
=====================================
@@ -465,12 +465,11 @@ static const MP4_Box_data_sbgp_entry_t *
return p_sampleentry;
}
-static es_out_id_t * MP4_CreateES( es_out_t *out, const es_format_t *p_fmt,
- bool b_forced_spu )
+static es_out_id_t * MP4_CreateES( es_out_t *out, const es_format_t *p_fmt )
{
es_out_id_t *p_es = es_out_Add( out, p_fmt );
/* Force SPU which isn't selected/defaulted */
- if( p_fmt->i_cat == SPU_ES && p_es && b_forced_spu )
+ if( p_fmt->i_cat == SPU_ES && p_es && p_fmt->subs.b_forced )
es_out_Control( out, ES_OUT_SET_ES_DEFAULT, p_es );
return p_es;
@@ -3196,7 +3195,6 @@ static void TrackConfigApply( const track_config_t *p_cfg,
memcpy( p_track->rgi_chans_reordering, p_cfg->rgi_chans_reordering,
AOUT_CHAN_MAX * sizeof(p_cfg->rgi_chans_reordering[0]) );
p_track->i_chans_to_reorder = p_cfg->i_chans_to_reorder;
- p_track->b_forced_spu = p_cfg->b_forced_spu;
p_track->i_block_flags = p_cfg->i_block_flags;
p_track->b_ignore_implicit_pts = p_cfg->b_ignore_implicit_pts;
}
@@ -3406,7 +3404,7 @@ static int TrackCreateES( demux_t *p_demux, mp4_track_t *p_track,
p_track->p_sample = p_sample;
if( pp_es )
- *pp_es = MP4_CreateES( p_demux->out, p_fmt, p_track->b_forced_spu );
+ *pp_es = MP4_CreateES( p_demux->out, p_fmt );
return ( !pp_es || *pp_es ) ? VLC_SUCCESS : VLC_EGENERIC;
}
@@ -3724,7 +3722,7 @@ static int TrackUpdateFormat( demux_t *p_demux, mp4_track_t *p_track,
es_out_Del( p_demux->out, p_track->p_es );
- p_track->p_es = MP4_CreateES( p_demux->out, &tmpfmt, cfg.b_forced_spu );
+ p_track->p_es = MP4_CreateES( p_demux->out, &tmpfmt );
if( !p_track->p_es )
{
msg_Err( p_demux, "cannot create es for track[Id 0x%x]",
=====================================
modules/demux/mp4/mp4.h
=====================================
@@ -90,7 +90,6 @@ typedef struct
uint8_t rgi_chans_reordering[AOUT_CHAN_MAX];
uint8_t i_chans_to_reorder;
- bool b_forced_spu; /* forced track selection (never done by default/priority) */
bool b_ignore_implicit_pts;
uint32_t i_block_flags;
@@ -106,7 +105,6 @@ typedef struct
bool b_selected; /* is the trak being played */
int i_use_flags; /* !=0 Set when track is referenced by specific reference types.
You'll need to lookup other tracks tref to know the ref source */
- bool b_forced_spu; /* forced track selection (never done by default/priority) */
uint32_t i_switch_group;
bool b_mac_encoding;
=====================================
po/POTFILES.in
=====================================
@@ -157,6 +157,7 @@ modules/access/dc1394.c
modules/access/dcp/dcp.cpp
modules/access/decklink.cpp
modules/access/disc_helper.h
+modules/access/dvd_description.h
modules/access/dshow/dshow.cpp
modules/access/dsm/access.c
modules/access/dsm/sd.c
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/f95729fbeb1c72593715d013a5d6765ce06c5252...60e4617ddbd2db845520afb0edc982f0c3da2a5c
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/f95729fbeb1c72593715d013a5d6765ce06c5252...60e4617ddbd2db845520afb0edc982f0c3da2a5c
You're receiving this email because of your account on code.videolan.org. Manage all notifications: https://code.videolan.org/-/profile/notifications | Help: https://code.videolan.org/help
More information about the vlc-commits
mailing list