vo_x11: use two buffers like Xv

This commit is contained in:
Rudolf Polzer 2013-01-02 13:20:38 +01:00 committed by wm4
parent 4044754d24
commit aaa27ead86
1 changed files with 94 additions and 71 deletions

View File

@ -59,12 +59,12 @@ struct priv {
struct mp_image *original_image; struct mp_image *original_image;
/* local data */ /* local data */
unsigned char *ImageData; unsigned char *ImageData[2];
//! original unaligned pointer for free //! original unaligned pointer for free
unsigned char *ImageDataOrig; unsigned char *ImageDataOrig[2];
/* X11 related variables */ /* X11 related variables */
XImage *myximage; XImage *myximage[2];
int depth, bpp; int depth, bpp;
XWindowAttributes attribs; XWindowAttributes attribs;
@ -91,11 +91,16 @@ struct priv {
int firstTime; int firstTime;
#ifdef HAVE_SHM int current_buf;
int visible_buf;
int num_buffers;
int total_buffers;
int Shmem_Flag; int Shmem_Flag;
#ifdef HAVE_SHM
int Shm_Warned_Slow; int Shm_Warned_Slow;
XShmSegmentInfo Shminfo[1]; XShmSegmentInfo Shminfo[2];
int gXErrorFlag; int gXErrorFlag;
#endif #endif
}; };
@ -111,13 +116,14 @@ static void check_events(struct vo *vo)
if (ret & VO_EVENT_RESIZE) if (ret & VO_EVENT_RESIZE)
vo_x11_clearwindow(vo, vo->x11->window); vo_x11_clearwindow(vo, vo->x11->window);
else if (ret & VO_EVENT_EXPOSE) else if (ret & VO_EVENT_EXPOSE)
vo_x11_clearwindow_part(vo, vo->x11->window, p->myximage->width, vo_x11_clearwindow_part(vo, vo->x11->window,
p->myximage->height); p->myximage[p->current_buf]->width,
p->myximage[p->current_buf]->height);
if (ret & VO_EVENT_EXPOSE && p->int_pause) if (ret & VO_EVENT_EXPOSE && p->int_pause)
flip_page(vo); flip_page(vo);
} }
static void getMyXImage(struct priv *p) static void getMyXImage(struct priv *p, int foo)
{ {
struct vo *vo = p->vo; struct vo *vo = p->vo;
#ifdef HAVE_SHM #ifdef HAVE_SHM
@ -132,52 +138,50 @@ static void getMyXImage(struct priv *p)
} }
if (p->Shmem_Flag) { if (p->Shmem_Flag) {
p->myximage = p->myximage[foo] =
XShmCreateImage(vo->x11->display, p->vinfo.visual, p->depth, XShmCreateImage(vo->x11->display, p->vinfo.visual, p->depth,
ZPixmap, NULL, &p->Shminfo[0], p->image_width, ZPixmap, NULL, &p->Shminfo[foo], p->image_width,
p->image_height); p->image_height);
if (p->myximage == NULL) { if (p->myximage[foo] == NULL) {
mp_msg(MSGT_VO, MSGL_WARN, mp_msg(MSGT_VO, MSGL_WARN,
"Shared memory error,disabling ( Ximage error )\n"); "Shared memory error,disabling ( Ximage error )\n");
goto shmemerror; goto shmemerror;
} }
p->Shminfo[0].shmid = shmget(IPC_PRIVATE, p->Shminfo[foo].shmid = shmget(IPC_PRIVATE,
p->myximage->bytes_per_line * p->myximage[foo]->bytes_per_line *
p->myximage->height, p->myximage[foo]->height,
IPC_CREAT | 0777); IPC_CREAT | 0777);
if (p->Shminfo[0].shmid < 0) { if (p->Shminfo[foo].shmid < 0) {
XDestroyImage(p->myximage); XDestroyImage(p->myximage[foo]);
mp_msg(MSGT_VO, MSGL_V, "%s\n", strerror(errno)); mp_msg(MSGT_VO, MSGL_V, "%s\n", strerror(errno));
//perror( strerror( errno ) ); //perror( strerror( errno ) );
mp_msg(MSGT_VO, MSGL_WARN, mp_msg(MSGT_VO, MSGL_WARN,
"Shared memory error,disabling ( seg id error )\n"); "Shared memory error,disabling ( seg id error )\n");
goto shmemerror; goto shmemerror;
} }
p->Shminfo[0].shmaddr = (char *) shmat(p->Shminfo[0].shmid, 0, 0); p->Shminfo[foo].shmaddr = (char *) shmat(p->Shminfo[foo].shmid, 0, 0);
if (p->Shminfo[0].shmaddr == ((char *) -1)) { if (p->Shminfo[foo].shmaddr == ((char *) -1)) {
XDestroyImage(p->myximage); XDestroyImage(p->myximage[foo]);
if (p->Shminfo[0].shmaddr != ((char *) -1))
shmdt(p->Shminfo[0].shmaddr);
mp_msg(MSGT_VO, MSGL_WARN, mp_msg(MSGT_VO, MSGL_WARN,
"Shared memory error,disabling ( address error )\n"); "Shared memory error,disabling ( address error )\n");
goto shmemerror; goto shmemerror;
} }
p->myximage->data = p->Shminfo[0].shmaddr; p->myximage[foo]->data = p->Shminfo[foo].shmaddr;
p->ImageData = (unsigned char *) p->myximage->data; p->ImageData[foo] = (unsigned char *) p->myximage[foo]->data;
p->Shminfo[0].readOnly = False; p->Shminfo[foo].readOnly = False;
XShmAttach(vo->x11->display, &p->Shminfo[0]); XShmAttach(vo->x11->display, &p->Shminfo[foo]);
XSync(vo->x11->display, False); XSync(vo->x11->display, False);
if (p->gXErrorFlag) { if (p->gXErrorFlag) {
XDestroyImage(p->myximage); XDestroyImage(p->myximage[foo]);
shmdt(p->Shminfo[0].shmaddr); shmdt(p->Shminfo[foo].shmaddr);
mp_msg(MSGT_VO, MSGL_WARN, "Shared memory error,disabling.\n"); mp_msg(MSGT_VO, MSGL_WARN, "Shared memory error,disabling.\n");
p->gXErrorFlag = 0; p->gXErrorFlag = 0;
goto shmemerror; goto shmemerror;
} else } else
shmctl(p->Shminfo[0].shmid, IPC_RMID, 0); shmctl(p->Shminfo[foo].shmid, IPC_RMID, 0);
if (!p->firstTime) { if (!p->firstTime) {
mp_msg(MSGT_VO, MSGL_V, "Sharing memory.\n"); mp_msg(MSGT_VO, MSGL_V, "Sharing memory.\n");
@ -187,36 +191,40 @@ static void getMyXImage(struct priv *p)
shmemerror: shmemerror:
p->Shmem_Flag = 0; p->Shmem_Flag = 0;
#endif #endif
p->myximage = p->myximage[foo] =
XCreateImage(vo->x11->display, p->vinfo.visual, p->depth, ZPixmap, XCreateImage(vo->x11->display, p->vinfo.visual, p->depth, ZPixmap,
0, NULL, p->image_width, p->image_height, 8, 0); 0, NULL, p->image_width, p->image_height, 8, 0);
p->ImageDataOrig = p->ImageDataOrig[foo] =
malloc(p->myximage->bytes_per_line * p->image_height + 32); malloc(p->myximage[foo]->bytes_per_line * p->image_height + 32);
p->myximage->data = p->ImageDataOrig + 16 - ((long)p->ImageDataOrig & 15); p->myximage[foo]->data = p->ImageDataOrig[foo] + 16
memset(p->myximage->data, 0, p->myximage->bytes_per_line * p->image_height); - ((long)p->ImageDataOrig & 15);
p->ImageData = p->myximage->data; memset(p->myximage[foo]->data, 0, p->myximage[foo]->bytes_per_line
* p->image_height);
p->ImageData[foo] = p->myximage[foo]->data;
#ifdef HAVE_SHM #ifdef HAVE_SHM
} }
#endif #endif
} }
static void freeMyXImage(struct priv *p) static void freeMyXImage(struct priv *p, int foo)
{ {
struct vo *vo = p->vo; struct vo *vo = p->vo;
#ifdef HAVE_SHM #ifdef HAVE_SHM
if (p->Shmem_Flag) { if (p->Shmem_Flag) {
XShmDetach(vo->x11->display, &p->Shminfo[0]); XShmDetach(vo->x11->display, &p->Shminfo[foo]);
XDestroyImage(p->myximage); XDestroyImage(p->myximage[foo]);
shmdt(p->Shminfo[0].shmaddr); shmdt(p->Shminfo[foo].shmaddr);
} else } else
#endif #endif
{ {
p->myximage->data = p->ImageDataOrig; if (p->myximage[foo]) {
XDestroyImage(p->myximage); p->myximage[foo]->data = p->ImageDataOrig[foo];
p->ImageDataOrig = NULL; XDestroyImage(p->myximage[foo]);
p->ImageDataOrig[foo] = NULL;
}
} }
p->myximage = NULL; p->myximage[foo] = NULL;
p->ImageData = NULL; p->ImageData[foo] = NULL;
} }
#if BYTE_ORDER == BIG_ENDIAN #if BYTE_ORDER == BIG_ENDIAN
@ -335,11 +343,14 @@ static int config(struct vo *vo, uint32_t width, uint32_t height,
#endif #endif
} }
if (p->myximage) { int i;
freeMyXImage(p); for (i = 0; i < p->total_buffers; i++)
sws_freeContext(p->swsContext); freeMyXImage(p, i);
} sws_freeContext(p->swsContext);
getMyXImage(p); p->num_buffers = 2;
p->total_buffers = p->num_buffers;
for (i = 0; i < p->total_buffers; i++)
getMyXImage(p, i);
while (fmte->mpfmt) { while (fmte->mpfmt) {
int depth = IMGFMT_RGB_DEPTH(fmte->mpfmt); int depth = IMGFMT_RGB_DEPTH(fmte->mpfmt);
@ -348,11 +359,11 @@ static int config(struct vo *vo, uint32_t width, uint32_t height,
if (depth == 15) if (depth == 15)
depth = 16; depth = 16;
if (depth == p->myximage->bits_per_pixel && if (depth == p->myximage[0]->bits_per_pixel &&
fmte->byte_order == p->myximage->byte_order && fmte->byte_order == p->myximage[0]->byte_order &&
fmte->red_mask == p->myximage->red_mask && fmte->red_mask == p->myximage[0]->red_mask &&
fmte->green_mask == p->myximage->green_mask && fmte->green_mask == p->myximage[0]->green_mask &&
fmte->blue_mask == p->myximage->blue_mask) fmte->blue_mask == p->myximage[0]->blue_mask)
break; break;
fmte++; fmte++;
} }
@ -363,7 +374,7 @@ static int config(struct vo *vo, uint32_t width, uint32_t height,
return -1; return -1;
} }
p->out_format = fmte->mpfmt; p->out_format = fmte->mpfmt;
p->bpp = p->myximage->bits_per_pixel; p->bpp = p->myximage[0]->bits_per_pixel;
p->out_offset = 0; p->out_offset = 0;
// We can easily "emulate" non-native RGB32 and BGR32 // We can easily "emulate" non-native RGB32 and BGR32
if (p->out_format == (IMGFMT_BGR32 | 128) if (p->out_format == (IMGFMT_BGR32 | 128)
@ -392,8 +403,10 @@ static void Display_Image(struct priv *p, XImage *myximage, uint8_t *ImageData)
{ {
struct vo *vo = p->vo; struct vo *vo = p->vo;
XImage *x_image = p->myximage[p->current_buf];
int x = (vo->dwidth - p->dst_width) / 2; int x = (vo->dwidth - p->dst_width) / 2;
int y = (vo->dheight - p->myximage->height) / 2; int y = (vo->dheight - x_image->height) / 2;
// do not draw if the image needs rescaling // do not draw if the image needs rescaling
if ((p->old_vo_dwidth != vo->dwidth || if ((p->old_vo_dwidth != vo->dwidth ||
@ -404,29 +417,29 @@ static void Display_Image(struct priv *p, XImage *myximage, uint8_t *ImageData)
x = vo->dx; x = vo->dx;
y = vo->dy; y = vo->dy;
} }
p->myximage->data += p->out_offset; x_image->data += p->out_offset;
#ifdef HAVE_SHM #ifdef HAVE_SHM
if (p->Shmem_Flag) { if (p->Shmem_Flag) {
XShmPutImage(vo->x11->display, vo->x11->window, vo->x11->vo_gc, XShmPutImage(vo->x11->display, vo->x11->window, vo->x11->vo_gc,
p->myximage, 0, 0, x, y, p->dst_width, p->myximage->height, x_image, 0, 0, x, y, p->dst_width, x_image->height,
True); True);
vo->x11->ShmCompletionWaitCount++; vo->x11->ShmCompletionWaitCount++;
} else } else
#endif #endif
{ {
XPutImage(vo->x11->display, vo->x11->window, vo->x11->vo_gc, XPutImage(vo->x11->display, vo->x11->window, vo->x11->vo_gc,
p->myximage, 0, 0, x, y, p->dst_width, p->myximage->height); x_image, 0, 0, x, y, p->dst_width, x_image->height);
} }
p->myximage->data -= p->out_offset; x_image->data -= p->out_offset;
} }
static struct mp_image get_x_buffer(struct priv *p) static struct mp_image get_x_buffer(struct priv *p, int buf_index)
{ {
struct mp_image img = {0}; struct mp_image img = {0};
mp_image_set_size(&img, p->image_width, p->image_height); mp_image_set_size(&img, p->image_width, p->image_height);
mp_image_setfmt(&img, p->out_format); mp_image_setfmt(&img, p->out_format);
img.planes[0] = p->ImageData; img.planes[0] = p->ImageData[buf_index];
img.stride[0] = p->image_width * ((p->bpp + 7) / 8); img.stride[0] = p->image_width * ((p->bpp + 7) / 8);
return img; return img;
@ -436,7 +449,7 @@ static void draw_osd(struct vo *vo, struct osd_state *osd)
{ {
struct priv *p = vo->priv; struct priv *p = vo->priv;
struct mp_image img = get_x_buffer(p); struct mp_image img = get_x_buffer(p, p->current_buf);
struct mp_osd_res res = { struct mp_osd_res res = {
.w = img.w, .w = img.w,
@ -482,8 +495,13 @@ static void wait_for_completion(struct vo *vo, int max_outstanding)
static void flip_page(struct vo *vo) static void flip_page(struct vo *vo)
{ {
struct priv *p = vo->priv; struct priv *p = vo->priv;
Display_Image(p, p->myximage, p->ImageData); Display_Image(p, p->myximage[p->current_buf],
XSync(vo->x11->display, False); p->ImageData[p->current_buf]);
p->visible_buf = p->current_buf;
p->current_buf = (p->current_buf + 1) % p->num_buffers;
if (!p->Shmem_Flag)
XSync(vo->x11->display, False);
} }
static void draw_image(struct vo *vo, mp_image_t *mpi) static void draw_image(struct vo *vo, mp_image_t *mpi)
@ -492,7 +510,7 @@ static void draw_image(struct vo *vo, mp_image_t *mpi)
uint8_t *dst[MP_MAX_PLANES] = {NULL}; uint8_t *dst[MP_MAX_PLANES] = {NULL};
int dstStride[MP_MAX_PLANES] = {0}; int dstStride[MP_MAX_PLANES] = {0};
wait_for_completion(vo, 0); wait_for_completion(vo, p->num_buffers - 1);
if ((p->old_vo_dwidth != vo->dwidth || p->old_vo_dheight != vo->dheight) if ((p->old_vo_dwidth != vo->dwidth || p->old_vo_dheight != vo->dheight)
/*&& y==0 */ && p->zoomFlag) /*&& y==0 */ && p->zoomFlag)
@ -516,16 +534,19 @@ static void draw_image(struct vo *vo, mp_image_t *mpi)
p->image_width = (newW + 7) & (~7); p->image_width = (newW + 7) & (~7);
p->image_height = newH; p->image_height = newH;
freeMyXImage(p); int i;
getMyXImage(p); for (i = 0; i < p->total_buffers; i++)
freeMyXImage(p, i);
sws_freeContext(oldContext); sws_freeContext(oldContext);
for (i = 0; i < p->total_buffers; i++)
getMyXImage(p, i);
} else } else
p->swsContext = oldContext; p->swsContext = oldContext;
p->dst_width = newW; p->dst_width = newW;
} }
dstStride[0] = p->image_width * ((p->bpp + 7) / 8); dstStride[0] = p->image_width * ((p->bpp + 7) / 8);
dst[0] = p->ImageData; dst[0] = p->ImageData[p->current_buf];
if (p->Flip_Flag) { if (p->Flip_Flag) {
dst[0] += dstStride[0] * (p->image_height - 1); dst[0] += dstStride[0] * (p->image_height - 1);
dstStride[0] = -dstStride[0]; dstStride[0] = -dstStride[0];
@ -576,8 +597,10 @@ static int query_format(struct vo *vo, uint32_t format)
static void uninit(struct vo *vo) static void uninit(struct vo *vo)
{ {
struct priv *p = vo->priv; struct priv *p = vo->priv;
if (p->myximage) if (p->myximage[0])
freeMyXImage(p); freeMyXImage(p, 0);
if (p->myximage[1])
freeMyXImage(p, 1);
talloc_free(p->original_image); talloc_free(p->original_image);