From bf5c0a89f0078ea886e80eeaaf826003cd515982 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Moutte?= Date: Sun, 11 Mar 2007 22:23:04 +0000 Subject: [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. --- sys/directdraw/gstdirectdrawsink.c | 1137 +++++++++++++++++++++--------------- sys/directdraw/gstdirectdrawsink.h | 9 + 2 files changed, 686 insertions(+), 460 deletions(-) (limited to 'sys/directdraw') 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 @@ * * * - * 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", @@ -165,351 +176,30 @@ gst_directdraw_sink_expose (GstXOverlay * overlay) } static void -gst_directdraw_sink_xoverlay_interface_init (GstXOverlayClass * iface) -{ - iface->set_xwindow_id = gst_directdraw_sink_set_window_id; - iface->expose = gst_directdraw_sink_expose; -} - -static void -gst_directdraw_sink_init_interfaces (GType type) -{ - static const GInterfaceInfo iface_info = { - (GInterfaceInitFunc) gst_directdraw_sink_interface_init, - NULL, - NULL, - }; - - static const GInterfaceInfo xoverlay_info = { - (GInterfaceInitFunc) gst_directdraw_sink_xoverlay_interface_init, - NULL, - NULL, - }; - - g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE, - &iface_info); - 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"; +gst_directdraw_sink_xoverlay_interface_init (GstXOverlayClass * iface) +{ + iface->set_xwindow_id = gst_directdraw_sink_set_window_id; + iface->expose = gst_directdraw_sink_expose; +} + +static void +gst_directdraw_sink_init_interfaces (GType type) +{ + static const GInterfaceInfo iface_info = { + (GInterfaceInitFunc) gst_directdraw_sink_interface_init, + NULL, + NULL, + }; + + static const GInterfaceInfo xoverlay_info = { + (GInterfaceInitFunc) gst_directdraw_sink_xoverlay_interface_init, + NULL, + NULL, + }; + + g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE, + &iface_info); + g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &xoverlay_info); } /* Subclass of GstBuffer which manages buffer_pool surfaces lifetime */ @@ -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); @@ -1022,8 +803,349 @@ gst_directdraw_sink_show_frame (GstBaseSink * bsink, GstBuffer * buf) "IDirectDrawSurface7_Blt (offscreen surface from buffer_alloc) " "returned %s", DDErrorString (hRes)); } - - return GST_FLOW_OK; + + 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 @@ -1031,7 +1153,6 @@ 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); @@ -1273,6 +1439,49 @@ EnumModesCallback2 (LPDDSURFACEDESC2 lpDDSurfaceDesc, LPVOID lpContext) return DDENUMRET_OK; } +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) { @@ -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 -- cgit v1.2.1