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) {
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;
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 =
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
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);