From cdaa2971dbd829159a8e09c03ec001acefb28388 Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Tue, 27 Dec 2011 13:38:39 +0000 Subject: [PATCH] Writing CATALOG and ISRC into Q sub-channel of CD SAO sessions --- cdrskin/cdrskin.1 | 6 +- cdrskin/cdrskin_timestamp.h | 2 +- doc/cookbook.txt | 28 +++++- libburn/cdtext.c | 23 ++++- libburn/write.c | 174 ++++++++++++++++++++++++++++++------ 5 files changed, 193 insertions(+), 40 deletions(-) diff --git a/cdrskin/cdrskin.1 b/cdrskin/cdrskin.1 index 18f37b2..186c929 100644 --- a/cdrskin/cdrskin.1 +++ b/cdrskin/cdrskin.1 @@ -2,7 +2,7 @@ .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" 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. .\" .\" Some roff macros, for reference: @@ -506,9 +506,7 @@ present. .br cdrskin currently supports TRACK datatypes AUDIO and MODE1/2048 which may 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 -the Q sub-channel of the program area. Data source may be of FILE type BINARY -or MOTOROLA. +is interpreted yet. Data source may be of FILE type BINARY or MOTOROLA. .TP .BI \-dao Alias for option -sao. Write CD in Session at Once mode diff --git a/cdrskin/cdrskin_timestamp.h b/cdrskin/cdrskin_timestamp.h index b3d48b6..f42286f 100644 --- a/cdrskin/cdrskin_timestamp.h +++ b/cdrskin/cdrskin_timestamp.h @@ -1 +1 @@ -#define Cdrskin_timestamP "2011.12.27.115645" +#define Cdrskin_timestamP "2011.12.27.133733" diff --git a/doc/cookbook.txt b/doc/cookbook.txt index b2c9e71..e619221 100644 --- a/doc/cookbook.txt +++ b/doc/cookbook.txt @@ -225,7 +225,7 @@ sync. libburn uses the info provided by 52h READ TRACK INFORMATION. Guided by reading libburn/* from http://icculus.org/burn 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, - Optiarc BD RW BD-5300S, + Optiarc BD RW BD-5300S, LG BDDVDRW GGC-H20L For libburnia-project.org by Thomas Schmitt @@ -264,7 +264,8 @@ CTL|ADR, TNO, INDEX, DATA FORM, SCMS, MIN, SEC, FRAME . CTL is 40h for data and 00h for audio. (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). INDEX is a subaddress within tracks. This recipe uses only INDEX 01h within 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. 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) 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. 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. + +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: (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 -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 (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) Data Block Type Layout of payload blocks 0 (is ignored) Audio Pause Length 150 = 2 seconds (ignored ?) + +>>> CATALOG +>>> no ISRC with SAO + Any other parameters may be set to 0. 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. diff --git a/libburn/cdtext.c b/libburn/cdtext.c index d7f1c2f..6f2e16d 100755 --- a/libburn/cdtext.c +++ b/libburn/cdtext.c @@ -620,6 +620,9 @@ static int v07t_cdtext_to_track(struct burn_track *track, int block, /* 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, char *path, int block, int flag) { @@ -802,6 +805,10 @@ cannot_open:; &int0x01, 0, "UPC_ISRC", 0); if (ret <= 0) goto ex; + if (!(flag & 2)) { + memcpy(session->mediacatalog, payload, 13); + session->mediacatalog[13] = 0; + } session_attr_seen[0xe] = 1; } else if (strncmp(line, "Disc Information ", 17) == 0) { @@ -928,9 +935,15 @@ bad_track_no:; strcmp(line + 9, "Message") == 0) pack_type = 0x85; else if (strcmp(line + 9, "0x8e") == 0 || - strcmp(line + 9, "ISRC") == 0) + strcmp(line + 9, "ISRC") == 0) { 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, "Unknown v07t Track purpose specifier '%s'", line + 9); @@ -958,6 +971,12 @@ bad_track_no:; goto bad_track_no; } 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, &int0x00, 0x8e, "", 0); if (ret <= 0) diff --git a/libburn/write.c b/libburn/write.c index 56034cf..c303fc6 100644 --- a/libburn/write.c +++ b/libburn/write.c @@ -272,7 +272,6 @@ int burn_write_close_track(struct burn_write_opts *o, struct burn_session *s, } - /* ts A61030 */ 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: This is unused since about Feb 2006, icculus.org/burn CVS. The compiler complains. We shall please our compiler. + # define 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) { int i; unsigned char *unit; printf("\n"); - printf("ctladr|trno|indx|form|scms| msf\n"); - printf("------+----+----+----+----+--------\n"); + printf("ctladr|trno|indx|form|scms| msf | text\n"); + printf("------+----+----+----+----+----------+--------\n"); for (i = 0; i < sheet->count; i++) { unit = sheet->data + 8 * i; - printf(" %1X %1X | %02X | %02X | %02X | %02X |", - (unit[0] & 0xf0) >> 4, unit[0] & 0xf, unit[1], unit[2], - unit[3], unit[4]); - printf("%02X:%02X:%02X\n", unit[5], unit[6], unit[7]); + 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 |", + (unit[0] & 0xf0) >> 4, unit[0] & 0xf, + unit[1], unit[2], unit[3], unit[4]); + printf(" %02X:%02X:%02X |\n", + unit[5], unit[6], unit[7]); + } } + fflush(stdout); } #endif /* Libburn_write_with_print_cuE */ -/* ts A61009 : changed type from void to int */ -/** @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) +/* ts B11226 */ +static int new_cue(struct cue_sheet *sheet, int number, int flag) { - unsigned char *unit; unsigned char *ptr; - int m, s, f; - burn_lba_to_msf(lba, &m, &s, &f); - - sheet->count++; - ptr = realloc(sheet->data, sheet->count * 8); - - /* ts A61009 */ - /* a ssert(ptr); */ + ptr = realloc(sheet->data, (sheet->count + number) * 8); if (ptr == NULL) { libdax_msgs_submit(libdax_messenger, -1, 0x00020111, 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); return -1; } - 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[0] = ctladr; unit[1] = tno; @@ -362,13 +399,59 @@ static int add_cue(struct cue_sheet *sheet, unsigned char ctladr, 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 */ struct cue_sheet *burn_create_toc_entries(struct burn_write_opts *o, struct burn_session *session, int nwa) { int i, m, s, f, form, pform, runtime = -150, ret, track_length; - int leadin_form; + int leadin_form, leadin_start; unsigned char ctladr; struct burn_drive *d; 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 rem = 0; + d = o->drive; #ifdef Libburn_sao_can_appenD @@ -422,13 +506,28 @@ struct cue_sheet *burn_create_toc_entries(struct burn_write_opts *o, 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) 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) goto failed; - runtime += 150; 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++) { 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 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;} /* Try to create CD-TEXT from .cdtext_* of session and track */ ret = burn_create_text_packs(o, s, 0); + self_made_text_packs = 1; if (ret <= 0) goto ex; - self_made_text_packs = 1; if (o->num_text_packs <= 0) {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) { nwa = 0; /* get_nwa() will be called in burn_track() */ } else { - d->send_write_parameters(d, o); 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) 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) d->send_cue_sheet(d, sheet); if (sheet->data != NULL)