Writing CATALOG and ISRC into Q sub-channel of CD SAO sessions

This commit is contained in:
Thomas Schmitt 2011-12-27 13:38:39 +00:00
parent 67ae1413e3
commit cdaa2971db
5 changed files with 193 additions and 40 deletions

View File

@ -2,7 +2,7 @@
.\" First parameter, NAME, should be all caps .\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1) .\" other parameters are allowed: see man(7), man(1)
.TH CDRSKIN 1 "Dec 25, 2011" .TH CDRSKIN 1 "Dec 27, 2011"
.\" Please adjust this date whenever revising the manpage. .\" Please adjust this date whenever revising the manpage.
.\" .\"
.\" Some roff macros, for reference: .\" Some roff macros, for reference:
@ -506,9 +506,7 @@ present.
.br .br
cdrskin currently supports TRACK datatypes AUDIO and MODE1/2048 which may cdrskin currently supports TRACK datatypes AUDIO and MODE1/2048 which may
not be mixed. It ignores commands POSTGAP, PREGAP, and FLAGS. Only INDEX 01 not be mixed. It ignores commands POSTGAP, PREGAP, and FLAGS. Only INDEX 01
is interpreted yet. Commands CATALOG and ISRC only affect CD-TEXT but not is interpreted yet. Data source may be of FILE type BINARY or MOTOROLA.
the Q sub-channel of the program area. Data source may be of FILE type BINARY
or MOTOROLA.
.TP .TP
.BI \-dao .BI \-dao
Alias for option -sao. Write CD in Session at Once mode Alias for option -sao. Write CD in Session at Once mode

View File

@ -1 +1 @@
#define Cdrskin_timestamP "2011.12.27.115645" #define Cdrskin_timestamP "2011.12.27.133733"

View File

@ -225,7 +225,7 @@ sync. libburn uses the info provided by 52h READ TRACK INFORMATION.
Guided by reading libburn/* from http://icculus.org/burn Guided by reading libburn/* from http://icculus.org/burn
backed by reading mmc5r03c.pdf from http://www.t10.org/ftp/t10/drafts/mmc5/ backed by reading mmc5r03c.pdf from http://www.t10.org/ftp/t10/drafts/mmc5/
and by experiments with drives NEC ND-4570A, LG GSA-4082B, LITE-ON LTR48125S, and by experiments with drives NEC ND-4570A, LG GSA-4082B, LITE-ON LTR48125S,
Optiarc BD RW BD-5300S, Optiarc BD RW BD-5300S, LG BDDVDRW GGC-H20L
For libburnia-project.org by Thomas Schmitt <scdbackup@gmx.net> For libburnia-project.org by Thomas Schmitt <scdbackup@gmx.net>
@ -264,7 +264,8 @@ CTL|ADR, TNO, INDEX, DATA FORM, SCMS, MIN, SEC, FRAME .
CTL is 40h for data and 00h for audio. CTL is 40h for data and 00h for audio.
(mmc5r03c.pdf 6.33.3.4) (mmc5r03c.pdf 6.33.3.4)
ADR is always 01h. ADR is 01h for entries which define time points. It is 02h for media catalog
entries and it is 03h for track ISRC entries.
TNO is the track number (1 to 99). TNO is the track number (1 to 99).
INDEX is a subaddress within tracks. This recipe uses only INDEX 01h within INDEX is a subaddress within tracks. This recipe uses only INDEX 01h within
tracks. tracks.
@ -277,18 +278,33 @@ MIN, SEC, FRAME give the MSF address where the described data entity starts.
LBA = frames - 150, 75 frames = 1 sec , 60 sec = 1 min. LBA = frames - 150, 75 frames = 1 sec , 60 sec = 1 min.
This address must increase from entry to entry (or at least stay equal). This address must increase from entry to entry (or at least stay equal).
The first two entries describe the Media Catalog Number, a string of 13
characters, also known with CD-TEXT as "UPC/EAN".
(02h, catalog characters 1 to 7)
(02h, catalog characters 8 to 13, 00h)
These two entries shall be omitted if no catalog number is given.
The first entry describes the Lead-in. Its content is The next entry (eventually being the first one) describes the Lead-in.
Its content is
(CTL|ADR ,00h,00h, DATA FORM ,00h,00h,00h,00h) (CTL|ADR ,00h,00h, DATA FORM ,00h,00h,00h,00h)
With the CTL|ADR for the first track: 41h for data, 01h for audio. With the CTL|ADR for the first track: 41h for data, 01h for audio.
DATA FORM is 41h if CD-TEXT shall be stored in Lean-in. Else it is 01h. DATA FORM is 41h if CD-TEXT shall be stored in Lean-in. Else it is 01h.
The LBA for the first write is negative: -150. This corresponds to MSF address The LBA for the first write is negative: -150. This corresponds to MSF address
00h:00h:00h. All addresses are to be given in MSF format. 00h:00h:00h. All addresses are to be given in MSF format.
Each track may be preceded by two entries describing an ISRC string of 12
characters.
(CTL | 03h, TNO, characters 1 to 6)
(CTL | 03h, TNO, characters 7 to 12)
These entries shall be omitted if no ISRC is given for the track.
CTL shall be the same as with the track.
The first information track on disc is preceded by a pause encoding of 2 sec: The first information track on disc is preceded by a pause encoding of 2 sec:
(CTL|ADR,01h,00h, DATA FORM ,00h,00h,00h,00h) (CTL|ADR,01h,00h, DATA FORM ,00h,00h,00h,00h)
with DATA FORM = 00h for audio and 10h for data. By those 2 seconds the MSF with DATA FORM = 00h for audio and 10h for data. By those 2 seconds the MSF
address increases to 00h:02h:00h = LBA 0. address increases to 00h:02h:00h = LBA 0. This entry has to come after ISRC,
if ISRC is given for the track.
Each track is represented by an entry Each track is represented by an entry
(CTL|ADR, TNO ,01h,DATA FORM,00h, MIN , SEC , FRAME) (CTL|ADR, TNO ,01h,DATA FORM,00h, MIN , SEC , FRAME)
@ -331,6 +347,10 @@ A Write Parameters mode page 05h has to be composed and transmitted via
Track Mode Describes frame type 0 (is ignored) Track Mode Describes frame type 0 (is ignored)
Data Block Type Layout of payload blocks 0 (is ignored) Data Block Type Layout of payload blocks 0 (is ignored)
Audio Pause Length 150 = 2 seconds (ignored ?) Audio Pause Length 150 = 2 seconds (ignored ?)
>>> CATALOG
>>> no ISRC with SAO
Any other parameters may be set to 0. Any other parameters may be set to 0.
Mode page data as of MMC-5 table 644 are preceded by a Mode Parameter Header Mode page data as of MMC-5 table 644 are preceded by a Mode Parameter Header
as of SPC-3 table 240. This 8-byte header may be filled with zeros. as of SPC-3 table 240. This 8-byte header may be filled with zeros.

View File

@ -620,6 +620,9 @@ static int v07t_cdtext_to_track(struct burn_track *track, int block,
/* ts B11215 API */ /* ts B11215 API */
/* @param flag bit1= do not attach CATALOG to session or ISRC to track for
writing to Q sub-channel
*/
int burn_session_input_sheet_v07t(struct burn_session *session, int burn_session_input_sheet_v07t(struct burn_session *session,
char *path, int block, int flag) char *path, int block, int flag)
{ {
@ -802,6 +805,10 @@ cannot_open:;
&int0x01, 0, "UPC_ISRC", 0); &int0x01, 0, "UPC_ISRC", 0);
if (ret <= 0) if (ret <= 0)
goto ex; goto ex;
if (!(flag & 2)) {
memcpy(session->mediacatalog, payload, 13);
session->mediacatalog[13] = 0;
}
session_attr_seen[0xe] = 1; session_attr_seen[0xe] = 1;
} else if (strncmp(line, "Disc Information ", 17) == 0) { } else if (strncmp(line, "Disc Information ", 17) == 0) {
@ -928,9 +935,15 @@ bad_track_no:;
strcmp(line + 9, "Message") == 0) strcmp(line + 9, "Message") == 0)
pack_type = 0x85; pack_type = 0x85;
else if (strcmp(line + 9, "0x8e") == 0 || else if (strcmp(line + 9, "0x8e") == 0 ||
strcmp(line + 9, "ISRC") == 0) strcmp(line + 9, "ISRC") == 0) {
pack_type = 0x8e; pack_type = 0x8e;
else { if (!(flag & 2)) {
ret = burn_track_set_isrc_string(
tracks[tno], payload, 0);
if (ret <= 0)
goto ex;
}
} else {
sprintf(msg, sprintf(msg,
"Unknown v07t Track purpose specifier '%s'", "Unknown v07t Track purpose specifier '%s'",
line + 9); line + 9);
@ -958,6 +971,12 @@ bad_track_no:;
goto bad_track_no; goto bad_track_no;
} }
tno -= track_offset; tno -= track_offset;
if (!(flag & 2)) {
ret = burn_track_set_isrc_string(
tracks[tno], payload, 0);
if (ret <= 0)
goto ex;
}
ret = v07t_cdtext_to_track(tracks[tno], block, payload, ret = v07t_cdtext_to_track(tracks[tno], block, payload,
&int0x00, 0x8e, "", 0); &int0x00, 0x8e, "", 0);
if (ret <= 0) if (ret <= 0)

View File

@ -272,7 +272,6 @@ int burn_write_close_track(struct burn_write_opts *o, struct burn_session *s,
} }
/* ts A61030 */ /* ts A61030 */
int burn_write_close_session(struct burn_write_opts *o) int burn_write_close_session(struct burn_write_opts *o)
{ {
@ -301,46 +300,66 @@ int burn_write_close_session(struct burn_write_opts *o)
/* ts A60819: /* ts A60819:
This is unused since about Feb 2006, icculus.org/burn CVS. This is unused since about Feb 2006, icculus.org/burn CVS.
The compiler complains. We shall please our compiler. The compiler complains. We shall please our compiler.
# define Libburn_write_with_function_print_cuE
*/ */
#ifdef Libburn_write_with_function_print_cuE #ifdef Libburn_write_with_function_print_cuE
static char cue_printify(char c)
{
if (c >= 32 && c < 127)
return c;
return '#';
}
static void print_cue(struct cue_sheet *sheet) static void print_cue(struct cue_sheet *sheet)
{ {
int i; int i;
unsigned char *unit; unsigned char *unit;
printf("\n"); printf("\n");
printf("ctladr|trno|indx|form|scms| msf\n"); printf("ctladr|trno|indx|form|scms| msf | text\n");
printf("------+----+----+----+----+--------\n"); printf("------+----+----+----+----+----------+--------\n");
for (i = 0; i < sheet->count; i++) { for (i = 0; i < sheet->count; i++) {
unit = sheet->data + 8 * i; unit = sheet->data + 8 * i;
if ((unit[0] & 0xf) == 2) {
printf(
" %1X %1X | | | | | | %c%c%c%c%c%c%c\n",
(unit[0] & 0xf0) >> 4, unit[0] & 0xf,
cue_printify(unit[1]), cue_printify(unit[2]),
cue_printify(unit[3]), cue_printify(unit[4]),
cue_printify(unit[5]), cue_printify(unit[6]),
unit[7] == 0 ? ' ' : cue_printify(unit[7]));
} else if ((unit[0] & 0xf) == 3) {
printf(
" %1X %1X | %02X | | | | | %c%c%c%c%c%c\n",
(unit[0] & 0xf0) >> 4, unit[0] & 0xf,
unit[1], cue_printify(unit[2]),
cue_printify(unit[3]), cue_printify(unit[4]),
cue_printify(unit[5]), cue_printify(unit[6]),
cue_printify(unit[7]));
} else {
printf(" %1X %1X | %02X | %02X | %02X | %02X |", printf(" %1X %1X | %02X | %02X | %02X | %02X |",
(unit[0] & 0xf0) >> 4, unit[0] & 0xf, unit[1], unit[2], (unit[0] & 0xf0) >> 4, unit[0] & 0xf,
unit[3], unit[4]); unit[1], unit[2], unit[3], unit[4]);
printf("%02X:%02X:%02X\n", unit[5], unit[6], unit[7]); printf(" %02X:%02X:%02X |\n",
unit[5], unit[6], unit[7]);
} }
} }
fflush(stdout);
}
#endif /* Libburn_write_with_print_cuE */ #endif /* Libburn_write_with_print_cuE */
/* ts A61009 : changed type from void to int */ /* ts B11226 */
/** @return 1 = success , <=0 failure */ static int new_cue(struct cue_sheet *sheet, int number, int flag)
static int add_cue(struct cue_sheet *sheet, unsigned char ctladr,
unsigned char tno, unsigned char indx,
unsigned char form, unsigned char scms, int lba)
{ {
unsigned char *unit;
unsigned char *ptr; unsigned char *ptr;
int m, s, f;
burn_lba_to_msf(lba, &m, &s, &f); ptr = realloc(sheet->data, (sheet->count + number) * 8);
sheet->count++;
ptr = realloc(sheet->data, sheet->count * 8);
/* ts A61009 */
/* a ssert(ptr); */
if (ptr == NULL) { if (ptr == NULL) {
libdax_msgs_submit(libdax_messenger, -1, 0x00020111, libdax_msgs_submit(libdax_messenger, -1, 0x00020111,
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH, LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
@ -348,8 +367,26 @@ static int add_cue(struct cue_sheet *sheet, unsigned char ctladr,
0, 0); 0, 0);
return -1; return -1;
} }
sheet->data = ptr; sheet->data = ptr;
sheet->count += number;
return 1;
}
/* ts B11226 : outsourced new_cue() */
/** @return 1 = success , <=0 failure */
static int add_cue(struct cue_sheet *sheet, unsigned char ctladr,
unsigned char tno, unsigned char indx,
unsigned char form, unsigned char scms, int lba)
{
unsigned char *unit;
int m, s, f, ret;
burn_lba_to_msf(lba, &m, &s, &f);
ret = new_cue(sheet, 1, 0);
if (ret <= 0)
return -1;
unit = sheet->data + (sheet->count - 1) * 8; unit = sheet->data + (sheet->count - 1) * 8;
unit[0] = ctladr; unit[0] = ctladr;
unit[1] = tno; unit[1] = tno;
@ -362,13 +399,59 @@ static int add_cue(struct cue_sheet *sheet, unsigned char ctladr,
return 1; return 1;
} }
/* ts B11226 */
static int add_catalog_cue(struct cue_sheet *sheet, unsigned char catalog[13])
{
unsigned char *unit;
int i, ret;
ret = new_cue(sheet, 2, 0);
if (ret <= 0)
return -1;
unit = sheet->data + (sheet->count - 2) * 8;
unit[0] = unit[8] = 0x02;
for (i = 0; i < 13; i++)
unit[1 + (i >= 7) * 8 + (i % 7)] = catalog[i];
unit[15] = 0x00;
return 1;
}
/* ts B11226 */
static int add_isrc_cue(struct cue_sheet *sheet, unsigned char ctladr, int tno,
struct isrc *isrc)
{
unsigned char *unit;
int i, ret;
char text[8];
ret = new_cue(sheet, 2, 0);
if (ret <= 0)
return -1;
unit = sheet->data + (sheet->count - 2) * 8;
unit[0] = unit[8] = (ctladr & 0xf0) | 0x03;
unit[1] = unit[9] = tno;
unit[2] = isrc->country[0];
unit[3] = isrc->country[1];
unit[4] = isrc->owner[0];
unit[5] = isrc->owner[1];
unit[6] = isrc->owner[2];
sprintf(text, "%-2.2u%-5.5u", (unsigned int) isrc->year, isrc->serial);
unit[7] = text[0];
for (i = 1; i < 7; i++)
unit[9 + i] = text[i];
return 1;
}
/* ts A61114: added parameter nwa */ /* ts A61114: added parameter nwa */
struct cue_sheet *burn_create_toc_entries(struct burn_write_opts *o, struct cue_sheet *burn_create_toc_entries(struct burn_write_opts *o,
struct burn_session *session, struct burn_session *session,
int nwa) int nwa)
{ {
int i, m, s, f, form, pform, runtime = -150, ret, track_length; int i, m, s, f, form, pform, runtime = -150, ret, track_length;
int leadin_form; int leadin_form, leadin_start;
unsigned char ctladr; unsigned char ctladr;
struct burn_drive *d; struct burn_drive *d;
struct burn_toc_entry *e; struct burn_toc_entry *e;
@ -377,6 +460,7 @@ struct cue_sheet *burn_create_toc_entries(struct burn_write_opts *o,
int ntr = session->tracks; int ntr = session->tracks;
int rem = 0; int rem = 0;
d = o->drive; d = o->drive;
#ifdef Libburn_sao_can_appenD #ifdef Libburn_sao_can_appenD
@ -422,13 +506,28 @@ struct cue_sheet *burn_create_toc_entries(struct burn_write_opts *o,
leadin_form = 0x41; leadin_form = 0x41;
} }
} }
ret = add_cue(sheet, ctladr | 1, 0, 0, leadin_form, 0, runtime);
if (o->has_mediacatalog)
ret = add_catalog_cue(sheet, o->mediacatalog);
else if (session->mediacatalog[0])
ret = add_catalog_cue(sheet, session->mediacatalog);
else
ret = 1;
if (ret <= 0) if (ret <= 0)
goto failed; goto failed;
ret = add_cue(sheet, ctladr | 1, 1, 0, form, 0, runtime);
/* ts B11225
MMC-5 6.33.3.15 Data Form of Sub-channel
seems to indicate that for leadin_form 0x41 one should announce
d->start_lba as start of the leadin (e.g. -12490) and that data
block type should 2 or 3 with mode page 05h. But my drives refuse
on that.
It works with LBA -150 and data block type 0. Shrug.
*/
leadin_start = runtime;
ret = add_cue(sheet, ctladr | 1, 0, 0, leadin_form, 0, leadin_start);
if (ret <= 0) if (ret <= 0)
goto failed; goto failed;
runtime += 150;
d->toc_entries = ntr + 3; d->toc_entries = ntr + 3;
@ -483,6 +582,20 @@ struct cue_sheet *burn_create_toc_entries(struct burn_write_opts *o,
for (i = 0; i < ntr; i++) { for (i = 0; i < ntr; i++) {
type_to_form(tar[i]->mode, &ctladr, &form); type_to_form(tar[i]->mode, &ctladr, &form);
if (tar[i]->isrc.has_isrc) {
ret = add_isrc_cue(sheet, ctladr, i + 1,
&(tar[i]->isrc));
if (ret <= 0)
goto failed;
}
if (i == 0) {
ret = add_cue(sheet, ctladr | 1, 1, 0, form, 0,
runtime);
if (ret <= 0)
goto failed;
runtime += 150;
}
/* ts A70121 : This seems to be thw wrong test. Correct would /* ts A70121 : This seems to be thw wrong test. Correct would
be to compare tar[]->mode or bit2 of ctladr. be to compare tar[]->mode or bit2 of ctladr.
@ -705,9 +818,9 @@ static int burn_write_leadin_cdtext(struct burn_write_opts *o,
{ret = 1; goto ex;} {ret = 1; goto ex;}
/* Try to create CD-TEXT from .cdtext_* of session and track */ /* Try to create CD-TEXT from .cdtext_* of session and track */
ret = burn_create_text_packs(o, s, 0); ret = burn_create_text_packs(o, s, 0);
self_made_text_packs = 1;
if (ret <= 0) if (ret <= 0)
goto ex; goto ex;
self_made_text_packs = 1;
if (o->num_text_packs <= 0) if (o->num_text_packs <= 0)
{ret = 1; goto ex;} {ret = 1; goto ex;}
} }
@ -2673,7 +2786,6 @@ return crap. so we send the command, then ignore the result.
if (o->write_type == BURN_WRITE_TAO) { if (o->write_type == BURN_WRITE_TAO) {
nwa = 0; /* get_nwa() will be called in burn_track() */ nwa = 0; /* get_nwa() will be called in burn_track() */
} else { } else {
d->send_write_parameters(d, o); d->send_write_parameters(d, o);
ret = d->get_nwa(d, -1, &lba, &nwa); ret = d->get_nwa(d, -1, &lba, &nwa);
@ -2701,7 +2813,11 @@ return crap. so we send the command, then ignore the result.
if (sheet == NULL) if (sheet == NULL)
goto fail; goto fail;
/* print_cue(sheet);*/ #ifdef Libburn_write_with_function_print_cuE
print_cue(sheet);
/* goto fail_wo_sync; */
#endif /* Libburn_write_with_function_print_cuE */
if (o->write_type == BURN_WRITE_SAO) if (o->write_type == BURN_WRITE_SAO)
d->send_cue_sheet(d, sheet); d->send_cue_sheet(d, sheet);
if (sheet->data != NULL) if (sheet->data != NULL)