mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-01 21:18:52 +00:00
d3dvideosink: Set actual buffer size to buffer pool
If configured size of buffer pool and actual buffer size are mismatched, pool will do unwanted buffer resize. Fixes #801
This commit is contained in:
parent
dee5201392
commit
6c6d351665
1 changed files with 122 additions and 70 deletions
|
@ -519,18 +519,97 @@ gst_d3dsurface_buffer_pool_get_options (GstBufferPool * pool)
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Calculate actual required buffer size from D3DLOCKED_RECT structure.
|
||||||
|
* Note that D3D could require larger Pitch value than minimum required one in theory.
|
||||||
|
* See also
|
||||||
|
* https://docs.microsoft.com/en-us/windows/desktop/direct3d9/width-vs--pitch */
|
||||||
|
static gboolean
|
||||||
|
d3d_calculate_buffer_size (GstVideoInfo * info, D3DLOCKED_RECT * lr,
|
||||||
|
gsize * offset, gint * stride, gsize * size)
|
||||||
|
{
|
||||||
|
switch (GST_VIDEO_INFO_FORMAT (info)) {
|
||||||
|
case GST_VIDEO_FORMAT_BGR:
|
||||||
|
offset[0] = 0;
|
||||||
|
stride[0] = lr->Pitch;
|
||||||
|
*size = lr->Pitch * GST_VIDEO_INFO_HEIGHT (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 (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 (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 (info) * 2;
|
||||||
|
break;
|
||||||
|
case GST_VIDEO_FORMAT_I420:
|
||||||
|
case GST_VIDEO_FORMAT_YV12:
|
||||||
|
offset[0] = 0;
|
||||||
|
stride[0] = lr->Pitch;
|
||||||
|
if (GST_VIDEO_INFO_FORMAT (info) == GST_VIDEO_FORMAT_YV12) {
|
||||||
|
offset[1] =
|
||||||
|
offset[0] + stride[0] * GST_VIDEO_INFO_COMP_HEIGHT (info, 0);
|
||||||
|
stride[1] = lr->Pitch / 2;
|
||||||
|
offset[2] =
|
||||||
|
offset[1] + stride[1] * GST_VIDEO_INFO_COMP_HEIGHT (info, 1);
|
||||||
|
stride[2] = lr->Pitch / 2;
|
||||||
|
*size = offset[2] + stride[2] * GST_VIDEO_INFO_COMP_HEIGHT (info, 2);
|
||||||
|
} else {
|
||||||
|
offset[2] =
|
||||||
|
offset[0] + stride[0] * GST_VIDEO_INFO_COMP_HEIGHT (info, 0);
|
||||||
|
stride[2] = lr->Pitch / 2;
|
||||||
|
offset[1] =
|
||||||
|
offset[2] + stride[2] * GST_VIDEO_INFO_COMP_HEIGHT (info, 2);
|
||||||
|
stride[1] = lr->Pitch / 2;
|
||||||
|
*size = offset[1] + stride[1] * GST_VIDEO_INFO_COMP_HEIGHT (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 (info, 0);
|
||||||
|
stride[1] = lr->Pitch;
|
||||||
|
*size = offset[1] + stride[1] * GST_VIDEO_INFO_COMP_HEIGHT (info, 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_LOG ("Calculated buffer size: %" G_GSIZE_FORMAT
|
||||||
|
" (%s %dx%d, Pitch %d)", *size,
|
||||||
|
gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (info)),
|
||||||
|
GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info), lr->Pitch);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_d3dsurface_buffer_pool_set_config (GstBufferPool * bpool,
|
gst_d3dsurface_buffer_pool_set_config (GstBufferPool * bpool,
|
||||||
GstStructure * config)
|
GstStructure * config)
|
||||||
{
|
{
|
||||||
GstD3DSurfaceBufferPool *pool = GST_D3DSURFACE_BUFFER_POOL_CAST (bpool);
|
GstD3DSurfaceBufferPool *pool = GST_D3DSURFACE_BUFFER_POOL_CAST (bpool);
|
||||||
|
GstD3DVideoSink *sink = pool->sink;
|
||||||
|
GstD3DVideoSinkClass *klass = GST_D3DVIDEOSINK_GET_CLASS (sink);
|
||||||
GstCaps *caps;
|
GstCaps *caps;
|
||||||
GstVideoInfo info;
|
GstVideoInfo info;
|
||||||
|
LPDIRECT3DSURFACE9 surface;
|
||||||
if (!GST_BUFFER_POOL_CLASS
|
D3DFORMAT d3dformat;
|
||||||
(gst_d3dsurface_buffer_pool_parent_class)->set_config (bpool, config)) {
|
gint stride[GST_VIDEO_MAX_PLANES] = { 0, };
|
||||||
return FALSE;
|
gsize offset[GST_VIDEO_MAX_PLANES] = { 0, };
|
||||||
}
|
D3DLOCKED_RECT lr;
|
||||||
|
HRESULT hr;
|
||||||
|
gsize size;
|
||||||
|
|
||||||
if (!gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL)
|
if (!gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL)
|
||||||
|| !caps) {
|
|| !caps) {
|
||||||
|
@ -544,8 +623,8 @@ gst_d3dsurface_buffer_pool_set_config (GstBufferPool * bpool,
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gst_video_format_to_d3d_format (GST_VIDEO_INFO_FORMAT (&info)) ==
|
d3dformat = gst_video_format_to_d3d_format (GST_VIDEO_INFO_FORMAT (&info));
|
||||||
D3DFMT_UNKNOWN) {
|
if (d3dformat == D3DFMT_UNKNOWN) {
|
||||||
GST_ERROR_OBJECT (pool, "Unsupported video format in caps %" GST_PTR_FORMAT,
|
GST_ERROR_OBJECT (pool, "Unsupported video format in caps %" GST_PTR_FORMAT,
|
||||||
caps);
|
caps);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -554,6 +633,33 @@ gst_d3dsurface_buffer_pool_set_config (GstBufferPool * bpool,
|
||||||
GST_LOG_OBJECT (pool, "%dx%d, caps %" GST_PTR_FORMAT, info.width, info.height,
|
GST_LOG_OBJECT (pool, "%dx%d, caps %" GST_PTR_FORMAT, info.width, info.height,
|
||||||
caps);
|
caps);
|
||||||
|
|
||||||
|
/* Create a surface to get exact buffer size */
|
||||||
|
hr = IDirect3DDevice9_CreateOffscreenPlainSurface (klass->d3d.
|
||||||
|
device.d3d_device, GST_VIDEO_INFO_WIDTH (&info),
|
||||||
|
GST_VIDEO_INFO_HEIGHT (&info), d3dformat, D3DPOOL_DEFAULT, &surface,
|
||||||
|
NULL);
|
||||||
|
if (hr != D3D_OK) {
|
||||||
|
GST_ERROR_OBJECT (sink, "Failed to create D3D surface");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
IDirect3DSurface9_LockRect (surface, &lr, NULL, 0);
|
||||||
|
if (!lr.pBits) {
|
||||||
|
GST_ERROR_OBJECT (sink, "Failed to lock D3D surface");
|
||||||
|
IDirect3DSurface9_Release (surface);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!d3d_calculate_buffer_size (&info, &lr, offset, stride, &size)) {
|
||||||
|
GST_ERROR_OBJECT (sink, "Failed to get buffer size");
|
||||||
|
IDirect3DSurface9_UnlockRect (surface);
|
||||||
|
IDirect3DSurface9_Release (surface);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
IDirect3DSurface9_UnlockRect (surface);
|
||||||
|
IDirect3DSurface9_Release (surface);
|
||||||
|
|
||||||
pool->info = info;
|
pool->info = info;
|
||||||
|
|
||||||
pool->add_metavideo =
|
pool->add_metavideo =
|
||||||
|
@ -566,7 +672,10 @@ gst_d3dsurface_buffer_pool_set_config (GstBufferPool * bpool,
|
||||||
gst_object_ref_sink (pool->allocator);
|
gst_object_ref_sink (pool->allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
gst_buffer_pool_config_set_params (config, caps, size, 2, 0);
|
||||||
|
|
||||||
|
return GST_BUFFER_POOL_CLASS
|
||||||
|
(gst_d3dsurface_buffer_pool_parent_class)->set_config (bpool, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
|
@ -609,68 +718,11 @@ gst_d3dsurface_buffer_pool_alloc_buffer (GstBufferPool * bpool,
|
||||||
goto fallback;
|
goto fallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (GST_VIDEO_INFO_FORMAT (&pool->info)) {
|
if (!d3d_calculate_buffer_size (&pool->info, &lr, offset, stride, &size)) {
|
||||||
case GST_VIDEO_FORMAT_BGR:
|
GST_ERROR_OBJECT (sink, "Failed to get buffer size");
|
||||||
offset[0] = 0;
|
IDirect3DSurface9_UnlockRect (surface);
|
||||||
stride[0] = lr.Pitch;
|
IDirect3DSurface9_Release (surface);
|
||||||
size = lr.Pitch * GST_VIDEO_INFO_HEIGHT (&pool->info) * 3;
|
return GST_FLOW_ERROR;
|
||||||
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;
|
|
||||||
if (GST_VIDEO_INFO_FORMAT (&pool->info) == GST_VIDEO_FORMAT_YV12) {
|
|
||||||
offset[1] =
|
|
||||||
offset[0] + stride[0] * GST_VIDEO_INFO_COMP_HEIGHT (&pool->info, 0);
|
|
||||||
stride[1] = lr.Pitch / 2;
|
|
||||||
offset[2] =
|
|
||||||
offset[1] + stride[1] * GST_VIDEO_INFO_COMP_HEIGHT (&pool->info, 1);
|
|
||||||
stride[2] = lr.Pitch / 2;
|
|
||||||
size =
|
|
||||||
offset[2] + stride[2] * GST_VIDEO_INFO_COMP_HEIGHT (&pool->info, 2);
|
|
||||||
} else {
|
|
||||||
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);
|
IDirect3DSurface9_UnlockRect (surface);
|
||||||
|
|
Loading…
Reference in a new issue