📄 vod.c
字号:
#include "httppil.h"#include "httpapi.h"#define VOD_PATH "video"typedef struct _PL_ENTRY { struct _PL_ENTRY *next; void* data;} PL_ENTRY;typedef enum { ACT_NOTHING=0, ACT_SKIP,} VOD_CLIENT_ACTIONS;typedef int (*PL_ENUM_CALLBACK)(PL_ENTRY *entry, void *arg); PL_ENTRY* plAddEntry(PL_ENTRY **hdr, void* data);PL_ENTRY* plFindEntry(PL_ENTRY *hdr, void* data);void* plGetEntry(PL_ENTRY **hdr);void* plDelEntry(PL_ENTRY **hdr, void* data);void* plAdvanceEntry(PL_ENTRY **hdr, void* data);int plEnumEntries(PL_ENTRY *hdr, PL_ENUM_CALLBACK pfnEnumCallback, void *arg, int from, int count);static PL_ENTRY* plhdr=NULL;static int listindex=0,listcount=0;static PL_ENTRY played={NULL,NULL};static PL_ENTRY *lastplayed=&played;static int playcount=0;static char vodbuf[256];static char streamPath[64];static char *vodroot=NULL;static char *htmlbuf=NULL;static int vodLookForFile(char* keyword, char *pathbuf){ char subdir[4]; char buf[128],httppath[64]; int ret; subdir[0]=keyword[0]; subdir[1]=keyword[1]; subdir[2]=0; sprintf(httppath,"%s/%s",vodroot,subdir); for (ret=ReadDir(httppath,buf);!ret;ret=ReadDir(NULL,buf)) { if (strstr(buf,keyword)) { if (pathbuf) sprintf(pathbuf,"%s/%s/%s",VOD_PATH,subdir,buf); break; } } ReadDir(NULL,NULL); return ret?0:1;}static int EnumSelections(PL_ENTRY *entry, void *arg){ char **p=(char**)arg; *p+=sprintf(*p,"%05d ",entry->data); return 0;}static int EnumSelectionsHtml(PL_ENTRY *entry, void *arg){ char **p=(char**)arg,*q,*s; char keyword[16]; char buf[128]; int len; sprintf(keyword,"%05d",entry->data); vodLookForFile(keyword,buf); s=strstr(buf,keyword); q=strchr(s,'.'); if (!q) return 0; *q=0; len=sprintf(*p,"<p>%s <a href='/vod/del=%s&inf=list'>[Del]</a> <a href='/vod/adv=%s&inf=list'>[Top]</a></p>",s,keyword,keyword); *p+=len; return 0;}int uhVodInit(HttpParam* hp, void* arg){ if (!arg) { //initialization vodroot=malloc(strlen(hp->pchWebPath)+7); sprintf(vodroot,"%s/%s",hp->pchWebPath,VOD_PATH); } else { //de-initialization if (vodroot) free(vodroot); if (htmlbuf) free(htmlbuf); } return 0;}#define VOD_LOOP_COUNT 4int uhVodStream(UrlHandlerParam* param){ if (param->request->iStartByte==0) { int code; while ((code=(int)plGetEntry(&plhdr))) { char keyword[16]; sprintf(keyword,"%05d",code); if (vodLookForFile(keyword,streamPath)) break; DEBUG("[vod] %d not available\n",code); } if (code) { lastplayed->next=malloc(sizeof(PL_ENTRY)); lastplayed=lastplayed->next; lastplayed->data=(void*)code; lastplayed->next=NULL; playcount++; } else { /* int i,cnt=0; do { i=rand() * VOD_LOOP_COUNT / (RAND_MAX+1); sprintf(streamPath,"%s/vodloop%d.mkv",vodroot,i); } while(!IsFileExist(streamPath) && ++cnt<VOD_LOOP_COUNT); */ sprintf(streamPath,"%s/vodloop.mkv",VOD_PATH); } } strcpy(param->pucBuffer,streamPath); DEBUG("[vod] stream: %s\n",streamPath); return FLAG_DATA_FILE;}int uhVod(UrlHandlerParam* param){ char *req=param->pucRequest; char *pbuf=param->pucBuffer; static VOD_CLIENT_ACTIONS action=0; param->fileType=HTTPFILETYPE_TEXT; for(;;) { switch (GETDWORD(req)) { case DEFDWORD('n','o','p',0): strcpy(pbuf,"state=OK"); break; case DEFDWORD('c','m','d','='): action=ACT_SKIP; strcpy(pbuf,"Play next"); param->iDataBytes=9; return FLAG_DATA_RAW; case DEFDWORD('i','n','f','='): { int itemcount=0; req+=4; switch (GETDWORD(req)) { case DEFDWORD('l','i','s','t'): itemcount=listcount; break; case DEFDWORD('h','i','s','t'): itemcount=playcount; break; } pbuf=param->pucBuffer; if (itemcount>16) { if (htmlbuf) free(htmlbuf); htmlbuf=malloc(itemcount*128); pbuf=htmlbuf; param->pucBuffer=htmlbuf; } //FIXME: css file path pbuf+=sprintf(pbuf,"<html><head><link href='/vodsys/default.css' rel='stylesheet' type='text/css'></head><body>"); switch (GETDWORD(req)) { case DEFDWORD('l','i','s','t'): { int count; count=plEnumEntries(plhdr, EnumSelectionsHtml, (void*)&pbuf, 0, 0); pbuf+=sprintf(pbuf,"<p>Total: %d</p>",count); } break; case DEFDWORD('h','i','s','t'): { PL_ENTRY *pl; pbuf+=sprintf(pbuf,"<html><body>"); for (pl=played.next; pl; pl=pl->next) { pbuf+=sprintf(pbuf,"<p>%05d</p>",pl->data); } pbuf+=sprintf(pbuf,"<p>Total: %d</p>",playcount); } break; } pbuf+=sprintf(pbuf,"</body></html>"); param->iDataBytes=(int)(pbuf)-(int)(param->pucBuffer); param->fileType=HTTPFILETYPE_HTML; } return FLAG_DATA_RAW; case DEFDWORD('l','s','t','='): switch (GETDWORD(req+4)) { case DEFDWORD('n','e','x','t'): if (listindex<listcount-4) listindex+=4; break; case DEFDWORD('p','r','e','v'): listindex-=4; if (listindex<0) listindex=0; break; } case DEFDWORD('l','s','t',0): if (listindex>=listcount) listindex=0; if (listcount==0) { strcpy(pbuf,"osd=[empty]"); } else { char *p; strcpy(pbuf,"osd="); p=pbuf+4; if (listindex>0) *(p++)='<'; plEnumEntries(plhdr, EnumSelections, (void*)&p, listindex, 4); *p=0; if (listindex+4<listcount) strcat(pbuf,">"); DEBUG("[vod] list item %d-%d\n",listindex,listindex+3); } strcat(pbuf,"\notm=900"); break; case DEFDWORD('a','d','d','='): { void *data=NULL; int code; req+=4; code=atoi(req); if (plFindEntry(plhdr,(void*)code)) { strcpy(pbuf,"osd=ordered"); break; } if (vodLookForFile(req,NULL)) { data=plAddEntry(&plhdr,(void*)code); } if (data) sprintf(pbuf,"osd=[%s]\n",req); else strcpy(pbuf,"osd=error"); } break; case DEFDWORD('d','e','l','='): { void *data=NULL; int code=atoi(req+4); if (code) data=plDelEntry(&plhdr,(void*)code); if (data) sprintf(pbuf,"osd=%05d deleted",code); else strcpy(pbuf,"osd=error"); } break; case DEFDWORD('a','d','v','='): { void *data=NULL; int code=atoi(req+4); if (code) data=plAdvanceEntry(&plhdr,(void*)code); if (data) sprintf(pbuf,"osd=%05d topped",code); else strcpy(pbuf,"osd=error"); } break; case DEFDWORD('c','n','t',0): sprintf(pbuf,"osd=%d",playcount); break; default: strcpy(pbuf,"Invalid request"); } pbuf+=strlen(pbuf); if (!(req=strchr(req,'&'))) break; req++; } if (action) { pbuf+=sprintf(pbuf,"\nact=skip"); action=ACT_NOTHING; } param->iDataBytes=(int)pbuf-(int)(param->pucBuffer); return FLAG_DATA_RAW;}//////////////////////////////////////////////////////////////////// Playlist implementation//////////////////////////////////////////////////////////////////PL_ENTRY* plAddEntry(PL_ENTRY **hdr, void* data){ PL_ENTRY *ptr=*hdr; if (!ptr) { // allocate header *hdr=(PL_ENTRY*)malloc(sizeof(PL_ENTRY)); ptr=*hdr; } else { // travel to the end of list while (ptr->next) ptr=ptr->next; ptr->next=(PL_ENTRY*)malloc(sizeof(PL_ENTRY)); ptr=ptr->next; } ptr->data=data; ptr->next=NULL; listcount++; return ptr;}void* plGetEntry(PL_ENTRY **hdr){ PL_ENTRY *ptr=*hdr; void* data; if (!ptr) return NULL; data=ptr->data; *hdr=ptr->next; free(ptr); listcount--; return data;}PL_ENTRY* plFindEntry(PL_ENTRY *hdr, void* data){ PL_ENTRY *ptr; for (ptr=hdr; ptr; ptr=ptr->next) { if (ptr->data==data) return ptr; } return NULL;}void* plDelEntry(PL_ENTRY **hdr, void* data){ PL_ENTRY *ptr=*hdr,*prev=NULL; void* deleted; if (!ptr) return NULL; if (ptr->data==data) { deleted=ptr->data; *hdr=ptr->next; free(ptr); listcount--; return deleted; } for (prev=ptr, ptr=ptr->next; ptr; prev=ptr, ptr=ptr->next) { if (ptr->data==data) { deleted=ptr->data; prev->next=ptr->next; free(ptr); listcount--; return deleted; } } return NULL;}void* plAdvanceEntry(PL_ENTRY **hdr, void* data){ PL_ENTRY *ptr=*hdr,*prev=NULL; while (ptr) { if (ptr->data==data) { if (!prev) return 0; prev->next=ptr->next; ptr->next=*hdr; *hdr=ptr; return ptr; } prev=ptr; ptr=ptr->next; } return NULL;}int plEnumEntries(PL_ENTRY *hdr, PL_ENUM_CALLBACK pfnEnumCallback, void *arg, int from, int count){ PL_ENTRY *ptr=hdr; int hits; if (!pfnEnumCallback) return -1; for (hits=0;ptr;ptr=ptr->next,hits++) { if (count && hits>=from+count) return hits; if (hits>=from) if ((*pfnEnumCallback)(ptr, arg)) break; } return hits;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -