diff options
Diffstat (limited to 'src/input/vcd/libvcd/vcd.c')
-rw-r--r-- | src/input/vcd/libvcd/vcd.c | 2412 |
1 files changed, 0 insertions, 2412 deletions
diff --git a/src/input/vcd/libvcd/vcd.c b/src/input/vcd/libvcd/vcd.c deleted file mode 100644 index 0772149ec..000000000 --- a/src/input/vcd/libvcd/vcd.c +++ /dev/null @@ -1,2412 +0,0 @@ -/* - $Id: vcd.c,v 1.4 2006/12/08 16:26:10 mshopf Exp $ - - Copyright (C) 2000, 2004 Herbert Valerio Riedel <hvr@gnu.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <math.h> - -#include <cdio/cdio.h> -#include <cdio/iso9660.h> - -/* public headers */ -#include <libvcd/types.h> -#include <libvcd/info.h> - -#include <libvcd/files.h> -#include <libvcd/sector.h> -#include <libvcd/logging.h> - -/* Private headers */ -#include "assert.h" -#include "dict.h" -#include "directory.h" -#include "obj.h" -#include "pbc.h" -#include "salloc.h" -#include "util.h" -#include "vcd.h" - -static const char _rcsid[] = "$Id: vcd.c,v 1.4 2006/12/08 16:26:10 mshopf Exp $"; - -static const char zero[CDIO_CD_FRAMESIZE_RAW] = { 0, }; - -#define DEFAULT_ISO_PREPARER_ID "GNU VCDImager " VERSION " " HOST_ARCH - -/* exported private functions - */ - -mpeg_sequence_t * -_vcd_obj_get_sequence_by_id (VcdObj *obj, const char sequence_id[]) -{ - CdioListNode *node; - - vcd_assert (sequence_id != NULL); - vcd_assert (obj != NULL); - - _CDIO_LIST_FOREACH (node, obj->mpeg_sequence_list) - { - mpeg_sequence_t *_sequence = _cdio_list_node_data (node); - - if (_sequence->id && !strcmp (sequence_id, _sequence->id)) - return _sequence; - } - - return NULL; -} - -mpeg_sequence_t * -_vcd_obj_get_sequence_by_entry_id (VcdObj *obj, const char entry_id[]) -{ - CdioListNode *node; - - vcd_assert (entry_id != NULL); - vcd_assert (obj != NULL); - - _CDIO_LIST_FOREACH (node, obj->mpeg_sequence_list) - { - mpeg_sequence_t *_sequence = _cdio_list_node_data (node); - CdioListNode *node2; - - /* default entry point */ - if (_sequence->default_entry_id - && !strcmp (entry_id, _sequence->default_entry_id)) - return _sequence; - - /* additional entry points */ - _CDIO_LIST_FOREACH (node2, _sequence->entry_list) - { - entry_t *_entry = _cdio_list_node_data (node2); - - if (_entry->id - && !strcmp (entry_id, _entry->id)) - return _sequence; - } - } - - /* not found */ - - return NULL; -} - -mpeg_segment_t * -_vcd_obj_get_segment_by_id (VcdObj *obj, const char segment_id[]) -{ - CdioListNode *node; - - vcd_assert (segment_id != NULL); - vcd_assert (obj != NULL); - - _CDIO_LIST_FOREACH (node, obj->mpeg_segment_list) - { - mpeg_segment_t *_segment = _cdio_list_node_data (node); - - if (_segment->id && !strcmp (segment_id, _segment->id)) - return _segment; - } - - return NULL; -} - -bool -_vcd_obj_has_cap_p (const VcdObj *obj, enum vcd_capability_t capability) -{ - switch (capability) - { - case _CAP_VALID: - switch (obj->type) - { - case VCD_TYPE_VCD: - case VCD_TYPE_VCD11: - case VCD_TYPE_VCD2: - case VCD_TYPE_SVCD: - case VCD_TYPE_HQVCD: - return true; - break; - - case VCD_TYPE_INVALID: - return false; - break; - } - break; - - case _CAP_MPEG2: - switch (obj->type) - { - case VCD_TYPE_VCD: - case VCD_TYPE_VCD11: - case VCD_TYPE_VCD2: - case VCD_TYPE_INVALID: - return false; - break; - - case VCD_TYPE_SVCD: - case VCD_TYPE_HQVCD: - return true; - break; - } - break; - - case _CAP_PBC: - switch (obj->type) - { - case VCD_TYPE_VCD: - case VCD_TYPE_VCD11: - case VCD_TYPE_INVALID: - return false; - break; - - case VCD_TYPE_VCD2: - case VCD_TYPE_SVCD: - case VCD_TYPE_HQVCD: - return true; - break; - } - break; - - case _CAP_PBC_X: - switch (obj->type) - { - case VCD_TYPE_VCD: - case VCD_TYPE_VCD11: - case VCD_TYPE_INVALID: - case VCD_TYPE_SVCD: - case VCD_TYPE_HQVCD: - return false; - break; - - case VCD_TYPE_VCD2: - return true; - break; - } - break; - - case _CAP_4C_SVCD: - switch (obj->type) - { - case VCD_TYPE_VCD: - case VCD_TYPE_VCD11: - case VCD_TYPE_INVALID: - case VCD_TYPE_VCD2: - return false; - break; - - case VCD_TYPE_SVCD: - case VCD_TYPE_HQVCD: - return true; - break; - } - break; - - case _CAP_PAL_BITS: - return _vcd_obj_has_cap_p (obj, _CAP_PBC); /* for now */ - break; - - case _CAP_MPEG1: - return !_vcd_obj_has_cap_p (obj, _CAP_MPEG2); /* for now */ - break; - - case _CAP_TRACK_MARGINS: - return !_vcd_obj_has_cap_p (obj, _CAP_MPEG2); /* for now */ - break; - } - - vcd_assert_not_reached (); - return false; -} - -/* - * public methods - */ - -VcdObj * -vcd_obj_new (vcd_type_t vcd_type) -{ - VcdObj *new_obj = NULL; - static bool _first = true; - - if (_first) - { -#if defined(_DEVELOPMENT_) - vcd_warn ("initializing libvcd %s [%s]", VERSION, HOST_ARCH); - vcd_warn (" "); - vcd_warn (" this is the UNSTABLE development branch!"); - vcd_warn (" use only if you know what you are doing"); - vcd_warn (" see http://www.hvrlab.org/~hvr/vcdimager/ for more information"); - vcd_warn (" "); -#else - vcd_debug ("initializing libvcd %s [%s]", VERSION, HOST_ARCH); -#endif - _first = false; - } - - new_obj = _vcd_malloc (sizeof (VcdObj)); - new_obj->type = vcd_type; - - if (!_vcd_obj_has_cap_p (new_obj, _CAP_VALID)) - { - vcd_error ("VCD type not supported"); - free (new_obj); - return NULL; - } - - if (vcd_type == VCD_TYPE_VCD) - vcd_warn ("VCD 1.0 support is experimental -- user feedback needed!"); - - new_obj->iso_volume_label = strdup (""); - new_obj->iso_publisher_id = strdup (""); - new_obj->iso_application_id = strdup (""); - new_obj->iso_preparer_id = _vcd_strdup_upper (DEFAULT_ISO_PREPARER_ID); - new_obj->info_album_id = strdup (""); - new_obj->info_volume_count = 1; - new_obj->info_volume_number = 1; - - new_obj->custom_file_list = _cdio_list_new (); - new_obj->custom_dir_list = _cdio_list_new (); - - - new_obj->mpeg_sequence_list = _cdio_list_new (); - - new_obj->mpeg_segment_list = _cdio_list_new (); - - new_obj->pbc_list = _cdio_list_new (); - - /* gap's defined by IEC-10149 / ECMA-130 */ - - /* pre-gap's for tracks but the first one */ - new_obj->track_pregap = CDIO_PREGAP_SECTORS; - /* post-gap after last track */ - new_obj->leadout_pregap = CDIO_POSTGAP_SECTORS; - - if (_vcd_obj_has_cap_p (new_obj, _CAP_TRACK_MARGINS)) - { - new_obj->track_front_margin = 30; - new_obj->track_rear_margin = 45; - } - else - { - new_obj->track_front_margin = 0; - new_obj->track_rear_margin = 0; - } - - return new_obj; -} - -int -vcd_obj_remove_item (VcdObj *obj, const char id[]) -{ - vcd_warn ("vcd_obj_remove_item('%s') not implemented yet!", id); - - return -1; -} - -static void -_vcd_obj_remove_mpeg_track (VcdObj *obj, int track_id) -{ - int length; - mpeg_sequence_t *track = NULL; - CdioListNode *node = NULL; - - vcd_assert (track_id >= 0); - - node = _vcd_list_at (obj->mpeg_sequence_list, track_id); - - vcd_assert (node != NULL); - - track = (mpeg_sequence_t *) _cdio_list_node_data (node); - - vcd_mpeg_source_destroy (track->source, true); - - length = track->info->packets; - length += obj->track_pregap + obj->track_front_margin + 0 + obj->track_rear_margin; - - /* fixup offsets */ - { - CdioListNode *node2 = node; - while ((node2 = _cdio_list_node_next (node2)) != NULL) - ((mpeg_sequence_t *) _cdio_list_node_data (node))->relative_start_extent -= length; - } - - obj->relative_end_extent -= length; - - /* shift up */ - _cdio_list_node_free (node, true); -} - -int -vcd_obj_append_segment_play_item (VcdObj *obj, VcdMpegSource *mpeg_source, - const char item_id[]) -{ - mpeg_segment_t *segment = NULL; - - vcd_assert (obj != NULL); - vcd_assert (mpeg_source != NULL); - - if (!_vcd_obj_has_cap_p (obj, _CAP_PBC)) - { - vcd_error ("segment play items not supported for this vcd type"); - return -1; - } - - if (!item_id) - { - vcd_error ("no id given for segment play item"); - return -1; - } - - if (_vcd_pbc_lookup (obj, item_id)) - { - vcd_error ("item id (%s) exists already", item_id); - return -1; - } - - vcd_info ("scanning mpeg segment item #%d for scanpoints...", - _cdio_list_length (obj->mpeg_segment_list)); - - vcd_mpeg_source_scan (mpeg_source, !obj->relaxed_aps, - obj->update_scan_offsets, NULL, NULL); - - if (vcd_mpeg_source_get_info (mpeg_source)->packets == 0) - { - vcd_error ("mpeg is empty?"); - return -1; - } - - /* create list node */ - - segment = _vcd_malloc (sizeof (mpeg_sequence_t)); - - segment->source = mpeg_source; - - segment->id = strdup (item_id); - - segment->info = vcd_mpeg_source_get_info (mpeg_source); - segment->segment_count = _vcd_len2blocks (segment->info->packets, 150); - - segment->pause_list = _cdio_list_new (); - - vcd_debug ("SPI length is %d sector(s), allocated %d segment(s)", - segment->info->packets, - segment->segment_count); - - _cdio_list_append (obj->mpeg_segment_list, segment); - - return 0; -} - -int -vcd_obj_append_sequence_play_item (VcdObj *obj, VcdMpegSource *mpeg_source, - const char item_id[], - const char default_entry_id[]) -{ - unsigned length; - mpeg_sequence_t *sequence = NULL; - int track_no = _cdio_list_length (obj->mpeg_sequence_list); - - vcd_assert (obj != NULL); - vcd_assert (mpeg_source != NULL); - - if (item_id && _vcd_pbc_lookup (obj, item_id)) - { - vcd_error ("item id (%s) exist already", item_id); - return -1; - } - - if (default_entry_id && _vcd_pbc_lookup (obj, default_entry_id)) - { - vcd_error ("default entry id (%s) exist already", default_entry_id); - return -1; - } - - if (default_entry_id && item_id && !strcmp (item_id, default_entry_id)) - { - vcd_error ("default entry id == item id (%s)", item_id); - return -1; - } - - vcd_info ("scanning mpeg sequence item #%d for scanpoints...", track_no); - vcd_mpeg_source_scan (mpeg_source, !obj->relaxed_aps, - obj->update_scan_offsets, NULL, NULL); - - sequence = _vcd_malloc (sizeof (mpeg_sequence_t)); - - sequence->source = mpeg_source; - - if (item_id) - sequence->id = strdup (item_id); - - if (default_entry_id) - sequence->default_entry_id = strdup (default_entry_id); - - sequence->info = vcd_mpeg_source_get_info (mpeg_source); - length = sequence->info->packets; - - sequence->entry_list = _cdio_list_new (); - sequence->pause_list = _cdio_list_new (); - - obj->relative_end_extent += obj->track_pregap; - sequence->relative_start_extent = obj->relative_end_extent; - - obj->relative_end_extent += obj->track_front_margin + length + obj->track_rear_margin; - - /* sanity checks */ - - if (length < 75) - vcd_warn ("mpeg stream shorter than 75 sectors"); - - if (!_vcd_obj_has_cap_p (obj, _CAP_PAL_BITS) - && vcd_mpeg_get_norm (&sequence->info->shdr[0]) != MPEG_NORM_FILM - && vcd_mpeg_get_norm (&sequence->info->shdr[0]) != MPEG_NORM_NTSC) - vcd_warn ("VCD 1.x should contain only NTSC/FILM video (may work with PAL nevertheless)"); - - if (!_vcd_obj_has_cap_p (obj, _CAP_MPEG1) - && sequence->info->version == MPEG_VERS_MPEG1) - vcd_warn ("this VCD type should not contain MPEG1 streams"); - - if (!_vcd_obj_has_cap_p (obj, _CAP_MPEG2) - && sequence->info->version == MPEG_VERS_MPEG2) - vcd_warn ("this VCD type should not contain MPEG2 streams"); - - if (!sequence->info->shdr[0].seen - || sequence->info->shdr[1].seen - || sequence->info->shdr[2].seen) - vcd_warn ("sequence items should contain a motion video stream!"); - - { - int i; - - for (i = 0; i < 3; i++) - { - if (sequence->info->ahdr[i].seen) - { - if (i && !_vcd_obj_has_cap_p (obj, _CAP_MPEG2)) - vcd_warn ("audio stream #%d not supported by this VCD type", i); - - if (sequence->info->ahdr[i].sampfreq != 44100) - vcd_warn ("audio stream #%d has sampling frequency %d Hz (should be 44100 Hz)", - i, sequence->info->ahdr[i].sampfreq); - - if (sequence->info->ahdr[i].layer != 2) - vcd_warn ("audio stream #%d is not layer II", i); - - if (_vcd_obj_has_cap_p (obj, _CAP_MPEG1) - && sequence->info->ahdr[i].bitrate != 224*1024) - vcd_warn ("audio stream #%d has bitrate %d kbps (should be 224 kbps for this vcd type)", - i, sequence->info->ahdr[i].bitrate); - } - else if (!i && !_vcd_obj_has_cap_p (obj, _CAP_MPEG2)) - { - vcd_warn ("this VCD type requires an audio stream to be present"); - } - } - } - - /* vcd_debug ("track# %d's detected playing time: %.2f seconds", */ - /* track_no, sequence->info->playing_time); */ - - _cdio_list_append (obj->mpeg_sequence_list, sequence); - - return track_no; -} - -static int -_pause_cmp (pause_t *ent1, pause_t *ent2) -{ - if (ent1->time < ent2->time) - return -1; - - if (ent1->time > ent2->time) - return 1; - - return 0; -} - -int -vcd_obj_add_sequence_pause (VcdObj *obj, const char sequence_id[], - double pause_time, const char pause_id[]) -{ - mpeg_sequence_t *_sequence; - - vcd_assert (obj != NULL); - - if (sequence_id) - _sequence = _vcd_obj_get_sequence_by_id (obj, sequence_id); - else - _sequence = - _cdio_list_node_data (_cdio_list_end (obj->mpeg_sequence_list)); - - if (!_sequence) - { - vcd_error ("sequence id `%s' not found", sequence_id); - return -1; - } - - if (pause_id) - vcd_warn ("pause id ignored..."); - - { - pause_t *_pause = _vcd_malloc (sizeof (pause_t)); - - if (pause_id) - _pause->id = strdup (pause_id); - _pause->time = pause_time; - - _cdio_list_append (_sequence->pause_list, _pause); - } - - _vcd_list_sort (_sequence->pause_list, - (_cdio_list_cmp_func) _pause_cmp); - - vcd_debug ("added autopause point at %f", pause_time); - - return 0; -} - -int -vcd_obj_add_segment_pause (VcdObj *obj, const char segment_id[], - double pause_time, const char pause_id[]) -{ - mpeg_segment_t *_segment; - - vcd_assert (obj != NULL); - - if (segment_id) - _segment = _vcd_obj_get_segment_by_id (obj, segment_id); - else - _segment = _cdio_list_node_data (_cdio_list_end (obj->mpeg_segment_list)); - - if (!_segment) - { - vcd_error ("segment id `%s' not found", segment_id); - return -1; - } - - if (pause_id) - vcd_warn ("pause id ignored..."); - - { - pause_t *_pause = _vcd_malloc (sizeof (pause_t)); - - if (pause_id) - _pause->id = strdup (pause_id); - _pause->time = pause_time; - - _cdio_list_append (_segment->pause_list, _pause); - } - - _vcd_list_sort (_segment->pause_list, - (_cdio_list_cmp_func) _pause_cmp); - - vcd_debug ("added autopause point at %f", pause_time); - - return 0; -} - -static int -_entry_cmp (entry_t *ent1, entry_t *ent2) -{ - if (ent1->time < ent2->time) - return -1; - - if (ent1->time > ent2->time) - return 1; - - return 0; -} - -int -vcd_obj_add_sequence_entry (VcdObj *obj, const char sequence_id[], - double entry_time, const char entry_id[]) -{ - mpeg_sequence_t *_sequence; - - vcd_assert (obj != NULL); - - if (sequence_id) - _sequence = _vcd_obj_get_sequence_by_id (obj, sequence_id); - else - _sequence = - _cdio_list_node_data (_cdio_list_end (obj->mpeg_sequence_list)); - - if (!_sequence) - { - vcd_error ("sequence id `%s' not found", sequence_id); - return -1; - } - - if (_cdio_list_length (_sequence->entry_list) >= MAX_SEQ_ENTRIES) - { - vcd_error ("only %d entries per sequence allowed!", MAX_SEQ_ENTRIES); - return -1; - } - - if (entry_id && _vcd_pbc_lookup (obj, entry_id)) - { - vcd_error ("item id (%s) exists already", entry_id); - return -1; - } - - { - entry_t *_entry = _vcd_malloc (sizeof (entry_t)); - - if (entry_id) - _entry->id = strdup (entry_id); - _entry->time = entry_time; - - _cdio_list_append (_sequence->entry_list, _entry); - } - - _vcd_list_sort (_sequence->entry_list, - (_cdio_list_cmp_func) _entry_cmp); - - return 0; -} - -void -vcd_obj_destroy (VcdObj *obj) -{ - CdioListNode *node; - - vcd_assert (obj != NULL); - vcd_assert (!obj->in_output); - - free (obj->iso_volume_label); - free (obj->iso_application_id); - - _CDIO_LIST_FOREACH (node, obj->custom_file_list) - { - custom_file_t *p = _cdio_list_node_data (node); - - free (p->iso_pathname); - } - - _cdio_list_free (obj->custom_file_list, true); - - _cdio_list_free (obj->custom_dir_list, true); - - while (_cdio_list_length (obj->mpeg_sequence_list)) - _vcd_obj_remove_mpeg_track (obj, 0); - _cdio_list_free (obj->mpeg_sequence_list, true); - - free (obj); -} - -int -vcd_obj_set_param_uint (VcdObj *obj, vcd_parm_t param, unsigned arg) -{ - vcd_assert (obj != NULL); - - switch (param) - { - case VCD_PARM_VOLUME_COUNT: - obj->info_volume_count = arg; - if (!IN (obj->info_volume_count, 1, 65535)) - { - obj->info_volume_count = CLAMP (obj->info_volume_count, 1, 65535); - vcd_warn ("volume count out of range, clamping to range"); - } - vcd_debug ("changed volume count to %u", obj->info_volume_count); - break; - - case VCD_PARM_VOLUME_NUMBER: - obj->info_volume_number = arg; - if (!IN (obj->info_volume_number, 0, 65534)) - { - obj->info_volume_number = CLAMP (obj->info_volume_number, 0, 65534); - vcd_warn ("volume number out of range, clamping to range"); - } - vcd_debug ("changed volume number to %u", obj->info_volume_number); - break; - - case VCD_PARM_RESTRICTION: - obj->info_restriction = arg; - if (!IN (obj->info_restriction, 0, 3)) - { - obj->info_restriction = CLAMP (obj->info_restriction, 0, 65534); - vcd_warn ("restriction out of range, clamping to range"); - } - vcd_debug ("changed restriction number to %u", obj->info_restriction); - break; - - case VCD_PARM_LEADOUT_PREGAP: - obj->leadout_pregap = arg; - if (!IN (obj->leadout_pregap, 0, 300)) - { - obj->leadout_pregap = CLAMP (obj->leadout_pregap, 0, 300); - vcd_warn ("ledout pregap out of range, clamping to allowed range"); - } - if (obj->leadout_pregap < CDIO_PREGAP_SECTORS) - vcd_warn ("track leadout pregap set below %d sectors; created (s)vcd may be non-working", - CDIO_PREGAP_SECTORS); - - vcd_debug ("changed leadout pregap to %u", obj->leadout_pregap); - break; - - case VCD_PARM_TRACK_PREGAP: - obj->track_pregap = arg; - if (!IN (obj->track_pregap, 1, 300)) - { - obj->track_pregap = CLAMP (obj->track_pregap, 1, 300); - vcd_warn ("track pregap out of range, clamping to allowed range"); - } - if (obj->track_pregap < CDIO_PREGAP_SECTORS) - vcd_warn ("track pre gap set below %d sectors; created (S)VCD may be non-working", - CDIO_PREGAP_SECTORS); - vcd_debug ("changed track pregap to %u", obj->track_pregap); - break; - - case VCD_PARM_TRACK_FRONT_MARGIN: - obj->track_front_margin = arg; - if (!IN (obj->track_front_margin, 0, CDIO_PREGAP_SECTORS)) - { - obj->track_front_margin = CLAMP (obj->track_front_margin, 0, - CDIO_PREGAP_SECTORS); - vcd_warn ("front margin out of range, clamping to allowed range"); - } - if (_vcd_obj_has_cap_p (obj, _CAP_TRACK_MARGINS) - && obj->track_front_margin < 15) - vcd_warn ("front margin set smaller than recommended (%d < 15 sectors) for disc type used", - obj->track_front_margin); - - vcd_debug ("changed front margin to %u", obj->track_front_margin); - break; - - case VCD_PARM_TRACK_REAR_MARGIN: - obj->track_rear_margin = arg; - if (!IN (obj->track_rear_margin, 0, CDIO_POSTGAP_SECTORS)) - { - obj->track_rear_margin = CLAMP (obj->track_rear_margin, 0, - CDIO_POSTGAP_SECTORS); - vcd_warn ("rear margin out of range, clamping to allowed range"); - } - if (_vcd_obj_has_cap_p (obj, _CAP_TRACK_MARGINS) - && obj->track_rear_margin < 15) - vcd_warn ("rear margin set smaller than recommended (%d < 15 sectors) for disc type used", - obj->track_rear_margin); - vcd_debug ("changed rear margin to %u", obj->track_rear_margin); - break; - - default: - vcd_assert_not_reached (); - break; - } - - return 0; -} - -int -vcd_obj_set_param_str (VcdObj *obj, vcd_parm_t param, const char *arg) -{ - vcd_assert (obj != NULL); - vcd_assert (arg != NULL); - - switch (param) - { - case VCD_PARM_VOLUME_ID: - free (obj->iso_volume_label); - obj->iso_volume_label = strdup (arg); - if (strlen (obj->iso_volume_label) > 32) - { - obj->iso_volume_label[32] = '\0'; - vcd_warn ("Volume label too long, will be truncated"); - } - vcd_debug ("changed volume label to `%s'", obj->iso_volume_label); - break; - - case VCD_PARM_PUBLISHER_ID: - free (obj->iso_publisher_id); - obj->iso_publisher_id = strdup (arg); - if (strlen (obj->iso_publisher_id) > 128) - { - obj->iso_publisher_id[128] = '\0'; - vcd_warn ("Publisher ID too long, will be truncated"); - } - vcd_debug ("changed publisher id to `%s'", obj->iso_publisher_id); - break; - - case VCD_PARM_PREPARER_ID: - free (obj->iso_preparer_id); - obj->iso_preparer_id = strdup (arg); - if (strlen (obj->iso_preparer_id) > 128) - { - obj->iso_preparer_id[128] = '\0'; - vcd_warn ("Preparer ID too long, will be truncated"); - } - vcd_debug ("changed preparer id to `%s'", obj->iso_preparer_id); - break; - - case VCD_PARM_APPLICATION_ID: - free (obj->iso_application_id); - obj->iso_application_id = strdup (arg); - if (strlen (obj->iso_application_id) > 128) - { - obj->iso_application_id[128] = '\0'; - vcd_warn ("Application ID too long, will be truncated"); - } - vcd_debug ("changed application id to `%s'", obj->iso_application_id); - break; - - case VCD_PARM_ALBUM_ID: - free (obj->info_album_id); - obj->info_album_id = strdup (arg); - if (strlen (obj->info_album_id) > 16) - { - obj->info_album_id[16] = '\0'; - vcd_warn ("Album ID too long, will be truncated"); - } - vcd_debug ("changed album id to `%s'", obj->info_album_id); - break; - - default: - vcd_assert_not_reached (); - break; - } - - return 0; -} - -int -vcd_obj_set_param_bool (VcdObj *obj, vcd_parm_t param, bool arg) -{ - vcd_assert (obj != NULL); - - switch (param) - { - case VCD_PARM_RELAXED_APS: - obj->relaxed_aps = arg ? true : false; - vcd_debug ("changing 'relaxed aps' to %d", obj->relaxed_aps); - break; - - case VCD_PARM_NEXT_VOL_LID2: - obj->info_use_lid2 = arg ? true : false; - vcd_debug ("changing 'next volume use lid 2' to %d", obj->info_use_lid2); - break; - - case VCD_PARM_NEXT_VOL_SEQ2: - obj->info_use_seq2 = arg ? true : false; - vcd_debug ("changing 'next volume use sequence 2' to %d", obj->info_use_seq2); - break; - - case VCD_PARM_SVCD_VCD3_MPEGAV: - if (obj->type == VCD_TYPE_SVCD) - { - if ((obj->svcd_vcd3_mpegav = arg ? true : false)) - vcd_warn ("!! enabling deprecated VCD3.0 MPEGAV folder --" - " SVCD will not be IEC62107 compliant !!"); - } - else - vcd_error ("parameter not applicable for vcd type"); - break; - - case VCD_PARM_SVCD_VCD3_ENTRYSVD: - if (obj->type == VCD_TYPE_SVCD) - { - if ((obj->svcd_vcd3_entrysvd = arg ? true : false)) - vcd_warn ("!! enabling deprecated VCD3.0 ENTRYSVD signature --" - " SVCD will not be IEC62107 compliant !!"); - } - else - vcd_error ("parameter not applicable for vcd type"); - break; - - case VCD_PARM_SVCD_VCD3_TRACKSVD: - if (obj->type == VCD_TYPE_SVCD) - { - if ((obj->svcd_vcd3_tracksvd = arg ? true : false)) - vcd_warn ("!! enabling deprecated VCD3.0 TRACK.SVD format --" - " SVCD will not be IEC62107 compliant !!"); - } - else - vcd_error ("parameter not applicable for vcd type"); - break; - - case VCD_PARM_UPDATE_SCAN_OFFSETS: - if (_vcd_obj_has_cap_p (obj, _CAP_4C_SVCD)) - { - obj->update_scan_offsets = arg ? true : false; - vcd_debug ("changing 'update scan offsets' to %d", obj->update_scan_offsets); - } - else - vcd_error ("parameter not applicable for vcd type"); - break; - - case VCD_PARM_LEADOUT_PAUSE: - vcd_warn ("use of 'leadout pause' is deprecated and may be removed in later releases;" - " use 'leadout pregap' instead"); - vcd_obj_set_param_uint (obj, VCD_PARM_LEADOUT_PREGAP, - (arg ? CDIO_PREGAP_SECTORS : 0)); - break; - - default: - vcd_assert_not_reached (); - break; - } - - return 0; -} - -int -vcd_obj_add_dir (VcdObj *obj, const char iso_pathname[]) -{ - char *_iso_pathname; - - vcd_assert (obj != NULL); - vcd_assert (iso_pathname != NULL); - - _iso_pathname = _vcd_strdup_upper (iso_pathname); - - if (!iso9660_dirname_valid_p (_iso_pathname)) - { - vcd_error("pathname `%s' is not a valid iso pathname", - _iso_pathname); - free (_iso_pathname); - return 1; - } - - _cdio_list_append (obj->custom_dir_list, _iso_pathname); - - _vcd_list_sort (obj->custom_dir_list, - (_cdio_list_cmp_func) strcmp); - - return 0; -} - -int -vcd_obj_add_file (VcdObj *obj, const char iso_pathname[], - VcdDataSource *file, bool raw_flag) -{ - uint32_t size = 0, sectors = 0; - - vcd_assert (obj != NULL); - vcd_assert (file != NULL); - vcd_assert (iso_pathname != NULL); - vcd_assert (strlen (iso_pathname) > 0); - vcd_assert (file != NULL); - - size = vcd_data_source_stat (file); - - /* close file to save file descriptors */ - vcd_data_source_close (file); - - if (raw_flag) - { - if (!size) - { - vcd_error("raw mode2 file must not be empty\n"); - return 1; - } - - sectors = size / M2RAW_SECTOR_SIZE; - - if (size % M2RAW_SECTOR_SIZE) - { - vcd_error("raw mode2 file must have size multiple of %d \n", - M2RAW_SECTOR_SIZE); - return 1; - } - } - else - sectors = _vcd_len2blocks (size, CDIO_CD_FRAMESIZE); - - { - custom_file_t *p; - char *_iso_pathname = _vcd_strdup_upper (iso_pathname); - - if (!iso9660_pathname_valid_p (_iso_pathname)) - { - vcd_error("pathname `%s' is not a valid iso pathname", - _iso_pathname); - free (_iso_pathname); - return 1; - } - - p = _vcd_malloc (sizeof (custom_file_t)); - - p->file = file; - p->iso_pathname = _iso_pathname; - p->raw_flag = raw_flag; - - p->size = size; - p->start_extent = 0; - p->sectors = sectors; - - _cdio_list_append (obj->custom_file_list, p); - } - - return 0; -} - -static void -_finalize_vcd_iso_track_allocation (VcdObj *obj) -{ - int n; - CdioListNode *node; - - uint32_t dir_secs = SECTOR_NIL; - - _dict_clean (obj); - - /* pre-alloc 16 blocks of ISO9660 required silence */ - if (_vcd_salloc (obj->iso_bitmap, 0, 16) == SECTOR_NIL) - vcd_assert_not_reached (); - - /* keep karaoke sectors blank -- well... guess I'm too paranoid :) */ - if (_vcd_salloc (obj->iso_bitmap, 75, 75) == SECTOR_NIL) - vcd_assert_not_reached (); - - /* pre-alloc descriptors, PVD */ - _dict_insert (obj, "pvd", ISO_PVD_SECTOR, 1, SM_EOR); /* EOR */ - /* EVD */ - _dict_insert (obj, "evd", ISO_EVD_SECTOR, 1, SM_EOR|SM_EOF); /* EOR+EOF */ - - /* reserve for iso directory */ - dir_secs = _vcd_salloc (obj->iso_bitmap, 18, 75-18); - - /* VCD information area */ - - _dict_insert (obj, "info", INFO_VCD_SECTOR, 1, SM_EOF); /* INFO.VCD */ /* EOF */ - _dict_insert (obj, "entries", ENTRIES_VCD_SECTOR, 1, SM_EOF); /* ENTRIES.VCD */ /* EOF */ - - /* PBC */ - - if (_vcd_pbc_available (obj)) - { - _dict_insert (obj, "lot", LOT_VCD_SECTOR, LOT_VCD_SIZE, SM_EOF); /* LOT.VCD */ /* EOF */ - _dict_insert (obj, "psd", PSD_VCD_SECTOR, - _vcd_len2blocks (get_psd_size (obj, false), ISO_BLOCKSIZE), SM_EOF); /* PSD.VCD */ /* EOF */ - } - - if (_vcd_obj_has_cap_p (obj, _CAP_4C_SVCD)) - { - _dict_insert (obj, "tracks", SECTOR_NIL, 1, SM_EOF); /* TRACKS.SVD */ - _dict_insert (obj, "search", SECTOR_NIL, - _vcd_len2blocks (get_search_dat_size (obj), ISO_BLOCKSIZE), SM_EOF); /* SEARCH.DAT */ - - vcd_assert (_dict_get_bykey (obj, "tracks")->sector > INFO_VCD_SECTOR); - vcd_assert (_dict_get_bykey (obj, "search")->sector > INFO_VCD_SECTOR); - } - - /* done with primary information area */ - - obj->mpeg_segment_start_extent = - _vcd_len2blocks (_vcd_salloc_get_highest (obj->iso_bitmap) + 1, 75) * 75; - - /* salloc up to end of vcd sector */ - for(n = 0;n < obj->mpeg_segment_start_extent;n++) - _vcd_salloc (obj->iso_bitmap, n, 1); - - vcd_assert (_vcd_salloc_get_highest (obj->iso_bitmap) + 1 == obj->mpeg_segment_start_extent); - - /* insert segments */ - - _CDIO_LIST_FOREACH (node, obj->mpeg_segment_list) - { - mpeg_segment_t *_segment = _cdio_list_node_data (node); - - _segment->start_extent = - _vcd_salloc (obj->iso_bitmap, SECTOR_NIL, - _segment->segment_count * VCDINFO_SEGMENT_SECTOR_SIZE); - - vcd_assert (_segment->start_extent % 75 == 0); - vcd_assert (_vcd_salloc_get_highest (obj->iso_bitmap) + 1 - == _segment->start_extent - + _segment->segment_count * VCDINFO_SEGMENT_SECTOR_SIZE); - } - - obj->ext_file_start_extent = _vcd_salloc_get_highest (obj->iso_bitmap) + 1; - - vcd_assert (obj->ext_file_start_extent % 75 == 0); - - /* go on with EXT area */ - - if (_vcd_obj_has_cap_p (obj, _CAP_4C_SVCD)) - { - _dict_insert (obj, "scandata", SECTOR_NIL, - _vcd_len2blocks (get_scandata_dat_size (obj), - ISO_BLOCKSIZE), - SM_EOF); - } - - if (_vcd_obj_has_cap_p (obj, _CAP_PBC_X) - &&_vcd_pbc_available (obj)) - { - _dict_insert (obj, "lot_x", SECTOR_NIL, LOT_VCD_SIZE, SM_EOF); - - _dict_insert (obj, "psd_x", SECTOR_NIL, - _vcd_len2blocks (get_psd_size (obj, true), ISO_BLOCKSIZE), - SM_EOF); - } - - - obj->custom_file_start_extent = - _vcd_salloc_get_highest (obj->iso_bitmap) + 1; - - /* now for the custom files */ - - _CDIO_LIST_FOREACH (node, obj->custom_file_list) - { - custom_file_t *p = _cdio_list_node_data (node); - - if (p->sectors) - { - p->start_extent = - _vcd_salloc(obj->iso_bitmap, SECTOR_NIL, p->sectors); - vcd_assert (p->start_extent != SECTOR_NIL); - } - else /* zero sized files -- set dummy extent */ - p->start_extent = obj->custom_file_start_extent; - } - - /* calculate iso size -- after this point no sector shall be - allocated anymore */ - - obj->iso_size = - MAX (MIN_ISO_SIZE, _vcd_salloc_get_highest (obj->iso_bitmap) + 1); - - vcd_debug ("iso9660: highest alloced sector is %lu (using %d as isosize)", - (unsigned long int) _vcd_salloc_get_highest (obj->iso_bitmap), - obj->iso_size); - - /* after this point the ISO9660's size is frozen */ -} - -static void -_finalize_vcd_iso_track_filesystem (VcdObj *obj) -{ - int n; - CdioListNode *node; - - /* create filesystem entries */ - - switch (obj->type) { - case VCD_TYPE_VCD: - case VCD_TYPE_VCD11: - case VCD_TYPE_VCD2: - /* add only necessary directories! */ - /* _vcd_directory_mkdir (obj->dir, "CDDA"); */ - /* _vcd_directory_mkdir (obj->dir, "CDI"); */ - _vcd_directory_mkdir (obj->dir, "EXT"); - /* _vcd_directory_mkdir (obj->dir, "KARAOKE"); */ - _vcd_directory_mkdir (obj->dir, "MPEGAV"); - _vcd_directory_mkdir (obj->dir, "VCD"); - - /* add segment dir only when there are actually segment play items */ - if (_cdio_list_length (obj->mpeg_segment_list)) - _vcd_directory_mkdir (obj->dir, "SEGMENT"); - - _vcd_directory_mkfile (obj->dir, "VCD/ENTRIES.VCD", - _dict_get_bykey (obj, "entries")->sector, - ISO_BLOCKSIZE, false, 0); - _vcd_directory_mkfile (obj->dir, "VCD/INFO.VCD", - _dict_get_bykey (obj, "info")->sector, - ISO_BLOCKSIZE, false, 0); - - /* only for vcd2.0 */ - if (_vcd_pbc_available (obj)) - { - _vcd_directory_mkfile (obj->dir, "VCD/LOT.VCD", - _dict_get_bykey (obj, "lot")->sector, - ISO_BLOCKSIZE*LOT_VCD_SIZE, false, 0); - _vcd_directory_mkfile (obj->dir, "VCD/PSD.VCD", - _dict_get_bykey (obj, "psd")->sector, - get_psd_size (obj, false), false, 0); - } - break; - - case VCD_TYPE_SVCD: - case VCD_TYPE_HQVCD: - _vcd_directory_mkdir (obj->dir, "EXT"); - - if (!obj->svcd_vcd3_mpegav) - _vcd_directory_mkdir (obj->dir, "MPEG2"); - else - { - vcd_warn ("adding MPEGAV dir for *DEPRECATED* SVCD VCD30 mode"); - _vcd_directory_mkdir (obj->dir, "MPEGAV"); - } - - /* add segment dir only when there are actually segment play items */ - if (_cdio_list_length (obj->mpeg_segment_list)) - _vcd_directory_mkdir (obj->dir, "SEGMENT"); - - _vcd_directory_mkdir (obj->dir, "SVCD"); - - _vcd_directory_mkfile (obj->dir, "SVCD/ENTRIES.SVD", - _dict_get_bykey (obj, "entries")->sector, - ISO_BLOCKSIZE, false, 0); - _vcd_directory_mkfile (obj->dir, "SVCD/INFO.SVD", - _dict_get_bykey (obj, "info")->sector, - ISO_BLOCKSIZE, false, 0); - - if (_vcd_pbc_available (obj)) - { - _vcd_directory_mkfile (obj->dir, "SVCD/LOT.SVD", - _dict_get_bykey (obj, "lot")->sector, - ISO_BLOCKSIZE*LOT_VCD_SIZE, false, 0); - _vcd_directory_mkfile (obj->dir, "SVCD/PSD.SVD", - _dict_get_bykey (obj, "psd")->sector, - get_psd_size (obj, false), false, 0); - } - - _vcd_directory_mkfile (obj->dir, "SVCD/SEARCH.DAT", - _dict_get_bykey (obj, "search")->sector, - get_search_dat_size (obj), false, 0); - _vcd_directory_mkfile (obj->dir, "SVCD/TRACKS.SVD", - _dict_get_bykey (obj, "tracks")->sector, - ISO_BLOCKSIZE, false, 0); - break; - - default: - vcd_assert_not_reached (); - break; - } - - /* SEGMENTS */ - - n = 1; - _CDIO_LIST_FOREACH (node, obj->mpeg_segment_list) - { - mpeg_segment_t *segment = _cdio_list_node_data (node); - char segment_pathname[128] = { 0, }; - const char *fmt = NULL; - uint8_t fnum = 0; - - switch (obj->type) - { - case VCD_TYPE_VCD2: - fmt = "SEGMENT/ITEM%4.4d.DAT"; - fnum = 1; - break; - case VCD_TYPE_SVCD: - case VCD_TYPE_HQVCD: - fmt = "SEGMENT/ITEM%4.4d.MPG"; - fnum = 0; - break; - default: - vcd_assert_not_reached (); - } - - snprintf (segment_pathname, sizeof (segment_pathname), fmt, n); - - _vcd_directory_mkfile (obj->dir, segment_pathname, segment->start_extent, - segment->info->packets * ISO_BLOCKSIZE, - true, fnum); - - vcd_assert (n <= MAX_SEGMENTS); - - n += segment->segment_count; - } - - /* EXT files */ - - if (_vcd_obj_has_cap_p (obj, _CAP_PBC_X) - &&_vcd_pbc_available (obj)) - { - /* psd_x -- extended PSD */ - _vcd_directory_mkfile (obj->dir, "EXT/PSD_X.VCD", - _dict_get_bykey (obj, "psd_x")->sector, - get_psd_size (obj, true), false, 1); - - /* lot_x -- extended LOT */ - _vcd_directory_mkfile (obj->dir, "EXT/LOT_X.VCD", - _dict_get_bykey (obj, "lot_x")->sector, - ISO_BLOCKSIZE*LOT_VCD_SIZE, false, 1); - - vcd_assert (obj->type == VCD_TYPE_VCD2); - } - - if (_vcd_obj_has_cap_p (obj, _CAP_4C_SVCD)) - { - /* scandata.dat -- scanpoints */ - _vcd_directory_mkfile (obj->dir, "EXT/SCANDATA.DAT", - _dict_get_bykey (obj, "scandata")->sector, - get_scandata_dat_size (obj), false, 0); - } - - /* custom files/dirs */ - _CDIO_LIST_FOREACH (node, obj->custom_dir_list) - { - char *p = _cdio_list_node_data (node); - _vcd_directory_mkdir (obj->dir, p); - } - - _CDIO_LIST_FOREACH (node, obj->custom_file_list) - { - custom_file_t *p = _cdio_list_node_data (node); - - _vcd_directory_mkfile (obj->dir, p->iso_pathname, p->start_extent, - (p->raw_flag - ? (ISO_BLOCKSIZE * (p->size / M2RAW_SECTOR_SIZE)) - : p->size), - p->raw_flag, 1); - } - - - n = 0; - _CDIO_LIST_FOREACH (node, obj->mpeg_sequence_list) - { - char avseq_pathname[128] = { 0, }; - const char *fmt = NULL; - mpeg_sequence_t *_sequence = _cdio_list_node_data (node); - uint32_t extent = _sequence->relative_start_extent; - uint8_t file_num = 0; - - extent += obj->iso_size; - - switch (obj->type) - { - case VCD_TYPE_VCD: - fmt = "MPEGAV/MUSIC%2.2d.DAT"; - file_num = n + 1; - break; - - case VCD_TYPE_VCD11: - case VCD_TYPE_VCD2: - fmt = "MPEGAV/AVSEQ%2.2d.DAT"; - file_num = n + 1; - break; - case VCD_TYPE_SVCD: - case VCD_TYPE_HQVCD: - fmt = "MPEG2/AVSEQ%2.2d.MPG"; - file_num = 0; - - /* if vcd3 compat mode, override */ - if (obj->svcd_vcd3_mpegav) - { - fmt = "MPEGAV/AVSEQ%2.2d.MPG"; - file_num = n + 1; - } - - break; - default: - vcd_assert_not_reached (); - } - - vcd_assert (n < 98); - - snprintf (avseq_pathname, sizeof (avseq_pathname), fmt, n + 1); - - /* file entry contains front margin, mpeg stream and rear margin */ - _vcd_directory_mkfile (obj->dir, avseq_pathname, extent, - (obj->track_front_margin - + _sequence->info->packets - + obj->track_rear_margin) * ISO_BLOCKSIZE, - true, file_num); - - n++; - } - - /* register isofs dir structures */ - { - uint32_t dirs_size = _vcd_directory_get_size (obj->dir); - - /* be sure to stay out of information areas */ - - switch (obj->type) - { - case VCD_TYPE_VCD: - case VCD_TYPE_VCD11: - case VCD_TYPE_VCD2: - /* karaoke area starts at 03:00 */ - if (16 + 2 + dirs_size + 2 >= 75) - vcd_error ("directory section to big for a VCD"); - break; - - case VCD_TYPE_SVCD: - case VCD_TYPE_HQVCD: - /* since no karaoke exists the next fixed area starts at 04:00 */ - if (16 + 2 + dirs_size + 2 >= 150) - vcd_error ("directory section to big for a SVCD"); - break; - default: - vcd_assert_not_reached (); - } - - /* un-alloc small area */ - - _vcd_salloc_free (obj->iso_bitmap, 18, dirs_size + 2); - - /* alloc it again! */ - - _dict_insert (obj, "dir", 18, dirs_size, SM_EOR|SM_EOF); - _dict_insert (obj, "ptl", 18 + dirs_size, 1, SM_EOR|SM_EOF); - _dict_insert (obj, "ptm", 18 + dirs_size + 1, 1, SM_EOR|SM_EOF); - } -} - -static void -_finalize_vcd_iso_track (VcdObj *obj) -{ - _vcd_pbc_finalize (obj); - _finalize_vcd_iso_track_allocation (obj); - _finalize_vcd_iso_track_filesystem (obj); -} - -static int -_callback_wrapper (VcdObj *obj, int force) -{ - const int cb_frequency = 75; - - if (obj->last_cb_call + cb_frequency > obj->sectors_written && !force) - return 0; - - obj->last_cb_call = obj->sectors_written; - - if (obj->progress_callback) { - progress_info_t _pi; - - _pi.sectors_written = obj->sectors_written; - _pi.total_sectors = obj->relative_end_extent + obj->iso_size; - _pi.in_track = obj->in_track; - _pi.total_tracks = _cdio_list_length (obj->mpeg_sequence_list) + 1; - - return obj->progress_callback (&_pi, obj->callback_user_data); - } - else - return 0; -} - -static int -_write_m2_image_sector (VcdObj *obj, const void *data, uint32_t extent, - uint8_t fnum, uint8_t cnum, uint8_t sm, uint8_t ci) -{ - char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, }; - - vcd_assert (extent == obj->sectors_written); - - _vcd_make_mode2(buf, data, extent, fnum, cnum, sm, ci); - - vcd_image_sink_write (obj->image_sink, buf, extent); - - obj->sectors_written++; - - return _callback_wrapper (obj, false); -} - -static int -_write_m2_raw_image_sector (VcdObj *obj, const void *data, uint32_t extent) -{ - char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, }; - - vcd_assert (extent == obj->sectors_written); - - _vcd_make_raw_mode2(buf, data, extent); - - vcd_image_sink_write (obj->image_sink, buf, extent); - - obj->sectors_written++; - - return _callback_wrapper (obj, false); -} - -static void -_write_source_mode2_raw (VcdObj *obj, VcdDataSource *source, uint32_t extent) -{ - int n; - uint32_t sectors; - - sectors = vcd_data_source_stat (source) / M2RAW_SECTOR_SIZE; - - vcd_data_source_seek (source, 0); - - for (n = 0;n < sectors;n++) { - char buf[M2RAW_SECTOR_SIZE] = { 0, }; - - vcd_data_source_read (source, buf, M2RAW_SECTOR_SIZE, 1); - - if (_write_m2_raw_image_sector (obj, buf, extent+n)) - break; - } - - vcd_data_source_close (source); -} - -static void -_write_source_mode2_form1 (VcdObj *obj, VcdDataSource *source, uint32_t extent) -{ - int n; - uint32_t sectors, size, last_block_size; - - size = vcd_data_source_stat (source); - - sectors = _vcd_len2blocks (size, CDIO_CD_FRAMESIZE); - - last_block_size = size % CDIO_CD_FRAMESIZE; - if (!last_block_size) - last_block_size = CDIO_CD_FRAMESIZE; - - vcd_data_source_seek (source, 0); - - for (n = 0;n < sectors;n++) { - char buf[CDIO_CD_FRAMESIZE] = { 0, }; - - vcd_data_source_read (source, buf, - ((n + 1 == sectors) - ? last_block_size - : CDIO_CD_FRAMESIZE), 1); - - if (_write_m2_image_sector (obj, buf, extent+n, 1, 0, - ((n+1 < sectors) - ? SM_DATA - : SM_DATA |SM_EOF), - 0)) - break; - } - - vcd_data_source_close (source); -} - -static int -_write_sequence (VcdObj *obj, int track_idx) -{ - mpeg_sequence_t *track = - _cdio_list_node_data (_vcd_list_at (obj->mpeg_sequence_list, track_idx)); - CdioListNode *pause_node; - int n, lastsect = obj->sectors_written; - char buf[2324]; - struct { - int audio; - int video; - int zero; - int ogt; - int unknown; - } mpeg_packets = {0, }; - - - { - char *norm_str = NULL; - const struct vcd_mpeg_stream_vid_info *_info = &track->info->shdr[0]; - - switch (vcd_mpeg_get_norm (_info)) { - case MPEG_NORM_PAL: - norm_str = strdup ("PAL SIF (352x288/25fps)"); - break; - case MPEG_NORM_NTSC: - norm_str = strdup ("NTSC SIF (352x240/29.97fps)"); - break; - case MPEG_NORM_FILM: - norm_str = strdup ("FILM SIF (352x240/24fps)"); - break; - case MPEG_NORM_PAL_S: - norm_str = strdup ("PAL 2/3 D1 (480x576/25fps)"); - break; - case MPEG_NORM_NTSC_S: - norm_str = strdup ("NTSC 2/3 D1 (480x480/29.97fps)"); - break; - - case MPEG_NORM_OTHER: - { - char buf[1024] = { 0, }; - switch (_info->vsize) - { - case 480: - case 240: - snprintf (buf, sizeof (buf), "NTSC UNKNOWN (%dx%d/%2.2ffps)", - _info->hsize, _info->vsize, _info->frate); - break; - case 288: - case 576: - snprintf (buf, sizeof (buf), "PAL UNKNOWN (%dx%d/%2.2ffps)", - _info->hsize, _info->vsize, _info->frate); - break; - default: - snprintf (buf, sizeof (buf), "UNKNOWN (%dx%d/%2.2ffps)", - _info->hsize, _info->vsize, _info->frate); - break; - } - norm_str = strdup (buf); - } - break; - } - - { - char buf[1024] = { 0, }, buf2[1024] = { 0, }; - int i; - - for (i = 0; i < 3; i++) - if (track->info->ahdr[i].seen) - { - const char *_mode_str[] = { - 0, - "stereo", - "jstereo", - "dual", - "single", - 0 - }; - - snprintf (buf, sizeof (buf), "audio[%d]: l%d/%2.1fkHz/%dkbps/%s ", - i, - track->info->ahdr[i].layer, - track->info->ahdr[i].sampfreq / 1000.0, - track->info->ahdr[i].bitrate / 1024, - _mode_str[track->info->ahdr[i].mode]); - - strncat (buf2, buf, sizeof(buf2) - strlen(buf2) - 1); - } - - vcd_info ("writing track %d, %s, %s, %s...", track_idx + 2, - (track->info->version == MPEG_VERS_MPEG1 ? "MPEG1" : "MPEG2"), - norm_str, buf2); - } - - free (norm_str); - } - - for (n = 0; n < obj->track_pregap; n++) - _write_m2_image_sector (obj, zero, lastsect++, 0, 0, SM_FORM2, 0); - - for (n = 0; n < obj->track_front_margin;n++) - _write_m2_image_sector (obj, zero, lastsect++, track_idx + 1, - 0, SM_FORM2|SM_REALT, 0); - - pause_node = _cdio_list_begin (track->pause_list); - - for (n = 0; n < track->info->packets; n++) { - int ci = 0, sm = 0, cnum = 0, fnum = 0; - struct vcd_mpeg_packet_info pkt_flags; - bool set_trigger = false; - - vcd_mpeg_source_get_packet (track->source, n, buf, &pkt_flags, - obj->update_scan_offsets); - - while (pause_node) - { - pause_t *_pause = _cdio_list_node_data (pause_node); - - if (!pkt_flags.has_pts) - break; /* no pts */ - - if (pkt_flags.pts < _pause->time) - break; /* our time has not come yet */ - - /* seems it's time to trigger! */ - set_trigger = true; - - vcd_debug ("setting auto pause trigger for time %f (pts %f) @%d", - _pause->time, pkt_flags.pts, n); - - pause_node = _cdio_list_node_next (pause_node); - } - - switch (vcd_mpeg_packet_get_type (&pkt_flags)) - { - case PKT_TYPE_VIDEO: - mpeg_packets.video++; - sm = SM_FORM2|SM_REALT|SM_VIDEO; - ci = CI_VIDEO; - cnum = CN_VIDEO; - break; - - case PKT_TYPE_OGT: - mpeg_packets.ogt++; - sm = SM_FORM2|SM_REALT|SM_VIDEO; - ci = CI_OGT; - cnum = CN_OGT; - break; - - case PKT_TYPE_AUDIO: - mpeg_packets.audio++; - sm = SM_FORM2|SM_REALT|SM_AUDIO; - ci = CI_AUDIO; - cnum = CN_AUDIO; - if (pkt_flags.audio[1] || pkt_flags.audio[2]) - { - ci = CI_AUDIO2; - cnum = CN_AUDIO2; - } - break; - - - case PKT_TYPE_ZERO: - mpeg_packets.zero++; - mpeg_packets.unknown--; - case PKT_TYPE_EMPTY: - mpeg_packets.unknown++; - sm = SM_FORM2|SM_REALT; - ci = CI_EMPTY; - cnum = CN_EMPTY; - break; - - case PKT_TYPE_INVALID: - vcd_error ("invalid mpeg packet found at packet# %d" - " -- please fix this mpeg file!", n); - vcd_mpeg_source_close (track->source); - return 1; - break; - - default: - vcd_assert_not_reached (); - } - - if (n == track->info->packets - 1) - { - sm |= SM_EOR; - if (!obj->track_rear_margin) /* if no rear margin... */ - sm |= SM_EOF; - } - - if (set_trigger) - sm |= SM_TRIG; - - fnum = track_idx + 1; - - if (_vcd_obj_has_cap_p (obj, _CAP_4C_SVCD) - && !obj->svcd_vcd3_mpegav) /* IEC62107 SVCDs have a - simplified subheader */ - { - fnum = 1; - ci = CI_MPEG2; - } - - if (_write_m2_image_sector (obj, buf, lastsect++, fnum, cnum, sm, ci)) - break; - } - - vcd_mpeg_source_close (track->source); - - for (n = 0; n < obj->track_rear_margin; n++) - { - const uint8_t ci = 0, cnum = 0; - uint8_t fnum = track_idx + 1; - uint8_t sm = SM_FORM2 | SM_REALT; - - if (n + 1 == obj->track_rear_margin) - sm |= SM_EOF; - - _write_m2_image_sector (obj, zero, lastsect++, fnum, cnum, sm, ci); - } - - vcd_debug ("MPEG packet statistics: %d video, %d audio, %d zero, %d ogt, %d unknown", - mpeg_packets.video, mpeg_packets.audio, mpeg_packets.zero, mpeg_packets.ogt, - mpeg_packets.unknown); - - return 0; -} - -static int -_write_segment (VcdObj *obj, mpeg_segment_t *_segment) -{ - CdioListNode *pause_node; - unsigned packet_no; - int n = obj->sectors_written; - - vcd_assert (_segment->start_extent == n); - - pause_node = _cdio_list_begin (_segment->pause_list); - - for (packet_no = 0; - packet_no < (_segment->segment_count * VCDINFO_SEGMENT_SECTOR_SIZE); - packet_no++) - { - uint8_t buf[M2F2_SECTOR_SIZE] = { 0, }; - uint8_t fn, cn, sm, ci; - - if (packet_no < _segment->info->packets) - { - struct vcd_mpeg_packet_info pkt_flags; - bool set_trigger = false; - bool _need_eor = false; - - vcd_mpeg_source_get_packet (_segment->source, packet_no, - buf, &pkt_flags, obj->update_scan_offsets); - - fn = 1; - cn = CN_EMPTY; - sm = SM_FORM2 | SM_REALT; - ci = CI_EMPTY; - - while (pause_node) - { - pause_t *_pause = _cdio_list_node_data (pause_node); - - if (!pkt_flags.has_pts) - break; /* no pts */ - - if (pkt_flags.pts < _pause->time) - break; /* our time has not come yet */ - - /* seems it's time to trigger! */ - set_trigger = true; - - vcd_debug ("setting auto pause trigger for time %f (pts %f) @%d", - _pause->time, pkt_flags.pts, n); - - pause_node = _cdio_list_node_next (pause_node); - } - - switch (vcd_mpeg_packet_get_type (&pkt_flags)) - { - case PKT_TYPE_VIDEO: - sm = SM_FORM2 | SM_REALT | SM_VIDEO; - - ci = CI_VIDEO; - cn = CN_VIDEO; - - if (pkt_flags.video[1]) - ci = CI_STILL, cn = CN_STILL; - else if (pkt_flags.video[2]) - ci = CI_STILL2, cn = CN_STILL2; - - if (pkt_flags.video[1] || pkt_flags.video[2]) - { /* search for endcode -- hack */ - int idx; - - for (idx = 0; idx <= 2320; idx++) - if (buf[idx] == 0x00 - && buf[idx + 1] == 0x00 - && buf[idx + 2] == 0x01 - && buf[idx + 3] == 0xb7) - { - _need_eor = true; - break; - } - } - break; - - case PKT_TYPE_AUDIO: - sm = SM_FORM2 | SM_REALT | SM_AUDIO; - - ci = CI_AUDIO; - cn = CN_AUDIO; - break; - - case PKT_TYPE_EMPTY: - ci = CI_EMPTY; - cn = CN_EMPTY; - break; - - default: - /* fixme -- check.... */ - break; - } - - if (_vcd_obj_has_cap_p (obj, _CAP_4C_SVCD)) - { - cn = 1; - sm = SM_FORM2 | SM_REALT | SM_VIDEO; - ci = CI_MPEG2; - } - - if (packet_no + 1 == _segment->info->packets) - sm |= SM_EOF; - - if (set_trigger) - sm |= SM_TRIG; - - if (_need_eor) - { - vcd_debug ("setting EOR for SeqEnd at packet# %d ('%s')", - packet_no, _segment->id); - sm |= SM_EOR; - } - } - else - { - fn = 1; - cn = CN_EMPTY; - sm = SM_FORM2 | SM_REALT; - ci = CI_EMPTY; - - if (_vcd_obj_has_cap_p (obj, _CAP_4C_SVCD)) - { - fn = 0; - sm = SM_FORM2; - } - - } - - _write_m2_image_sector (obj, buf, n, fn, cn, sm, ci); - - n++; - } - - vcd_mpeg_source_close (_segment->source); - - return 0; -} - -static uint32_t -_get_closest_aps (const struct vcd_mpeg_stream_info *_mpeg_info, double t, - struct aps_data *_best_aps) -{ - CdioListNode *node; - struct aps_data best_aps; - bool first = true; - - vcd_assert (_mpeg_info != NULL); - vcd_assert (_mpeg_info->shdr[0].aps_list != NULL); - - _CDIO_LIST_FOREACH (node, _mpeg_info->shdr[0].aps_list) - { - struct aps_data *_aps = _cdio_list_node_data (node); - - if (first) - { - best_aps = *_aps; - first = false; - } - else if (fabs (_aps->timestamp - t) < fabs (best_aps.timestamp - t)) - best_aps = *_aps; - else - break; - } - - if (_best_aps) - *_best_aps = best_aps; - - return best_aps.packet_no; -} - -static void -_update_entry_points (VcdObj *obj) -{ - CdioListNode *sequence_node; - - _CDIO_LIST_FOREACH (sequence_node, obj->mpeg_sequence_list) - { - mpeg_sequence_t *_sequence = _cdio_list_node_data (sequence_node); - CdioListNode *entry_node; - unsigned last_packet_no = 0; - - _CDIO_LIST_FOREACH (entry_node, _sequence->entry_list) - { - entry_t *_entry = _cdio_list_node_data (entry_node); - - _get_closest_aps (_sequence->info, _entry->time, &_entry->aps); - - vcd_log ((fabs (_entry->aps.timestamp - _entry->time) > 1 - ? VCD_LOG_WARN - : VCD_LOG_DEBUG), - "requested entry point (id=%s) at %f, " - "closest possible entry point at %f", - _entry->id, _entry->time, _entry->aps.timestamp); - - if (last_packet_no == _entry->aps.packet_no) - vcd_warn ("entry point '%s' falls into same sector as previous one!", - _entry->id); - - last_packet_no = _entry->aps.packet_no; - } - } -} - -static int -_write_vcd_iso_track (VcdObj *obj, const time_t *create_time) -{ - CdioListNode *node; - int n; - - /* generate dir sectors */ - - _vcd_directory_dump_entries (obj->dir, - _dict_get_bykey (obj, "dir")->buf, - _dict_get_bykey (obj, "dir")->sector); - - _vcd_directory_dump_pathtables (obj->dir, - _dict_get_bykey (obj, "ptl")->buf, - _dict_get_bykey (obj, "ptm")->buf); - - /* generate PVD and EVD at last... */ - iso9660_set_pvd (_dict_get_bykey (obj, "pvd")->buf, - obj->iso_volume_label, - obj->iso_publisher_id, - obj->iso_preparer_id, - obj->iso_application_id, - obj->iso_size, - _dict_get_bykey (obj, "dir")->buf, - _dict_get_bykey (obj, "ptl")->sector, - _dict_get_bykey (obj, "ptm")->sector, - iso9660_pathtable_get_size (_dict_get_bykey (obj, "ptm")->buf), - create_time -); - - iso9660_set_evd (_dict_get_bykey (obj, "evd")->buf); - - /* fill VCD relevant files with data */ - - set_info_vcd (obj, _dict_get_bykey (obj, "info")->buf); - set_entries_vcd (obj, _dict_get_bykey (obj, "entries")->buf); - - if (_vcd_pbc_available (obj)) - { - if (_vcd_obj_has_cap_p (obj, _CAP_PBC_X)) - { - set_lot_vcd (obj, _dict_get_bykey (obj, "lot_x")->buf, true); - set_psd_vcd (obj, _dict_get_bykey (obj, "psd_x")->buf, true); - } - - _vcd_pbc_check_unreferenced (obj); - - set_lot_vcd (obj, _dict_get_bykey (obj, "lot")->buf, false); - set_psd_vcd (obj, _dict_get_bykey (obj, "psd")->buf, false); - } - - if (_vcd_obj_has_cap_p (obj, _CAP_4C_SVCD)) - { - set_tracks_svd (obj, _dict_get_bykey (obj, "tracks")->buf); - set_search_dat (obj, _dict_get_bykey (obj, "search")->buf); - set_scandata_dat (obj, _dict_get_bykey (obj, "scandata")->buf); - } - - /* start actually writing stuff */ - - vcd_info ("writing track 1 (ISO9660)..."); - - /* 00:02:00 -> 00:04:74 */ - for (n = 0;n < obj->mpeg_segment_start_extent; n++) - { - const void *content = NULL; - uint8_t flags = SM_DATA; - - content = _dict_get_sector (obj, n); - flags |= _dict_get_sector_flags (obj, n); - - if (content == NULL) - content = zero; - - _write_m2_image_sector (obj, content, n, 0, 0, flags, 0); - } - - /* SEGMENTS */ - - vcd_assert (n == obj->mpeg_segment_start_extent); - - _CDIO_LIST_FOREACH (node, obj->mpeg_segment_list) - { - mpeg_segment_t *_segment = _cdio_list_node_data (node); - - _write_segment (obj, _segment); - } - - n = obj->sectors_written; - - /* EXT stuff */ - - vcd_assert (n == obj->ext_file_start_extent); - - for (;n < obj->custom_file_start_extent; n++) - { - const void *content = NULL; - uint8_t flags = SM_DATA; - uint8_t fileno = _vcd_obj_has_cap_p (obj, _CAP_4C_SVCD) ? 0 : 1; - - content = _dict_get_sector (obj, n); - flags |= _dict_get_sector_flags (obj, n); - - if (content == NULL) - { - vcd_debug ("unexpected empty EXT sector"); - content = zero; - } - - _write_m2_image_sector (obj, content, n, fileno, 0, flags, 0); - } - - /* write custom files */ - - vcd_assert (n == obj->custom_file_start_extent); - - _CDIO_LIST_FOREACH (node, obj->custom_file_list) - { - custom_file_t *p = _cdio_list_node_data (node); - - vcd_info ("writing file `%s' (%lu bytes%s)", - p->iso_pathname, (unsigned long) p->size, - p->raw_flag ? ", raw sectors file": ""); - if (p->raw_flag) - _write_source_mode2_raw (obj, p->file, p->start_extent); - else - _write_source_mode2_form1 (obj, p->file, p->start_extent); - } - - /* blank unalloced tracks */ - while ((n = _vcd_salloc (obj->iso_bitmap, SECTOR_NIL, 1)) < obj->iso_size) - _write_m2_image_sector (obj, zero, n, 0, 0, SM_DATA, 0); - - return 0; -} - - -long -vcd_obj_get_image_size (VcdObj *obj) -{ - long size_sectors = -1; - - vcd_assert (!obj->in_output); - - if (_cdio_list_length (obj->mpeg_sequence_list) > 0) - { - /* fixme -- make this efficient */ - size_sectors = vcd_obj_begin_output (obj); - vcd_obj_end_output (obj); - } - - return size_sectors; -} - -long -vcd_obj_begin_output (VcdObj *obj) -{ - uint32_t image_size; - - vcd_assert (obj != NULL); - vcd_assert (_cdio_list_length (obj->mpeg_sequence_list) > 0); - - vcd_assert (!obj->in_output); - obj->in_output = true; - - obj->in_track = 1; - obj->sectors_written = 0; - - obj->iso_bitmap = _vcd_salloc_new (); - - obj->dir = _vcd_directory_new (); - - obj->buffer_dict_list = _cdio_list_new (); - - _finalize_vcd_iso_track (obj); - - _update_entry_points (obj); - - image_size = obj->relative_end_extent + obj->iso_size; - - image_size += obj->leadout_pregap; - - if (image_size > CDIO_CD_MAX_SECTORS) - vcd_error ("image too big (%d sectors > %d sectors)", - (unsigned) image_size, (unsigned) CDIO_CD_MAX_SECTORS); - - { - char *_tmp = cdio_lba_to_msf_str (image_size); - - if (image_size > CDIO_CD_74MIN_SECTORS) - vcd_warn ("generated image (%d sectors [%s]) may not fit " - "on 74min CDRs (%d sectors)", - (unsigned) image_size, _tmp, (unsigned) CDIO_CD_74MIN_SECTORS); - - free (_tmp); - } - - return image_size; -} - - -void -vcd_obj_end_output (VcdObj *obj) -{ - vcd_assert (obj != NULL); - - vcd_assert (obj->in_output); - obj->in_output = false; - - _vcd_directory_destroy (obj->dir); - _vcd_salloc_destroy (obj->iso_bitmap); - - _dict_clean (obj); - _cdio_list_free (obj->buffer_dict_list, true); -} - -int -vcd_obj_append_pbc_node (VcdObj *obj, struct _pbc_t *_pbc) -{ - vcd_assert (obj != NULL); - vcd_assert (_pbc != NULL); - - if (!_vcd_obj_has_cap_p (obj, _CAP_PBC)) - { - vcd_error ("PBC not supported for current VCD type"); - return -1; - } - - if (_pbc->item_id && _vcd_pbc_lookup (obj, _pbc->item_id)) - { - vcd_error ("item id (%s) exists already", _pbc->item_id); - return -1; - } - - _cdio_list_append (obj->pbc_list, _pbc); - - return 0; -} - -int -vcd_obj_write_image (VcdObj *obj, VcdImageSink *image_sink, - progress_callback_t callback, void *user_data, - const time_t *create_time) -{ - CdioListNode *node; - - vcd_assert (obj != NULL); - vcd_assert (obj->in_output); - - if (!image_sink) - return -1; - - /* start with meta info */ - - { - CdioList *cue_list; - vcd_cue_t *_cue; - - cue_list = _cdio_list_new (); - - _cdio_list_append (cue_list, (_cue = _vcd_malloc (sizeof (vcd_cue_t)))); - - _cue->lsn = 0; - _cue->type = VCD_CUE_TRACK_START; - - _CDIO_LIST_FOREACH (node, obj->mpeg_sequence_list) - { - mpeg_sequence_t *track = _cdio_list_node_data (node); - CdioListNode *entry_node; - - _cdio_list_append (cue_list, - (_cue = _vcd_malloc (sizeof (vcd_cue_t)))); - - _cue->lsn = track->relative_start_extent + obj->iso_size; - _cue->lsn -= obj->track_pregap; - _cue->type = VCD_CUE_PREGAP_START; - - _cdio_list_append (cue_list, - (_cue = _vcd_malloc (sizeof (vcd_cue_t)))); - - _cue->lsn = track->relative_start_extent + obj->iso_size; - _cue->type = VCD_CUE_TRACK_START; - - _CDIO_LIST_FOREACH (entry_node, track->entry_list) - { - entry_t *_entry = _cdio_list_node_data (entry_node); - - _cdio_list_append (cue_list, - (_cue = _vcd_malloc (sizeof (vcd_cue_t)))); - - _cue->lsn = obj->iso_size; - _cue->lsn += track->relative_start_extent; - _cue->lsn += obj->track_front_margin; - _cue->lsn += _entry->aps.packet_no; - - _cue->type = VCD_CUE_SUBINDEX; - } - } - - /* add last one... */ - - _cdio_list_append (cue_list, (_cue = _vcd_malloc (sizeof (vcd_cue_t)))); - - _cue->lsn = obj->relative_end_extent + obj->iso_size; - - _cue->lsn += obj->leadout_pregap; - - _cue->type = VCD_CUE_END; - - /* send it to image object */ - - vcd_image_sink_set_cuesheet (image_sink, cue_list); - - _cdio_list_free (cue_list, true); - } - - /* and now for the pay load */ - - { - unsigned track; - - vcd_assert (obj != NULL); - vcd_assert (obj->sectors_written == 0); - - vcd_assert (obj->in_output); - - obj->progress_callback = callback; - obj->callback_user_data = user_data; - obj->image_sink = image_sink; - - if (_callback_wrapper (obj, true)) - return 1; - - if (_write_vcd_iso_track (obj, create_time)) - return 1; - - if (obj->update_scan_offsets) - vcd_info ("'update scan offsets' option enabled for the following tracks!"); - - for (track = 0;track < _cdio_list_length (obj->mpeg_sequence_list);track++) - { - obj->in_track++; - - if (_callback_wrapper (obj, true)) - return 1; - - if (_write_sequence (obj, track)) - return 1; - } - - if (obj->leadout_pregap) - { - int n, lastsect = obj->sectors_written; - - vcd_debug ("writting post-gap ('leadout pregap')..."); - - for (n = 0; n < obj->leadout_pregap; n++) - _write_m2_image_sector (obj, zero, lastsect++, 0, 0, SM_FORM2, 0); - } - - if (_callback_wrapper (obj, true)) - return 1; - - obj->image_sink = NULL; - - vcd_image_sink_destroy (image_sink); - - return 0; /* ok */ - } -} - -const char * -vcd_version_string (bool full_text) -{ - if (!full_text) - return ("GNU VCDImager " VERSION " [" HOST_ARCH "]"); - - return ("%s (GNU VCDImager) " VERSION "\n" - "Written by Herbert Valerio Riedel and Rocky Bernstein.\n" - "\n" - "http://www.gnu.org/software/vcdimager/\n" - "\n" - "Copyright (C) 2000-2003 Herbert Valerio Riedel <hvr@gnu.org>\n" - " 2003 Rocky Bernstein <rocky@panix.com>\n" - "\n" - "This is free software; see the source for copying conditions. There is NO\n" - "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"); -} - - -/* - * Local variables: - * c-file-style: "gnu" - * tab-width: 8 - * indent-tabs-mode: nil - * End: - */ |