diff options
Diffstat (limited to 'libvo/vo_xv.c')
-rw-r--r-- | libvo/vo_xv.c | 947 |
1 files changed, 504 insertions, 443 deletions
diff --git a/libvo/vo_xv.c b/libvo/vo_xv.c index 6f1f7b6a36..54eecd2015 100644 --- a/libvo/vo_xv.c +++ b/libvo/vo_xv.c @@ -37,13 +37,18 @@ Buffer allocation: #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <stdint.h> +#include <stdbool.h> #include "config.h" +#include "options.h" +#include "talloc.h" #include "mp_msg.h" #include "help_mp.h" #include "video_out.h" -#include "video_out_internal.h" - +#include "libmpcodecs/vfcap.h" +#include "libmpcodecs/mp_image.h" +#include "osd.h" #include <X11/Xlib.h> #include <X11/Xutil.h> @@ -58,10 +63,7 @@ Buffer allocation: #include "subopt-helper.h" #include "input/input.h" - -#ifdef CONFIG_GUI -#include "gui/interface.h" -#endif +#include "mp_fifo.h" #include "libavutil/common.h" @@ -72,719 +74,778 @@ static const vo_info_t info = { "" }; -const LIBVO_EXTERN(xv) #ifdef HAVE_SHM #include <sys/ipc.h> #include <sys/shm.h> #include <X11/extensions/XShm.h> - -static XShmSegmentInfo Shminfo[NUM_BUFFERS]; -static int Shmem_Flag; #endif // Note: depends on the inclusion of X11/extensions/XShm.h #include <X11/extensions/Xv.h> #include <X11/extensions/Xvlib.h> -// FIXME: dynamically allocate this stuff -static void allocate_xvimage(int); -static unsigned int ver, rel, req, ev, err; -static unsigned int formats, adaptors, xv_format; -static XvAdaptorInfo *ai = NULL; -static XvImageFormatValues *fo=NULL; - -static int current_buf = 0; -static int current_ip_buf = 0; -static int num_buffers = 1; // default -static int visible_buf = -1; // -1 means: no buffer was drawn yet -static XvImage *xvimage[NUM_BUFFERS]; - - -static uint32_t image_width; -static uint32_t image_height; -static uint32_t image_format; - -static int int_pause; +struct xvctx { + XvAdaptorInfo *ai; + XvImageFormatValues *fo; + unsigned int formats, adaptors, xv_format; + int current_buf; + int current_ip_buf; + int num_buffers; + int total_buffers; + int have_visible_image_copy; + int have_next_image_copy; + int unchanged_visible_image; + int unchanged_next_image; + int visible_buf; + XvImage *xvimage[NUM_BUFFERS + 1]; + uint32_t image_width; + uint32_t image_height; + uint32_t image_format; + int is_paused; + struct vo_rect src_rect; + struct vo_rect dst_rect; + uint32_t max_width, max_height; // zero means: not set + int event_fd_registered; // for uninit called from preinit + int mode_switched; + int osd_objects_drawn; + void (*draw_alpha_fnc)(void *ctx, int x0, int y0, int w, int h, + unsigned char *src, unsigned char *srca, + int stride); +#ifdef HAVE_SHM + XShmSegmentInfo Shminfo[NUM_BUFFERS + 1]; + int Shmem_Flag; +#endif +}; -static struct vo_rect src_rect; -static struct vo_rect dst_rect; -static uint32_t max_width = 0, max_height = 0; // zero means: not set +static void allocate_xvimage(struct vo *, int); -static void (*draw_alpha_fnc) (int x0, int y0, int w, int h, - unsigned char *src, unsigned char *srca, - int stride); -static void draw_alpha_yv12(int x0, int y0, int w, int h, +static void draw_alpha_yv12(void *p, int x0, int y0, int w, int h, unsigned char *src, unsigned char *srca, int stride) { - x0 += image_width * (vo_panscan_x >> 1) / (vo_dwidth + vo_panscan_x); + struct vo *vo = p; + struct xvctx *ctx = vo->priv; + x0 += ctx->image_width * (vo->panscan_x >> 1) + / (vo->dwidth + vo->panscan_x); vo_draw_alpha_yv12(w, h, src, srca, stride, - xvimage[current_buf]->data + - xvimage[current_buf]->offsets[0] + - xvimage[current_buf]->pitches[0] * y0 + x0, - xvimage[current_buf]->pitches[0]); + ctx->xvimage[ctx->current_buf]->data + + ctx->xvimage[ctx->current_buf]->offsets[0] + + ctx->xvimage[ctx->current_buf]->pitches[0] * y0 + x0, + ctx->xvimage[ctx->current_buf]->pitches[0]); + ctx->osd_objects_drawn++; } -static void draw_alpha_yuy2(int x0, int y0, int w, int h, +static void draw_alpha_yuy2(void *p, int x0, int y0, int w, int h, unsigned char *src, unsigned char *srca, int stride) { - x0 += image_width * (vo_panscan_x >> 1) / (vo_dwidth + vo_panscan_x); + struct vo *vo = p; + struct xvctx *ctx = vo->priv; + x0 += ctx->image_width * (vo->panscan_x >> 1) + / (vo->dwidth + vo->panscan_x); vo_draw_alpha_yuy2(w, h, src, srca, stride, - xvimage[current_buf]->data + - xvimage[current_buf]->offsets[0] + - xvimage[current_buf]->pitches[0] * y0 + 2 * x0, - xvimage[current_buf]->pitches[0]); + ctx->xvimage[ctx->current_buf]->data + + ctx->xvimage[ctx->current_buf]->offsets[0] + + ctx->xvimage[ctx->current_buf]->pitches[0] * y0 + 2 * x0, + ctx->xvimage[ctx->current_buf]->pitches[0]); + ctx->osd_objects_drawn++; } -static void draw_alpha_uyvy(int x0, int y0, int w, int h, +static void draw_alpha_uyvy(void *p, int x0, int y0, int w, int h, unsigned char *src, unsigned char *srca, int stride) { - x0 += image_width * (vo_panscan_x >> 1) / (vo_dwidth + vo_panscan_x); + struct vo *vo = p; + struct xvctx *ctx = vo->priv; + x0 += ctx->image_width * (vo->panscan_x >> 1) + / (vo->dwidth + vo->panscan_x); vo_draw_alpha_yuy2(w, h, src, srca, stride, - xvimage[current_buf]->data + - xvimage[current_buf]->offsets[0] + - xvimage[current_buf]->pitches[0] * y0 + 2 * x0 + 1, - xvimage[current_buf]->pitches[0]); + ctx->xvimage[ctx->current_buf]->data + + ctx->xvimage[ctx->current_buf]->offsets[0] + + ctx->xvimage[ctx->current_buf]->pitches[0] * y0 + 2 * x0 + 1, + ctx->xvimage[ctx->current_buf]->pitches[0]); + ctx->osd_objects_drawn++; } -static void draw_alpha_null(int x0, int y0, int w, int h, +static void draw_alpha_null(void *p, int x0, int y0, int w, int h, unsigned char *src, unsigned char *srca, int stride) { } -static void deallocate_xvimage(int foo); +static void deallocate_xvimage(struct vo *vo, int foo); -static void resize(void) +static void resize(struct vo *vo) { - calc_src_dst_rects(image_width, image_height, &src_rect, &dst_rect, NULL, NULL); - vo_x11_clearwindow_part(mDisplay, vo_window, dst_rect.width, dst_rect.height, 1); - vo_xv_draw_colorkey(dst_rect.left, dst_rect.top, dst_rect.width, dst_rect.height); + struct xvctx *ctx = vo->priv; + + calc_src_dst_rects(vo, ctx->image_width, ctx->image_height, &ctx->src_rect, + &ctx->dst_rect, NULL, NULL); + struct vo_rect *dst = &ctx->dst_rect; + vo_x11_clearwindow_part(vo, vo->x11->window, dst->width, dst->height, 1); + vo_xv_draw_colorkey(vo, dst->left, dst->top, dst->width, dst->height); } /* * connect to server, create and map window, * allocate colors and (shared) memory */ -static int config(uint32_t width, uint32_t height, uint32_t d_width, - uint32_t d_height, uint32_t flags, char *title, - uint32_t format) +static int config(struct vo *vo, uint32_t width, uint32_t height, + uint32_t d_width, uint32_t d_height, uint32_t flags, + char *title, uint32_t format) { + struct vo_x11_state *x11 = vo->x11; XVisualInfo vinfo; XSetWindowAttributes xswa; XWindowAttributes attribs; unsigned long xswamask; int depth; + struct xvctx *ctx = vo->priv; + int i; -#ifdef CONFIG_XF86VM - int vm = flags & VOFLAG_MODESWITCHING; -#endif - - image_height = height; - image_width = width; - image_format = format; + ctx->image_height = height; + ctx->image_width = width; + ctx->image_format = format; - if ((max_width != 0 && max_height != 0) && - (image_width > max_width || image_height > max_height)) - { - mp_msg( MSGT_VO, MSGL_ERR, MSGTR_VO_XV_ImagedimTooHigh, - image_width, image_height, max_width, max_height); + if ((ctx->max_width != 0 && ctx->max_height != 0) + && (ctx->image_width > ctx->max_width + || ctx->image_height > ctx->max_height)) { + mp_tmsg(MSGT_VO, MSGL_ERR, "Source image dimensions are too high: %ux%u (maximum is %ux%u)\n", + ctx->image_width, ctx->image_height, ctx->max_width, + ctx->max_height); return -1; } - int_pause = 0; - visible_buf = -1; - - num_buffers = - vo_doublebuffering ? (vo_directrendering ? NUM_BUFFERS : 2) : 1; + ctx->visible_buf = -1; + ctx->have_visible_image_copy = false; + ctx->have_next_image_copy = false; /* check image formats */ - { - unsigned int i; - - xv_format = 0; - for (i = 0; i < formats; i++) - { - mp_msg(MSGT_VO, MSGL_V, - "Xvideo image format: 0x%x (%4.4s) %s\n", fo[i].id, - (char *) &fo[i].id, - (fo[i].format == XvPacked) ? "packed" : "planar"); - if (fo[i].id == format) - xv_format = fo[i].id; - } - if (!xv_format) - return -1; + ctx->xv_format = 0; + for (i = 0; i < ctx->formats; i++) { + mp_msg(MSGT_VO, MSGL_V, "Xvideo image format: 0x%x (%4.4s) %s\n", + ctx->fo[i].id, (char *) &ctx->fo[i].id, + (ctx->fo[i].format == XvPacked) ? "packed" : "planar"); + if (ctx->fo[i].id == format) + ctx->xv_format = ctx->fo[i].id; } + if (!ctx->xv_format) + return -1; -#ifdef CONFIG_GUI - if (use_gui) - guiGetEvent(guiSetShVideo, 0); // the GUI will set up / resize the window - else -#endif { #ifdef CONFIG_XF86VM - if (vm) - { - vo_vm_switch(); + int vm = flags & VOFLAG_MODESWITCHING; + if (vm) { + vo_vm_switch(vo); + ctx->mode_switched = 1; } #endif - XGetWindowAttributes(mDisplay, DefaultRootWindow(mDisplay), + XGetWindowAttributes(x11->display, DefaultRootWindow(x11->display), &attribs); depth = attribs.depth; if (depth != 15 && depth != 16 && depth != 24 && depth != 32) depth = 24; - XMatchVisualInfo(mDisplay, mScreen, depth, TrueColor, &vinfo); + XMatchVisualInfo(x11->display, x11->screen, depth, TrueColor, &vinfo); xswa.background_pixel = 0; - if (xv_ck_info.method == CK_METHOD_BACKGROUND) - { - xswa.background_pixel = xv_colorkey; - } + if (x11->xv_ck_info.method == CK_METHOD_BACKGROUND) + xswa.background_pixel = x11->xv_colorkey; xswa.border_pixel = 0; xswamask = CWBackPixel | CWBorderPixel; - vo_x11_create_vo_window(&vinfo, vo_dx, vo_dy, vo_dwidth, vo_dheight, - flags, CopyFromParent, "xv", title); - XChangeWindowAttributes(mDisplay, vo_window, xswamask, &xswa); + vo_x11_create_vo_window(vo, &vinfo, vo->dx, vo->dy, vo->dwidth, + vo->dheight, flags, CopyFromParent, "xv", + title); + XChangeWindowAttributes(x11->display, x11->window, xswamask, &xswa); #ifdef CONFIG_XF86VM - if (vm) - { + if (vm) { /* Grab the mouse pointer in our window */ if (vo_grabpointer) - XGrabPointer(mDisplay, vo_window, True, 0, - GrabModeAsync, GrabModeAsync, - vo_window, None, CurrentTime); - XSetInputFocus(mDisplay, vo_window, RevertToNone, CurrentTime); + XGrabPointer(x11->display, x11->window, True, 0, GrabModeAsync, + GrabModeAsync, x11->window, None, CurrentTime); + XSetInputFocus(x11->display, x11->window, RevertToNone, + CurrentTime); } #endif } mp_msg(MSGT_VO, MSGL_V, "using Xvideo port %d for hw scaling\n", - xv_port); - - switch (xv_format) - { - case IMGFMT_YV12: - case IMGFMT_I420: - case IMGFMT_IYUV: - draw_alpha_fnc = draw_alpha_yv12; - break; - case IMGFMT_YUY2: - case IMGFMT_YVYU: - draw_alpha_fnc = draw_alpha_yuy2; - break; - case IMGFMT_UYVY: - draw_alpha_fnc = draw_alpha_uyvy; - break; - default: - draw_alpha_fnc = draw_alpha_null; + x11->xv_port); + + switch (ctx->xv_format) { + case IMGFMT_YV12: + case IMGFMT_I420: + case IMGFMT_IYUV: + ctx->draw_alpha_fnc = draw_alpha_yv12; + break; + case IMGFMT_YUY2: + case IMGFMT_YVYU: + ctx->draw_alpha_fnc = draw_alpha_yuy2; + break; + case IMGFMT_UYVY: + ctx->draw_alpha_fnc = draw_alpha_uyvy; + break; + default: + ctx->draw_alpha_fnc = draw_alpha_null; } - if (vo_config_count) - for (current_buf = 0; current_buf < num_buffers; ++current_buf) - deallocate_xvimage(current_buf); + // In case config has been called before + for (i = 0; i < ctx->total_buffers; i++) + deallocate_xvimage(vo, i); + + ctx->num_buffers = + vo_doublebuffering ? (vo_directrendering ? NUM_BUFFERS : 2) : 1; + ctx->total_buffers = ctx->num_buffers + 1; + + for (i = 0; i < ctx->total_buffers; i++) + allocate_xvimage(vo, i); - for (current_buf = 0; current_buf < num_buffers; ++current_buf) - allocate_xvimage(current_buf); + ctx->current_buf = 0; + ctx->current_ip_buf = 0; - current_buf = 0; - current_ip_buf = 0; - resize(); + resize(vo); return 0; } -static void allocate_xvimage(int foo) +static void allocate_xvimage(struct vo *vo, int foo) { + struct xvctx *ctx = vo->priv; + struct vo_x11_state *x11 = vo->x11; /* * allocate XvImages. FIXME: no error checking, without * mit-shm this will bomb... trzing to fix ::atmos */ #ifdef HAVE_SHM - if (mLocalDisplay && XShmQueryExtension(mDisplay)) - Shmem_Flag = 1; - else - { - Shmem_Flag = 0; - mp_msg(MSGT_VO, MSGL_INFO, - MSGTR_LIBVO_XV_SharedMemoryNotSupported); + if (x11->display_is_local && XShmQueryExtension(x11->display)) + ctx->Shmem_Flag = 1; + else { + ctx->Shmem_Flag = 0; + mp_tmsg(MSGT_VO, MSGL_INFO, "[VO_XV] Shared memory not supported\nReverting to normal Xv.\n"); } - if (Shmem_Flag) - { - xvimage[foo] = - (XvImage *) XvShmCreateImage(mDisplay, xv_port, xv_format, - NULL, image_width, image_height, - &Shminfo[foo]); - - Shminfo[foo].shmid = - shmget(IPC_PRIVATE, xvimage[foo]->data_size, IPC_CREAT | 0777); - Shminfo[foo].shmaddr = (char *) shmat(Shminfo[foo].shmid, 0, 0); - Shminfo[foo].readOnly = False; - - xvimage[foo]->data = Shminfo[foo].shmaddr; - XShmAttach(mDisplay, &Shminfo[foo]); - XSync(mDisplay, False); - shmctl(Shminfo[foo].shmid, IPC_RMID, 0); + if (ctx->Shmem_Flag) { + ctx->xvimage[foo] = + (XvImage *) XvShmCreateImage(x11->display, x11->xv_port, + ctx->xv_format, NULL, + ctx->image_width, ctx->image_height, + &ctx->Shminfo[foo]); + + ctx->Shminfo[foo].shmid = shmget(IPC_PRIVATE, + ctx->xvimage[foo]->data_size, + IPC_CREAT | 0777); + ctx->Shminfo[foo].shmaddr = (char *) shmat(ctx->Shminfo[foo].shmid, 0, + 0); + ctx->Shminfo[foo].readOnly = False; + + ctx->xvimage[foo]->data = ctx->Shminfo[foo].shmaddr; + XShmAttach(x11->display, &ctx->Shminfo[foo]); + XSync(x11->display, False); + shmctl(ctx->Shminfo[foo].shmid, IPC_RMID, 0); } else #endif { - xvimage[foo] = - (XvImage *) XvCreateImage(mDisplay, xv_port, xv_format, NULL, - image_width, image_height); - xvimage[foo]->data = malloc(xvimage[foo]->data_size); - XSync(mDisplay, False); + ctx->xvimage[foo] = + (XvImage *) XvCreateImage(x11->display, x11->xv_port, + ctx->xv_format, NULL, ctx->image_width, + ctx->image_height); + ctx->xvimage[foo]->data = malloc(ctx->xvimage[foo]->data_size); + XSync(x11->display, False); } - memset(xvimage[foo]->data, 128, xvimage[foo]->data_size); + memset(ctx->xvimage[foo]->data, 128, ctx->xvimage[foo]->data_size); return; } -static void deallocate_xvimage(int foo) +static void deallocate_xvimage(struct vo *vo, int foo) { + struct xvctx *ctx = vo->priv; #ifdef HAVE_SHM - if (Shmem_Flag) - { - XShmDetach(mDisplay, &Shminfo[foo]); - shmdt(Shminfo[foo].shmaddr); + if (ctx->Shmem_Flag) { + XShmDetach(vo->x11->display, &ctx->Shminfo[foo]); + shmdt(ctx->Shminfo[foo].shmaddr); } else #endif { - free(xvimage[foo]->data); + free(ctx->xvimage[foo]->data); } - XFree(xvimage[foo]); + XFree(ctx->xvimage[foo]); - XSync(mDisplay, False); + XSync(vo->x11->display, False); return; } -static inline void put_xvimage( XvImage * xvi ) +static inline void put_xvimage(struct vo *vo, XvImage *xvi) { + struct xvctx *ctx = vo->priv; + struct vo_x11_state *x11 = vo->x11; + struct vo_rect *src = &ctx->src_rect; + struct vo_rect *dst = &ctx->dst_rect; #ifdef HAVE_SHM - if (Shmem_Flag) - { - XvShmPutImage(mDisplay, xv_port, vo_window, vo_gc, - xvi, - src_rect.left, src_rect.top, src_rect.width, src_rect.height, - dst_rect.left, dst_rect.top, dst_rect.width, dst_rect.height, + if (ctx->Shmem_Flag) { + XvShmPutImage(x11->display, x11->xv_port, x11->window, x11->vo_gc, xvi, + src->left, src->top, src->width, src->height, + dst->left, dst->top, dst->width, dst->height, False); } else #endif { - XvPutImage(mDisplay, xv_port, vo_window, vo_gc, - xvi, - src_rect.left, src_rect.top, src_rect.width, src_rect.height, - dst_rect.left, dst_rect.top, dst_rect.width, dst_rect.height); + XvPutImage(x11->display, x11->xv_port, x11->window, x11->vo_gc, xvi, + src->left, src->top, src->width, src->height, + dst->left, dst->top, dst->width, dst->height); } } -static void check_events(void) +// Only copies luma for planar formats as draw_alpha doesn't change others */ +static void copy_backup_image(struct vo *vo, int dest, int src) { - int e = vo_x11_check_events(mDisplay); + struct xvctx *ctx = vo->priv; + + XvImage *vb = ctx->xvimage[dest]; + XvImage *cp = ctx->xvimage[src]; + memcpy_pic(vb->data + vb->offsets[0], cp->data + cp->offsets[0], + vb->width, vb->height, + vb->pitches[0], cp->pitches[0]); +} + +static void check_events(struct vo *vo) +{ + struct xvctx *ctx = vo->priv; + int e = vo_x11_check_events(vo); if (e & VO_EVENT_EXPOSE || e & VO_EVENT_RESIZE) - { - resize(); - } + resize(vo); - if ((e & VO_EVENT_EXPOSE || e & VO_EVENT_RESIZE) && int_pause) - { + if ((e & VO_EVENT_EXPOSE || e & VO_EVENT_RESIZE) && ctx->is_paused) { /* did we already draw a buffer */ - if ( visible_buf != -1 ) - { - /* redraw the last visible buffer */ - put_xvimage( xvimage[visible_buf] ); + if (ctx->visible_buf != -1) { + /* redraw the last visible buffer */ + put_xvimage(vo, ctx->xvimage[ctx->visible_buf]); } } } -static void draw_osd(void) +static void draw_osd(struct vo *vo, struct osd_state *osd) { - vo_draw_text(image_width - - image_width * vo_panscan_x / (vo_dwidth + vo_panscan_x), - image_height, draw_alpha_fnc); + struct xvctx *ctx = vo->priv; + + ctx->osd_objects_drawn = 0; + osd_draw_text(osd, + ctx->image_width - + ctx->image_width * vo->panscan_x / (vo->dwidth + + vo->panscan_x), + ctx->image_height, ctx->draw_alpha_fnc, vo); + if (ctx->osd_objects_drawn) + ctx->unchanged_next_image = false; } -static void flip_page(void) +static int redraw_osd(struct vo *vo, struct osd_state *osd) { - put_xvimage( xvimage[current_buf] ); + struct xvctx *ctx = vo->priv; + + if (ctx->have_visible_image_copy) + copy_backup_image(vo, ctx->visible_buf, ctx->num_buffers); + else if (ctx->unchanged_visible_image) { + copy_backup_image(vo, ctx->num_buffers, ctx->visible_buf); + ctx->have_visible_image_copy = true; + } + else + return false; + int temp = ctx->current_buf; + ctx->current_buf = ctx->visible_buf; + draw_osd(vo, osd); + ctx->current_buf = temp; + put_xvimage(vo, ctx->xvimage[ctx->visible_buf]); + return true; +} + +static void flip_page(struct vo *vo) +{ + struct xvctx *ctx = vo->priv; + put_xvimage(vo, ctx->xvimage[ctx->current_buf]); /* remember the currently visible buffer */ - visible_buf = current_buf; + ctx->visible_buf = ctx->current_buf; - if (num_buffers > 1) - { - current_buf = - vo_directrendering ? 0 : ((current_buf + 1) % num_buffers); - XFlush(mDisplay); + ctx->have_visible_image_copy = ctx->have_next_image_copy; + ctx->have_next_image_copy = false; + ctx->unchanged_visible_image = ctx->unchanged_next_image; + ctx->unchanged_next_image = false; + + if (ctx->num_buffers > 1) { + ctx->current_buf = vo_directrendering ? 0 : ((ctx->current_buf + 1) % + ctx->num_buffers); + XFlush(vo->x11->display); } else - XSync(mDisplay, False); + XSync(vo->x11->display, False); return; } -static int draw_slice(uint8_t * image[], int stride[], int w, int h, - int x, int y) +static int draw_slice(struct vo *vo, uint8_t *image[], int stride[], int w, + int h, int x, int y) { + struct xvctx *ctx = vo->priv; uint8_t *dst; + XvImage *current_image = ctx->xvimage[ctx->current_buf]; - dst = xvimage[current_buf]->data + xvimage[current_buf]->offsets[0] + - xvimage[current_buf]->pitches[0] * y + x; - memcpy_pic(dst, image[0], w, h, xvimage[current_buf]->pitches[0], - stride[0]); + dst = current_image->data + current_image->offsets[0] + + current_image->pitches[0] * y + x; + memcpy_pic(dst, image[0], w, h, current_image->pitches[0], stride[0]); x /= 2; y /= 2; w /= 2; h /= 2; - dst = xvimage[current_buf]->data + xvimage[current_buf]->offsets[1] + - xvimage[current_buf]->pitches[1] * y + x; - if (image_format != IMGFMT_YV12) - memcpy_pic(dst, image[1], w, h, xvimage[current_buf]->pitches[1], - stride[1]); + dst = current_image->data + current_image->offsets[1] + + current_image->pitches[1] * y + x; + if (ctx->image_format != IMGFMT_YV12) + memcpy_pic(dst, image[1], w, h, current_image->pitches[1], stride[1]); else - memcpy_pic(dst, image[2], w, h, xvimage[current_buf]->pitches[1], - stride[2]); - - dst = xvimage[current_buf]->data + xvimage[current_buf]->offsets[2] + - xvimage[current_buf]->pitches[2] * y + x; - if (image_format == IMGFMT_YV12) - memcpy_pic(dst, image[1], w, h, xvimage[current_buf]->pitches[1], - stride[1]); + memcpy_pic(dst, image[2], w, h, current_image->pitches[1], stride[2]); + + dst = current_image->data + current_image->offsets[2] + + current_image->pitches[2] * y + x; + if (ctx->image_format == IMGFMT_YV12) + memcpy_pic(dst, image[1], w, h, current_image->pitches[1], stride[1]); else - memcpy_pic(dst, image[2], w, h, xvimage[current_buf]->pitches[1], - stride[2]); + memcpy_pic(dst, image[2], w, h, current_image->pitches[1], stride[2]); return 0; } -static int draw_frame(uint8_t * src[]) +static uint32_t draw_image(struct vo *vo, mp_image_t *mpi) { - return VO_ERROR; -} + struct xvctx *ctx = vo->priv; + + ctx->have_next_image_copy = false; -static uint32_t draw_image(mp_image_t * mpi) -{ if (mpi->flags & MP_IMGFLAG_DIRECT) - { // direct rendering: - current_buf = (int) (mpi->priv); // hack! - return VO_TRUE; - } - if (mpi->flags & MP_IMGFLAG_DRAW_CALLBACK) - return VO_TRUE; // done - if (mpi->flags & MP_IMGFLAG_PLANAR) - { - draw_slice(mpi->planes, mpi->stride, mpi->w, mpi->h, 0, 0); - return VO_TRUE; - } - if (mpi->flags & MP_IMGFLAG_YUV) - { + ctx->current_buf = (int) (mpi->priv); // hack! + else if (mpi->flags & MP_IMGFLAG_DRAW_CALLBACK) + ; // done + else if (mpi->flags & MP_IMGFLAG_PLANAR) + draw_slice(vo, mpi->planes, mpi->stride, mpi->w, mpi->h, 0, 0); + else if (mpi->flags & MP_IMGFLAG_YUV) // packed YUV: - memcpy_pic(xvimage[current_buf]->data + - xvimage[current_buf]->offsets[0], mpi->planes[0], + memcpy_pic(ctx->xvimage[ctx->current_buf]->data + + ctx->xvimage[ctx->current_buf]->offsets[0], mpi->planes[0], mpi->w * (mpi->bpp / 8), mpi->h, - xvimage[current_buf]->pitches[0], mpi->stride[0]); - return VO_TRUE; + ctx->xvimage[ctx->current_buf]->pitches[0], mpi->stride[0]); + else + return false; + + if (ctx->is_paused) { + copy_backup_image(vo, ctx->num_buffers, ctx->current_buf); + ctx->have_next_image_copy = true; } - return VO_FALSE; // not (yet) supported + ctx->unchanged_next_image = true; + return true; } -static uint32_t get_image(mp_image_t * mpi) +static uint32_t get_image(struct xvctx *ctx, mp_image_t *mpi) { - int buf = current_buf; // we shouldn't change current_buf unless we do DR! + // we shouldn't change current_buf unless we do DR! + int buf = ctx->current_buf; - if (mpi->type == MP_IMGTYPE_STATIC && num_buffers > 1) + if (mpi->type == MP_IMGTYPE_STATIC && ctx->num_buffers > 1) return VO_FALSE; // it is not static - if (mpi->imgfmt != image_format) + if (mpi->imgfmt != ctx->image_format) return VO_FALSE; // needs conversion :( -// if(mpi->flags&MP_IMGFLAG_READABLE) return VO_FALSE; // slow video ram - if (mpi->flags & MP_IMGFLAG_READABLE && - (mpi->type == MP_IMGTYPE_IPB || mpi->type == MP_IMGTYPE_IP)) - { + if (mpi->flags & MP_IMGFLAG_READABLE + && (mpi->type == MP_IMGTYPE_IPB || mpi->type == MP_IMGTYPE_IP)) { // reference (I/P) frame of IP or IPB: - if (num_buffers < 2) + if (ctx->num_buffers < 2) return VO_FALSE; // not enough - current_ip_buf ^= 1; + ctx->current_ip_buf ^= 1; // for IPB with 2 buffers we can DR only one of the 2 P frames: - if (mpi->type == MP_IMGTYPE_IPB && num_buffers < 3 - && current_ip_buf) + if (mpi->type == MP_IMGTYPE_IPB && ctx->num_buffers < 3 + && ctx->current_ip_buf) return VO_FALSE; - buf = current_ip_buf; + buf = ctx->current_ip_buf; if (mpi->type == MP_IMGTYPE_IPB) ++buf; // preserve space for B } - if (mpi->height > xvimage[buf]->height) + if (mpi->height > ctx->xvimage[buf]->height) return VO_FALSE; //buffer to small - if (mpi->width * (mpi->bpp / 8) > xvimage[buf]->pitches[0]) + if (mpi->width * (mpi->bpp / 8) > ctx->xvimage[buf]->pitches[0]) return VO_FALSE; //buffer to small if ((mpi->flags & (MP_IMGFLAG_ACCEPT_STRIDE | MP_IMGFLAG_ACCEPT_WIDTH)) - || (mpi->width * (mpi->bpp / 8) == xvimage[buf]->pitches[0])) - { - current_buf = buf; - mpi->planes[0] = - xvimage[current_buf]->data + xvimage[current_buf]->offsets[0]; - mpi->stride[0] = xvimage[current_buf]->pitches[0]; + || (mpi->width * (mpi->bpp / 8) == ctx->xvimage[buf]->pitches[0])) { + ctx->current_buf = buf; + XvImage *current_image = ctx->xvimage[ctx->current_buf]; + mpi->planes[0] = current_image->data + current_image->offsets[0]; + mpi->stride[0] = current_image->pitches[0]; mpi->width = mpi->stride[0] / (mpi->bpp / 8); - if (mpi->flags & MP_IMGFLAG_PLANAR) - { - if (mpi->flags & MP_IMGFLAG_SWAPPED) - { + if (mpi->flags & MP_IMGFLAG_PLANAR) { + if (mpi->flags & MP_IMGFLAG_SWAPPED) { // I420 - mpi->planes[1] = - xvimage[current_buf]->data + - xvimage[current_buf]->offsets[1]; - mpi->planes[2] = - xvimage[current_buf]->data + - xvimage[current_buf]->offsets[2]; - mpi->stride[1] = xvimage[current_buf]->pitches[1]; - mpi->stride[2] = xvimage[current_buf]->pitches[2]; - } else - { + mpi->planes[1] = current_image->data + + current_image->offsets[1]; + mpi->planes[2] = current_image->data + + current_image->offsets[2]; + mpi->stride[1] = current_image->pitches[1]; + mpi->stride[2] = current_image->pitches[2]; + } else { // YV12 - mpi->planes[1] = - xvimage[current_buf]->data + - xvimage[current_buf]->offsets[2]; - mpi->planes[2] = - xvimage[current_buf]->data + - xvimage[current_buf]->offsets[1]; - mpi->stride[1] = xvimage[current_buf]->pitches[2]; - mpi->stride[2] = xvimage[current_buf]->pitches[1]; + mpi->planes[1] = current_image->data + + current_image->offsets[2]; + mpi->planes[2] = current_image->data + + current_image->offsets[1]; + mpi->stride[1] = current_image->pitches[2]; + mpi->stride[2] = current_image->pitches[1]; } } mpi->flags |= MP_IMGFLAG_DIRECT; - mpi->priv = (void *) current_buf; -// printf("mga: get_image() SUCCESS -> Direct Rendering ENABLED\n"); + mpi->priv = (void *) ctx->current_buf; return VO_TRUE; } return VO_FALSE; } -static int query_format(uint32_t format) +static int query_format(struct xvctx *ctx, uint32_t format) { uint32_t i; int flag = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_OSD | VFCAP_ACCEPT_STRIDE; // FIXME! check for DOWN /* check image formats */ - for (i = 0; i < formats; i++) - { - if (fo[i].id == format) + for (i = 0; i < ctx->formats; i++) { + if (ctx->fo[i].id == format) return flag; //xv_format = fo[i].id; } return 0; } -static void uninit(void) +static void uninit(struct vo *vo) { + struct xvctx *ctx = vo->priv; int i; - if (!vo_config_count) - return; - visible_buf = -1; - XvFreeAdaptorInfo(ai); - ai = NULL; - if(fo){ - XFree(fo); - fo=NULL; + ctx->visible_buf = -1; + if (ctx->ai) + XvFreeAdaptorInfo(ctx->ai); + ctx->ai = NULL; + if (ctx->fo) { + XFree(ctx->fo); + ctx->fo = NULL; } - for (i = 0; i < num_buffers; i++) - deallocate_xvimage(i); + for (i = 0; i < ctx->total_buffers; i++) + deallocate_xvimage(vo, i); #ifdef CONFIG_XF86VM - vo_vm_close(); + if (ctx->mode_switched) + vo_vm_close(vo); #endif - mp_input_rm_event_fd(ConnectionNumber(mDisplay)); - vo_x11_uninit(); + if (ctx->event_fd_registered) + mp_input_rm_key_fd(vo->input_ctx, ConnectionNumber(vo->x11->display)); + // uninit() shouldn't get called unless initialization went past vo_init() + vo_x11_uninit(vo); } -static int preinit(const char *arg) +static int x11_fd_callback(void *ctx, int fd) +{ + struct vo *vo = ctx; + check_events(vo); + return mplayer_get_key(vo->key_fifo, 0); +} + +static int preinit(struct vo *vo, const char *arg) { XvPortID xv_p; int busy_ports = 0; unsigned int i; strarg_t ck_src_arg = { 0, NULL }; strarg_t ck_method_arg = { 0, NULL }; + struct xvctx *ctx = talloc_zero(vo, struct xvctx); + vo->priv = ctx; + struct vo_x11_state *x11 = vo->x11; int xv_adaptor = -1; const opt_t subopts[] = { /* name arg type arg var test */ - { "port", OPT_ARG_INT, &xv_port, int_pos }, + { "port", OPT_ARG_INT, &x11->xv_port, int_pos }, { "adaptor", OPT_ARG_INT, &xv_adaptor, int_non_neg }, { "ck", OPT_ARG_STR, &ck_src_arg, xv_test_ck }, { "ck-method", OPT_ARG_STR, &ck_method_arg, xv_test_ckm }, { NULL } |