diff options
author | Luo Jinghua <sunmoon1997@gmail.com> | 2009-09-02 15:10:53 +0800 |
---|---|---|
committer | Luo Jinghua <sunmoon1997@gmail.com> | 2009-09-02 15:10:53 +0800 |
commit | 4cf9ceff200476e001737d56ad9ba3f4690d87a5 (patch) | |
tree | 9ad4fad80d6555b0b01db9700b15c9f2d522ba70 |
-rw-r--r-- | Makefile | 20 | ||||
-rw-r--r-- | input_pps.c | 338 | ||||
-rw-r--r-- | pps-fixed.h | 12 | ||||
-rw-r--r-- | pps.h | 372 |
4 files changed, 742 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d384d03 --- /dev/null +++ b/Makefile @@ -0,0 +1,20 @@ +plugindir = `xine-config --plugindir` +CFLAGS = -Wall -g -O0 -fPIC -shared `xine-config --cflags` +LIBS = -lppswrapper `xine-config --libs` +LDFLAGS = -shared +plugin = xineplug_inp_pps.so + +all: $(plugin) + +.c.o: + $(CC) -o $@ $< $(CFLAGS) + +$(plugin): input_pps.o + $(CC) -o $@ $< $(LIBS) $(LDFLAGS) + +install: $(plugin) + install $< $(plugindir) + +clean: + -rm *.o + -rm *.so diff --git a/input_pps.c b/input_pps.c new file mode 100644 index 0000000..7de012d --- /dev/null +++ b/input_pps.c @@ -0,0 +1,338 @@ +/* + * Copyright (C) 2009 Luo Jinghua<sunmoon1997@gmail.com> + * + * 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 <unistd.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> + +#define LOG_MODULE "input_pps" +#define LOG_VERBOSE +/* +#define LOG +*/ + +#include <xine/xine_internal.h> +#include <xine/xineutils.h> +#include <xine/input_plugin.h> + +#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 } +}; + diff --git a/pps-fixed.h b/pps-fixed.h new file mode 100644 index 0000000..80014a8 --- /dev/null +++ b/pps-fixed.h @@ -0,0 +1,12 @@ +#ifndef PPS_FIXED_H +#define PPS_FIXED_H + +#define uint64_t pps_uint64_t +#define int64_t pps_int64_t + +#include "pps.h" + +#undef uint64_t +#undef int64_t + +#endif @@ -0,0 +1,372 @@ +#ifndef __PPS_H__ +#define __PPS_H__ + + +#ifndef HASH_VALUE_LENGTH +#define HASH_VALUE_LENGTH 20 +#endif + +#define PPS_EXTRA_MSG_LEN 64 +#define PPS_MAX_MAP_SIZE 65536 + +typedef unsigned long long uint64_t; +typedef long long int64_t; + +typedef enum pps_event_id +{ + EPPS_SERVER_TIMEOUT, // 0, 连接服务器超时,停止播放 + EPPS_NO_SERVER, // 1, 找不到服务器,停止播放 + EPPS_SERVER_NO_RESPONSE, // 2, 服务器未响应,停止播放 + EPPS_SERVER_INVALID, // 3, 解析服务器域名失败. + EPPS_VERSION_LOW, // 4, 客户端版本号太低,退出网络 + EPPS_CLIENT_NAME, // 5, 客户端名称或引用页不正确,退出播放 + EPPS_URL_INVALID, // 6, 播放的文件不存在或网址错误 + EPPS_NO_SERVICE, // 7, 服务不存在,停止播放 + EPPS_OUT_OF_SERVICE, // 8, 不在服务区. + EPPS_MEDIA_INFO_ERROR, // 9, 媒体信息加载时错误.. + EPPS_INDEX_INFO_ERROR, // 10, 媒体索引信息错误 + EPPS_NO_INDEX, // 11, 没有获取到媒体索引信息,不能拖动播放位置 + EPPS_NO_MEIDIA, // 12, 找不到媒体 + EPPS_MULTI_INSTANCE, // 13, 请确定是否有另一个实例正在播放此文件 + EPPS_PREPARE_MEDIA_INFO, // 14, 正在准备媒体信息 + EPPS_GETTING_MEDIA_INFO, // 15, 正在获取媒体信息 + EPPS_GETTING_INDEX_INFO, // 16, 正在获取媒体索引信息 + EPPS_PLAYING, // 17, 正在播放 + EPPS_BUFFERING, // 18, 正在缓冲数据 + EPPS_CONNECTING, // 19, 正在连入网络 + EPPS_MEDIA_READY, // 20, 准备媒体就绪 + EPPS_PARSING_SERVER, // 21, 正在解析服务器域名.. + EPPS_GET_MEDIA_INFO, // 22, 已成功获取到媒体信息. + EPPS_BUFFERED, // 23, 数据缓冲完毕. + EPPS_PREPARE_MEDIA, // 24, 准备媒体 + EPPS_STORAGE_ERROR, // 25. 访问存储器失败 + EPPS_QUIT, // 26. 程序退出 + + EPPS_DATA_TIMEOUT, // 27, 等待数据超时 + + EPPS_UPDATING, // 28, 正在升级 + EPPS_UPDATE_FAILED, // 29, 升级失败 + EPPS_UPDATE_OK, // 30, 升级成功 +}pps_event_id; + +typedef struct pps_event +{ + pps_event_id id; + unsigned int wparam; + unsigned int lparam; + char extra[PPS_EXTRA_MSG_LEN]; +}pps_event; + +#ifdef __cplusplus +extern "C" { +#endif + +typedef int (*pps_callback)(int index, pps_event event); + +#ifdef __cplusplus +} +#endif + + +typedef struct ppsvod_iteminfo +{ + int index; + char hash_id[HASH_VALUE_LENGTH]; // task hash id + char *file_name; // save name + unsigned int file_size; // total file size + int progress; // download percent + int down_speed; // download speed (byte/s) + int up_speed; // upload speed (byte/s) + int peer_count; // peer count has connected + int status; // has the task been started? +}ppsvod_iteminfo; + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Description: ppsvod initialization, must be called before all. + * param: Datatype Param name In/Out Comment + * const char * oem_name in + * const char * terminal_type in + * const char * device_id in + * pps_callback pcallback in callback function pointer + * return: int return 0 if success; -1 if failed. + */ +int ppsvod_create(const char *oem_name, + const char * terminal_type, + const char *device_id, + pps_callback pcallback); + +/* + * Description: uninitialize ppsvod, call this fuction when you want to exit ppsvod. + * param: Datatype Param name In/Out Comment + * void + * return: int return 0 if success; -1 if failed + */ +int ppsvod_destroy(void); + +/* + * Description: Add an item into ppsvod internal list. + * param: Datatype Param name In/Out Comment + * char * url In url to add + * int vip_flag In flag for vip items + * return: int return a file descriptor if success; -1 if failed. + */ +int ppsvod_add_item(char *url, int vip_flag); + +/* + * Description: Remove an item from ppsvod internal list. + * param: Datatype Param name In/Out Comment + * int fd In file descriptor + * return: int return 0 if success; -1 if failed. + */ +int ppsvod_remove_item(int fd); + +/* + * Description: start to play a file. + * param: Datatype Param name In/Out Comment + * int fd In file descriptor + * const char* validcode In + * return: int return 0 if success; -1 if failed. + */ +int ppsvod_play_item(int fd, const char * validcode); + +/* + * Description: stop the playing url. + * param: Datatype Param name In/Out Comment + * int fd In file descriptor + * return: int return 0 if success; -1 if failed; -3 means validcode error. + */ +int ppsvod_stop_item(int fd); + +/* + * Description: read data. + * param: Datatype Param name In/Out Comment + * int fd In file descriptor + * char * buffer Out buffer to store data + * unsigned int length In data length + * unsigned int position In from where to read. + * struct timeval* wait_time In time length that read() can block + * return: int return length of data if success; -1 if failed(errno + * is set to EAGAIN if data is temporarily unavailable; etherwise, + * some error happens or EOF reaches). + */ +int ppsvod_read(int fd, char *buffer, unsigned int length, unsigned int position, struct timeval *wait_time); + +/* + * Description: Drop read operation + * param: Datatype Param name In/Out Comment + * int fd In file descriptor + */ +void ppsvod_drop_read(int fd); + +/* + * Description: seeking within a playing url. + * param: Datatype Param name In/Out Comment + * int fd In file descriptor + * unsigned int position In seeking destination + * return: int return 0 if success; -1 if failed. + */ +int ppsvod_seek(int fd, unsigned int position); + +/* + * Description: get total file length + * param: Datatype Param name In/Out Comment + * int fd In file descriptor + * return: int return file length if success; -1 if failed. + */ +int ppsvod_get_file_length(int fd); + +/* + * Description: validate url. + * param: Datatype Param name In/Out Comment + * const char* url In url to check + * return: int return 0 if success; -1 if failed. + */ +int ppsvod_check_url(const char* url); + +/* + * Description: Get information for a playing file. + * param: Datatype Param name In/Out Comment + * int fd In file descriptor + * return: ppsvod_iteminfo* return a pointer to ppsvod_iteminfo if success; + * NULL if failed. + */ +ppsvod_iteminfo *ppsvod_get_item_info(int fd); + +/* + * Description: Free memory of a ppsvod_iteminfo* pointer + * param: Datatype Param name In/Out Comment + * ppsvod_iteminfo* piteminfo In pointer returned by ppsvod_get_item_info + * return: void + */ +void ppsvod_free_item_info(ppsvod_iteminfo *piteminfo); + +/* + * APIs for playlist operation + */ + +/* + * Define download, unzip and parse vodlist file status. + * vodlist status use highest 4 bits to express stage, use + * lowest 8 bits to express every stage process + */ +#define VODLIST_IDLE 0x0 +#define VODLIST_DOWNLOADING 0x10000000 +#define VODLIST_UNCOMPRESSING 0x20000000 +#define VODLIST_PARSING 0x40000000 +#define VODLIST_UPDATE_SUCCESS 0x80000000 +#define VODLIST_UPDATE_FAIL 0xff000000 + +typedef struct __ppscategory +{ + int id; /* category or subcategory id */ + char *name; /* category or subcategory num */ + int type; /* subcategory type. 0: movie, 1: teleplay */ + int subcatnum; /* subcategory number under this category */ + struct __ppscategory *psubcat; /* subcategory array */ + + struct __ppscategory *next; +}ppscategory; + + +typedef struct __ppsitem +{ + int id; /* Item id */ + int index; /* Item index */ + int size; /* Item size (MB) */ + int duration; /* Item duration (Minute)*/ + char *format; /* file format (rm/rmvb/wmv) */ + int bitrate; /* bitrate */ + char *ppsurl; /* pps vod url */ + int vipflag; /* vip flags */ + struct __ppsitem *next; +}ppsitem; + +typedef struct __ppschannel +{ + char *name; /* channel name */ + char *director; + char *actor; + char *area; + int size; /* all items' total size under this channel (MB) */ + char *pubtime; /* publish time */ + int duration; /* all items' total duration time under this channel (Min) */ + char *lang; /* channel language */ + char *desc; /* channel description */ + char *BImgUrl; /* Big Image Url */ + char *SImgUrl; /* Small Image Url */ + int itemnum; /* num of items */ + struct __ppsitem *pitems; /* point to items list */ + + struct __ppschannel *next; +}ppschannel; + + +/* + * description: vod list initialization, must be called before all. + * param: datatype param name in/out comment + * void + * return: int return 0 if success; -1 if failed. +*/ +int pps_vodlist_init(void); + +/* + * description: vod list uninitialize, call this fuction when you want to exit pps vodlist. + * param: datatype param name in/out comment + * void + * return: int return 0 if success; -1 if failed. +*/ +int pps_vodlist_uninit(void); + +/* + * description: get all categories and sub categories list. + * param: datatype param name in/out comment + * void + * return: ppscategory* pointer of all categories, null if failed. +*/ +ppscategory *pps_vodlist_getcat(int *catnum); + +/* + * description: get channels under pointed catogory and sub category. + * param: datatype param name in/out comment + * int catid in class id + * int subcatid in sub class id + * int page_size in channels one page have + * int page_num in page num which want to query + * return: ppschannel pointer of channels, null if failed. +*/ +ppschannel *pps_vodlist_getchannel(int catid, int subcatid, int page_size, int page_num); + +/* + * Description: configure directory for store cache, config, data and logs. + * param: Datatype Param name In/Out Comment + * const char* root_path In root path used to store + * return: int return 0 if success, -1 if failed. + * comment: + */ +int ppsvod_save_config_dir(const char * root_path); + +/* + * Description: load configure directory for store cache, config, data and logs. + * param: Datatype Param name In/Out Comment + * void + * return: char* return root path if success, NULL if failed. + * comment: + */ +char *ppsvod_get_config_dir(void); + +/* + * Description: load default configure directory for store cache, config, data and logs. + * param: Datatype Param name In/Out Comment + * void + * return: int return 0 if success, -1 if failed. + * comment: + */ +int ppsvod_default_config_dir(void); + +/* + * Description: Deposit money for PPS VIP account + * param: Datatype Param name In/Out Comment + * const char* password In 17 numbers sold by pps + * return: int return 0 if success, -1 if failed. + * comment: + */ +int ppsvod_charge(const char* password); + +/* + * Description: Get account type of current user + * param: Datatype Param name In/Out Comment + * void + * return: int return -1 if failed; + * return 0: Non-VIP user + * return 1: Payment VIP + * comment: + */ +int ppsvod_get_account_type(void); + +/* + * Description: Get expire time of vip qualification + * param: Datatype Param name In/Out Comment + * char* time Out memory allocated by caller + * return: int -1: failed + * 0: OK + */ +int ppsvod_get_vip_expire_time(char *time); + + +/* + * Description: Get time from network + * param: Datatype Param name In/Out Comment + * struct timeval tv Out time since 1970 + * return: int return 0 if success, -1 if failed. + * comment: + */ +int ppsvod_get_time(struct timeval *tv); + +#ifdef __cplusplus +} +#endif +#endif // __PPS_H__ |