mplayer.c: #include mplayer.h and access_mpcontext.h
[mplayer.git] / libvo / vo_zr2.c
blobc50e95c1bc4e5ecc26e697c9322f7c191790aaf0
1 /*
2 * vo_zr2.c - playback on zoran cards
3 * Based on vo_zr.c,v 1.27
4 * Copyright (C) Rik Snel 2001-2005, License GNU GPL v2 or later
5 */
7 /* $Id$ */
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <fcntl.h>
14 #include <errno.h>
15 #include <sys/stat.h>
16 #include <sys/types.h>
17 #include <sys/time.h>
18 #include <sys/mman.h>
19 #include <sys/ioctl.h>
20 #include <linux/types.h>
21 #include <linux/videodev.h>
22 #include "config.h"
23 #include "videodev_mjpeg.h"
24 #include "video_out.h"
25 #include "video_out_internal.h"
26 #include "mp_msg.h"
27 #include "subopt-helper.h"
28 #include "fastmemcpy.h"
30 static const vo_info_t info = {
31 "Zoran ZR360[56]7/ZR36060 Driver (DC10(+)/buz/lml33/MatroxRR)",
32 "zr2",
33 "Rik Snel <rsnel@cube.dyndns.org>",
37 const LIBVO_EXTERN(zr2)
39 typedef struct {
40 /* options */
41 char *subdevice;
43 /* information for (and about) the zoran card */
45 unsigned char *buf; /* the JPEGs will be placed here */
46 struct mjpeg_requestbuffers zrq; /* info about this buffer */
48 int vdes; /* file descriptor of card */
49 int playing; /* 0 or 1 */
50 int frame, sync, queue; /* buffer management */
51 struct mjpeg_sync zs; /* state information */
52 struct mjpeg_params zp;
53 struct video_capability vc; /* max resolution and so on */
54 } vo_zr2_priv_t;
56 static vo_zr2_priv_t priv;
58 #define ZR2_MJPEG_NBUFFERS 2
59 #define ZR2_MJPEG_SIZE 1024*256
61 /* some convenient #define's, is this portable enough? */
62 #define DBG2(...) mp_msg(MSGT_VO, MSGL_DBG2, "vo_zr2: " __VA_ARGS__)
63 #define VERBOSE(...) mp_msg(MSGT_VO, MSGL_V, "vo_zr2: " __VA_ARGS__)
64 #define ERROR(...) mp_msg(MSGT_VO, MSGL_ERR, "vo_zr2: " __VA_ARGS__)
65 #define WARNING(...) mp_msg(MSGT_VO, MSGL_WARN, "vo_zr2: " __VA_ARGS__)
67 static void stop_playing(vo_zr2_priv_t *p) {
68 if (p->playing) {
69 p->frame = -1;
70 if (ioctl(p->vdes, MJPIOC_QBUF_PLAY, &p->frame) < 0)
71 ERROR("error stopping playback\n");
72 p->playing = 0;
73 p->sync = 0;
74 p->queue = 0;
75 p->frame = 0;
79 static const char *guess_device(const char *suggestion, int inform) {
80 struct stat vstat;
81 int res;
82 static const char * const devs[] = {
83 "/dev/video",
84 "/dev/video0",
85 "/dev/v4l/video0",
86 "/dev/v4l0",
87 "/dev/v4l",
88 NULL
90 const char * const *dev = devs;
92 if (suggestion) {
93 if (!*suggestion) {
94 ERROR("error: specified device name is empty string\n");
95 return NULL;
98 res = stat(suggestion, &vstat);
99 if (res == 0 && S_ISCHR(vstat.st_mode)) {
100 if (inform) VERBOSE("using device %s\n", suggestion);
101 return suggestion;
102 } else {
103 if (res != 0) ERROR("%s does not exist\n", suggestion);
104 else ERROR("%s is no character device\n", suggestion);
105 /* don't try to be smarter than the user, just exit */
106 return NULL;
110 while (*(++dev) != NULL) {
111 if (stat(*dev, &vstat) == 0 && S_ISCHR(vstat.st_mode)) {
112 VERBOSE("guessed video device %s\n", *dev);
113 return *dev;
115 dev++;
118 ERROR("unable to find video device\n");
120 return NULL;
123 static int query_format(uint32_t format) {
124 if (format==IMGFMT_ZRMJPEGNI ||
125 format==IMGFMT_ZRMJPEGIT ||
126 format==IMGFMT_ZRMJPEGIB)
127 return VFCAP_CSP_SUPPORTED|VFCAP_CSP_SUPPORTED_BY_HW;
128 return 0;
131 static uint32_t draw_image(mp_image_t *mpi) {
132 vo_zr2_priv_t *p = &priv;
133 int size = (int)mpi->planes[1];
134 if (size > (int)p->zrq.size) {
135 ERROR("incoming JPEG image (size=%d) doesn't fit in buffer\n",
136 size);
137 return VO_FALSE;
140 /* looking for free buffer */
141 if (p->queue - p->sync < (int)p->zrq.count) p->frame = p->queue;
142 else {
143 if (ioctl(p->vdes, MJPIOC_SYNC, &p->zs) < 0) {
144 ERROR("error waiting for buffer to become free\n");
145 return VO_FALSE;
147 p->frame = p->zs.frame;
148 p->sync++;
151 /* copy the jpeg image to the buffer which we acquired */
152 fast_memcpy(p->buf + p->zrq.size*p->frame, mpi->planes[0], size);
154 return VO_TRUE;
157 static const char *normstring(int norm) {
158 switch (norm) {
159 case VIDEO_MODE_PAL:
160 return "PAL";
161 case VIDEO_MODE_NTSC:
162 return "NTSC";
163 case VIDEO_MODE_SECAM:
164 return "SECAM";
165 case VIDEO_MODE_AUTO:
166 return "auto";
168 return "undefined";
171 static int get_norm(const char *n) {
172 if (!strcmp(n, "PAL")) return VIDEO_MODE_PAL;
173 if (!strcmp(n, "NTSC")) return VIDEO_MODE_NTSC;
174 if (!strcmp(n, "SECAM")) return VIDEO_MODE_SECAM;
175 if (!strcmp(n, "auto")) return VIDEO_MODE_AUTO;
176 return -1; /* invalid */
179 static int nc(const char **norm) {
180 if (get_norm(*norm) == -1) {
181 ERROR("norm \"%s\" is not supported, choose from PAL, NTSC, SECAM and auto\n", *norm);
182 return 0;
183 } else return 1;
186 static int pbc(int *prebuf) {
187 if (*prebuf) WARNING("prebuffering is not yet supported\n");
188 return 1;
191 static int preinit(const char *arg) {
192 vo_zr2_priv_t *p = &priv;
193 const char *dev = NULL;
194 char *dev_arg = NULL, *norm_arg = NULL;
195 int norm = VIDEO_MODE_AUTO, prebuf = 0;
196 opt_t subopts[] = { /* don't want warnings with -Wall... */
197 { "dev", OPT_ARG_MSTRZ, &dev_arg, NULL, 0 },
198 { "prebuf", OPT_ARG_BOOL, &prebuf, (opt_test_f)pbc, 0 },
199 { "norm", OPT_ARG_MSTRZ, &norm_arg, (opt_test_f)nc, 0 },
200 { NULL, 0, NULL, NULL, 0 }
203 VERBOSE("preinit() called with arg: %s\n", arg);
204 memset(p, 0, sizeof(*p)); /* set defaults */
205 p->vdes = -1;
207 if (subopt_parse(arg, subopts)) {
208 mp_msg(MSGT_VO, MSGL_FATAL,
209 "Allowed suboptions for -vo zr2 are:\n"
210 "- dev=DEVICE (default: %s)\n"
211 "- norm=PAL|NTSC|SECAM|auto (default: auto)\n"
212 "- prebuf/noprebuf (default:"
213 " noprebuf)\n"
214 "\n"
215 "Example: mplayer -vo zr2:dev=/dev/video1:"
216 "norm=PAL movie.avi\n\n"
217 , guess_device(NULL, 0));
218 free(norm_arg);
219 free(dev_arg);
220 return -1;
223 /* interpret the strings we got from subopt_parse */
224 if (norm_arg) {
225 norm = get_norm(norm_arg);
226 free(norm_arg);
229 if (dev_arg) dev = dev_arg;
231 dev = guess_device(dev, 1);
232 if (!dev) {
233 free(dev_arg);
234 uninit();
235 return 1;
238 p->vdes = open(dev, O_RDWR);
239 if (p->vdes < 0) {
240 ERROR("error opening %s: %s\n", dev, strerror(errno));
241 free(dev_arg);
242 uninit();
243 return 1;
246 free(dev_arg);
248 /* check if we really are dealing with a zoran card */
249 if (ioctl(p->vdes, MJPIOC_G_PARAMS, &p->zp) < 0) {
250 ERROR("%s probably is not a DC10(+)/buz/lml33\n", dev);
251 uninit();
252 return 1;
255 VERBOSE("kernel driver version %d.%d, current norm is %s\n",
256 p->zp.major_version, p->zp.minor_version,
257 normstring(p->zp.norm));
259 /* changing the norm in the zoran_params and MJPIOC_S_PARAMS
260 * does nothing the last time I tried, so bail out if the norm
261 * is not correct */
262 if (norm != VIDEO_MODE_AUTO && p->zp.norm != norm) {
263 ERROR("mplayer currently can't change the video norm, "
264 "change it with (eg.) XawTV and retry.\n");
265 uninit();
266 return 1;
269 /* gather useful information */
270 if (ioctl(p->vdes, VIDIOCGCAP, &p->vc) < 0) {
271 ERROR("error getting video capabilities from %s\n", dev);
272 uninit();
273 return 1;
276 VERBOSE("card reports maxwidth=%d, maxheight=%d\n",
277 p->vc.maxwidth, p->vc.maxheight);
279 /* according to the mjpegtools source, some cards return a bogus
280 * vc.maxwidth, correct it here. If a new zoran card appears with a
281 * maxwidth different 640, 720 or 768 this code may lead to problems */
282 if (p->vc.maxwidth != 640 && p->vc.maxwidth != 768) {
283 VERBOSE("card probably reported bogus width (%d), "
284 "changing to 720\n", p->vc.maxwidth);
285 p->vc.maxwidth = 720;
288 p->zrq.count = ZR2_MJPEG_NBUFFERS;
289 p->zrq.size = ZR2_MJPEG_SIZE;
291 if (ioctl(p->vdes, MJPIOC_REQBUFS, &p->zrq)) {
292 ERROR("error requesting %d buffers of size %d\n",
293 ZR2_MJPEG_NBUFFERS, ZR2_MJPEG_NBUFFERS);
294 uninit();
295 return 1;
298 VERBOSE("got %ld buffers of size %ld (wanted %d buffers of size %d)\n",
299 p->zrq.count, p->zrq.size, ZR2_MJPEG_NBUFFERS,
300 ZR2_MJPEG_SIZE);
302 p->buf = (unsigned char*)mmap(0, p->zrq.count*p->zrq.size,
303 PROT_READ|PROT_WRITE, MAP_SHARED, p->vdes, 0);
305 if (p->buf == MAP_FAILED) {
306 ERROR("error mapping requested buffers: %s", strerror(errno));
307 uninit();
308 return 1;
311 return 0;
314 static int config(uint32_t width, uint32_t height, uint32_t d_width,
315 uint32_t d_height, uint32_t flags, char *title, uint32_t format) {
316 int fields = 1, top_first = 1, err = 0;
317 int stretchx = 1, stretchy = 1;
318 struct mjpeg_params zptmp;
319 vo_zr2_priv_t *p = &priv;
320 VERBOSE("config() called\n");
322 /* paranoia check */
323 if (!query_format(format)) {
324 ERROR("called with wrong format, should be impossible\n");
325 return 1;
328 if ((int)height > p->vc.maxheight) {
329 ERROR("input height %d is too large, maxheight=%d\n",
330 height, p->vc.maxheight);
331 err = 1;
334 if (format != IMGFMT_ZRMJPEGNI) {
335 fields = 2;
336 if (format == IMGFMT_ZRMJPEGIB)
337 top_first = 0;
338 } else if ((int)height > p->vc.maxheight/2) {
339 ERROR("input is too high (%d) for non-interlaced playback"
340 "max=%d\n", height, p->vc.maxheight);
341 err = 1;
344 if (width%16 != 0) {
345 ERROR("input width=%d, must be multiple of 16\n", width);
346 err = 1;
349 if (height%(fields*8) != 0) {
350 ERROR("input height=%d, must be multiple of %d\n",
351 height, 2*fields);
352 err = 1;
355 /* we assume sample_aspect = 1 */
356 if (fields == 1) {
357 if (2*d_width <= (uint32_t)p->vc.maxwidth) {
358 VERBOSE("stretching x direction to preserve aspect\n");
359 d_width *= 2;
360 } else VERBOSE("unable to preserve aspect, screen width "
361 "too small\n");
364 if (d_width == width) stretchx = 1;
365 else if (d_width == 2*width) stretchx = 2;
366 #if 0 /* do minimal stretching for now */
367 else if (d_width == 4*width) stretchx = 4;
368 else WARNING("d_width must be {1,2,4}*width, using defaults\n");
370 if (d_height == height) stretchy = 1;
371 else if (d_height == 2*height) stretchy = 2;
372 else if (d_height == 4*height) stretchy = 4;
373 else WARNING("d_height must be {1,2,4}*height, using defaults\n");
374 #endif
376 if (stretchx*width > (uint32_t)p->vc.maxwidth) {
377 ERROR("movie to be played is too wide, width=%d>maxwidth=%d\n",
378 width*stretchx, p->vc.maxwidth);
379 err = 1;
382 if (stretchy*height > (uint32_t)p->vc.maxheight) {
383 ERROR("movie to be played is too heigh, height=%d>maxheight"
384 "=%d\n", height*stretchy, p->vc.maxheight);
385 err = 1;
388 if (err == 1) return 1;
390 /* some video files (eg. concatenated MPEG files), make MPlayer
391 * call config() during playback while no parameters have changed.
392 * We make configuration changes to a temporary params structure,
393 * compare it with the old params structure and only apply the new
394 * config if it is different from the old one. */
395 memcpy(&zptmp, &p->zp, sizeof(zptmp));
397 /* translate the configuration to zoran understandable format */
398 zptmp.decimation = 0;
399 zptmp.HorDcm = stretchx;
400 zptmp.VerDcm = stretchy;
401 zptmp.TmpDcm = 1;
402 zptmp.field_per_buff = fields;
403 zptmp.odd_even = top_first;
405 /* center the image on screen */
406 zptmp.img_x = (p->vc.maxwidth - width*stretchx)/2;
407 zptmp.img_y = (p->vc.maxheight - height*stretchy*(3-fields))/4;
409 zptmp.img_width = stretchx*width;
410 zptmp.img_height = stretchy*height/fields;
412 VERBOSE("tv: %dx%d, out: %dx%d+%d+%d, in: %ux%u %s%s%s\n",
413 p->vc.maxwidth, p->vc.maxheight,
414 zptmp.img_width, 2*zptmp.img_height,
415 zptmp.img_x, 2*zptmp.img_y,
416 width, height, (fields == 1) ? "non-interlaced" : "",
417 (fields == 2 && top_first == 1)
418 ? "interlaced top first" : "",
419 (fields == 2 && top_first == 0)
420 ? "interlaced bottom first" : "");
422 if (memcmp(&zptmp, &p->zp, sizeof(zptmp))) {
423 /* config differs, we must update */
424 memcpy(&p->zp, &zptmp, sizeof(zptmp));
425 stop_playing(p);
426 if (ioctl(p->vdes, MJPIOC_S_PARAMS, &p->zp) < 0) {
427 ERROR("error writing display params to card\n");
428 return 1;
430 VERBOSE("successfully written display parameters to card\n");
431 } else VERBOSE("config didn't change, no need to write it to card\n");
433 return 0;
436 static int control(uint32_t request, void *data) {
437 switch (request) {
438 case VOCTRL_QUERY_FORMAT:
439 return query_format(*((uint32_t*)data));
440 case VOCTRL_DRAW_IMAGE:
441 return draw_image(data);
443 return VO_NOTIMPL;
446 static int draw_frame(uint8_t *src[]) {
447 return 0;
450 static int draw_slice(uint8_t *image[], int stride[],
451 int w, int h, int x, int y) {
452 return 0;
455 static void draw_osd(void) {
458 static void flip_page(void) {
459 vo_zr2_priv_t *p = &priv;
460 /* queueing the buffer for playback */
461 /* queueing the first buffer automatically starts playback */
462 if (p->playing == 0) p->playing = 1;
463 if (ioctl(p->vdes, MJPIOC_QBUF_PLAY, &p->frame) < 0)
464 ERROR("error queueing buffer for playback\n");
465 else p->queue++;
468 static void check_events(void) {
471 static void uninit(void) {
472 vo_zr2_priv_t *p = &priv;
473 VERBOSE("uninit() called (may be called from preinit() on error)\n");
475 stop_playing(p);
477 if (p->buf && munmap(p->buf, p->zrq.size*p->zrq.count))
478 ERROR("error munmapping buffer: %s\n", strerror(errno));
480 if (p->vdes >= 0) close(p->vdes);
481 free(p->subdevice);