mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-19 16:21:17 +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;
|
||||
}
|
||||
|
||||
/* 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
|
||||
gst_d3dsurface_buffer_pool_set_config (GstBufferPool * bpool,
|
||||
GstStructure * config)
|
||||
{
|
||||
GstD3DSurfaceBufferPool *pool = GST_D3DSURFACE_BUFFER_POOL_CAST (bpool);
|
||||
GstD3DVideoSink *sink = pool->sink;
|
||||
GstD3DVideoSinkClass *klass = GST_D3DVIDEOSINK_GET_CLASS (sink);
|
||||
GstCaps *caps;
|
||||
GstVideoInfo info;
|
||||
|
||||
if (!GST_BUFFER_POOL_CLASS
|
||||
(gst_d3dsurface_buffer_pool_parent_class)->set_config (bpool, config)) {
|
||||
return FALSE;
|
||||
}
|
||||
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;
|
||||
|
||||
if (!gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL)
|
||||
|| !caps) {
|
||||
|
@ -544,8 +623,8 @@ gst_d3dsurface_buffer_pool_set_config (GstBufferPool * bpool,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
if (gst_video_format_to_d3d_format (GST_VIDEO_INFO_FORMAT (&info)) ==
|
||||
D3DFMT_UNKNOWN) {
|
||||
d3dformat = gst_video_format_to_d3d_format (GST_VIDEO_INFO_FORMAT (&info));
|
||||
if (d3dformat == D3DFMT_UNKNOWN) {
|
||||
GST_ERROR_OBJECT (pool, "Unsupported video format in caps %" GST_PTR_FORMAT,
|
||||
caps);
|
||||
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,
|
||||
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->add_metavideo =
|
||||
|
@ -566,7 +672,10 @@ gst_d3dsurface_buffer_pool_set_config (GstBufferPool * bpool,
|
|||
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
|
||||
|
@ -609,68 +718,11 @@ gst_d3dsurface_buffer_pool_alloc_buffer (GstBufferPool * bpool,
|
|||
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;
|
||||
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;
|
||||
if (!d3d_calculate_buffer_size (&pool->info, &lr, offset, stride, &size)) {
|
||||
GST_ERROR_OBJECT (sink, "Failed to get buffer size");
|
||||
IDirect3DSurface9_UnlockRect (surface);
|
||||
IDirect3DSurface9_Release (surface);
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
IDirect3DSurface9_UnlockRect (surface);
|
||||
|
|
Loading…
Reference in a new issue