summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSébastien Moutte <sebastien@moutte.net>2007-03-11 22:23:04 +0000
committerJan Schmidt <thaytan@noraisin.net>2009-05-16 01:29:16 +0100
commitbf5c0a89f0078ea886e80eeaaf826003cd515982 (patch)
tree53af30d554cebd754b88546d3dd7d97106e93ca1
parent2949448e31eceb4f2066712d669efb4b4a9b85aa (diff)
downloadgstreamer-plugins-bad-bf5c0a89f0078ea886e80eeaaf826003cd515982.tar.gz
[MOVED FROM GOOD] sys/directdraw/gstdirectdrawsink.*: Handle display mode changes during playback.
Original commit message from CVS: * sys/directdraw/gstdirectdrawsink.c: * sys/directdraw/gstdirectdrawsink.h: Handle display mode changes during playback.
-rw-r--r--sys/directdraw/gstdirectdrawsink.c1085
-rw-r--r--sys/directdraw/gstdirectdrawsink.h9
2 files changed, 660 insertions, 434 deletions
diff --git a/sys/directdraw/gstdirectdrawsink.c b/sys/directdraw/gstdirectdrawsink.c
index b7e3fc866..ab778c841 100644
--- a/sys/directdraw/gstdirectdrawsink.c
+++ b/sys/directdraw/gstdirectdrawsink.c
@@ -30,7 +30,7 @@
*
* <refsect2>
* <para>
- * DirectdrawSink renders video frames to any win32 window. This element can receive
+ * DirectdrawSink renders video RGB frames to any win32 window. This element can receive
* a window ID from the application through the XOverlay interface and will then render
* video frames in this window.
* If no Window ID was provided by the application, the element will create its
@@ -88,21 +88,32 @@ static GstFlowReturn gst_directdraw_sink_show_frame (GstBaseSink * bsink,
static gboolean gst_directdraw_sink_setup_ddraw (GstDirectDrawSink * ddrawsink);
static gboolean gst_directdraw_sink_create_default_window (GstDirectDrawSink *
ddrawsink);
-static gboolean gst_directdraw_sink_create_ddraw_surface (GstDirectDrawSink *
+static gboolean gst_directdraw_sink_check_primary_surface (GstDirectDrawSink *
+ ddrawsink);
+static gboolean gst_directdraw_sink_check_offscreen_surface (GstDirectDrawSink *
ddrawsink);
static GstCaps *gst_directdraw_sink_get_ddrawcaps (GstDirectDrawSink *
ddrawsink);
+static GstCaps
+ *gst_directdraw_sink_create_caps_from_surfacedesc (LPDDSURFACEDESC2 desc);
static void gst_directdraw_sink_cleanup (GstDirectDrawSink * ddrawsink);
static void gst_directdraw_sink_bufferpool_clear (GstDirectDrawSink *
ddrawsink);
static void gst_directdraw_sink_ddraw_put (GstDirectDrawSink * ddrawsink,
GstDDrawSurface * surface);
+static gboolean gst_ddrawvideosink_get_format_from_caps (GstDirectDrawSink *
+ ddrawsink, GstCaps * caps, DDPIXELFORMAT * pPixelFormat);
+static void gst_directdraw_sink_center_rect (GstDirectDrawSink * ddrawsink,
+ RECT src, RECT dst, RECT * result);
+char *DDErrorString (HRESULT hr);
/* surfaces management functions */
static void gst_directdraw_sink_surface_destroy (GstDirectDrawSink * ddrawsink,
GstDDrawSurface * surface);
static GstDDrawSurface *gst_directdraw_sink_surface_create (GstDirectDrawSink *
ddrawsink, GstCaps * caps, size_t size);
+static gboolean gst_directdraw_sink_surface_check (GstDirectDrawSink *
+ ddrawsink, GstDDrawSurface * surface);
static GstStaticPadTemplate directdrawsink_sink_factory =
GST_STATIC_PAD_TEMPLATE ("sink",
@@ -191,327 +202,6 @@ gst_directdraw_sink_init_interfaces (GType type)
g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &xoverlay_info);
}
-/* Utility functions */
-
-/* this function fill a DDPIXELFORMAT using Gstreamer caps */
-static gboolean
-gst_ddrawvideosink_get_format_from_caps (GstDirectDrawSink * ddrawsink,
- GstCaps * caps, DDPIXELFORMAT * pPixelFormat)
-{
- GstStructure *structure = NULL;
- gboolean ret = TRUE;
-
- /* check params */
- g_return_val_if_fail (pPixelFormat, FALSE);
- g_return_val_if_fail (caps, FALSE);
-
- /* init structure */
- memset (pPixelFormat, 0, sizeof (DDPIXELFORMAT));
- pPixelFormat->dwSize = sizeof (DDPIXELFORMAT);
-
- if (!(structure = gst_caps_get_structure (caps, 0))) {
- GST_CAT_ERROR_OBJECT (directdrawsink_debug, ddrawsink,
- "can't get structure pointer from caps");
- return FALSE;
- }
-
- if (gst_structure_has_name (structure, "video/x-raw-rgb")) {
- gint depth, bitcount, bitmask, endianness;
-
- pPixelFormat->dwFlags = DDPF_RGB;
- ret &= gst_structure_get_int (structure, "bpp", &bitcount);
- pPixelFormat->dwRGBBitCount = bitcount;
- ret &= gst_structure_get_int (structure, "depth", &depth);
- ret &= gst_structure_get_int (structure, "red_mask", &bitmask);
- pPixelFormat->dwRBitMask = bitmask;
- ret &= gst_structure_get_int (structure, "green_mask", &bitmask);
- pPixelFormat->dwGBitMask = bitmask;
- ret &= gst_structure_get_int (structure, "blue_mask", &bitmask);
- pPixelFormat->dwBBitMask = bitmask;
-
- gst_structure_get_int (structure, "endianness", &endianness);
- if (endianness == G_BIG_ENDIAN) {
- endianness = G_LITTLE_ENDIAN;
- pPixelFormat->dwRBitMask = GUINT32_TO_BE (pPixelFormat->dwRBitMask);
- pPixelFormat->dwGBitMask = GUINT32_TO_BE (pPixelFormat->dwGBitMask);
- pPixelFormat->dwBBitMask = GUINT32_TO_BE (pPixelFormat->dwBBitMask);
- }
- } else if (gst_structure_has_name (structure, "video/x-raw-yuv")) {
- gint fourcc;
-
- pPixelFormat->dwFlags = DDPF_FOURCC;
- ret &= gst_structure_get_fourcc (structure, "format", &fourcc);
- pPixelFormat->dwFourCC = fourcc;
- } else {
- GST_CAT_WARNING_OBJECT (directdrawsink_debug, ddrawsink,
- "unknown caps name received %" GST_PTR_FORMAT, caps);
- ret = FALSE;
- }
-
- return ret;
-}
-
-/* This function centers the RECT of source surface to
-a dest surface and set the result RECT into result */
-static void
-gst_directdraw_sink_center_rect (GstDirectDrawSink * ddrawsink, RECT src,
- RECT dst, RECT * result)
-{
- gdouble src_ratio, dst_ratio;
- long src_width = src.right;
- long src_height = src.bottom;
- long dst_width = dst.right - dst.left;
- long dst_heigth = dst.bottom - dst.top;
- long result_width = 0, result_height = 0;
-
- g_return_if_fail (result != NULL);
-
- src_ratio = (gdouble) src_width / src_height;
- dst_ratio = (gdouble) dst_width / dst_heigth;
-
- if (src_ratio > dst_ratio) {
- /* new height */
- result_height = (long) (dst_width / src_ratio);
-
- result->left = dst.left;
- result->right = dst.right;
- result->top = dst.top + (dst_heigth - result_height) / 2;
- result->bottom = result->top + result_height;
-
- } else if (src_ratio < dst_ratio) {
- /* new width */
- result_width = (long) (dst_heigth * src_ratio);
-
- result->top = dst.top;
- result->bottom = dst.bottom;
- result->left = dst.left + (dst_width - result_width) / 2;
- result->right = result->left + result_width;
-
- } else {
- /* same ratio */
- memcpy (result, &dst, sizeof (RECT));
- }
-
- GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
- "source is %ldx%ld dest is %ldx%ld, result is %ldx%ld with x,y %ldx%ld",
- src_width, src_height, dst_width, dst_heigth,
- result->right - result->left, result->bottom - result->top, result->left,
- result->right);
-}
-
-/**
- * Get DirectDraw error message.
- * @hr: HRESULT code
- * Returns: Text representation of the error.
- */
-char *
-DDErrorString (HRESULT hr)
-{
- switch (hr) {
- case DDERR_ALREADYINITIALIZED:
- return "DDERR_ALREADYINITIALIZED";
- case DDERR_CANNOTATTACHSURFACE:
- return "DDERR_CANNOTATTACHSURFACE";
- case DDERR_CANNOTDETACHSURFACE:
- return "DDERR_CANNOTDETACHSURFACE";
- case DDERR_CURRENTLYNOTAVAIL:
- return "DDERR_CURRENTLYNOTAVAIL";
- case DDERR_EXCEPTION:
- return "DDERR_EXCEPTION";
- case DDERR_GENERIC:
- return "DDERR_GENERIC";
- case DDERR_HEIGHTALIGN:
- return "DDERR_HEIGHTALIGN";
- case DDERR_INCOMPATIBLEPRIMARY:
- return "DDERR_INCOMPATIBLEPRIMARY";
- case DDERR_INVALIDCAPS:
- return "DDERR_INVALIDCAPS";
- case DDERR_INVALIDCLIPLIST:
- return "DDERR_INVALIDCLIPLIST";
- case DDERR_INVALIDMODE:
- return "DDERR_INVALIDMODE";
- case DDERR_INVALIDOBJECT:
- return "DDERR_INVALIDOBJECT";
- case DDERR_INVALIDPARAMS:
- return "DDERR_INVALIDPARAMS";
- case DDERR_INVALIDPIXELFORMAT:
- return "DDERR_INVALIDPIXELFORMAT";
- case DDERR_INVALIDRECT:
- return "DDERR_INVALIDRECT";
- case DDERR_LOCKEDSURFACES:
- return "DDERR_LOCKEDSURFACES";
- case DDERR_NO3D:
- return "DDERR_NO3D";
- case DDERR_NOALPHAHW:
- return "DDERR_NOALPHAHW";
- case DDERR_NOCLIPLIST:
- return "DDERR_NOCLIPLIST";
- case DDERR_NOCOLORCONVHW:
- return "DDERR_NOCOLORCONVHW";
- case DDERR_NOCOOPERATIVELEVELSET:
- return "DDERR_NOCOOPERATIVELEVELSET";
- case DDERR_NOCOLORKEY:
- return "DDERR_NOCOLORKEY";
- case DDERR_NOCOLORKEYHW:
- return "DDERR_NOCOLORKEYHW";
- case DDERR_NODIRECTDRAWSUPPORT:
- return "DDERR_NODIRECTDRAWSUPPORT";
- case DDERR_NOEXCLUSIVEMODE:
- return "DDERR_NOEXCLUSIVEMODE";
- case DDERR_NOFLIPHW:
- return "DDERR_NOFLIPHW";
- case DDERR_NOGDI:
- return "DDERR_NOGDI";
- case DDERR_NOMIRRORHW:
- return "DDERR_NOMIRRORHW";
- case DDERR_NOTFOUND:
- return "DDERR_NOTFOUND";
- case DDERR_NOOVERLAYHW:
- return "DDERR_NOOVERLAYHW";
- case DDERR_NORASTEROPHW:
- return "DDERR_NORASTEROPHW";
- case DDERR_NOROTATIONHW:
- return "DDERR_NOROTATIONHW";
- case DDERR_NOSTRETCHHW:
- return "DDERR_NOSTRETCHHW";
- case DDERR_NOT4BITCOLOR:
- return "DDERR_NOT4BITCOLOR";
- case DDERR_NOT4BITCOLORINDEX:
- return "DDERR_NOT4BITCOLORINDEX";
- case DDERR_NOT8BITCOLOR:
- return "DDERR_NOT8BITCOLOR";
- case DDERR_NOTEXTUREHW:
- return "DDERR_NOTEXTUREHW";
- case DDERR_NOVSYNCHW:
- return "DDERR_NOVSYNCHW";
- case DDERR_NOZBUFFERHW:
- return "DDERR_NOZBUFFERHW";
- case DDERR_NOZOVERLAYHW:
- return "DDERR_NOZOVERLAYHW";
- case DDERR_OUTOFCAPS:
- return "DDERR_OUTOFCAPS";
- case DDERR_OUTOFMEMORY:
- return "DDERR_OUTOFMEMORY";
- case DDERR_OUTOFVIDEOMEMORY:
- return "DDERR_OUTOFVIDEOMEMORY";
- case DDERR_OVERLAYCANTCLIP:
- return "DDERR_OVERLAYCANTCLIP";
- case DDERR_OVERLAYCOLORKEYONLYONEACTIVE:
- return "DDERR_OVERLAYCOLORKEYONLYONEACTIVE";
- case DDERR_PALETTEBUSY:
- return "DDERR_PALETTEBUSY";
- case DDERR_COLORKEYNOTSET:
- return "DDERR_COLORKEYNOTSET";
- case DDERR_SURFACEALREADYATTACHED:
- return "DDERR_SURFACEALREADYATTACHED";
- case DDERR_SURFACEALREADYDEPENDENT:
- return "DDERR_SURFACEALREADYDEPENDENT";
- case DDERR_SURFACEBUSY:
- return "DDERR_SURFACEBUSY";
- case DDERR_CANTLOCKSURFACE:
- return "DDERR_CANTLOCKSURFACE";
- case DDERR_SURFACEISOBSCURED:
- return "DDERR_SURFACEISOBSCURED";
- case DDERR_SURFACELOST:
- return "DDERR_SURFACELOST";
- case DDERR_SURFACENOTATTACHED:
- return "DDERR_SURFACENOTATTACHED";
- case DDERR_TOOBIGHEIGHT:
- return "DDERR_TOOBIGHEIGHT";
- case DDERR_TOOBIGSIZE:
- return "DDERR_TOOBIGSIZE";
- case DDERR_TOOBIGWIDTH:
- return "DDERR_TOOBIGWIDTH";
- case DDERR_UNSUPPORTED:
- return "DDERR_UNSUPPORTED";
- case DDERR_UNSUPPORTEDFORMAT:
- return "DDERR_UNSUPPORTEDFORMAT";
- case DDERR_UNSUPPORTEDMASK:
- return "DDERR_UNSUPPORTEDMASK";
- case DDERR_VERTICALBLANKINPROGRESS:
- return "DDERR_VERTICALBLANKINPROGRESS";
- case DDERR_WASSTILLDRAWING:
- return "DDERR_WASSTILLDRAWING";
- case DDERR_XALIGN:
- return "DDERR_XALIGN";
- case DDERR_INVALIDDIRECTDRAWGUID:
- return "DDERR_INVALIDDIRECTDRAWGUID";
- case DDERR_DIRECTDRAWALREADYCREATED:
- return "DDERR_DIRECTDRAWALREADYCREATED";
- case DDERR_NODIRECTDRAWHW:
- return "DDERR_NODIRECTDRAWHW";
- case DDERR_PRIMARYSURFACEALREADYEXISTS:
- return "DDERR_PRIMARYSURFACEALREADYEXISTS";
- case DDERR_NOEMULATION:
- return "DDERR_NOEMULATION";
- case DDERR_REGIONTOOSMALL:
- return "DDERR_REGIONTOOSMALL";
- case DDERR_CLIPPERISUSINGHWND:
- return "DDERR_CLIPPERISUSINGHWND";
- case DDERR_NOCLIPPERATTACHED:
- return "DDERR_NOCLIPPERATTACHED";
- case DDERR_NOHWND:
- return "DDERR_NOHWND";
- case DDERR_HWNDSUBCLASSED:
- return "DDERR_HWNDSUBCLASSED";
- case DDERR_HWNDALREADYSET:
- return "DDERR_HWNDALREADYSET";
- case DDERR_NOPALETTEATTACHED:
- return "DDERR_NOPALETTEATTACHED";
- case DDERR_NOPALETTEHW:
- return "DDERR_NOPALETTEHW";
- case DDERR_BLTFASTCANTCLIP:
- return "DDERR_BLTFASTCANTCLIP";
- case DDERR_NOBLTHW:
- return "DDERR_NOBLTHW";
- case DDERR_NODDROPSHW:
- return "DDERR_NODDROPSHW";
- case DDERR_OVERLAYNOTVISIBLE:
- return "DDERR_OVERLAYNOTVISIBLE";
- case DDERR_NOOVERLAYDEST:
- return "DDERR_NOOVERLAYDEST";
- case DDERR_INVALIDPOSITION:
- return "DDERR_INVALIDPOSITION";
- case DDERR_NOTAOVERLAYSURFACE:
- return "DDERR_NOTAOVERLAYSURFACE";
- case DDERR_EXCLUSIVEMODEALREADYSET:
- return "DDERR_EXCLUSIVEMODEALREADYSET";
- case DDERR_NOTFLIPPABLE:
- return "DDERR_NOTFLIPPABLE";
- case DDERR_CANTDUPLICATE:
- return "DDERR_CANTDUPLICATE";
- case DDERR_NOTLOCKED:
- return "DDERR_NOTLOCKED";
- case DDERR_CANTCREATEDC:
- return "DDERR_CANTCREATEDC";
- case DDERR_NODC:
- return "DDERR_NODC";
- case DDERR_WRONGMODE:
- return "DDERR_WRONGMODE";
- case DDERR_IMPLICITLYCREATED:
- return "DDERR_IMPLICITLYCREATED";
- case DDERR_NOTPALETTIZED:
- return "DDERR_NOTPALETTIZED";
- case DDERR_UNSUPPORTEDMODE:
- return "DDERR_UNSUPPORTEDMODE";
- case DDERR_NOMIPMAPHW:
- return "DDERR_NOMIPMAPHW";
- case DDERR_INVALIDSURFACETYPE:
- return "DDERR_INVALIDSURFACETYPE";
- case DDERR_DCALREADYCREATED:
- return "DDERR_DCALREADYCREATED";
- case DDERR_CANTPAGELOCK:
- return "DDERR_CANTPAGELOCK";
- case DDERR_CANTPAGEUNLOCK:
- return "DDERR_CANTPAGEUNLOCK";
- case DDERR_NOTPAGELOCKED:
- return "DDERR_NOTPAGELOCKED";
- case DDERR_NOTINITIALIZED:
- return "DDERR_NOTINITIALIZED";
- }
- return "Unknown Error";
-}
-
/* Subclass of GstBuffer which manages buffer_pool surfaces lifetime */
static void gst_ddrawsurface_finalize (GstDDrawSurface * surface);
@@ -574,7 +264,8 @@ gst_ddrawsurface_finalize (GstDDrawSurface * surface)
if ((surface->width != ddrawsink->video_width) ||
(surface->height != ddrawsink->video_height) ||
(memcmp (&surface->dd_pixel_format, &ddrawsink->dd_pixel_format,
- sizeof (DDPIXELFORMAT)) != 0)
+ sizeof (DDPIXELFORMAT)) != 0 ||
+ !gst_directdraw_sink_surface_check (ddrawsink, surface))
) {
GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
"destroy image as its size changed %dx%d vs current %dx%d",
@@ -724,6 +415,8 @@ gst_directdraw_sink_init (GstDirectDrawSink * ddrawsink,
ddrawsink->buffer_pool = NULL;
ddrawsink->keep_aspect_ratio = FALSE;
ddrawsink->pool_lock = g_mutex_new ();
+ ddrawsink->can_blit_between_colorspace = TRUE;
+ ddrawsink->must_recreate_offscreen = FALSE;
memset (&ddrawsink->dd_pixel_format, 0, sizeof (DDPIXELFORMAT));
/*video default values */
@@ -794,7 +487,7 @@ gst_directdraw_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
}
/* create an offscreen surface with the caps */
- ret = gst_directdraw_sink_create_ddraw_surface (ddrawsink);
+ ret = gst_directdraw_sink_check_offscreen_surface (ddrawsink);
if (!ret) {
GST_ELEMENT_ERROR (ddrawsink, CORE, NEGOTIATION,
("Can't create a directdraw offscreen surface with the input caps"),
@@ -851,13 +544,13 @@ gst_directdraw_sink_buffer_alloc (GstBaseSink * bsink, guint64 offset,
{
GstDirectDrawSink *ddrawsink = GST_DIRECTDRAW_SINK (bsink);
GstDDrawSurface *surface = NULL;
- GstStructure *structure = NULL;
GstFlowReturn ret = GST_FLOW_OK;
+ GstCaps *buffer_caps = caps;
+ gboolean buffercaps_unref = FALSE;
GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
"a buffer of %d bytes was requested", size);
- structure = gst_caps_get_structure (caps, 0);
g_mutex_lock (ddrawsink->pool_lock);
/* Inspect our buffer pool */
@@ -872,7 +565,8 @@ gst_directdraw_sink_buffer_alloc (GstBaseSink * bsink, guint64 offset,
if ((surface->width != ddrawsink->video_width) ||
(surface->height != ddrawsink->video_height) ||
(memcmp (&surface->dd_pixel_format, &ddrawsink->dd_pixel_format,
- sizeof (DDPIXELFORMAT)))
+ sizeof (DDPIXELFORMAT)) ||
+ !gst_directdraw_sink_surface_check (ddrawsink, surface))
) {
gst_directdraw_sink_surface_destroy (ddrawsink, surface);
surface = NULL;
@@ -883,20 +577,111 @@ gst_directdraw_sink_buffer_alloc (GstBaseSink * bsink, guint64 offset,
}
}
+ if (!ddrawsink->can_blit_between_colorspace) {
+ /* Hardware doesn't support blit from one colorspace to another.
+ * Check if the colorspace of the current display mode has changed since
+ * the last negociation. If it's the case, we will have to renegociate
+ */
+ guint depth;
+ HRESULT hres;
+ DDSURFACEDESC2 surface_desc;
+ GstStructure *structure = NULL;
+
+ structure = gst_caps_get_structure (caps, 0);
+ if (!gst_structure_get_int (structure, "depth", &depth)) {
+ GST_CAT_DEBUG_OBJECT (directdrawsink_debug, ddrawsink,
+ "Can't get depth from buffer_alloc caps");
+ return GST_FLOW_ERROR;
+ }
+ surface_desc.dwSize = sizeof (DDSURFACEDESC);
+ hres = IDirectDraw7_GetDisplayMode (ddrawsink->ddraw_object, &surface_desc);
+ if (hres != DD_OK) {
+ GST_CAT_DEBUG_OBJECT (directdrawsink_debug, ddrawsink,
+ "Can't get current display mode (error=%d)", hres);
+ return GST_FLOW_ERROR;
+ }
+
+ if (depth != gst_directdraw_sink_get_depth (&surface_desc.ddpfPixelFormat)) {
+ GstCaps *copy_caps = NULL;
+ GstStructure *copy_structure = NULL;
+ GstCaps *display_caps = NULL;
+ GstStructure *display_structure = NULL;
+
+ /* make a copy of the original caps */
+ copy_caps = gst_caps_copy (caps);
+ copy_structure = gst_caps_get_structure (copy_caps, 0);
+
+ display_caps =
+ gst_directdraw_sink_create_caps_from_surfacedesc (&surface_desc);
+ if (display_caps) {
+ display_structure = gst_caps_get_structure (display_caps, 0);
+ if (display_structure) {
+ gint bpp, endianness, red_mask, green_mask, blue_mask;
+
+ /* get new display mode properties */
+ gst_structure_get_int (display_structure, "depth", &depth);
+ gst_structure_get_int (display_structure, "bpp", &bpp);
+ gst_structure_get_int (display_structure, "endianness", &endianness);
+ gst_structure_get_int (display_structure, "red_mask", &red_mask);
+ gst_structure_get_int (display_structure, "green_mask", &green_mask);
+ gst_structure_get_int (display_structure, "blue_mask", &blue_mask);
+
+ /* apply the new display mode changes to the previous caps */
+ gst_structure_set (copy_structure,
+ "bpp", G_TYPE_INT, bpp,
+ "depth", G_TYPE_INT, depth,
+ "endianness", G_TYPE_INT, endianness,
+ "red_mask", G_TYPE_INT, red_mask,
+ "green_mask", G_TYPE_INT, green_mask,
+ "blue_mask", G_TYPE_INT, blue_mask, NULL);
+
+ if (gst_pad_peer_accept_caps (GST_VIDEO_SINK_PAD (ddrawsink),
+ copy_caps)) {
+ buffer_caps = copy_caps;
+ buffercaps_unref = TRUE;
+ /* update buffer size needed to store video frames according to new caps */
+ size = ddrawsink->video_width * ddrawsink->video_height * (bpp / 8);
+
+ /* update our member pixel format */
+ gst_ddrawvideosink_get_format_from_caps (ddrawsink, buffer_caps,
+ &ddrawsink->dd_pixel_format);
+ ddrawsink->must_recreate_offscreen = TRUE;
+
+ GST_CAT_DEBUG_OBJECT (directdrawsink_debug, ddrawsink,
+ " desired caps %s \n\n new caps %s", gst_caps_to_string (caps),
+ gst_caps_to_string (buffer_caps));
+ } else {
+ GST_CAT_DEBUG_OBJECT (directdrawsink_debug, ddrawsink,
+ "peer refused caps re-negociation "
+ "and we can't render with the current caps.");
+ ret = GST_FLOW_ERROR;
+ }
+ }
+ gst_caps_unref (display_caps);
+ }
+
+ if (!buffercaps_unref)
+ gst_caps_unref (copy_caps);
+ }
+ }
+
/* We haven't found anything, creating a new one */
if (!surface) {
- surface = gst_directdraw_sink_surface_create (ddrawsink, caps, size);
+ surface = gst_directdraw_sink_surface_create (ddrawsink, buffer_caps, size);
}
/* Now we should have a surface, set appropriate caps on it */
if (surface) {
- gst_buffer_set_caps (GST_BUFFER (surface), caps);
+ gst_buffer_set_caps (GST_BUFFER (surface), buffer_caps);
}
g_mutex_unlock (ddrawsink->pool_lock);
*buf = GST_BUFFER (surface);
+ if (buffercaps_unref)
+ gst_caps_unref (buffer_caps);
+
return ret;
}
@@ -912,13 +697,9 @@ gst_directdraw_sink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
/* save a reference to the input buffer */
if (ddrawsink->last_buffer != buf) {
if (ddrawsink->last_buffer) {
- GST_CAT_LOG_OBJECT (directdrawsink_debug, ddrawsink, "unreffing %p",
- ddrawsink->last_buffer);
gst_buffer_unref (ddrawsink->last_buffer);
}
}
- GST_CAT_LOG_OBJECT (directdrawsink_debug, ddrawsink,
- "reffing %p as our current buffer", buf);
ddrawsink->last_buffer = gst_buffer_ref (buf);
} else {
/* use last buffer */
@@ -944,6 +725,17 @@ gst_directdraw_sink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
&destsurf_rect);
}
+ if (ddrawsink->must_recreate_offscreen && ddrawsink->offscreen_surface) {
+ IDirectDrawSurface7_Release (ddrawsink->offscreen_surface);
+ ddrawsink->offscreen_surface = NULL;
+ }
+
+ /* check for surfaces lost */
+ if (!gst_directdraw_sink_check_primary_surface (ddrawsink) ||
+ !gst_directdraw_sink_check_offscreen_surface (ddrawsink)) {
+ return GST_FLOW_ERROR;
+ }
+
if (!GST_IS_DDRAWSURFACE (buf) ||
((GST_IS_DDRAWSURFACE (buf)) && (GST_BUFFER (buf)->malloc_data))) {
/* We are receiving a system memory buffer so we will copy
@@ -956,12 +748,6 @@ gst_directdraw_sink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
ZeroMemory (&surf_desc, sizeof (surf_desc));
surf_desc.dwSize = sizeof (surf_desc);
- /* Check for lost surface */
- if (IDirectDrawSurface7_IsLost (ddrawsink->offscreen_surface) ==
- DDERR_SURFACELOST) {
- IDirectDrawSurface7_Restore (ddrawsink->offscreen_surface);
- }
-
/* Lock the surface */
hRes =
IDirectDrawSurface7_Lock (ddrawsink->offscreen_surface, NULL,
@@ -1009,11 +795,6 @@ gst_directdraw_sink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
IDirectDrawSurface7_Unlock (surface->surface, NULL);
surface->locked = FALSE;
- /* Check for lost surfaces */
- if (IDirectDrawSurface7_IsLost (surface->surface) == DDERR_SURFACELOST) {
- IDirectDrawSurface7_Restore (surface->surface);
- }
-
/* blit to our primary surface */
hRes = IDirectDrawSurface7_Blt (ddrawsink->primary_surface, &destsurf_rect,
surface->surface, NULL, DDBLT_WAIT, NULL);
@@ -1026,12 +807,352 @@ gst_directdraw_sink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
return GST_FLOW_OK;
}
+static void
+gst_directdraw_sink_get_times (GstBaseSink * bsink, GstBuffer * buf,
+ GstClockTime * start, GstClockTime * end)
+{
+ GstDirectDrawSink *ddrawsink;
+
+ ddrawsink = GST_DIRECTDRAW_SINK (bsink);
+
+ if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
+ *start = GST_BUFFER_TIMESTAMP (buf);
+ if (GST_BUFFER_DURATION_IS_VALID (buf)) {
+ *end = *start + GST_BUFFER_DURATION (buf);
+ } else {
+ if (ddrawsink->fps_n > 0) {
+ *end = *start + (GST_SECOND * ddrawsink->fps_d) / ddrawsink->fps_n;
+ }
+ }
+ }
+}
+
+/* Utility functions */
+
+/* this function fill a DDPIXELFORMAT using Gstreamer caps */
+static gboolean
+gst_ddrawvideosink_get_format_from_caps (GstDirectDrawSink * ddrawsink,
+ GstCaps * caps, DDPIXELFORMAT * pPixelFormat)
+{
+ GstStructure *structure = NULL;
+ gboolean ret = TRUE;
+
+ /* check params */
+ g_return_val_if_fail (pPixelFormat, FALSE);
+ g_return_val_if_fail (caps, FALSE);
+
+ /* init structure */
+ memset (pPixelFormat, 0, sizeof (DDPIXELFORMAT));
+ pPixelFormat->dwSize = sizeof (DDPIXELFORMAT);
+
+ if (!(structure = gst_caps_get_structure (caps, 0))) {
+ GST_CAT_ERROR_OBJECT (directdrawsink_debug, ddrawsink,
+ "can't get structure pointer from caps");
+ return FALSE;
+ }
+
+ if (gst_structure_has_name (structure, "video/x-raw-rgb")) {
+ gint depth, bitcount, bitmask, endianness;
+
+ pPixelFormat->dwFlags = DDPF_RGB;
+ ret &= gst_structure_get_int (structure, "bpp", &bitcount);
+ pPixelFormat->dwRGBBitCount = bitcount;
+ ret &= gst_structure_get_int (structure, "depth", &depth);
+ ret &= gst_structure_get_int (structure, "red_mask", &bitmask);
+ pPixelFormat->dwRBitMask = bitmask;
+ ret &= gst_structure_get_int (structure, "green_mask", &bitmask);
+ pPixelFormat->dwGBitMask = bitmask;
+ ret &= gst_structure_get_int (structure, "blue_mask", &bitmask);
+ pPixelFormat->dwBBitMask = bitmask;
+
+ gst_structure_get_int (structure, "endianness", &endianness);
+ if (endianness == G_BIG_ENDIAN) {
+ endianness = G_LITTLE_ENDIAN;
+ pPixelFormat->dwRBitMask = GUINT32_TO_BE (pPixelFormat->dwRBitMask);
+ pPixelFormat->dwGBitMask = GUINT32_TO_BE (pPixelFormat->dwGBitMask);
+ pPixelFormat->dwBBitMask = GUINT32_TO_BE (pPixelFormat->dwBBitMask);
+ }
+ } else if (gst_structure_has_name (structure, "video/x-raw-yuv")) {
+ gint fourcc;
+
+ pPixelFormat->dwFlags = DDPF_FOURCC;
+ ret &= gst_structure_get_fourcc (structure, "format", &fourcc);
+ pPixelFormat->dwFourCC = fourcc;
+ } else {
+ GST_CAT_WARNING_OBJECT (directdrawsink_debug, ddrawsink,
+ "unknown caps name received %" GST_PTR_FORMAT, caps);
+ ret = FALSE;
+ }
+
+ return ret;
+}
+
+/* This function centers the RECT of source surface to
+a dest surface and set the result RECT into result */
+static void
+gst_directdraw_sink_center_rect (GstDirectDrawSink * ddrawsink, RECT src,
+ RECT dst, RECT * result)
+{
+ gdouble src_ratio, dst_ratio;
+ long src_width = src.right;
+ long src_height = src.bottom;
+ long dst_width = dst.right - dst.left;
+ long dst_heigth = dst.bottom - dst.top;
+ long result_width = 0, result_height = 0;
+
+ g_return_if_fail (result != NULL);
+
+ src_ratio = (gdouble) src_width / src_height;
+ dst_ratio = (gdouble) dst_width / dst_heigth;
+
+ if (src_ratio > dst_ratio) {
+ /* new height */
+ result_height = (long) (dst_width / src_ratio);
+
+ result->left = dst.left;
+ result->right = dst.right;
+ result->top = dst.top + (dst_heigth - result_height) / 2;
+ result->bottom = result->top + result_height;
+
+ } else if (src_ratio < dst_ratio) {
+ /* new width */
+ result_width = (long) (dst_heigth * src_ratio);
+
+ result->top = dst.top;
+ result->bottom = dst.bottom;
+ result->left = dst.left + (dst_width - result_width) / 2;
+ result->right = result->left + result_width;
+
+ } else {
+ /* same ratio */
+ memcpy (result, &dst, sizeof (RECT));
+ }
+
+ GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
+ "source is %ldx%ld dest is %ldx%ld, result is %ldx%ld with x,y %ldx%ld",
+ src_width, src_height, dst_width, dst_heigth,
+ result->right - result->left, result->bottom - result->top, result->left,
+ result->right);
+}
+
+/**
+ * Get DirectDraw error message.
+ * @hr: HRESULT code
+ * Returns: Text representation of the error.
+ */
+char *
+DDErrorString (HRESULT hr)
+{
+ switch (hr) {
+ case DDERR_ALREADYINITIALIZED:
+ return "DDERR_ALREADYINITIALIZED";
+ case DDERR_CANNOTATTACHSURFACE:
+ return "DDERR_CANNOTATTACHSURFACE";
+ case DDERR_CANNOTDETACHSURFACE:
+ return "DDERR_CANNOTDETACHSURFACE";
+ case DDERR_CURRENTLYNOTAVAIL:
+ return "DDERR_CURRENTLYNOTAVAIL";
+ case DDERR_EXCEPTION:
+ return "DDERR_EXCEPTION";
+ case DDERR_GENERIC:
+ return "DDERR_GENERIC";
+ case DDERR_HEIGHTALIGN:
+ return "DDERR_HEIGHTALIGN";
+ case DDERR_INCOMPATIBLEPRIMARY:
+ return "DDERR_INCOMPATIBLEPRIMARY";
+ case DDERR_INVALIDCAPS:
+ return "DDERR_INVALIDCAPS";
+ case DDERR_INVALIDCLIPLIST:
+ return "DDERR_INVALIDCLIPLIST";
+ case DDERR_INVALIDMODE:
+ return "DDERR_INVALIDMODE";
+ case DDERR_INVALIDOBJECT:
+ return "DDERR_INVALIDOBJECT";
+ case DDERR_INVALIDPARAMS:
+ return "DDERR_INVALIDPARAMS";
+ case DDERR_INVALIDPIXELFORMAT:
+ return "DDERR_INVALIDPIXELFORMAT";
+ case DDERR_INVALIDRECT:
+ return "DDERR_INVALIDRECT";
+ case DDERR_LOCKEDSURFACES:
+ return "DDERR_LOCKEDSURFACES";
+ case DDERR_NO3D:
+ return "DDERR_NO3D";
+ case DDERR_NOALPHAHW:
+ return "DDERR_NOALPHAHW";
+ case DDERR_NOCLIPLIST:
+ return "DDERR_NOCLIPLIST";
+ case DDERR_NOCOLORCONVHW:
+ return "DDERR_NOCOLORCONVHW";
+ case DDERR_NOCOOPERATIVELEVELSET:
+ return "DDERR_NOCOOPERATIVELEVELSET";
+ case DDERR_NOCOLORKEY:
+ return "DDERR_NOCOLORKEY";
+ case DDERR_NOCOLORKEYHW:
+ return "DDERR_NOCOLORKEYHW";
+ case DDERR_NODIRECTDRAWSUPPORT:
+ return "DDERR_NODIRECTDRAWSUPPORT";
+ case DDERR_NOEXCLUSIVEMODE:
+ return "DDERR_NOEXCLUSIVEMODE";
+ case DDERR_NOFLIPHW:
+ return "DDERR_NOFLIPHW";
+ case DDERR_NOGDI:
+ return "DDERR_NOGDI";
+ case DDERR_NOMIRRORHW:
+ return "DDERR_NOMIRRORHW";
+ case DDERR_NOTFOUND:
+ return "DDERR_NOTFOUND";
+ case DDERR_NOOVERLAYHW:
+ return "DDERR_NOOVERLAYHW";
+ case DDERR_NORASTEROPHW:
+ return "DDERR_NORASTEROPHW";
+ case DDERR_NOROTATIONHW:
+ return "DDERR_NOROTATIONHW";
+ case DDERR_NOSTRETCHHW:
+ return "DDERR_NOSTRETCHHW";
+ case DDERR_NOT4BITCOLOR:
+ return "DDERR_NOT4BITCOLOR";
+ case DDERR_NOT4BITCOLORINDEX:
+ return "DDERR_NOT4BITCOLORINDEX";
+ case DDERR_NOT8BITCOLOR:
+ return "DDERR_NOT8BITCOLOR";
+ case DDERR_NOTEXTUREHW:
+ return "DDERR_NOTEXTUREHW";
+ case DDERR_NOVSYNCHW:
+ return "DDERR_NOVSYNCHW";
+ case DDERR_NOZBUFFERHW:
+ return "DDERR_NOZBUFFERHW";
+ case DDERR_NOZOVERLAYHW:
+ return "DDERR_NOZOVERLAYHW";
+ case DDERR_OUTOFCAPS:
+ return "DDERR_OUTOFCAPS";
+ case DDERR_OUTOFMEMORY:
+ return "DDERR_OUTOFMEMORY";
+ case DDERR_OUTOFVIDEOMEMORY:
+ return "DDERR_OUTOFVIDEOMEMORY";
+ case DDERR_OVERLAYCANTCLIP:
+ return "DDERR_OVERLAYCANTCLIP";
+ case DDERR_OVERLAYCOLORKEYONLYONEACTIVE:
+ return "DDERR_OVERLAYCOLORKEYONLYONEACTIVE";
+ case DDERR_PALETTEBUSY:
+ return "DDERR_PALETTEBUSY";
+ case DDERR_COLORKEYNOTSET:
+ return "DDERR_COLORKEYNOTSET";
+ case DDERR_SURFACEALREADYATTACHED:
+ return "DDERR_SURFACEALREADYATTACHED";
+ case DDERR_SURFACEALREADYDEPENDENT:
+ return "DDERR_SURFACEALREADYDEPENDENT";
+ case DDERR_SURFACEBUSY:
+ return "DDERR_SURFACEBUSY";
+ case DDERR_CANTLOCKSURFACE:
+ return "DDERR_CANTLOCKSURFACE";
+ case DDERR_SURFACEISOBSCURED:
+ return "DDERR_SURFACEISOBSCURED";
+ case DDERR_SURFACELOST:
+ return "DDERR_SURFACELOST";
+ case DDERR_SURFACENOTATTACHED:
+ return "DDERR_SURFACENOTATTACHED";
+ case DDERR_TOOBIGHEIGHT:
+ return "DDERR_TOOBIGHEIGHT";
+ case DDERR_TOOBIGSIZE:
+ return "DDERR_TOOBIGSIZE";
+ case DDERR_TOOBIGWIDTH:
+ return "DDERR_TOOBIGWIDTH";
+ case DDERR_UNSUPPORTED:
+ return "DDERR_UNSUPPORTED";
+ case DDERR_UNSUPPORTEDFORMAT:
+ return "DDERR_UNSUPPORTEDFORMAT";
+ case DDERR_UNSUPPORTEDMASK:
+ return "DDERR_UNSUPPORTEDMASK";
+ case DDERR_VERTICALBLANKINPROGRESS:
+ return "DDERR_VERTICALBLANKINPROGRESS";
+ case DDERR_WASSTILLDRAWING:
+ return "DDERR_WASSTILLDRAWING";
+ case DDERR_XALIGN:
+ return "DDERR_XALIGN";
+ case DDERR_INVALIDDIRECTDRAWGUID:
+ return "DDERR_INVALIDDIRECTDRAWGUID";
+ case DDERR_DIRECTDRAWALREADYCREATED:
+ return "DDERR_DIRECTDRAWALREADYCREATED";
+ case DDERR_NODIRECTDRAWHW:
+ return "DDERR_NODIRECTDRAWHW";
+ case DDERR_PRIMARYSURFACEALREADYEXISTS:
+ return "DDERR_PRIMARYSURFACEALREADYEXISTS";
+ case DDERR_NOEMULATION:
+ return "DDERR_NOEMULATION";
+ case DDERR_REGIONTOOSMALL:
+ return "DDERR_REGIONTOOSMALL";
+ case DDERR_CLIPPERISUSINGHWND:
+ return "DDERR_CLIPPERISUSINGHWND";
+ case DDERR_NOCLIPPERATTACHED:
+ return "DDERR_NOCLIPPERATTACHED";
+ case DDERR_NOHWND:
+ return "DDERR_NOHWND";
+ case DDERR_HWNDSUBCLASSED:
+ return "DDERR_HWNDSUBCLASSED";
+ case DDERR_HWNDALREADYSET:
+ return "DDERR_HWNDALREADYSET";
+ case DDERR_NOPALETTEATTACHED:
+ return "DDERR_NOPALETTEATTACHED";
+ case DDERR_NOPALETTEHW:
+ return "DDERR_NOPALETTEHW";
+ case DDERR_BLTFASTCANTCLIP:
+ return "DDERR_BLTFASTCANTCLIP";
+ case DDERR_NOBLTHW:
+ return "DDERR_NOBLTHW";
+ case DDERR_NODDROPSHW:
+ return "DDERR_NODDROPSHW";
+ case DDERR_OVERLAYNOTVISIBLE:
+ return "DDERR_OVERLAYNOTVISIBLE";
+ case DDERR_NOOVERLAYDEST:
+ return "DDERR_NOOVERLAYDEST";
+ case DDERR_INVALIDPOSITION:
+ return "DDERR_INVALIDPOSITION";
+ case DDERR_NOTAOVERLAYSURFACE:
+ return "DDERR_NOTAOVERLAYSURFACE";
+ case DDERR_EXCLUSIVEMODEALREADYSET:
+ return "DDERR_EXCLUSIVEMODEALREADYSET";
+ case DDERR_NOTFLIPPABLE:
+ return "DDERR_NOTFLIPPABLE";
+ case DDERR_CANTDUPLICATE:
+ return "DDERR_CANTDUPLICATE";
+ case DDERR_NOTLOCKED:
+ return "DDERR_NOTLOCKED";
+ case DDERR_CANTCREATEDC:
+ return "DDERR_CANTCREATEDC";
+ case DDERR_NODC:
+ return "DDERR_NODC";
+ case DDERR_WRONGMODE:
+ return "DDERR_WRONGMODE";
+ case DDERR_IMPLICITLYCREATED:
+ return "DDERR_IMPLICITLYCREATED";
+ case DDERR_NOTPALETTIZED:
+ return "DDERR_NOTPALETTIZED";
+ case DDERR_UNSUPPORTEDMODE:
+ return "DDERR_UNSUPPORTEDMODE";
+ case DDERR_NOMIPMAPHW:
+ return "DDERR_NOMIPMAPHW";
+ case DDERR_INVALIDSURFACETYPE:
+ return "DDERR_INVALIDSURFACETYPE";
+ case DDERR_DCALREADYCREATED:
+ return "DDERR_DCALREADYCREATED";
+ case DDERR_CANTPAGELOCK:
+ return "DDERR_CANTPAGELOCK";
+ case DDERR_CANTPAGEUNLOCK:
+ return "DDERR_CANTPAGEUNLOCK";
+ case DDERR_NOTPAGELOCKED:
+ return "DDERR_NOTPAGELOCKED";
+ case DDERR_NOTINITIALIZED:
+ return "DDERR_NOTINITIALIZED";
+ }
+ return "Unknown Error";
+}
+
static gboolean
gst_directdraw_sink_setup_ddraw (GstDirectDrawSink * ddrawsink)
{
gboolean bRet = TRUE;
HRESULT hRes;
- DDSURFACEDESC2 dd_surface_desc;
/* create an instance of the ddraw object use DDCREATE_EMULATIONONLY as first parameter to
force Directdraw to use the hardware emulation layer */
@@ -1054,30 +1175,18 @@ gst_directdraw_sink_setup_ddraw (GstDirectDrawSink * ddrawsink)
return FALSE;
}
- /*create our primary surface */
- memset (&dd_surface_desc, 0, sizeof (dd_surface_desc));
- dd_surface_desc.dwSize = sizeof (dd_surface_desc);
- dd_surface_desc.dwFlags = DDSD_CAPS;
- dd_surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
- hRes = IDirectDraw7_CreateSurface (ddrawsink->ddraw_object, &dd_surface_desc,
- &ddrawsink->primary_surface, NULL);
- if (hRes != DD_OK) {
- GST_ELEMENT_ERROR (ddrawsink, RESOURCE, WRITE,
- ("Failed to create our primary surface error=%s", DDErrorString (hRes)),
- (NULL));
- return FALSE;
- }
-
/* setup the clipper object */
hRes = IDirectDraw7_CreateClipper (ddrawsink->ddraw_object, 0,
&ddrawsink->clipper, NULL);
if (hRes == DD_OK) {
hRes = IDirectDrawClipper_SetHWnd (ddrawsink->clipper, 0,
ddrawsink->video_window);
- hRes = IDirectDrawSurface7_SetClipper (ddrawsink->primary_surface,
- ddrawsink->clipper);
}
+ /* create our primary surface */
+ if (!gst_directdraw_sink_check_primary_surface (ddrawsink))
+ return FALSE;
+
/* directdraw objects are setup */
ddrawsink->setup = TRUE;
@@ -1171,10 +1280,95 @@ failed:
}
static gboolean
-gst_directdraw_sink_create_ddraw_surface (GstDirectDrawSink * ddrawsink)
+gst_directdraw_sink_check_primary_surface (GstDirectDrawSink * ddrawsink)
{
+ HRESULT hres;
DDSURFACEDESC2 dd_surface_desc;
- HRESULT hRes;
+
+ /* if our primary surface already exist, check if it's not lost */
+ if (ddrawsink->primary_surface) {
+ if (IDirectDrawSurface7_IsLost (ddrawsink->primary_surface) == DD_OK) {
+ /* no problem with our primary surface */
+ return TRUE;
+ } else {
+ /* our primary surface was lost, try to restore it */
+ if (IDirectDrawSurface7_Restore (ddrawsink->primary_surface) == DD_OK) {
+ /* restore is done */
+ GST_CAT_LOG_OBJECT (directdrawsink_debug, ddrawsink,
+ "Our primary surface" " was restored after lost");
+ return TRUE;
+ } else {
+ /* failed to restore our primary surface,
+ * probably because the display mode was changed.
+ * Release this surface and recreate a new one.
+ */
+ GST_CAT_LOG_OBJECT (directdrawsink_debug, ddrawsink,
+ "Our primary surface"
+ " was lost and display mode has changed. Destroy and recreate our surface.");
+ IDirectDrawSurface7_Release (ddrawsink->primary_surface);
+ ddrawsink->primary_surface = NULL;
+
+ /* also release offscreen surface */
+ IDirectDrawSurface7_Release (ddrawsink->offscreen_surface);
+ ddrawsink->offscreen_surface = NULL;
+ }
+ }
+ }
+
+ /* create our primary surface */
+ memset (&dd_surface_desc, 0, sizeof (dd_surface_desc));
+ dd_surface_desc.dwSize = sizeof (dd_surface_desc);
+ dd_surface_desc.dwFlags = DDSD_CAPS;
+ dd_surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
+ hres = IDirectDraw7_CreateSurface (ddrawsink->ddraw_object, &dd_surface_desc,
+ &ddrawsink->primary_surface, NULL);
+ if (hres != DD_OK) {
+ GST_ELEMENT_ERROR (ddrawsink, RESOURCE, WRITE,
+ ("Failed to create our primary surface error=%s", DDErrorString (hres)),
+ (NULL));
+ return FALSE;
+ }
+
+ /* attach our clipper object to the new primary surface */
+ if (ddrawsink->clipper) {
+ hres = IDirectDrawSurface7_SetClipper (ddrawsink->primary_surface,
+ ddrawsink->clipper);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+gst_directdraw_sink_check_offscreen_surface (GstDirectDrawSink * ddrawsink)
+{
+ DDSURFACEDESC2 dd_surface_desc;
+ HRESULT hres;
+
+ /* if our offscreen surface already exist, check if it's not lost */
+ if (ddrawsink->offscreen_surface) {
+ if (IDirectDrawSurface7_IsLost (ddrawsink->offscreen_surface) == DD_OK) {
+ /* no problem with our offscreen surface */
+ return TRUE;
+ } else {
+ /* our offscreen surface was lost, try to restore it */
+ if (IDirectDrawSurface7_Restore (ddrawsink->offscreen_surface) == DD_OK) {
+ /* restore is done */
+ GST_CAT_LOG_OBJECT (directdrawsink_debug, ddrawsink,
+ "Our offscreen surface" " was restored after lost");
+ return TRUE;
+ } else {
+ /* failed to restore our offscreen surface,
+ * probably because the display mode was changed.
+ * Release this surface and recreate a new one.
+ */
+ GST_CAT_LOG_OBJECT (directdrawsink_debug, ddrawsink,
+ "Our offscreen surface"
+ " was lost and display mode has changed. Destroy and recreate our surface.");
+ IDirectDrawSurface7_Release (ddrawsink->offscreen_surface);
+ ddrawsink->offscreen_surface = NULL;
+ }
+ }
+ }
memset (&dd_surface_desc, 0, sizeof (dd_surface_desc));
dd_surface_desc.dwSize = sizeof (dd_surface_desc);
@@ -1185,38 +1379,19 @@ gst_directdraw_sink_create_ddraw_surface (GstDirectDrawSink * ddrawsink)
memcpy (&(dd_surface_desc.ddpfPixelFormat), &ddrawsink->dd_pixel_format,
sizeof (DDPIXELFORMAT));
- dd_surface_desc.ddsCaps.dwCaps =
- DDSCAPS_OFFSCREENPLAIN /*|DDSCAPS_SYSTEMMEMORY */ ;
- hRes =
- IDirectDraw7_CreateSurface (ddrawsink->ddraw_object, &dd_surface_desc,
+ dd_surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+ hres = IDirectDraw7_CreateSurface (ddrawsink->ddraw_object, &dd_surface_desc,
&ddrawsink->offscreen_surface, NULL);
- if (hRes != DD_OK) {
+ if (hres != DD_OK) {
GST_CAT_WARNING_OBJECT (directdrawsink_debug, ddrawsink,
"create_ddraw_surface:CreateSurface (offscreen surface for buffer_pool) failed %s",
- DDErrorString (hRes));
+ DDErrorString (hres));
return FALSE;
}
- return TRUE;
-}
-
-static void
-gst_directdraw_sink_get_times (GstBaseSink * bsink, GstBuffer * buf,
- GstClockTime * start, GstClockTime * end)
-{
- GstDirectDrawSink *ddrawsink;
- ddrawsink = GST_DIRECTDRAW_SINK (bsink);
+ ddrawsink->must_recreate_offscreen = FALSE;
- if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
- *start = GST_BUFFER_TIMESTAMP (buf);
- if (GST_BUFFER_DURATION_IS_VALID (buf)) {
- *end = *start + GST_BUFFER_DURATION (buf);
- } else {
- if (ddrawsink->fps_n > 0) {
- *end = *start + (GST_SECOND * ddrawsink->fps_d) / ddrawsink->fps_n;
- }
- }
- }
+ return TRUE;
}
static int
@@ -1254,17 +1429,8 @@ EnumModesCallback2 (LPDDSURFACEDESC2 lpDDSurfaceDesc, LPVOID lpContext)
if ((lpDDSurfaceDesc->ddpfPixelFormat.dwFlags & DDPF_RGB) != DDPF_RGB)
return DDENUMRET_OK;
- format_caps = gst_caps_new_simple ("video/x-raw-rgb",
- "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
- "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
- "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1,
- "bpp", G_TYPE_INT, lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount,
- "depth", G_TYPE_INT,
- gst_directdraw_sink_get_depth (&lpDDSurfaceDesc->ddpfPixelFormat),
- "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, "red_mask", G_TYPE_INT,
- lpDDSurfaceDesc->ddpfPixelFormat.dwRBitMask, "green_mask", G_TYPE_INT,
- lpDDSurfaceDesc->ddpfPixelFormat.dwGBitMask, "blue_mask", G_TYPE_INT,
- lpDDSurfaceDesc->ddpfPixelFormat.dwBBitMask, NULL);
+ format_caps =
+ gst_directdraw_sink_create_caps_from_surfacedesc (lpDDSurfaceDesc);
if (format_caps) {
gst_caps_append (ddrawsink->caps, format_caps);
@@ -1274,6 +1440,49 @@ EnumModesCallback2 (LPDDSURFACEDESC2 lpDDSurfaceDesc, LPVOID lpContext)
}
static GstCaps *
+gst_directdraw_sink_create_caps_from_surfacedesc (LPDDSURFACEDESC2 desc)
+{
+ GstCaps *caps = NULL;
+ gint endianness = G_LITTLE_ENDIAN;
+ gint depth;
+
+ if ((desc->ddpfPixelFormat.dwFlags & DDPF_RGB) != DDPF_RGB)
+ return NULL;
+
+ depth = gst_directdraw_sink_get_depth (&desc->ddpfPixelFormat);
+
+ if (desc->ddpfPixelFormat.dwRGBBitCount == 24 ||
+ desc->ddpfPixelFormat.dwRGBBitCount == 32) {
+ /* ffmpegcolorspace handles 24/32 bpp RGB as big-endian. */
+ endianness = G_BIG_ENDIAN;
+ desc->ddpfPixelFormat.dwRBitMask =
+ GUINT32_TO_BE (desc->ddpfPixelFormat.dwRBitMask);
+ desc->ddpfPixelFormat.dwGBitMask =
+ GUINT32_TO_BE (desc->ddpfPixelFormat.dwGBitMask);
+ desc->ddpfPixelFormat.dwBBitMask =
+ GUINT32_TO_BE (desc->ddpfPixelFormat.dwBBitMask);
+ if (desc->ddpfPixelFormat.dwRGBBitCount == 24) {
+ desc->ddpfPixelFormat.dwRBitMask >>= 8;
+ desc->ddpfPixelFormat.dwGBitMask >>= 8;
+ desc->ddpfPixelFormat.dwBBitMask >>= 8;
+ }
+ }
+
+ caps = gst_caps_new_simple ("video/x-raw-rgb",
+ "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
+ "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
+ "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1,
+ "bpp", G_TYPE_INT, desc->ddpfPixelFormat.dwRGBBitCount,
+ "depth", G_TYPE_INT, depth,
+ "endianness", G_TYPE_INT, endianness,
+ "red_mask", G_TYPE_INT, desc->ddpfPixelFormat.dwRBitMask,
+ "green_mask", G_TYPE_INT, desc->ddpfPixelFormat.dwGBitMask,
+ "blue_mask", G_TYPE_INT, desc->ddpfPixelFormat.dwBBitMask, NULL);
+
+ return caps;
+}
+
+static GstCaps *
gst_directdraw_sink_get_ddrawcaps (GstDirectDrawSink * ddrawsink)
{
HRESULT hRes = S_OK;
@@ -1297,13 +1506,14 @@ gst_directdraw_sink_get_ddrawcaps (GstDirectDrawSink * ddrawsink)
/* we don't test for DDCAPS_BLTSTRETCH on the hardware as the directdraw emulation layer can do it */
if (!(ddcaps_hardware.dwCaps & DDCAPS_BLTFOURCC)) {
DDSURFACEDESC2 surface_desc;
- gint endianness = G_LITTLE_ENDIAN;
- gint depth;
GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink,
"hardware doesn't support blit from one colorspace to another one. "
"so we will create a caps with only the current display mode");
+ /* save blit caps */
+ ddrawsink->can_blit_between_colorspace = FALSE;
+
surface_desc.dwSize = sizeof (DDSURFACEDESC);
hRes = IDirectDraw7_GetDisplayMode (ddrawsink->ddraw_object, &surface_desc);
if (hRes != DD_OK) {
@@ -1313,36 +1523,8 @@ gst_directdraw_sink_get_ddrawcaps (GstDirectDrawSink * ddrawsink)
return NULL;
}
- depth = gst_directdraw_sink_get_depth (&surface_desc.ddpfPixelFormat);
-
- if (surface_desc.ddpfPixelFormat.dwRGBBitCount == 24 ||
- surface_desc.ddpfPixelFormat.dwRGBBitCount == 32) {
- /* ffmpegcolorspace handles 24/32 bpp RGB as big-endian. */
- endianness = G_BIG_ENDIAN;
- surface_desc.ddpfPixelFormat.dwRBitMask =
- GUINT32_TO_BE (surface_desc.ddpfPixelFormat.dwRBitMask);
- surface_desc.ddpfPixelFormat.dwGBitMask =
- GUINT32_TO_BE (surface_desc.ddpfPixelFormat.dwGBitMask);
- surface_desc.ddpfPixelFormat.dwBBitMask =
- GUINT32_TO_BE (surface_desc.ddpfPixelFormat.dwBBitMask);
- if (surface_desc.ddpfPixelFormat.dwRGBBitCount == 24) {
- surface_desc.ddpfPixelFormat.dwRBitMask >>= 8;
- surface_desc.ddpfPixelFormat.dwGBitMask >>= 8;
- surface_desc.ddpfPixelFormat.dwBBitMask >>= 8;
- }
- }
-
- format_caps = gst_caps_new_simple ("video/x-raw-rgb",
- "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
- "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
- "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1,
- "bpp", G_TYPE_INT, surface_desc.ddpfPixelFormat.dwRGBBitCount,
- "depth", G_TYPE_INT, depth,
- "endianness", G_TYPE_INT, endianness,
- "red_mask", G_TYPE_INT, surface_desc.ddpfPixelFormat.dwRBitMask,
- "green_mask", G_TYPE_INT, surface_desc.ddpfPixelFormat.dwGBitMask,
- "blue_mask", G_TYPE_INT, surface_desc.ddpfPixelFormat.dwBBitMask, NULL);
-
+ format_caps =
+ gst_directdraw_sink_create_caps_from_surfacedesc (&surface_desc);
if (format_caps) {
gst_caps_append (ddrawsink->caps, format_caps);
}
@@ -1356,6 +1538,9 @@ gst_directdraw_sink_get_ddrawcaps (GstDirectDrawSink * ddrawsink)
"the hardware can blit from one colorspace to another, "
"then enumerate the colorspace supported by the hardware");
+ /* save blit caps */
+ ddrawsink->can_blit_between_colorspace = TRUE;
+
/* enumerate display modes exposed by directdraw object
to know supported RGB modes */
hRes =
@@ -1376,7 +1561,8 @@ gst_directdraw_sink_get_ddrawcaps (GstDirectDrawSink * ddrawsink)
("No supported caps found."), (NULL));
return NULL;
}
- //GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink, "returning caps %s", gst_caps_to_string (ddrawsink->caps));
+
+ /*GST_CAT_INFO_OBJECT (directdrawsink_debug, ddrawsink, "returning caps %s", gst_caps_to_string (ddrawsink->caps)); */
return ddrawsink->caps;
}
@@ -1418,7 +1604,15 @@ gst_directdraw_sink_surface_create (GstDirectDrawSink * ddrawsink,
"failed getting pixel format from caps %" GST_PTR_FORMAT, caps);
}
- if (ddrawsink->ddraw_object) {
+ /* disable return of directdraw surface to buffer alloc because actually I have no solution
+ * to handle display mode changes. The problem is that when the display mode is changed
+ * surface's memory is freed then the upstream filter would crash trying to write to this memory.
+ * Directdraw has a system lock (DDLOCK_NOSYSLOCK to disable it) to prevent display mode changes
+ * when a surface memory is locked but we need to disable this lock to return multiple buffers (surfaces)
+ * and do not lock directdraw API calls.
+ */
+ if (0) {
+/* if (ddrawsink->ddraw_object) {*/
/* Creating an internal surface which will be used as GstBuffer, we used
the detected pixel format and video dimensions */
@@ -1518,6 +1712,29 @@ no_sink:
return;
}
+static gboolean
+gst_directdraw_sink_surface_check (GstDirectDrawSink * ddrawsink,
+ GstDDrawSurface * surface)
+{
+ if (!surface->surface)
+ return TRUE; /* system memory buffer */
+
+ if (IDirectDrawSurface7_IsLost (surface->surface) == DD_OK) {
+ /* no problem with this surface */
+ return TRUE;
+ } else {
+ /* this surface was lost, try to restore it */
+ if (IDirectDrawSurface7_Restore (ddrawsink->offscreen_surface) == DD_OK) {
+ /* restore is done */
+ GST_CAT_LOG_OBJECT (directdrawsink_debug, ddrawsink, "A surface from our"
+ " bufferpool was restored after lost");
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
static void
gst_directdraw_sink_bufferpool_clear (GstDirectDrawSink * ddrawsink)
{
diff --git a/sys/directdraw/gstdirectdrawsink.h b/sys/directdraw/gstdirectdrawsink.h
index 3bd55dd34..68a2a14b2 100644
--- a/sys/directdraw/gstdirectdrawsink.h
+++ b/sys/directdraw/gstdirectdrawsink.h
@@ -120,6 +120,15 @@ struct _GstDirectDrawSink
/* TRUE when directdraw objects are setup */
gboolean setup;
+
+ /* TRUE if the hardware support blitting from one colorspace to another */
+ gboolean can_blit_between_colorspace;
+
+ /* this flag is used to force re-creation of our offscreen surface
+ * it's need when hardware doesn't support fourcc blit and the bit deph
+ * of the current display mode changes.
+ */
+ gboolean must_recreate_offscreen;
};
struct _GstDirectDrawSinkClass