New API call burn_write_opts_set_leadin_text()

This commit is contained in:
Thomas Schmitt 2011-12-05 20:36:31 +00:00
parent b385a3863e
commit 7be652ac6b
9 changed files with 281 additions and 19 deletions

View File

@ -1 +1 @@
#define Cdrskin_timestamP "2011.12.03.113345"
#define Cdrskin_timestamP "2011.12.05.203600"

View File

@ -20,6 +20,7 @@ Content:
Guided by reading mmc-r10a.pdf , O.8 "Write a Track"
from http://www.t10.org/ftp/t10/drafts/mmc/
backed by reading mmc5r03c.pdf from http://www.t10.org/ftp/t10/drafts/mmc5/
by reading mmc3r10g.pdf from http://www.t10.org/ftp/t10/drafts/mmc3/
by reading spc3r23.pdf from http://www.t10.org/ftp/t10/drafts/spc3/
by reading libburn/* from http://icculus.org/burn
and by experiments with drives NEC ND-4570A, LG GSA-4082B, LITE-ON LTR48125S
@ -193,7 +194,9 @@ If POINT is >= 1 and <= 99 (63h) then the descriptor is about the track of
which POINT tells the number.
The start address of this track can be read from PMIN, PSEC, PFRAME where
it is encoded in MSF format:
blocks = frames - 150, 75 frames = 1 sec , 60 sec = 1 min.
If M is smaller than 90: LBA = (M * 60 + S) * 75 + F - 150
Else : LBA = (M * 60 + S) * 75 + F - 450150
The length of the track is given by MIN,SEC,FRAME in the same format.
If POINT = A0h then the descriptor tells in PMIN the first track number of its
@ -267,8 +270,8 @@ TNO is the track number (1 to 99).
INDEX is a subaddress within tracks. This recipe uses only INDEX 01h within
tracks.
(mmc5r03c.pdf 4.2.3.5.2)
DATA FORM is 00h for audio payload , 10h for data. (01h for audio pause is not
used in libburn).
DATA FORM is 00h for audio payload, 01h for audio pause, 10h for data,
41h for CD-TEXT in Lead-in.
(mmc5r03c.pdf 6.33.3.11 CD-DA Data Form, 6.33.3.12 CD-ROM mode 1 Form)
SCMS is always 00h.
MIN, SEC, FRAME give the MSF address where the described data entity starts.
@ -277,8 +280,9 @@ This address must increase from entry to entry (or at least stay equal).
The first entry describes the Lead-in. Its content is
(CTL|ADR ,00h,00h,01h,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.
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.
@ -312,6 +316,12 @@ next lower possible value by the drive. So it is helpful to add a few
kbytes/sec just in case the drive has rounding problems.
(mmc5r03c.pdf 6.37)
If CD-TEXT shall be written into Lead-in, then it is necessary to obtain the
Start Time of Lead-in by 43h READ TOC/PMA/ATIP Format 0100b. It is an MFS
address which varies from media manufacturer to media manufacturer.
Minute will be >= 90. Therefore this conversion applies:
LBA = (M * 60 + S) * 75 + F - 450150
A Write Parameters mode page 05h has to be composed and transmitted via
55h MODE SELECT. This page describes the following parameters:
BUFE Buffer Underrun protection 0=off, 1=on
@ -338,15 +348,31 @@ blocks written. I.e the Transfer Length of the previous 2Ah WRITE has to be
added to the Logical Block Address for the next 2Ah WRITE. Only full blocks
can be written.
(mmc5r03c.pdf, 6.44)
Writing begins at LBA -150 which is to be transmitted as 4-byte, Big-endian,
two's-complement. E.g: -150 = FFh FFh FFh 6Ah. This is the natural form found
with about any 32-bit processor, so only the endianness has to be taken into
respect when converting a 32-bit integer into a LBA for command 2Ah WRITE.
Block addresses may be negative for areas before the normally readable
data. Data representation of addresses is 4-byte, big-endian, two's-complement.
E.g: -150 = FFh FFh FFh 6Ah.
This is the natural form found with about any 32-bit processor, so only
the endianness has to be taken into respect when converting a 32-bit
integer into a LBA for command 2Ah WRITE.
If CD-TEXT shall be written into Lead-in, then writing begins at the start
address of Lead-in, which was obtained above.
The 18 bytes of each text pack have to be split up to 24 bytes with only the
lowest six bits used in each byte. E.g. text pack
8F 00 2A 00 01 01 03 00 06 05 04 05 07 06 01 02 48 65
becomes
23 30 00 2A 00 00 04 01 00 30 00 06 01 10 10 05 01 30 18 01 00 24 21 25
4 of these 24 byte packs form a block of DATA FORM 41h. I.e. only 96 bytes
payload per block. The whole range from Lead-in start to LBA -150 has to be
filled with blocks of this form. Therefore it is necessary to write the
list of given packs in repeated cycles.
A typical Lead-in start address is -11635 = FFh FFh D2h 8Dh.
At first the mandatory pause preceding the first track has to be written as
150 blocks of the matching sector size: 2048 for data, 2352 for audio.
By this, the LBA increases from -150 to 0.
Writing without CD-TEXT begins at LBA -150 = FFh FFh FFh 6Ah.
In both cases, the mandatory pause preceding the first track has to be
written as 150 blocks of the matching sector size: 2048 for data,
2352 for audio. By this, the LBA increases from -150 to 0.
Next the tracks' payload is sent. For each track exactly the number of blocks
has to be transmitted as is announced in the Cue Sheet by the difference
@ -370,6 +396,58 @@ to media by 35h SYNCHRONIZE CACHE.
No further finalization is necessary. (I.e. no 5Bh CLOSE TRACK SESSION.)
-------------------------------------------------------------------------------
Obtaining CD-TEXT from Lead-in :
Audio CDs may contain CD-TEXT information in their Lead-in. It is gained by
43h READ TOC/PMA/ATIP, Format 0101b. The reply consists of 4 bytes header,
of which the first two bytes give the number of following bytes as big-endian
16 bit number. The other two bytes are 0.
Following are text packs of 18 bytes each.
(mmc5r03c.pdf 6.26.3.7.1 table 495)
The format of a text pack is explained in (mmc3r10g.pdf, appendix J).
Each pack of a 4-bytes are header, 12 byte pieces of 0-terminated texts
or binary data, and 2 bytes of CRC.
The first byte of each pack tells the pack type (text meaning):
0x80 = Title
0x81 = Names of performers
0x82 = Songwriters
0x83 = Composers,
0x84 = Arrangers
0x85 = Messages
0x86 = text-and-binary: Disc Identification
0x87 = text-and-binary: Genre Identification
0x88 = binary: Table of Content information
0x89 = binary: Second Table of Content information
0x8e = UPC/EAN code of the album and ISRC code of each track
0x8f = binary: Size Information of the Block
The second byte tells the track number to which the first text piece in
a pack is associated. Number 0 means the whole album. Higher numbers are
valid for types 0x80 to 0x85, and 0x8e. With these types, there should be
one text for the disc and one for each track.
The third byte is a sequential counter.
The fourth byte is the Block Number and Character Position Indicator.
It consists of three bit fields:
bit7 = Double Bytes Character Code (0= single byte characters)
bit4-6 = Block Number (groups text packs in language blocks)
bit0-3 = Character position. Either the number of characters which
the current text inherited from the previous pack, or
15 if the current text started before the previous pack.
A text may span over several packs. Unused characters in a pack are used for
the next text of the same pack type. If no text of the same type follows,
then the remaining text bytes are set to 0.
The CRC algorithm is known as CRC-16-CCITT with divisor 0x11021.
MMC-3 says: "All bits shall be inverted."
----------------------------------------------------------------------------
What is known about mixed mode sessions :

View File

@ -1310,8 +1310,8 @@ int burn_disc_get_cd_info(struct burn_drive *d, char disc_type[80],
0x8f = binary: Size Information of the Block
The second byte tells the track number to which the first text piece in
a pack is associated. Number 0 means the whole album. Higher numbers are
valid for types 0x80 to 0x85, and 0x8e. There should be one text for each
track with these types.
valid for types 0x80 to 0x85, and 0x8e. With these types, there should be
one text for the disc and one for each track.
The third byte is a sequential counter.
The fourth byte is the Block Number and Character Position Indicator.
It consists of three bit fields:
@ -1321,13 +1321,14 @@ int burn_disc_get_cd_info(struct burn_drive *d, char disc_type[80],
the current text inherited from the previous pack, or
15 if the current text started before the previous pack.
The two CRC bytes are optional. Polynomial is x^16 + x^12 + x^5 + 1.
"All bits shall be inverted."
@param d The drive to query.
@param text_packs Will point to an allocated memory buffer with CD-TEXT.
It will only contain text packs, and not be prepended
by the TOC header of four bytes, which gets stored with
file cdtext.dat by cdrecord -vv -toc. The first two of
these bytes are supposed hold the number of CD-TEXT
these bytes are supposed to hold the number of CD-TEXT
bytes + 2. The other two bytes are supposed to be 0.
Dispose this buffer by free(), when no longer needed.
@param num_packs Will tell the number of text packs, i.e. the number of
@ -2431,6 +2432,23 @@ void burn_write_opts_set_mediacatalog(struct burn_write_opts *opts, unsigned cha
*/
void burn_write_opts_set_multi(struct burn_write_opts *opts, int multi);
/* ts B11204 */
/** Submit an array of CD-TEXT packs which shall be written to the Lead-in
of a SAO write run on CD.
@param opts The option object to be manipulated
@param text_packs Array of bytes which form CD-TEXT packs of 18 bytes
each. See burn_disc_get_leadin_text() for a description
of the text pack format.
No header of 4 bytes must be prepended which would
tell the number of pack bytes + 2.
@param num_packs The number of 18 byte packs in text_packs.
@param flag Bitfield for control purposes. Unused yet. Submit 0.
@return 1 on success, <= 0 on failure
@since 1.2.0
*/
int burn_write_opts_set_leadin_text(struct burn_write_opts *opts,
unsigned char *text_packs,
int num_packs, int flag);
/* ts A61222 */
/** Sets a start address for writing to media and write modes which allow to

View File

@ -154,6 +154,7 @@ burn_write_opts_set_fillup;
burn_write_opts_set_force;
burn_write_opts_set_format;
burn_write_opts_set_has_mediacatalog;
burn_write_opts_set_leadin_text;
burn_write_opts_set_mediacatalog;
burn_write_opts_set_multi;
burn_write_opts_set_perform_opc;

View File

@ -577,6 +577,7 @@ Range "scdbackup" : 0x00020000 to 0x0002ffff
0x00020188 (FAILURE,HIGH) = Cannot close damaged track on given media type
0x00020189 (FATAL,HIGH) = Drive is already grabbed by libburn
0x0002018a (SORRY,HIGH) = Timeout exceeded. Retry cancled.
0x0002018b (FAILURE,HIGH) = Too many CD-TEXT packs
libdax_audioxtr:
0x00020200 (SORRY,HIGH) = Cannot open audio source file

View File

@ -945,7 +945,7 @@ int mmc_write(struct burn_drive *d, int start, struct buffer *buf)
#ifdef Libburn_log_in_and_out_streaM
/* <<< ts A61031 */
if(tee_fd!=-1) {
write(tee_fd,c->page->data,len*2048);
write(tee_fd, c->page->data, c->page->bytes);
}
#endif /* Libburn_log_in_and_out_streaM */

View File

@ -12,6 +12,7 @@
#include "options.h"
#include "drive.h"
#include "transport.h"
#include "init.h"
/* ts A61007 */
/* #include <a ssert.h> */
@ -51,6 +52,8 @@ struct burn_write_opts *burn_write_opts_new(struct burn_drive *drive)
opts->do_stream_recording = 0;
opts->dvd_obs_override = 0;
opts->stdio_fsync_size = Libburn_stdio_fsync_limiT;
opts->text_packs = NULL;
opts->num_text_packs = 0;
opts->has_mediacatalog = 0;
opts->format = BURN_CDROM;
opts->multi = 0;
@ -60,8 +63,11 @@ struct burn_write_opts *burn_write_opts_new(struct burn_drive *drive)
void burn_write_opts_free(struct burn_write_opts *opts)
{
if (--opts->refcount <= 0)
free(opts);
if (--opts->refcount > 0)
return;
if (opts->text_packs != NULL)
free(opts->text_packs);
free(opts);
}
struct burn_read_opts *burn_read_opts_new(struct burn_drive *drive)
@ -189,6 +195,41 @@ void burn_write_opts_set_multi(struct burn_write_opts *opts, int multi)
}
/* ts B11204 */
int burn_write_opts_set_leadin_text(struct burn_write_opts *opts,
unsigned char *text_packs,
int num_packs, int flag)
{
int ret;
unsigned char *pack_buffer = NULL;
if (num_packs > 3640) {
/* READ TOC/PMA/ATIP can at most return 3640.7 packs */
libdax_msgs_submit(libdax_messenger, opts->drive->global_index,
0x0002018b,
LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
"Too many CD-TEXT packs (> 3640)", 0, 0);
ret= 0; goto ex;
}
if (num_packs > 0)
BURN_ALLOC_MEM(pack_buffer, unsigned char, num_packs * 18);
if (opts->text_packs != NULL) {
free(opts->text_packs);
opts->text_packs = NULL;
}
if (num_packs > 0) {
memcpy(pack_buffer, text_packs, num_packs * 18);
opts->text_packs = pack_buffer;
}
opts->num_text_packs = num_packs;
ret = 1;
ex:;
return ret;
}
/* ts A61222 */
void burn_write_opts_set_start_byte(struct burn_write_opts *opts, off_t value)
{
@ -296,6 +337,10 @@ do_sao:;
{wt = BURN_WRITE_SAO; goto ex;}
no_sao:;
try_tao:;
if (opts->num_text_packs > 0) {
strcat(reasons, "CD-TEXT: write type SAO required, ");
{wt = BURN_WRITE_NONE; goto ex;}
}
if ((flag & 1) && opts->write_type != BURN_WRITE_TAO)
goto try_raw;
reason_pt = reasons + strlen(reasons);

View File

@ -69,6 +69,9 @@ struct burn_write_opts
Values 0 or >= 32 counted in 2 KB blocks. */
int stdio_fsync_size;
/* ts B11203 : CD-TEXT */
unsigned char *text_packs;
int num_text_packs;
/** A disc can have a media catalog number */
int has_mediacatalog;

View File

@ -368,6 +368,7 @@ struct cue_sheet *burn_create_toc_entries(struct burn_write_opts *o,
int nwa)
{
int i, m, s, f, form, pform, runtime = -150, ret, track_length;
int leadin_form;
unsigned char ctladr;
struct burn_drive *d;
struct burn_toc_entry *e;
@ -404,7 +405,11 @@ struct cue_sheet *burn_create_toc_entries(struct burn_write_opts *o,
"Track mode has unusable value", 0, 0);
goto failed;
}
ret = add_cue(sheet, ctladr | 1, 0, 0, 1, 0, runtime);
if (o->num_text_packs > 0)
leadin_form = 0x41;
else
leadin_form = 0x01;
ret = add_cue(sheet, ctladr | 1, 0, 0, leadin_form, 0, runtime);
if (ret <= 0)
goto failed;
ret = add_cue(sheet, ctladr | 1, 1, 0, form, 0, runtime);
@ -650,11 +655,110 @@ int burn_write_leadout(struct burn_write_opts *o,
return 1;
}
int burn_write_leadin_cdtext(struct burn_write_opts *o, struct burn_session *s,
int flag)
{
int ret, i, j, si, lba, sub_cursor = 0, err, write_lba, sectors = 0;
unsigned char *subdata = NULL;
struct burn_drive *d = o->drive;
struct buffer *buf = NULL;
enum burn_drive_status was_busy;
#ifdef Libburn_debug_cd_texT
unsigned char *packs;
#endif
if (o->num_text_packs <= 0)
{ret = 1; goto ex;}
was_busy = d->busy;
d->busy = BURN_DRIVE_WRITING_LEADIN;
#ifdef Libburn_debug_cd_texT
packs = o->text_packs;
fprintf(stderr,
"libburn_DEBUG: 8 bit CD-TEXT packs to be transmitted:\n");
for (i = 0; i < 18 * o->num_text_packs; i += 18) {
fprintf(stderr, "%4d :", i / 18);
for (j = 0; j < 18; j++) {
if (j >= 4 && j <= 15 && packs[i + j] >= 32 &&
packs[i + j] <= 126 && packs[i] != 0x88 &&
packs[i] != 0x89 && packs[i] != 0x8f)
fprintf(stderr, " %c", packs[i + j]);
else
fprintf(stderr, " %2.2X", packs[i + j]);
}
fprintf(stderr, "\n");
}
#endif /* Libburn_debug_cd_texT */
/* Chop from 8 bit text pack to 6 bit subchannel */
BURN_ALLOC_MEM(subdata, unsigned char, o->num_text_packs * 24);
for (i = 0; i < 18 * o->num_text_packs; i += 3) {
si = i / 3 * 4;
subdata[si + 0] = (o->text_packs[i + 0] >> 2) & 0x3f;
subdata[si + 1] = (o->text_packs[i + 0] << 4) & 0x30;
subdata[si + 1] |= (o->text_packs[i + 1] >> 4) & 0x0f;
subdata[si + 2] = (o->text_packs[i + 1] << 2) & 0x3c;
subdata[si + 2] |= (o->text_packs[i + 2] >> 6) & 0x03;
subdata[si + 3] = (o->text_packs[i + 2] >> 0) & 0x3f;
}
/* Start at Lead-in address of ATIP and write blocks up to -150 */
BURN_ALLOC_MEM(buf, struct buffer, 1);
write_lba = d->start_lba;
for (lba = d->start_lba; lba < -150; lba++) {
/* Collect subdata in buf */
for (j = 0; j < 4; j++) {
memcpy(buf->data + buf->bytes,
subdata + sub_cursor * 24, 24);
sub_cursor = (sub_cursor + 1) % o->num_text_packs;
buf->bytes += 24;
}
buf->sectors++;
sectors++;
/* When full or last sector : perform WRITE */
if (buf->bytes + 96 >= 32768 || lba == -151) {
#ifdef Libburn_debug_cd_texT
fprintf(stderr,
"libburn_DEBUG: 6 bit data to be transmitted:\n");
for (i = 0; i < buf->bytes; i += 24) {
fprintf(stderr, "%4d :", i / 24);
for (j = 0; j < 24; j++)
fprintf(stderr, " %2.2X",
buf->data[i + j]);
fprintf(stderr, "\n");
}
#endif /* Libburn_debug_cd_texT */
err = d->write(d, write_lba, buf);
if (err == BE_CANCELLED)
{ ret = 0; goto ex; }
write_lba += sectors;
sectors = buf->sectors = buf->bytes = 0;
}
}
ret = 1;
ex:;
BURN_FREE_MEM(subdata);
BURN_FREE_MEM(buf);
d->busy = was_busy;
return ret;
}
int burn_write_session(struct burn_write_opts *o, struct burn_session *s)
{
struct burn_drive *d = o->drive;
int i, ret;
if (o->write_type == BURN_WRITE_SAO) {
ret = burn_write_leadin_cdtext(o, s, 0);
if (ret <= 0)
goto ex;
}
d->rlba = 0;
for (i = 0; i < s->tracks; i++) {
if (!burn_write_track(o, s, i))
@ -1001,6 +1105,10 @@ int burn_precheck_write(struct burn_write_opts *o, struct burn_disc *disc,
reason_pt= reasons + strlen(reasons);
if (d->status == BURN_DISC_UNSUITABLE)
goto unsuitable_profile;
if (d->current_profile != 0x09 && d->current_profile != 0x0a)
if (o->num_text_packs > 0)
strcat(reasons,
"CD-TEXT supported only with write CD media, ");
if (d->drive_role == 2 || d->drive_role == 5 ||
d->current_profile == 0x1a || d->current_profile == 0x12 ||
d->current_profile == 0x43) {
@ -1014,6 +1122,14 @@ int burn_precheck_write(struct burn_write_opts *o, struct burn_disc *disc,
strcat(reasons, "unsuitable track mode found, ");
if (o->start_byte >= 0)
strcat(reasons, "write start address not supported, ");
if (o->num_text_packs > 0) {
if (o->write_type != BURN_WRITE_SAO)
strcat(reasons,
"CD-TEXT supported only with write type SAO, ");
if (d->start_lba == -2000000000)
strcat(reasons,
"No Lead-in start address known with CD-TEXT, ");
}
} else if (d->current_profile == 0x13) {
/* DVD-RW Restricted Overwrite */
if (o->start_byte >= 0 && (o->start_byte % 32768))