summaryrefslogtreecommitdiff
path: root/sys/d3dvideosink
diff options
context:
space:
mode:
authorSebastian Dröge <sebastian.droege@collabora.co.uk>2012-12-22 21:59:03 +0100
committerSebastian Dröge <sebastian.droege@collabora.co.uk>2013-03-26 13:39:46 +0100
commit81304a795693ebe35983a400039e0482cbaea7e3 (patch)
tree644d249ba330b33dea04da2daff07df0f23e1c59 /sys/d3dvideosink
parentabede65bbcaa26df1fdcffe6cca6f49a8b44370f (diff)
downloadgstreamer-plugins-bad-81304a795693ebe35983a400039e0482cbaea7e3.tar.gz
d3dvideosink: Implement a buffer pool that shares D3D surfaces with upstream
Diffstat (limited to 'sys/d3dvideosink')
-rw-r--r--sys/d3dvideosink/d3dhelpers.c654
-rw-r--r--sys/d3dvideosink/d3dhelpers.h30
-rw-r--r--sys/d3dvideosink/d3dvideosink.c105
-rw-r--r--sys/d3dvideosink/d3dvideosink.h3
4 files changed, 664 insertions, 128 deletions
diff --git a/sys/d3dvideosink/d3dhelpers.c b/sys/d3dvideosink/d3dhelpers.c
index 081d4029d..6d0f70deb 100644
--- a/sys/d3dvideosink/d3dhelpers.c
+++ b/sys/d3dvideosink/d3dhelpers.c
@@ -37,8 +37,8 @@ static gboolean d3d_init_swap_chain (GstD3DVideoSink * sink, HWND hWnd);
static gboolean d3d_release_swap_chain (GstD3DVideoSink * sink);
static gboolean d3d_resize_swap_chain (GstD3DVideoSink * sink);
static gboolean d3d_present_swap_chain (GstD3DVideoSink * sink);
-static gboolean d3d_copy_buffer_to_surface (GstD3DVideoSink * sink,
- LPDIRECT3DSURFACE9 surface, GstBuffer * buffer);
+static gboolean d3d_copy_buffer (GstD3DVideoSink * sink,
+ GstBuffer * from, GstBuffer * to);
static gboolean d3d_stretch_and_copy (GstD3DVideoSink * sink,
LPDIRECT3DSURFACE9 back_buffer);
static HWND d3d_create_internal_window (GstD3DVideoSink * sink);
@@ -315,6 +315,392 @@ d3d_format_comp_compare (gconstpointer a, gconstpointer b)
return 1;
}
+#define GST_D3D_SURFACE_MEMORY_NAME "D3DSurface"
+
+typedef struct
+{
+ GstMemory mem;
+
+ GstD3DVideoSink *sink;
+
+ GMutex lock;
+ gint map_count;
+
+ LPDIRECT3DSURFACE9 surface;
+ D3DLOCKED_RECT lr;
+ gint x, y, width, height;
+} GstD3DSurfaceMemory;
+
+static GstMemory *
+gst_d3d_surface_memory_allocator_alloc (GstAllocator * allocator, gsize size,
+ GstAllocationParams * params)
+{
+ g_assert_not_reached ();
+ return NULL;
+}
+
+static void
+gst_d3d_surface_memory_allocator_free (GstAllocator * allocator,
+ GstMemory * mem)
+{
+ GstD3DSurfaceMemory *dmem = (GstD3DSurfaceMemory *) mem;
+
+ /* If this is a sub-memory, do nothing */
+ if (mem->parent)
+ return;
+
+ if (dmem->lr.pBits)
+ g_warning ("d3dvideosink: Freeing memory that is still mapped");
+
+ IDirect3DSurface9_Release (dmem->surface);
+ gst_object_unref (dmem->sink);
+ g_mutex_clear (&dmem->lock);
+ g_slice_free (GstD3DSurfaceMemory, dmem);
+}
+
+static gpointer
+gst_d3d_surface_memory_map (GstMemory * mem, gsize maxsize, GstMapFlags flags)
+{
+ GstD3DSurfaceMemory *parent;
+ gpointer ret = NULL;
+ gint d3d_flags = ((flags & GST_MAP_WRITE) == 0) ? D3DLOCK_READONLY : 0;
+
+ /* find the real parent */
+ if ((parent = (GstD3DSurfaceMemory *) mem->parent) == NULL)
+ parent = (GstD3DSurfaceMemory *) mem;
+
+ g_mutex_lock (&parent->lock);
+ if (!parent->map_count
+ && IDirect3DSurface9_LockRect (parent->surface, &parent->lr, NULL,
+ d3d_flags) != D3D_OK) {
+ ret = NULL;
+ goto done;
+ }
+
+ ret = parent->lr.pBits;
+ parent->map_count++;
+
+done:
+ g_mutex_unlock (&parent->lock);
+
+ return ret;
+}
+
+static void
+gst_d3d_surface_memory_unmap (GstMemory * mem)
+{
+ GstD3DSurfaceMemory *parent;
+
+ /* find the real parent */
+ if ((parent = (GstD3DSurfaceMemory *) mem->parent) == NULL)
+ parent = (GstD3DSurfaceMemory *) mem;
+
+ g_mutex_lock (&parent->lock);
+ parent->map_count--;
+ if (parent->map_count == 0) {
+ IDirect3DSurface9_UnlockRect (parent->surface);
+ memset (&parent->lr, 0, sizeof (parent->lr));
+ }
+
+ g_mutex_unlock (&parent->lock);
+}
+
+static GstMemory *
+gst_d3d_surface_memory_share (GstMemory * mem, gssize offset, gssize size)
+{
+ GstD3DSurfaceMemory *sub;
+ GstD3DSurfaceMemory *parent;
+
+ /* find the real parent */
+ if ((parent = (GstD3DSurfaceMemory *) mem->parent) == NULL)
+ parent = (GstD3DSurfaceMemory *) mem;
+
+ if (size == -1)
+ size = mem->size - offset;
+
+ sub = g_slice_new0 (GstD3DSurfaceMemory);
+ /* the shared memory is always readonly */
+ gst_memory_init (GST_MEMORY_CAST (sub), GST_MINI_OBJECT_FLAGS (parent) |
+ GST_MINI_OBJECT_FLAG_LOCK_READONLY, mem->allocator,
+ GST_MEMORY_CAST (parent), mem->maxsize, mem->align, mem->offset + offset,
+ size);
+
+ return GST_MEMORY_CAST (sub);
+}
+
+typedef struct
+{
+ GstAllocator parent;
+} GstD3DSurfaceMemoryAllocator;
+
+typedef struct
+{
+ GstAllocatorClass parent_class;
+} GstD3DSurfaceMemoryAllocatorClass;
+
+GType gst_d3d_surface_memory_allocator_get_type (void);
+G_DEFINE_TYPE (GstD3DSurfaceMemoryAllocator, gst_d3d_surface_memory_allocator,
+ GST_TYPE_ALLOCATOR);
+
+#define GST_TYPE_D3D_SURFACE_MEMORY_ALLOCATOR (gst_d3d_surface_memory_allocator_get_type())
+#define GST_IS_D3D_SURFACE_MEMORY_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_D3D_SURFACE_MEMORY_ALLOCATOR))
+
+static void
+gst_d3d_surface_memory_allocator_class_init (GstD3DSurfaceMemoryAllocatorClass *
+ klass)
+{
+ GstAllocatorClass *allocator_class;
+
+ allocator_class = (GstAllocatorClass *) klass;
+
+ allocator_class->alloc = gst_d3d_surface_memory_allocator_alloc;
+ allocator_class->free = gst_d3d_surface_memory_allocator_free;
+}
+
+static void
+gst_d3d_surface_memory_allocator_init (GstD3DSurfaceMemoryAllocator * allocator)
+{
+ GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator);
+
+ alloc->mem_type = GST_D3D_SURFACE_MEMORY_NAME;
+ alloc->mem_map = gst_d3d_surface_memory_map;
+ alloc->mem_unmap = gst_d3d_surface_memory_unmap;
+ alloc->mem_share = gst_d3d_surface_memory_share;
+ /* fallback copy */
+
+ GST_OBJECT_FLAG_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
+}
+
+G_DEFINE_TYPE (GstD3DSurfaceBufferPool, gst_d3dsurface_buffer_pool,
+ GST_TYPE_VIDEO_BUFFER_POOL);
+
+GstBufferPool *
+gst_d3dsurface_buffer_pool_new (GstD3DVideoSink * sink)
+{
+ GstD3DSurfaceBufferPool *pool;
+
+ pool = g_object_new (GST_TYPE_D3DSURFACE_BUFFER_POOL, NULL);
+ pool->sink = gst_object_ref (sink);
+
+ GST_LOG_OBJECT (pool, "new buffer pool %p", pool);
+
+ return GST_BUFFER_POOL_CAST (pool);
+}
+
+static void
+gst_d3dsurface_buffer_pool_finalize (GObject * object)
+{
+ GstD3DSurfaceBufferPool *pool = GST_D3DSURFACE_BUFFER_POOL_CAST (object);
+
+ GST_LOG_OBJECT (pool, "finalize buffer pool %p", pool);
+
+ gst_object_unref (pool->sink);
+ if (pool->allocator)
+ gst_object_unref (pool->allocator);
+
+ G_OBJECT_CLASS (gst_d3dsurface_buffer_pool_parent_class)->finalize (object);
+}
+
+static const gchar **
+gst_d3dsurface_buffer_pool_get_options (GstBufferPool * pool)
+{
+ static const gchar *options[] = { GST_BUFFER_POOL_OPTION_VIDEO_META, NULL };
+
+ return options;
+}
+
+static gboolean
+gst_d3dsurface_buffer_pool_set_config (GstBufferPool * bpool,
+ GstStructure * config)
+{
+ GstD3DSurfaceBufferPool *pool = GST_D3DSURFACE_BUFFER_POOL_CAST (bpool);
+ GstCaps *caps;
+ GstVideoInfo info;
+
+ if (!GST_BUFFER_POOL_CLASS
+ (gst_d3dsurface_buffer_pool_parent_class)->set_config (bpool, config)) {
+ return FALSE;
+ }
+
+ if (!gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL)
+ || !caps) {
+ GST_ERROR_OBJECT (pool, "Buffer pool configuration without caps");
+ return FALSE;
+ }
+
+ /* now parse the caps from the config */
+ if (!gst_video_info_from_caps (&info, caps)) {
+ GST_ERROR_OBJECT (pool, "Failed to parse caps %" GST_PTR_FORMAT, caps);
+ return FALSE;
+ }
+
+ if (gst_video_format_to_d3d_format (GST_VIDEO_INFO_FORMAT (&info)) ==
+ D3DFMT_UNKNOWN) {
+ GST_ERROR_OBJECT (pool, "Unsupported video format in caps %" GST_PTR_FORMAT,
+ caps);
+ return FALSE;
+ }
+
+ GST_LOG_OBJECT (pool, "%dx%d, caps %" GST_PTR_FORMAT, info.width, info.height,
+ caps);
+
+ pool->info = info;
+
+ pool->add_metavideo =
+ gst_buffer_pool_config_has_option (config,
+ GST_BUFFER_POOL_OPTION_VIDEO_META);
+
+ if (pool->add_metavideo)
+ pool->allocator =
+ g_object_new (GST_TYPE_D3D_SURFACE_MEMORY_ALLOCATOR, NULL);
+
+ return TRUE;
+}
+
+static GstFlowReturn
+gst_d3dsurface_buffer_pool_alloc (GstBufferPool * bpool, GstBuffer ** buffer,
+ GstBufferPoolAcquireParams * params)
+{
+ GstD3DSurfaceBufferPool *pool = GST_D3DSURFACE_BUFFER_POOL_CAST (bpool);
+ GstD3DVideoSink *sink = pool->sink;
+ GstD3DVideoSinkClass *klass = GST_D3DVIDEOSINK_GET_CLASS (sink);
+ GstD3DSurfaceMemory *mem;
+ LPDIRECT3DSURFACE9 surface;
+ D3DFORMAT d3dformat;
+ gint stride[GST_VIDEO_MAX_PLANES] = { 0, };
+ gsize offset[GST_VIDEO_MAX_PLANES] = { 0, };
+ D3DLOCKED_RECT lr;
+ HRESULT hr;
+ gsize size = 0;
+
+ *buffer = NULL;
+ if (!pool->add_metavideo) {
+ GST_DEBUG_OBJECT (pool, "No video meta allowed, fallback alloc");
+ goto fallback;
+ }
+
+ d3dformat =
+ gst_video_format_to_d3d_format (GST_VIDEO_INFO_FORMAT (&pool->info));
+ hr = IDirect3DDevice9_CreateOffscreenPlainSurface (klass->d3d.
+ device.d3d_device, GST_VIDEO_INFO_WIDTH (&pool->info),
+ GST_VIDEO_INFO_HEIGHT (&pool->info), d3dformat, D3DPOOL_DEFAULT, &surface,
+ NULL);
+ if (hr != D3D_OK) {
+ GST_ERROR_OBJECT (sink, "Failed to create D3D surface");
+ goto fallback;
+ }
+
+ IDirect3DSurface9_LockRect (surface, &lr, NULL, D3DLOCK_READONLY);
+ if (!lr.pBits) {
+ GST_ERROR_OBJECT (sink, "Failed to lock D3D surface");
+ IDirect3DSurface9_Release (surface);
+ goto fallback;
+ }
+
+ switch (GST_VIDEO_INFO_FORMAT (&pool->info)) {
+ case GST_VIDEO_FORMAT_BGR:
+ offset[0] = 0;
+ stride[0] = lr.Pitch;
+ size = lr.Pitch * GST_VIDEO_INFO_HEIGHT (&pool->info) * 3;
+ break;
+ case GST_VIDEO_FORMAT_BGRx:
+ case GST_VIDEO_FORMAT_RGBx:
+ case GST_VIDEO_FORMAT_BGRA:
+ case GST_VIDEO_FORMAT_RGBA:
+ offset[0] = 0;
+ stride[0] = lr.Pitch;
+ size = lr.Pitch * GST_VIDEO_INFO_HEIGHT (&pool->info) * 4;
+ break;
+ case GST_VIDEO_FORMAT_RGB16:
+ case GST_VIDEO_FORMAT_RGB15:
+ offset[0] = 0;
+ stride[0] = lr.Pitch;
+ size = lr.Pitch * GST_VIDEO_INFO_HEIGHT (&pool->info) * 2;
+ break;
+ case GST_VIDEO_FORMAT_YUY2:
+ case GST_VIDEO_FORMAT_UYVY:
+ offset[0] = 0;
+ stride[0] = lr.Pitch;
+ size = lr.Pitch * GST_VIDEO_INFO_HEIGHT (&pool->info) * 2;
+ break;
+ case GST_VIDEO_FORMAT_I420:
+ case GST_VIDEO_FORMAT_YV12:
+ offset[0] = 0;
+ stride[0] = lr.Pitch;
+ offset[2] =
+ offset[0] + stride[0] * GST_VIDEO_INFO_COMP_HEIGHT (&pool->info, 0);
+ stride[2] = lr.Pitch / 2;
+ offset[1] =
+ offset[2] + stride[2] * GST_VIDEO_INFO_COMP_HEIGHT (&pool->info, 2);
+ stride[1] = lr.Pitch / 2;
+ size =
+ offset[1] + stride[1] * GST_VIDEO_INFO_COMP_HEIGHT (&pool->info, 1);
+ break;
+ case GST_VIDEO_FORMAT_NV12:
+ offset[0] = 0;
+ stride[0] = lr.Pitch;
+ offset[1] =
+ offset[0] + stride[0] * GST_VIDEO_INFO_COMP_HEIGHT (&pool->info, 0);
+ stride[1] = lr.Pitch;
+ size =
+ offset[1] + stride[1] * GST_VIDEO_INFO_COMP_HEIGHT (&pool->info, 1);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ IDirect3DSurface9_UnlockRect (surface);
+
+ *buffer = gst_buffer_new ();
+
+ gst_buffer_add_video_meta_full (*buffer, GST_VIDEO_FRAME_FLAG_NONE,
+ GST_VIDEO_INFO_FORMAT (&pool->info), GST_VIDEO_INFO_WIDTH (&pool->info),
+ GST_VIDEO_INFO_HEIGHT (&pool->info),
+ GST_VIDEO_INFO_N_PLANES (&pool->info), offset, stride);
+
+ mem = g_slice_new0 (GstD3DSurfaceMemory);
+ gst_memory_init (GST_MEMORY_CAST (mem), 0, pool->allocator, NULL, size, 0, 0,
+ size);
+
+ mem->surface = surface;
+ mem->sink = gst_object_ref (sink);
+ mem->x = mem->y = 0;
+ mem->width = GST_VIDEO_INFO_WIDTH (&pool->info);
+ mem->height = GST_VIDEO_INFO_HEIGHT (&pool->info);
+ g_mutex_init (&mem->lock);
+
+ gst_buffer_append_memory (*buffer, GST_MEMORY_CAST (mem));
+
+ return GST_FLOW_OK;
+
+fallback:
+ {
+ return
+ GST_BUFFER_POOL_CLASS
+ (gst_d3dsurface_buffer_pool_parent_class)->alloc_buffer (bpool, buffer,
+ params);
+ }
+}
+
+static void
+gst_d3dsurface_buffer_pool_class_init (GstD3DSurfaceBufferPoolClass * klass)
+{
+ GObjectClass *gobject_class = (GObjectClass *) klass;
+ GstBufferPoolClass *gstbufferpool_class = (GstBufferPoolClass *) klass;
+
+ gobject_class->finalize = gst_d3dsurface_buffer_pool_finalize;
+
+ gstbufferpool_class->get_options = gst_d3dsurface_buffer_pool_get_options;
+ gstbufferpool_class->set_config = gst_d3dsurface_buffer_pool_set_config;
+ gstbufferpool_class->alloc_buffer = gst_d3dsurface_buffer_pool_alloc;
+}
+
+static void
+gst_d3dsurface_buffer_pool_init (GstD3DSurfaceBufferPool * pool)
+{
+}
+
GstCaps *
d3d_supported_caps (GstD3DVideoSink * sink)
{
@@ -759,6 +1145,14 @@ end:
gboolean
d3d_stop (GstD3DVideoSink * sink)
{
+ if (sink->pool)
+ gst_buffer_pool_set_active (sink->pool, FALSE);
+ if (sink->fallback_pool)
+ gst_buffer_pool_set_active (sink->fallback_pool, FALSE);
+ gst_object_replace ((GstObject **) & sink->pool, NULL);
+ gst_object_replace ((GstObject **) & sink->fallback_pool, NULL);
+ gst_buffer_replace (&sink->fallback_buffer, NULL);
+
/* Release D3D resources */
d3d_set_window_handle (sink, 0, FALSE);
return TRUE;
@@ -1031,51 +1425,43 @@ end:
}
static gboolean
-d3d_copy_buffer_to_surface (GstD3DVideoSink * sink, LPDIRECT3DSURFACE9 surface,
- GstBuffer * buffer)
+d3d_copy_buffer (GstD3DVideoSink * sink, GstBuffer * from, GstBuffer * to)
{
- D3DLOCKED_RECT lr;
- guint8 *dest;
- int deststride;
gboolean ret = FALSE;
- gint unhdl_line = 0;
- GstVideoFrame frame;
+ GstVideoFrame from_frame, to_frame;
+
+ memset (&from_frame, 0, sizeof (from_frame));
+ memset (&to_frame, 0, sizeof (to_frame));
+
LOCK_SINK (sink);
if (!sink->d3d.renderable || sink->d3d.device_lost)
goto end;
- if (!buffer
- || !gst_video_frame_map (&frame, &sink->info, buffer, GST_MAP_READ)) {
+ if (!gst_video_frame_map (&from_frame, &sink->info, from, GST_MAP_READ) ||
+ !gst_video_frame_map (&to_frame, &sink->info, to, GST_MAP_WRITE)) {
GST_ERROR_OBJECT (sink, "NULL GstBuffer");
goto end;
}
- IDirect3DSurface9_LockRect (surface, &lr, NULL, 0);
- dest = (guint8 *) lr.pBits;
-
- if (!dest) {
- GST_ERROR_OBJECT (sink, "No D3D surface dest buffer");
- goto unlock_surface;
- }
-
- deststride = lr.Pitch;
-
switch (sink->format) {
case GST_VIDEO_FORMAT_YUY2:
case GST_VIDEO_FORMAT_UYVY:{
const guint8 *src;
- gint srcstride;
+ guint8 *dst;
+ gint dststride, srcstride;
gint i, h, w;
- src = GST_VIDEO_FRAME_PLANE_DATA (&frame, 0);
- srcstride = GST_VIDEO_FRAME_PLANE_STRIDE (&frame, 0);
- h = GST_VIDEO_FRAME_HEIGHT (&frame);
- w = GST_ROUND_UP_4 (GST_VIDEO_FRAME_WIDTH (&frame) * 2);
+ src = GST_VIDEO_FRAME_PLANE_DATA (&from_frame, 0);
+ dst = GST_VIDEO_FRAME_PLANE_DATA (&to_frame, 0);
+ srcstride = GST_VIDEO_FRAME_PLANE_STRIDE (&from_frame, 0);
+ dststride = GST_VIDEO_FRAME_PLANE_STRIDE (&to_frame, 0);
+ h = GST_VIDEO_FRAME_HEIGHT (&from_frame);
+ w = GST_ROUND_UP_4 (GST_VIDEO_FRAME_WIDTH (&from_frame) * 2);
for (i = 0; i < h; i++) {
- memcpy (dest, src, w);
- dest += deststride;
+ memcpy (dst, src, w);
+ dst += dststride;
src += srcstride;
}
@@ -1084,36 +1470,21 @@ d3d_copy_buffer_to_surface (GstD3DVideoSink * sink, LPDIRECT3DSURFACE9 surface,
case GST_VIDEO_FORMAT_I420:
case GST_VIDEO_FORMAT_YV12:{
const guint8 *src;
- gint srcstride, deststride_;
- guint8 *dest_;
- gint i, j, h, h_, w_;
-
- h = GST_VIDEO_FRAME_HEIGHT (&frame);
+ guint8 *dst;
+ gint srcstride, dststride;
+ gint i, j, h_, w_;
for (i = 0; i < 3; i++) {
- src = GST_VIDEO_FRAME_COMP_DATA (&frame, i);
- srcstride = GST_VIDEO_FRAME_COMP_STRIDE (&frame, i);
- h_ = GST_VIDEO_FRAME_COMP_HEIGHT (&frame, i);
- w_ = GST_VIDEO_FRAME_COMP_WIDTH (&frame, i);
-
- switch (i) {
- case 0:
- deststride_ = deststride;
- dest_ = dest;
- break;
- case 2:
- deststride_ = deststride / 2;
- dest_ = dest + h * deststride;
- break;
- case 1:
- deststride_ = deststride / 2;
- dest_ = dest + h * deststride + h_ * deststride_;
- break;
- }
+ src = GST_VIDEO_FRAME_COMP_DATA (&from_frame, i);
+ dst = GST_VIDEO_FRAME_COMP_DATA (&to_frame, i);
+ srcstride = GST_VIDEO_FRAME_COMP_STRIDE (&from_frame, i);
+ dststride = GST_VIDEO_FRAME_COMP_STRIDE (&to_frame, i);
+ h_ = GST_VIDEO_FRAME_COMP_HEIGHT (&from_frame, i);
+ w_ = GST_VIDEO_FRAME_COMP_WIDTH (&from_frame, i);
for (j = 0; j < h_; j++) {
- memcpy (dest_, src, w_);
- dest_ += deststride_;
+ memcpy (dst, src, w_);
+ dst += dststride;
src += srcstride;
}
}
@@ -1122,30 +1493,21 @@ d3d_copy_buffer_to_surface (GstD3DVideoSink * sink, LPDIRECT3DSURFACE9 surface,
}
case GST_VIDEO_FORMAT_NV12:{
const guint8 *src;
- gint srcstride;
- guint8 *dest_;
- gint i, j, h, h_, w_;
-
- h = GST_VIDEO_FRAME_HEIGHT (&frame);
+ guint8 *dst;
+ gint srcstride, dststride;
+ gint i, j, h_, w_;
for (i = 0; i < 2; i++) {
- src = GST_VIDEO_FRAME_PLANE_DATA (&frame, i);
- srcstride = GST_VIDEO_FRAME_PLANE_STRIDE (&frame, i);
- h_ = GST_VIDEO_FRAME_COMP_HEIGHT (&frame, i);
- w_ = GST_VIDEO_FRAME_COMP_WIDTH (&frame, i);
-
- switch (i) {
- case 0:
- dest_ = dest;
- break;
- case 1:
- dest_ = dest + h * deststride;
- break;
- }
+ src = GST_VIDEO_FRAME_PLANE_DATA (&from_frame, i);
+ dst = GST_VIDEO_FRAME_PLANE_DATA (&to_frame, i);
+ srcstride = GST_VIDEO_FRAME_PLANE_STRIDE (&from_frame, i);
+ dststride = GST_VIDEO_FRAME_PLANE_STRIDE (&to_frame, i);
+ h_ = GST_VIDEO_FRAME_COMP_HEIGHT (&from_frame, i);
+ w_ = GST_VIDEO_FRAME_COMP_WIDTH (&from_frame, i);
for (j = 0; j < h_; j++) {
- memcpy (dest_, src, w_ * 2);
- dest_ += deststride;
+ memcpy (dst, src, w_ * 2);
+ dst += dststride;
src += srcstride;
}
}
@@ -1157,17 +1519,20 @@ d3d_copy_buffer_to_surface (GstD3DVideoSink * sink, LPDIRECT3DSURFACE9 surface,
case GST_VIDEO_FORMAT_BGRx:
case GST_VIDEO_FORMAT_RGBx:{
const guint8 *src;
- gint srcstride;
+ guint8 *dst;
+ gint srcstride, dststride;
gint i, h, w;
- src = GST_VIDEO_FRAME_PLANE_DATA (&frame, 0);
- srcstride = GST_VIDEO_FRAME_PLANE_STRIDE (&frame, 0);
- h = GST_VIDEO_FRAME_HEIGHT (&frame);
- w = GST_VIDEO_FRAME_WIDTH (&frame) * 4;
+ src = GST_VIDEO_FRAME_PLANE_DATA (&from_frame, 0);
+ dst = GST_VIDEO_FRAME_PLANE_DATA (&to_frame, 0);
+ srcstride = GST_VIDEO_FRAME_PLANE_STRIDE (&from_frame, 0);
+ dststride = GST_VIDEO_FRAME_PLANE_STRIDE (&to_frame, 0);
+ h = GST_VIDEO_FRAME_HEIGHT (&from_frame);
+ w = GST_VIDEO_FRAME_WIDTH (&from_frame) * 4;
for (i = 0; i < h; i++) {
- memcpy (dest, src, w);
- dest += deststride;
+ memcpy (dst, src, w);
+ dst += dststride;
src += srcstride;
}
@@ -1175,17 +1540,20 @@ d3d_copy_buffer_to_surface (GstD3DVideoSink * sink, LPDIRECT3DSURFACE9 surface,
}
case GST_VIDEO_FORMAT_BGR:{
const guint8 *src;
- gint srcstride;
+ guint8 *dst;
+ gint srcstride, dststride;
gint i, h, w;
- src = GST_VIDEO_FRAME_PLANE_DATA (&frame, 0);
- srcstride = GST_VIDEO_FRAME_PLANE_STRIDE (&frame, 0);
- h = GST_VIDEO_FRAME_HEIGHT (&frame);
- w = GST_VIDEO_FRAME_WIDTH (&frame) * 3;
+ src = GST_VIDEO_FRAME_PLANE_DATA (&from_frame, 0);
+ dst = GST_VIDEO_FRAME_PLANE_DATA (&to_frame, 0);
+ srcstride = GST_VIDEO_FRAME_PLANE_STRIDE (&from_frame, 0);
+ dststride = GST_VIDEO_FRAME_PLANE_STRIDE (&to_frame, 0);
+ h = GST_VIDEO_FRAME_HEIGHT (&from_frame);
+ w = GST_VIDEO_FRAME_WIDTH (&from_frame) * 3;
for (i = 0; i < h; i++) {
- memcpy (dest, src, w);
- dest += deststride;
+ memcpy (dst, src, w);
+ dst += dststride;
src += srcstride;
}
@@ -1194,45 +1562,47 @@ d3d_copy_buffer_to_surface (GstD3DVideoSink * sink, LPDIRECT3DSURFACE9 surface,
case GST_VIDEO_FORMAT_RGB16:
case GST_VIDEO_FORMAT_RGB15:{
const guint8 *src;
- gint srcstride;
+ guint8 *dst;
+ gint srcstride, dststride;
gint i, h, w;
- src = GST_VIDEO_FRAME_PLANE_DATA (&frame, 0);
- srcstride = GST_VIDEO_FRAME_PLANE_STRIDE (&frame, 0);
- h = GST_VIDEO_FRAME_HEIGHT (&frame);
- w = GST_VIDEO_FRAME_WIDTH (&frame) * 2;
+ src = GST_VIDEO_FRAME_PLANE_DATA (&from_frame, 0);
+ dst = GST_VIDEO_FRAME_PLANE_DATA (&to_frame, 0);
+ srcstride = GST_VIDEO_FRAME_PLANE_STRIDE (&from_frame, 0);
+ dststride = GST_VIDEO_FRAME_PLANE_STRIDE (&to_frame, 0);
+ h = GST_VIDEO_FRAME_HEIGHT (&from_frame);
+ w = GST_VIDEO_FRAME_WIDTH (&from_frame) * 2;
for (i = 0; i < h; i++) {
- memcpy (dest, src, w);
- dest += deststride;
+ memcpy (dst, src, w);
+ dst += dststride;
src += srcstride;
}
break;
}
default:
- unhdl_line = __LINE__;
goto unhandled_format;
}
- goto done;
-
-unhandled_format:
- GST_ERROR_OBJECT (sink,
- "Unhandled format [LN:%d] '%s' -> '%s' (should not get here)", unhdl_line,
- gst_video_format_to_string (sink->format),
- d3d_format_to_string (sink->d3d.format));
- goto unlock_surface;
-
-done:
ret = TRUE;
-unlock_surface:
- IDirect3DSurface9_UnlockRect (surface);
- gst_video_frame_unmap (&frame);
end:
+ if (from_frame.buffer)
+ gst_video_frame_unmap (&from_frame);
+ if (to_frame.buffer)
+ gst_video_frame_unmap (&to_frame);
+
UNLOCK_SINK (sink);
return ret;
+
+unhandled_format:
+ GST_ERROR_OBJECT (sink,
+ "Unhandled format '%s' -> '%s' (should not get here)",
+ gst_video_format_to_string (sink->format),
+ d3d_format_to_string (sink->d3d.format));
+ ret = FALSE;
+ goto end;
}
static gboolean
@@ -1397,12 +1767,9 @@ GstFlowReturn
d3d_render_buffer (GstD3DVideoSink * sink, GstBuffer * buf)
{
GstFlowReturn ret = GST_FLOW_OK;
- GstMapInfo map;
+ GstMemory *mem;
LPDIRECT3DSURFACE9 surface = NULL;
- g_return_val_if_fail (gst_buffer_map (buf, &map, GST_MAP_READ) != FALSE,
- GST_FLOW_ERROR);
-
LOCK_SINK (sink);
if (!sink->d3d.window_handle) {
@@ -1428,26 +1795,59 @@ d3d_render_buffer (GstD3DVideoSink * sink, GstBuffer * buf)
goto end;
}
- if (!surface) {
- HRESULT hr;
- GstD3DVideoSinkClass *klass = GST_D3DVIDEOSINK_GET_CLASS (sink);
+ if (gst_buffer_n_memory (buf) != 1 ||
+ (mem = gst_buffer_peek_memory (buf, 0)) == 0 ||
+ !gst_memory_is_type (mem, GST_D3D_SURFACE_MEMORY_NAME)) {
+ GstBuffer *tmp;
+ GstBufferPoolAcquireParams params = { 0, };
- hr = IDirect3DDevice9_CreateOffscreenPlainSurface (klass->d3d.
- device.d3d_device, GST_VIDEO_SINK_WIDTH (sink),
- GST_VIDEO_SINK_HEIGHT (sink), sink->d3d.format, D3DPOOL_DEFAULT,
- &surface, NULL);
- if (hr != D3D_OK || surface == NULL) {
- GST_ERROR_OBJECT (sink, "Failed to create D3D surface");
+ if (!sink->fallback_pool
+ || !gst_buffer_pool_set_active (sink->fallback_pool, TRUE)) {
+ ret = GST_FLOW_NOT_NEGOTIATED;
+ goto end;
+ }
+
+ /* take a buffer from our pool, if there is no buffer in the pool something
+ * is seriously wrong, waiting for the pool here might deadlock when we try
+ * to go to PAUSED because we never flush the pool. */
+ params.flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT;
+ ret = gst_buffer_pool_acquire_buffer (sink->fallback_pool, &tmp, &params);
+ if (ret != GST_FLOW_OK)
+ goto end;
+
+ if (sink->fallback_buffer) {
+ gst_buffer_unref (sink->fallback_buffer);
+ sink->fallback_buffer = NULL;
+ }
+
+ mem = gst_buffer_peek_memory (tmp, 0);
+ if (!mem || !gst_memory_is_type (mem, GST_D3D_SURFACE_MEMORY_NAME)) {
ret = GST_FLOW_ERROR;
+ gst_buffer_unref (tmp);
goto end;
}
- d3d_copy_buffer_to_surface (sink, surface, buf);
- if (sink->d3d.surface)
- IDirect3DSurface9_Release (sink->d3d.surface);
- IDirect3DSurface9_AddRef (surface);
- sink->d3d.surface = surface;
+ d3d_copy_buffer (sink, buf, tmp);
+ buf = tmp;
+
+ surface = ((GstD3DSurfaceMemory *) mem)->surface;
+
+ /* Need to keep an additional ref until the next buffer
+ * to make sure it isn't reused until then */
+ sink->fallback_buffer = buf;
+ } else {
+ mem = gst_buffer_peek_memory (buf, 0);
+ surface = ((GstD3DSurfaceMemory *) mem)->surface;
+
+ if (sink->fallback_buffer) {
+ gst_buffer_unref (sink->fallback_buffer);
+ sink->fallback_buffer = NULL;
+ }
}
+ if (sink->d3d.surface)
+ IDirect3DSurface9_Release (sink->d3d.surface);
+ IDirect3DSurface9_AddRef (surface);
+ sink->d3d.surface = surface;
if (!d3d_present_swap_chain (sink)) {
ret = GST_FLOW_ERROR;
diff --git a/sys/d3dvideosink/d3dhelpers.h b/sys/d3dvideosink/d3dhelpers.h
index d3467aa2c..1e2530311 100644
--- a/sys/d3dvideosink/d3dhelpers.h
+++ b/sys/d3dvideosink/d3dhelpers.h
@@ -92,7 +92,6 @@ typedef struct _GstD3DData {
gboolean device_lost;
} GstD3DData;
-
gboolean d3d_class_init(GstD3DVideoSink * klass);
void d3d_class_destroy(GstD3DVideoSink * klass);
@@ -105,4 +104,33 @@ GstFlowReturn d3d_render_buffer(GstD3DVideoSink * sink, GstBuffer * buf);
GstCaps * d3d_supported_caps(GstD3DVideoSink * sink);
gboolean d3d_set_render_format(GstD3DVideoSink * sink);
+#define GST_TYPE_D3DSURFACE_BUFFER_POOL (gst_d3dsurface_buffer_pool_get_type())
+#define GST_IS_D3DSURFACE_BUFFER_POOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_D3DSURFACE_BUFFER_POOL))
+#define GST_D3DSURFACE_BUFFER_POOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_D3DSURFACE_BUFFER_POOL, GstD3DSurfaceBufferPool))
+#define GST_D3DSURFACE_BUFFER_POOL_CAST(obj) ((GstD3DSurfaceBufferPool*)(obj))
+
+typedef struct _GstD3DSurfaceBufferPool {
+ GstVideoBufferPool parent;
+
+ GstD3DVideoSink *sink;
+ GstVideoInfo info;
+ gboolean add_metavideo;
+
+ GstAllocator *allocator;
+} GstD3DSurfaceBufferPool;
+
+typedef struct _GstD3DSurfaceBufferPoolClass {
+ GstVideoBufferPoolClass parent_class;
+} GstD3DSurfaceBufferPoolClass;
+
+GType gst_d3dsurface_meta_api_get_type (void);
+#define GST_D3DSURFACE_META_API_TYPE (gst_d3dsurface_meta_api_get_type())
+const GstMetaInfo * gst_d3dsurface_meta_get_info (void);
+#define GST_D3DSURFACE_META_INFO (gst_d3dsurface_meta_get_info())
+
+#define gst_buffer_get_d3dsurface_meta(b) ((GstD3DSurfaceMeta*)gst_buffer_get_meta((b),GST_D3DSURFACE_META_API_TYPE))
+
+GType gst_d3dsurface_buffer_pool_get_type (void);
+GstBufferPool * gst_d3dsurface_buffer_pool_new (GstD3DVideoSink * sink);
+
#endif /* _D3DHELPERS_H_ */
diff --git a/sys/d3dvideosink/d3dvideosink.c b/sys/d3dvideosink/d3dvideosink.c
index cd57b5703..5ce12eb26 100644
--- a/sys/d3dvideosink/d3dvideosink.c
+++ b/sys/d3dvideosink/d3dvideosink.c
@@ -185,6 +185,9 @@ gst_d3dvideosink_finalize (GObject * gobject)
GST_DEBUG_OBJECT (sink, " ");
+ gst_object_replace ((GstObject **) & sink->pool, NULL);
+ gst_object_replace ((GstObject **) & sink->fallback_pool, NULL);
+
gst_caps_replace (&sink->supported_caps, NULL);
g_rec_mutex_clear (&sink->lock);
@@ -274,6 +277,9 @@ gst_d3dvideosink_set_caps (GstBaseSink * bsink, GstCaps * caps)
gint display_par_n = 1, display_par_d = 1; /* display's PAR */
guint num, den;
gchar *tmp = NULL;
+ GstBufferPool *newpool, *oldpool;
+ GstBufferPool *newfbpool, *oldfbpool;
+ GstStructure *config;
GST_DEBUG_OBJECT (bsink, " ");
@@ -356,6 +362,40 @@ gst_d3dvideosink_set_caps (GstBaseSink * bsink, GstCaps * caps)
/* Create a window (or start using an application-supplied one, then connect the graph */
d3d_prepare_window (sink);
+ newpool = gst_d3dsurface_buffer_pool_new (sink);
+ config = gst_buffer_pool_get_config (newpool);
+ /* we need at least 2 buffer because we hold on to the last one */
+ gst_buffer_pool_config_set_params (config, caps, sink->info.size, 2, 0);
+ if (!gst_buffer_pool_set_config (newpool, config)) {
+ gst_object_unref (newpool);
+ GST_ERROR_OBJECT (sink, "Failed to set buffer pool configuration");
+ return FALSE;
+ }
+
+ newfbpool = gst_d3dsurface_buffer_pool_new (sink);
+ config = gst_buffer_pool_get_config (newfbpool);
+ /* we need at least 2 buffer because we hold on to the last one */
+ gst_buffer_pool_config_set_params (config, caps, sink->info.size, 2, 0);
+ /* Fallback pool must use videometa */
+ gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
+ if (!gst_buffer_pool_set_config (newfbpool, config)) {
+ gst_object_unref (newfbpool);
+ GST_ERROR_OBJECT (sink, "Failed to set buffer pool configuration");
+ return FALSE;
+ }
+
+ GST_OBJECT_LOCK (sink);
+ oldpool = sink->pool;
+ sink->pool = newpool;
+ oldfbpool = sink->fallback_pool;
+ sink->fallback_pool = newfbpool;
+ GST_OBJECT_UNLOCK (sink);
+
+ if (oldpool)
+ gst_object_unref (oldpool);
+ if (oldfbpool)
+ gst_object_unref (oldfbpool);
+
return TRUE;
/* ERRORS */
incompatible_caps:
@@ -411,8 +451,73 @@ gst_d3dvideosink_stop (GstBaseSink * bsink)
static gboolean
gst_d3dvideosink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
{
+ GstD3DVideoSink *sink = GST_D3DVIDEOSINK (bsink);
+ GstBufferPool *pool;
+ GstStructure *config;
+ GstCaps *caps;
+ guint size;
+ gboolean need_pool;
+
+ gst_query_parse_allocation (query, &caps, &need_pool);
+ if (!caps) {
+ GST_DEBUG_OBJECT (sink, "no caps specified");
+ return FALSE;
+ }
+
gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
+ GST_OBJECT_LOCK (sink);
+ pool = sink->pool ? gst_object_ref (sink->pool) : NULL;
+ GST_OBJECT_UNLOCK (sink);
+
+ if (pool) {
+ GstCaps *pcaps;
+
+ /* we had a pool, check caps */
+ GST_DEBUG_OBJECT (sink, "check existing pool caps");
+ config = gst_buffer_pool_get_config (pool);
+ gst_buffer_pool_config_get_params (config, &pcaps, &size, NULL, NULL);
+
+ if (!gst_caps_is_equal (caps, pcaps)) {
+ GST_DEBUG_OBJECT (sink, "pool has different caps");
+ /* different caps, we can't use this pool */
+ gst_object_unref (pool);
+ pool = NULL;
+ }
+ gst_structure_free (config);
+ }
+
+ if (pool == NULL && need_pool) {
+ GstVideoInfo info;
+
+ if (!gst_video_info_from_caps (&info, caps)) {
+ GST_ERROR_OBJECT (sink, "allocation query has invalid caps %"
+ GST_PTR_FORMAT, caps);
+ return FALSE;
+ }
+
+ GST_DEBUG_OBJECT (sink, "create new pool");
+ pool = gst_d3dsurface_buffer_pool_new (sink);
+
+ /* the normal size of a frame */
+ size = info.size;
+
+ config = gst_buffer_pool_get_config (pool);
+ /* we need at least 2 buffer because we hold on to the last one */
+ gst_buffer_pool_config_set_params (config, caps, size, 2, 0);
+ if (!gst_buffer_pool_set_config (pool, config)) {
+ gst_object_unref (pool);
+ GST_ERROR_OBJECT (sink, "failed to set pool configuration");
+ return FALSE;
+ }
+ }
+
+ if (pool) {
+ /* we need at least 2 buffer because we hold on to the last one */
+ gst_query_add_allocation_pool (query, pool, size, 2, 0);
+ gst_object_unref (pool);
+ }
+
return TRUE;
}
diff --git a/sys/d3dvideosink/d3dvideosink.h b/sys/d3dvideosink/d3dvideosink.h
index 453169914..2ec2908b0 100644
--- a/sys/d3dvideosink/d3dvideosink.h
+++ b/sys/d3dvideosink/d3dvideosink.h
@@ -52,6 +52,9 @@ struct _GstD3DVideoSink
GstVideoInfo info;
gint width;
gint height;
+ GstBufferPool *pool;
+ GstBufferPool *fallback_pool;
+ GstBuffer *fallback_buffer;
GstVideoRectangle render_rect;