[libdvdnav-devel] [Git][videolan/libdvdread][master] 11 commits: DVD-Audio: Add Audio Still Video Set (ASVS) IFO structures
Jean-Baptiste Kempf (@jbk)
gitlab at videolan.org
Sun Dec 7 20:40:01 UTC 2025
Jean-Baptiste Kempf pushed to branch master at VideoLAN / libdvdread
Commits:
44182853 by Saifelden Mohamed Ismail at 2025-12-05T12:58:18+02:00
DVD-Audio: Add Audio Still Video Set (ASVS) IFO structures
- - - - -
6e98b103 by Saifelden Mohamed Ismail at 2025-12-05T14:20:01+02:00
DVD-Audio: add still frame structures in ATS
- - - - -
32beeadf by Saifelden Mohamed Ismail at 2025-12-05T14:20:13+02:00
DVD-Audio: Add Audio Still Video Set (ASVS) IFO reads
- - - - -
148b4df1 by Saifelden Mohamed Ismail at 2025-12-07T16:12:37+02:00
DVD-Audio: Add asvs enum members
- - - - -
b1252962 by Saifelden Mohamed Ismail at 2025-12-07T16:12:41+02:00
DVD-Audio: Add asvs ifo and backup file open and stat
- - - - -
01f411d5 by Saifelden Mohamed Ismail at 2025-12-07T16:12:41+02:00
DVD-Audio: expose audio_sv.vob menu in DVDOpenFile
- - - - -
5c3bbafd by Saifelden Mohamed Ismail at 2025-12-07T16:12:41+02:00
DVD-Audio: expose Audio Still Video Set (ASVS) ifo and backup
- - - - -
d272808f by Saifelden Mohamed Ismail at 2025-12-07T16:12:41+02:00
DVD-Audio: Add function prototype for set_stream
- - - - -
39d78008 by Saifelden Mohamed Ismail at 2025-12-07T16:12:41+02:00
DVD-Audio: introduce stream type member and setter function
- - - - -
75e2685d by Saifelden Mohamed Ismail at 2025-12-07T16:12:41+02:00
DVD-Audio: Make css and cpxm decryption available simultaneously
- - - - -
482f0ab6 by Saifelden Mohamed Ismail at 2025-12-07T16:12:41+02:00
DVD-Audio: fix stream (AOB, VOB) type logic
- - - - -
6 changed files:
- src/dvd_input.c
- src/dvd_input.h
- src/dvd_reader.c
- src/dvdread/dvd_reader.h
- src/dvdread/ifo_types.h
- src/ifo_read.c
Changes:
=====================================
src/dvd_input.c
=====================================
@@ -75,8 +75,6 @@ int (*dvdinput_init) (dvd_input_t, uint8_t* mkb);
# define DVDcpxm_open_stream(a, b) \
dvdcpxm_open_stream((void*)(a), (dvdcss_stream_cb*)(b))
# define DVDcpxm_open(a) dvdcss_open((char*)(a))
-# define DVDcpxm_close dvdcpxm_close
-# define DVDcpxm_seek dvdcpxm_seek
# define DVDcpxm_read dvdcpxm_read
# define DVDcpxm_init dvdcpxm_init
#endif
@@ -102,10 +100,6 @@ static int (*DVDcss_read) (dvdcss_t, void *, int, int);
#define DVDCSS_SEEK_KEY (1 << 1)
/* function to setup the cpxm struct */
#ifdef HAVE_DVDCSS_DVDCPXM_H
-static dvdcss_t (*DVDcpxm_open_stream) (void *, dvdcss_stream_cb *);
-static dvdcss_t (*DVDcpxm_open) (const char *);
-static int (*DVDcpxm_close) (dvdcss_t);
-static int (*DVDcpxm_seek) (dvdcss_t, int, int);
static int (*DVDcpxm_read) (dvdcss_t, void *, int, int);
static int (*DVDcpxm_init) (dvdcss_t, uint8_t* p_mkb);
#endif
@@ -139,6 +133,12 @@ struct dvd_input_s {
dvd_logger_cb *logcb;
off_t ipos;
+ /* This variable keeps track of the current files stream_type,
+ * and in turn determined the decryption method to use */
+ /* DVD_A -> AOB */
+ /* DVD_V -> VOB */
+ dvd_type_t stream_type;
+
/* dummy file input */
int fd;
/* stream input */
@@ -153,6 +153,7 @@ static dvd_input_t dvd_input_New(void *priv, dvd_logger_cb *logcb)
dev->priv = priv;
dev->logcb = logcb;
dev->ipos = 0;
+ dev->stream_type = DVD_V;
/* Initialize all inputs to safe defaults */
dev->dvdcss = NULL;
@@ -215,6 +216,11 @@ static int css_seek(dvd_input_t dev, int blocks)
*/
static int css_title(dvd_input_t dev, int block)
{
+#ifdef HAVE_DVDCSS_DVDCPXM_H
+ if (dev->stream_type == DVD_A)
+ return DVDcss_seek(dev->dvdcss, block, DVDINPUT_NOFLAGS);
+ else
+#endif
return DVDcss_seek(dev->dvdcss, block, DVDCSS_SEEK_KEY);
}
@@ -223,6 +229,11 @@ static int css_title(dvd_input_t dev, int block)
*/
static int css_read(dvd_input_t dev, void *buffer, int blocks, int flags)
{
+#ifdef HAVE_DVDCSS_DVDCPXM_H
+ if (dev->stream_type == DVD_A)
+ return DVDcpxm_read(dev->dvdcss, buffer, blocks, flags);
+ else
+#endif
return DVDcss_read(dev->dvdcss, buffer, blocks, flags);
}
@@ -241,34 +252,6 @@ static int css_close(dvd_input_t dev)
}
#ifdef HAVE_DVDCSS_DVDCPXM_H
-/**
- * seek into the device.
- */
-static int cpxm_seek(dvd_input_t dev, int blocks)
-{
- /* DVDINPUT_NOFLAGS should match the DVDCSS_NOFLAGS value. */
- return DVDcpxm_seek(dev->dvdcss, blocks, DVDINPUT_NOFLAGS);
-}
-
-/**
- * read data from the device.
- */
-static int cpxm_read(dvd_input_t dev, void *buffer, int blocks, int flags)
-{
- return DVDcpxm_read(dev->dvdcss, buffer, blocks, flags);
-}
-
-static int cpxm_close(dvd_input_t dev)
-{
- int ret;
-
- ret = DVDcpxm_close(dev->dvdcss);
-
- free(dev);
-
- return ret;
-}
-
/**
* Setup Datastructure.
*/
@@ -526,63 +509,49 @@ int dvdinput_setup(void *priv, dvd_logger_cb *logcb, dvd_type_t dvda_flag)
/* Locate the functions, DVD_V or DVD_A */
if(dvdcss_library != NULL) {
/* functions should have the same template*/
- switch(dvda_flag) {
- case DVD_V:
- /* hybrid discs encrypt video tracks with css*/
- DVDcss_open_stream = (dvdcss_t (*)(void *, dvdcss_stream_cb *))
- dlsym(dvdcss_library, U_S "dvdcss_open_stream");
- DVDcss_open = (dvdcss_t (*)(const char*))
- dlsym(dvdcss_library, U_S "dvdcss_open");
- DVDcss_close = (int (*)(dvdcss_t))
- dlsym(dvdcss_library, U_S "dvdcss_close");
- DVDcss_seek = (int (*)(dvdcss_t, int, int))
- dlsym(dvdcss_library, U_S "dvdcss_seek");
- DVDcss_read = (int (*)(dvdcss_t, void*, int, int))
- dlsym(dvdcss_library, U_S "dvdcss_read");
- if(dlsym(dvdcss_library, U_S "dvdcss_crack")) {
- DVDReadLog(priv, logcb, DVD_LOGGER_LEVEL_ERROR,
- "Old (pre-0.0.2) version of libdvdcss found. "
- "libdvdread: You should get the latest version from "
- "https://www.videolan.org/" );
- } else if( ( !DVDcss_open || !DVDcss_close || !DVDcss_seek
- || !DVDcss_read ) && dvda_flag == DVD_V ) {
- DVDReadLog(priv, logcb, DVD_LOGGER_LEVEL_ERROR,
- "Missing symbols in %s, "
- "this shouldn't happen !", CSS_LIB);
- dlclose(dvdcss_library);
- dvdcss_library = NULL;
- }
- break;
- case DVD_A:
+ /* hybrid discs encrypt video tracks with css*/
+ DVDcss_open_stream = (dvdcss_t (*)(void *, dvdcss_stream_cb *))
+ dlsym(dvdcss_library, U_S "dvdcss_open_stream");
+ DVDcss_open = (dvdcss_t (*)(const char*))
+ dlsym(dvdcss_library, U_S "dvdcss_open");
+ DVDcss_close = (int (*)(dvdcss_t))
+ dlsym(dvdcss_library, U_S "dvdcss_close");
+ DVDcss_seek = (int (*)(dvdcss_t, int, int))
+ dlsym(dvdcss_library, U_S "dvdcss_seek");
+ DVDcss_read = (int (*)(dvdcss_t, void*, int, int))
+ dlsym(dvdcss_library, U_S "dvdcss_read");
+ if (dvda_flag == DVD_A) {
#ifdef HAVE_DVDCSS_DVDCPXM_H
- DVDcpxm_open_stream = (dvdcss_t (*)(void *, dvdcss_stream_cb *))
- dlsym(dvdcss_library, U_S "dvdcss_open_stream");
- DVDcpxm_open = (dvdcss_t (*)(const char*))
- dlsym(dvdcss_library, U_S "dvdcss_open");
- DVDcpxm_close = (int (*)(dvdcss_t))
- dlsym(dvdcss_library, U_S "dvdcpxm_close");
- DVDcpxm_seek = (int (*)(dvdcss_t, int, int))
- dlsym(dvdcss_library, U_S "dvdcpxm_seek");
- DVDcpxm_read = (int (*)(dvdcss_t, void*, int, int))
- dlsym(dvdcss_library, U_S "dvdcpxm_read");
- DVDcpxm_init = (int (*)(dvdcss_t, uint8_t *p_mkb))
- dlsym(dvdcss_library, U_S "dvdcpxm_init");
-
- if( ( !DVDcpxm_open || !DVDcpxm_close || !DVDcpxm_seek
- || !DVDcpxm_read || !DVDcpxm_init ) && dvda_flag == DVD_A ) {
- DVDReadLog(priv, logcb, DVD_LOGGER_LEVEL_ERROR,
- "Missing symbols in %s, "
- "DVD-Audio support not present in libdvdcss", CSS_LIB);
- dlclose(dvdcss_library);
- dvdcss_library = NULL;
- }
-#else /* We are trying to open a DVD-Audio, but we don't have the DVDcss CPXM */
- DVDReadLog(priv, logcb, DVD_LOGGER_LEVEL_ERROR,
- "DVD-Audio headers not present, update the DVDCSS library");
- dlclose(dvdcss_library);
- dvdcss_library = NULL;
+ DVDcpxm_read = (int (*)(dvdcss_t, void*, int, int))
+ dlsym(dvdcss_library, U_S "dvdcpxm_read");
+ DVDcpxm_init = (int (*)(dvdcss_t, uint8_t *p_mkb))
+ dlsym(dvdcss_library, U_S "dvdcpxm_init");
+#else
+ DVDReadLog(priv, logcb, DVD_LOGGER_LEVEL_ERROR,
+ "DVD-Audio headers not present, update the DVDCSS library");
+ dlclose(dvdcss_library);
+ dvdcss_library = NULL;
+#endif
+ }
+ if(dlsym(dvdcss_library, U_S "dvdcss_crack")) {
+ DVDReadLog(priv, logcb, DVD_LOGGER_LEVEL_ERROR,
+ "Old (pre-0.0.2) version of libdvdcss found. "
+ "libdvdread: You should get the latest version from "
+ "https://www.videolan.org/" );
+ } else if(!DVDcss_open || !DVDcss_close || !DVDcss_seek || !DVDcss_read) {
+ DVDReadLog(priv, logcb, DVD_LOGGER_LEVEL_ERROR,
+ "Missing symbols in %s, "
+ "this shouldn't happen !", CSS_LIB);
+ dlclose(dvdcss_library);
+ dvdcss_library = NULL;
+#ifdef HAVE_DVDCSS_DVDCPXM_H
+ } else if(!DVDcpxm_read || !DVDcpxm_init) {
+ DVDReadLog(priv, logcb, DVD_LOGGER_LEVEL_ERROR,
+ "Missing symbols for DVD-Audio in %s, "
+ "this shouldn't happen !", CSS_LIB);
+ dlclose(dvdcss_library);
+ dvdcss_library = NULL;
#endif
- break;
}
}
#endif /* HAVE_DVDCSS_DVDCSS_H */
@@ -596,26 +565,19 @@ int dvdinput_setup(void *priv, dvd_logger_cb *logcb, dvd_type_t dvda_flag)
*/
/* libdvdcss wrapper functions */
- switch(dvda_flag){
- case DVD_V:
- dvdinput_open = css_open;
- dvdinput_close = css_close;
- dvdinput_seek = css_seek;
- dvdinput_title = css_title;
- dvdinput_read = css_read;
- break;
- case DVD_A:
+ dvdinput_open = css_open;
+ dvdinput_close = css_close;
+ dvdinput_seek = css_seek;
+ dvdinput_title = css_title;
+ dvdinput_read = css_read;
+
+ /* additional setup function that must be run for DVD_A decryption */
+ if (dvda_flag == DVD_A) {
#ifdef HAVE_DVDCSS_DVDCPXM_H
- dvdinput_open = css_open;
- dvdinput_close = cpxm_close;
- dvdinput_seek = cpxm_seek;
- dvdinput_title = cpxm_seek; /* cpxm title is just seek */
- dvdinput_read = cpxm_read;
- dvdinput_init = cpxm_init;
+ dvdinput_init = cpxm_init;
#else
- assert(!"libdvdcss compiled without DVD-Audio (CPXM) support");
+ assert(!"libdvdcss compiled without DVD-Audio (CPXM) support");
#endif
- break;
}
return 1;
@@ -632,3 +594,9 @@ int dvdinput_setup(void *priv, dvd_logger_cb *logcb, dvd_type_t dvda_flag)
return 0;
}
}
+
+/* change the stream type, this will set the decryption method */
+void dvdinput_set_stream(dvd_input_t dev, dvd_type_t decryption_type)
+{
+ dev->stream_type = decryption_type;
+}
=====================================
src/dvd_input.h
=====================================
@@ -65,6 +65,8 @@ extern int (*dvdinput_title) (dvd_input_t, int);
extern int (*dvdinput_read) (dvd_input_t, void *, int, int);
/* run to initialize DVD-Audio encryption */
extern int (*dvdinput_init) (dvd_input_t, uint8_t* mkb);
+
+extern void dvdinput_set_stream(dvd_input_t, dvd_type_t);
/**
* Setup function accessed by dvd_reader.c. Returns 1 if there is CSS support.
*/
=====================================
src/dvd_reader.c
=====================================
@@ -1011,12 +1011,26 @@ static dvd_file_t *DVDOpenVOBUDF( dvd_reader_t *ctx, int title, int menu )
char filename[ MAX_UDF_FILE_NAME_LEN ];
uint32_t start, len;
dvd_file_t *dvd_file;
-
+ /* stream type must be set to determine decryption method*/
+ /* DVD-Audio discs contain both AOBs and VOBs */
+ /* DVD_V = VOB, DVD_A = AOB */
+ dvd_type_t stream_type;
if( title == 0 ) {
+ stream_type = DVD_V;
sprintf( filename, "/%s_TS/%s_TS.VOB", DVD_TYPE_STRING( ctx->dvd_type ), DVD_TYPE_STRING( ctx->dvd_type ) );
+ } else if(!menu) {
+ /* DVD Content - Tracks/Chapters */
+ stream_type = ctx->dvd_type;
+ sprintf( filename, "/%s_TS/%cTS_%02d_1.%cOB", DVD_TYPE_STRING( ctx->dvd_type ),
+ STREAM_TYPE_STRING( ctx->dvd_type ), title, STREAM_TYPE_STRING( ctx->dvd_type ) );
} else {
- sprintf( filename, "/%s_TS/%cTS_%02d_%d.%cOB", DVD_TYPE_STRING( ctx->dvd_type ), STREAM_TYPE_STRING( ctx->dvd_type ),
- title, menu ? 0 : 1, STREAM_TYPE_STRING( ctx->dvd_type ) );
+ stream_type = DVD_V;
+ if ( ctx->dvd_type == DVD_V )
+ /* DVD_Video title menu */
+ sprintf( filename, "/VIDEO_TS/VTS_%02d_0.VOB", title );
+ else if ( ctx->dvd_type == DVD_A )
+ /* DVD_Audio title menu */
+ sprintf( filename, "/AUDIO_TS/AUDIO_SV.VOB" );
}
start = UDFFindFile( ctx, filename, &len );
if( start == 0 ) return NULL;
@@ -1026,7 +1040,7 @@ static dvd_file_t *DVDOpenVOBUDF( dvd_reader_t *ctx, int title, int menu )
dvd_file->ctx = ctx;
/* css vars not used in CPXM */
- if( ctx->dvd_type == DVD_V )
+ if( stream_type == DVD_V )
/*Hack*/ dvd_file->css_title = title << 1 | menu;
dvd_file->lb_start = start;
@@ -1044,7 +1058,7 @@ static dvd_file_t *DVDOpenVOBUDF( dvd_reader_t *ctx, int title, int menu )
}
}
- if( ctx->dvd_type == DVD_V && ctx->rd->css_state == 1 /* Need key init */ ) {
+ if( stream_type == DVD_V && ctx->rd->css_state == 1 /* Need key init */ ) {
initAllCSSKeys( ctx );
ctx->rd->css_state = 2;
}
@@ -1054,6 +1068,7 @@ static dvd_file_t *DVDOpenVOBUDF( dvd_reader_t *ctx, int title, int menu )
}
*/
+ dvdinput_set_stream( ctx->rd->dev, stream_type );
return dvd_file;
}
@@ -1076,11 +1091,15 @@ static dvd_file_t *DVDOpenVOBPath( dvd_reader_t *ctx, int title, int menu )
dvd_input_t dev;
if( title == 0 ) {
- /* there can not be an AUDIO_TS.AOB, there is however sometimes an AUDIO_TS.VOB menu */
+ /* the root menu is AUDIO_TS.VOB or VIDEO_TS.VOB */
sprintf(filename, "%s_TS.VOB", DVD_TYPE_STRING( ctx->dvd_type ) );
- } else if ( ctx->dvd_type == DVD_V ) {
+ } else {
/* there are no ATS_%02i_0.AOB's */
- sprintf( filename, "VTS_%02i_0.VOB", title );
+ if ( ctx->dvd_type == DVD_V )
+ sprintf( filename, "VTS_%02i_0.VOB", title );
+ else
+ /* Remaining title menus would be in the still videos VOB */
+ sprintf( filename, "AUDIO_SV.VOB" );
}
if( !findDVDFile( ctx, filename, full_path ) ) {
free( dvd_file );
@@ -1103,6 +1122,8 @@ static dvd_file_t *DVDOpenVOBPath( dvd_reader_t *ctx, int title, int menu )
dvd_file->title_devs[ 0 ] = dev;
dvdinput_title( dvd_file->title_devs[0], 0);
dvd_file->filesize = dvd_file->title_sizes[ 0 ];
+ /* menus are always VOB streams */
+ dvdinput_set_stream(dev, DVD_V);
} else {
int i;
@@ -1121,6 +1142,8 @@ static dvd_file_t *DVDOpenVOBPath( dvd_reader_t *ctx, int title, int menu )
dvd_file->title_sizes[ i ] = fileinfo.st_size / DVD_VIDEO_LB_LEN;
dvd_file->title_devs[ i ] = dvdinput_open( ctx->priv, &ctx->logcb, full_path, NULL );
+ /* setting type of stream will determine what decryption to use */
+ dvdinput_set_stream( dvd_file->title_devs[ i ], ctx->dvd_type );
dvdinput_title( dvd_file->title_devs[ i ], 0 );
dvd_file->filesize += dvd_file->title_sizes[ i ];
}
@@ -1167,12 +1190,14 @@ dvd_file_t *DVDOpenFile( dvd_reader_t *ctx, int titlenum,
break;
case DVD_READ_MENU_VOBS:
if( dvd->isImageFile ) {
- /* there is only one DVD-Audio menu vob, this call should be restricted */
- if ( ctx->dvd_type == DVD_A && titlenum != 0 )
+ /* there is only two DVD-Audio menu vobs, and the second is optional
+ * in the case of DVD-Audio, this should return 0 for AUDIO_TS.VOB, which is the main menu
+ * AUDIO_SV.VOB is the Audio Still Video Set (ASVS), and contains the title menus */
+ if ( ctx->dvd_type == DVD_A && titlenum > 1 )
Log2( ctx, "Defaulting to the only menu on DVD-Audio discs" );
- return DVDOpenVOBUDF( ctx, ( ctx->dvd_type == DVD_V ? titlenum : 0 ), 1 );
+ return DVDOpenVOBUDF( ctx, ( ctx->dvd_type == DVD_V ? titlenum : titlenum > 0 ), 1 );
} else {
- return DVDOpenVOBPath( ctx, ( ctx->dvd_type == DVD_V ? titlenum : 0 ), 1 );
+ return DVDOpenVOBPath( ctx, ( ctx->dvd_type == DVD_V ? titlenum : titlenum > 0 ), 1 );
}
break;
case DVD_READ_TITLE_VOBS:
@@ -1190,6 +1215,24 @@ dvd_file_t *DVDOpenFile( dvd_reader_t *ctx, int titlenum,
return NULL;
}
strcpy( filename, "/AUDIO_TS/AUDIO_PP.IFO" );
+ break;
+ case DVD_READ_ASVS_INFO:
+ /* no other way to reach ASVS menu*/
+ if( ctx->dvd_type == DVD_V ) {
+ Log1( ctx, "ASVS IFO is exclusive to DVD-Audio" );
+ return NULL;
+ }
+ strcpy( filename, "/AUDIO_TS/AUDIO_SV.IFO" );
+
+ break;
+ case DVD_READ_ASVS_INFO_BACKUP:
+ /* no other way to reach ASVS menu*/
+ if( ctx->dvd_type == DVD_V ) {
+ Log1( ctx, "ASVS IFO Backup is exclusive to DVD-Audio" );
+ return NULL;
+ }
+ strcpy( filename, "/AUDIO_TS/AUDIO_SV.BUP" );
+
break;
default:
Log1( ctx, "Invalid domain for file open." );
@@ -1383,6 +1426,24 @@ int DVDFileStat( dvd_reader_t *reader, int titlenum,
}
strcpy( filename, "/AUDIO_TS/AUDIO_PP.IFO" );
+ break;
+ case DVD_READ_ASVS_INFO:
+ /* no other way to reach ASVS menu*/
+ if( reader->dvd_type == DVD_V ) {
+ Log1( reader, "ASVS IFO is exclusive to DVD-Audio" );
+ return -1;
+ }
+ strcpy( filename, "/AUDIO_TS/AUDIO_SV.IFO" );
+
+ break;
+ case DVD_READ_ASVS_INFO_BACKUP:
+ /* no other way to reach ASVS menu*/
+ if( reader->dvd_type == DVD_V ) {
+ Log1( reader, "ASVS IFO Backup is exclusive to DVD-Audio" );
+ return -1;
+ }
+ strcpy( filename, "/AUDIO_TS/AUDIO_SV.BUP" );
+
break;
default:
Log1(reader, "Invalid domain for file stat." );
=====================================
src/dvdread/dvd_reader.h
=====================================
@@ -187,6 +187,8 @@ typedef enum {
the title set are opened and read as a
single file. */
DVD_READ_SAMG_INFO, /* for the AUDIO_PP.IFO */
+ DVD_READ_ASVS_INFO, /* for the AUDIO_SV.IFO */
+ DVD_READ_ASVS_INFO_BACKUP, /* for the AUDIO_SV.BUP */
} dvd_read_domain_t;
/**
=====================================
src/dvdread/ifo_types.h
=====================================
@@ -913,6 +913,27 @@ typedef struct {
} ATTRIBUTE_PACKED atsi_track_pointer_t;
#define ATSI_TRACK_POINTER_SIZE 12U
+/* the bellow entries are likely related to still frames, they are still largly undocumented
+ * likely contain some information on duration of still images */
+typedef struct {
+ uint8_t unknown_1; /* always 0x01 */
+ uint8_t unknown_2; /* probably a flag. sometimes 00, sometimes 04 */
+ uint16_t start_value; /* seems like a set of ranges, next entry starts where this ends */
+ uint16_t end_value;
+} ATTRIBUTE_PACKED atsi_asvs_range_t;
+#define ATSI_ASVS_RANGES_TABLE_SIZE 6U
+
+/* there is one set of these per frame group, resets at 01 when at start of group */
+typedef struct {
+ uint8_t frame_index; /* overall frame index? */
+ uint8_t unknown_1; /* zero? */
+ uint16_t unknown_2;
+ uint16_t unknown_3;
+ uint16_t unknown_4;
+ uint16_t unknown_5;
+} ATTRIBUTE_PACKED atsi_asvs_frame_t;
+#define ATSI_ASVS_FRAME_TABLE_SIZE 10U
+
typedef struct {
uint16_t unknown_1; /* will be 0x0000*/
uint8_t nr_tracks; /* unsure if this holds up for other files*/
@@ -925,6 +946,10 @@ typedef struct {
uint16_t unknown_5; /* will be 0x0000*/
atsi_track_timestamp_t *atsi_track_timestamp_rows; /*length determined by nr_tracks*/
atsi_track_pointer_t *atsi_track_pointer_rows;
+
+ /* these entries only exist when theres an ASVS */
+ atsi_asvs_range_t *atsi_asvs_range_rows; /* length determined by nr_tracks */
+ atsi_asvs_frame_t *atsi_track_still_frame_rows; /* length determined by the ASVS struct, total nr of frames */
} ATTRIBUTE_PACKED atsi_title_record_t;
#define ATSI_TITLE_ROW_TABLE_SIZE 16U
@@ -937,6 +962,75 @@ typedef struct {
} ATTRIBUTE_PACKED atsi_title_table_t;
#define ATSI_TITLE_TABLE_SIZE 8U
+/**
+ * ASVS
+ *
+ * Structures relating to the Audio Still Video Set (ASVS).
+ */
+
+/**
+ * ASVS Frame Groupings (unofficial term):
+ *
+ * Frame groupings are unrelated to DVD-Audio audio groups. When multiple
+ * groupings exist, they represent sets of frames per audio track (typically
+ * lyric pages or per-track menus). Each DVD-Audio trackpoint requires an
+ * associated still frame.
+ *
+ * Multiple groupings present:
+ * - Frame records use relative sector offsets from grouping's start_sector
+ * - High bit (0x8000) set in frame_record_t marks grouping boundaries
+ *
+ * Single grouping only:
+ * - Frame records contain absolute sector addresses (high bit clear)
+ * - Seems to indicates simple still frames without menus/lyrics
+ *
+ * The unknown2[72] block likely contains encoder metadata (resolution, color)
+ * and is likely not required for frame extraction.
+ *
+ * there seems to be header offset in the vob file of 35 bytes
+ */
+
+ /**
+ * ASVS Group Entry
+ * Describes a contiguous sequence of frames in the MPEG stream,
+ */
+typedef struct {
+ uint8_t nr_frames;
+ uint8_t unknown;
+ uint16_t start_frame; /* seems to be the number of the start frame (index + 1) */
+ uint16_t zero1;
+ uint16_t start_sector; /* start sector of frame VOBU packet in AUDIO_TS.VOB */
+} ATTRIBUTE_PACKED asvs_group_t;
+#define ASVS_GROUP_SIZE 8U
+
+#define ASVS_GROUP_MAX_SIZE 99U
+
+/**
+ * offset in sectors relative to the group start_sector
+ * total number of frames is the sum of nr_frames for each element in asvs_groups
+ * If high bit set (0x8000): relative offset within group
+ * Otherwise: absolute frame position
+ */
+typedef uint16_t frame_record_t;
+#define ASVS_FRAME_RECORD_SIZE 2U
+
+/**
+ * Audio Still Video Set Management Table. Exclusive to DVD-Audio discs
+ */
+typedef struct {
+ char asvs_identifier[12]; /* DVDAUDIOASVS */
+ uint16_t asvs_nr_groups; /* number of elements in asvs_groups */
+ uint16_t specification_version; /* always 0x0012 */
+ uint16_t zero1;
+ uint16_t unknown1; /* always 0002 */
+ uint16_t zero2;
+ uint16_t length_sectors; /* seems like length of AUDIO_TS.VOB in sectors */
+ uint8_t unknown2[72]; /* not sure what these are. 0x00108080 repeateds alot */
+ asvs_group_t asvs_groups[ASVS_GROUP_MAX_SIZE]; /* size determined by asvs_nr_groups */
+ frame_record_t *frame_offsets_sectors;
+} ATTRIBUTE_PACKED asvs_mat_t;
+#define ASVS_MAT_SIZE 888U
+
/**
* PartOfTitle Unit Information.
*/
@@ -1058,6 +1152,9 @@ typedef struct {
/* ATSI */
atsi_mat_t *atsi_mat;
atsi_title_table_t *atsi_title_table;
+
+ /* ASVS */
+ asvs_mat_t *asvs_mat;
};
};
=====================================
src/ifo_read.c
=====================================
@@ -94,6 +94,8 @@ static int ifoRead_VMG(ifo_handle_t *ifofile);
static int ifoRead_AMG(ifo_handle_t *ifofile);
/* Can be used to make simple dvd-a playback, no menus*/
static int ifoRead_SAMG(ifo_handle_t *ifofile);
+/* for the still video set */
+static int ifoRead_ASVS(ifo_handle_t *ifofile);
static int ifoRead_VTS(ifo_handle_t *ifofile);
static int ifoRead_ATS(ifo_handle_t *ifofile);
@@ -192,7 +194,7 @@ CHECK_STRUCT_SIZE(atsi_mat_t, 0, ATSI_MAT_SIZE);
CHECK_STRUCT_SIZE(atsi_title_index_t, 0, ATSI_TITLE_INDEX_SIZE);
CHECK_STRUCT_SIZE(atsi_track_timestamp_t, 0, ATSI_TRACK_TIMESTAMP_SIZE);
CHECK_STRUCT_SIZE(atsi_track_pointer_t, 0, ATSI_TRACK_POINTER_SIZE);
-CHECK_STRUCT_SIZE(atsi_title_record_t, 2, ATSI_TITLE_ROW_TABLE_SIZE);
+CHECK_STRUCT_SIZE(atsi_title_record_t, 4, ATSI_TITLE_ROW_TABLE_SIZE);
CHECK_STRUCT_SIZE(atsi_title_table_t, 2, ATSI_TITLE_TABLE_SIZE);
CHECK_STRUCT_SIZE(downmix_coeff_t, 0, DOWNMIX_COEFF_SIZE);
@@ -471,6 +473,16 @@ static ifo_handle_t *ifoOpenFileOrBackup(dvd_reader_t *ctx, int title,
if(!ifoRead_SAMG(ifofile))
goto ifoOpen_fail;
+ /* The Audio Still Video Set (ASVS) is optional, though usually exists */
+ ifop->file = DVDOpenFile(ctx, 2, backup ? DVD_READ_ASVS_INFO_BACKUP
+ : DVD_READ_ASVS_INFO);
+ if(!ifop->file)
+ Log1(ctx, "Disc does not have a still video set");
+ else {
+ if(!ifoRead_ASVS(ifofile))
+ goto ifoOpen_fail;
+ }
+
return ifofile;
}
@@ -825,6 +837,75 @@ static int ifoRead_SAMG(ifo_handle_t *ifofile) {
return 1;
}
+static int ifoRead_ASVS(ifo_handle_t *ifofile){
+
+ struct ifo_handle_private_s *ifop = PRIV(ifofile);
+ asvs_mat_t *asvs_mat;
+
+ asvs_mat = calloc(1, sizeof(asvs_mat_t));
+
+ if(!asvs_mat)
+ return 0;
+
+ ifofile->asvs_mat = asvs_mat;
+
+ if(!DVDFileSeek_(ifop->file, 0)) {
+ free(ifofile->asvs_mat);
+ ifofile->asvs_mat = NULL;
+ return 0;
+ }
+
+ if(!DVDReadBytes(ifop->file, asvs_mat, ASVS_MAT_SIZE)) {
+ free(ifofile->asvs_mat);
+ ifofile->asvs_mat = NULL;
+ return 0;
+ }
+
+ if(strncmp("DVDAUDIOASVS", asvs_mat->asvs_identifier, 12) != 0) {
+ free(ifofile->asvs_mat);
+ ifofile->asvs_mat = NULL;
+ return 0;
+ }
+
+ B2N_16(asvs_mat->asvs_nr_groups);
+ B2N_16(asvs_mat->specification_version);
+ B2N_16(asvs_mat->length_sectors);
+
+ int total_nr_frames = 0;
+ for (int i = 0; i < asvs_mat->asvs_nr_groups; i++ ) {
+ B2N_16(asvs_mat->asvs_groups[i].start_frame);
+ B2N_16(asvs_mat->asvs_groups[i].start_sector);
+ CHECK_ZERO(asvs_mat->asvs_groups[i].zero1);
+ total_nr_frames+=asvs_mat->asvs_groups[i].start_sector;
+ }
+
+
+ asvs_mat->frame_offsets_sectors = calloc(total_nr_frames, ASVS_FRAME_RECORD_SIZE);
+ if(!asvs_mat->frame_offsets_sectors) {
+ free(ifofile->asvs_mat);
+ ifofile->asvs_mat = NULL;
+ return 0;
+ }
+
+ if(!DVDReadBytes(ifop->file, asvs_mat->frame_offsets_sectors,
+ total_nr_frames * ASVS_FRAME_RECORD_SIZE )) {
+ free(asvs_mat->frame_offsets_sectors);
+ free(ifofile->asvs_mat);
+ ifofile->asvs_mat = NULL;
+ return 0;
+ }
+
+ for(int i = 0; i < total_nr_frames; i++)
+ B2N_16(asvs_mat->frame_offsets_sectors[i]);
+
+
+ CHECK_VALUE(asvs_mat->specification_version == 0x0012);
+ CHECK_ZERO(asvs_mat->zero1);
+ CHECK_ZERO(asvs_mat->zero2);
+ return 1;
+
+}
+
int ifoRead_TT(ifo_handle_t *ifofile) {
struct ifo_handle_private_s *ifop = PRIV(ifofile);
View it on GitLab: https://code.videolan.org/videolan/libdvdread/-/compare/c7f373951bae9642e1ce1fbb2cd02f92c09756e0...482f0ab6de0e3771ed3f573e7107585ba105a6ae
--
View it on GitLab: https://code.videolan.org/videolan/libdvdread/-/compare/c7f373951bae9642e1ce1fbb2cd02f92c09756e0...482f0ab6de0e3771ed3f573e7107585ba105a6ae
You're receiving this email because of your account on code.videolan.org.
VideoLAN code repository instance
More information about the libdvdnav-devel
mailing list