[libdvdnav-devel] [Git][videolan/libdvdread][master] 3 commits: ifoRead_ASVS: size the frame table from nr_frames

Jean-Baptiste Kempf (@jbk) gitlab at videolan.org
Sun Jul 12 19:32:20 UTC 2026



Jean-Baptiste Kempf pushed to branch master at VideoLAN / libdvdread


Commits:
0d5b6530 by Kacper Michajłow at 2026-07-12T21:26:33+02:00
ifoRead_ASVS: size the frame table from nr_frames

The ASVS frame offset table length was computed by summing each group's
start_sector instead of its nr_frames, massively over-reading the IFO.

- - - - -
e9dbc9f3 by Kacper Michajłow at 2026-07-12T21:26:33+02:00
ifoRead_TT: parse the ASVS still picture table

The per-title still picture table that atsi_title_record_t declares was
never read. Parse it into the declared atsi_asvs_range_rows and
atsi_track_still_frame_rows when a title has stills, locating it via the
title record pointer previously named unknown_5 (renamed to
start_still_pic_table now that its meaning is known). The number of still
frame records is derived from the range rows' end offsets.

- - - - -
79da58a7 by Kacper Michajłow at 2026-07-12T21:26:33+02:00
ifo: name and document DVD-Audio ATSI and ASVS fields

Name the still-picture sequence and onset fields, clarify the track
timestamp, sector pointer and ASVS group comments, and fix an
atsi_title_index_t field name typo.

- - - - -


2 changed files:

- src/dvdread/ifo_types.h
- src/ifo_read.c


Changes:

=====================================
src/dvdread/ifo_types.h
=====================================
@@ -914,8 +914,8 @@ typedef struct {
 
 typedef struct {
   uint16_t unknown_1; /* appears to be index, +0x100 for each iter*/
-  uint16_t unkown_2; /* either 0x0000 or 0x0100*/
-  uint32_t offset_record_table; 
+  uint16_t unknown_2; /* either 0x0000 or 0x0100*/
+  uint32_t offset_record_table;
 } ATTRIBUTE_PACKED atsi_title_index_t;
 #define ATSI_TITLE_INDEX_SIZE 8U
 
@@ -925,9 +925,9 @@ typedef struct {
   uint16_t unknown_2; /* will be 0x0000*/
   uint8_t  track_number_in_title;
   uint8_t  unknown_3; /* will be 0x00*/
-  uint32_t first_pts_of_track; /* this is MPEG time, Not DVD time */
+  uint32_t first_pts_of_track; /* PTS of the track's first cell; resets per track, not a title-relative timeline */
 
-  uint32_t length_pts_of_track; /* this is MPEG time, Not DVD time */
+  uint32_t length_pts_of_track; /* track duration in PTS ticks; sums to the title's length_pts */
 
   uint8_t  zero[6];
 } ATTRIBUTE_PACKED atsi_track_timestamp_t;
@@ -936,29 +936,28 @@ typedef struct {
 /* this will come after all of the track timstamps, a set of 12byte sector pointer records. One for each track*/
 typedef struct {
   uint32_t unknown_1; /* will be 0x01000000*/
-  uint32_t start_sector; /* relative to first AOB file*/
-  uint32_t end_sector; /* relative to first end of AOB file */
+  uint32_t start_sector; /* first sector, relative to the first AOB file */
+  uint32_t end_sector; /* last sector, inclusive, relative to the first AOB file */
 } 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 */
+/* One entry per track. start_value and end_value are byte offsets delimiting the
+ * track's records in the still frame table (atsi_asvs_frame_t) that follows. */
 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;
+  uint8_t  unknown_2; /* flag, 0x00 or 0x04 */
+  uint16_t start_value; /* first byte offset into the still frame records */
+  uint16_t end_value;   /* last byte offset into the still frame records */
 } 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 */
+/* there is one set of these per frame group */
 typedef struct {
-  uint8_t  frame_index; /* overall frame index? */
+  uint8_t  pic_seq;   /* picture number within the frame group; restarts at each group */
   uint8_t  unknown_1; /* zero? */
   uint16_t unknown_2;
+  uint32_t onset_pts; /* onset time (90 kHz) relative to the track start */
   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
 
@@ -971,13 +970,14 @@ typedef struct {
   uint16_t unknown_3; /* will be 0x0000*/
   uint16_t unknown_4; /* will be 0x0010*/
   uint16_t start_sector_pointers_table; /* pointer to start of sector pointers table, relative to start of title record*/
-  uint16_t unknown_5; /* will be 0x0000*/
+  uint16_t start_still_pic_table; /* pointer to the still picture table, relative to start of title record; 0 if the title has no stills */
   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 */
+  /* these entries only exist when theres an ASVS. The range rows (one per
+   * track) hold byte offsets into the still frame records that follow them. */
   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 */
+  atsi_asvs_frame_t      *atsi_track_still_frame_rows;
 } ATTRIBUTE_PACKED atsi_title_record_t;
 #define ATSI_TITLE_ROW_TABLE_SIZE 16U
 
@@ -1027,7 +1027,7 @@ typedef struct {
   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 */
+  uint16_t start_sector; /* start sector of the group's frames in AUDIO_SV.VOB */
 } ATTRIBUTE_PACKED asvs_group_t;
 #define ASVS_GROUP_SIZE 8U
 


=====================================
src/ifo_read.c
=====================================
@@ -745,6 +745,8 @@ void ifoFree_TT(ifo_handle_t *ifofile){
     for (int j=0;j<ifofile->atsi_title_table->nr_titles;j++){
       free((ifofile->atsi_title_table->atsi_title_row_tables+j)->atsi_track_pointer_rows);
       free((ifofile->atsi_title_table->atsi_title_row_tables+j)->atsi_track_timestamp_rows);
+      free((ifofile->atsi_title_table->atsi_title_row_tables+j)->atsi_asvs_range_rows);
+      free((ifofile->atsi_title_table->atsi_title_row_tables+j)->atsi_track_still_frame_rows);
     }
     free(ifofile->atsi_title_table->atsi_title_row_tables);
     free(ifofile->atsi_title_table->atsi_index_rows);
@@ -1057,7 +1059,7 @@ static int ifoRead_ASVS(ifo_handle_t *ifofile){
     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;
+    total_nr_frames+=asvs_mat->asvs_groups[i].nr_frames;
   }
 
 
@@ -1087,6 +1089,64 @@ static int ifoRead_ASVS(ifo_handle_t *ifofile){
 
 }
 
+/* Read the still picture table (ASVS) of an audio title, if present. */
+static void ifoRead_TT_stillpics(struct ifo_handle_private_s *ifop,
+                                 atsi_title_record_t *index,
+                                 uint32_t record_offset) {
+  int nr_tracks = index->nr_tracks;
+  atsi_asvs_range_t *ranges;
+  atsi_asvs_frame_t *frames;
+  int base, max_end = 0, nr_frames;
+
+  if(nr_tracks <= 0)
+    return;
+
+  if(!DVDFileSeek_(ifop->file, record_offset + index->start_still_pic_table
+                   + DVD_BLOCK_LEN))
+    return;
+
+  ranges = calloc(nr_tracks, sizeof(atsi_asvs_range_t));
+  if(!ranges)
+    return;
+
+  if(!DVDReadBytes(ifop->file, ranges, nr_tracks * sizeof(atsi_asvs_range_t))) {
+    free(ranges);
+    return;
+  }
+
+  for(int j = 0; j < nr_tracks; j++) {
+    B2N_16(ranges[j].start_value);
+    B2N_16(ranges[j].end_value);
+    if(ranges[j].end_value > max_end)
+      max_end = ranges[j].end_value;
+  }
+  index->atsi_asvs_range_rows = ranges;
+
+  /* The still frame records follow the range table; end_values are byte
+   * offsets into them, so the last referenced record bounds their count. */
+  base = nr_tracks * ATSI_ASVS_RANGES_TABLE_SIZE;
+  if(max_end < base)
+    return;
+  nr_frames = (max_end - base) / ATSI_ASVS_FRAME_TABLE_SIZE + 1;
+
+  frames = calloc(nr_frames, sizeof(atsi_asvs_frame_t));
+  if(!frames)
+    return;
+
+  if(!DVDReadBytes(ifop->file, frames, nr_frames * sizeof(atsi_asvs_frame_t))) {
+    free(frames);
+    return;
+  }
+
+  for(int j = 0; j < nr_frames; j++) {
+    B2N_16(frames[j].unknown_2);
+    B2N_32(frames[j].onset_pts);
+    B2N_16(frames[j].unknown_3);
+  }
+
+  index->atsi_track_still_frame_rows = frames;
+}
+
 int ifoRead_TT(ifo_handle_t *ifofile) {
 
   struct ifo_handle_private_s *ifop = PRIV(ifofile);
@@ -1155,6 +1215,7 @@ int ifoRead_TT(ifo_handle_t *ifofile) {
       goto fail_audio;
 
     B2N_16(index->start_sector_pointers_table);
+    B2N_16(index->start_still_pic_table);
     B2N_32(index->length_pts);
     int nr_tracks=index->nr_tracks;
     int nr_pointer_records = index->nr_pointer_records;
@@ -1203,6 +1264,9 @@ int ifoRead_TT(ifo_handle_t *ifofile) {
                  == ( ATSI_TITLE_ROW_TABLE_SIZE 
                  + index->nr_tracks * ATSI_TRACK_TIMESTAMP_SIZE ) );
 
+    if(index->start_still_pic_table)
+      ifoRead_TT_stillpics(ifop, index, record_offset);
+
   }
   return 1;
 
@@ -1210,6 +1274,8 @@ int ifoRead_TT(ifo_handle_t *ifofile) {
       for (int j = 0; j < i; j++){
         free((atsi_title_table->atsi_title_row_tables + j)->atsi_track_pointer_rows);
         free((atsi_title_table->atsi_title_row_tables + j)->atsi_track_timestamp_rows);
+        free((atsi_title_table->atsi_title_row_tables + j)->atsi_asvs_range_rows);
+        free((atsi_title_table->atsi_title_row_tables + j)->atsi_track_still_frame_rows);
       }
       free(atsi_title_table->atsi_title_row_tables);
       free(ifofile->atsi_title_table->atsi_index_rows);



View it on GitLab: https://code.videolan.org/videolan/libdvdread/-/compare/17f1f079e0dbf49804b2f4b426b056a65aca4270...79da58a7193d8011669838e70f99842d1aec09f1

-- 
View it on GitLab: https://code.videolan.org/videolan/libdvdread/-/compare/17f1f079e0dbf49804b2f4b426b056a65aca4270...79da58a7193d8011669838e70f99842d1aec09f1
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 libdvdnav-devel mailing list