struct _GstD3D11Download
{
GstD3D11BaseFilter parent;
+
+ GstBuffer *staging_buffer;
};
#define gst_d3d11_download_parent_class parent_class
G_DEFINE_TYPE (GstD3D11Download, gst_d3d11_download,
GST_TYPE_D3D11_BASE_FILTER);
+static void gst_d3d11_download_dispose (GObject * object);
+static gboolean gst_d3d11_download_stop (GstBaseTransform * trans);
+static gboolean gst_d3d11_download_sink_event (GstBaseTransform * trans,
+ GstEvent * event);
static GstCaps *gst_d3d11_download_transform_caps (GstBaseTransform * trans,
GstPadDirection direction, GstCaps * caps, GstCaps * filter);
static gboolean gst_d3d11_download_propose_allocation (GstBaseTransform * trans,
GstQuery * query);
static GstFlowReturn gst_d3d11_download_transform (GstBaseTransform * trans,
GstBuffer * inbuf, GstBuffer * outbuf);
+static gboolean gst_d3d11_download_set_info (GstD3D11BaseFilter * filter,
+ GstCaps * incaps, GstVideoInfo * in_info, GstCaps * outcaps,
+ GstVideoInfo * out_info);
static void
gst_d3d11_download_class_init (GstD3D11DownloadClass * klass)
{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
GstBaseTransformClass *trans_class = GST_BASE_TRANSFORM_CLASS (klass);
+ GstD3D11BaseFilterClass *bfilter_class = GST_D3D11_BASE_FILTER_CLASS (klass);
+
+ gobject_class->dispose = gst_d3d11_download_dispose;
gst_element_class_add_static_pad_template (element_class, &sink_template);
gst_element_class_add_static_pad_template (element_class, &src_template);
trans_class->passthrough_on_same_caps = TRUE;
+ trans_class->stop = GST_DEBUG_FUNCPTR (gst_d3d11_download_stop);
+ trans_class->sink_event = GST_DEBUG_FUNCPTR (gst_d3d11_download_sink_event);
trans_class->transform_caps =
GST_DEBUG_FUNCPTR (gst_d3d11_download_transform_caps);
trans_class->propose_allocation =
GST_DEBUG_FUNCPTR (gst_d3d11_download_decide_allocation);
trans_class->transform = GST_DEBUG_FUNCPTR (gst_d3d11_download_transform);
+ bfilter_class->set_info = GST_DEBUG_FUNCPTR (gst_d3d11_download_set_info);
+
GST_DEBUG_CATEGORY_INIT (gst_d3d11_download_debug,
"d3d11download", 0, "d3d11download Element");
}
{
}
+static void
+gst_d3d11_download_dispose (GObject * object)
+{
+ GstD3D11Download *self = GST_D3D11_DOWNLOAD (object);
+
+ gst_clear_buffer (&self->staging_buffer);
+
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static gboolean
+gst_d3d11_download_stop (GstBaseTransform * trans)
+{
+ GstD3D11Download *self = GST_D3D11_DOWNLOAD (trans);
+
+ gst_clear_buffer (&self->staging_buffer);
+
+ return GST_BASE_TRANSFORM_CLASS (parent_class)->stop (trans);
+}
+
+static gboolean
+gst_d3d11_download_sink_event (GstBaseTransform * trans, GstEvent * event)
+{
+ GstD3D11Download *self = GST_D3D11_DOWNLOAD (trans);
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_EOS:
+ /* We don't need to hold this staging buffer after eos */
+ gst_clear_buffer (&self->staging_buffer);
+ break;
+ default:
+ break;
+ }
+
+ return GST_BASE_TRANSFORM_CLASS (parent_class)->sink_event (trans, event);
+}
+
static GstCaps *
_set_caps_features (const GstCaps * caps, const gchar * feature_name)
{
query);
}
+static gboolean
+gst_d3d11_download_can_use_staging_buffer (GstD3D11Download * self,
+ GstBuffer * inbuf)
+{
+ GstD3D11BaseFilter *filter = GST_D3D11_BASE_FILTER (self);
+ gint i;
+
+ /* staging buffer doesn't need to be used for non-d3d11 memory */
+ for (i = 0; i < gst_buffer_n_memory (inbuf); i++) {
+ GstMemory *mem = gst_buffer_peek_memory (inbuf, i);
+
+ if (!gst_is_d3d11_memory (mem))
+ return FALSE;
+ }
+
+ if (self->staging_buffer)
+ return TRUE;
+
+ self->staging_buffer = gst_d3d11_allocate_staging_buffer_for (inbuf,
+ &filter->in_info, TRUE);
+
+ if (!self->staging_buffer) {
+ GST_WARNING_OBJECT (self, "Couldn't allocate staging buffer");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
static GstFlowReturn
gst_d3d11_download_transform (GstBaseTransform * trans, GstBuffer * inbuf,
GstBuffer * outbuf)
{
GstD3D11BaseFilter *filter = GST_D3D11_BASE_FILTER (trans);
+ GstD3D11Download *self = GST_D3D11_DOWNLOAD (trans);
GstVideoFrame in_frame, out_frame;
+ GstFlowReturn ret = GST_FLOW_OK;
+ gboolean use_staging_buf;
+ GstBuffer *target_inbuf = inbuf;
gint i;
- if (!gst_video_frame_map (&in_frame, &filter->in_info, inbuf,
+ use_staging_buf = gst_d3d11_download_can_use_staging_buffer (self, inbuf);
+
+ if (use_staging_buf) {
+ GST_TRACE_OBJECT (self, "Copy input buffer to staging buffer");
+
+ /* Copy d3d11 texture to staging texture */
+ if (!gst_d3d11_buffer_copy_into (self->staging_buffer, inbuf)) {
+ GST_ERROR_OBJECT (self,
+ "Failed to copy input buffer into staging texture");
+ return GST_FLOW_ERROR;
+ }
+
+ target_inbuf = self->staging_buffer;
+ }
+
+ if (!gst_video_frame_map (&in_frame, &filter->in_info, target_inbuf,
GST_MAP_READ | GST_VIDEO_FRAME_MAP_FLAG_NO_REF))
goto invalid_buffer;
for (i = 0; i < GST_VIDEO_FRAME_N_PLANES (&in_frame); i++) {
if (!gst_video_frame_copy_plane (&out_frame, &in_frame, i)) {
GST_ERROR_OBJECT (filter, "Couldn't copy %dth plane", i);
- return GST_FLOW_ERROR;
+ ret = GST_FLOW_ERROR;
+ break;
}
}
gst_video_frame_unmap (&out_frame);
gst_video_frame_unmap (&in_frame);
- return GST_FLOW_OK;
+ return ret;
/* ERRORS */
invalid_buffer:
return GST_FLOW_ERROR;
}
}
+
+static gboolean
+gst_d3d11_download_set_info (GstD3D11BaseFilter * filter,
+ GstCaps * incaps, GstVideoInfo * in_info, GstCaps * outcaps,
+ GstVideoInfo * out_info)
+{
+ GstD3D11Download *self = GST_D3D11_DOWNLOAD (filter);
+
+ gst_clear_buffer (&self->staging_buffer);
+
+ return TRUE;
+}
struct _GstD3D11Upload
{
GstD3D11BaseFilter parent;
+
+ GstBuffer *staging_buffer;
};
#define gst_d3d11_upload_parent_class parent_class
G_DEFINE_TYPE (GstD3D11Upload, gst_d3d11_upload, GST_TYPE_D3D11_BASE_FILTER);
+static void gst_d3d11_upload_dispose (GObject * object);
+static gboolean gst_d3d11_upload_stop (GstBaseTransform * trans);
+static gboolean gst_d3d11_upload_sink_event (GstBaseTransform * trans,
+ GstEvent * event);
static GstCaps *gst_d3d11_upload_transform_caps (GstBaseTransform * trans,
GstPadDirection direction, GstCaps * caps, GstCaps * filter);
static gboolean gst_d3d11_upload_propose_allocation (GstBaseTransform * trans,
GstQuery * query);
static GstFlowReturn gst_d3d11_upload_transform (GstBaseTransform * trans,
GstBuffer * inbuf, GstBuffer * outbuf);
+static gboolean gst_d3d11_upload_set_info (GstD3D11BaseFilter * filter,
+ GstCaps * incaps, GstVideoInfo * in_info, GstCaps * outcaps,
+ GstVideoInfo * out_info);
static void
gst_d3d11_upload_class_init (GstD3D11UploadClass * klass)
{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
GstBaseTransformClass *trans_class = GST_BASE_TRANSFORM_CLASS (klass);
+ GstD3D11BaseFilterClass *bfilter_class = GST_D3D11_BASE_FILTER_CLASS (klass);
+
+ gobject_class->dispose = gst_d3d11_upload_dispose;
gst_element_class_add_static_pad_template (element_class, &sink_template);
gst_element_class_add_static_pad_template (element_class, &src_template);
trans_class->passthrough_on_same_caps = TRUE;
+ trans_class->stop = GST_DEBUG_FUNCPTR (gst_d3d11_upload_stop);
+ trans_class->sink_event = GST_DEBUG_FUNCPTR (gst_d3d11_upload_sink_event);
trans_class->transform_caps =
GST_DEBUG_FUNCPTR (gst_d3d11_upload_transform_caps);
trans_class->propose_allocation =
GST_DEBUG_FUNCPTR (gst_d3d11_upload_decide_allocation);
trans_class->transform = GST_DEBUG_FUNCPTR (gst_d3d11_upload_transform);
+ bfilter_class->set_info = GST_DEBUG_FUNCPTR (gst_d3d11_upload_set_info);
+
GST_DEBUG_CATEGORY_INIT (gst_d3d11_upload_debug,
"d3d11upload", 0, "d3d11upload Element");
}
{
}
+static void
+gst_d3d11_upload_dispose (GObject * object)
+{
+ GstD3D11Upload *self = GST_D3D11_UPLOAD (object);
+
+ gst_clear_buffer (&self->staging_buffer);
+
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static gboolean
+gst_d3d11_upload_stop (GstBaseTransform * trans)
+{
+ GstD3D11Upload *self = GST_D3D11_UPLOAD (trans);
+
+ gst_clear_buffer (&self->staging_buffer);
+
+ return GST_BASE_TRANSFORM_CLASS (parent_class)->stop (trans);
+}
+
+static gboolean
+gst_d3d11_upload_sink_event (GstBaseTransform * trans, GstEvent * event)
+{
+ GstD3D11Upload *self = GST_D3D11_UPLOAD (trans);
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_EOS:
+ /* We don't need to hold this staging buffer after eos */
+ gst_clear_buffer (&self->staging_buffer);
+ break;
+ default:
+ break;
+ }
+
+ return GST_BASE_TRANSFORM_CLASS (parent_class)->sink_event (trans, event);
+}
+
static GstCaps *
_set_caps_features (const GstCaps * caps, const gchar * feature_name)
{
query);
}
+static gboolean
+gst_d3d11_upload_can_use_staging_buffer (GstD3D11Upload * self,
+ GstBuffer * outbuf)
+{
+ GstD3D11BaseFilter *filter = GST_D3D11_BASE_FILTER (self);
+ gint i;
+
+ /* staging buffer doesn't need to be used for non-d3d11 memory */
+ for (i = 0; i < gst_buffer_n_memory (outbuf); i++) {
+ GstMemory *mem = gst_buffer_peek_memory (outbuf, i);
+
+ if (!gst_is_d3d11_memory (mem))
+ return FALSE;
+ }
+
+ if (self->staging_buffer)
+ return TRUE;
+
+ self->staging_buffer = gst_d3d11_allocate_staging_buffer_for (outbuf,
+ &filter->out_info, TRUE);
+
+ if (!self->staging_buffer) {
+ GST_WARNING_OBJECT (self, "Couldn't allocate staging buffer");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
static GstFlowReturn
gst_d3d11_upload_transform (GstBaseTransform * trans, GstBuffer * inbuf,
GstBuffer * outbuf)
{
GstD3D11BaseFilter *filter = GST_D3D11_BASE_FILTER (trans);
-
+ GstD3D11Upload *self = GST_D3D11_UPLOAD (trans);
GstVideoFrame in_frame, out_frame;
- gint i;
GstFlowReturn ret = GST_FLOW_OK;
+ gboolean use_staging_buf;
+ GstBuffer *target_outbuf = outbuf;
+ gint i;
+
+ use_staging_buf = gst_d3d11_upload_can_use_staging_buffer (self, outbuf);
+
+ if (use_staging_buf) {
+ GST_TRACE_OBJECT (self, "Copy input buffer to staging buffer");
+ target_outbuf = self->staging_buffer;
+ }
if (!gst_video_frame_map (&in_frame, &filter->in_info, inbuf,
GST_MAP_READ | GST_VIDEO_FRAME_MAP_FLAG_NO_REF))
goto invalid_buffer;
- if (!gst_video_frame_map (&out_frame, &filter->out_info, outbuf,
+ if (!gst_video_frame_map (&out_frame, &filter->out_info, target_outbuf,
GST_MAP_WRITE | GST_VIDEO_FRAME_MAP_FLAG_NO_REF)) {
gst_video_frame_unmap (&in_frame);
goto invalid_buffer;
for (i = 0; i < GST_VIDEO_FRAME_N_PLANES (&in_frame); i++) {
if (!gst_video_frame_copy_plane (&out_frame, &in_frame, i)) {
- GST_ERROR_OBJECT (filter, "Couldn't copy %dth plane", i);
+ GST_ERROR_OBJECT (filter, "Couldn't copy plane %d", i);
ret = GST_FLOW_ERROR;
break;
}
gst_video_frame_unmap (&out_frame);
gst_video_frame_unmap (&in_frame);
+ /* Copy staging texture to d3d11 texture */
+ if (use_staging_buf) {
+ if (!gst_d3d11_buffer_copy_into (outbuf, self->staging_buffer)) {
+ GST_ERROR_OBJECT (self, "Cannot copy staging texture into texture");
+ return GST_FLOW_ERROR;
+ }
+ }
+
return ret;
/* ERRORS */
return GST_FLOW_ERROR;
}
}
+
+static gboolean
+gst_d3d11_upload_set_info (GstD3D11BaseFilter * filter,
+ GstCaps * incaps, GstVideoInfo * in_info, GstCaps * outcaps,
+ GstVideoInfo * out_info)
+{
+ GstD3D11Upload *self = GST_D3D11_UPLOAD (filter);
+
+ gst_clear_buffer (&self->staging_buffer);
+
+ return TRUE;
+}
return NULL;
}
+GstBuffer *
+gst_d3d11_allocate_staging_buffer_for (GstBuffer * buffer,
+ const GstVideoInfo * info, gboolean add_videometa)
+{
+ GstD3D11Memory *dmem;
+ GstD3D11Device *device;
+ GstD3D11AllocationParams *params = NULL;
+ GstD3D11Allocator *alloc = NULL;
+ GstBuffer *staging_buffer = NULL;
+ D3D11_TEXTURE2D_DESC *desc;
+ gint i;
+
+ for (i = 0; i < gst_buffer_n_memory (buffer); i++) {
+ GstMemory *mem = gst_buffer_peek_memory (buffer, i);
+
+ if (!gst_is_d3d11_memory (mem)) {
+ GST_DEBUG ("Not a d3d11 memory");
+
+ return NULL;
+ }
+ }
+
+ dmem = (GstD3D11Memory *) gst_buffer_peek_memory (buffer, 0);
+ device = dmem->device;
+
+ params = gst_d3d11_allocation_params_new (device, (GstVideoInfo *) info,
+ 0, 0);
+
+ if (!params) {
+ GST_WARNING ("Couldn't create alloc params");
+ goto done;
+ }
+
+ desc = ¶ms->desc[0];
+ /* resolution of semi-planar formats must be multiple of 2 */
+ if (desc[0].Format == DXGI_FORMAT_NV12 || desc[0].Format == DXGI_FORMAT_P010
+ || desc[0].Format == DXGI_FORMAT_P016) {
+ if (desc[0].Width % 2 || desc[0].Height % 2) {
+ gint width, height;
+ GstVideoAlignment align;
+
+ width = GST_ROUND_UP_2 (desc[0].Width);
+ height = GST_ROUND_UP_2 (desc[0].Height);
+
+ gst_video_alignment_reset (&align);
+ align.padding_right = width - desc[0].Width;
+ align.padding_bottom = height - desc[0].Height;
+
+ gst_d3d11_allocation_params_alignment (params, &align);
+ }
+ }
+
+ alloc = gst_d3d11_allocator_new (device);
+ if (!alloc) {
+ GST_WARNING ("Couldn't create allocator");
+ goto done;
+ }
+
+ staging_buffer = gst_d3d11_allocate_staging_buffer (alloc,
+ info, params->d3d11_format, params->desc, add_videometa);
+
+ if (!staging_buffer)
+ GST_WARNING ("Couldn't allocate staging buffer");
+
+done:
+ if (params)
+ gst_d3d11_allocation_params_free (params);
+
+ if (alloc)
+ gst_object_unref (alloc);
+
+ return staging_buffer;
+}
+
gboolean
_gst_d3d11_result (HRESULT hr, GstD3D11Device * device, GstDebugCategory * cat,
const gchar * file, const gchar * function, gint line)
return SUCCEEDED (hr);
#endif
}
+
+gboolean
+gst_d3d11_buffer_copy_into (GstBuffer * dst, GstBuffer * src)
+{
+ guint i;
+ guint num_mem;
+
+ g_return_val_if_fail (GST_IS_BUFFER (dst), FALSE);
+ g_return_val_if_fail (GST_IS_BUFFER (src), FALSE);
+
+ num_mem = gst_buffer_n_memory (dst);
+ if (num_mem != gst_buffer_n_memory (src)) {
+ GST_WARNING ("different num memory");
+ return FALSE;
+ }
+
+ for (i = 0; i < num_mem; i++) {
+ GstMemory *dst_mem, *src_mem;
+ GstD3D11Memory *dst_dmem, *src_dmem;
+ GstMapInfo dst_info;
+ GstMapInfo src_info;
+ ID3D11Resource *dst_texture, *src_texture;
+ ID3D11DeviceContext *device_context;
+ GstD3D11Device *device;
+ D3D11_BOX src_box = { 0, };
+
+ dst_mem = gst_buffer_peek_memory (dst, i);
+ src_mem = gst_buffer_peek_memory (src, i);
+
+ if (!gst_is_d3d11_memory (dst_mem)) {
+ GST_WARNING ("dst memory is not d3d11");
+ return FALSE;
+ }
+
+ if (!gst_is_d3d11_memory (src_mem)) {
+ GST_WARNING ("src memory is not d3d11");
+ return FALSE;
+ }
+
+ dst_dmem = (GstD3D11Memory *) dst_mem;
+ src_dmem = (GstD3D11Memory *) src_mem;
+
+ device = dst_dmem->device;
+ if (device != src_dmem->device) {
+ GST_WARNING ("different device");
+ return FALSE;
+ }
+
+ if (dst_dmem->desc.Format != src_dmem->desc.Format) {
+ GST_WARNING ("different dxgi format");
+ return FALSE;
+ }
+
+ device_context = gst_d3d11_device_get_device_context_handle (device);
+
+ if (!gst_memory_map (dst_mem, &dst_info, GST_MAP_WRITE | GST_MAP_D3D11)) {
+ GST_ERROR ("Cannot map dst d3d11 memory");
+ return FALSE;
+ }
+
+ if (!gst_memory_map (src_mem, &src_info, GST_MAP_READ | GST_MAP_D3D11)) {
+ GST_ERROR ("Cannot map src d3d11 memory");
+ gst_memory_unmap (dst_mem, &dst_info);
+ return FALSE;
+ }
+
+ dst_texture = (ID3D11Resource *) dst_info.data;
+ src_texture = (ID3D11Resource *) src_info.data;
+
+ /* src/dst texture size might be different if padding was used.
+ * select smaller size */
+ src_box.left = 0;
+ src_box.top = 0;
+ src_box.front = 0;
+ src_box.back = 1;
+ src_box.right = MIN (src_dmem->desc.Width, dst_dmem->desc.Width);
+ src_box.bottom = MIN (src_dmem->desc.Height, dst_dmem->desc.Height);
+
+ gst_d3d11_device_lock (device);
+ ID3D11DeviceContext_CopySubresourceRegion (device_context,
+ dst_texture, dst_dmem->subresource_index, 0, 0, 0,
+ src_texture, src_dmem->subresource_index, &src_box);
+ gst_d3d11_device_unlock (device);
+
+ gst_memory_unmap (src_mem, &src_info);
+ gst_memory_unmap (dst_mem, &dst_info);
+ }
+
+ return TRUE;
+}
const D3D11_TEXTURE2D_DESC desc[GST_VIDEO_MAX_PLANES],
gboolean add_videometa);
+GstBuffer * gst_d3d11_allocate_staging_buffer_for (GstBuffer * buffer,
+ const GstVideoInfo * info,
+ gboolean add_videometa);
+
+gboolean gst_d3d11_buffer_copy_into (GstBuffer * dst,
+ GstBuffer * src);
+
gboolean _gst_d3d11_result (HRESULT hr,
GstD3D11Device * device,
GstDebugCategory * cat,