summaryrefslogtreecommitdiff
path: root/src/video_out/video_out_xv.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_out/video_out_xv.c')
-rw-r--r--src/video_out/video_out_xv.c319
1 files changed, 228 insertions, 91 deletions
diff --git a/src/video_out/video_out_xv.c b/src/video_out/video_out_xv.c
index eb9d0bb5c..7c77a53cc 100644
--- a/src/video_out/video_out_xv.c
+++ b/src/video_out/video_out_xv.c
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: video_out_xv.c,v 1.44 2001/06/18 15:43:00 richwareham Exp $
+ * $Id: video_out_xv.c,v 1.45 2001/06/24 22:20:26 guenter Exp $
*
* video_out_xv.c, X11 video extension interface for xine
*
@@ -50,6 +50,7 @@
#include <string.h>
#include "monitor.h"
+#include "utils.h"
#include "video_out.h"
#include "video_out_x11.h"
#include "xine_internal.h"
@@ -95,6 +96,7 @@ typedef struct {
XvPortID xv_port;
XColor black;
int expecting_event; /* completion event handling */
+ int use_shm;
xv_property_t props[VO_NUM_PROPERTIES];
uint32_t capabilities;
@@ -127,9 +129,8 @@ typedef struct {
} xv_driver_t;
-/*
- *
- */
+int gX11Fail;
+
static uint32_t xv_get_capabilities (vo_driver_t *this_gen) {
xv_driver_t *this = (xv_driver_t *) this_gen;
@@ -186,9 +187,174 @@ static vo_frame_t *xv_alloc_frame (vo_driver_t *this_gen) {
return (vo_frame_t *) frame;
}
-/*
- *
- */
+int HandleXError (Display *display, XErrorEvent *xevent) {
+
+ char str [1024];
+
+ XGetErrorText (display, xevent->error_code, str, 1024);
+
+ printf ("received X error event: %s\n", str);
+
+ gX11Fail = 1;
+ return 0;
+
+}
+
+static void x11_InstallXErrorHandler (xv_driver_t *this)
+{
+ XSetErrorHandler (HandleXError);
+ XFlush (this->display);
+}
+
+static void x11_DeInstallXErrorHandler (xv_driver_t *this)
+{
+ XSetErrorHandler (NULL);
+ XFlush (this->display);
+}
+
+static XvImage *create_ximage (xv_driver_t *this, XShmSegmentInfo *shminfo,
+ int width, int height, int format) {
+
+ unsigned int xv_format;
+ XvImage *image;
+
+ switch (format) {
+ case IMGFMT_YV12:
+ xv_format = this->xv_format_yv12;
+ break;
+ case IMGFMT_RGB:
+ xv_format = this->xv_format_rgb;
+ break;
+ case IMGFMT_YUY2:
+ xv_format = this->xv_format_yuy2;
+ break;
+ default:
+ fprintf (stderr, "create_ximage: unknown format %08x\n",format);
+ exit (1);
+ }
+
+ if (this->use_shm) {
+
+ /*
+ * try shm
+ */
+
+ gX11Fail = 0;
+ x11_InstallXErrorHandler (this);
+
+ image = XvShmCreateImage(this->display, this->xv_port, xv_format, 0,
+ width, height, shminfo);
+
+ if (image == NULL ) {
+ printf("video_out_xv: XvShmCreateImage failed\n");
+ printf("video_out_xv: => not using MIT Shared Memory extension.\n");
+ this->use_shm = 0;
+ goto finishShmTesting;
+ }
+
+ shminfo->shmid=shmget(IPC_PRIVATE,
+ image->data_size,
+ IPC_CREAT | 0777);
+
+ if (image->data_size==0) {
+ printf("video_out_xv: XvShmCreateImage returned a zero size\n");
+ printf("video_out_xv: => not using MIT Shared Memory extension.\n");
+ this->use_shm = 0;
+ goto finishShmTesting;
+ }
+
+ if (shminfo->shmid < 0 ) {
+ perror("video_out_xv: shared memory error in shmget: ");
+ printf("video_out_xv: => not using MIT Shared Memory extension.\n");
+ this->use_shm = 0;
+ goto finishShmTesting;
+ }
+
+ shminfo->shmaddr = (char *) shmat(shminfo->shmid, 0, 0);
+
+ if (shminfo->shmaddr == NULL) {
+ printf("video_out_xv: shared memory error (address error NULL)\n");
+ this->use_shm = 0;
+ goto finishShmTesting;
+ }
+
+ if (shminfo->shmaddr == ((char *) -1)) {
+ printf("video_out_xv: shared memory error (address error)\n");
+ this->use_shm = 0;
+ goto finishShmTesting;
+ }
+
+ shminfo->readOnly = False;
+ image->data = shminfo->shmaddr;
+
+ XShmAttach(this->display, shminfo);
+
+ XSync(this->display, False);
+ shmctl(shminfo->shmid, IPC_RMID, 0);
+
+ if (gX11Fail) {
+ printf ("video_out_xv: x11 error during shared memory XImage creation\n");
+ printf ("video_out_xv: => not using MIT Shared Memory extension.\n");
+ shmdt (shminfo->shmaddr);
+ shmctl (shminfo->shmid, IPC_RMID, 0);
+ shminfo->shmid = -1;
+ this->use_shm = 0;
+ goto finishShmTesting;
+ }
+
+ /*
+ * Now that the Xserver has learned about and attached to the
+ * shared memory segment, delete it. It's actually deleted by
+ * the kernel when all users of that segment have detached from
+ * it. Gives an automatic shared memory cleanup in case we crash.
+ */
+ shmctl (shminfo->shmid, IPC_RMID, 0);
+ shminfo->shmid = -1;
+
+ finishShmTesting:
+ x11_DeInstallXErrorHandler(this);
+ }
+
+
+ /*
+ * fall back to plain Xv if necessary
+ */
+
+ if (!this->use_shm) {
+
+ char *data;
+
+ data = xmalloc (width * height * 3/2);
+
+ image = XvCreateImage (this->display, this->xv_port,
+ xv_format, data, width, height);
+
+
+ }
+ return image;
+}
+
+static void dispose_ximage (xv_driver_t *this,
+ XShmSegmentInfo *shminfo,
+ XvImage *myimage) {
+
+ if (this->use_shm) {
+
+ XShmDetach (this->display, shminfo);
+ XFree (myimage);
+ shmdt (shminfo->shmaddr);
+ if (shminfo->shmid >= 0) {
+ shmctl (shminfo->shmid, IPC_RMID, 0);
+ shminfo->shmid = -1;
+ }
+
+ } else {
+
+ XFree (myimage);
+
+ }
+}
+
static void xv_update_frame_format (vo_driver_t *this_gen,
vo_frame_t *frame_gen,
uint32_t width, uint32_t height,
@@ -196,7 +362,6 @@ static void xv_update_frame_format (vo_driver_t *this_gen,
xv_driver_t *this = (xv_driver_t *) this_gen;
xv_frame_t *frame = (xv_frame_t *) frame_gen;
- unsigned int xv_format;
if ((frame->width != width)
|| (frame->height != height)
@@ -211,77 +376,12 @@ static void xv_update_frame_format (vo_driver_t *this_gen,
*/
if (frame->image) {
- XShmDetach (this->display, &frame->shminfo);
-
- XFree (frame->image);
- shmdt (frame->shminfo.shmaddr);
- shmctl (frame->shminfo.shmid, IPC_RMID,NULL);
-
+ dispose_ximage (this, &frame->shminfo, frame->image);
frame->image = NULL;
}
- switch (format) {
- case IMGFMT_YV12:
- xv_format = this->xv_format_yv12;
- break;
- case IMGFMT_RGB:
- xv_format = this->xv_format_rgb;
- break;
- case IMGFMT_YUY2:
- xv_format = this->xv_format_yuy2;
- break;
- default:
- fprintf (stderr, "xv_update_frame_format: unknown format %08x\n",format);
- exit (1);
- }
-
- frame->image = XvShmCreateImage(this->display, this->xv_port, xv_format, 0,
- width, height, &frame->shminfo);
-
- if (frame->image == NULL ) {
- fprintf(stderr, "xv_image_format: XvShmCreateImage failed.\n");
- exit (1);
- }
-
- frame->shminfo.shmid=shmget(IPC_PRIVATE,
- frame->image->data_size,
- IPC_CREAT | 0777);
-
- if (frame->image->data_size==0) {
- fprintf(stderr, "xv_update_frame_format: XvShmCreateImage "
- "returned a zero size\n");
- exit (1);
- }
-
- if (frame->shminfo.shmid < 0 ) {
- perror("xv_update_frame_format: shared memory error in shmget: ");
- exit (1);
- }
+ frame->image = create_ximage (this, &frame->shminfo, width, height, format);
- frame->shminfo.shmaddr = (char *) shmat(frame->shminfo.shmid, 0, 0);
-
- if (frame->shminfo.shmaddr == NULL) {
- fprintf(stderr, "xv_update_frame_format: shared memory "
- "error (address error NULL)\n");
- exit (1);
- }
-
- if (frame->shminfo.shmaddr == ((char *) -1)) {
- fprintf(stderr, "xv_update_frame_format: shared memory "
- "error (address error)\n");
- exit (1);
- }
-
- frame->shminfo.readOnly = False;
- frame->image->data = frame->shminfo.shmaddr;
-
- /* memset (frame->image->data,0,frame->image->data_size); */
-
- XShmAttach(this->display, &frame->shminfo);
-
- XSync(this->display, False);
- shmctl(frame->shminfo.shmid, IPC_RMID, 0);
-
frame->vo_frame.base[0] = frame->image->data;
frame->vo_frame.base[1] = frame->image->data + width * height * 5 / 4;
frame->vo_frame.base[2] = frame->image->data + width * height;
@@ -326,6 +426,7 @@ static void xv_adapt_to_output_area (xv_driver_t *this,
* clear unused output area
*/
+ XLockDisplay (this->display);
XSetForeground (this->display, this->gc, this->black.pixel);
XFillRectangle(this->display, this->drawable, this->gc,
@@ -343,7 +444,7 @@ static void xv_adapt_to_output_area (xv_driver_t *this,
this->output_xoffset+this->output_width, dest_y,
dest_width - this->output_xoffset - this->output_width,
dest_height);
-
+ XUnlockDisplay (this->display);
}
/*
@@ -470,13 +571,22 @@ static void xv_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen) {
XLockDisplay (this->display);
this->cur_frame = frame;
- XvShmPutImage(this->display, this->xv_port,
- this->drawable, this->gc, frame->image,
- 0, 0, frame->width, frame->height-5,
- this->output_xoffset, this->output_yoffset,
- this->output_width, this->output_height, True);
-
- this->expecting_event = 10;
+
+ if (this->use_shm) {
+ XvShmPutImage(this->display, this->xv_port,
+ this->drawable, this->gc, frame->image,
+ 0, 0, frame->width, frame->height-5,
+ this->output_xoffset, this->output_yoffset,
+ this->output_width, this->output_height, True);
+
+ this->expecting_event = 10;
+ } else {
+ XvPutImage(this->display, this->xv_port,
+ this->drawable, this->gc, frame->image,
+ 0, 0, frame->width, frame->height-5,
+ this->output_xoffset, this->output_yoffset,
+ this->output_width, this->output_height);
+ }
XFlush(this->display);
@@ -587,12 +697,26 @@ static int xv_gui_data_exchange (vo_driver_t *this_gen,
/* FIXME : take care of completion events */
if (xev->count == 0) {
- if (this->cur_frame)
- XvShmPutImage(this->display, this->xv_port,
- this->drawable, this->gc, this->cur_frame->image,
- 0, 0, this->cur_frame->width, this->cur_frame->height-5,
- this->output_xoffset, this->output_yoffset,
- this->output_width, this->output_height, False);
+ if (this->cur_frame) {
+ XLockDisplay (this->display);
+
+ if (this->use_shm) {
+ XvShmPutImage(this->display, this->xv_port,
+ this->drawable, this->gc, this->cur_frame->image,
+ 0, 0, this->cur_frame->width, this->cur_frame->height-5,
+ this->output_xoffset, this->output_yoffset,
+ this->output_width, this->output_height, False);
+ } else {
+ XvPutImage(this->display, this->xv_port,
+ this->drawable, this->gc, this->cur_frame->image,
+ 0, 0, this->cur_frame->width, this->cur_frame->height-5,
+ this->output_xoffset, this->output_yoffset,
+ this->output_width, this->output_height);
+ }
+ XFlush(this->display);
+
+ XUnlockDisplay (this->display);
+ }
}
}
break;
@@ -613,9 +737,11 @@ static void xv_exit (vo_driver_t *this_gen) {
xv_driver_t *this = (xv_driver_t *) this_gen;
+ XLockDisplay (this->display);
if(XvUngrabPort (this->display, this->xv_port, CurrentTime) != Success) {
fprintf(stderr, "xv_exit: XvUngrabPort() failed.\n");
}
+ XUnlockDisplay (this->display);
}
/*
@@ -676,6 +802,8 @@ vo_driver_t *init_video_out_plugin (config_values_t *config, void *visual_gen) {
int nattr;
x11_visual_t *visual = (x11_visual_t *) visual_gen;
XColor dummy;
+ XvImage *myimage;
+ XShmSegmentInfo myshminfo;
display = visual->display;
xine_debug = config->lookup_int (config, "xine_debug", 0);
@@ -685,7 +813,7 @@ vo_driver_t *init_video_out_plugin (config_values_t *config, void *visual_gen) {
*/
if (Success != XvQueryExtension(display,&ver,&rel,&req,&ev,&err)) {
- fprintf (stderr, "video_out_xv: Xv extension not present.\n");
+ printf ("video_out_xv: Xv extension not present.\n");
return NULL;
}
@@ -695,7 +823,7 @@ vo_driver_t *init_video_out_plugin (config_values_t *config, void *visual_gen) {
if (Success != XvQueryAdaptors(display,DefaultRootWindow(display),
&adaptors,&adaptor_info)) {
- fprintf(stderr, "video_out_xv: XvQueryAdaptors failed.\n");
+ printf("video_out_xv: XvQueryAdaptors failed.\n");
return NULL;
}
@@ -869,6 +997,15 @@ vo_driver_t *init_video_out_plugin (config_values_t *config, void *visual_gen) {
}
}
+ /*
+ * try to create a shared image
+ * to find out if MIT shm really works
+ */
+
+ myimage = create_ximage (this, &myshminfo, 100, 100, IMGFMT_YV12);
+ dispose_ximage (this, &myshminfo, myimage);
+
+
return &this->vo_driver;
}