[vlc-commits] [Git][videolan/vlc][master] 5 commits: access: dvdread: allow type override
Steve Lhomme (@robUx4)
gitlab at videolan.org
Sat Apr 11 11:53:31 UTC 2026
Steve Lhomme pushed to branch master at VideoLAN / VLC
Commits:
b530cfdf by Saifelden Mohamed Ismail at 2026-04-11T11:38:43+00:00
access: dvdread: allow type override
- - - - -
6cd1bdca by Saifelden Mohamed Ismail at 2026-04-11T11:38:43+00:00
access: dvdread: add DVD-VR submodule
- - - - -
db895f04 by Saifelden Mohamed Ismail at 2026-04-11T11:38:43+00:00
dvdread: adjust dvd-type fallback behavior
- - - - -
78680661 by Saifelden Mohamed Ismail at 2026-04-11T11:38:43+00:00
dvd-vr: adjust logging for vr
- - - - -
5c535461 by Saifelden Mohamed Ismail at 2026-04-11T11:38:43+00:00
access: dvdread: formatting adjustments
- - - - -
1 changed file:
- modules/access/dvdread.c
Changes:
=====================================
modules/access/dvdread.c
=====================================
@@ -73,12 +73,25 @@
#define ANGLE_LONGTEXT N_( \
"Default DVD angle." )
+
+/*****************************************************************************
+ * DVDRead Version Compatibility
+ *****************************************************************************/
+#if DVDREAD_VERSION > DVDREAD_VERSION_CODE(7, 0, 1)
+#define DVDREAD_HAS_DVDVIDEORECORDING 1
+#endif
+
#if DVDREAD_VERSION >= DVDREAD_VERSION_CODE(7, 0, 0)
#define DVDREAD_HAS_DVDAUDIO 1
#endif
-#ifdef DVDREAD_HAS_DVDAUDIO
-#define SET_AREA( p_demux, title, chapter, angle ) \
+#if defined(DVDREAD_HAS_DVDVIDEORECORDING)
+#define SET_AREA( p_demux, title, chapter, angle ) \
+ (((p_sys->type) == DVD_VR ? DvdVRReadSetArea : \
+ (p_sys->type) == DVD_A ? DvdAudioReadSetArea : \
+ DvdReadSetArea)( p_demux, title, chapter, -1 ))
+#elif defined(DVDREAD_HAS_DVDAUDIO)
+#define SET_AREA( p_demux, title, chapter, angle ) \
(((p_sys->type) == DVD_A ? DvdAudioReadSetArea : DvdReadSetArea)( p_demux, title, chapter, -1 ))
#else
#define SET_AREA( p_demux, title, chapter, angle ) \
@@ -89,12 +102,16 @@
typedef enum
{
DVD_V = 0,
- DVD_A= 1,
+ DVD_A = 1,
+ DVD_VR = 2,
} dvd_type_t;
static int Open ( vlc_object_t * );
static void Close( vlc_object_t * );
+/* DVD-VideoRecording Optional force method */
+static int OpenVideoRecording( vlc_object_t *p_this );
+
/* Sets DVD-audio behavior for Open function*/
static int OpenAudio ( vlc_object_t * );
@@ -113,6 +130,10 @@ vlc_module_begin ()
set_capability( "access", 1 )
add_shortcut( "dvda", "dvd" )
set_callbacks( OpenAudio, Close )
+ add_submodule()
+ set_capability( "access", 1 )
+ add_shortcut( "dvdvr", "dvd" )
+ set_callbacks( OpenVideoRecording, Close )
vlc_module_end ()
/* how many blocks DVDRead will read in each loop */
@@ -156,6 +177,20 @@ typedef struct
};
#endif
+#ifdef DVDREAD_HAS_DVDVIDEORECORDING
+ /* VideoRecording tables */
+ struct
+ {
+ /* address map of recordings */
+ pgc_gi_t *pgc_gi;
+ /* titles, labels for recordings */
+ ud_pgcit_t *ud_pgcit;
+ /* keep track of vobu index */
+ /* pointer to current program */
+ pgi_t *p_cur_pgi;
+ };
+#endif
+
};
dsi_t dsi_pack;
@@ -201,6 +236,12 @@ static void ESNew( demux_t *, int, int );
static int DvdReadSetArea ( demux_t *, int, int, int );
static int DvdReadSeek ( demux_t *, uint32_t );
+#ifdef DVDREAD_HAS_DVDVIDEORECORDING
+static int DvdVRReadSetArea ( demux_t *, int, int, int );
+static int DvdVRReadSeek( demux_t *, uint32_t );
+static vlc_tick_t DVDVRGetTitleLength( pgc_gi_t *pgc_gi, ud_pgcit_t *ud_pgcit, int program);
+static void DvdVRFindCell( demux_t *p_demux );
+#endif
#ifdef DVDREAD_HAS_DVDAUDIO
static int DvdAudioReadSetArea ( demux_t *, int, int, int );
static int DvdAudioReadSeek( demux_t *, uint32_t );
@@ -281,7 +322,8 @@ static int OpenCommon( vlc_object_t *p_this , dvd_type_t type )
dvd_reader_t *p_dvdread;
switch (type) {
case DVD_A:
- msg_Err( p_demux, "Version of libdvdread does not support DVD-audio" );
+ case DVD_VR:
+ msg_Err( p_demux, "Version of libdvdread does not support this DVD-VideoRecording" );
free( psz_file );
return VLC_EGENERIC;
default:
@@ -291,7 +333,8 @@ static int OpenCommon( vlc_object_t *p_this , dvd_type_t type )
#else
switch (type) {
case DVD_A:
- msg_Err( p_demux, "Version of libdvdread does not support DVD-audio" );
+ case DVD_VR:
+ msg_Err( p_demux, "Version of libdvdread does not support this DVD-Audio" );
free( psz_file );
return VLC_EGENERIC;
default:
@@ -326,10 +369,11 @@ static int OpenCommon( vlc_object_t *p_this , dvd_type_t type )
msg_Err( p_demux, "Invalid UDF DVD. (Found ISO9660 '%s')", rgsz_volid );
}
}
- msg_Warn( p_demux, "cannot open %cMG info", ( type == DVD_V ? 'V' : 'A' ) );
+ msg_Warn( p_demux, "cannot open %s info", ( type == DVD_V ? "VMG" : type == DVD_VR ? "RTAV_VMGI" : "AMG" ) );
+ DVDClose( p_dvdread );
return VLC_EGENERIC;
}
- msg_Dbg( p_demux, "%cMG opened", ( type == DVD_V ? 'V' : 'A' ) );
+ msg_Dbg( p_demux, "%s opened", ( type == DVD_V ? "VMG" : type == DVD_VR ? "RTAV_VMGI" : "AMG" ) );
/* Fill p_demux field */
DEMUX_INIT_COMMON(); p_sys = p_demux->p_sys;
@@ -352,7 +396,23 @@ static int OpenCommon( vlc_object_t *p_this , dvd_type_t type )
if( p_sys->i_angle <= 0 ) p_sys->i_angle = 1;
/* store type state internally */
- p_sys->type = type;
+ /* if open2 is called, in 7.1.0 dvd may force the type */
+ switch (p_sys->p_vmg_file->ifo_format)
+ {
+#ifdef DVDREAD_HAS_DVDVIDEORECORDING
+ case IFO_VIDEO_RECORDING:
+ p_sys->type = DVD_VR;
+ p_sys->ud_pgcit = p_sys->p_vmg_file->ud_pgcit;
+ p_sys->pgc_gi = p_sys->p_vmg_file->pgc_gi;
+ break;
+#endif
+ case IFO_AUDIO:
+ p_sys->type = DVD_A;
+ break;
+ default:
+ p_sys->type = type;
+ break;
+ }
DemuxTitles( p_demux, &p_sys->i_angle );
if( SET_AREA( p_demux, 0, 0, p_sys->i_angle ) != VLC_SUCCESS )
@@ -370,6 +430,10 @@ static int Open( vlc_object_t *p_this )
{
if( OpenCommon( p_this, DVD_V ) != VLC_SUCCESS )
{
+ msg_Dbg( p_this, "Trying DVD-Video Recording as a fallback" );
+ if( OpenCommon( p_this, DVD_VR ) == VLC_SUCCESS )
+ return VLC_SUCCESS;
+
msg_Dbg( p_this, "Trying DVD-Audio as a fallback" );
return OpenCommon( p_this, DVD_A );
}
@@ -380,6 +444,13 @@ static int OpenAudio( vlc_object_t *p_this )
{
return OpenCommon( p_this, DVD_A );
}
+
+/* should not need a specific callback if libdvdread picks up the type */
+static int OpenVideoRecording( vlc_object_t *p_this )
+{
+ return OpenCommon( p_this, DVD_VR );
+}
+
/*****************************************************************************
* Close:
*****************************************************************************/
@@ -451,7 +522,8 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
int *pi_int;
int i;
- if(unlikely(!p_sys->p_vts_file))
+ /* dvd-vr does not have vts */
+ if(unlikely(!p_sys->p_vts_file && p_sys->type != DVD_VR))
return VLC_EGENERIC;
switch( i_query )
@@ -471,10 +543,13 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
{
f = va_arg( args, double );
-#ifdef DVDREAD_HAS_DVDAUDIO
+#if defined(DVDREAD_HAS_DVDVIDEORECORDING)
+ if ( p_sys->type == DVD_VR )
+ return DvdVRReadSeek( p_demux, f * p_sys->i_title_blocks );
+#endif
+#if defined(DVDREAD_HAS_DVDAUDIO)
if ( p_sys->type == DVD_A )
return DvdAudioReadSeek( p_demux, f * p_sys->i_title_blocks );
- else
#endif
return DvdReadSeek( p_demux, f * p_sys->i_title_blocks );
}
@@ -482,9 +557,14 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
if( p_sys->cur_title >= 0 && p_sys->cur_title < p_sys->i_titles )
{
vlc_tick_t length;
-#ifdef DVDREAD_HAS_DVDAUDIO
+#if defined(DVDREAD_HAS_DVDVIDEORECORDING)
+ if (p_sys->type == DVD_VR )
+ length = p_sys->titles[p_sys->cur_title]->i_length;
+ else
+#endif
+#if defined(DVDREAD_HAS_DVDAUDIO)
if (p_sys->type == DVD_A )
- length = FROM_SCALE_NZ( ( uint64_t ) p_sys->p_title_table->length_pts );
+ length = FROM_SCALE_NZ( ( uint64_t ) p_sys->p_title_table->length_pts );
else
#endif
length = dvdtime_to_time( &p_sys->p_cur_pgc->playback_time );
@@ -500,7 +580,12 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
if( p_sys->cur_title >= 0 && p_sys->cur_title < p_sys->i_titles )
{
vlc_tick_t length;
-#ifdef DVDREAD_HAS_DVDAUDIO
+#if defined(DVDREAD_HAS_DVDVIDEORECORDING)
+ if (p_sys->type == DVD_VR )
+ length = p_sys->titles[p_sys->cur_title]->i_length;
+ else
+#endif
+#if defined(DVDREAD_HAS_DVDAUDIO)
if ( p_sys->type == DVD_A )
length = FROM_SCALE_NZ( ( uint64_t ) p_sys->p_title_table->length_pts );
else
@@ -608,20 +693,22 @@ static int Demux( demux_t *p_demux )
demux_sys_t *p_sys = p_demux->p_sys;
dvd_type_t type = p_sys->type;
- if(unlikely(!p_sys->p_vts_file))
+ if(unlikely(!p_sys->p_vts_file && p_sys->type != DVD_VR))
return VLC_DEMUXER_EOF;
uint8_t p_buffer[DVD_VIDEO_LB_LEN * DVD_BLOCK_READ_ONCE];
int i_blocks_once, i_read;
-#ifdef DVDREAD_HAS_DVDAUDIO
bool at_end_of_title =
(type == DVD_V && p_sys->i_cur_cell >= p_sys->p_cur_pgc->nr_of_cells)
- || (type == DVD_A && p_sys->i_cur_block>= p_sys->i_title_end_block);
-#else
- bool at_end_of_title =
- (type == DVD_V && p_sys->i_cur_cell >= p_sys->p_cur_pgc->nr_of_cells);
+#if defined(DVDREAD_HAS_DVDAUDIO)
+ || (type == DVD_A && p_sys->i_cur_block >= p_sys->i_title_end_block)
+#endif
+#if defined(DVDREAD_HAS_DVDVIDEORECORDING)
+ || (type == DVD_VR && p_sys->i_cur_cell >= p_sys->i_title_end_cell
+ && !p_sys->i_pack_len)
#endif
+ ;
/*
* Playback by cell in this pgc, starting at the cell for our chapter.
@@ -633,6 +720,66 @@ static int Demux( demux_t *p_demux )
/*
* Check end of pack, and select the following one
*/
+#if defined(DVDREAD_HAS_DVDVIDEORECORDING)
+ if( !p_sys->i_pack_len && type == DVD_VR
+ && p_sys->i_cur_cell < p_sys->i_title_end_cell )
+ {
+ uint16_t srpn = p_sys->ud_pgcit->m_c_gi[p_sys->i_cur_cell].m_vobi_srpn;
+ if( srpn == 0 || srpn > p_sys->pgc_gi->nr_of_programs )
+ {
+ msg_Err( p_demux, "invalid m_vobi_srpn %u", srpn );
+ return VLC_EGENERIC;
+ }
+
+ vobu_map_t *map = &p_sys->pgc_gi->pgi[srpn - 1].map;
+
+ p_sys->i_cur_block = map->vob_offset;
+
+ if( map->nr_of_time_info >= 2 )
+ {
+ uint32_t last_adr = map->time_infos[map->nr_of_time_info - 1].vobu_adr;
+ uint32_t last_entn = map->time_infos[map->nr_of_time_info - 1].vobu_entn;
+ if( last_entn > 1 )
+ p_sys->i_pack_len = (uint32_t)( (uint64_t)last_adr
+ * map->nr_of_vobu_info / ( last_entn - 1 ) );
+ else
+ p_sys->i_pack_len = map->nr_of_vobu_info * (DVD_VIDEO_LB_LEN / 4);
+ }
+ else
+ {
+ uint32_t sects_per_vobu = 0;
+ for( int p = 0; p < p_sys->pgc_gi->nr_of_programs; p++ )
+ {
+ vobu_map_t *m = &p_sys->pgc_gi->pgi[p].map;
+ if( m->nr_of_time_info >= 2
+ && m->time_infos[m->nr_of_time_info - 1].vobu_entn > 1 )
+ {
+ sects_per_vobu = m->time_infos[m->nr_of_time_info - 1].vobu_adr
+ / ( m->time_infos[m->nr_of_time_info - 1].vobu_entn - 1 );
+ break;
+ }
+ }
+ if( !sects_per_vobu )
+ sects_per_vobu = DVD_VIDEO_LB_LEN / 4; /* safe overestimate */
+ p_sys->i_pack_len = map->nr_of_vobu_info * sects_per_vobu;
+ }
+
+ p_sys->i_title_offset += map->nr_of_vobu_info;
+
+ p_sys->i_cur_cell++;
+ DvdVRFindCell( p_demux );
+ }
+ else
+#endif
+#if defined(DVDREAD_HAS_DVDAUDIO)
+ if( !p_sys->i_pack_len && type == DVD_A )
+ {
+ p_sys->i_pack_len = p_sys->i_title_blocks;
+ p_sys->i_cur_block = p_sys->p_title_table->atsi_track_pointer_rows[p_sys->i_chapter].start_sector;
+
+ }
+ else
+#endif
if( !p_sys->i_pack_len && type == DVD_V )
{
/* Read NAV packet */
@@ -665,14 +812,6 @@ static int Demux( demux_t *p_demux )
p_sys->i_title_offset++;
}
-#ifdef DVDREAD_HAS_DVDAUDIO
- else if( !p_sys->i_pack_len && type == DVD_A )
- {
- p_sys->i_pack_len = p_sys->i_title_blocks;
- p_sys->i_cur_block = p_sys->p_title_table->atsi_track_pointer_rows[p_sys->i_chapter].start_sector;
-
- }
-#endif
if( at_end_of_title )
{
int k = p_sys->i_title;
@@ -707,7 +846,8 @@ static int Demux( demux_t *p_demux )
}
p_sys->i_cur_block += i_read;
- p_sys->i_title_offset += i_read;
+ if( type != DVD_VR )
+ p_sys->i_title_offset += i_read;
#if 0
msg_Dbg( p_demux, "i_blocks: %d len: %d current: 0x%02x",
@@ -1363,6 +1503,256 @@ static int DvdAudioReadSetArea( demux_t *p_demux, int i_title, int i_track,
}
#endif
+#ifdef DVDREAD_HAS_DVDVIDEORECORDING
+static int DvdVRReadSetArea( demux_t *p_demux, int i_title, int i_chapter,
+ int i_angle )
+{
+ VLC_UNUSED( i_angle );
+ demux_sys_t *p_sys = p_demux->p_sys;
+
+ /* user made title selection */
+ if( i_title >= 0 && i_title < p_sys->i_titles &&
+ i_title != p_sys->i_title )
+ {
+ int i_start_cell, i_end_cell;
+
+ if( p_sys->p_title != NULL )
+ DVDCloseFile( p_sys->p_title );
+ if( !( p_sys->p_title = DVDOpenFile( p_sys->p_dvdread, 0, DVD_READ_TITLE_VOBS ) ) )
+ {
+ msg_Err( p_demux, "cannot open VR_MOVIE.VRO");
+ return VLC_EGENERIC;
+ }
+
+ uint16_t fpid = p_sys->ud_pgcit->ud_pgci_items[i_title].first_prog_id;
+ if( fpid == 0 || fpid == 0xFFFF
+ || fpid > p_sys->pgc_gi->nr_of_programs )
+ {
+ msg_Warn( p_demux, "invalid first_prog_id %u for title %d",
+ fpid, i_title );
+ return VLC_EGENERIC;
+ }
+ i_start_cell = p_sys->i_title_start_cell = fpid - 1;
+
+ p_sys->i_cur_cell = i_start_cell;
+ i_end_cell = p_sys->i_title_end_cell = p_sys->ud_pgcit->ud_pgci_items[i_title].first_prog_id - 1 +
+ p_sys->ud_pgcit->ud_pgci_items[i_title].nr_of_programs;
+
+ p_sys->i_chapters = 0;
+ for (int c = i_start_cell; c < i_end_cell; c++)
+ {
+ m_c_gi_t *cell = &p_sys->ud_pgcit->m_c_gi[c];
+ p_sys->i_chapters += cell->c_epi_n ? cell->c_epi_n : 1;
+ }
+
+ /* which program we should search for our timestamp */
+ uint16_t m_vobi_srpn = p_sys->ud_pgcit->m_c_gi[i_start_cell].m_vobi_srpn;
+
+ /* find the corresponding address */
+ p_sys->p_cur_pgi = &p_sys->pgc_gi->pgi[m_vobi_srpn - 1];
+
+ uint32_t vob_offset = p_sys->p_cur_pgi->map.vob_offset;
+
+ p_sys->i_cur_block = vob_offset;
+
+ p_sys->i_title_blocks = 0;
+ for( int c = i_start_cell; c < i_end_cell; c++ )
+ {
+ uint16_t srpn = p_sys->ud_pgcit->m_c_gi[c].m_vobi_srpn;
+ p_sys->i_title_blocks += p_sys->pgc_gi->pgi[srpn - 1].map.nr_of_vobu_info;
+ }
+ p_sys->i_title_offset = 0;
+ p_sys->i_pack_len = 0;
+
+ p_sys->i_title = i_title;
+
+ /*
+ * Destroy obsolete ES by reinitializing program 0
+ * and find all ES in title with ifo data
+ */
+
+ for( int i = 0; i < PS_TK_COUNT; i++ )
+ {
+ ps_track_t *tk = &p_sys->tk[i];
+ if( tk->b_configured )
+ {
+ es_format_Clean( &tk->fmt );
+ if( tk->es ) es_out_Del( p_demux->out, tk->es );
+ }
+ tk->b_configured = false;
+ }
+
+ es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
+
+ if( p_sys->cur_title != i_title)
+ {
+ p_sys->updates |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
+ p_sys->cur_title = i_title;
+ p_sys->cur_chapter = 0;
+ }
+
+ }
+ else if( i_title != -1 && i_title != p_sys->i_title )
+ {
+ return VLC_EGENERIC; /* Couldn't set title */
+ }
+
+ /* Search for chapter */
+ if( i_chapter >= 0 && i_chapter < p_sys->i_chapters )
+ {
+ int i, j;
+ int accum_chapter = 0;
+ uint32_t chapter_ptm;
+ uint32_t chapter_program;
+ int found = 0;
+
+ /* find the correct entry point */
+ for (i = p_sys->i_title_start_cell;
+ i < p_sys->i_title_end_cell && !found; i++)
+ {
+ int n_ep = p_sys->ud_pgcit->m_c_gi[i].c_epi_n;
+ if( n_ep == 0 )
+ {
+ /* cell has no explicit entry points — treat as one chapter */
+ if( accum_chapter == i_chapter )
+ {
+ chapter_ptm = p_sys->ud_pgcit->m_c_gi[i].c_v_s_ptm.ptm;
+ chapter_program = p_sys->ud_pgcit->m_c_gi[i].m_vobi_srpn;
+ found = 1;
+ break;
+ }
+ accum_chapter++;
+ }
+ else
+ {
+ for (j = 0; j < n_ep; j++)
+ {
+ if (accum_chapter == i_chapter)
+ {
+ chapter_ptm = p_sys->ud_pgcit->m_c_gi[i].m_c_epi[j].ep_ptm.ptm;
+ chapter_program = p_sys->ud_pgcit->m_c_gi[i].m_vobi_srpn;
+ found = 1;
+ break;
+ }
+ accum_chapter++;
+ }
+ }
+ }
+ if (!found)
+ return VLC_EGENERIC;
+
+ /* search map for the address */
+ vobu_map_t map = p_sys->pgc_gi->pgi[chapter_program - 1].map;
+
+ /* find a vobu index to search for */
+ uint32_t relative_ptm = chapter_ptm
+ - p_sys->pgc_gi->pgi[chapter_program - 1].header.vob_v_s_ptm.ptm;
+
+ uint32_t total_pts = p_sys->pgc_gi->pgi[chapter_program - 1].header.vob_v_e_ptm.ptm
+ - p_sys->pgc_gi->pgi[chapter_program - 1].header.vob_v_s_ptm.ptm;
+
+ uint32_t estimated_vobu = 0;
+ if( total_pts > 0 && map.nr_of_vobu_info > 0 )
+ estimated_vobu = (uint32_t)( (uint64_t)relative_ptm
+ * map.nr_of_vobu_info / total_pts );
+
+ int time_offset_i = 0;
+ while ( time_offset_i < map.nr_of_time_info - 1
+ && map.time_infos[time_offset_i + 1].vobu_entn <= estimated_vobu )
+ time_offset_i++;
+
+ uint32_t chapter_offset = map.time_infos[time_offset_i].vobu_adr + map.vob_offset;
+ p_sys->i_cur_block = chapter_offset;
+ p_sys->i_pack_len = 0;
+ p_sys->i_chapter = i_chapter;
+ p_sys->cur_chapter = i_chapter;
+
+ for( int ci = p_sys->i_title_start_cell;
+ ci < p_sys->i_title_end_cell; ci++ )
+ {
+ if( p_sys->ud_pgcit->m_c_gi[ci].m_vobi_srpn == chapter_program )
+ {
+ p_sys->i_cur_cell = ci;
+ break;
+ }
+ }
+
+ p_sys->i_title_offset = 0;
+ for( int ci = p_sys->i_title_start_cell;
+ ci < p_sys->i_cur_cell; ci++ )
+ {
+ uint16_t s = p_sys->ud_pgcit->m_c_gi[ci].m_vobi_srpn;
+ p_sys->i_title_offset += p_sys->pgc_gi->pgi[s - 1].map.nr_of_vobu_info;
+ }
+
+ return VLC_SUCCESS;
+ }
+ else if( i_chapter != -1 )
+ {
+ return VLC_EGENERIC; /* Couln't set chapter */
+ }
+
+ return VLC_SUCCESS;
+}
+
+static void DvdVRFindCell( demux_t *p_demux )
+{
+ demux_sys_t *p_sys = p_demux->p_sys;
+
+ p_sys->i_next_cell = p_sys->i_cur_cell + 1;
+
+ if( p_sys->i_cur_cell >= p_sys->i_title_end_cell )
+ return;
+
+ /* labelled as entry point in dvd-vr */
+ int chapter = 0;
+
+ /* see if we've reached the next entry point */
+ ud_pgci_t *psi = &p_sys->ud_pgcit->ud_pgci_items[p_sys->i_title];
+ int cell_base = psi->first_prog_id - 1;
+
+ for( int i = 0; i < psi->nr_of_programs; i++ )
+ {
+ int cell_idx = cell_base + i;
+ m_c_gi_t *cell = &p_sys->ud_pgcit->m_c_gi[cell_idx];
+
+ if ( cell_idx == p_sys->i_cur_cell )
+ break;
+
+ /* entry points are chapters, count cell as 1 if no entry points */
+ chapter += cell->c_epi_n ? cell->c_epi_n : 1;
+
+ }
+
+ if( chapter >= p_sys->i_chapters )
+ chapter = p_sys->i_chapters > 0 ? p_sys->i_chapters - 1 : 0;
+
+ if( chapter != p_sys->i_chapter )
+ {
+ p_sys->i_chapter = chapter;
+ if( p_sys->cur_chapter != chapter )
+ {
+ p_sys->updates |= INPUT_UPDATE_SEEKPOINT;
+ p_sys->cur_chapter = chapter;
+ }
+ }
+
+}
+
+static vlc_tick_t DVDVRGetTitleLength( pgc_gi_t *pgc_gi, ud_pgcit_t *ud_pgcit, int program)
+{
+ uint64_t length_ptm = 0;
+ uint16_t first_prog_id = ud_pgcit->ud_pgci_items[program].first_prog_id;
+ uint16_t nr_of_programs = ud_pgcit->ud_pgci_items[program].nr_of_programs;
+
+ for ( int i = 0; i < nr_of_programs; i++ )
+ length_ptm += pgc_gi->pgi[first_prog_id -1 + i].header.vob_v_e_ptm.ptm
+ - pgc_gi->pgi[first_prog_id -1 + i].header.vob_v_s_ptm.ptm;
+
+ return FROM_SCALE_NZ( length_ptm );
+}
+#endif
+
/*****************************************************************************
* DvdReadSeek : Goes to a given position on the stream.
*****************************************************************************
@@ -1503,6 +1893,48 @@ static int DvdAudioReadSeek( demux_t *p_demux, uint32_t i_block_offset ){
}
#endif
+#ifdef DVDREAD_HAS_DVDVIDEORECORDING
+static int DvdVRReadSeek( demux_t *p_demux, uint32_t i_block_offset )
+{
+ demux_sys_t *p_sys = p_demux->p_sys;
+ int i_chapter = 0;
+ uint32_t vobu_accum = 0;
+
+ int cell_base = p_sys->ud_pgcit->ud_pgci_items[p_sys->i_title].first_prog_id - 1;
+ int nr = p_sys->ud_pgcit->ud_pgci_items[p_sys->i_title].nr_of_programs;
+
+ for( int c = 0; c < nr; c++ )
+ {
+ int cell_idx = cell_base + c;
+ uint16_t srpn = p_sys->ud_pgcit->m_c_gi[cell_idx].m_vobi_srpn;
+ uint16_t cell_vobus = p_sys->pgc_gi->pgi[srpn - 1].map.nr_of_vobu_info;
+
+ if( i_block_offset < vobu_accum + cell_vobus )
+ {
+ p_sys->i_cur_cell = cell_idx;
+ break;
+ }
+ vobu_accum += cell_vobus;
+
+ i_chapter += p_sys->ud_pgcit->m_c_gi[cell_idx].c_epi_n
+ ? p_sys->ud_pgcit->m_c_gi[cell_idx].c_epi_n : 1;
+ }
+
+ if( i_chapter < p_sys->i_chapters &&
+ p_sys->cur_chapter != i_chapter )
+ {
+ p_sys->updates |= INPUT_UPDATE_SEEKPOINT;
+ p_sys->cur_chapter = i_chapter;
+ }
+
+ p_sys->i_pack_len = 0;
+ p_sys->i_title_offset = vobu_accum;
+ p_sys->i_chapter = i_chapter;
+
+ return VLC_SUCCESS;
+}
+#endif
+
/*****************************************************************************
* DvdReadHandleDSI
*****************************************************************************/
@@ -1675,6 +2107,24 @@ static void DvdReadFindCell( demux_t *p_demux )
}
}
+static const char* ParseTxtEncoding( uint8_t txt_encoding )
+{
+ const char* charset = "Unknown";
+
+ switch (txt_encoding) {
+ case 0x00: charset = "ASCII"; break;
+ case 0x01: charset = "ISO646-JP"; break;
+ case 0x10: charset = "JIS_C6220-1969-RO"; break;
+ case 0x11: charset = "ISO_8859-1"; break;
+ case 0x12: charset = "SHIFT_JIS"; break;
+ default:
+ charset = "ISO_8859-15";
+ break;
+ }
+
+ return charset;
+}
+
/*****************************************************************************
* DemuxTitles: get the titles/chapters or group/tracks structure
*****************************************************************************/
@@ -1688,6 +2138,13 @@ static void DemuxTitles( demux_t *p_demux, int *pi_angle )
/* Find out number of titles/chapters */
int32_t i_titles;
+#ifdef DVDREAD_HAS_DVDVIDEORECORDING
+ const char* disc_charset = NULL;
+ if ( p_sys->type == DVD_VR ) {
+ disc_charset = ParseTxtEncoding( p_sys->p_vmg_file->rtav_vmgi->txt_encoding );
+ i_titles = p_sys->ud_pgcit->nr_of_pgci;
+ } else
+#endif
#ifdef DVDREAD_HAS_DVDAUDIO
if ( p_sys->type == DVD_A )
i_titles = p_sys->p_vmg_file->info_table_second_sector->nr_of_titles;
@@ -1703,7 +2160,24 @@ static void DemuxTitles( demux_t *p_demux, int *pi_angle )
{
int32_t i_chapters = 0;
int j;
-
+#ifdef DVDREAD_HAS_DVDVIDEORECORDING
+ if ( p_sys->type == DVD_VR )
+ {
+ /* chapters are entry points across all cells */
+ uint16_t fpid = p_sys->ud_pgcit->ud_pgci_items[i].first_prog_id;
+ if( fpid == 0 || fpid == 0xFFFF
+ || fpid > p_sys->pgc_gi->nr_of_programs )
+ continue; /* invalid PSI, skip this title */
+ int cell_base = fpid - 1;
+ int nr = p_sys->ud_pgcit->ud_pgci_items[i].nr_of_programs;
+ for( int c = 0; c < nr; c++ )
+ {
+ m_c_gi_t *cell = &p_sys->ud_pgcit->m_c_gi[cell_base + c];
+ i_chapters += cell->c_epi_n ? cell->c_epi_n : 1;
+ }
+ }
+ else
+#endif
#ifdef DVDREAD_HAS_DVDAUDIO
if ( p_sys->type == DVD_A )
i_chapters = p_sys->p_vmg_file->info_table_second_sector->tracks_info[i].nr_chapters_in_title;
@@ -1714,19 +2188,75 @@ static void DemuxTitles( demux_t *p_demux, int *pi_angle )
msg_Dbg( p_demux, "title %d has %d chapters", i, i_chapters );
t = vlc_input_title_New();
+ if ( unlikely( !t ) )
+ return;
+#ifdef DVDREAD_HAS_DVDVIDEORECORDING
+ if ( p_sys->type == DVD_VR ) {
+ char* converted_title = FromCharset(
+ disc_charset,
+ p_sys->ud_pgcit->ud_pgci_items[i].title,
+ strnlen( p_sys->ud_pgcit->ud_pgci_items[i].title,
+ sizeof(p_sys->ud_pgcit->ud_pgci_items[i].title) )
+ );
+ if ( converted_title && *converted_title )
+ t->psz_name = converted_title;
+ else {
+ free(converted_title);
+ t->psz_name = strndup(p_sys->ud_pgcit->ud_pgci_items[i].label,
+ sizeof(p_sys->ud_pgcit->ud_pgci_items[i].label) );
+ }
+ t->i_length = DVDVRGetTitleLength( p_sys->pgc_gi, p_sys->ud_pgcit, i );
-#ifdef DVDREAD_HAS_DVDAUDIO
- if ( p_sys->type == DVD_A )
- t->i_length = FROM_SCALE_NZ( p_sys->p_vmg_file->
- info_table_second_sector->tracks_info[i].len_audio_zone_pts );
-#endif
+ /* create one seekpoint per entry point */
+ int cell_base = p_sys->ud_pgcit->ud_pgci_items[i].first_prog_id - 1;
+ int nr = p_sys->ud_pgcit->ud_pgci_items[i].nr_of_programs;
+ for( int c = 0; c < nr; c++ )
+ {
+ m_c_gi_t *cell = &p_sys->ud_pgcit->m_c_gi[cell_base + c];
+ if( cell->c_epi_n > 0 )
+ {
+ for( int ep = 0; ep < cell->c_epi_n; ep++ )
+ {
+ s = vlc_seekpoint_New();
+ if ( unlikely( !s ) )
+ goto fail;
+
+ s->i_time_offset = FROM_SCALE_NZ( (uint64_t)cell->m_c_epi[ep].ep_ptm.ptm );
+ TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
+ }
+ }
+ else
+ {
+ s = vlc_seekpoint_New();
+ if ( unlikely( !s ) )
+ goto fail;
- for( j = 0; j < __MAX( i_chapters, 1 ); j++ )
+ s->i_time_offset = FROM_SCALE_NZ( (uint64_t)cell->c_v_s_ptm.ptm );
+ TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
+ }
+ }
+
+ }
+ else
+#endif
{
- s = vlc_seekpoint_New();
- TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
+#ifdef DVDREAD_HAS_DVDAUDIO
+ if ( p_sys->type == DVD_A )
+ t->i_length = FROM_SCALE_NZ( p_sys->p_vmg_file->
+ info_table_second_sector->tracks_info[i].len_audio_zone_pts );
+#endif
+ for( j = 0; j < __MAX( i_chapters, 1 ); j++ )
+ {
+ s = vlc_seekpoint_New();
+ TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
+ }
}
-
TAB_APPEND( p_sys->i_titles, p_sys->titles, t );
}
+ return;
+
+fail:
+ vlc_input_title_Delete( t );
+ return;
+
}
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/5966bab95d28304f527e6221a7e63ed708e63f25...5c5354618ebb40347d75863097ce3bb4be36eec3
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/5966bab95d28304f527e6221a7e63ed708e63f25...5c5354618ebb40347d75863097ce3bb4be36eec3
You're receiving this email because of your account on code.videolan.org.
More information about the vlc-commits
mailing list