[MPlayer-dev-eng] [RFC] -vo arcade

rsnel at cube.dyndns.org rsnel at cube.dyndns.org
Sat Sep 7 21:15:38 CEST 2002


Hello,

I wrote a vo driver for Tower T2 of the Bibliotheque nationale de France.
(see http://www.blinkenlights.de/arcade) If can be used by Project
Blinkenlights to play movies on this tower and by other people to
generate movies for playback on the same tower. Currently there are some
problems with realtime playback, I am working with people of Project
blinkenlights to resolve those problems.

----

Compilation:

compile mplayer with:
./configure --enable-arcade
make
make install

Usage:

mplayer -vo arcade:host=ruunat:11223 -vop scale=26:20 bar.mpg
mplayer -vo arcade:host=localhost -vop scale=26:20 bar.mpg
(the default port is 2323)

mplayer -vo arcade:file=foo.bml -vop scale=26:20 bar.mpg

mplayer -vo arcade:file=file1.bml:host=bla.com:123:file=file2.bml \
	-vop scale=26:20 bar.mpg

If you want to play with this driver you need blib-0.6, blinkentools-2.0
and blinkensim-2.0 (or newer versions), see
http://sven.gimp.org/blinkenlights .

-----

The patch is attached to this mail for review, if there are no objections
I will put the driver in CVS myself.

Greetings,

Rik.

-- 
Nothing is ever a total loss; it can always serve as a bad example.
-------------- next part --------------
diff -Nur -x CVS -x mplayer -x mencoder -x config.mak -x config.h -x *.a -x *.so -x *.o -x version.h -x configure.log -x .* -x *~ -x *.rej main/configure main.dev/configure
--- main/configure	Thu Sep  5 19:03:51 2002
+++ main.dev/configure	Sat Sep  7 20:31:47 2002
@@ -200,6 +200,7 @@
   --enable-tdfxfb        build with tdfxfb support [disable]
   --enable-directfb      build with DirectFB support [autodetect]
   --enable-zr            build with ZR360[56]7/ZR36060 support [autodetect]
+  --enable-arcade	 build with Blinkenlights Arcade support [disable]
 
 Audio:
   --disable-ossaudio     disable OSS sound support [autodetect]
@@ -975,6 +976,7 @@
 _tdfxfb=no
 _directfb=auto
 _zr=auto
+_arcade=no
 _largefiles=no
 _language=en
 _shm=auto
@@ -1130,6 +1132,8 @@
   --disable-directfb)	_directfb=no	;;
   --enable-zr)		_zr=yes		;;
   --disable-zr)		_zr=no		;;
+  --enable-arcade)	_arcade=yes	;;
+  --disable-arcade)	_arcade=no	;;
   --enable-mtrr)	_mtrr=yes	;;
   --disable-mtrr)	_mtrr=no	;;
   --enable-largefiles)	_largefiles=yes	;;
@@ -3743,6 +3747,17 @@
   echores "$_zr"
 fi
 
+echocheck "arcade"
+if test "$_arcade" = yes ; then
+  _def_arcade='#define HAVE_ARCADE 1'
+  _vosrc="$_vosrc vo_arcade.c"
+  _vomodules="arcade $_vomodules"
+else
+  _def_arcade='#undef HAVE_ARCADE'
+  _novomodules="arcade $_novomodules"
+fi
+echores "$_arcade"
+
 echocheck "XviD"
 cat > $TMPC << EOF
 #include <xvid.h>
@@ -4765,6 +4780,7 @@
 $_def_directfb
 $_def_directfb_version
 $_def_zr
+$_def_arcade
 $_def_mga
 $_def_xmga
 $_def_syncfb
diff -Nur -x CVS -x mplayer -x mencoder -x config.mak -x config.h -x *.a -x *.so -x *.o -x version.h -x configure.log -x .* -x *~ -x *.rej main/libvo/video_out.c main.dev/libvo/video_out.c
--- main/libvo/video_out.c	Mon Aug 26 13:56:44 2002
+++ main.dev/libvo/video_out.c	Sat Sep  7 20:31:10 2002
@@ -81,6 +81,7 @@
 extern vo_functions_t video_out_null;
 //extern vo_functions_t video_out_odivx;
 extern vo_functions_t video_out_zr;
+extern vo_functions_t video_out_arcade;
 extern vo_functions_t video_out_pgm;
 extern vo_functions_t video_out_md5;
 extern vo_functions_t video_out_syncfb;
@@ -163,6 +164,9 @@
 #endif
 #ifdef HAVE_ZR
 	&video_out_zr,
+#endif
+#ifdef HAVE_ARCADE
+	&video_out_arcade,
 #endif
 
 #ifdef HAVE_PNG
diff -Nur -x CVS -x mplayer -x mencoder -x config.mak -x config.h -x *.a -x *.so -x *.o -x version.h -x configure.log -x .* -x *~ -x *.rej main/libvo/vo_arcade.c main.dev/libvo/vo_arcade.c
--- main/libvo/vo_arcade.c	Thu Jan  1 01:00:00 1970
+++ main.dev/libvo/vo_arcade.c	Sat Sep  7 20:31:10 2002
@@ -0,0 +1,345 @@
+/* 
+ * vo_arcade.c - playback on Tower T2 of Bibliotheque nationale de France 
+ * 
+ * UDP socket handling copied from bsender.c part of blib-0.6: 
+ * http://sven.gimp.org/blinkenlights/
+ * Copyright (c)  2001-2001 The Blinkenlights Crew:
+ * 	Sven Neumann <sven at gimp.org>
+ * 	Michael Natterer <mitch at gimp.org>
+ * 	Daniel Mack <daniel at yoobay.net>
+ * (these portions are licensed under GNU GPL v2 or "(at your option)
+ * any later version")
+ * 
+ * Other stuff: Copyright (C) Rik Snel 2002, License GNU GPL v2
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <linux/types.h>
+
+#include "config.h"
+
+#include "video_out.h"
+#include "video_out_internal.h"
+#include "../mp_msg.h"
+#include "../cfgparser.h"
+#include "fastmemcpy.h"
+
+LIBVO_EXTERN (arcade)
+
+static vo_info_t vo_info = 
+{
+	"Blinkenlights Arcade driver: http://www.blinkenlights.de/arcade",
+	"arcade",
+	"Rik Snel <snel at phys.uu.nl>",
+	""
+};
+
+/* General variables */
+
+static unsigned char *image = NULL;
+static unsigned char *tmp = NULL;
+static int framenum, yoff, stride;
+static char *arcade_subdevice = NULL;
+static int prevpts = -1;
+
+typedef struct {
+	char *name; /* filename */
+	FILE *fp;
+} arcade_file_t;
+
+typedef struct {
+	char *name; /* hostname */
+	int port;
+	int fd; /* file descriptor */
+	struct sockaddr_in addr;
+} arcade_host_t;
+
+typedef struct {
+} arcade_frame_header_t;
+
+typedef struct {
+	uint32_t magic;
+	uint16_t height;
+	uint16_t width;
+	uint16_t channels;
+	uint16_t maxval;
+	unsigned char data[0];
+} arcade_packet_t;
+
+static arcade_packet_t *arcade_packet;
+
+/* arbitrary limit because I am too lazy to do proper memory management */
+#define ARCADE_MAX_FILES 16
+#define ARCADE_MAX_HOSTS 16
+static arcade_file_t arcade_files[ARCADE_MAX_FILES];
+static arcade_host_t arcade_hosts[ARCADE_MAX_HOSTS];
+static int no_arcade_files = 0;
+static int no_arcade_hosts = 0;
+
+static uint32_t config(uint32_t width, uint32_t height, uint32_t d_width, 
+	uint32_t d_height, uint32_t fullscreen, char *title, uint32_t format)
+{
+	framenum = 0;
+	if (format != IMGFMT_YV12) {
+		mp_msg(MSGT_VO, MSGL_ERR, "vo_arcade called with wrong format");
+		return 1;
+	}
+	if (width > 26) {
+		mp_msg(MSGT_VO, MSGL_ERR, "arcade: width of movie too large %d > 26\n", width);
+		return 1;
+	}	
+	if (height > 20) {
+		mp_msg(MSGT_VO, MSGL_ERR, "arcade: height of movie too large %d > 20\n", height);
+		return 1;
+	}	
+	if (!image) {
+		mp_msg(MSGT_VO, MSGL_ERR, "arcade: image should be initialized, internal error\n");
+		return 1;
+	}
+	printf("image=%p, arcade_packet=%p\n", image, arcade_packet);
+	memset(image, 128, 26*20); /* blank the Y part of the image */
+	mp_msg(MSGT_VO, MSGL_V, "vo_config arcade called\n");
+	return 0;
+}
+
+static const vo_info_t* get_info(void) {
+	return &vo_info;
+}
+
+static void draw_osd(void) {
+}
+
+static void flip_page (void) {
+	int i, j, k;
+	if (prevpts >= 0) {
+		for (i = 0; i < no_arcade_files; i++) {
+			fprintf(arcade_files[i].fp, 
+					"    <frame duration=\"%d\">\n", 
+					(vo_pts - prevpts)/90);
+			for (j = 0; j < 20; j++) {
+				fprintf(arcade_files[i].fp, "        <row>");
+				for (k = 0; k < 26; k++) 
+					fprintf(arcade_files[i].fp, "%02x", 
+							*(tmp + j * 26 + k));
+				fprintf(arcade_files[i].fp, "</row>\n");
+			}
+			fprintf(arcade_files[i].fp, "    </frame>\n");
+		}
+	}
+
+	memcpy(tmp, image, 26*20);
+	prevpts = vo_pts;
+	if (framenum%10 == 0) {
+	for (i = 0; i < no_arcade_hosts; i++) {
+		if (write(arcade_hosts[i].fd, arcade_packet, 26*20 + 12) 
+				!= 26*20 + 12) 
+			mp_msg(MSGT_VO, MSGL_ERR, "unable to send to %s\n",
+					arcade_hosts[i].name);
+	}
+	}
+	framenum++;
+	return;
+}
+
+static uint32_t draw_frame(uint8_t * src[]) {
+	int i, j;
+	char *source, *dest;
+	//printf("draw frame called\n");
+#if 0
+		zr_info_t *zr = &zr_info[j];
+		geo_t *g = &zr->g;
+		source = src[0] + 2*g->yoff*zr->vdec*zr->stride + 2*g->xoff;
+		dest = zr->image + 2*zr->off_y;
+		for (i = 0; i < g->height/zr->vdec; i++) {
+			memcpy(dest, source, zr->image_width*2);
+			dest += 2*zr->image_width;
+			source += zr->vdec*zr->stride;
+		}
+#endif 
+	return 0;
+}
+
+static uint32_t query_format(uint32_t format) {
+	if(format==IMGFMT_YV12 || format==IMGFMT_YUY2) 
+	    return VFCAP_CSP_SUPPORTED|VFCAP_CSP_SUPPORTED_BY_HW;
+	return 0;
+}
+
+static void uninit(void) {
+	int i;
+	mp_msg(MSGT_VO, MSGL_V, "arcade: uninit called\n");
+	free(arcade_packet);
+	free(arcade_subdevice);
+	for (i = 0; i < no_arcade_files; i++) {
+		fprintf(arcade_files[i].fp, "</blm>\n");
+		fclose(arcade_files[i].fp);
+	}
+	for (i = 0; i < no_arcade_hosts; i++) close(arcade_hosts[i].fd);
+}
+
+static void check_events(void) {
+}
+
+static uint32_t draw_slice(uint8_t *srcimg[], int stride[],
+		int wf, int hf, int xf, int yf) {
+	int i, j, w, h, x, y;
+	uint8_t *dst;
+	uint8_t *src=srcimg[0];
+	uint8_t *src1=srcimg[1];
+	uint8_t *src2=srcimg[2];
+	w = wf; h = hf; x = xf; y = yf;
+	dst=image; /* + zr->off_y + zr->image_width*(y/zr->vdec)+x;*/
+	// copy Y:
+	for (i = 0; i < h; i++) {
+		memcpy(dst,src,w);
+		dst+=26;
+		src+=stride[0];
+
+	}
+ 	return 0;
+}
+
+
+static uint32_t preinit(const char *arg) {
+	char *p, *q;
+	int end = 0, i;
+	struct hostent *dest;
+	if (!arg || strlen(arg) == 0) {
+		mp_msg(MSGT_VO, MSGL_ERR, "arcade: subdevice must be given, example: -vo arcade:host=localhost\n");
+		return 1;
+	}
+	
+	arcade_subdevice = malloc(strlen(arg) + 1);
+	if (!arcade_subdevice) {
+		mp_msg(MSGT_VO, MSGL_ERR, "arcade: out of memory error\n");
+		return 1;
+	}
+	p = arcade_subdevice;
+	strcpy(p, arg);
+	mp_msg(MSGT_VO, MSGL_V, "arcade: preinit called with %s\n", arg);
+	while (!end) {
+		q = p + 5;
+		if (!strncmp(p, "file=", 5)) {
+			if (no_arcade_files == ARCADE_MAX_FILES) {
+				mp_msg(MSGT_VO, MSGL_ERR, "arcade: maximum number of hosts reached (%d)\n", ARCADE_MAX_FILES);
+				return 1;
+			}
+			p += 5;
+			while (*q != ',' && *q != '\0') q++;
+			if (*q == '\0') end = 1;
+			*q = '\0';
+			arcade_files[no_arcade_files].name = p;
+			mp_msg(MSGT_VO, MSGL_V, "arcadefile[%d]: %s\n", 
+					no_arcade_files, p);
+			no_arcade_files++;
+		} else if (!strncmp(p, "host=", 5)) {
+			if (no_arcade_hosts == ARCADE_MAX_HOSTS) {
+				mp_msg(MSGT_VO, MSGL_ERR, "arcade: maximum number of hosts reached (%d)\n", ARCADE_MAX_HOSTS);
+				return 1;
+			}
+			p += 5;
+			while (*q != ',' && *q != '\0' && *q != ':') q++;
+			if (*q == ':') {
+				*q++ = '\0';
+				arcade_hosts[no_arcade_hosts].name = p;
+				arcade_hosts[no_arcade_hosts].port = atoi(q);
+				while (*q != ',' && *q != '\0') q++;
+				if (*q == '\0') end = 1;
+			} else {
+				/* use default port */
+				if (*q == '\0') end = 1;
+				*q = '\0';
+				arcade_hosts[no_arcade_hosts].name = p;
+				arcade_hosts[no_arcade_hosts].port = 2323; 
+			}
+			mp_msg(MSGT_VO, MSGL_V, 
+					"arcadehost[%d]: %s:%d\n", 
+					no_arcade_hosts, p,
+					arcade_hosts[no_arcade_hosts].port);
+			no_arcade_hosts++;
+		} else {
+			mp_msg(MSGT_VO, MSGL_ERR, "arcade: syntax error in entry %d in subdevice %s, should be a comma seperated\nlist of host=name:port and file=foo.bml\n", no_arcade_hosts, no_arcade_files, arg);
+			return 1;
+		}
+		p = ++q;
+	}
+	arcade_packet = malloc(12+26*30); /* YV12 26x20 + header */
+	image = ((unsigned char*)arcade_packet + 12);
+	tmp = malloc(26*20);
+	
+	if (!arcade_packet || !tmp) {
+		mp_msg(MSGT_VO, MSGL_ERR, "arcade: out of memory error\n");
+		return 1;
+	}
+	arcade_packet->magic = htonl(0x23542666);
+	arcade_packet->width = htons(26);
+	arcade_packet->height = htons(20);
+	arcade_packet->channels = htons(1);
+	arcade_packet->maxval = htons(255);
+
+	/* open all files */
+	for (i = 0; i < no_arcade_files; i++) {
+		FILE *fp;
+		fp = fopen(arcade_files[i].name, "w");
+		if (!fp) {
+			mp_msg(MSGT_VO, MSGL_ERR, "arcade: error opening %s\n", arcade_files[i].name);
+			return 1;
+		}
+		fprintf(fp, 
+"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+"<blm width=\"26\" height=\"20\" bits=\"8\" channels=\"1\">\n"
+"    <header>\n"
+"        <title>Movie autogenerated by MPlayer</title>\n"
+"        <url>http://www.mplayerhq.hu</url>\n"
+"    </header>\n");
+		arcade_files[i].fp = fp;
+	}
+	/* open all sockets */
+	for (i = 0; i < no_arcade_hosts; i++) {
+		dest = gethostbyname(arcade_hosts[i].name);
+		if (!dest) {
+			mp_msg(MSGT_VO, MSGL_ERR, "unable to resolve host %s\n", arcade_hosts[i].name);
+			return 1;
+		}
+
+		arcade_hosts[i].fd = -1;
+		arcade_hosts[i].addr.sin_family = AF_INET;
+		arcade_hosts[i].addr.sin_port = htons(arcade_hosts[i].port);
+
+		memcpy(&arcade_hosts[i].addr.sin_addr.s_addr,
+				dest->h_addr_list[0], dest->h_length);
+
+		arcade_hosts[i].fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+		if (arcade_hosts[i].fd < 0) {
+			mp_msg(MSGT_VO, MSGL_ERR, "couldn't create socket for %s\n", arcade_hosts[i].name);
+			return 1;
+		}
+		if (connect(arcade_hosts[i].fd,
+				(struct sockaddr *)&arcade_hosts[i].addr,
+				sizeof(arcade_hosts[i].addr)) < 0) {
+			mp_msg(MSGT_VO, MSGL_ERR, "couldn;t connect socket for %s\n", arcade_hosts[i].name);
+			close(arcade_hosts[i].fd);
+		}
+	}
+	return 0;
+}
+
+static uint32_t control(uint32_t request, void *data, ...) {
+	switch (request) {
+		case VOCTRL_QUERY_FORMAT:
+			return query_format(*((uint32_t*)data));
+  		}
+  	return VO_NOTIMPL;
+}


More information about the MPlayer-dev-eng mailing list