/* * Copyright (C) 2009 Luo Jinghua * * PPStream plugin for xine * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA * * pps input plugin */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #define LOG_MODULE "input_pps" #define LOG_VERBOSE /* #define LOG */ #include #include #include #include "pps-fixed.h" #ifndef EXPORTED #define EXPORTED #endif typedef struct { input_class_t input_class; xine_t *xine; } pps_input_class_t; typedef struct { input_plugin_t input_plugin; int fd; int size; xine_stream_t *stream; char *mrl; off_t curpos; } pps_input_plugin_t; static off_t pps_plugin_read (input_plugin_t *this_gen, char *buf, off_t len) { pps_input_plugin_t *this = (pps_input_plugin_t *) this_gen; int ret; lprintf ("pps_plugin_read: %"PRId64" bytes ...\n", len); while (1) { struct timeval tv; int error; tv.tv_sec = 0; tv.tv_usec = 500000; ret = ppsvod_read(this->fd, buf, len, this->curpos, &tv); error = errno; if (ret >= 0) break; if (error != EAGAIN) return -1; usleep (5000); } if (ret > 0) this->curpos += ret; return ret; } static buf_element_t *pps_plugin_read_block (input_plugin_t *this_gen, fifo_buffer_t *fifo, off_t todo) { /*pps_input_plugin_t *this = (pps_input_plugin_t *) this_gen; */ buf_element_t *buf = fifo->buffer_pool_alloc (fifo); int total_bytes; lprintf ("pps_plugin_read_block: %"PRId64" bytes...\n", todo); if (todo > buf->max_size) todo = buf->max_size; if (todo < 0) { buf->free_buffer (buf); return NULL; } buf->content = buf->mem; buf->type = BUF_DEMUX_BLOCK; total_bytes = pps_plugin_read (this_gen, (char*)buf->content, todo); if (total_bytes != todo) { buf->free_buffer (buf); return NULL; } buf->size = total_bytes; return buf; } static off_t pps_plugin_seek (input_plugin_t *this_gen, off_t offset, int origin) { pps_input_plugin_t *this = (pps_input_plugin_t *) this_gen; int ret; lprintf ("seek %"PRId64" bytes, origin %d\n", offset, origin); /* only realtive forward-seeking is implemented */ if (origin == SEEK_CUR) { offset += this->curpos; } else if (origin == SEEK_END) { if (this->size == -1) return -1; offset = this->size - offset; } ret = ppsvod_seek (this->fd, offset); if (ret < 0) { return -1; } this->curpos = offset; return this->curpos; } static off_t pps_plugin_get_length (input_plugin_t *this_gen) { pps_input_plugin_t *this = (pps_input_plugin_t *) this_gen; if (this->size == -1) this->size = ppsvod_get_file_length(this->fd); return this->size; } static uint32_t pps_plugin_get_capabilities (input_plugin_t *this_gen) { return INPUT_CAP_SEEKABLE; } static uint32_t pps_plugin_get_blocksize (input_plugin_t *this_gen) { return 0; } static off_t pps_plugin_get_current_pos (input_plugin_t *this_gen){ pps_input_plugin_t *this = (pps_input_plugin_t *) this_gen; /* printf ("current pos is %"PRId64"\n", this->curpos); */ return this->curpos; } static int pps_plugin_event_callback (int index, pps_event event) { return 0; } static void pps_plugin_dispose (input_plugin_t *this_gen) { pps_input_plugin_t *this = (pps_input_plugin_t *) this_gen; if (this->fd >= 0) { ppsvod_stop_item(this->fd); ppsvod_remove_item(this->fd); this->fd = -1; } if(this->mrl) free(this->mrl); ppsvod_destroy(); free (this); } static const char* pps_plugin_get_mrl (input_plugin_t *this_gen) { pps_input_plugin_t *this = (pps_input_plugin_t *) this_gen; return this->mrl; } static int pps_plugin_get_optional_data (input_plugin_t *this_gen, void *data, int data_type) { #if 0 pps_input_plugin_t *this = (pps_input_plugin_t *) this_gen; switch (data_type) { case INPUT_OPTIONAL_DATA_PREVIEW: break; } #endif return INPUT_OPTIONAL_UNSUPPORTED; } static int pps_plugin_open (input_plugin_t *this_gen) { pps_input_plugin_t *this = (pps_input_plugin_t *) this_gen; int ret; lprintf ("trying to open '%s'\n", this->mrl); if (ppsvod_create("ppstream", "demo", "ppsdemo001", pps_plugin_event_callback) < 0) { lprintf ("Failed to initialize ppsvod.\n"); return 0; } ret = ppsvod_add_item(this->mrl, 0); if (ret < 0) { lprintf ("Failed to open url.\n"); ppsvod_destroy(); return 0; } this->fd = ret; ret = ppsvod_play_item(this->fd, NULL); if (ret < 0) { lprintf ("Failed to play url.\n"); ppsvod_remove_item(this->fd); ppsvod_destroy(); return 0; } this->size = ppsvod_get_file_length(this->fd); return 1; } static input_plugin_t *pps_class_get_instance (input_class_t *cls_gen, xine_stream_t *stream, const char *mrl) { /* pps_input_class_t *cls = (pps_input_class_t *) cls_gen; */ pps_input_plugin_t *this; if (strncasecmp (mrl, "pps://", 6) && strncasecmp (mrl, "tvod://", 7)) return NULL; this = calloc(1, sizeof (pps_input_plugin_t)); this->stream = stream; this->fd = -1; this->mrl = strdup (mrl); this->input_plugin.open = pps_plugin_open; this->input_plugin.get_capabilities = pps_plugin_get_capabilities; this->input_plugin.read = pps_plugin_read; this->input_plugin.read_block = pps_plugin_read_block; this->input_plugin.seek = pps_plugin_seek; this->input_plugin.get_current_pos = pps_plugin_get_current_pos; this->input_plugin.get_length = pps_plugin_get_length; this->input_plugin.get_blocksize = pps_plugin_get_blocksize; this->input_plugin.get_mrl = pps_plugin_get_mrl; this->input_plugin.dispose = pps_plugin_dispose; this->input_plugin.get_optional_data = pps_plugin_get_optional_data; this->input_plugin.input_class = cls_gen; return &this->input_plugin; } /* * pps input plugin class stuff */ static const char *pps_class_get_description (input_class_t *this_gen) { return _("pps streaming input plugin"); } static const char *pps_class_get_identifier (input_class_t *this_gen) { return "pps"; } static void pps_class_dispose (input_class_t *this_gen) { pps_input_class_t *this = (pps_input_class_t *) this_gen; free (this); } static void *init_class (xine_t *xine, void *data) { pps_input_class_t *this; this = calloc(1, sizeof (pps_input_class_t)); this->xine = xine; this->input_class.get_instance = pps_class_get_instance; this->input_class.get_identifier = pps_class_get_identifier; this->input_class.get_description = pps_class_get_description; this->input_class.get_dir = NULL; this->input_class.get_autoplay_list = NULL; this->input_class.dispose = pps_class_dispose; this->input_class.eject_media = NULL; return this; } /* * exported plugin catalog entry */ const plugin_info_t xine_plugin_info[] EXPORTED = { /* type, API, "name", version, special_info, init_function */ { PLUGIN_INPUT, 17, "pps", XINE_VERSION_CODE, NULL, init_class }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } };