[libdvdnav-devel] [Git][videolan/libdvdread][master] 3 commits: Fix the ATSI_MAT down mix coefficient tables
Jean-Baptiste Kempf (@jbk)
gitlab at videolan.org
Wed Jul 29 06:48:54 UTC 2026
Jean-Baptiste Kempf pushed to branch master at VideoLAN / libdvdread
Commits:
5f9a33db by Kacper Michajłow at 2026-07-29T08:47:57+02:00
Fix the ATSI_MAT down mix coefficient tables
The sixteen ATS_DM_COEFT tables occupy 288 bytes of the ATSI_MAT, 18
bytes each, not 16 (US 2001/0008578 FIG. 25, RBP 384 to 671), so every
table after the first parsed shifted. Each table holds a left and right
gain code pair for up to eight audio channels in stream order, given by
the channel group assignment of the audio attribute; 0xff mutes a
channel. On the one available disc with coefficients the 18 byte stride
lines up exactly and the pair structure is consistent, while the old
named 5.1 fields misassigned the channels.
The audio programs select among the tables: bytes 2 and 3 of the
ATS_PGI are the attribute number and the down mix coefficient table
number (ATRN and DM_COEFTN, US 2001/0008578 [0258]), not reserved.
- - - - -
99780dff by Kacper Michajłow at 2026-07-29T08:47:57+02:00
Identify the SAMG chapter audio fields
Bytes 17 to 19 of a chapter record repeat the quantization, sampling
frequency and channel assignment of the track in the audio pack private
header encoding (US 6,580,671 FIG. 29): a nibble per channel group with
0xf marking an absent second group, and the 5-bit channel layout code.
The third byte is the channel assignment, not a channel count; the
values decode identically to the packs on every disc checked.
- - - - -
e37cb329 by Kacper Michajłow at 2026-07-29T08:47:57+02:00
Identify the ASVU attribute bits
US 6,788,880 FIG. 53 gives the still picture attribute layout: video
compression mode, TV system, aspect ratio, display mode and source
picture resolution. The values seen on discs decode accordingly: the
625/50 discs set the TV system field, and the 16:9 disc the aspect and
letterbox display mode.
- - - - -
3 changed files:
- src/dvdread/ifo_types.h
- src/ifo_print.c
- src/ifo_read.c
Changes:
=====================================
src/dvdread/ifo_types.h
=====================================
@@ -477,48 +477,32 @@ typedef struct {
} ATTRIBUTE_PACKED vmgi_mat_t;
#define VMGI_MAT_SIZE 510U
-/* Downmix coefficients can be used to reduce 5.1 channels to stereo in DVD-Audio Discs */
-/** Downmix equations
- * Left_out = Lf_left * Lf
- * + Rf_left * Rf
- * + C_left * C
- * + LFE_left * LFE
- * + Ls_left * Ls
- * + Rs_left * Rs;
- *
- * Right_out = Lf_right * Lf
- * + Rf_right * Rf
- * + C_right * C
- * + LFE_right * LFE
- * + Ls_right * Ls
- * + Rs_right * Rs;
- *
- * Where:
- * - Lf, Rf, C, LFE, Ls, Rs are the 5.1 input channels
- * - Left_out, Right_out are the stereo output channels
- * - Each coefficient (e.g. Lf_left, C_right) is an 8-bit gain factor
+/**
+ * One down mix coefficient table (ATS_DM_COEFT). Sixteen tables follow the
+ * audio attributes in the ATSI_MAT; each audio program selects the table to
+ * mix its multichannel audio down to two channels through the dm_coeftn of
+ * its ATS_PGI:
+ *
+ * Left_out = sum over the channels of coef ch.left * ch
+ * Right_out = sum over the channels of coef ch.right * ch
+ *
+ * The pairs follow the channels of the stream, given by the channel group
+ * assignment of the audio attribute, except that the LFE is ordered last:
+ * a 5.1 track uses Lf, Rf, C, Ls, Rs, LFE. Pairs past the channel count
+ * are zero. A coefficient is a gain code: 0.2 dB per step from 0 dB at
+ * 0x00 to -40 dB at 0xc8, then 0.4 dB per step down to -61.8 dB at 0xfe,
+ * and 0xff mutes the channel. The tables are all zero when the ATS has no
+ * AOBs of its own, and on discs whose MLP streams carry their own down
+ * mix instead.
*/
-
typedef struct {
- /* it seems each entry is started and ended with padding */
uint16_t zero_1;
- /* each coefficient corresponds to stereo side for a channel in 5.1 */
- uint8_t Lf_left;
- uint8_t Lf_right;
- uint8_t Rf_left;
- uint8_t Rf_right;
- uint8_t C_left;
- uint8_t C_right;
- uint8_t LFE_left;
- uint8_t LFE_right;
- uint8_t Ls_left;
- uint8_t Ls_right;
- uint8_t Rs_left;
- uint8_t Rs_right;
-
- uint16_t zero_2;
+ struct ATTRIBUTE_PACKED {
+ uint8_t left;
+ uint8_t right;
+ } dm_coef[8]; /* one pair per audio channel of the stream */
} ATTRIBUTE_PACKED downmix_coeff_t;
-#define DOWNMIX_COEFF_SIZE 16U
+#define DOWNMIX_COEFF_SIZE 18U
/**
@@ -539,11 +523,14 @@ typedef struct {
uint32_t chapter_len;
uint32_t zero_2;
uint8_t record_code; /* the top bit is set on the first chapter of a group */
- uint8_t bit_depth;
- uint8_t sampling_rate;
- uint8_t nr_channels;
- /* some DVD's made with authoring software keep downmix coefficients here */
- /* since I do not have samples of commercial discs that do this, I will not include it */
+ /* the next three bytes use the audio pack private header encoding: a
+ * nibble per channel group, 0xf when there is no second group */
+ uint8_t bit_depth; /* quantization: 0 16-bit, 1 20-bit, 2 24-bit */
+ uint8_t sampling_rate; /* 0 48 kHz, 8 44.1 kHz, +1 and +2 double it */
+ uint8_t channel_assignment; /* channel layout code, 0 to 20 */
+ /* some DVD's made with authoring software keep downmix coefficients here:
+ * bytes 4 to 15 then hold six left/right gain code pairs as in the
+ * ATSI_MAT tables */
uint8_t zero_3[20];
uint32_t start_sector_1; /* first sector of the chapter, an absolute sector of the volume */
uint32_t start_sector_2; /* the same sector repeated again */
@@ -912,7 +899,7 @@ typedef struct {
atsi_record_t atsi_record[ATSI_RECORD_MAX_SIZE];
downmix_coeff_t downmix_coefficients[DOWNMIX_COEFF_MAX_SIZE];
} ATTRIBUTE_PACKED atsi_mat_t;
-#define ATSI_MAT_SIZE 640U
+#define ATSI_MAT_SIZE 672U
typedef struct {
uint8_t srp_index; /* 1-based, top bit set marks the primary entry and clear the secondary */
@@ -923,16 +910,24 @@ typedef struct {
} ATTRIBUTE_PACKED atsi_title_index_t;
#define ATSI_TITLE_INDEX_SIZE 8U
-/* one per audio program in the title */
-typedef struct {
- uint8_t prog_alloc_flags; /* top bit set on the first program of the title */
- uint8_t prog_time_attr_flags; /* either 0x00, 0x10 or 0x30, meaning not confirmed */
- uint16_t reserved_1; /* always 0x0000 */
+/* one per audio program in the title (the ATS_PGI) */
+typedef struct {
+ uint8_t prog_alloc_flags; /* b7 the relation to the previous program, set
+ on the first; b6 an STC discontinuity;
+ b5-b3 which audio attribute of the ATSI_MAT
+ applies (ATRN); b2-b0 the bit shift of
+ channel group 2 */
+ uint8_t prog_downmix_flags; /* b5 down mix prohibited; b4 down mix
+ coefficients not valid; b3-b0 which down
+ mix coefficient table applies (DM_COEFTN) */
+ uint16_t rti_flags; /* real time information flags, zero without RTI */
uint8_t track_number_in_title; /* the cell this program starts on, 1-based */
uint8_t unknown_3; /* always 0x00 */
uint32_t first_pts_of_track; /* start PTS of the program's first cell, not always a title-relative timeline */
uint32_t length_pts_of_track; /* length of the program in PTS, the programs sum to length_pts */
- uint8_t zero[6]; /* will be 0x00 */
+ uint32_t pause_pts_of_track; /* pause after the program, MPEG PTS; only 0 seen */
+ uint8_t cmi; /* copyright management information; only 0 seen */
+ uint8_t reserved_2;
} ATTRIBUTE_PACKED atsi_track_timestamp_t;
#define ATSI_TRACK_TIMESTAMP_SIZE 20U
@@ -1061,9 +1056,13 @@ typedef struct {
uint32_t asv_ea; /* last sector of the last still picture,
counted from the first ASVOBS sector */
uint16_t asvu_atr[4]; /* still picture attributes, selected per
- unit by asvu_atrn; the low byte holds
- the sub-picture setup: 0x00 no streams,
- 0x03 one stream, 0x05 two streams */
+ unit by asvu_atrn: b15-b14 compression
+ (1 MPEG-2), b13-b12 TV system (0
+ 525/60, 1 625/50), b11-b10 aspect (0
+ 4:3, 3 16:9), b9-b8 display mode,
+ b5-b3 source resolution; the low bits
+ hold the sub-picture setup: 0x00 no
+ streams, 0x03 one, 0x05 two */
uint32_t sp_plt[16]; /* sub-picture palette, 16 colours,
0x00YYCrCb, default 0x00108080 */
asvu_gi_t asvu_gi[ASVU_GI_MAX_SIZE]; /* size determined by asvs_nr_of_asvus */
=====================================
src/ifo_print.c
=====================================
@@ -647,26 +647,18 @@ static void ifo_print_atsi_records(atsi_record_t *records){
static void ifo_print_downmix_coefficients(downmix_coeff_t *downmix_coefficients) {
for (int i = 0; i < DOWNMIX_COEFF_MAX_SIZE; i++) {
- printf("DOWNMIX COEFFICIENTS:\n");
+ const downmix_coeff_t *t = &downmix_coefficients[i];
+ int used = 0;
- printf("Lf_left, Lf_right: %02x, %02x\n ",
- downmix_coefficients[i].Lf_left, downmix_coefficients[i].Lf_right);
-
- printf("Rf_left, Rf_right: %02x, %02x\n ",
- downmix_coefficients[i].Rf_left, downmix_coefficients[i].Rf_right);
-
- printf("C_left, C_right: %02x, %02x\n ",
- downmix_coefficients[i].C_left, downmix_coefficients[i].C_right);
-
- printf("LFE_left, LFE_right: %02x, %02x\n ",
- downmix_coefficients[i].LFE_left, downmix_coefficients[i].LFE_right);
-
- printf("Ls_left, Ls_right: %02x, %02x\n ",
- downmix_coefficients[i].Ls_left, downmix_coefficients[i].Ls_right);
-
- printf("Rs_left, Rs_right: %02x, %02x\n ",
- downmix_coefficients[i].Rs_left, downmix_coefficients[i].Rs_right);
+ for (int ch = 0; ch < 8; ch++)
+ used |= t->dm_coef[ch].left | t->dm_coef[ch].right;
+ if (!used)
+ continue;
+ printf("Downmix coefficient table %d (left/right gain codes):", i);
+ for (int ch = 0; ch < 8; ch++)
+ printf(" %02x/%02x", t->dm_coef[ch].left, t->dm_coef[ch].right);
+ printf("\n");
}
}
=====================================
src/ifo_read.c
=====================================
@@ -1263,9 +1263,10 @@ int ifoRead_TT(ifo_handle_t *ifofile) {
}
for (int j = 0; j<nr_tracks; j++) {
- CHECK_ZERO(index->atsi_track_timestamp_rows[j].zero);
+ B2N_16(index->atsi_track_timestamp_rows[j].rti_flags);
B2N_32(index->atsi_track_timestamp_rows[j].first_pts_of_track);
B2N_32(index->atsi_track_timestamp_rows[j].length_pts_of_track);
+ B2N_32(index->atsi_track_timestamp_rows[j].pause_pts_of_track);
}
for (int j = 0; j<nr_pointer_records; j++) {
@@ -1990,7 +1991,6 @@ static int ifoRead_ATS(ifo_handle_t *ifofile) {
for (int i=0; i < DOWNMIX_COEFF_MAX_SIZE; i++) {
CHECK_ZERO(atsi_mat->downmix_coefficients[i].zero_1);
- CHECK_ZERO(atsi_mat->downmix_coefficients[i].zero_2);
}
View it on GitLab: https://code.videolan.org/videolan/libdvdread/-/compare/1335d694cf8f56ca7127f2362d4c37c4274c5a56...e37cb32951503dea45df362580b558623d32f80b
--
View it on GitLab: https://code.videolan.org/videolan/libdvdread/-/compare/1335d694cf8f56ca7127f2362d4c37c4274c5a56...e37cb32951503dea45df362580b558623d32f80b
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