uint32_t id; /* XVideo format */
uint16_t width; /* display width */
uint16_t height; /* display height */
+ uint32_t data_size; /* picture byte size (for non-SHM) */
bool shm; /* whether to use MIT-SHM */
};
static void Deinit (vout_thread_t *);
static void Display (vout_thread_t *, picture_t *);
static int Manage (vout_thread_t *);
+static int Control (vout_thread_t *, int, va_list);
int CheckError (vout_thread_t *vout, const char *str, xcb_void_cookie_t ck)
{
vout->pf_end = Deinit;
vout->pf_display = Display;
vout->pf_manage = Manage;
+ vout->pf_control = Control;
return VLC_SUCCESS;
error:
free (p_sys);
}
-static int QueryBestSize (vout_thread_t *vout,
- unsigned *restrict width, unsigned *restrict height)
-{
- vout_sys_t *p_sys = vout->p_sys;
- xcb_xv_query_best_size_reply_t *r;
- xcb_xv_query_best_size_cookie_t ck;
-
- ck = xcb_xv_query_best_size (p_sys->conn, p_sys->port,
- vout->fmt_in.i_visible_width,
- vout->fmt_in.i_visible_height,
- *width, *height, false);
- r = xcb_xv_query_best_size_reply (p_sys->conn, ck, NULL);
- if (r == NULL)
- return VLC_EGENERIC;
-
- msg_Dbg (vout, "best size: %ux%u -> %ux%u", *width, *height,
- r->actual_width, r->actual_height);
- *width = r->actual_width;
- *height = r->actual_height;
- free (r);
- return VLC_SUCCESS;
-}
-
-
static vlc_fourcc_t ParseFormat (vout_thread_t *vout,
const xcb_xv_image_format_info_t *restrict f)
{
{
case 32:
if (f->depth == 24)
- return VLC_FOURCC ('R', 'V', '3', '2');
+ return VLC_CODEC_RGB32;
break;
case 24:
if (f->depth == 24)
- return VLC_FOURCC ('R', 'V', '2', '4');
+ return VLC_CODEC_RGB24;
break;
case 16:
if (f->depth == 16)
- return VLC_FOURCC ('R', 'V', '1', '6');
+ return VLC_CODEC_RGB16;
if (f->depth == 15)
- return VLC_FOURCC ('R', 'V', '1', '5');
+ return VLC_CODEC_RGB15;
break;
case 8:
if (f->depth == 8)
- return VLC_FOURCC ('R', 'G', 'B', '2');
+ return VLC_CODEC_RGB8;
break;
}
break;
{
/*untested: case 24:
if (f->vhorz_u_period == 1 && f->vvert_u_period == 1)
- return VLC_FOURCC ('I', '4', '4', '4');
+ return VLC_CODEC_I444;
break;*/
case 16:
if (f->vhorz_u_period == 2 && f->vvert_u_period == 1)
{
if (!strcmp ((const char *)f->vcomp_order, "YUYV"))
- return VLC_FOURCC ('Y', 'U', 'Y', '2');
+ return VLC_CODEC_YUYV;
if (!strcmp ((const char *)f->vcomp_order, "UYVY"))
- return VLC_FOURCC ('U', 'Y', 'V', 'Y');
+ return VLC_CODEC_UYVY;
}
break;
}
if (f->vhorz_u_period == 2 && f->vvert_u_period == 2)
{
if (!strcmp ((const char *)f->vcomp_order, "YVU"))
- return VLC_FOURCC ('Y', 'V', '1', '2');
+ return VLC_CODEC_YV12;
if (!strcmp ((const char *)f->vcomp_order, "YUV"))
- return VLC_FOURCC ('I', '4', '2', '0');
+ return VLC_CODEC_I420;
}
}
break;
}
+static const xcb_xv_image_format_info_t *
+FindFormat (vout_thread_t *vout, vlc_fourcc_t chroma, xcb_xv_port_t port,
+ const xcb_xv_list_image_formats_reply_t *list,
+ xcb_xv_query_image_attributes_reply_t **restrict pa)
+{
+ xcb_connection_t *conn = vout->p_sys->conn;
+ const xcb_xv_image_format_info_t *f, *end;
+
+#ifndef XCB_XV_OLD
+ f = xcb_xv_list_image_formats_format (list);
+#else
+ f = (xcb_xv_image_format_info_t *) (list + 1);
+#endif
+ end = f + xcb_xv_list_image_formats_format_length (list);
+ for (; f < end; f++)
+ {
+ if (chroma != ParseFormat (vout, f))
+ continue;
+
+ xcb_xv_query_image_attributes_reply_t *i;
+ i = xcb_xv_query_image_attributes_reply (conn,
+ xcb_xv_query_image_attributes (conn, port, f->id,
+ vout->fmt_in.i_width, vout->fmt_in.i_height), NULL);
+ if (i == NULL)
+ continue;
+
+ if (i->width != vout->fmt_in.i_width
+ || i->height != vout->fmt_in.i_height)
+ {
+ msg_Warn (vout, "incompatible size %ux%u -> %"PRIu32"x%"PRIu32,
+ vout->fmt_in.i_width, vout->fmt_in.i_height,
+ i->width, i->height);
+ free (i);
+ continue;
+ }
+ *pa = i;
+ return f;
+ }
+ return NULL;
+}
+
/**
* Allocate drawable window and picture buffers.
*/
static int Init (vout_thread_t *vout)
{
vout_sys_t *p_sys = vout->p_sys;
- unsigned x, y, width, height;
+ xcb_xv_query_image_attributes_reply_t *att = NULL;
+ bool swap_planes = false; /* whether X wants V before U */
/* FIXME: check max image size */
xcb_xv_adaptor_info_iterator_t it;
if (r == NULL)
continue;
- const xcb_xv_image_format_info_t *f, *end;
- f = xcb_xv_list_image_formats_format (r);
- end = f + xcb_xv_list_image_formats_format_length (r);
- for (; f < end; f++)
- {
- vlc_fourcc_t chroma = ParseFormat (vout, f);
- if (!chroma)
- continue;
+ const xcb_xv_image_format_info_t *fmt;
- if (chroma == vout->fmt_in.i_chroma)
+ /* Video chroma in preference order */
+ const vlc_fourcc_t chromas[] = {
+ vout->fmt_in.i_chroma,
+ VLC_CODEC_YUYV,
+ VLC_CODEC_RGB24,
+ VLC_CODEC_RGB15,
+ };
+ for (size_t i = 0; i < sizeof (chromas) / sizeof (chromas[0]); i++)
+ {
+ vlc_fourcc_t chroma = chromas[i];
+ fmt = FindFormat (vout, chroma, a->base_id, r, &att);
+ if (fmt != NULL)
{
vout->output.i_chroma = chroma;
- p_sys->id = f->id;
- break;
+ goto found_format;
}
- /* TODO: RGB masks */
}
-
free (r);
- /* TODO: grab port */
+ continue;
- msg_Dbg (vout, "using image format 0x%"PRIx32, p_sys->id);
+ found_format:
+ /* TODO: grab port */
p_sys->port = a->base_id;
msg_Dbg (vout, "using port %"PRIu32, p_sys->port);
- break;
+
+ p_sys->id = fmt->id;
+ msg_Dbg (vout, "using image format 0x%"PRIx32, p_sys->id);
+ if (fmt->type == XCB_XV_IMAGE_FORMAT_INFO_TYPE_RGB)
+ {
+ vout->fmt_out.i_rmask = vout->output.i_rmask = fmt->red_mask;
+ vout->fmt_out.i_gmask = vout->output.i_gmask = fmt->green_mask;
+ vout->fmt_out.i_bmask = vout->output.i_bmask = fmt->blue_mask;
+ }
+ else
+ if (fmt->num_planes == 3)
+ swap_planes = !strcmp ((const char *)fmt->vcomp_order, "YVU");
+ free (r);
+ goto found_adaptor;
+ }
+ msg_Err (vout, "no available XVideo adaptor");
+ return VLC_EGENERIC; /* no usable adaptor */
+
+ /* Allocate picture buffers */
+ const uint32_t *offsets;
+found_adaptor:
+ offsets = xcb_xv_query_image_attributes_offsets (att);
+ p_sys->data_size = att->data_size;
+
+ I_OUTPUTPICTURES = 0;
+ for (size_t index = 0; I_OUTPUTPICTURES < 2; index++)
+ {
+ picture_t *pic = vout->p_picture + index;
+
+ if (index > sizeof (vout->p_picture) / sizeof (pic))
+ break;
+ if (pic->i_status != FREE_PICTURE)
+ continue;
+
+ picture_Setup (pic, vout->output.i_chroma,
+ att->width, att->height,
+ vout->fmt_in.i_aspect);
+ if (PictureAlloc (vout, pic, att->data_size,
+ p_sys->shm ? p_sys->conn : NULL))
+ break;
+ /* Allocate further planes as specified by XVideo */
+ /* We assume that offsets[0] is zero */
+ for (int i = 1; i < pic->i_planes; i++)
+ pic->p[i].p_pixels =
+ pic->p->p_pixels + offsets[swap_planes ? (3 - i) : i];
+ PP_OUTPUTPICTURE[I_OUTPUTPICTURES++] = pic;
}
+ free (att);
- /* TODO: fallback to RV24 or I420 */
- if (!vout->output.i_chroma)
- return VLC_EGENERIC; /* no usable adaptor */
+ unsigned x, y, width, height;
if (GetWindowSize (p_sys->embed, p_sys->conn, &width, &height))
return VLC_EGENERIC;
vout_PlacePicture (vout, width, height, &x, &y, &width, &height);
- if (QueryBestSize (vout, &width, &height))
- return VLC_EGENERIC;
const uint32_t values[] = { x, y, width, height, };
xcb_configure_window (p_sys->conn, p_sys->window,
XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y |
XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
values);
+ xcb_flush (p_sys->conn);
p_sys->height = height;
p_sys->width = width;
vout->output.i_width = vout->fmt_out.i_width = vout->fmt_in.i_width;
vout->output.i_height = vout->fmt_out.i_height = vout->fmt_in.i_height;
vout->fmt_out.i_x_offset = vout->fmt_in.i_x_offset;
- p_vout->fmt_out.i_y_offset = vout->fmt_in.i_y_offset;
+ vout->fmt_out.i_y_offset = vout->fmt_in.i_y_offset;
assert (height > 0);
vout->output.i_aspect = vout->fmt_out.i_aspect =
width * VOUT_ASPECT_FACTOR / height;
- /* Allocate picture buffers */
- I_OUTPUTPICTURES = 0;
- for (size_t index = 0; I_OUTPUTPICTURES < 2; index++)
- {
- picture_t *pic = vout->p_picture + index;
-
- if (index > sizeof (vout->p_picture) / sizeof (pic))
- break;
- if (pic->i_status != FREE_PICTURE)
- continue;
-
- vout_InitPicture (vout, pic, vout->output.i_chroma,
- vout->output.i_width, vout->output.i_height,
- vout->output.i_aspect);
- if (PictureAlloc (vout, pic, pic->p->i_pitch * pic->p->i_lines,
- p_sys->shm ? p_sys->conn : NULL))
- break;
- PP_OUTPUTPICTURE[I_OUTPUTPICTURES++] = pic;
- }
- xcb_flush (p_sys->conn);
return VLC_SUCCESS;
}
if (segment)
xcb_xv_shm_put_image (p_sys->conn, p_sys->port, p_sys->window,
p_sys->gc, segment, p_sys->id, 0,
- /* Src: */ 0, 0,
- pic->p->i_visible_pitch / pic->p->i_pixel_pitch,
- pic->p->i_visible_lines,
+ /* Src: */ vout->fmt_out.i_x_offset,
+ vout->fmt_out.i_y_offset,
+ vout->fmt_out.i_visible_width,
+ vout->fmt_out.i_visible_height,
/* Dst: */ 0, 0, p_sys->width, p_sys->height,
/* Memory: */
pic->p->i_pitch / pic->p->i_pixel_pitch,
else
xcb_xv_put_image (p_sys->conn, p_sys->port, p_sys->window,
p_sys->gc, p_sys->id,
- 0, 0,
- pic->p->i_visible_pitch / pic->p->i_pixel_pitch,
- pic->p->i_visible_lines,
+ vout->fmt_out.i_x_offset, vout->fmt_out.i_y_offset,
+ vout->fmt_out.i_visible_width,
+ vout->fmt_out.i_visible_height,
0, 0, p_sys->width, p_sys->height,
- pic->p->i_pitch / pic->p->i_pixel_pitch,
- pic->p->i_lines,
- pic->p->i_pitch * pic->p->i_lines, pic->p->p_pixels);
+ vout->fmt_out.i_width, vout->fmt_out.i_height,
+ p_sys->data_size, pic->p->p_pixels);
xcb_flush (p_sys->conn);
}
msg_Err (vout, "X server failure");
return VLC_EGENERIC;
}
+
+ CommonManage (vout);
+ if (vout->i_changes & VOUT_SIZE_CHANGE)
+ { /* TODO: factor this code with XV and X11 Init() */
+ unsigned x, y, width, height;
+
+ if (GetWindowSize (p_sys->embed, p_sys->conn, &width, &height))
+ return VLC_EGENERIC;
+ vout_PlacePicture (vout, width, height, &x, &y, &width, &height);
+
+ const uint32_t values[] = { x, y, width, height, };
+ xcb_configure_window (p_sys->conn, p_sys->window, XCB_CONFIG_WINDOW_X |
+ XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH |
+ XCB_CONFIG_WINDOW_HEIGHT, values);
+ vout->p_sys->width = width; // XXX: <-- this is useless, as the zoom is
+ vout->p_sys->height = height; // handled with VOUT_SET_SIZE anyway.
+ vout->i_changes &= ~VOUT_SIZE_CHANGE;
+ }
return VLC_SUCCESS;
}
vout->p_sys->width = width;
vout->p_sys->height = height;
}
+
+static int Control (vout_thread_t *vout, int query, va_list ap)
+{
+ return vout_ControlWindow (vout->p_sys->embed, query, ap);
+}