📄 vcd.c
字号:
/* $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);}intvcd_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;}intvcd_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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -