diff options
author | Miguel Freitas <miguelfreitas@users.sourceforge.net> | 2003-08-21 00:37:26 +0000 |
---|---|---|
committer | Miguel Freitas <miguelfreitas@users.sourceforge.net> | 2003-08-21 00:37:26 +0000 |
commit | fa630d674955c0a6ea29d1427081e200223b85cc (patch) | |
tree | 3a696b538dfcfa9e8ed81244f2f7549380df97ac /src | |
parent | 44d393d0d8b4ff75e76e21860386ce5c145d304a (diff) | |
download | xine-lib-fa630d674955c0a6ea29d1427081e200223b85cc.tar.gz xine-lib-fa630d674955c0a6ea29d1427081e200223b85cc.tar.bz2 |
RIP Input Plugin
CVS patchset: 5300
CVS date: 2003/08/21 00:37:26
Diffstat (limited to 'src')
-rw-r--r-- | src/input/input_dvd.c | 11 | ||||
-rw-r--r-- | src/input/input_http.c | 11 | ||||
-rw-r--r-- | src/input/input_plugin.h | 10 | ||||
-rw-r--r-- | src/xine-engine/Makefile.am | 3 | ||||
-rw-r--r-- | src/xine-engine/input_rip.c | 425 | ||||
-rw-r--r-- | src/xine-engine/xine.c | 40 | ||||
-rw-r--r-- | src/xine-engine/xine_internal.h | 3 |
7 files changed, 495 insertions, 8 deletions
diff --git a/src/input/input_dvd.c b/src/input/input_dvd.c index 8c7290ddc..9fe9805dd 100644 --- a/src/input/input_dvd.c +++ b/src/input/input_dvd.c @@ -18,7 +18,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: input_dvd.c,v 1.166 2003/06/29 10:57:08 mroi Exp $ + * $Id: input_dvd.c,v 1.167 2003/08/21 00:37:26 miguelfreitas Exp $ * */ @@ -255,7 +255,11 @@ static uint32_t dvd_plugin_get_capabilities (input_plugin_t *this_gen) { trace_print("Called\n"); - return INPUT_CAP_BLOCK | + return INPUT_CAP_BLOCK | + /* TODO: figure out if there is any "allow copying" flag on DVD. + * maybe set INPUT_CAP_RIP_FORBIDDEN only for encrypted media? + */ + INPUT_CAP_RIP_FORBIDDEN | #if CAN_SEEK (this->seekable ? INPUT_CAP_SEEKABLE : 0) | #endif @@ -1732,6 +1736,9 @@ static void *init_class (xine_t *xine, void *data) { /* * $Log: input_dvd.c,v $ + * Revision 1.167 2003/08/21 00:37:26 miguelfreitas + * RIP Input Plugin + * * Revision 1.166 2003/06/29 10:57:08 mroi * on some DVDs, the first highlight information (which button to highlight) will * arrive before the first SPU packet, therefore the SPU decoder has not yet been diff --git a/src/input/input_http.c b/src/input/input_http.c index 7ac5e8b59..ea87ccbe7 100644 --- a/src/input/input_http.c +++ b/src/input/input_http.c @@ -19,7 +19,7 @@ * * input plugin for http network streams * - * $Id: input_http.c,v 1.62 2003/06/19 14:46:03 guenter Exp $ + * $Id: input_http.c,v 1.63 2003/08/21 00:37:29 miguelfreitas Exp $ */ #ifdef HAVE_CONFIG_H @@ -541,8 +541,15 @@ static off_t http_plugin_get_length (input_plugin_t *this_gen) { } static uint32_t http_plugin_get_capabilities (input_plugin_t *this_gen) { + http_input_plugin_t *this = (http_input_plugin_t *) this_gen; + uint32_t caps = INPUT_CAP_PREVIEW; + + /* Nullsoft asked to not allow saving streaming nsv files */ + if (this->filename && + !strncmp(this->filename + strlen(this->filename) - 4, ".nsv", 4)) + caps |= INPUT_CAP_RIP_FORBIDDEN; - return INPUT_CAP_PREVIEW; + return caps; } static uint32_t http_plugin_get_blocksize (input_plugin_t *this_gen) { diff --git a/src/input/input_plugin.h b/src/input/input_plugin.h index 99fb1d738..4377ae51a 100644 --- a/src/input/input_plugin.h +++ b/src/input/input_plugin.h @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: input_plugin.h,v 1.50 2003/07/03 00:58:51 andruil Exp $ + * $Id: input_plugin.h,v 1.51 2003/08/21 00:37:29 miguelfreitas Exp $ */ #ifndef HAVE_INPUT_PLUGIN_H @@ -265,6 +265,14 @@ struct input_plugin_s { #define INPUT_CAP_CHAPTERS 0x00000080 +/* + * INPUT_CAP_RIP_FORBIDDEN: + * means that rip/disk saving must not be used. + * (probably at author's request) + */ + +#define INPUT_CAP_RIP_FORBIDDEN 0x00000100 + #define INPUT_IS_SEEKABLE(input) (((input)->get_capabilities(input) & INPUT_CAP_SEEKABLE) != 0) #define INPUT_OPTIONAL_UNSUPPORTED 0 diff --git a/src/xine-engine/Makefile.am b/src/xine-engine/Makefile.am index d82c3811a..0a4a04155 100644 --- a/src/xine-engine/Makefile.am +++ b/src/xine-engine/Makefile.am @@ -13,7 +13,8 @@ libxine_la_SOURCES = xine.c metronom.c configfile.c buffer.c \ load_plugins.c video_decoder.c buffer_types.c \ audio_decoder.c video_out.c audio_out.c resample.c events.c \ video_overlay.c osd.c scratch.c demux.c vo_scale.c \ - xine_interface.c post.c tvmode.c broadcaster.c io_helper.c + xine_interface.c post.c tvmode.c broadcaster.c io_helper.c \ + input_rip.c # FIXME: these are currently unused: EXTRA_DIST = lrb.c lrb.h diff --git a/src/xine-engine/input_rip.c b/src/xine-engine/input_rip.c new file mode 100644 index 000000000..122837db2 --- /dev/null +++ b/src/xine-engine/input_rip.c @@ -0,0 +1,425 @@ +/* + * Copyright (C) 2000-2003 the xine project + * + * This file is part of xine, a free video player. + * + * xine 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. + * + * xine 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 + * + * Rip Input Plugin for catching streams + * + * It saves raw data into file as go from input plugins. + * + * Usage: + * + * - activation: + * xine stream_mrl#rip:file.raw + * + * - it's possible speeder saving streams in the xine without playing: + * xine stream_mrl#rip:file.raw;noaudio;novideo + * + * $Id: input_rip.c,v 1.1 2003/08/21 00:37:29 miguelfreitas Exp $ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <string.h> +#include <errno.h> + +/* logging */ +/* +#define LOG 1 +*/ +#define LOG_MODULE "input_rip" +#define CLR_FAIL "\e[1;31m" +#define CLR_RST "\e[0;39m" + +#include "xine_internal.h" + +#define SCRATCH_SIZE 1024 + +typedef struct { + input_plugin_t input_plugin; /* inherited structure */ + + input_plugin_t *main_input_plugin; /* original input plugin */ + + xine_stream_t *stream; + FILE *file; /* destination file */ + + char *preview; /* preview data */ + off_t preview_size; /* size of read preview data */ + off_t curpos; /* current position */ +} rip_input_plugin_t; + + +/* + * read data from input plugin and write it into file + */ +static off_t rip_plugin_read(input_plugin_t *this_gen, char *buf, off_t len) { + rip_input_plugin_t *this = (rip_input_plugin_t *)this_gen; + off_t retlen, nreal, npreview; + + lprintf("reading %lld bytes\n", len); + + if (this->curpos < this->preview_size && this->preview) { + /* get some data from preview */ + npreview = this->preview_size - this->curpos; + if (npreview > len) npreview = len; + + lprintf(" => get %lld bytes from preview (%lld bytes)\n", npreview, this->preview_size); + + memcpy(buf, &this->preview[this->curpos], npreview); + } else { + /* no data from preview */ + npreview = 0; + } + + /* really to read/catch */ + nreal = len - npreview; + if (nreal) { + lprintf(" => read %lld bytes from input plugin\n", nreal); + + /* read from main input plugin */ + retlen = this->main_input_plugin->read(this->main_input_plugin, &buf[npreview], nreal); + lprintf("%s => returned %lld\e" CLR_RST "\n", retlen == nreal ? "" : CLR_FAIL, retlen); + + if (retlen < 0) { + xine_log(this->stream->xine, XINE_LOG_MSG, + _("input_rip: reading by input plugin failed\n")); + return -1; + } + + /* write to file */ + if (retlen && this->file) { + if (fwrite(buf + npreview, retlen, 1, this->file) != 1) { + xine_log(this->stream->xine, XINE_LOG_MSG, + _("input_rip: error writing to file %lld bytes: %s\n"), + retlen, strerror(errno)); + return 0; + } + } + } else { + retlen = 0; + } + + this->curpos += (npreview + retlen); + + return npreview + retlen; +} + +/* + * open catching file and slave input plugin + */ +static int rip_plugin_open(input_plugin_t *this_gen) { + rip_input_plugin_t *this = (rip_input_plugin_t *)this_gen; + + xine_log(this->stream->xine, XINE_LOG_MSG, + _("input_rip: open() function should never be called\n")); + return 0; +} + +/* + * delete seeking from capabilities, + * set preview cap (implemented by original plugin or rip plugin) + * + * preview capability can be deleted after opening with some special inputs + */ +static uint32_t rip_plugin_get_capabilities(input_plugin_t *this_gen) { + rip_input_plugin_t *this = (rip_input_plugin_t *)this_gen; + uint32_t caps; + + caps = this->main_input_plugin->get_capabilities(this->main_input_plugin); + return (caps & (~INPUT_CAP_SEEKABLE)) | (this->preview ? INPUT_CAP_PREVIEW : 0); +} + +/* + * read a block of data from input plugin and write it into file + * + * This rip plugin returns block unchanged from main input plugin. But special + * case is reading over preview - it returns own allocated block. + */ +static buf_element_t *rip_plugin_read_block(input_plugin_t *this_gen, fifo_buffer_t *fifo, off_t todo) { + rip_input_plugin_t *this = (rip_input_plugin_t *)this_gen; + buf_element_t *buf; + off_t npreview, nreal, retval; + + lprintf("read %lld bytes (block)\n", todo); + + if (!todo) return NULL; + + /* number of bytes from preview */ + if (this->preview && this->curpos < this->preview_size) { + npreview = this->preview_size - this->curpos; + if (npreview > todo) npreview = todo; + } else { + npreview = 0; + } + /* really read & catched bytes */ + nreal = todo - npreview; + + if (npreview) { + /* new block created by rip input plugin */ + buf = fifo->buffer_pool_alloc(fifo); + buf->content = buf->mem; + buf->type = BUF_DEMUX_BLOCK; + buf->size = npreview; + memcpy(buf->content, &this->preview[this->curpos], npreview); + + lprintf(" => read %lld bytes by rip plugin (block)\n", nreal + npreview); + retval = rip_plugin_read(this_gen, &buf->content[npreview], nreal); + if (retval != nreal) { + buf->free_buffer(buf); + return NULL; + } + + buf->size += retval; + } else { + /* all data go as block from input plugin */ + lprintf(" => reading %lld bytes from input plugin (block)\n", nreal); + + buf = this->main_input_plugin->read_block(this->main_input_plugin, fifo, nreal); + if (!buf) { + lprintf(CLR_FAIL " => reading failed (block)" CLR_RST "\n"); + return NULL; + } + } + + this->curpos += buf->size; + + /* write the block */ + if (buf && this->file && buf->type == BUF_DEMUX_BLOCK) { + if (nreal > 0 && fwrite(&buf->content[npreview], nreal, 1, this->file) != 1) { + xine_log(this->stream->xine, XINE_LOG_MSG, + _("input_rip: error writing to file: %s\n"), strerror(errno)); + buf->free_buffer(buf); + return NULL; + } + } + + return buf; +} + +/* + * enabled only forward seeking + */ +static off_t rip_plugin_seek(input_plugin_t *this_gen, off_t offset, int origin) { + char buffer[SCRATCH_SIZE]; + rip_input_plugin_t *this = (rip_input_plugin_t *)this_gen; + uint32_t blocksize; + off_t toread, writed; + + lprintf("seek, offset %lld, origin %d (curpos %lld)\n", offset, origin, this->curpos); + + switch (origin) { + case SEEK_SET: toread = offset - this->curpos; break; + case SEEK_CUR: toread = offset; break; + default: toread = 0; + } + + if (toread < 0) { + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, + "cannot seek back (%lld bytes)\n", -toread); + return -1; + } + + if( this_gen->get_capabilities(this_gen) & INPUT_CAP_BLOCK ) + blocksize = this_gen->get_blocksize(this_gen); + else + blocksize = 1; + + toread -= (toread % blocksize); + + /* read/catch by sizeof(buffer) bytes */ + while (toread > 0) { + if( blocksize > 1 ) { + buf_element_t *buf; + + buf = rip_plugin_read_block(this_gen, this->stream->video_fifo, blocksize); + if (buf) { + writed = buf->size; + buf->free_buffer(buf); + } else { + toread = 0; + writed = 0; + } + } else { + writed = rip_plugin_read(this_gen, buffer, (toread > sizeof buffer) ? (sizeof buffer) : toread); + } + + if (writed <= 0) { + xine_log(this->stream->xine, XINE_LOG_MSG, + _("input_rip: seeking failed\n")); + break; + } + toread -= writed; + } + + lprintf(" => newpos %lld\n", this->curpos); + + return this->curpos; +} + +/* + * return current position, + * check values for debug build + */ +static off_t rip_plugin_get_current_pos(input_plugin_t *this_gen) { + rip_input_plugin_t *this = (rip_input_plugin_t *)this_gen; +#ifdef DEBUG + off_t pos; + + pos = this->main_input_plugin->get_current_pos(this->main_input_plugin); + if (pos != this->curpos) { + lprintf("position: computed = %lld, input plugin = %lld\n", this->curpos, pos); + } +#endif + + return this->curpos; +} + +static off_t rip_plugin_get_length (input_plugin_t *this_gen) { + rip_input_plugin_t *this = (rip_input_plugin_t *)this_gen; + + return this->main_input_plugin->get_length(this->main_input_plugin); +} + +static uint32_t rip_plugin_get_blocksize(input_plugin_t *this_gen) { + rip_input_plugin_t *this = (rip_input_plugin_t *)this_gen; + + return this->main_input_plugin->get_blocksize(this->main_input_plugin); +} + +static char* rip_plugin_get_mrl (input_plugin_t *this_gen) { + rip_input_plugin_t *this = (rip_input_plugin_t *)this_gen; + + return this->main_input_plugin->get_mrl(this->main_input_plugin); +} + +static int rip_plugin_get_optional_data (input_plugin_t *this_gen, + void *data, int data_type) { + rip_input_plugin_t *this = (rip_input_plugin_t *)this_gen; + + lprintf("get optional data\n"); + if (this->preview && data_type == INPUT_OPTIONAL_DATA_PREVIEW) { + memcpy(data, this->preview, this->preview_size); + return this->preview_size; + } else + return this->main_input_plugin->get_optional_data( + this->main_input_plugin, data, data_type); +} + +/* + * dispose main input plugin and self + */ +static void rip_plugin_dispose(input_plugin_t *this_gen) { + rip_input_plugin_t *this = (rip_input_plugin_t *)this_gen; + + lprintf("rip_plugin_dispose\n"); + + this->main_input_plugin->dispose(this->main_input_plugin); + if (this->file) fclose(this->file); + if (this->preview) free(this->preview); + free(this); +} + +/* + * create self instance, + * target file for writing stream is specified in 'data' + */ +input_plugin_t *rip_plugin_get_instance (xine_stream_t *stream, const char *filename) { + rip_input_plugin_t *this; + input_plugin_t *main_plugin = stream->input_plugin; + + lprintf("rip_plugin_get_instance(catch file = %s)\n", filename ? filename : "(null)"); + + /* check given input plugin */ + if (!stream->input_plugin) { + xine_log(stream->xine, XINE_LOG_MSG, + _("input_rip: input plugin not defined!\n")); + return NULL; + } + + if ( main_plugin->get_capabilities(main_plugin) & INPUT_CAP_RIP_FORBIDDEN ) { + xine_log(stream->xine, XINE_LOG_MSG, + _("input_rip: ripping/caching is not permitted!\n")); + return NULL; + } + + if (!filename || !filename[0]) { + xine_log(stream->xine, XINE_LOG_MSG, + _("input_rip: file name not given!\n")); + return NULL; + } + + this = (rip_input_plugin_t *)xine_xmalloc(sizeof(rip_input_plugin_t)); + this->main_input_plugin = main_plugin; + this->stream = stream; + this->curpos = 0; + + if ((this->file = fopen(filename, "wb")) == NULL) { + xine_log(this->stream->xine, XINE_LOG_MSG, + _("input_rip: error opening file %s: %s\n"), + filename, strerror(errno)); + free(this); + return NULL; + } + + /* fill preview memory */ + if ( main_plugin->get_capabilities(main_plugin) & INPUT_CAP_BLOCK ) { + buf_element_t *buf; + uint32_t blocksize; + + blocksize = main_plugin->get_blocksize(main_plugin); + buf = main_plugin->read_block(main_plugin, stream->video_fifo, blocksize); + + this->preview_size = buf->size; + this->preview = malloc(this->preview_size); + memcpy(this->preview, buf->content, this->preview_size); + + buf->free_buffer(buf); + } else { + this->preview = malloc(MAX_PREVIEW_SIZE); + this->preview_size = main_plugin->read(main_plugin, this->preview, MAX_PREVIEW_SIZE); + } + + if (this->file && this->preview && this->preview_size) { + if (fwrite(this->preview, this->preview_size, 1, this->file) != 1) { + xine_log(this->stream->xine, XINE_LOG_MSG, + _("input_rip: error writing to file %lld bytes: %s\n"), + this->preview_size, strerror(errno)); + fclose(this->file); + free(this); + return NULL; + } + } + + + this->input_plugin.open = rip_plugin_open; + this->input_plugin.get_capabilities = rip_plugin_get_capabilities; + this->input_plugin.read = rip_plugin_read; + this->input_plugin.read_block = rip_plugin_read_block; + this->input_plugin.seek = rip_plugin_seek; + this->input_plugin.get_current_pos = rip_plugin_get_current_pos; + this->input_plugin.get_length = rip_plugin_get_length; + this->input_plugin.get_blocksize = rip_plugin_get_blocksize; + this->input_plugin.get_mrl = rip_plugin_get_mrl; + this->input_plugin.get_optional_data = rip_plugin_get_optional_data; + this->input_plugin.dispose = rip_plugin_dispose; + this->input_plugin.input_class = main_plugin->input_class; + + return &this->input_plugin; +} diff --git a/src/xine-engine/xine.c b/src/xine-engine/xine.c index eb3e03f7f..5eaab21a1 100644 --- a/src/xine-engine/xine.c +++ b/src/xine-engine/xine.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: xine.c,v 1.253 2003/08/15 14:35:09 mroi Exp $ + * $Id: xine.c,v 1.254 2003/08/21 00:37:29 miguelfreitas Exp $ */ /* @@ -576,6 +576,44 @@ static int xine_open_internal (xine_stream_t *stream, const char *mrl) { } continue; } + if (strncasecmp(stream_setup, "rip", 3) == 0) { + if (*(stream_setup += 3) == ':') { + /* filename to rip */ + const char *tmp = ++stream_setup; + char *filename; + input_plugin_t *input_rip; + + stream_setup = strchr(stream_setup, ';'); + if (stream_setup) { + filename = (char *)malloc(stream_setup - tmp + 1); + memcpy(filename, tmp, stream_setup - tmp); + filename[stream_setup - tmp] = '\0'; + } else { + filename = (char *)malloc(strlen(tmp)); + memcpy(filename, tmp, strlen(tmp)); + filename[strlen(tmp)] = '\0'; + } + + xine_log(stream->xine, XINE_LOG_MSG, + _("xine: join rip input plugin\n")); + input_rip = rip_plugin_get_instance (stream, filename); + if( input_rip ) { + stream->input_plugin = input_rip; + } else { + printf("xine: error opening rip plugin instance\n"); + stream->err = XINE_ERROR_MALFORMED_MRL; + stream->status = XINE_STATUS_STOP; + return 0; + } + + } else { + printf("xine: error while parsing mrl\n"); + stream->err = XINE_ERROR_MALFORMED_MRL; + stream->status = XINE_STATUS_STOP; + return 0; + } + continue; + } if (strncasecmp(stream_setup, "lastdemuxprobe", 14) == 0) { if (*(stream_setup += 14) == ':') { /* all demuxers will be probed before the specified one */ diff --git a/src/xine-engine/xine_internal.h b/src/xine-engine/xine_internal.h index 2610288f3..c0c92b7a9 100644 --- a/src/xine-engine/xine_internal.h +++ b/src/xine-engine/xine_internal.h @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: xine_internal.h,v 1.138 2003/05/20 13:50:57 mroi Exp $ + * $Id: xine_internal.h,v 1.139 2003/08/21 00:37:29 miguelfreitas Exp $ * */ @@ -289,6 +289,7 @@ input_plugin_t *find_input_plugin (xine_stream_t *stream, const char *mrl); demux_plugin_t *find_demux_plugin (xine_stream_t *stream, input_plugin_t *input); demux_plugin_t *find_demux_plugin_by_name (xine_stream_t *stream, const char *name, input_plugin_t *input); demux_plugin_t *find_demux_plugin_last_probe(xine_stream_t *stream, const char *last_demux_name, input_plugin_t *input); +input_plugin_t *rip_plugin_get_instance (xine_stream_t *stream, const char *filename); /* create decoder fifos and threads */ |