📄 vcdplayer.c
字号:
/* $Id: vcdplayer.c,v 1.20 2007/02/21 23:17:14 dgp85 Exp $ Copyright (C) 2002, 2003, 2004, 2005 Rocky Bernstein <rocky@panix.com> 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/* Standard includes */#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <unistd.h>#include <time.h>#include <string.h>#ifdef HAVE_STRINGS_H#include <strings.h>#endif#include <errno.h>#ifdef HAVE_VCDNAV#include <libvcd/files.h>#include <cdio/iso9660.h>#else#include "libvcd/files.h"#include "cdio/iso9660.h"#endif#include "vcdplayer.h"#include "vcdio.h"/* This function is _not_ exported by libvcd, its usage should be avoided, most * likely. */void vcdinfo_get_seg_resolution(const vcdinfo_obj_t *p_vcdinfo, segnum_t i_seg, /*out*/ uint16_t *max_x, /*out*/ uint16_t *max_y);#define LOG_ERR(p_vcdplayer, s, args...) \ if (p_vcdplayer != NULL && p_vcdplayer->log_err != NULL) \ p_vcdplayer->log_err("%s: "s, __func__ , ##args)unsigned long int vcdplayer_debug = 0;static void _vcdplayer_set_origin(vcdplayer_t *p_vcdplayer);/*! Return true if playback control (PBC) is on*/boolvcdplayer_pbc_is_on(const vcdplayer_t *p_vcdplayer) { return VCDINFO_INVALID_ENTRY != p_vcdplayer->i_lid; }/* Given an itemid, return the size for the object (via information previously stored when opening the vcd). */static size_t_vcdplayer_get_item_size(vcdplayer_t *p_vcdplayer, vcdinfo_itemid_t itemid) { switch (itemid.type) { case VCDINFO_ITEM_TYPE_ENTRY: return p_vcdplayer->entry[itemid.num].size; break; case VCDINFO_ITEM_TYPE_SEGMENT: return p_vcdplayer->segment[itemid.num].size; break; case VCDINFO_ITEM_TYPE_TRACK: return p_vcdplayer->track[itemid.num-1].size; break; case VCDINFO_ITEM_TYPE_LID: /* Play list number (LID) */ return 0; break; case VCDINFO_ITEM_TYPE_NOTFOUND: case VCDINFO_ITEM_TYPE_SPAREID2: default: LOG_ERR(p_vcdplayer, "%s %d\n", _("bad item type"), itemid.type); return 0; }}#define add_format_str_info(val) \ { \ const char *str = val; \ unsigned int len; \ if (val != NULL) { \ len=strlen(str); \ if (len != 0) { \ strncat(tp, str, TEMP_STR_LEN-(tp-temp_str)); \ tp += len; \ } \ saw_control_prefix = false; \ } \ }#define add_format_num_info(val, fmt) \ { \ char num_str[10]; \ unsigned int len; \ snprintf(num_str, sizeof(num_str), fmt, val); \ len=strlen(num_str); \ if (len != 0) { \ strncat(tp, num_str, TEMP_STR_LEN-(tp-temp_str)); \ tp += len; \ } \ saw_control_prefix = false; \ }/*! Take a format string and expand escape sequences, that is sequences that begin with %, with information from the current VCD. The expanded string is returned. Here is a list of escape sequences: %A : The album information %C : The VCD volume count - the number of CD's in the collection. %c : The VCD volume num - the number of the CD in the collection. %F : The VCD Format, e.g. VCD 1.0, VCD 1.1, VCD 2.0, or SVCD %I : The current entry/segment/playback type, e.g. ENTRY, TRACK, SEGMENT... %L : The playlist ID prefixed with " LID" if it exists %N : The current number of the above - a decimal number %P : The publisher ID %p : The preparer ID %S : If we are in a segment (menu), the kind of segment %T : The track number %V : The volume set ID %v : The volume ID A number between 1 and the volume count. %% : a %*/char *vcdplayer_format_str(vcdplayer_t *p_vcdplayer, const char format_str[]){#define TEMP_STR_SIZE 256#define TEMP_STR_LEN (TEMP_STR_SIZE-1) static char temp_str[TEMP_STR_SIZE]; size_t i; char * tp = temp_str; bool saw_control_prefix = false; size_t format_len = strlen(format_str); vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd; memset(temp_str, 0, TEMP_STR_SIZE); for (i=0; i<format_len; i++) { if (!saw_control_prefix && format_str[i] != '%') { *tp++ = format_str[i]; saw_control_prefix = false; continue; } switch(format_str[i]) { case '%': if (saw_control_prefix) { *tp++ = '%'; } saw_control_prefix = !saw_control_prefix; break; case 'A': add_format_str_info(vcdinfo_strip_trail(vcdinfo_get_album_id(p_vcdinfo), MAX_ALBUM_LEN)); break; case 'c': add_format_num_info(vcdinfo_get_volume_num(p_vcdinfo), "%d"); break; case 'C': add_format_num_info(vcdinfo_get_volume_count(p_vcdinfo), "%d"); break; case 'F': add_format_str_info(vcdinfo_get_format_version_str(p_vcdinfo)); break; case 'I': { switch (p_vcdplayer->play_item.type) { case VCDINFO_ITEM_TYPE_TRACK: strncat(tp, "Track", TEMP_STR_LEN-(tp-temp_str)); tp += strlen("Track"); break; case VCDINFO_ITEM_TYPE_ENTRY: strncat(tp, "Entry", TEMP_STR_LEN-(tp-temp_str)); tp += strlen("Entry"); break; case VCDINFO_ITEM_TYPE_SEGMENT: strncat(tp, "Segment", TEMP_STR_LEN-(tp-temp_str)); tp += strlen("Segment"); break; case VCDINFO_ITEM_TYPE_LID: strncat(tp, "List ID", TEMP_STR_LEN-(tp-temp_str)); tp += strlen("List ID"); break; case VCDINFO_ITEM_TYPE_SPAREID2: strncat(tp, "Navigation", TEMP_STR_LEN-(tp-temp_str)); tp += strlen("Navigation"); break; default: /* What to do? */ ; } saw_control_prefix = false; } break; case 'L': if (vcdplayer_pbc_is_on(p_vcdplayer)) { char num_str[20]; snprintf(num_str, sizeof(num_str), " List ID %d", p_vcdplayer->i_lid); strncat(tp, num_str, TEMP_STR_LEN-(tp-temp_str)); tp += strlen(num_str); } saw_control_prefix = false; break; case 'N': add_format_num_info(p_vcdplayer->play_item.num, "%d"); break; case 'p': add_format_str_info(vcdinfo_get_preparer_id(p_vcdinfo)); break; case 'P': add_format_str_info(vcdinfo_get_publisher_id(p_vcdinfo)); break; case 'S': if ( VCDINFO_ITEM_TYPE_SEGMENT==p_vcdplayer->play_item.type ) { char seg_type_str[30]; snprintf(seg_type_str, sizeof(seg_type_str), " %s", vcdinfo_video_type2str(p_vcdinfo, p_vcdplayer->play_item.num)); strncat(tp, seg_type_str, TEMP_STR_LEN-(tp-temp_str)); tp += strlen(seg_type_str); } saw_control_prefix = false; break; case 'T': add_format_num_info(p_vcdplayer->i_track, "%d"); break; case 'V': add_format_str_info(vcdinfo_get_volumeset_id(p_vcdinfo)); break; case 'v': add_format_str_info(vcdinfo_get_volume_id(p_vcdinfo)); break; default: *tp++ = '%'; *tp++ = format_str[i]; saw_control_prefix = false; } } return strdup(temp_str);}static void_vcdplayer_update_entry(vcdinfo_obj_t *p_vcdinfo, uint16_t ofs, uint16_t *entry, const char *label){ if ( ofs == VCDINFO_INVALID_OFFSET ) { *entry = VCDINFO_INVALID_ENTRY; } else { vcdinfo_offset_t *off = vcdinfo_get_offset_t(p_vcdinfo, ofs); if (off != NULL) { *entry = off->lid; dbg_print(INPUT_DBG_PBC, "%s: LID %d\n", label, off->lid); } else *entry = VCDINFO_INVALID_ENTRY; }}/*! Update next/prev/return/default navigation buttons (via p_vcdplayer->i_lid). Update size of play-item (via p_vcdplayer->play_item).*/voidvcdplayer_update_nav(vcdplayer_t *p_vcdplayer){ int play_item = p_vcdplayer->play_item.num; vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd; int min_entry = 1; int max_entry = 0; if (vcdplayer_pbc_is_on(p_vcdplayer)) { vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), p_vcdplayer->i_lid); switch (p_vcdplayer->pxd.descriptor_type) { case PSD_TYPE_SELECTION_LIST: case PSD_TYPE_EXT_SELECTION_LIST: if (p_vcdplayer->pxd.psd == NULL) return; _vcdplayer_update_entry(p_vcdinfo, vcdinf_psd_get_prev_offset(p_vcdplayer->pxd.psd), &(p_vcdplayer->prev_entry), "prev"); _vcdplayer_update_entry(p_vcdinfo, vcdinf_psd_get_next_offset(p_vcdplayer->pxd.psd), &(p_vcdplayer->next_entry), "next"); _vcdplayer_update_entry(p_vcdinfo, vcdinf_psd_get_return_offset(p_vcdplayer->pxd.psd), &(p_vcdplayer->return_entry), "return"); _vcdplayer_update_entry(p_vcdinfo, vcdinfo_get_default_offset(p_vcdinfo, p_vcdplayer->i_lid), &(p_vcdplayer->default_entry), "default"); break; case PSD_TYPE_PLAY_LIST: if (p_vcdplayer->pxd.pld == NULL) return; _vcdplayer_update_entry(p_vcdinfo, vcdinf_pld_get_prev_offset(p_vcdplayer->pxd.pld), &(p_vcdplayer->prev_entry), "prev"); _vcdplayer_update_entry(p_vcdinfo, vcdinf_pld_get_next_offset(p_vcdplayer->pxd.pld), &(p_vcdplayer->next_entry), "next"); _vcdplayer_update_entry(p_vcdinfo, vcdinf_pld_get_return_offset(p_vcdplayer->pxd.pld), &(p_vcdplayer->return_entry), "return"); p_vcdplayer->default_entry = VCDINFO_INVALID_ENTRY; break; case PSD_TYPE_END_LIST: p_vcdplayer->origin_lsn = p_vcdplayer->i_lsn = p_vcdplayer->end_lsn = VCDINFO_NULL_LSN; /* Fall through */ case PSD_TYPE_COMMAND_LIST: p_vcdplayer->next_entry = p_vcdplayer->prev_entry = p_vcdplayer->return_entry = VCDINFO_INVALID_ENTRY; p_vcdplayer->default_entry = VCDINFO_INVALID_ENTRY; break; } if (p_vcdplayer->update_title) p_vcdplayer->update_title(); return; } /* PBC is not on. Set up for simplified next, prev, and return. */ switch (p_vcdplayer->play_item.type) { case VCDINFO_ITEM_TYPE_ENTRY: case VCDINFO_ITEM_TYPE_SEGMENT: case VCDINFO_ITEM_TYPE_TRACK: switch (p_vcdplayer->play_item.type) { case VCDINFO_ITEM_TYPE_ENTRY: max_entry = p_vcdplayer->i_entries; min_entry = 0; /* Can remove when Entries start at 1. */ p_vcdplayer->i_track = vcdinfo_get_track(p_vcdinfo, play_item); p_vcdplayer->track_lsn = vcdinfo_get_track_lsn(p_vcdinfo, p_vcdplayer->i_track); break; case VCDINFO_ITEM_TYPE_SEGMENT: max_entry = p_vcdplayer->i_segments; p_vcdplayer->i_track = VCDINFO_INVALID_TRACK; break; case VCDINFO_ITEM_TYPE_TRACK: max_entry = p_vcdplayer->i_tracks; p_vcdplayer->i_track = p_vcdplayer->play_item.num; p_vcdplayer->track_lsn = vcdinfo_get_track_lsn(p_vcdinfo, p_vcdplayer->i_track); break; default: ; /* Handle exceptional cases below */ } _vcdplayer_set_origin(p_vcdplayer); /* Set next, prev, return and default to simple and hopefully useful values. */ if (play_item+1 >= max_entry) p_vcdplayer->next_entry = VCDINFO_INVALID_ENTRY; else p_vcdplayer->next_entry = play_item+1; if (play_item-1 >= min_entry) p_vcdplayer->prev_entry = play_item-1; else p_vcdplayer->prev_entry = VCDINFO_INVALID_ENTRY; p_vcdplayer->default_entry = play_item; p_vcdplayer->return_entry = min_entry; break; case VCDINFO_ITEM_TYPE_LID: { /* Should have handled above. */ break; } default: ; } p_vcdplayer->update_title();}/*! Set reading to play an entire track.*/static void_vcdplayer_set_track(vcdplayer_t *p_vcdplayer, unsigned int i_track) { if (i_track < 1 || i_track > p_vcdplayer->i_tracks) return; else { vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd; vcdinfo_itemid_t itemid; itemid.num = i_track; itemid.type = VCDINFO_ITEM_TYPE_TRACK; p_vcdplayer->i_still = 0; p_vcdplayer->i_lsn = vcdinfo_get_track_lsn(p_vcdinfo, i_track); p_vcdplayer->play_item = itemid; p_vcdplayer->i_track = i_track; p_vcdplayer->track_lsn = p_vcdplayer->i_lsn; _vcdplayer_set_origin(p_vcdplayer); dbg_print(INPUT_DBG_LSN, "LSN: %u\n", p_vcdplayer->i_lsn); }}/*! Set reading to play an entry*/static void_vcdplayer_set_entry(vcdplayer_t *p_vcdplayer, unsigned int num) { vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd; const unsigned int i_entries = vcdinfo_get_num_entries(p_vcdinfo); if (num >= i_entries) { LOG_ERR(p_vcdplayer, "%s %d\n", _("bad entry number"), num); return; } else { vcdinfo_itemid_t itemid; itemid.num = num; itemid.type = VCDINFO_ITEM_TYPE_ENTRY; p_vcdplayer->i_still = 0; p_vcdplayer->i_lsn = vcdinfo_get_entry_lsn(p_vcdinfo, num); p_vcdplayer->play_item = itemid; p_vcdplayer->i_track = vcdinfo_get_track(p_vcdinfo, num); p_vcdplayer->track_lsn = vcdinfo_get_track_lsn(p_vcdinfo, p_vcdplayer->i_track); p_vcdplayer->track_end_lsn = p_vcdplayer->track_lsn + p_vcdplayer->track[p_vcdplayer->i_track-1].size; _vcdplayer_set_origin(p_vcdplayer); dbg_print((INPUT_DBG_LSN|INPUT_DBG_PBC), "LSN: %u, track_end LSN: %u\n", p_vcdplayer->i_lsn, p_vcdplayer->track_end_lsn); }}/*! Set reading to play an segment (e.g. still frame)*/static void_vcdplayer_set_segment(vcdplayer_t *p_vcdplayer, unsigned int num) { vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd; segnum_t i_segs = vcdinfo_get_num_segments(p_vcdinfo); if (num >= i_segs) { LOG_ERR(p_vcdplayer, "%s %d\n", _("bad segment number"), num); return; } else { vcdinfo_itemid_t itemid;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -