From 478c8ba2992782b0860ea38d87552ab0108f1050 Mon Sep 17 00:00:00 2001 From: Julien Moutte Date: Fri, 4 Nov 2005 18:28:56 +0000 Subject: ext/directfb/dfbvideosink.*: Now does clipping when surface is too small, handles upstream elements that are not call... Original commit message from CVS: 2005-11-04 Julien MOUTTE * ext/directfb/dfbvideosink.c: (gst_dfbvideosink_surface_create), (gst_dfbvideosink_surface_destroy), (gst_dfbvideosink_get_best_vmode), (gst_dfbvideosink_getcaps), (gst_dfbvideosink_center_rect), (gst_dfbvideosink_show_frame), (gst_dfbvideosink_buffer_alloc): * ext/directfb/dfbvideosink.h: Now does clipping when surface is too small, handles upstream elements that are not calling gst_pad_alloc_buffer, fixes a lot of bugs. --- ext/directfb/dfbvideosink.c | 293 ++++++++++++++++++++++---------------------- 1 file changed, 144 insertions(+), 149 deletions(-) (limited to 'ext/directfb/dfbvideosink.c') diff --git a/ext/directfb/dfbvideosink.c b/ext/directfb/dfbvideosink.c index 27902136..e9d68725 100644 --- a/ext/directfb/dfbvideosink.c +++ b/ext/directfb/dfbvideosink.c @@ -133,8 +133,8 @@ gst_dfbvideosink_surface_create (GstDfbVideoSink * dfbvideosink, GstCaps * caps, surface = (GstDfbSurface *) gst_mini_object_new (GST_TYPE_DFBSURFACE); - /* Creating an internal surface which will be used as GstBuffer, we used - the detected pixel format and video dimensions */ + surface->locked = FALSE; + structure = gst_caps_get_structure (caps, 0); if (!gst_structure_get_int (structure, "width", &surface->width) || @@ -142,40 +142,52 @@ gst_dfbvideosink_surface_create (GstDfbVideoSink * dfbvideosink, GstCaps * caps, GST_WARNING ("failed getting geometry from caps %" GST_PTR_FORMAT, caps); } - s_dsc.flags = DSDESC_PIXELFORMAT | DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_CAPS; - surface->pixel_format = gst_dfbvideosink_get_format_from_caps (caps); - s_dsc.pixelformat = surface->pixel_format; - s_dsc.width = surface->width; - s_dsc.height = surface->height; - s_dsc.caps = DSCAPS_VIDEOONLY; + if (dfbvideosink->dfb) { + /* Creating an internal surface which will be used as GstBuffer, we used + the detected pixel format and video dimensions */ + + s_dsc.flags = + DSDESC_PIXELFORMAT | DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_CAPS; + + s_dsc.pixelformat = surface->pixel_format; + s_dsc.width = surface->width; + s_dsc.height = surface->height; + s_dsc.caps = DSCAPS_VIDEOONLY; + + ret = dfbvideosink->dfb->CreateSurface (dfbvideosink->dfb, &s_dsc, + &surface->surface); + if (ret != DFB_OK) { + GST_WARNING ("failed creating a DirectFB surface"); + gst_object_unref (surface); + surface = NULL; + goto beach; + } - ret = dfbvideosink->dfb->CreateSurface (dfbvideosink->dfb, &s_dsc, - &surface->surface); - if (ret != DFB_OK) { - GST_WARNING ("failed creating a DirectFB surface"); - gst_object_unref (surface); - surface = NULL; - goto beach; + /* Clearing surface */ + surface->surface->Clear (surface->surface, 0x00, 0x00, 0x00, 0xFF); + + /* Locking the surface to acquire the memory pointer */ + surface->surface->Lock (surface->surface, DSLF_WRITE, &data, &pitch); + surface->locked = TRUE; + GST_BUFFER_DATA (surface) = data; + GST_BUFFER_SIZE (surface) = pitch * surface->height; + + GST_DEBUG ("creating a %dx%d surface with %s pixel format, line pitch %d", + surface->width, surface->height, + gst_dfbvideosink_get_format_name (surface->pixel_format), pitch); + } else { + GST_BUFFER (surface)->malloc_data = g_malloc (size); + GST_BUFFER_DATA (surface) = GST_BUFFER (surface)->malloc_data; + GST_BUFFER_SIZE (surface) = size; + surface->surface = NULL; + GST_DEBUG ("allocating a buffer of %d bytes", size); } /* Keep a ref to our sink */ surface->dfbvideosink = gst_object_ref (dfbvideosink); - /* Clearing surface */ - surface->surface->Clear (surface->surface, 0x00, 0x00, 0x00, 0xFF); - - /* Locking the surface to acquire the memory pointer */ - surface->surface->Lock (surface->surface, DSLF_WRITE, &data, &pitch); - GST_BUFFER_DATA (surface) = data; - GST_BUFFER_SIZE (surface) = pitch * surface->height; - - /* FIXME : check that size matches with our line pitch * height */ - GST_DEBUG ("creating a %dx%d surface with %s pixel format, line pitch %d", - surface->width, surface->height, - gst_dfbvideosink_get_format_name (surface->pixel_format), pitch); - beach: return surface; } @@ -190,10 +202,19 @@ gst_dfbvideosink_surface_destroy (GstDfbVideoSink * dfbvideosink, /* Release our internal surface */ if (surface->surface) { + if (surface->locked) { + surface->surface->Unlock (surface->surface); + surface->locked = FALSE; + } surface->surface->Release (surface->surface); surface->surface = NULL; } + if (GST_BUFFER (surface)->malloc_data) { + g_free (GST_BUFFER (surface)->malloc_data); + GST_BUFFER (surface)->malloc_data = NULL; + } + if (!surface->dfbvideosink) { goto no_sink; } @@ -833,6 +854,10 @@ gst_dfbvideosink_get_best_vmode (GstDfbVideoSink * dfbvideosink, gint v_width, g_return_val_if_fail (GST_IS_DFBVIDEOSINK (dfbvideosink), FALSE); + if (!dfbvideosink->vmodes) { + goto beach; + } + walk = dfbvideosink->vmodes; vmode = (GstDfbVMode *) walk->data; @@ -872,6 +897,7 @@ gst_dfbvideosink_get_best_vmode (GstDfbVideoSink * dfbvideosink, gint v_width, ret = TRUE; +beach: return ret; } @@ -931,8 +957,8 @@ gst_dfbvideosink_getcaps (GstBaseSink * bsink) GstStructure *structure = gst_caps_get_structure (caps, i); gst_structure_set (structure, - "width", GST_TYPE_INT_RANGE, 1, dfbvideosink->out_width, - "height", GST_TYPE_INT_RANGE, 1, dfbvideosink->out_height, + "width", GST_TYPE_INT_RANGE, 1, G_MAXINT, + "height", GST_TYPE_INT_RANGE, 1, G_MAXINT, "framerate", GST_TYPE_DOUBLE_RANGE, 0.0, G_MAXDOUBLE, NULL); } @@ -1105,10 +1131,10 @@ gst_dfbvideosink_center_rect (DFBRectangle src, DFBRectangle dst, g_return_if_fail (result != NULL); if (!scale) { - result->w = src.w; - result->h = src.h; - result->x = (dst.w - src.w) / 2; - result->y = (dst.h - src.h) / 2; + result->w = MIN (src.w, dst.w); + result->h = MIN (src.h, dst.h); + result->x = (dst.w - result->w) / 2; + result->y = (dst.h - result->h) / 2; } else { gdouble src_ratio, dst_ratio; @@ -1140,7 +1166,7 @@ gst_dfbvideosink_center_rect (DFBRectangle src, DFBRectangle dst, static GstFlowReturn gst_dfbvideosink_show_frame (GstBaseSink * bsink, GstBuffer * buf) { - GstDfbVideoSink *dfbvideosink; + GstDfbVideoSink *dfbvideosink = NULL; DFBResult res; DFBRectangle dst, src, result; GstFlowReturn ret = GST_FLOW_OK; @@ -1152,133 +1178,107 @@ gst_dfbvideosink_show_frame (GstBaseSink * bsink, GstBuffer * buf) goto beach; } - /* Actual drawing */ if (GST_IS_DFBSURFACE (buf)) { GstDfbSurface *surface = GST_DFBSURFACE (buf); - /* Blit to the fullscreen primary */ - GST_DEBUG ("show frame with a buffer we allocated"); - src.w = surface->width; src.h = surface->height; + } else { + src.w = dfbvideosink->video_width; + src.h = dfbvideosink->video_height; + } - dfbvideosink->primary->GetSize (dfbvideosink->primary, &dst.w, &dst.h); - - /* Unlocking surface before blit */ - surface->surface->Unlock (surface->surface); + /* If we are rendering from a buffer we did not allocate or to an external + * surface, we will memcpy data */ + if (!GST_IS_DFBSURFACE (buf) || dfbvideosink->ext_surface) { + IDirectFBSurface *dest = NULL, *surface = NULL; + gpointer data; + gint dest_pitch, src_pitch, line; - gst_dfbvideosink_center_rect (src, dst, &result, dfbvideosink->hw_scaling); + /* As we are not blitting no acceleration is possible. If the surface is + * too small we do clipping, if it's too big we center. Theoretically as + * we are using buffer_alloc, there's a chance that we have been able to + * do reverse caps negotiation */ - if (dfbvideosink->hw_scaling) { - dfbvideosink->primary->StretchBlit (dfbvideosink->primary, - surface->surface, NULL, &result); + if (dfbvideosink->ext_surface) { + surface = dfbvideosink->ext_surface; + GST_DEBUG ("memcpy to an external surface subsurface"); } else { - dfbvideosink->primary->Blit (dfbvideosink->primary, surface->surface, - NULL, result.x, result.y); - } - - if (dfbvideosink->backbuffer) { - dfbvideosink->primary->Flip (dfbvideosink->primary, NULL, 0); + surface = dfbvideosink->primary; + GST_DEBUG ("memcpy to a primary subsurface"); } - } else { - if (dfbvideosink->ext_surface) { - IDirectFBSurface *dest = NULL; - gpointer data; - gint dest_pitch, src_pitch, line; - - /* External surface, no buffer_alloc optimization */ - GST_DEBUG ("show frame for an external surface (memcpy)"); - - src.w = dfbvideosink->video_width; - src.h = dfbvideosink->video_height; - - dfbvideosink->ext_surface->GetSize (dfbvideosink->ext_surface, &dst.w, - &dst.h); - - gst_dfbvideosink_center_rect (src, dst, &result, FALSE); - res = dfbvideosink->ext_surface->GetSubSurface (dfbvideosink->ext_surface, - &result, &dest); - if (res != DFB_OK) { - GST_WARNING ("failed when getting a sub surface from the external one"); - ret = GST_FLOW_UNEXPECTED; - goto beach; - } - - res = dest->Lock (dest, DSLF_WRITE, &data, &dest_pitch); - if (res != DFB_OK) { - GST_WARNING ("failed locking the external subsurface for writing"); - ret = GST_FLOW_ERROR; - goto beach; - } - - /* Source video rowbytes */ - src_pitch = GST_BUFFER_SIZE (buf) / result.h; + res = surface->GetSize (surface, &dst.w, &dst.h); - /* Write each line respecting subsurface pitch */ - for (line = 0; line < result.h; line++) { - memcpy (data, GST_BUFFER_DATA (buf) + (line * src_pitch), src_pitch); - data += dest_pitch; - } - - dest->Unlock (dest); - - dest->Release (dest); + /* Center / Clip */ + gst_dfbvideosink_center_rect (src, dst, &result, FALSE); - if (dfbvideosink->backbuffer) { - dfbvideosink->ext_surface->Flip (dfbvideosink->ext_surface, NULL, 0); - } - } else { - IDirectFBSurface *dest = NULL; - DFBSurfaceDescription s_dsc; - gpointer data; - gint pitch; + res = surface->GetSubSurface (surface, &result, &dest); + if (res != DFB_OK) { + GST_WARNING ("failed when getting a sub surface"); + ret = GST_FLOW_UNEXPECTED; + goto beach; + } - /* Our peer is bad, it's not using pad_buffer_alloc */ - GST_DEBUG ("show frame for a buffer we did not allocate (memcpy)"); + res = dest->Lock (dest, DSLF_WRITE, &data, &dest_pitch); + if (res != DFB_OK) { + GST_WARNING ("failed locking the external subsurface for writing"); + ret = GST_FLOW_ERROR; + goto beach; + } - src.w = dfbvideosink->video_width; - src.h = dfbvideosink->video_height; + /* Source video rowbytes */ + src_pitch = GST_BUFFER_SIZE (buf) / src.h; - dfbvideosink->primary->GetSize (dfbvideosink->primary, &dst.w, &dst.h); + /* Write each line respecting subsurface pitch */ + for (line = 0; line < result.h; line++) { + /* We do clipping */ + memcpy (data, GST_BUFFER_DATA (buf) + (line * src_pitch), + MIN (src_pitch, dest_pitch)); + data += dest_pitch; + } - gst_dfbvideosink_center_rect (src, dst, &result, - dfbvideosink->hw_scaling); + res = dest->Unlock (dest); - s_dsc.flags = DSDESC_PIXELFORMAT | DSDESC_WIDTH | - DSDESC_HEIGHT | DSDESC_CAPS; + res = dest->Release (dest); - s_dsc.pixelformat = dfbvideosink->pixel_format; - s_dsc.width = dfbvideosink->video_width; - s_dsc.height = dfbvideosink->video_height; - s_dsc.caps = DSCAPS_VIDEOONLY; + if (dfbvideosink->backbuffer) { + res = surface->Flip (surface, NULL, 0); + } + } else if (dfbvideosink->primary) { + /* Else we will [Stretch]Blit to our primary */ + GstDfbSurface *surface = GST_DFBSURFACE (buf); - res = dfbvideosink->dfb->CreateSurface (dfbvideosink->dfb, &s_dsc, &dest); - if (res != DFB_OK) { - GST_WARNING ("failed creating a surface to memcpy buffer data"); - goto beach; - } + GST_DEBUG ("blitting to a primary surface"); - dest->Lock (dest, DSLF_WRITE, &data, &pitch); + dfbvideosink->primary->GetSize (dfbvideosink->primary, &dst.w, &dst.h); - memcpy (data, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); + /* Unlocking surface before blit */ + surface->surface->Unlock (surface->surface); + surface->locked = FALSE; - dest->Unlock (dest); + gst_dfbvideosink_center_rect (src, dst, &result, dfbvideosink->hw_scaling); - if (dfbvideosink->hw_scaling) { - dfbvideosink->primary->StretchBlit (dfbvideosink->primary, dest, NULL, - &result); - } else { - dfbvideosink->primary->Blit (dfbvideosink->primary, dest, NULL, - result.x, result.y); - } + if (dfbvideosink->hw_scaling) { + dfbvideosink->primary->StretchBlit (dfbvideosink->primary, + surface->surface, NULL, &result); + } else { + DFBRectangle clip; - dest->Release (dest); + clip.x = clip.y = 0; + clip.w = result.w; + clip.h = result.h; + dfbvideosink->primary->Blit (dfbvideosink->primary, surface->surface, + &clip, result.x, result.y); + } - if (dfbvideosink->backbuffer) { - dfbvideosink->primary->Flip (dfbvideosink->primary, NULL, 0); - } + if (dfbvideosink->backbuffer) { + dfbvideosink->primary->Flip (dfbvideosink->primary, NULL, 0); } + } else { + GST_WARNING ("no primary, no external surface what's going on ?"); + ret = GST_FLOW_UNEXPECTED; + goto beach; } beach: @@ -1319,12 +1319,6 @@ gst_dfbvideosink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size, GST_DEBUG ("a buffer of %d bytes was requested with caps %" GST_PTR_FORMAT " and offset %llu", size, caps, offset); - /* If we use an external surface we can't allocate surfaces ourselves */ - if (dfbvideosink->ext_surface) { - *buf = NULL; - goto beach; - } - desired_caps = gst_caps_copy (caps); structure = gst_caps_get_structure (desired_caps, 0); @@ -1347,16 +1341,17 @@ gst_dfbvideosink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size, dst.w = vmode.width; dst.h = vmode.height; } else { - dst.w = dfbvideosink->out_width; - dst.h = dfbvideosink->out_height; + if (dfbvideosink->ext_surface) { + dfbvideosink->ext_surface->GetSize (dfbvideosink->ext_surface, &dst.w, + &dst.h); + } else { + dfbvideosink->primary->GetSize (dfbvideosink->primary, &dst.w, &dst.h); + } + dfbvideosink->out_width = dst.w; + dfbvideosink->out_height = dst.h; } - if (!dfbvideosink->ext_surface) { - gst_dfbvideosink_center_rect (src, dst, &result, TRUE); - } else { - /* Except for an external surface */ - result = dst; - } + gst_dfbvideosink_center_rect (src, dst, &result, TRUE); if (width != result.w && height != result.h) { GstPad *peer = gst_pad_get_peer (GST_VIDEO_SINK_PAD (dfbvideosink)); -- cgit v1.2.1