1 /*
2 Copyright (C) 2018, Rocky Bernstein <rocky@gnu.org>
3 Copyright (C) 2000, 2004-2005 Herbert Valerio Riedel <hvr@gnu.org>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <ctype.h>
28 #include <math.h>
29
30 #define _VCD_INFO_PRIVATE_H
31 /* We don't want to pull in cdio's config */
32 #define __CDIO_CONFIG_H__
33 #include <cdio/cdio.h>
34 #include <cdio/util.h>
35 #include <cdio/iso9660.h>
36
37 /* public headers */
38 #include <libvcd/types.h>
39 #include <libvcd/info.h>
40
41 #include <libvcd/files.h>
42 #include <libvcd/sector.h>
43 #include <libvcd/logging.h>
44
45 /* Private headers */
46 #include "assert.h"
47 #include "dict.h"
48 #include "directory.h"
49 #include "obj.h"
50 #include "pbc.h"
51 #include "salloc.h"
52 #include "util.h"
53 #include "vcd.h"
54
55 static const char zero[CDIO_CD_FRAMESIZE_RAW] = { 0, };
56
57 #define DEFAULT_ISO_PREPARER_ID "GNU VCDImager " VERSION " " HOST_ARCH
58
sequence_free(mpeg_sequence_t * data)59 static void sequence_free(mpeg_sequence_t *data)
60 {
61 if (data != NULL) free(data);
62 }
63
dict_free(struct _dict_t * data)64 static void dict_free(struct _dict_t *data)
65 {
66 if (data != NULL) free(data);
67 }
68
cue_data_free(vcd_cue_t * data)69 static void cue_data_free(vcd_cue_t *data)
70 {
71 if (data != NULL) free(data);
72 }
73
74
75 /* exported private functions
76 */
77
78 mpeg_sequence_t *
_vcd_obj_get_sequence_by_id(VcdObj_t * p_obj,const char sequence_id[])79 _vcd_obj_get_sequence_by_id (VcdObj_t *p_obj, const char sequence_id[])
80 {
81 CdioListNode_t *node;
82
83 vcd_assert (sequence_id != NULL);
84 vcd_assert (p_obj != NULL);
85
86 _CDIO_LIST_FOREACH (node, p_obj->mpeg_sequence_list)
87 {
88 mpeg_sequence_t *_sequence = _cdio_list_node_data (node);
89
90 if (_sequence->id && !strcmp (sequence_id, _sequence->id))
91 return _sequence;
92 }
93
94 return NULL;
95 }
96
97 mpeg_sequence_t *
_vcd_obj_get_sequence_by_entry_id(VcdObj_t * p_obj,const char entry_id[])98 _vcd_obj_get_sequence_by_entry_id (VcdObj_t *p_obj, const char entry_id[])
99 {
100 CdioListNode_t *node;
101
102 vcd_assert (entry_id != NULL);
103 vcd_assert (p_obj != NULL);
104
105 _CDIO_LIST_FOREACH (node, p_obj->mpeg_sequence_list)
106 {
107 mpeg_sequence_t *_sequence = _cdio_list_node_data (node);
108 CdioListNode_t *node2;
109
110 /* default entry point */
111 if (_sequence->default_entry_id
112 && !strcmp (entry_id, _sequence->default_entry_id))
113 return _sequence;
114
115 /* additional entry points */
116 _CDIO_LIST_FOREACH (node2, _sequence->entry_list)
117 {
118 entry_t *_entry = _cdio_list_node_data (node2);
119
120 if (_entry->id
121 && !strcmp (entry_id, _entry->id))
122 return _sequence;
123 }
124 }
125
126 /* not found */
127
128 return NULL;
129 }
130
131 mpeg_segment_t *
_vcd_obj_get_segment_by_id(VcdObj_t * p_obj,const char segment_id[])132 _vcd_obj_get_segment_by_id (VcdObj_t *p_obj, const char segment_id[])
133 {
134 CdioListNode_t *node;
135
136 vcd_assert (segment_id != NULL);
137 vcd_assert (p_obj != NULL);
138
139 _CDIO_LIST_FOREACH (node, p_obj->mpeg_segment_list)
140 {
141 mpeg_segment_t *_segment = _cdio_list_node_data (node);
142
143 if (_segment->id && !strcmp (segment_id, _segment->id))
144 return _segment;
145 }
146
147 return NULL;
148 }
149
150 bool
_vcd_obj_has_cap_p(const VcdObj_t * p_obj,enum vcd_capability_t capability)151 _vcd_obj_has_cap_p (const VcdObj_t *p_obj, enum vcd_capability_t capability)
152 {
153 switch (capability)
154 {
155 case _CAP_VALID:
156 switch (p_obj->type)
157 {
158 case VCD_TYPE_VCD:
159 case VCD_TYPE_VCD11:
160 case VCD_TYPE_VCD2:
161 case VCD_TYPE_SVCD:
162 case VCD_TYPE_HQVCD:
163 return true;
164 break;
165
166 case VCD_TYPE_INVALID:
167 return false;
168 break;
169 }
170 break;
171
172 case _CAP_MPEG2:
173 switch (p_obj->type)
174 {
175 case VCD_TYPE_VCD:
176 case VCD_TYPE_VCD11:
177 case VCD_TYPE_VCD2:
178 case VCD_TYPE_INVALID:
179 return false;
180 break;
181
182 case VCD_TYPE_SVCD:
183 case VCD_TYPE_HQVCD:
184 return true;
185 break;
186 }
187 break;
188
189 case _CAP_PBC:
190 switch (p_obj->type)
191 {
192 case VCD_TYPE_VCD:
193 case VCD_TYPE_VCD11:
194 case VCD_TYPE_INVALID:
195 return false;
196 break;
197
198 case VCD_TYPE_VCD2:
199 case VCD_TYPE_SVCD:
200 case VCD_TYPE_HQVCD:
201 return true;
202 break;
203 }
204 break;
205
206 case _CAP_PBC_X:
207 switch (p_obj->type)
208 {
209 case VCD_TYPE_VCD:
210 case VCD_TYPE_VCD11:
211 case VCD_TYPE_INVALID:
212 case VCD_TYPE_SVCD:
213 case VCD_TYPE_HQVCD:
214 return false;
215 break;
216
217 case VCD_TYPE_VCD2:
218 return true;
219 break;
220 }
221 break;
222
223 case _CAP_4C_SVCD:
224 switch (p_obj->type)
225 {
226 case VCD_TYPE_VCD:
227 case VCD_TYPE_VCD11:
228 case VCD_TYPE_INVALID:
229 case VCD_TYPE_VCD2:
230 return false;
231 break;
232
233 case VCD_TYPE_SVCD:
234 case VCD_TYPE_HQVCD:
235 return true;
236 break;
237 }
238 break;
239
240 case _CAP_PAL_BITS:
241 return _vcd_obj_has_cap_p (p_obj, _CAP_PBC); /* for now */
242 break;
243
244 case _CAP_MPEG1:
245 return !_vcd_obj_has_cap_p (p_obj, _CAP_MPEG2); /* for now */
246 break;
247
248 case _CAP_TRACK_MARGINS:
249 return !_vcd_obj_has_cap_p (p_obj, _CAP_MPEG2); /* for now */
250 break;
251 }
252
253 vcd_assert_not_reached ();
254 return false;
255 }
256
257 /*
258 * public methods
259 */
260
261 VcdObj_t *
vcd_obj_new(vcd_type_t vcd_type)262 vcd_obj_new (vcd_type_t vcd_type)
263 {
264 VcdObj_t *p_new_obj = NULL;
265 static bool _first = true;
266
267 if (_first)
268 {
269 #if defined(_DEVELOPMENT_)
270 vcd_warn ("initializing libvcd %s [%s]", VERSION, HOST_ARCH);
271 vcd_warn (" ");
272 vcd_warn (" this is the Beta development branch!");
273 vcd_warn (" use only if you know what you are doing");
274 vcd_warn (" see http://www.hvrlab.org/~hvr/vcdimager/ for more information");
275 vcd_warn (" ");
276 #else
277 vcd_debug ("initializing libvcd %s [%s]", VERSION, HOST_ARCH);
278 #endif
279 _first = false;
280 }
281
282 p_new_obj = calloc(1, sizeof (VcdObj_t));
283 p_new_obj->type = vcd_type;
284
285 if (!_vcd_obj_has_cap_p (p_new_obj, _CAP_VALID))
286 {
287 vcd_error ("VCD type not supported");
288 free (p_new_obj);
289 return NULL;
290 }
291
292 if (vcd_type == VCD_TYPE_VCD)
293 vcd_warn ("VCD 1.0 support is experimental -- user feedback needed!");
294
295 p_new_obj->iso_volume_label = strdup ("");
296 p_new_obj->iso_publisher_id = strdup ("");
297 p_new_obj->iso_application_id = strdup ("");
298 p_new_obj->iso_preparer_id = _vcd_strdup_upper (DEFAULT_ISO_PREPARER_ID);
299 p_new_obj->info_album_id = strdup ("");
300 p_new_obj->info_volume_count = 1;
301 p_new_obj->info_volume_number = 1;
302
303 p_new_obj->custom_file_list = _cdio_list_new ();
304 p_new_obj->custom_dir_list = _cdio_list_new ();
305
306
307 p_new_obj->mpeg_sequence_list = _cdio_list_new ();
308
309 p_new_obj->mpeg_segment_list = _cdio_list_new ();
310
311 p_new_obj->pbc_list = _cdio_list_new ();
312
313 /* gap's defined by IEC-10149 / ECMA-130 */
314
315 /* pre-gap's for tracks but the first one */
316 p_new_obj->track_pregap = CDIO_PREGAP_SECTORS;
317 /* post-gap after last track */
318 p_new_obj->leadout_pregap = CDIO_POSTGAP_SECTORS;
319
320 if (_vcd_obj_has_cap_p (p_new_obj, _CAP_TRACK_MARGINS))
321 {
322 p_new_obj->track_front_margin = 30;
323 p_new_obj->track_rear_margin = 45;
324 }
325 else
326 {
327 p_new_obj->track_front_margin = 0;
328 p_new_obj->track_rear_margin = 0;
329 }
330
331 return p_new_obj;
332 }
333
334 int
vcd_obj_remove_item(VcdObj_t * p_vcdobj,const char id[])335 vcd_obj_remove_item (VcdObj_t *p_vcdobj, const char id[])
336 {
337 vcd_warn ("vcd_obj_remove_item('%s') not implemented yet!", id);
338
339 return -1;
340 }
341
342 static void
_vcd_obj_remove_mpeg_track(VcdObj_t * p_vcdobj,int track_id)343 _vcd_obj_remove_mpeg_track (VcdObj_t *p_vcdobj, int track_id)
344 {
345 int length;
346 mpeg_sequence_t *track = NULL;
347 CdioListNode_t *node = NULL;
348
349 vcd_assert (track_id >= 0);
350
351 node = _vcd_list_at (p_vcdobj->mpeg_sequence_list, track_id);
352
353 vcd_assert (node != NULL);
354
355 track = (mpeg_sequence_t *) _cdio_list_node_data (node);
356
357 vcd_mpeg_source_destroy (track->source, true);
358
359 length = track->info ? track->info->packets : 0;
360 length += p_vcdobj->track_pregap + p_vcdobj->track_front_margin
361 + 0 + p_vcdobj->track_rear_margin;
362
363 /* fixup offsets */
364 {
365 CdioListNode_t *node2 = node;
366 while ((node2 = _cdio_list_node_next (node2)) != NULL)
367 ((mpeg_sequence_t *) _cdio_list_node_data (node))->relative_start_extent
368 -= length;
369 }
370
371 p_vcdobj->relative_end_extent -= length;
372
373 /* shift up */
374 _cdio_list_node_free (node, true, NULL);
375 }
376
377 int
vcd_obj_append_segment_play_item(VcdObj_t * p_vcdobj,VcdMpegSource_t * p_mpeg_source,const char item_id[])378 vcd_obj_append_segment_play_item (VcdObj_t *p_vcdobj,
379 VcdMpegSource_t *p_mpeg_source,
380 const char item_id[])
381 {
382 mpeg_segment_t *segment = NULL;
383
384 vcd_assert (p_vcdobj != NULL);
385 vcd_assert (p_mpeg_source != NULL);
386
387 if (!_vcd_obj_has_cap_p (p_vcdobj, _CAP_PBC))
388 {
389 vcd_error ("segment play items not supported for this vcd type");
390 return -1;
391 }
392
393 if (!item_id)
394 {
395 vcd_error ("no id given for segment play item");
396 return -1;
397 }
398
399 if (_vcd_pbc_lookup (p_vcdobj, item_id))
400 {
401 vcd_error ("item id (%s) exists already", item_id);
402 return -1;
403 }
404
405 vcd_info ("scanning mpeg segment item #%d for scanpoints...",
406 _cdio_list_length (p_vcdobj->mpeg_segment_list));
407
408 vcd_mpeg_source_scan (p_mpeg_source, !p_vcdobj->relaxed_aps,
409 p_vcdobj->update_scan_offsets, NULL, NULL);
410
411 if (vcd_mpeg_source_get_info (p_mpeg_source)->packets == 0)
412 {
413 vcd_error ("mpeg is empty?");
414 return -1;
415 }
416
417 /* create list node */
418
419 segment = calloc(1, sizeof (mpeg_sequence_t));
420
421 segment->source = p_mpeg_source;
422
423 segment->id = strdup (item_id);
424
425 segment->info = vcd_mpeg_source_get_info (p_mpeg_source);
426 segment->segment_count = _vcd_len2blocks (segment->info->packets, 150);
427
428 segment->pause_list = _cdio_list_new ();
429
430 vcd_debug ("SPI length is %d sector(s), allocated %d segment(s)",
431 segment->info->packets,
432 segment->segment_count);
433
434 _cdio_list_append (p_vcdobj->mpeg_segment_list, segment);
435
436 return 0;
437 }
438
439 int
vcd_obj_append_sequence_play_item(VcdObj_t * p_vcdobj,VcdMpegSource_t * p_mpeg_source,const char item_id[],const char default_entry_id[])440 vcd_obj_append_sequence_play_item (VcdObj_t *p_vcdobj,
441 VcdMpegSource_t *p_mpeg_source,
442 const char item_id[],
443 const char default_entry_id[])
444 {
445 unsigned length;
446 mpeg_sequence_t *sequence = NULL;
447 int track_no = _cdio_list_length (p_vcdobj->mpeg_sequence_list);
448
449 vcd_assert (p_vcdobj != NULL);
450 vcd_assert (p_mpeg_source != NULL);
451
452 if (item_id && _vcd_pbc_lookup (p_vcdobj, item_id))
453 {
454 vcd_error ("item id (%s) exist already", item_id);
455 return -1;
456 }
457
458 if (default_entry_id && _vcd_pbc_lookup (p_vcdobj, default_entry_id))
459 {
460 vcd_error ("default entry id (%s) exist already", default_entry_id);
461 return -1;
462 }
463
464 if (default_entry_id && item_id && !strcmp (item_id, default_entry_id))
465 {
466 vcd_error ("default entry id == item id (%s)", item_id);
467 return -1;
468 }
469
470 vcd_info ("scanning mpeg sequence item #%d for scanpoints...", track_no);
471 vcd_mpeg_source_scan (p_mpeg_source, !p_vcdobj->relaxed_aps,
472 p_vcdobj->update_scan_offsets, NULL, NULL);
473
474 sequence = calloc(1, sizeof (mpeg_sequence_t));
475
476 sequence->source = p_mpeg_source;
477
478 if (item_id)
479 sequence->id = strdup (item_id);
480
481 if (default_entry_id)
482 sequence->default_entry_id = strdup (default_entry_id);
483
484 sequence->info = vcd_mpeg_source_get_info (p_mpeg_source);
485 length = sequence->info->packets;
486
487 sequence->entry_list = _cdio_list_new ();
488 sequence->pause_list = _cdio_list_new ();
489
490 p_vcdobj->relative_end_extent += p_vcdobj->track_pregap;
491 sequence->relative_start_extent = p_vcdobj->relative_end_extent;
492
493 p_vcdobj->relative_end_extent += p_vcdobj->track_front_margin + length
494 + p_vcdobj->track_rear_margin;
495
496 /* sanity checks */
497
498 if (length < 75)
499 vcd_warn ("mpeg stream shorter than 75 sectors");
500
501 if (!_vcd_obj_has_cap_p (p_vcdobj, _CAP_PAL_BITS)
502 && vcd_mpeg_get_norm (&sequence->info->shdr[0]) != MPEG_NORM_FILM
503 && vcd_mpeg_get_norm (&sequence->info->shdr[0]) != MPEG_NORM_NTSC)
504 vcd_warn ("VCD 1.x should contain only NTSC/FILM video (may work with PAL nevertheless)");
505
506 if (!_vcd_obj_has_cap_p (p_vcdobj, _CAP_MPEG1)
507 && sequence->info->version == MPEG_VERS_MPEG1)
508 vcd_warn ("this VCD type should not contain MPEG1 streams");
509
510 if (!_vcd_obj_has_cap_p (p_vcdobj, _CAP_MPEG2)
511 && sequence->info->version == MPEG_VERS_MPEG2)
512 vcd_warn ("this VCD type should not contain MPEG2 streams");
513
514 if (!sequence->info->shdr[0].seen
515 || sequence->info->shdr[1].seen
516 || sequence->info->shdr[2].seen)
517 vcd_warn ("sequence items should contain a motion video stream!");
518
519 {
520 int i;
521
522 for (i = 0; i < 3; i++)
523 {
524 if (sequence->info->ahdr[i].seen)
525 {
526 if (i && !_vcd_obj_has_cap_p (p_vcdobj, _CAP_MPEG2))
527 vcd_warn ("audio stream #%d not supported by this VCD type", i);
528
529 if (sequence->info->ahdr[i].sampfreq != 44100)
530 vcd_warn ("audio stream #%d has sampling frequency %d Hz (should be 44100 Hz)",
531 i, sequence->info->ahdr[i].sampfreq);
532
533 if (sequence->info->ahdr[i].layer != 2)
534 vcd_warn ("audio stream #%d is not layer II", i);
535
536 if (_vcd_obj_has_cap_p (p_vcdobj, _CAP_MPEG1)
537 && sequence->info->ahdr[i].bitrate != 224*1024)
538 vcd_warn ("audio stream #%d has bitrate %d kbps (should be 224 kbps for this vcd type)",
539 i, sequence->info->ahdr[i].bitrate);
540 }
541 else if (!i && !_vcd_obj_has_cap_p (p_vcdobj, _CAP_MPEG2))
542 {
543 vcd_warn ("this VCD type requires an audio stream to be present");
544 }
545 }
546 }
547
548 /* vcd_debug ("track# %d's detected playing time: %.2f seconds", */
549 /* track_no, sequence->info->playing_time); */
550
551 _cdio_list_append (p_vcdobj->mpeg_sequence_list, sequence);
552
553 return track_no;
554 }
555
556 static int
_pause_cmp(pause_t * ent1,pause_t * ent2)557 _pause_cmp (pause_t *ent1, pause_t *ent2)
558 {
559 if (ent1->time < ent2->time)
560 return -1;
561
562 if (ent1->time > ent2->time)
563 return 1;
564
565 return 0;
566 }
567
568 int
vcd_obj_add_sequence_pause(VcdObj_t * obj,const char sequence_id[],double pause_time,const char pause_id[])569 vcd_obj_add_sequence_pause (VcdObj_t *obj, const char sequence_id[],
570 double pause_time, const char pause_id[])
571 {
572 mpeg_sequence_t *p_sequence;
573
574 vcd_assert (obj != NULL);
575
576 if (sequence_id)
577 p_sequence = _vcd_obj_get_sequence_by_id (obj, sequence_id);
578 else
579 p_sequence =
580 _cdio_list_node_data (_cdio_list_end (obj->mpeg_sequence_list));
581
582 if (!p_sequence)
583 {
584 vcd_error ("sequence id `%s' not found", sequence_id);
585 return -1;
586 }
587
588 if (pause_id)
589 vcd_warn ("pause id ignored...");
590
591 {
592 pause_t *_pause = calloc(1, sizeof (pause_t));
593
594 if (pause_id)
595 _pause->id = strdup (pause_id);
596 _pause->time = pause_time;
597
598 _cdio_list_append (p_sequence->pause_list, _pause);
599 }
600
601 _vcd_list_sort (p_sequence->pause_list,
602 (_cdio_list_cmp_func_t) _pause_cmp);
603
604 vcd_debug ("added autopause point at %f", pause_time);
605
606 return 0;
607 }
608
609 int
vcd_obj_add_segment_pause(VcdObj_t * p_obj,const char segment_id[],double pause_time,const char pause_id[])610 vcd_obj_add_segment_pause (VcdObj_t *p_obj, const char segment_id[],
611 double pause_time, const char pause_id[])
612 {
613 mpeg_segment_t *_segment;
614
615 vcd_assert (p_obj != NULL);
616
617 if (segment_id)
618 _segment = _vcd_obj_get_segment_by_id (p_obj, segment_id);
619 else
620 _segment = _cdio_list_node_data (_cdio_list_end (p_obj->mpeg_segment_list));
621
622 if (!_segment)
623 {
624 vcd_error ("segment id `%s' not found", segment_id);
625 return -1;
626 }
627
628 if (pause_id)
629 vcd_warn ("pause id ignored...");
630
631 {
632 pause_t *_pause = calloc(1, sizeof (pause_t));
633
634 if (pause_id)
635 _pause->id = strdup (pause_id);
636 _pause->time = pause_time;
637
638 _cdio_list_append (_segment->pause_list, _pause);
639 }
640
641 _vcd_list_sort (_segment->pause_list,
642 (_cdio_list_cmp_func_t) _pause_cmp);
643
644 vcd_debug ("added autopause point at %f", pause_time);
645
646 return 0;
647 }
648
649 static int
_entry_cmp(entry_t * p_ent1,entry_t * p_ent2)650 _entry_cmp (entry_t *p_ent1, entry_t *p_ent2)
651 {
652 if (p_ent1->time < p_ent2->time)
653 return -1;
654
655 if (p_ent1->time > p_ent2->time)
656 return 1;
657
658 return 0;
659 }
660
661 int
vcd_obj_add_sequence_entry(VcdObj_t * p_obj,const char sequence_id[],double entry_time,const char entry_id[])662 vcd_obj_add_sequence_entry (VcdObj_t *p_obj, const char sequence_id[],
663 double entry_time, const char entry_id[])
664 {
665 mpeg_sequence_t *p_sequence;
666
667 vcd_assert (p_obj != NULL);
668
669 if (sequence_id)
670 p_sequence = _vcd_obj_get_sequence_by_id (p_obj, sequence_id);
671 else
672 p_sequence =
673 _cdio_list_node_data (_cdio_list_end (p_obj->mpeg_sequence_list));
674
675 if (!p_sequence)
676 {
677 vcd_error ("sequence id `%s' not found", sequence_id);
678 return -1;
679 }
680
681 if (_cdio_list_length (p_sequence->entry_list) >= MAX_SEQ_ENTRIES)
682 {
683 vcd_error ("only %d entries per sequence allowed!", MAX_SEQ_ENTRIES);
684 return -1;
685 }
686
687 if (entry_id && _vcd_pbc_lookup (p_obj, entry_id))
688 {
689 vcd_error ("item id (%s) exists already", entry_id);
690 return -1;
691 }
692
693 {
694 entry_t *_entry = calloc(1, sizeof (entry_t));
695
696 if (entry_id)
697 _entry->id = strdup (entry_id);
698 _entry->time = entry_time;
699
700 _cdio_list_append (p_sequence->entry_list, _entry);
701 }
702
703 _vcd_list_sort (p_sequence->entry_list,
704 (_cdio_list_cmp_func_t) _entry_cmp);
705
706 return 0;
707 }
708
709 void
vcd_obj_destroy(VcdObj_t * p_obj)710 vcd_obj_destroy (VcdObj_t *p_obj)
711 {
712 CdioListNode_t *p_node;
713
714 vcd_assert (p_obj != NULL);
715 vcd_assert (!p_obj->in_output);
716
717 free (p_obj->iso_volume_label);
718 free (p_obj->iso_application_id);
719
720 _CDIO_LIST_FOREACH (p_node, p_obj->custom_file_list)
721 {
722 custom_file_t *p = _cdio_list_node_data (p_node);
723
724 free (p->iso_pathname);
725 }
726
727 _cdio_list_free (p_obj->custom_file_list, true, NULL);
728
729 _cdio_list_free (p_obj->custom_dir_list, true, NULL);
730
731 while (_cdio_list_length (p_obj->mpeg_sequence_list))
732 _vcd_obj_remove_mpeg_track (p_obj, 0);
733 _cdio_list_free (p_obj->mpeg_sequence_list, true, (CdioDataFree_t) &sequence_free);
734
735 free (p_obj);
736 }
737
738 int
vcd_obj_set_param_uint(VcdObj_t * p_obj,vcd_parm_t param,unsigned arg)739 vcd_obj_set_param_uint (VcdObj_t *p_obj, vcd_parm_t param, unsigned arg)
740 {
741 vcd_assert (p_obj != NULL);
742
743 switch (param)
744 {
745 case VCD_PARM_VOLUME_COUNT:
746 p_obj->info_volume_count = arg;
747 if (!IN (p_obj->info_volume_count, 1, 65535))
748 {
749 p_obj->info_volume_count =
750 CLAMP (p_obj->info_volume_count, 1, 65535);
751 vcd_warn ("volume count out of range, clamping to range");
752 }
753 vcd_debug ("changed volume count to %u", p_obj->info_volume_count);
754 break;
755
756 case VCD_PARM_VOLUME_NUMBER:
757 p_obj->info_volume_number = arg;
758 if (!IN (p_obj->info_volume_number, 0, 65534))
759 {
760 p_obj->info_volume_number =
761 CLAMP (p_obj->info_volume_number, 0, 65534);
762 vcd_warn ("volume number out of range, clamping to range");
763 }
764 vcd_debug ("changed volume number to %u", p_obj->info_volume_number);
765 break;
766
767 case VCD_PARM_RESTRICTION:
768 p_obj->info_restriction = arg;
769 if (!IN (p_obj->info_restriction, 0, 3))
770 {
771 p_obj->info_restriction = CLAMP (p_obj->info_restriction, 0, 65534);
772 vcd_warn ("restriction out of range, clamping to range");
773 }
774 vcd_debug ("changed restriction number to %u", p_obj->info_restriction);
775 break;
776
777 case VCD_PARM_LEADOUT_PREGAP:
778 p_obj->leadout_pregap = arg;
779 if (!IN (p_obj->leadout_pregap, 0, 300))
780 {
781 p_obj->leadout_pregap = CLAMP (p_obj->leadout_pregap, 0, 300);
782 vcd_warn ("ledout pregap out of range, clamping to allowed range");
783 }
784 if (p_obj->leadout_pregap < CDIO_PREGAP_SECTORS)
785 vcd_warn ("track leadout pregap set below %d sectors; "
786 "created (S)VCD may be non-working",
787 CDIO_PREGAP_SECTORS);
788
789 vcd_debug ("changed leadout pregap to %u", p_obj->leadout_pregap);
790 break;
791
792 case VCD_PARM_TRACK_PREGAP:
793 p_obj->track_pregap = arg;
794 if (!IN (p_obj->track_pregap, 1, 300))
795 {
796 p_obj->track_pregap = CLAMP (p_obj->track_pregap, 1, 300);
797 vcd_warn ("track pregap out of range, clamping to allowed range");
798 }
799 if (p_obj->track_pregap < CDIO_PREGAP_SECTORS)
800 vcd_warn ("track pre gap set below %d sectors; "
801 "created (S)VCD may be non-working",
802 CDIO_PREGAP_SECTORS);
803 vcd_debug ("changed track pregap to %u", p_obj->track_pregap);
804 break;
805
806 case VCD_PARM_TRACK_FRONT_MARGIN:
807 p_obj->track_front_margin = arg;
808 if (!IN (p_obj->track_front_margin, 0, CDIO_PREGAP_SECTORS))
809 {
810 p_obj->track_front_margin = CLAMP (p_obj->track_front_margin, 0,
811 CDIO_PREGAP_SECTORS);
812 vcd_warn ("front margin out of range, clamping to allowed range");
813 }
814 if (_vcd_obj_has_cap_p (p_obj, _CAP_TRACK_MARGINS)
815 && p_obj->track_front_margin < 15)
816 vcd_warn ("front margin set smaller than recommended (%d < 15 sectors) for disc type used",
817 p_obj->track_front_margin);
818
819 vcd_debug ("changed front margin to %u", p_obj->track_front_margin);
820 break;
821
822 case VCD_PARM_TRACK_REAR_MARGIN:
823 p_obj->track_rear_margin = arg;
824 if (!IN (p_obj->track_rear_margin, 0, CDIO_POSTGAP_SECTORS))
825 {
826 p_obj->track_rear_margin = CLAMP (p_obj->track_rear_margin, 0,
827 CDIO_POSTGAP_SECTORS);
828 vcd_warn ("rear margin out of range, clamping to allowed range");
829 }
830 if (_vcd_obj_has_cap_p (p_obj, _CAP_TRACK_MARGINS)
831 && p_obj->track_rear_margin < 15)
832 vcd_warn ("rear margin set smaller than recommended (%d < 15 sectors) for disc type used",
833 p_obj->track_rear_margin);
834 vcd_debug ("changed rear margin to %u", p_obj->track_rear_margin);
835 break;
836
837 default:
838 vcd_assert_not_reached ();
839 break;
840 }
841
842 return 0;
843 }
844
845 int
vcd_obj_set_param_str(VcdObj_t * p_obj,vcd_parm_t param,const char * arg)846 vcd_obj_set_param_str (VcdObj_t *p_obj, vcd_parm_t param, const char *arg)
847 {
848 vcd_assert (p_obj != NULL);
849 vcd_assert (arg != NULL);
850
851 switch (param)
852 {
853 case VCD_PARM_VOLUME_ID:
854 free (p_obj->iso_volume_label);
855 p_obj->iso_volume_label = strdup (arg);
856 if (strlen (p_obj->iso_volume_label) > ISO_MAX_VOLUME_ID)
857 {
858 p_obj->iso_volume_label[ISO_MAX_VOLUME_ID] = '\0';
859 vcd_warn ("Volume label too long, will be truncated");
860 }
861 vcd_debug ("changed volume label to `%s'", p_obj->iso_volume_label);
862 break;
863
864 case VCD_PARM_PUBLISHER_ID:
865 free (p_obj->iso_publisher_id);
866 p_obj->iso_publisher_id = strdup (arg);
867 if (strlen (p_obj->iso_publisher_id) > ISO_MAX_PUBLISHER_ID)
868 {
869 p_obj->iso_publisher_id[ISO_MAX_PUBLISHER_ID] = '\0';
870 vcd_warn ("Publisher ID too long, will be truncated");
871 }
872 vcd_debug ("changed publisher id to `%s'", p_obj->iso_publisher_id);
873 break;
874
875 case VCD_PARM_PREPARER_ID:
876 free (p_obj->iso_preparer_id);
877 p_obj->iso_preparer_id = strdup (arg);
878 if (strlen (p_obj->iso_preparer_id) > ISO_MAX_PREPARER_ID)
879 {
880 p_obj->iso_preparer_id[ISO_MAX_PREPARER_ID] = '\0';
881 vcd_warn ("Preparer ID too long, will be truncated");
882 }
883 vcd_debug ("changed preparer id to `%s'", p_obj->iso_preparer_id);
884 break;
885
886 case VCD_PARM_APPLICATION_ID:
887 free (p_obj->iso_application_id);
888 p_obj->iso_application_id = strdup (arg);
889 if (strlen (p_obj->iso_application_id) > ISO_MAX_APPLICATION_ID)
890 {
891 p_obj->iso_application_id[ISO_MAX_APPLICATION_ID] = '\0';
892 vcd_warn ("Application ID too long, will be truncated");
893 }
894 vcd_debug ("changed application id to `%s'", p_obj->iso_application_id);
895 break;
896
897 case VCD_PARM_ALBUM_ID:
898 free (p_obj->info_album_id);
899 p_obj->info_album_id = strdup (arg);
900 if (strlen (p_obj->info_album_id) > 16)
901 {
902 p_obj->info_album_id[16] = '\0';
903 vcd_warn ("Album ID too long, will be truncated");
904 }
905 vcd_debug ("changed album id to `%s'", p_obj->info_album_id);
906 break;
907
908 default:
909 vcd_assert_not_reached ();
910 break;
911 }
912
913 return 0;
914 }
915
916 int
vcd_obj_set_param_bool(VcdObj_t * p_obj,vcd_parm_t param,bool arg)917 vcd_obj_set_param_bool (VcdObj_t *p_obj, vcd_parm_t param, bool arg)
918 {
919 vcd_assert (p_obj != NULL);
920
921 switch (param)
922 {
923 case VCD_PARM_RELAXED_APS:
924 p_obj->relaxed_aps = arg ? true : false;
925 vcd_debug ("changing 'relaxed aps' to %d", p_obj->relaxed_aps);
926 break;
927
928 case VCD_PARM_NEXT_VOL_LID2:
929 p_obj->info_use_lid2 = arg ? true : false;
930 vcd_debug ("changing 'next volume use lid 2' to %d",
931 p_obj->info_use_lid2);
932 break;
933
934 case VCD_PARM_NEXT_VOL_SEQ2:
935 p_obj->info_use_seq2 = arg ? true : false;
936 vcd_debug ("changing 'next volume use sequence 2' to %d",
937 p_obj->info_use_seq2);
938 break;
939
940 case VCD_PARM_SVCD_VCD3_MPEGAV:
941 if (p_obj->type == VCD_TYPE_SVCD)
942 {
943 if ((p_obj->svcd_vcd3_mpegav = arg ? true : false))
944 vcd_warn ("!! enabling deprecated VCD3.0 MPEGAV folder --"
945 " SVCD will not be IEC62107 compliant !!");
946 }
947 else
948 vcd_error ("parameter not applicable for vcd type");
949 break;
950
951 case VCD_PARM_SVCD_VCD3_ENTRYSVD:
952 if (p_obj->type == VCD_TYPE_SVCD)
953 {
954 if ((p_obj->svcd_vcd3_entrysvd = arg ? true : false))
955 vcd_warn ("!! enabling deprecated VCD3.0 ENTRYSVD signature --"
956 " SVCD will not be IEC62107 compliant !!");
957 }
958 else
959 vcd_error ("parameter not applicable for vcd type");
960 break;
961
962 case VCD_PARM_SVCD_VCD3_TRACKSVD:
963 if (p_obj->type == VCD_TYPE_SVCD)
964 {
965 if ((p_obj->svcd_vcd3_tracksvd = arg ? true : false))
966 vcd_warn ("!! enabling deprecated VCD3.0 TRACK.SVD format --"
967 " SVCD will not be IEC62107 compliant !!");
968 }
969 else
970 vcd_error ("parameter not applicable for vcd type");
971 break;
972
973 case VCD_PARM_UPDATE_SCAN_OFFSETS:
974 if (_vcd_obj_has_cap_p (p_obj, _CAP_4C_SVCD))
975 {
976 p_obj->update_scan_offsets = arg ? true : false;
977 vcd_debug ("changing 'update scan offsets' to %d",
978 p_obj->update_scan_offsets);
979 }
980 else
981 vcd_error ("parameter not applicable for vcd type");
982 break;
983
984 case VCD_PARM_LEADOUT_PAUSE:
985 vcd_warn ("use of 'leadout pause' is deprecated and may be removed in later releases;"
986 " use 'leadout pregap' instead");
987 vcd_obj_set_param_uint (p_obj, VCD_PARM_LEADOUT_PREGAP,
988 (arg ? CDIO_PREGAP_SECTORS : 0));
989 break;
990
991 default:
992 vcd_assert_not_reached ();
993 break;
994 }
995
996 return 0;
997 }
998
999 int
vcd_obj_add_dir(VcdObj_t * p_obj,const char iso_pathname[])1000 vcd_obj_add_dir (VcdObj_t *p_obj, const char iso_pathname[])
1001 {
1002 char *_iso_pathname;
1003
1004 vcd_assert (p_obj != NULL);
1005 vcd_assert (iso_pathname != NULL);
1006
1007 _iso_pathname = _vcd_strdup_upper (iso_pathname);
1008
1009 if (!iso9660_dirname_valid_p (_iso_pathname))
1010 {
1011 vcd_error("pathname `%s' is not a valid iso pathname",
1012 _iso_pathname);
1013 free (_iso_pathname);
1014 return 1;
1015 }
1016
1017 _cdio_list_append (p_obj->custom_dir_list, _iso_pathname);
1018
1019 _vcd_list_sort (p_obj->custom_dir_list,
1020 (_cdio_list_cmp_func_t) strcmp);
1021
1022 return 0;
1023 }
1024
1025 int
vcd_obj_add_file(VcdObj_t * p_obj,const char iso_pathname[],VcdDataSource_t * file,bool raw_flag)1026 vcd_obj_add_file (VcdObj_t *p_obj, const char iso_pathname[],
1027 VcdDataSource_t *file, bool raw_flag)
1028 {
1029 uint32_t size = 0, sectors = 0;
1030
1031 vcd_assert (p_obj != NULL);
1032 vcd_assert (file != NULL);
1033 vcd_assert (iso_pathname != NULL);
1034 vcd_assert (strlen (iso_pathname) > 0);
1035 vcd_assert (file != NULL);
1036
1037 size = vcd_data_source_stat (file);
1038
1039 /* close file to save file descriptors */
1040 vcd_data_source_close (file);
1041
1042 if (raw_flag)
1043 {
1044 if (!size)
1045 {
1046 vcd_error("raw mode2 file must not be empty\n");
1047 return 1;
1048 }
1049
1050 sectors = size / M2RAW_SECTOR_SIZE;
1051
1052 if (size % M2RAW_SECTOR_SIZE)
1053 {
1054 vcd_error("raw mode2 file must have size multiple of %d \n",
1055 M2RAW_SECTOR_SIZE);
1056 return 1;
1057 }
1058 }
1059 else
1060 sectors = _vcd_len2blocks (size, CDIO_CD_FRAMESIZE);
1061
1062 {
1063 custom_file_t *p;
1064 char *_iso_pathname = _vcd_strdup_upper (iso_pathname);
1065
1066 if (!iso9660_pathname_valid_p (_iso_pathname))
1067 {
1068 vcd_error("pathname `%s' is not a valid iso pathname",
1069 _iso_pathname);
1070 free (_iso_pathname);
1071 return 1;
1072 }
1073
1074 p = calloc(1, sizeof (custom_file_t));
1075
1076 p->file = file;
1077 p->iso_pathname = _iso_pathname;
1078 p->raw_flag = raw_flag;
1079
1080 p->size = size;
1081 p->start_extent = 0;
1082 p->sectors = sectors;
1083
1084 _cdio_list_append (p_obj->custom_file_list, p);
1085 }
1086
1087 return 0;
1088 }
1089
1090 static void
_finalize_vcd_iso_track_allocation(VcdObj_t * p_obj)1091 _finalize_vcd_iso_track_allocation (VcdObj_t *p_obj)
1092 {
1093 int n;
1094 CdioListNode_t *p_node;
1095
1096 _dict_clean (p_obj);
1097
1098 /* pre-alloc 16 blocks of ISO9660 required silence */
1099 if (_vcd_salloc (p_obj->iso_bitmap, 0, 16) == SECTOR_NIL)
1100 vcd_assert_not_reached ();
1101
1102 /* keep karaoke sectors blank -- well... guess I'm too paranoid :) */
1103 if (_vcd_salloc (p_obj->iso_bitmap, 75, 75) == SECTOR_NIL)
1104 vcd_assert_not_reached ();
1105
1106 /* pre-alloc descriptors, PVD */
1107 _dict_insert (p_obj, "pvd", ISO_PVD_SECTOR, 1, SM_EOR); /* EOR */
1108 /* EVD */
1109 _dict_insert (p_obj, "evd", ISO_EVD_SECTOR, 1, SM_EOR|SM_EOF); /* EOR+EOF */
1110
1111 /* reserve for iso directory */
1112 _vcd_salloc (p_obj->iso_bitmap, 18, 75-18);
1113
1114 /* VCD information area */
1115
1116 _dict_insert (p_obj, "info", INFO_VCD_SECTOR, 1, SM_EOF); /* INFO.VCD */ /* EOF */
1117 _dict_insert (p_obj, "entries", ENTRIES_VCD_SECTOR, 1, SM_EOF); /* ENTRIES.VCD */ /* EOF */
1118
1119 /* PBC */
1120
1121 if (_vcd_pbc_available (p_obj))
1122 {
1123 _dict_insert (p_obj, "lot", LOT_VCD_SECTOR, LOT_VCD_SIZE, SM_EOF); /* LOT.VCD */ /* EOF */
1124 _dict_insert (p_obj, "psd", PSD_VCD_SECTOR,
1125 _vcd_len2blocks (get_psd_size (p_obj, false), ISO_BLOCKSIZE), SM_EOF); /* PSD.VCD */ /* EOF */
1126 }
1127
1128 if (_vcd_obj_has_cap_p (p_obj, _CAP_4C_SVCD))
1129 {
1130 _dict_insert (p_obj, "tracks", SECTOR_NIL, 1, SM_EOF); /* TRACKS.SVD */
1131 _dict_insert (p_obj, "search", SECTOR_NIL,
1132 _vcd_len2blocks (get_search_dat_size (p_obj), ISO_BLOCKSIZE), SM_EOF); /* SEARCH.DAT */
1133
1134 vcd_assert (_dict_get_bykey (p_obj, "tracks")->sector > INFO_VCD_SECTOR);
1135 vcd_assert (_dict_get_bykey (p_obj, "search")->sector > INFO_VCD_SECTOR);
1136 }
1137
1138 /* done with primary information area */
1139
1140 p_obj->mpeg_segment_start_extent =
1141 _vcd_len2blocks (_vcd_salloc_get_highest (p_obj->iso_bitmap) + 1, 75) * 75;
1142
1143 /* salloc up to end of vcd sector */
1144 for(n = 0;n < p_obj->mpeg_segment_start_extent;n++)
1145 _vcd_salloc (p_obj->iso_bitmap, n, 1);
1146
1147 vcd_assert (_vcd_salloc_get_highest (p_obj->iso_bitmap) + 1 == p_obj->mpeg_segment_start_extent);
1148
1149 /* insert segments */
1150
1151 _CDIO_LIST_FOREACH (p_node, p_obj->mpeg_segment_list)
1152 {
1153 mpeg_segment_t *_segment = _cdio_list_node_data (p_node);
1154
1155 _segment->start_extent =
1156 _vcd_salloc (p_obj->iso_bitmap, SECTOR_NIL,
1157 _segment->segment_count * VCDINFO_SEGMENT_SECTOR_SIZE);
1158
1159 vcd_assert (_segment->start_extent % 75 == 0);
1160 vcd_assert (_vcd_salloc_get_highest (p_obj->iso_bitmap) + 1
1161 == _segment->start_extent
1162 + _segment->segment_count * VCDINFO_SEGMENT_SECTOR_SIZE);
1163 }
1164
1165 p_obj->ext_file_start_extent = _vcd_salloc_get_highest (p_obj->iso_bitmap) + 1;
1166
1167 vcd_assert (p_obj->ext_file_start_extent % 75 == 0);
1168
1169 /* go on with EXT area */
1170
1171 if (_vcd_obj_has_cap_p (p_obj, _CAP_4C_SVCD))
1172 {
1173 _dict_insert (p_obj, "scandata", SECTOR_NIL,
1174 _vcd_len2blocks (get_scandata_dat_size (p_obj),
1175 ISO_BLOCKSIZE),
1176 SM_EOF);
1177 }
1178
1179 if (_vcd_obj_has_cap_p (p_obj, _CAP_PBC_X)
1180 &&_vcd_pbc_available (p_obj))
1181 {
1182 _dict_insert (p_obj, "lot_x", SECTOR_NIL, LOT_VCD_SIZE, SM_EOF);
1183
1184 _dict_insert (p_obj, "psd_x", SECTOR_NIL,
1185 _vcd_len2blocks (get_psd_size (p_obj, true),
1186 ISO_BLOCKSIZE), SM_EOF);
1187 }
1188
1189
1190 p_obj->custom_file_start_extent =
1191 _vcd_salloc_get_highest (p_obj->iso_bitmap) + 1;
1192
1193 /* now for the custom files */
1194
1195 _CDIO_LIST_FOREACH (p_node, p_obj->custom_file_list)
1196 {
1197 custom_file_t *p = _cdio_list_node_data (p_node);
1198
1199 if (p->sectors)
1200 {
1201 p->start_extent =
1202 _vcd_salloc(p_obj->iso_bitmap, SECTOR_NIL, p->sectors);
1203 vcd_assert (p->start_extent != SECTOR_NIL);
1204 }
1205 else /* zero sized files -- set dummy extent */
1206 p->start_extent = p_obj->custom_file_start_extent;
1207 }
1208
1209 /* calculate iso size -- after this point no sector shall be
1210 allocated anymore */
1211
1212 p_obj->iso_size =
1213 MAX (MIN_ISO_SIZE, _vcd_salloc_get_highest (p_obj->iso_bitmap) + 1);
1214
1215 vcd_debug ("iso9660: highest alloced sector is %lu (using %d as isosize)",
1216 (unsigned long int) _vcd_salloc_get_highest (p_obj->iso_bitmap),
1217 p_obj->iso_size);
1218
1219 /* after this point the ISO9660's size is frozen */
1220 }
1221
1222 static void
_finalize_vcd_iso_track_filesystem(VcdObj_t * p_obj)1223 _finalize_vcd_iso_track_filesystem (VcdObj_t *p_obj)
1224 {
1225 int n;
1226 CdioListNode_t *p_node;
1227
1228 /* create filesystem entries */
1229
1230 switch (p_obj->type) {
1231 case VCD_TYPE_VCD:
1232 case VCD_TYPE_VCD11:
1233 case VCD_TYPE_VCD2:
1234 /* add only necessary directories! */
1235 /* _vcd_directory_mkdir (p_obj->dir, "CDDA"); */
1236 /* _vcd_directory_mkdir (p_obj->dir, "CDI"); */
1237 _vcd_directory_mkdir (p_obj->dir, "EXT");
1238 /* _vcd_directory_mkdir (p_obj->dir, "KARAOKE"); */
1239 _vcd_directory_mkdir (p_obj->dir, "MPEGAV");
1240 _vcd_directory_mkdir (p_obj->dir, "VCD");
1241
1242 /* add segment dir only when there are actually segment play items */
1243 if (_cdio_list_length (p_obj->mpeg_segment_list))
1244 _vcd_directory_mkdir (p_obj->dir, "SEGMENT");
1245
1246 _vcd_directory_mkfile (p_obj->dir, "VCD/ENTRIES.VCD",
1247 _dict_get_bykey (p_obj, "entries")->sector,
1248 ISO_BLOCKSIZE, false, 0);
1249 _vcd_directory_mkfile (p_obj->dir, "VCD/INFO.VCD",
1250 _dict_get_bykey (p_obj, "info")->sector,
1251 ISO_BLOCKSIZE, false, 0);
1252
1253 /* only for vcd2.0 */
1254 if (_vcd_pbc_available (p_obj))
1255 {
1256 _vcd_directory_mkfile (p_obj->dir, "VCD/LOT.VCD",
1257 _dict_get_bykey (p_obj, "lot")->sector,
1258 ISO_BLOCKSIZE*LOT_VCD_SIZE, false, 0);
1259 _vcd_directory_mkfile (p_obj->dir, "VCD/PSD.VCD",
1260 _dict_get_bykey (p_obj, "psd")->sector,
1261 get_psd_size (p_obj, false), false, 0);
1262 }
1263 break;
1264
1265 case VCD_TYPE_SVCD:
1266 case VCD_TYPE_HQVCD:
1267 _vcd_directory_mkdir (p_obj->dir, "EXT");
1268
1269 if (!p_obj->svcd_vcd3_mpegav)
1270 _vcd_directory_mkdir (p_obj->dir, "MPEG2");
1271 else
1272 {
1273 vcd_warn ("adding MPEGAV dir for *DEPRECATED* SVCD VCD30 mode");
1274 _vcd_directory_mkdir (p_obj->dir, "MPEGAV");
1275 }
1276
1277 /* add segment dir only when there are actually segment play items */
1278 if (_cdio_list_length (p_obj->mpeg_segment_list))
1279 _vcd_directory_mkdir (p_obj->dir, "SEGMENT");
1280
1281 _vcd_directory_mkdir (p_obj->dir, "SVCD");
1282
1283 _vcd_directory_mkfile (p_obj->dir, "SVCD/ENTRIES.SVD",
1284 _dict_get_bykey (p_obj, "entries")->sector,
1285 ISO_BLOCKSIZE, false, 0);
1286 _vcd_directory_mkfile (p_obj->dir, "SVCD/INFO.SVD",
1287 _dict_get_bykey (p_obj, "info")->sector,
1288 ISO_BLOCKSIZE, false, 0);
1289
1290 if (_vcd_pbc_available (p_obj))
1291 {
1292 _vcd_directory_mkfile (p_obj->dir, "SVCD/LOT.SVD",
1293 _dict_get_bykey (p_obj, "lot")->sector,
1294 ISO_BLOCKSIZE*LOT_VCD_SIZE, false, 0);
1295 _vcd_directory_mkfile (p_obj->dir, "SVCD/PSD.SVD",
1296 _dict_get_bykey (p_obj, "psd")->sector,
1297 get_psd_size (p_obj, false), false, 0);
1298 }
1299
1300 _vcd_directory_mkfile (p_obj->dir, "SVCD/SEARCH.DAT",
1301 _dict_get_bykey (p_obj, "search")->sector,
1302 get_search_dat_size (p_obj), false, 0);
1303 _vcd_directory_mkfile (p_obj->dir, "SVCD/TRACKS.SVD",
1304 _dict_get_bykey (p_obj, "tracks")->sector,
1305 ISO_BLOCKSIZE, false, 0);
1306 break;
1307
1308 default:
1309 vcd_assert_not_reached ();
1310 break;
1311 }
1312
1313 /* SEGMENTS */
1314
1315 n = 1;
1316 _CDIO_LIST_FOREACH (p_node, p_obj->mpeg_segment_list)
1317 {
1318 mpeg_segment_t *segment = _cdio_list_node_data (p_node);
1319 char segment_pathname[128] = { 0, };
1320 const char *fmt = NULL;
1321 uint8_t fnum = 0;
1322
1323 switch (p_obj->type)
1324 {
1325 case VCD_TYPE_VCD2:
1326 fmt = "SEGMENT/ITEM%4.4d.DAT";
1327 fnum = 1;
1328 break;
1329 case VCD_TYPE_SVCD:
1330 case VCD_TYPE_HQVCD:
1331 fmt = "SEGMENT/ITEM%4.4d.MPG";
1332 fnum = 0;
1333 break;
1334 default:
1335 vcd_assert_not_reached ();
1336 }
1337
1338 snprintf (segment_pathname, sizeof (segment_pathname), fmt, n);
1339
1340 _vcd_directory_mkfile (p_obj->dir, segment_pathname,
1341 segment->start_extent,
1342 segment->info->packets * ISO_BLOCKSIZE,
1343 true, fnum);
1344
1345 vcd_assert (n <= MAX_SEGMENTS);
1346
1347 n += segment->segment_count;
1348 }
1349
1350 /* EXT files */
1351
1352 if (_vcd_obj_has_cap_p (p_obj, _CAP_PBC_X)
1353 &&_vcd_pbc_available (p_obj))
1354 {
1355 /* psd_x -- extended PSD */
1356 _vcd_directory_mkfile (p_obj->dir, "EXT/PSD_X.VCD",
1357 _dict_get_bykey (p_obj, "psd_x")->sector,
1358 get_psd_size (p_obj, true), false, 1);
1359
1360 /* lot_x -- extended LOT */
1361 _vcd_directory_mkfile (p_obj->dir, "EXT/LOT_X.VCD",
1362 _dict_get_bykey (p_obj, "lot_x")->sector,
1363 ISO_BLOCKSIZE*LOT_VCD_SIZE, false, 1);
1364
1365 vcd_assert (p_obj->type == VCD_TYPE_VCD2);
1366 }
1367
1368 if (_vcd_obj_has_cap_p (p_obj, _CAP_4C_SVCD))
1369 {
1370 /* scandata.dat -- scanpoints */
1371 _vcd_directory_mkfile (p_obj->dir, "EXT/SCANDATA.DAT",
1372 _dict_get_bykey (p_obj, "scandata")->sector,
1373 get_scandata_dat_size (p_obj), false, 0);
1374 }
1375
1376 /* custom files/dirs */
1377 _CDIO_LIST_FOREACH (p_node, p_obj->custom_dir_list)
1378 {
1379 char *p = _cdio_list_node_data (p_node);
1380 _vcd_directory_mkdir (p_obj->dir, p);
1381 }
1382
1383 _CDIO_LIST_FOREACH (p_node, p_obj->custom_file_list)
1384 {
1385 custom_file_t *p = _cdio_list_node_data (p_node);
1386
1387 _vcd_directory_mkfile (p_obj->dir, p->iso_pathname, p->start_extent,
1388 (p->raw_flag
1389 ? (ISO_BLOCKSIZE * (p->size / M2RAW_SECTOR_SIZE))
1390 : p->size),
1391 p->raw_flag, 1);
1392 }
1393
1394
1395 n = 0;
1396 _CDIO_LIST_FOREACH (p_node, p_obj->mpeg_sequence_list)
1397 {
1398 char avseq_pathname[128] = { 0, };
1399 const char *fmt = NULL;
1400 mpeg_sequence_t *p_sequence = _cdio_list_node_data (p_node);
1401 uint32_t extent = p_sequence->relative_start_extent;
1402 uint8_t file_num = 0;
1403
1404 extent += p_obj->iso_size;
1405
1406 switch (p_obj->type)
1407 {
1408 case VCD_TYPE_VCD:
1409 fmt = "MPEGAV/MUSIC%2.2d.DAT";
1410 file_num = n + 1;
1411 break;
1412
1413 case VCD_TYPE_VCD11:
1414 case VCD_TYPE_VCD2:
1415 fmt = "MPEGAV/AVSEQ%2.2d.DAT";
1416 file_num = n + 1;
1417 break;
1418 case VCD_TYPE_SVCD:
1419 case VCD_TYPE_HQVCD:
1420 fmt = "MPEG2/AVSEQ%2.2d.MPG";
1421 file_num = 0;
1422
1423 /* if vcd3 compat mode, override */
1424 if (p_obj->svcd_vcd3_mpegav)
1425 {
1426 fmt = "MPEGAV/AVSEQ%2.2d.MPG";
1427 file_num = n + 1;
1428 }
1429
1430 break;
1431 default:
1432 vcd_assert_not_reached ();
1433 }
1434
1435 vcd_assert (n < 98);
1436
1437 snprintf (avseq_pathname, sizeof (avseq_pathname), fmt, n + 1);
1438
1439 /* file entry contains front margin, mpeg stream and rear margin */
1440 _vcd_directory_mkfile (p_obj->dir, avseq_pathname, extent,
1441 (p_obj->track_front_margin
1442 + p_sequence->info->packets
1443 + p_obj->track_rear_margin) * ISO_BLOCKSIZE,
1444 true, file_num);
1445
1446 n++;
1447 }
1448
1449 /* register isofs dir structures */
1450 {
1451 uint32_t dirs_size = _vcd_directory_get_size (p_obj->dir);
1452
1453 /* be sure to stay out of information areas */
1454
1455 switch (p_obj->type)
1456 {
1457 case VCD_TYPE_VCD:
1458 case VCD_TYPE_VCD11:
1459 case VCD_TYPE_VCD2:
1460 /* karaoke area starts at 03:00 */
1461 if (16 + 2 + dirs_size + 2 >= 75)
1462 vcd_error ("directory section to big for a VCD");
1463 break;
1464
1465 case VCD_TYPE_SVCD:
1466 case VCD_TYPE_HQVCD:
1467 /* since no karaoke exists the next fixed area starts at 04:00 */
1468 if (16 + 2 + dirs_size + 2 >= 150)
1469 vcd_error ("directory section to big for a SVCD");
1470 break;
1471 default:
1472 vcd_assert_not_reached ();
1473 }
1474
1475 /* un-alloc small area */
1476
1477 _vcd_salloc_free (p_obj->iso_bitmap, 18, dirs_size + 2);
1478
1479 /* alloc it again! */
1480
1481 _dict_insert (p_obj, "dir", 18, dirs_size, SM_EOR|SM_EOF);
1482 _dict_insert (p_obj, "ptl", 18 + dirs_size, 1, SM_EOR|SM_EOF);
1483 _dict_insert (p_obj, "ptm", 18 + dirs_size + 1, 1, SM_EOR|SM_EOF);
1484 }
1485 }
1486
1487 static void
_finalize_vcd_iso_track(VcdObj_t * p_obj)1488 _finalize_vcd_iso_track (VcdObj_t *p_obj)
1489 {
1490 _vcd_pbc_finalize (p_obj);
1491 _finalize_vcd_iso_track_allocation (p_obj);
1492 _finalize_vcd_iso_track_filesystem (p_obj);
1493 }
1494
1495 static int
_callback_wrapper(VcdObj_t * p_obj,int force)1496 _callback_wrapper (VcdObj_t *p_obj, int force)
1497 {
1498 const int cb_frequency = 75;
1499
1500 if (p_obj->last_cb_call + cb_frequency > p_obj->sectors_written && !force)
1501 return 0;
1502
1503 p_obj->last_cb_call = p_obj->sectors_written;
1504
1505 if (p_obj->progress_callback) {
1506 progress_info_t _pi;
1507
1508 _pi.sectors_written = p_obj->sectors_written;
1509 _pi.total_sectors = p_obj->relative_end_extent + p_obj->iso_size;
1510 _pi.in_track = p_obj->in_track;
1511 _pi.total_tracks = _cdio_list_length (p_obj->mpeg_sequence_list) + 1;
1512
1513 return p_obj->progress_callback (&_pi, p_obj->callback_user_data);
1514 }
1515 else
1516 return 0;
1517 }
1518
1519 static int
_write_m2_image_sector(VcdObj_t * obj,const void * data,uint32_t extent,uint8_t fnum,uint8_t cnum,uint8_t sm,uint8_t ci)1520 _write_m2_image_sector (VcdObj_t *obj, const void *data, uint32_t extent,
1521 uint8_t fnum, uint8_t cnum, uint8_t sm, uint8_t ci)
1522 {
1523 char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, };
1524
1525 vcd_assert (extent == obj->sectors_written);
1526
1527 _vcd_make_mode2(buf, data, extent, fnum, cnum, sm, ci);
1528
1529 vcd_image_sink_write (obj->image_sink, buf, extent);
1530
1531 obj->sectors_written++;
1532
1533 return _callback_wrapper (obj, false);
1534 }
1535
1536 static int
_write_m2_raw_image_sector(VcdObj_t * obj,const void * data,uint32_t extent)1537 _write_m2_raw_image_sector (VcdObj_t *obj, const void *data, uint32_t extent)
1538 {
1539 char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, };
1540
1541 vcd_assert (extent == obj->sectors_written);
1542
1543 _vcd_make_raw_mode2(buf, data, extent);
1544
1545 vcd_image_sink_write (obj->image_sink, buf, extent);
1546
1547 obj->sectors_written++;
1548
1549 return _callback_wrapper (obj, false);
1550 }
1551
1552 static void
_write_source_mode2_raw(VcdObj_t * obj,VcdDataSource_t * source,uint32_t extent)1553 _write_source_mode2_raw (VcdObj_t *obj, VcdDataSource_t *source,
1554 uint32_t extent)
1555 {
1556 int n;
1557 uint32_t sectors;
1558
1559 sectors = vcd_data_source_stat (source) / M2RAW_SECTOR_SIZE;
1560
1561 vcd_data_source_seek (source, 0);
1562
1563 for (n = 0;n < sectors;n++) {
1564 char buf[M2RAW_SECTOR_SIZE] = { 0, };
1565
1566 vcd_data_source_read (source, buf, M2RAW_SECTOR_SIZE, 1);
1567
1568 if (_write_m2_raw_image_sector (obj, buf, extent+n))
1569 break;
1570 }
1571
1572 vcd_data_source_close (source);
1573 }
1574
1575 static void
_write_source_mode2_form1(VcdObj_t * obj,VcdDataSource_t * source,uint32_t extent)1576 _write_source_mode2_form1 (VcdObj_t *obj, VcdDataSource_t *source,
1577 uint32_t extent)
1578 {
1579 int n;
1580 uint32_t sectors, size, last_block_size;
1581
1582 size = vcd_data_source_stat (source);
1583
1584 sectors = _vcd_len2blocks (size, CDIO_CD_FRAMESIZE);
1585
1586 last_block_size = size % CDIO_CD_FRAMESIZE;
1587 if (!last_block_size)
1588 last_block_size = CDIO_CD_FRAMESIZE;
1589
1590 vcd_data_source_seek (source, 0);
1591
1592 for (n = 0;n < sectors;n++) {
1593 char buf[CDIO_CD_FRAMESIZE] = { 0, };
1594
1595 vcd_data_source_read (source, buf,
1596 ((n + 1 == sectors)
1597 ? last_block_size
1598 : CDIO_CD_FRAMESIZE), 1);
1599
1600 if (_write_m2_image_sector (obj, buf, extent+n, 1, 0,
1601 ((n+1 < sectors)
1602 ? SM_DATA
1603 : SM_DATA |SM_EOF),
1604 0))
1605 break;
1606 }
1607
1608 vcd_data_source_close (source);
1609 }
1610
1611 static int
_write_sequence(VcdObj_t * p_obj,int track_idx)1612 _write_sequence (VcdObj_t *p_obj, int track_idx)
1613 {
1614 mpeg_sequence_t *track =
1615 _cdio_list_node_data (_vcd_list_at (p_obj->mpeg_sequence_list, track_idx));
1616 CdioListNode_t *pause_node;
1617 int n, lastsect = p_obj->sectors_written;
1618 char buf[2324];
1619 struct {
1620 int audio;
1621 int video;
1622 int zero;
1623 int ogt;
1624 int unknown;
1625 } mpeg_packets = {0, };
1626
1627
1628 {
1629 char *norm_str = NULL;
1630 const struct vcd_mpeg_stream_vid_info *_info = &track->info->shdr[0];
1631
1632 switch (vcd_mpeg_get_norm (_info)) {
1633 case MPEG_NORM_PAL:
1634 norm_str = strdup ("PAL SIF (352x288/25fps)");
1635 break;
1636 case MPEG_NORM_NTSC:
1637 norm_str = strdup ("NTSC SIF (352x240/29.97fps)");
1638 break;
1639 case MPEG_NORM_FILM:
1640 norm_str = strdup ("FILM SIF (352x240/24fps)");
1641 break;
1642 case MPEG_NORM_PAL_S:
1643 norm_str = strdup ("PAL 2/3 D1 (480x576/25fps)");
1644 break;
1645 case MPEG_NORM_NTSC_S:
1646 norm_str = strdup ("NTSC 2/3 D1 (480x480/29.97fps)");
1647 break;
1648
1649 case MPEG_NORM_OTHER:
1650 {
1651 char buf[1024] = { 0, };
1652 switch (_info->vsize)
1653 {
1654 case 480:
1655 case 240:
1656 snprintf (buf, sizeof (buf), "NTSC UNKNOWN (%dx%d/%2.2ffps)",
1657 _info->hsize, _info->vsize, _info->frate);
1658 break;
1659 case 288:
1660 case 576:
1661 snprintf (buf, sizeof (buf), "PAL UNKNOWN (%dx%d/%2.2ffps)",
1662 _info->hsize, _info->vsize, _info->frate);
1663 break;
1664 default:
1665 snprintf (buf, sizeof (buf), "UNKNOWN (%dx%d/%2.2ffps)",
1666 _info->hsize, _info->vsize, _info->frate);
1667 break;
1668 }
1669 norm_str = strdup (buf);
1670 }
1671 break;
1672 }
1673
1674 {
1675 char buf[1024] = { 0, }, buf2[1024] = { 0, };
1676 int i;
1677 int i_buf2 = 0;
1678
1679 for (i = 0; i < 3; i++)
1680 if (track->info->ahdr[i].seen)
1681 {
1682 const char *_mode_str[] = {
1683 0,
1684 "stereo",
1685 "jstereo",
1686 "dual",
1687 "single",
1688 0
1689 };
1690
1691 int i_buf = snprintf (buf, sizeof (buf),
1692 "audio[%d]: l%d/%2.1fkHz/%dkbps/%s ",
1693 i,
1694 track->info->ahdr[i].layer,
1695 track->info->ahdr[i].sampfreq / 1000.0,
1696 track->info->ahdr[i].bitrate / 1024,
1697 _mode_str[track->info->ahdr[i].mode]);
1698
1699 strncat (buf2, buf, sizeof(buf2)-strlen(buf2)-i_buf2-1);
1700 i_buf2 += i_buf;
1701 }
1702
1703 vcd_info ("writing track %d, %s, %s, %s...", track_idx + 2,
1704 (track->info->version == MPEG_VERS_MPEG1 ? "MPEG1" : "MPEG2"),
1705 norm_str, buf2);
1706 }
1707
1708 free (norm_str);
1709 }
1710
1711 for (n = 0; n < p_obj->track_pregap; n++)
1712 _write_m2_image_sector (p_obj, zero, lastsect++, 0, 0, SM_FORM2, 0);
1713
1714 for (n = 0; n < p_obj->track_front_margin;n++)
1715 _write_m2_image_sector (p_obj, zero, lastsect++, track_idx + 1,
1716 0, SM_FORM2|SM_REALT, 0);
1717
1718 pause_node = _cdio_list_begin (track->pause_list);
1719
1720 for (n = 0; n < track->info->packets; n++) {
1721 int ci = 0, sm = 0, cnum = 0, fnum = 0;
1722 struct vcd_mpeg_packet_info pkt_flags;
1723 bool set_trigger = false;
1724
1725 vcd_mpeg_source_get_packet (track->source, n, buf, &pkt_flags,
1726 p_obj->update_scan_offsets);
1727
1728 while (pause_node)
1729 {
1730 pause_t *_pause = _cdio_list_node_data (pause_node);
1731
1732 if (!pkt_flags.has_pts)
1733 break; /* no pts */
1734
1735 if (pkt_flags.pts < _pause->time)
1736 break; /* our time has not come yet */
1737
1738 /* seems it's time to trigger! */
1739 set_trigger = true;
1740
1741 vcd_debug ("setting auto pause trigger for time %f (pts %f) @%d",
1742 _pause->time, pkt_flags.pts, n);
1743
1744 pause_node = _cdio_list_node_next (pause_node);
1745 }
1746
1747 switch (vcd_mpeg_packet_get_type (&pkt_flags))
1748 {
1749 case PKT_TYPE_VIDEO:
1750 mpeg_packets.video++;
1751 sm = SM_FORM2|SM_REALT|SM_VIDEO;
1752 ci = CI_VIDEO;
1753 cnum = CN_VIDEO;
1754 break;
1755
1756 case PKT_TYPE_OGT:
1757 mpeg_packets.ogt++;
1758 sm = SM_FORM2|SM_REALT|SM_VIDEO;
1759 ci = CI_OGT;
1760 cnum = CN_OGT;
1761 break;
1762
1763 case PKT_TYPE_AUDIO:
1764 mpeg_packets.audio++;
1765 sm = SM_FORM2|SM_REALT|SM_AUDIO;
1766 ci = CI_AUDIO;
1767 cnum = CN_AUDIO;
1768 if (pkt_flags.audio[1] || pkt_flags.audio[2])
1769 {
1770 ci = CI_AUDIO2;
1771 cnum = CN_AUDIO2;
1772 }
1773 break;
1774
1775
1776 case PKT_TYPE_ZERO:
1777 mpeg_packets.zero++;
1778 mpeg_packets.unknown--;
1779 case PKT_TYPE_EMPTY:
1780 mpeg_packets.unknown++;
1781 sm = SM_FORM2|SM_REALT;
1782 ci = CI_EMPTY;
1783 cnum = CN_EMPTY;
1784 break;
1785
1786 case PKT_TYPE_INVALID:
1787 vcd_error ("invalid mpeg packet found at packet# %d"
1788 " -- please fix this mpeg file!", n);
1789 vcd_mpeg_source_close (track->source);
1790 return 1;
1791 break;
1792
1793 default:
1794 vcd_assert_not_reached ();
1795 }
1796
1797 if (n == track->info->packets - 1)
1798 {
1799 sm |= SM_EOR;
1800 if (!p_obj->track_rear_margin) /* if no rear margin... */
1801 sm |= SM_EOF;
1802 }
1803
1804 if (set_trigger)
1805 sm |= SM_TRIG;
1806
1807 fnum = track_idx + 1;
1808
1809 if (_vcd_obj_has_cap_p (p_obj, _CAP_4C_SVCD)
1810 && !p_obj->svcd_vcd3_mpegav) /* IEC62107 SVCDs have a
1811 simplified subheader */
1812 {
1813 fnum = 1;
1814 ci = CI_MPEG2;
1815 }
1816
1817 if (_write_m2_image_sector (p_obj, buf, lastsect++, fnum, cnum, sm, ci))
1818 break;
1819 }
1820
1821 vcd_mpeg_source_close (track->source);
1822
1823 for (n = 0; n < p_obj->track_rear_margin; n++)
1824 {
1825 const uint8_t ci = 0, cnum = 0;
1826 uint8_t fnum = track_idx + 1;
1827 uint8_t sm = SM_FORM2 | SM_REALT;
1828
1829 if (n + 1 == p_obj->track_rear_margin)
1830 sm |= SM_EOF;
1831
1832 _write_m2_image_sector (p_obj, zero, lastsect++, fnum, cnum, sm, ci);
1833 }
1834
1835 vcd_debug ("MPEG packet statistics: %d video, %d audio, %d zero, %d ogt, %d unknown",
1836 mpeg_packets.video, mpeg_packets.audio, mpeg_packets.zero, mpeg_packets.ogt,
1837 mpeg_packets.unknown);
1838
1839 return 0;
1840 }
1841
1842 static int
_write_segment(VcdObj_t * p_obj,mpeg_segment_t * p_segment)1843 _write_segment (VcdObj_t *p_obj, mpeg_segment_t *p_segment)
1844 {
1845 CdioListNode_t *pause_node;
1846 unsigned int packet_no;
1847 int n = p_obj->sectors_written;
1848
1849 vcd_assert (p_segment->start_extent == n);
1850
1851 pause_node = _cdio_list_begin (p_segment->pause_list);
1852
1853 for (packet_no = 0;
1854 packet_no < (p_segment->segment_count * VCDINFO_SEGMENT_SECTOR_SIZE);
1855 packet_no++)
1856 {
1857 uint8_t buf[M2F2_SECTOR_SIZE] = { 0, };
1858 uint8_t fn, cn, sm, ci;
1859
1860 if (packet_no < p_segment->info->packets)
1861 {
1862 struct vcd_mpeg_packet_info pkt_flags;
1863 bool set_trigger = false;
1864 bool _need_eor = false;
1865
1866 vcd_mpeg_source_get_packet (p_segment->source, packet_no,
1867 buf, &pkt_flags,
1868 p_obj->update_scan_offsets);
1869
1870 fn = 1;
1871 cn = CN_EMPTY;
1872 sm = SM_FORM2 | SM_REALT;
1873 ci = CI_EMPTY;
1874
1875 while (pause_node)
1876 {
1877 pause_t *_pause = _cdio_list_node_data (pause_node);
1878
1879 if (!pkt_flags.has_pts)
1880 break; /* no pts */
1881
1882 if (pkt_flags.pts < _pause->time)
1883 break; /* our time has not come yet */
1884
1885 /* seems it's time to trigger! */
1886 set_trigger = true;
1887
1888 vcd_debug ("setting auto pause trigger for time %f (pts %f) @%d",
1889 _pause->time, pkt_flags.pts, n);
1890
1891 pause_node = _cdio_list_node_next (pause_node);
1892 }
1893
1894 switch (vcd_mpeg_packet_get_type (&pkt_flags))
1895 {
1896 case PKT_TYPE_VIDEO:
1897 sm = SM_FORM2 | SM_REALT | SM_VIDEO;
1898
1899 ci = CI_VIDEO;
1900 cn = CN_VIDEO;
1901
1902 if (pkt_flags.video[1])
1903 ci = CI_STILL, cn = CN_STILL;
1904 else if (pkt_flags.video[2])
1905 ci = CI_STILL2, cn = CN_STILL2;
1906
1907 if (pkt_flags.video[1] || pkt_flags.video[2])
1908 { /* search for endcode -- hack */
1909 int idx;
1910
1911 for (idx = 0; idx <= 2320; idx++)
1912 if (buf[idx] == 0x00
1913 && buf[idx + 1] == 0x00
1914 && buf[idx + 2] == 0x01
1915 && buf[idx + 3] == 0xb7)
1916 {
1917 _need_eor = true;
1918 break;
1919 }
1920 }
1921 break;
1922
1923 case PKT_TYPE_AUDIO:
1924 sm = SM_FORM2 | SM_REALT | SM_AUDIO;
1925
1926 ci = CI_AUDIO;
1927 cn = CN_AUDIO;
1928 break;
1929
1930 case PKT_TYPE_EMPTY:
1931 ci = CI_EMPTY;
1932 cn = CN_EMPTY;
1933 break;
1934
1935 default:
1936 /* fixme -- check.... */
1937 break;
1938 }
1939
1940 if (_vcd_obj_has_cap_p (p_obj, _CAP_4C_SVCD))
1941 {
1942 cn = 1;
1943 sm = SM_FORM2 | SM_REALT | SM_VIDEO;
1944 ci = CI_MPEG2;
1945 }
1946
1947 if (packet_no + 1 == p_segment->info->packets)
1948 sm |= SM_EOF;
1949
1950 if (set_trigger)
1951 sm |= SM_TRIG;
1952
1953 if (_need_eor)
1954 {
1955 vcd_debug ("setting EOR for SeqEnd at packet# %d ('%s')",
1956 packet_no, p_segment->id);
1957 sm |= SM_EOR;
1958 }
1959 }
1960 else
1961 {
1962 fn = 1;
1963 cn = CN_EMPTY;
1964 sm = SM_FORM2 | SM_REALT;
1965 ci = CI_EMPTY;
1966
1967 if (_vcd_obj_has_cap_p (p_obj, _CAP_4C_SVCD))
1968 {
1969 fn = 0;
1970 sm = SM_FORM2;
1971 }
1972
1973 }
1974
1975 _write_m2_image_sector (p_obj, buf, n, fn, cn, sm, ci);
1976
1977 n++;
1978 }
1979
1980 vcd_mpeg_source_close (p_segment->source);
1981
1982 return 0;
1983 }
1984
1985 static uint32_t
_get_closest_aps(const struct vcd_mpeg_stream_info * _mpeg_info,double t,struct aps_data * _best_aps)1986 _get_closest_aps (const struct vcd_mpeg_stream_info *_mpeg_info, double t,
1987 struct aps_data *_best_aps)
1988 {
1989 CdioListNode_t *p_node;
1990 struct aps_data best_aps;
1991 bool first = true;
1992
1993 best_aps.packet_no = 0xFFFF; /* A number which will be caught as an error*/
1994 best_aps.timestamp = -1; /* A number which will be caught as an error*/
1995 vcd_assert (_mpeg_info != NULL);
1996 vcd_assert (_mpeg_info->shdr[0].aps_list != NULL);
1997
1998 _CDIO_LIST_FOREACH (p_node, _mpeg_info->shdr[0].aps_list)
1999 {
2000 struct aps_data *_aps = _cdio_list_node_data (p_node);
2001
2002 if (first)
2003 {
2004 best_aps = *_aps;
2005 first = false;
2006 }
2007 else if (fabs (_aps->timestamp - t) < fabs (best_aps.timestamp - t))
2008 best_aps = *_aps;
2009 else
2010 break;
2011 }
2012
2013 if (_best_aps)
2014 *_best_aps = best_aps;
2015
2016 return best_aps.packet_no;
2017 }
2018
2019 static void
_update_entry_points(VcdObj_t * p_obj)2020 _update_entry_points (VcdObj_t *p_obj)
2021 {
2022 CdioListNode_t *sequence_node;
2023
2024 _CDIO_LIST_FOREACH (sequence_node, p_obj->mpeg_sequence_list)
2025 {
2026 mpeg_sequence_t *_sequence = _cdio_list_node_data (sequence_node);
2027 CdioListNode_t *entry_node;
2028 unsigned int last_packet_no = 0;
2029
2030 _CDIO_LIST_FOREACH (entry_node, _sequence->entry_list)
2031 {
2032 entry_t *_entry = _cdio_list_node_data (entry_node);
2033
2034 _get_closest_aps (_sequence->info, _entry->time, &_entry->aps);
2035
2036 vcd_log ((fabs (_entry->aps.timestamp - _entry->time) > 1
2037 ? VCD_LOG_WARN
2038 : VCD_LOG_DEBUG),
2039 "requested entry point (id=%s) at %f, "
2040 "closest possible entry point at %f",
2041 _entry->id, _entry->time, _entry->aps.timestamp);
2042
2043 if (last_packet_no == _entry->aps.packet_no)
2044 vcd_warn ("entry point '%s' falls into same sector as previous one!",
2045 _entry->id);
2046
2047 last_packet_no = _entry->aps.packet_no;
2048 }
2049 }
2050 }
2051
2052 static int
_write_vcd_iso_track(VcdObj_t * p_obj,const time_t * p_create_time)2053 _write_vcd_iso_track (VcdObj_t *p_obj, const time_t *p_create_time)
2054 {
2055 CdioListNode_t *node;
2056 int n;
2057
2058 /* generate dir sectors */
2059
2060 _vcd_directory_dump_entries (p_obj->dir,
2061 _dict_get_bykey (p_obj, "dir")->buf,
2062 _dict_get_bykey (p_obj, "dir")->sector);
2063
2064 _vcd_directory_dump_pathtables (p_obj->dir,
2065 _dict_get_bykey (p_obj, "ptl")->buf,
2066 _dict_get_bykey (p_obj, "ptm")->buf);
2067
2068 /* generate PVD and EVD at last... */
2069 iso9660_set_pvd (_dict_get_bykey (p_obj, "pvd")->buf,
2070 p_obj->iso_volume_label,
2071 p_obj->iso_publisher_id,
2072 p_obj->iso_preparer_id,
2073 p_obj->iso_application_id,
2074 p_obj->iso_size,
2075 _dict_get_bykey (p_obj, "dir")->buf,
2076 _dict_get_bykey (p_obj, "ptl")->sector,
2077 _dict_get_bykey (p_obj, "ptm")->sector,
2078 iso9660_pathtable_get_size (_dict_get_bykey (p_obj, "ptm")->buf),
2079 p_create_time
2080 );
2081
2082 iso9660_set_evd (_dict_get_bykey (p_obj, "evd")->buf);
2083
2084 /* fill VCD relevant files with data */
2085
2086 set_info_vcd (p_obj, _dict_get_bykey (p_obj, "info")->buf);
2087 set_entries_vcd (p_obj, _dict_get_bykey (p_obj, "entries")->buf);
2088
2089 if (_vcd_pbc_available (p_obj))
2090 {
2091 if (_vcd_obj_has_cap_p (p_obj, _CAP_PBC_X))
2092 {
2093 set_lot_vcd (p_obj, _dict_get_bykey (p_obj, "lot_x")->buf, true);
2094 set_psd_vcd (p_obj, _dict_get_bykey (p_obj, "psd_x")->buf, true);
2095 }
2096
2097 _vcd_pbc_check_unreferenced (p_obj);
2098
2099 set_lot_vcd (p_obj, _dict_get_bykey (p_obj, "lot")->buf, false);
2100 set_psd_vcd (p_obj, _dict_get_bykey (p_obj, "psd")->buf, false);
2101 }
2102
2103 if (_vcd_obj_has_cap_p (p_obj, _CAP_4C_SVCD))
2104 {
2105 set_tracks_svd (p_obj, _dict_get_bykey (p_obj, "tracks")->buf);
2106 set_search_dat (p_obj, _dict_get_bykey (p_obj, "search")->buf);
2107 set_scandata_dat (p_obj, _dict_get_bykey (p_obj, "scandata")->buf);
2108 }
2109
2110 /* start actually writing stuff */
2111
2112 vcd_info ("writing track 1 (ISO9660)...");
2113
2114 /* 00:02:00 -> 00:04:74 */
2115 for (n = 0; n < p_obj->mpeg_segment_start_extent; n++)
2116 {
2117 const void *content = NULL;
2118 uint8_t flags = SM_DATA;
2119
2120 content = _dict_get_sector (p_obj, n);
2121 flags |= _dict_get_sector_flags (p_obj, n);
2122
2123 if (content == NULL)
2124 content = zero;
2125
2126 _write_m2_image_sector (p_obj, content, n, 0, 0, flags, 0);
2127 }
2128
2129 /* SEGMENTS */
2130
2131 vcd_assert (n == p_obj->mpeg_segment_start_extent);
2132
2133 _CDIO_LIST_FOREACH (node, p_obj->mpeg_segment_list)
2134 {
2135 mpeg_segment_t *p_segment = _cdio_list_node_data (node);
2136
2137 _write_segment (p_obj, p_segment);
2138 }
2139
2140 n = p_obj->sectors_written;
2141
2142 /* EXT stuff */
2143
2144 vcd_assert (n == p_obj->ext_file_start_extent);
2145
2146 for (;n < p_obj->custom_file_start_extent; n++)
2147 {
2148 const void *content = NULL;
2149 uint8_t flags = SM_DATA;
2150 uint8_t fileno = _vcd_obj_has_cap_p (p_obj, _CAP_4C_SVCD) ? 0 : 1;
2151
2152 content = _dict_get_sector (p_obj, n);
2153 flags |= _dict_get_sector_flags (p_obj, n);
2154
2155 if (content == NULL)
2156 {
2157 vcd_debug ("unexpected empty EXT sector");
2158 content = zero;
2159 }
2160
2161 _write_m2_image_sector (p_obj, content, n, fileno, 0, flags, 0);
2162 }
2163
2164 /* write custom files */
2165
2166 vcd_assert (n == p_obj->custom_file_start_extent);
2167
2168 _CDIO_LIST_FOREACH (node, p_obj->custom_file_list)
2169 {
2170 custom_file_t *p = _cdio_list_node_data (node);
2171
2172 vcd_info ("writing file `%s' (%lu bytes%s)",
2173 p->iso_pathname, (unsigned long) p->size,
2174 p->raw_flag ? ", raw sectors file": "");
2175 if (p->raw_flag)
2176 _write_source_mode2_raw (p_obj, p->file, p->start_extent);
2177 else
2178 _write_source_mode2_form1 (p_obj, p->file, p->start_extent);
2179 }
2180
2181 /* blank unalloced tracks */
2182 while ((n = _vcd_salloc (p_obj->iso_bitmap, SECTOR_NIL, 1)) < p_obj->iso_size)
2183 _write_m2_image_sector (p_obj, zero, n, 0, 0, SM_DATA, 0);
2184
2185 return 0;
2186 }
2187
2188
2189 long
vcd_obj_get_image_size(VcdObj_t * p_obj)2190 vcd_obj_get_image_size (VcdObj_t *p_obj)
2191 {
2192 long size_sectors = -1;
2193
2194 vcd_assert (!p_obj->in_output);
2195
2196 if (_cdio_list_length (p_obj->mpeg_sequence_list) > 0)
2197 {
2198 /* fixme -- make this efficient */
2199 size_sectors = vcd_obj_begin_output (p_obj);
2200 vcd_obj_end_output (p_obj);
2201 }
2202
2203 return size_sectors;
2204 }
2205
2206 long
vcd_obj_begin_output(VcdObj_t * p_obj)2207 vcd_obj_begin_output (VcdObj_t *p_obj)
2208 {
2209 uint32_t image_size;
2210
2211 vcd_assert (p_obj != NULL);
2212 vcd_assert (_cdio_list_length (p_obj->mpeg_sequence_list) > 0);
2213
2214 vcd_assert (!p_obj->in_output);
2215 p_obj->in_output = true;
2216
2217 p_obj->in_track = 1;
2218 p_obj->sectors_written = 0;
2219
2220 p_obj->iso_bitmap = _vcd_salloc_new ();
2221
2222 p_obj->dir = _vcd_directory_new ();
2223
2224 p_obj->buffer_dict_list = _cdio_list_new ();
2225
2226 _finalize_vcd_iso_track (p_obj);
2227
2228 _update_entry_points (p_obj);
2229
2230 image_size = p_obj->relative_end_extent + p_obj->iso_size;
2231
2232 image_size += p_obj->leadout_pregap;
2233
2234 if (image_size > CDIO_CD_MAX_SECTORS)
2235 vcd_error ("image too big (%d sectors > %d sectors)",
2236 (unsigned) image_size, (unsigned) CDIO_CD_MAX_SECTORS);
2237
2238 {
2239 char *_tmp = cdio_lba_to_msf_str (image_size);
2240
2241 if (image_size > CDIO_CD_74MIN_SECTORS)
2242 vcd_warn ("generated image (%d sectors [%s]) may not fit "
2243 "on 74min CDRs (%d sectors)",
2244 (unsigned) image_size, _tmp, (unsigned) CDIO_CD_74MIN_SECTORS);
2245
2246 free (_tmp);
2247 }
2248
2249 return image_size;
2250 }
2251
2252 void
vcd_obj_end_output(VcdObj_t * p_obj)2253 vcd_obj_end_output (VcdObj_t *p_obj)
2254 {
2255 vcd_assert (p_obj != NULL);
2256
2257 vcd_assert (p_obj->in_output);
2258 p_obj->in_output = false;
2259
2260 _vcd_directory_destroy (p_obj->dir);
2261 _vcd_salloc_destroy (p_obj->iso_bitmap);
2262
2263 _dict_clean (p_obj);
2264 _cdio_list_free (p_obj->buffer_dict_list, true, (CdioDataFree_t) &dict_free);
2265 }
2266
2267 int
vcd_obj_append_pbc_node(VcdObj_t * p_obj,struct _pbc_t * p_pbc)2268 vcd_obj_append_pbc_node (VcdObj_t *p_obj, struct _pbc_t *p_pbc)
2269 {
2270 vcd_assert (p_obj != NULL);
2271 vcd_assert (p_pbc != NULL);
2272
2273 if (!_vcd_obj_has_cap_p (p_obj, _CAP_PBC))
2274 {
2275 vcd_error ("PBC not supported for current VCD type");
2276 return -1;
2277 }
2278
2279 if (p_pbc->item_id && _vcd_pbc_lookup (p_obj, p_pbc->item_id))
2280 {
2281 vcd_error ("item id (%s) exists already", p_pbc->item_id);
2282 return -1;
2283 }
2284
2285 _cdio_list_append (p_obj->pbc_list, p_pbc);
2286
2287 return 0;
2288 }
2289
2290 int
vcd_obj_write_image(VcdObj_t * p_obj,VcdImageSink_t * p_image_sink,progress_callback_t callback,void * user_data,const time_t * p_create_time)2291 vcd_obj_write_image (VcdObj_t *p_obj, VcdImageSink_t *p_image_sink,
2292 progress_callback_t callback, void *user_data,
2293 const time_t *p_create_time)
2294 {
2295 CdioListNode_t *node;
2296
2297 vcd_assert (p_obj != NULL);
2298 vcd_assert (p_obj->in_output);
2299
2300 if (!p_image_sink)
2301 return -1;
2302
2303 /* start with meta info */
2304
2305 {
2306 CdioList_t *p_cue_list;
2307 vcd_cue_t *p_cue;
2308
2309 p_cue_list = _cdio_list_new ();
2310
2311 _cdio_list_append (p_cue_list, (p_cue = calloc(1, sizeof (vcd_cue_t))));
2312
2313 p_cue->lsn = 0;
2314 p_cue->type = VCD_CUE_TRACK_START;
2315
2316 _CDIO_LIST_FOREACH (node, p_obj->mpeg_sequence_list)
2317 {
2318 mpeg_sequence_t *p_track = _cdio_list_node_data (node);
2319 CdioListNode_t *p_entry_node;
2320
2321 _cdio_list_append (p_cue_list,
2322 (p_cue = calloc(1, sizeof (vcd_cue_t))));
2323
2324 p_cue->lsn = p_track->relative_start_extent + p_obj->iso_size;
2325 p_cue->lsn -= p_obj->track_pregap;
2326 p_cue->type = VCD_CUE_PREGAP_START;
2327
2328 _cdio_list_append (p_cue_list,
2329 (p_cue = calloc(1, sizeof (vcd_cue_t))));
2330
2331 p_cue->lsn = p_track->relative_start_extent + p_obj->iso_size;
2332 p_cue->type = VCD_CUE_TRACK_START;
2333
2334 _CDIO_LIST_FOREACH (p_entry_node, p_track->entry_list)
2335 {
2336 entry_t *_entry = _cdio_list_node_data (p_entry_node);
2337
2338 _cdio_list_append (p_cue_list,
2339 (p_cue = calloc(1, sizeof (vcd_cue_t))));
2340
2341 p_cue->lsn = p_obj->iso_size;
2342 p_cue->lsn += p_track->relative_start_extent;
2343 p_cue->lsn += p_obj->track_front_margin;
2344 p_cue->lsn += _entry->aps.packet_no;
2345
2346 p_cue->type = VCD_CUE_SUBINDEX;
2347 }
2348 }
2349
2350 /* add last one... */
2351
2352 _cdio_list_append (p_cue_list, (p_cue = calloc(1, sizeof (vcd_cue_t))));
2353
2354 p_cue->lsn = p_obj->relative_end_extent + p_obj->iso_size;
2355
2356 p_cue->lsn += p_obj->leadout_pregap;
2357
2358 p_cue->type = VCD_CUE_END;
2359
2360 /* send it to image object */
2361
2362 vcd_image_sink_set_cuesheet (p_image_sink, p_cue_list);
2363
2364 _cdio_list_free (p_cue_list, true, (CdioDataFree_t) &cue_data_free);
2365 }
2366
2367 /* and now for the pay load */
2368
2369 {
2370 unsigned int track;
2371
2372 vcd_assert (p_obj != NULL);
2373 vcd_assert (p_obj->sectors_written == 0);
2374
2375 vcd_assert (p_obj->in_output);
2376
2377 p_obj->progress_callback = callback;
2378 p_obj->callback_user_data = user_data;
2379 p_obj->image_sink = p_image_sink;
2380
2381 if (_callback_wrapper (p_obj, true))
2382 return 1;
2383
2384 if (_write_vcd_iso_track (p_obj, p_create_time))
2385 return 1;
2386
2387 if (p_obj->update_scan_offsets)
2388 vcd_info ("'update scan offsets' option enabled for "
2389 "the following tracks!");
2390
2391 for (track = 0;
2392 track < _cdio_list_length (p_obj->mpeg_sequence_list);
2393 track++)
2394 {
2395 p_obj->in_track++;
2396
2397 if (_callback_wrapper (p_obj, true))
2398 return 1;
2399
2400 if (_write_sequence (p_obj, track))
2401 return 1;
2402 }
2403
2404 if (p_obj->leadout_pregap)
2405 {
2406 int n, lastsect = p_obj->sectors_written;
2407
2408 vcd_debug ("writting post-gap ('leadout pregap')...");
2409
2410 for (n = 0; n < p_obj->leadout_pregap; n++)
2411 _write_m2_image_sector (p_obj, zero, lastsect++, 0, 0, SM_FORM2, 0);
2412 }
2413
2414 if (_callback_wrapper (p_obj, true))
2415 return 1;
2416
2417 p_obj->image_sink = NULL;
2418
2419 vcd_image_sink_destroy (p_image_sink);
2420
2421 return 0; /* ok */
2422 }
2423 }
2424
2425 const char *
vcd_version_string(bool full_text)2426 vcd_version_string (bool full_text)
2427 {
2428 if (!full_text)
2429 return ("GNU VCDImager " VERSION " [" HOST_ARCH "]");
2430
2431 return ("%s (GNU VCDImager) " VERSION "\n"
2432 "Written by Herbert Valerio Riedel and Rocky Bernstein.\n"
2433 "\n"
2434 "http://www.gnu.org/software/vcdimager/\n"
2435 "\n"
2436 "Copyright (C) 2000-2003 Herbert Valerio Riedel <hvr@gnu.org>\n"
2437 " 2003 Rocky Bernstein <rocky@gnu.org>\n"
2438 "\n"
2439 "This is free software; see the source for copying conditions. There is NO\n"
2440 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
2441 }
2442
2443
2444 /*
2445 * Local variables:
2446 * c-file-style: "gnu"
2447 * tab-width: 8
2448 * indent-tabs-mode: nil
2449 * End:
2450 */
2451