sys/xvimage/xvimagesink.c: Improve the errors produced on bad output, including some human readable description strings.

Original commit message from CVS:
* sys/xvimage/xvimagesink.c: (gst_xvimagesink_xvimage_new),
(gst_xvimagesink_get_xv_support), (gst_xvimagesink_xcontext_get),
(gst_xvimagesink_get_format_from_caps), (gst_xvimagesink_setcaps),
(gst_xvimagesink_show_frame), (gst_xvimagesink_buffer_alloc):
Improve the errors produced on bad output, including some human
readable description strings.
Handle RGB Xv formats properly by transforming them into our
big-endian caps description.
Use gst_caps_truncate to ensure that we never try and choose a
non-fixed caps in buffer_alloc.
Handle the case where the XServer has a different idea about the size
required for a particular frame and gives us too small a memory
allocation.
Use -1 to indicate 'no image format', because 0 is a valid XServer
image format number.
Put RGB Xv formats at the end of the caps, so that we always prefer
YUV format frames.
Iterate the available Xv Encodings to determine the maximum width and
height, and then return that in our caps.
This commit is contained in:
Jan Schmidt 2006-05-26 09:40:35 +00:00
parent 0d9b638931
commit c1236503cf
2 changed files with 150 additions and 37 deletions

View file

@ -1,3 +1,25 @@
2006-05-26 Jan Schmidt <thaytan@mad.scientist.com>
* sys/xvimage/xvimagesink.c: (gst_xvimagesink_xvimage_new),
(gst_xvimagesink_get_xv_support), (gst_xvimagesink_xcontext_get),
(gst_xvimagesink_get_format_from_caps), (gst_xvimagesink_setcaps),
(gst_xvimagesink_show_frame), (gst_xvimagesink_buffer_alloc):
Improve the errors produced on bad output, including some human
readable description strings.
Handle RGB Xv formats properly by transforming them into our
big-endian caps description.
Use gst_caps_truncate to ensure that we never try and choose a
non-fixed caps in buffer_alloc.
Handle the case where the XServer has a different idea about the size
required for a particular frame and gives us too small a memory
allocation.
Use -1 to indicate 'no image format', because 0 is a valid XServer
image format number.
Put RGB Xv formats at the end of the caps, so that we always prefer
YUV format frames.
Iterate the available Xv Encodings to determine the maximum width and
height, and then return that in our caps.
2006-05-25 Jan Schmidt <thaytan@mad.scientist.com> 2006-05-25 Jan Schmidt <thaytan@mad.scientist.com>
* gst/playback/gstdecodebin.c: (remove_fakesink), (pad_probe): * gst/playback/gstdecodebin.c: (remove_fakesink), (pad_probe):

View file

@ -488,9 +488,12 @@ gst_xvimagesink_xvimage_new (GstXvImageSink * xvimagesink, GstCaps * caps)
xvimage->height); xvimage->height);
xvimage->im_format = gst_xvimagesink_get_format_from_caps (xvimagesink, caps); xvimage->im_format = gst_xvimagesink_get_format_from_caps (xvimagesink, caps);
if (!xvimage->im_format) { if (xvimage->im_format == -1) {
GST_WARNING_OBJECT (xvimagesink, "failed to get format from caps %" GST_WARNING_OBJECT (xvimagesink, "failed to get format from caps %"
GST_PTR_FORMAT, caps); GST_PTR_FORMAT, caps);
GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
("Failed to create output image buffer of %dx%d pixels",
xvimage->width, xvimage->height), ("Invalid input caps"));
goto beach_unlocked; goto beach_unlocked;
} }
xvimage->xvimagesink = gst_object_ref (xvimagesink); xvimage->xvimagesink = gst_object_ref (xvimagesink);
@ -504,8 +507,11 @@ gst_xvimagesink_xvimage_new (GstXvImageSink * xvimagesink, GstCaps * caps)
xvimage->im_format, NULL, xvimage->im_format, NULL,
xvimage->width, xvimage->height, &xvimage->SHMInfo); xvimage->width, xvimage->height, &xvimage->SHMInfo);
if (!xvimage->xvimage) { if (!xvimage->xvimage) {
GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, (NULL), GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
("could not XvShmCreateImage a %dx%d image")); ("Failed to create output image buffer of %dx%d pixels",
xvimage->width, xvimage->height),
("could not XvShmCreateImage a %dx%d image",
xvimage->width, xvimage->height));
goto beach; goto beach;
} }
@ -516,14 +522,18 @@ gst_xvimagesink_xvimage_new (GstXvImageSink * xvimagesink, GstCaps * caps)
xvimage->SHMInfo.shmid = shmget (IPC_PRIVATE, xvimage->size, xvimage->SHMInfo.shmid = shmget (IPC_PRIVATE, xvimage->size,
IPC_CREAT | 0777); IPC_CREAT | 0777);
if (xvimage->SHMInfo.shmid == -1) { if (xvimage->SHMInfo.shmid == -1) {
GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, (NULL), GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
("Failed to create output image buffer of %dx%d pixels",
xvimage->width, xvimage->height),
("could not get shared memory of %d bytes", xvimage->size)); ("could not get shared memory of %d bytes", xvimage->size));
goto beach; goto beach;
} }
xvimage->SHMInfo.shmaddr = shmat (xvimage->SHMInfo.shmid, 0, 0); xvimage->SHMInfo.shmaddr = shmat (xvimage->SHMInfo.shmid, 0, 0);
if (xvimage->SHMInfo.shmaddr == ((void *) -1)) { if (xvimage->SHMInfo.shmaddr == ((void *) -1)) {
GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, (NULL), GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
("Failed to create output image buffer of %dx%d pixels",
xvimage->width, xvimage->height),
("Failed to shmat: %s", g_strerror (errno))); ("Failed to shmat: %s", g_strerror (errno)));
/* Clean up the shared memory segment */ /* Clean up the shared memory segment */
shmctl (xvimage->SHMInfo.shmid, IPC_RMID, 0); shmctl (xvimage->SHMInfo.shmid, IPC_RMID, 0);
@ -539,8 +549,9 @@ gst_xvimagesink_xvimage_new (GstXvImageSink * xvimagesink, GstCaps * caps)
xvimage->SHMInfo.readOnly = FALSE; xvimage->SHMInfo.readOnly = FALSE;
if (XShmAttach (xvimagesink->xcontext->disp, &xvimage->SHMInfo) == 0) { if (XShmAttach (xvimagesink->xcontext->disp, &xvimage->SHMInfo) == 0) {
GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, (NULL), GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
("Failed to XShmAttach")); ("Failed to create output image buffer of %dx%d pixels",
xvimage->width, xvimage->height), ("Failed to XShmAttach"));
goto beach; goto beach;
} }
@ -552,8 +563,11 @@ gst_xvimagesink_xvimage_new (GstXvImageSink * xvimagesink, GstCaps * caps)
xvimagesink->xcontext->xv_port_id, xvimagesink->xcontext->xv_port_id,
xvimage->im_format, NULL, xvimage->width, xvimage->height); xvimage->im_format, NULL, xvimage->width, xvimage->height);
if (!xvimage->xvimage) { if (!xvimage->xvimage) {
GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, (NULL), GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
("could not XvCreateImage a %dx%d image")); ("Failed to create outputimage buffer of %dx%d pixels",
xvimage->width, xvimage->height),
("could not XvCreateImage a %dx%d image",
xvimage->width, xvimage->height));
goto beach; goto beach;
} }
@ -1055,13 +1069,18 @@ gst_xvimagesink_get_xv_support (GstXvImageSink * xvimagesink,
XvAdaptorInfo *adaptors; XvAdaptorInfo *adaptors;
gint nb_formats; gint nb_formats;
XvImageFormatValues *formats = NULL; XvImageFormatValues *formats = NULL;
guint nb_encodings;
XvEncodingInfo *encodings = NULL;
gulong max_w = G_MAXINT, max_h = G_MAXINT;
GstCaps *caps = NULL; GstCaps *caps = NULL;
GstCaps *rgb_caps = NULL;
g_return_val_if_fail (xcontext != NULL, NULL); g_return_val_if_fail (xcontext != NULL, NULL);
/* First let's check that XVideo extension is available */ /* First let's check that XVideo extension is available */
if (!XQueryExtension (xcontext->disp, "XVideo", &i, &i, &i)) { if (!XQueryExtension (xcontext->disp, "XVideo", &i, &i, &i)) {
GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS, (NULL), GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS,
("Could not initialise Xv output"),
("XVideo extension is not available")); ("XVideo extension is not available"));
return NULL; return NULL;
} }
@ -1069,7 +1088,8 @@ gst_xvimagesink_get_xv_support (GstXvImageSink * xvimagesink,
/* Then we get adaptors list */ /* Then we get adaptors list */
if (Success != XvQueryAdaptors (xcontext->disp, xcontext->root, if (Success != XvQueryAdaptors (xcontext->disp, xcontext->root,
&nb_adaptors, &adaptors)) { &nb_adaptors, &adaptors)) {
GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS, (NULL), GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS,
("Could not initialise Xv output"),
("Failed getting XV adaptors list")); ("Failed getting XV adaptors list"));
return NULL; return NULL;
} }
@ -1099,8 +1119,8 @@ gst_xvimagesink_get_xv_support (GstXvImageSink * xvimagesink,
XvFreeAdaptorInfo (adaptors); XvFreeAdaptorInfo (adaptors);
if (!xcontext->xv_port_id) { if (!xcontext->xv_port_id) {
GST_ELEMENT_ERROR (xvimagesink, RESOURCE, BUSY, (NULL), GST_ELEMENT_ERROR (xvimagesink, RESOURCE, BUSY,
("No port available")); ("Could not initialise Xv output"), ("No port available"));
return NULL; return NULL;
} }
@ -1143,12 +1163,32 @@ gst_xvimagesink_get_xv_support (GstXvImageSink * xvimagesink,
XFree (attr); XFree (attr);
} }
/* Get the list of encodings supported by the adapter and look for the
* XV_IMAGE encoding so we can determine the maximum width and height
* supported */
XvQueryEncodings (xcontext->disp, xcontext->xv_port_id, &nb_encodings,
&encodings);
for (i = 0; i < nb_encodings; i++) {
GST_LOG_OBJECT (xvimagesink,
"Encoding %d, name %s, max wxh %lux%lu rate %d/%d",
i, encodings[i].name, encodings[i].width, encodings[i].height,
encodings[i].rate.numerator, encodings[i].rate.denominator);
if (strcmp (encodings[i].name, "XV_IMAGE") == 0) {
max_w = encodings[i].width;
max_h = encodings[i].height;
}
}
XvFreeEncodingInfo (encodings);
/* We get all image formats supported by our port */ /* We get all image formats supported by our port */
formats = XvListImageFormats (xcontext->disp, formats = XvListImageFormats (xcontext->disp,
xcontext->xv_port_id, &nb_formats); xcontext->xv_port_id, &nb_formats);
caps = gst_caps_new_empty (); caps = gst_caps_new_empty ();
for (i = 0; i < nb_formats; i++) { for (i = 0; i < nb_formats; i++) {
GstCaps *format_caps = NULL; GstCaps *format_caps = NULL;
gboolean is_rgb_format = FALSE;
/* We set the image format of the xcontext to an existing one. Sink /* We set the image format of the xcontext to an existing one. Sink
connect method will override that but we need to have at least a connect method will override that but we need to have at least a
@ -1159,23 +1199,44 @@ gst_xvimagesink_get_xv_support (GstXvImageSink * xvimagesink,
switch (formats[i].type) { switch (formats[i].type) {
case XvRGB: case XvRGB:
{ {
XvImageFormatValues *fmt = &(formats[i]);
gint endianness = G_BIG_ENDIAN;
if (fmt->byte_order == LSBFirst) {
/* our caps system handles 24/32bpp RGB as big-endian. */
if (fmt->bits_per_pixel == 24 || fmt->bits_per_pixel == 32) {
fmt->red_mask = GUINT32_TO_BE (fmt->red_mask);
fmt->green_mask = GUINT32_TO_BE (fmt->green_mask);
fmt->blue_mask = GUINT32_TO_BE (fmt->blue_mask);
if (fmt->bits_per_pixel == 24) {
fmt->red_mask >>= 8;
fmt->green_mask >>= 8;
fmt->blue_mask >>= 8;
}
} else
endianness = G_LITTLE_ENDIAN;
}
format_caps = gst_caps_new_simple ("video/x-raw-rgb", format_caps = gst_caps_new_simple ("video/x-raw-rgb",
"endianness", G_TYPE_INT, xcontext->endianness, "endianness", G_TYPE_INT, endianness,
"depth", G_TYPE_INT, xcontext->depth, "depth", G_TYPE_INT, fmt->depth,
"bpp", G_TYPE_INT, xcontext->bpp, "bpp", G_TYPE_INT, fmt->bits_per_pixel,
"blue_mask", G_TYPE_INT, formats[i].red_mask, "blue_mask", G_TYPE_INT, fmt->red_mask,
"green_mask", G_TYPE_INT, formats[i].green_mask, "green_mask", G_TYPE_INT, fmt->green_mask,
"red_mask", G_TYPE_INT, formats[i].blue_mask, "red_mask", G_TYPE_INT, fmt->blue_mask,
"width", GST_TYPE_INT_RANGE, 1, G_MAXINT, "width", GST_TYPE_INT_RANGE, 1, max_w,
"height", GST_TYPE_INT_RANGE, 1, G_MAXINT, "height", GST_TYPE_INT_RANGE, 1, max_h,
"framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
is_rgb_format = TRUE;
break; break;
} }
case XvYUV: case XvYUV:
format_caps = gst_caps_new_simple ("video/x-raw-yuv", format_caps = gst_caps_new_simple ("video/x-raw-yuv",
"format", GST_TYPE_FOURCC, formats[i].id, "format", GST_TYPE_FOURCC, formats[i].id,
"width", GST_TYPE_INT_RANGE, 1, G_MAXINT, "width", GST_TYPE_INT_RANGE, 1, max_w,
"height", GST_TYPE_INT_RANGE, 1, G_MAXINT, "height", GST_TYPE_INT_RANGE, 1, max_h,
"framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
break; break;
default: default:
@ -1192,10 +1253,21 @@ gst_xvimagesink_get_xv_support (GstXvImageSink * xvimagesink,
format->caps = gst_caps_copy (format_caps); format->caps = gst_caps_copy (format_caps);
xcontext->formats_list = g_list_append (xcontext->formats_list, format); xcontext->formats_list = g_list_append (xcontext->formats_list, format);
} }
}
if (is_rgb_format) {
if (rgb_caps == NULL)
rgb_caps = format_caps;
else
gst_caps_append (rgb_caps, format_caps);
} else
gst_caps_append (caps, format_caps); gst_caps_append (caps, format_caps);
} }
}
/* Collected all caps into either the caps or rgb_caps structures.
* Append rgb_caps on the end of YUV, so that YUV is always preferred */
if (rgb_caps)
gst_caps_append (caps, rgb_caps);
if (formats) if (formats)
XFree (formats); XFree (formats);
@ -1312,8 +1384,8 @@ gst_xvimagesink_xcontext_get (GstXvImageSink * xvimagesink)
if (!xcontext->disp) { if (!xcontext->disp) {
g_mutex_unlock (xvimagesink->x_lock); g_mutex_unlock (xvimagesink->x_lock);
g_free (xcontext); g_free (xcontext);
GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, (NULL), GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
("Could not open display")); ("Could not initialise Xv output"), ("Could not open display"));
return NULL; return NULL;
} }
@ -1342,8 +1414,8 @@ gst_xvimagesink_xcontext_get (GstXvImageSink * xvimagesink)
XCloseDisplay (xcontext->disp); XCloseDisplay (xcontext->disp);
g_mutex_unlock (xvimagesink->x_lock); g_mutex_unlock (xvimagesink->x_lock);
g_free (xcontext); g_free (xcontext);
GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS, (NULL), GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS,
("Could not get pixel formats")); ("Could not initialise Xv output"), ("Could not get pixel formats"));
return NULL; return NULL;
} }
@ -1561,7 +1633,7 @@ gst_xvimagesink_get_format_from_caps (GstXvImageSink * xvimagesink,
list = g_list_next (list); list = g_list_next (list);
} }
return 0; return -1;
} }
static GstCaps * static GstCaps *
@ -1615,8 +1687,11 @@ gst_xvimagesink_setcaps (GstBaseSink * bsink, GstCaps * caps)
fps = gst_structure_get_value (structure, "framerate"); fps = gst_structure_get_value (structure, "framerate");
ret &= (fps != NULL); ret &= (fps != NULL);
if (!ret) if (!ret) {
GST_DEBUG_OBJECT (xvimagesink, "Failed to retrieve either width, "
"height or framerate from intersected caps");
return FALSE; return FALSE;
}
xvimagesink->fps_n = gst_value_get_fraction_numerator (fps); xvimagesink->fps_n = gst_value_get_fraction_numerator (fps);
xvimagesink->fps_d = gst_value_get_fraction_denominator (fps); xvimagesink->fps_d = gst_value_get_fraction_denominator (fps);
@ -1624,7 +1699,9 @@ gst_xvimagesink_setcaps (GstBaseSink * bsink, GstCaps * caps)
xvimagesink->video_width = video_width; xvimagesink->video_width = video_width;
xvimagesink->video_height = video_height; xvimagesink->video_height = video_height;
im_format = gst_xvimagesink_get_format_from_caps (xvimagesink, caps); im_format = gst_xvimagesink_get_format_from_caps (xvimagesink, caps);
if (im_format == 0) { if (im_format == -1) {
GST_DEBUG_OBJECT (xvimagesink,
"Could not locate image format from caps %" GST_PTR_FORMAT, caps);
return FALSE; return FALSE;
} }
@ -1847,9 +1924,20 @@ gst_xvimagesink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
xvimagesink->xvimage = gst_xvimagesink_xvimage_new (xvimagesink, xvimagesink->xvimage = gst_xvimagesink_xvimage_new (xvimagesink,
GST_BUFFER_CAPS (buf)); GST_BUFFER_CAPS (buf));
if ((!xvimagesink->xvimage) || if (!xvimagesink->xvimage)
(xvimagesink->xvimage->size < GST_BUFFER_SIZE (buf))) /* The create method should have posted an informative error */
goto no_image; goto no_image;
if (xvimagesink->xvimage->size < GST_BUFFER_SIZE (buf)) {
GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
("Failed to create output image buffer of %dx%d pixels",
xvimagesink->xvimage->width, xvimagesink->xvimage->height),
("XServer allocated buffer size did not match input buffer"));
gst_xvimage_buffer_destroy (xvimagesink->xvimage);
xvimagesink->xvimage = NULL;
goto no_image;
}
} }
memcpy (xvimagesink->xvimage->xvimage->data, memcpy (xvimagesink->xvimage->xvimage->data,
@ -1866,8 +1954,6 @@ no_image:
{ {
/* No image available. That's very bad ! */ /* No image available. That's very bad ! */
GST_WARNING_OBJECT (xvimagesink, "could not create image"); GST_WARNING_OBJECT (xvimagesink, "could not create image");
GST_ELEMENT_ERROR (xvimagesink, CORE, NEGOTIATION, (NULL),
("Failed creating an XvImage in xvimagesink chain function."));
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
} }
} }
@ -1903,6 +1989,10 @@ gst_xvimagesink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size,
/* Check the caps against our xcontext */ /* Check the caps against our xcontext */
intersection = gst_caps_intersect (xvimagesink->xcontext->caps, caps); intersection = gst_caps_intersect (xvimagesink->xcontext->caps, caps);
/* Ensure the returned caps are fixed */
gst_caps_truncate (intersection);
GST_DEBUG_OBJECT (xvimagesink, "intersection in buffer alloc returned %" GST_DEBUG_OBJECT (xvimagesink, "intersection in buffer alloc returned %"
GST_PTR_FORMAT, intersection); GST_PTR_FORMAT, intersection);
@ -1972,7 +2062,8 @@ reuse_last_caps:
/* Get geometry from caps */ /* Get geometry from caps */
structure = gst_caps_get_structure (intersection, 0); structure = gst_caps_get_structure (intersection, 0);
if (!gst_structure_get_int (structure, "width", &width) || if (!gst_structure_get_int (structure, "width", &width) ||
!gst_structure_get_int (structure, "height", &height) || !image_format) { !gst_structure_get_int (structure, "height", &height) ||
image_format == -1) {
GST_WARNING_OBJECT (xvimagesink, "invalid caps for buffer allocation %" GST_WARNING_OBJECT (xvimagesink, "invalid caps for buffer allocation %"
GST_PTR_FORMAT, intersection); GST_PTR_FORMAT, intersection);
ret = GST_FLOW_UNEXPECTED; ret = GST_FLOW_UNEXPECTED;