📄 xineplug_inp_vcd.c
字号:
if (vcdinfo_get_lot(vcdplayer->vcd)) { for (n=0; n<vcdplayer->i_lids; n++) { uint16_t ofs = vcdinf_get_lot_offset(vcdinfo_get_lot(vcdplayer->vcd), n); if (ofs != PSD_OFS_DISABLED || vcdplayer->show_rejected) { memset(&mrl, 0, sizeof (mrl)); snprintf(mrl, sizeof(mrl), "%s%s@P%u%s", MRL_PREFIX, vcd_device, n+1, ofs == PSD_OFS_DISABLED ? "*" : ""); vcd_add_mrl_slot(class, mrl, 0, &i); class->mrl_segment_offset++; } } } /* Record MRL's for segments */ { segnum_t i_segments = vcdplayer->i_segments; for (n=0; n<i_segments; n++) { vcdinfo_video_segment_type_t segtype = vcdinfo_get_video_type(p_vcdinfo, n); char c='S'; switch (segtype) { { case VCDINFO_FILES_VIDEO_NTSC_STILL: case VCDINFO_FILES_VIDEO_NTSC_STILL2: case VCDINFO_FILES_VIDEO_NTSC_MOTION: c='s'; break; case VCDINFO_FILES_VIDEO_PAL_STILL: case VCDINFO_FILES_VIDEO_PAL_STILL2: case VCDINFO_FILES_VIDEO_PAL_MOTION: c='S'; break; default: ; } } memset(&mrl, 0, sizeof (mrl)); snprintf(mrl, sizeof(mrl), "%s%s@%c%u", MRL_PREFIX, vcd_device, c, n); vcd_add_mrl_slot(class, mrl, vcdplayer->segment[n].size, &i); } } dbg_print(INPUT_DBG_MRL, "offsets are track: %d, entry: %d, play: %d seg: %d\n", class->mrl_track_offset, class->mrl_entry_offset, class->mrl_play_offset, class->mrl_segment_offset); return true;}/*! parses a MRL which has the format vcd://[vcd_path][@[EPTS]?number]\*? Examples vcd:// - Play (navigate) default device: /dev/cdrom vcd://@ - same as above vcd:///dev/cdrom - probably same as above vcd:///dev/cdrom2 - Play (navigate) /dev/cdrom2 vcd:///dev/cdrom2@ - same as above vcd:///dev/cdrom2@T1 - Play Track 1 from /dev/cdrom2 vcd:///dev/cdrom@S1 - Play selection id 1 from /dev/cdrom vcd://dev/cdrom@E0 - Play Entry id 0 from default device vcd://@P1 - probably same as above. If there is no playback control, MRL will get converted into vcd://@E0 vcd://@P1* - probably same as above. vcd://@S0 - Play segment 0 from default device vcd://@3 - Play track 3 from default device vcd:///dev/cdrom2@1 - Play track 1 from /dev/cdrom2 vcd:///tmp/ntsc.bin@ - Play default item from /tmp/ntsc.bin vcd:///tmp/ntsc.bin/@E0 - Play entry 0 of /tmp/ntsc.binparameters: mrl : mrl to parse default_vcd_device: name of device to use when none given auto_type : type of selection (entry, track, LID) when none given used_default : true iff auto_type was used. */static boolvcd_parse_mrl(/*in*/ const char *default_vcd_device, /*in*/ char *mrl, /*out*/ char *device_str, /*out*/ vcdinfo_itemid_t *itemid, /*in */ vcdplayer_autoplay_t auto_type, /*out*/ bool *used_default) { char type_str[2]; int count; char *p; unsigned int num = 0; dbg_print(INPUT_DBG_CALL, "called mrl %s\n", mrl); type_str[0] ='\0'; itemid->type = (vcdinfo_item_enum_t) auto_type; *used_default = false; if ( NULL == mrl || strncasecmp(mrl, MRL_PREFIX, MRL_PREFIX_LEN) ) return false; p = &mrl[MRL_PREFIX_LEN - 2]; while (*p == '/') ++p; device_str[0] = '/'; device_str[1] = 0; count = sscanf (p, "%1023[^@]@%1[EePpSsTt]%u", device_str + 1, type_str, &num); itemid->num = num; switch (count) { case 1: /* Matched device, but nothing beyond that */ if (strlen(device_str)!=0 && device_str[0] != ':') { /* See if we have old-style MRL with no type specifier. If so, we assume "track". */ count = sscanf (p, "%u", &num); itemid->num = num; if (1==count) { type_str[0] = 'T'; if (default_vcd_device) strncpy(device_str, default_vcd_device, MAX_DEVICE_LEN); else *device_str = 0; } else _x_mrl_unescape (device_str); break; } case 2 ... 9: _x_mrl_unescape (device_str); case 0: case EOF: { /* No device/file given, so use the default device and try again. */ if (NULL == default_vcd_device) return false; strncpy(device_str, default_vcd_device, MAX_DEVICE_LEN); if (p[0] == '@') p++; count = sscanf (p, "%1[EePpSsTt]%u", type_str, &num); type_str[0] = toupper(type_str[0]); itemid->num = num; switch (count) { case EOF: /* Default PBC navigation. */ return true; case 0: /* See if we have old-style MRL with no type specifier. If so, we assume "track". */ count = sscanf (p, "%u", &num); if (1==count) { type_str[0] = 'T'; break; } /* Default PBC navigation. */ return true; case 1: /* Type given, but no number. Entries start at 0, other things start at 1 */ if (type_str[0] == 'P' || type_str[0] == 'T') itemid->num = 1; } } } /* We have some sort of track/selection/entry number */ switch (type_str[0]) { case 'E': itemid->type = VCDINFO_ITEM_TYPE_ENTRY; break; case '\0': /* None specified, use config value. */ itemid->type = (vcdinfo_item_enum_t) auto_type; *used_default = true; break; case 'P': itemid->type = VCDINFO_ITEM_TYPE_LID; break; case 'S': itemid->type = VCDINFO_ITEM_TYPE_SEGMENT; break; case 'T': itemid->type = VCDINFO_ITEM_TYPE_TRACK; break; default: ; } if ( 0==itemid->num && ( (VCDINFO_ITEM_TYPE_LID == itemid->type) || (VCDINFO_ITEM_TYPE_TRACK == itemid->type) ) ) itemid->num = 1; return true;}/*! From xine plugin spec: return capabilities of input source*/static uint32_t vcd_plugin_get_capabilities (input_plugin_t *this_gen){ uint32_t ret = INPUT_CAP_AUDIOLANG | INPUT_CAP_BLOCK | INPUT_CAP_CHAPTERS | INPUT_CAP_PREVIEW | (my_vcd.player.i_still ? 0: INPUT_CAP_SEEKABLE) | INPUT_CAP_SPULANG; dbg_print((INPUT_DBG_CALL|INPUT_DBG_EXT), "returning %d\n", ret); vcd_handle_events(); return ret;}# if FINISHED/* If needed, will fill out later... */static void vcd_read_ahead_cb(void *this_gen, xine_cfg_entry_t *entry){ return;}#endifstatic void vcd_flush_buffers(void){ _x_demux_flush_engine(my_vcd.stream);}/*! From xine plugin spec: read nlen bytes, return number of bytes read.*/static off_t vcd_plugin_read (input_plugin_t *this_gen, char *buf, const off_t nlen){ dbg_print((INPUT_DBG_CALL|INPUT_DBG_EXT), "Called with nlen %u\n", (unsigned int) nlen); /* FIXME: Tricking the demux_mpeg_block plugin */ buf[0] = 0; buf[1] = 0; buf[2] = 0x01; buf[3] = 0xba; return (off_t) 1;}/* Allocate and return a no-op buffer. This signals the outside to do nothing, but in contrast to returning NULL, it doesn't mean the stream has ended. We use this say for still frames. */#define RETURN_NOOP_BUF \ p_buf = fifo->buffer_pool_alloc (fifo); \ p_buf->type = BUF_CONTROL_NOP; \ return p_buf/* Handle keyboard events and if there were non which might affect playback, then sleep a little bit and return; */#define SLEEP_AND_HANDLE_EVENTS \ xine_usec_sleep(50000); \ if (vcd_handle_events()) goto read_block; \ RETURN_NOOP_BUF/*! From xine plugin spec: read one block, return newly allocated block (or NULL on failure) for blocked input sources len must be == blocksize the fifo parameter is only used to get access to the buffer_pool_alloc function*/static buf_element_t *vcd_plugin_read_block (input_plugin_t *this_gen, fifo_buffer_t *fifo, const off_t i_len) { vcd_input_plugin_t *vcd_input_plugin= (vcd_input_plugin_t *) this_gen; vcdplayer_t *p_vcdplayer = &my_vcd.player; buf_element_t *p_buf; uint8_t data[M2F2_SECTOR_SIZE] = {0}; if (fifo == NULL) { dbg_print(INPUT_DBG_CALL, "NULL fifo"); return NULL; } dbg_print(INPUT_DBG_CALL, "Called with i_len %u\n", (unsigned int) i_len); /* Should we change this to <= instead of !=? */ if (i_len != M2F2_SECTOR_SIZE) return NULL; /* If VCD isn't open, we need to open it now. */ if (!p_vcdplayer->b_opened) { if (!vcdio_open(p_vcdplayer, my_vcd.player_device)) { return NULL; } } if (vcd_handle_events()) goto read_block; if (p_vcdplayer->i_still > 0) { if ( time(NULL) >= vcd_input_plugin->pause_end_time ) { if (STILL_INDEFINITE_WAIT == p_vcdplayer->i_still) { dbg_print(INPUT_DBG_STILL, "Continuing still indefinite wait time\n"); vcd_input_plugin->pause_end_time = time(NULL) + p_vcdplayer->i_still; SLEEP_AND_HANDLE_EVENTS; } else { dbg_print(INPUT_DBG_STILL, "Still time ended\n"); p_vcdplayer->i_still = 0; } } else { SLEEP_AND_HANDLE_EVENTS; } } read_block: switch (vcdplayer_read(p_vcdplayer, data, i_len)) { case READ_END: /* End reached. Return NULL to indicated this. */ return NULL; case READ_ERROR: /* Some sort of error. */ return NULL; case READ_STILL_FRAME: { dbg_print(INPUT_DBG_STILL, "Handled still event wait time %u\n", p_vcdplayer->i_still); vcd_input_plugin->pause_end_time = time(NULL) + p_vcdplayer->i_still; RETURN_NOOP_BUF; } default: case READ_BLOCK: /* Read buffer */ p_buf = fifo->buffer_pool_alloc (fifo); p_buf->type = BUF_DEMUX_BLOCK; } p_buf->content = p_buf->mem; if (STILL_READING == p_vcdplayer->i_still && 0 == my_vcd.i_old_still) { my_vcd.i_old_deinterlace = xine_get_param(my_vcd.stream, XINE_PARAM_VO_DEINTERLACE); xine_set_param(my_vcd.stream, XINE_PARAM_VO_DEINTERLACE, 0); dbg_print(INPUT_DBG_STILL, "going into still, saving deinterlace %d\n", my_vcd.i_old_deinterlace); } else if (0 == p_vcdplayer->i_still && 0 != my_vcd.i_old_still) { dbg_print(INPUT_DBG_STILL, "going out of still, restoring deinterlace\n"); xine_set_param(my_vcd.stream, XINE_PARAM_VO_DEINTERLACE, my_vcd.i_old_deinterlace); } my_vcd.i_old_still = p_vcdplayer->i_still; /* Ideally this should probably be i_len. */ memcpy (p_buf->mem, data, M2F2_SECTOR_SIZE); return p_buf;}/*! From xine plugin spec: seek position, return new position if seeking failed, -1 is returned*/static off_t vcd_plugin_seek (input_plugin_t *this_gen, off_t offset, int origin) { return vcdio_seek (&my_vcd.player, offset, origin);}/*! From xine plugin spec: return length of input (-1 => unlimited, e.g. stream) length size is bytes.*/static vcdinfo_itemid_t old_play_item = {VCDINFO_ITEM_TYPE_NOTFOUND, 0};static off_t old_get_length = 0;static vcdplayer_slider_length_t old_slider_length;/* This routine is called a bit. Make reasonably fast. */static off_t vcd_plugin_get_length (input_plugin_t *this_gen) { vcd_input_plugin_t *ip= (vcd_input_plugin_t *) this_gen; vcdplayer_t *vcdplayer = &(ip->player); int n = vcdplayer->play_item.num; if (vcdplayer->play_item.num == old_play_item.num && vcdplayer->play_item.type == old_play_item.type && vcdplayer->slider_length == old_slider_length) return old_get_length; old_slider_length = vcdplayer->slider_length; old_play_item = vcdplayer->play_item;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -