⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vod.c

📁 MiniWeb是一个针对嵌入式应用而开发的微型Web Server
💻 C
字号:
#include "httppil.h"
#include "httpapi.h"

#define MAX_SESSIONS 2
#define PRE_ALLOC_UNIT 16
#define LOOP_VIDEO "vodloop.mp4"

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[MAX_SESSIONS];
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 int playingcode = 0;
static char *vodroot=NULL;
static char *htmlbuf=NULL;

static char** filelist = NULL;
static int filecount = 0;
static char** vodlist;
static int prefixlen = 0;

int EnumDir(char* pchDir)
{
	int i;
	char buf[256];
	char* path;
	int dirlen = strlen(pchDir) + 1;
	int pathlen = 0;
	char** dirlist = NULL;
	int dircount = 0;

	for (i = ReadDir(pchDir, buf); !i; i = ReadDir(NULL, buf)) {
		int len;
		if (buf[0] == '.' && (buf[1] == 0 || (buf[1] == '.' && buf[2] == 0))) continue;
		len = dirlen + strlen(buf) + 1;
		if (len > pathlen) {
			if (pathlen) free(path);
			path = malloc(len);
			pathlen = len;
		}
		sprintf(path, "%s/%s", pchDir, buf);
		if (IsDir(path)) {
			if (!(dircount % PRE_ALLOC_UNIT)) {
				dirlist = realloc(dirlist, (dircount + PRE_ALLOC_UNIT) * sizeof(char*));
			}
			dirlist[dircount++] = strdup(buf);
		} else {
			if (!(filecount % PRE_ALLOC_UNIT)) {
				filelist = realloc(filelist, (filecount + PRE_ALLOC_UNIT) * sizeof(char*));
			}
			filelist[filecount++] = strdup(path + prefixlen);
		}
	}
	for (i = 0; i < dircount; i++) {
		int len = dirlen + strlen(dirlist[i]) + 1;
		if (len > pathlen) {
			if (pathlen) free(path);
			path = malloc(len);
			pathlen = len;
		}
		sprintf(path, "%s/%s", pchDir, dirlist[i]);
		free(dirlist[i]);
		printf("%s\n", path);
		EnumDir(path);
	}
	free(dirlist);
	if (pathlen) free(path);
	return 0;
}

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;
	int len;
	char *filename;
	
	q = vodlist[(int)entry->data];
	q = strrchr(q, '/');
	if (!q) return -1;
	filename = strdup(++q);
	q = strrchr(filename, '.');
	if (!q) return 0;
	*q=0;
	len=sprintf(*p,"<p>%s <a href='/vod/del=%05d&inf=list'>[Del]</a> <a href='/vod/adv=%05d&inf=list'>[Top]</a></p>",filename,entry->data,entry->data);
	*p+=len;
	free(filename);
	return 0;
}

void vodInit(HttpParam* hp)
{
	int i;
	int code = 0;
	memset(plhdr, 0, sizeof(plhdr));
	vodroot=malloc(strlen(hp->pchWebPath)+7);
	sprintf(vodroot,"%s",hp->pchWebPath);
	vodlist = calloc(100000, sizeof(char*));
	prefixlen = strlen(vodroot) + 1;
 	EnumDir(vodroot);
	for (i = 0; i < filecount; i++) {
		char *p = strrchr(filelist[i], '/');
		if (p && *(p + 6) == ' ') {
			code = atoi(p + 1);
			if (code > 0) {
				vodlist[code] = filelist[i];
			}
		}
	}
	for (i = 0; i < 100000; i++) {
		if (vodlist[i]) {
			printf("%s\n", vodlist[i]);
		}
	}
	printf("Count: %d\n", filecount);
}

int ehVod(MW_EVENT event, void* arg)
{
	switch (event) {
	case MW_INIT:
		vodInit(arg);
		break;
	case MW_UNINIT:
		//un-initialization
		if (vodroot) free(vodroot);
		if (htmlbuf) free(htmlbuf);
		break;
	}
	return 0;
}

#define VOD_LOOP_COUNT 4

#ifdef WIN32
#define OPEN_FLAG O_RDONLY|0x8000
#else
#define OPEN_FLAG O_RDONLY
#endif

int GetSessionId(HttpVariables* pxVars)
{
	if (pxVars) {
		char *v = mwGetVarValue(pxVars,"session");
		if (v) return atoi(v);		
	}
	return 0;
}

int uhVodStream(UrlHandlerParam* param)
{
	static int code = 0;
	static int prevtime = 0;
	int session = GetSessionId(param->pxVars);

	DBG("Session: %d\n", session);
	if (param->hs->request.iStartByte==0 && time(NULL) - prevtime > 3) {
		prevtime = time(NULL);
		while ((code=(int)plGetEntry(&plhdr[session]))) {
			char keyword[16];
			sprintf(keyword,"%05d",code);
			if (vodlist[code]) break;
			DBG("[vod] %d not available\n",code);
		}
		if (vodlist[code]) {
			lastplayed->next=malloc(sizeof(PL_ENTRY));
			lastplayed=lastplayed->next;
			lastplayed->data=(void*)code;
			lastplayed->next=NULL;
			playcount++;
			playingcode = code;
		}
	}
	if (!playingcode) {
		sprintf(param->pucBuffer,LOOP_VIDEO);
	} else {
		sprintf(param->pucBuffer,"%s", vodlist[playingcode]);
	}
	DBG("[vod] stream: %s\n",param->pucBuffer);
	return FLAG_DATA_FILE;
}

int uhVod(UrlHandlerParam* param)
{
	char *req=param->pucRequest;
	char *pbuf=param->pucBuffer;
	static VOD_CLIENT_ACTIONS action=0;
	int session = GetSessionId(param->pxVars);

	DBG("Session: %d\n", session);
	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[session], 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[session], EnumSelections, (void*)&p, listindex, 4);
				*p=0;
				if (listindex+4<listcount) strcat(pbuf,">");
				DBG("[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[session],(void*)code)) {
				strcpy(pbuf,"osd=ordered");
				break;
			}
			if (vodlist[code]) {
				data=plAddEntry(&plhdr[session],(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[session],(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[session],(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;
		case DEFDWORD('p','l','a','y'): {
			int code = (int)plGetEntry(&plhdr[session]);
			if (code) {
				sprintf(pbuf, "%s", vodlist[code]);
			} else {
				strcpy(pbuf, LOOP_VIDEO);
			}
			} 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 + -