1 /* GStreamer
2 * Copyright (C) 2020 Seungha Yang <seungha@centricular.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 /**
21 * SECTION:element-d3d11vp8dec
22 * @title: d3d11vp8dec
23 *
24 * A Direct3D11/DXVA based VP8 video decoder
25 *
26 * ## Example launch line
27 * ```
28 * gst-launch-1.0 filesrc location=/path/to/vp8/file ! parsebin ! d3d11vp8dec ! d3d11videosink
29 * ```
30 *
31 * Since: 1.18
32 *
33 */
34
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #include "gstd3d11vp8dec.h"
40
41 #include <gst/codecs/gstvp8decoder.h>
42 #include <string.h>
43 #include <vector>
44
45 /* HACK: to expose dxva data structure on UWP */
46 #ifdef WINAPI_PARTITION_DESKTOP
47 #undef WINAPI_PARTITION_DESKTOP
48 #endif
49 #define WINAPI_PARTITION_DESKTOP 1
50 #include <d3d9.h>
51 #include <dxva.h>
52
53 GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_vp8_dec_debug);
54 #define GST_CAT_DEFAULT gst_d3d11_vp8_dec_debug
55
56 /* reference list 4 + 4 margin */
57 #define NUM_OUTPUT_VIEW 8
58
59 /* *INDENT-OFF* */
60 typedef struct _GstD3D11Vp8DecInner
61 {
62 GstD3D11Device *device = nullptr;
63 GstD3D11Decoder *d3d11_decoder = nullptr;
64
65 DXVA_PicParams_VP8 pic_params;
66 DXVA_Slice_VPx_Short slice;
67
68 /* In case of VP8, there's only one slice per picture so we don't
69 * need this bitstream buffer, but this will be used for 128 bytes alignment */
70 std::vector<guint8> bitstream_buffer;
71
72 guint width = 0;
73 guint height = 0;
74 GstVideoFormat out_format = GST_VIDEO_FORMAT_UNKNOWN;
75 } GstD3D11Vp8DecInner;
76 /* *INDENT-ON* */
77
78 typedef struct _GstD3D11Vp8Dec
79 {
80 GstVp8Decoder parent;
81 GstD3D11Vp8DecInner *inner;
82 } GstD3D11Vp8Dec;
83
84 typedef struct _GstD3D11Vp8DecClass
85 {
86 GstVp8DecoderClass parent_class;
87 GstD3D11DecoderSubClassData class_data;
88 } GstD3D11Vp8DecClass;
89
90 static GstElementClass *parent_class = NULL;
91
92 #define GST_D3D11_VP8_DEC(object) ((GstD3D11Vp8Dec *) (object))
93 #define GST_D3D11_VP8_DEC_GET_CLASS(object) \
94 (G_TYPE_INSTANCE_GET_CLASS ((object),G_TYPE_FROM_INSTANCE (object),GstD3D11Vp8DecClass))
95
96 static void gst_d3d11_vp8_dec_get_property (GObject * object,
97 guint prop_id, GValue * value, GParamSpec * pspec);
98 static void gst_d3d11_vp8_dec_finalize (GObject * object);
99 static void gst_d3d11_vp8_dec_set_context (GstElement * element,
100 GstContext * context);
101
102 static gboolean gst_d3d11_vp8_dec_open (GstVideoDecoder * decoder);
103 static gboolean gst_d3d11_vp8_dec_close (GstVideoDecoder * decoder);
104 static gboolean gst_d3d11_vp8_dec_negotiate (GstVideoDecoder * decoder);
105 static gboolean gst_d3d11_vp8_dec_decide_allocation (GstVideoDecoder *
106 decoder, GstQuery * query);
107 static gboolean gst_d3d11_vp8_dec_src_query (GstVideoDecoder * decoder,
108 GstQuery * query);
109 static gboolean gst_d3d11_vp8_sink_event (GstVideoDecoder * decoder,
110 GstEvent * event);
111
112 /* GstVp8Decoder */
113 static GstFlowReturn gst_d3d11_vp8_dec_new_sequence (GstVp8Decoder * decoder,
114 const GstVp8FrameHdr * frame_hdr);
115 static GstFlowReturn gst_d3d11_vp8_dec_new_picture (GstVp8Decoder * decoder,
116 GstVideoCodecFrame * frame, GstVp8Picture * picture);
117 static GstFlowReturn gst_d3d11_vp8_dec_start_picture (GstVp8Decoder * decoder,
118 GstVp8Picture * picture);
119 static GstFlowReturn gst_d3d11_vp8_dec_decode_picture (GstVp8Decoder * decoder,
120 GstVp8Picture * picture, GstVp8Parser * parser);
121 static GstFlowReturn gst_d3d11_vp8_dec_end_picture (GstVp8Decoder * decoder,
122 GstVp8Picture * picture);
123 static GstFlowReturn gst_d3d11_vp8_dec_output_picture (GstVp8Decoder *
124 decoder, GstVideoCodecFrame * frame, GstVp8Picture * picture);
125
126 static void
gst_d3d11_vp8_dec_class_init(GstD3D11Vp8DecClass * klass,gpointer data)127 gst_d3d11_vp8_dec_class_init (GstD3D11Vp8DecClass * klass, gpointer data)
128 {
129 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
130 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
131 GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (klass);
132 GstVp8DecoderClass *vp8decoder_class = GST_VP8_DECODER_CLASS (klass);
133 GstD3D11DecoderClassData *cdata = (GstD3D11DecoderClassData *) data;
134
135 gobject_class->get_property = gst_d3d11_vp8_dec_get_property;
136 gobject_class->finalize = gst_d3d11_vp8_dec_finalize;
137
138 element_class->set_context =
139 GST_DEBUG_FUNCPTR (gst_d3d11_vp8_dec_set_context);
140
141 parent_class = (GstElementClass *) g_type_class_peek_parent (klass);
142 gst_d3d11_decoder_class_data_fill_subclass_data (cdata, &klass->class_data);
143
144 /**
145 * GstD3D11Vp8Dec:adapter-luid:
146 *
147 * DXGI Adapter LUID for this element
148 *
149 * Since: 1.20
150 */
151 gst_d3d11_decoder_proxy_class_init (element_class, cdata,
152 "Seungha Yang <seungha.yang@navercorp.com>");
153
154 decoder_class->open = GST_DEBUG_FUNCPTR (gst_d3d11_vp8_dec_open);
155 decoder_class->close = GST_DEBUG_FUNCPTR (gst_d3d11_vp8_dec_close);
156 decoder_class->negotiate = GST_DEBUG_FUNCPTR (gst_d3d11_vp8_dec_negotiate);
157 decoder_class->decide_allocation =
158 GST_DEBUG_FUNCPTR (gst_d3d11_vp8_dec_decide_allocation);
159 decoder_class->src_query = GST_DEBUG_FUNCPTR (gst_d3d11_vp8_dec_src_query);
160 decoder_class->sink_event = GST_DEBUG_FUNCPTR (gst_d3d11_vp8_sink_event);
161
162 vp8decoder_class->new_sequence =
163 GST_DEBUG_FUNCPTR (gst_d3d11_vp8_dec_new_sequence);
164 vp8decoder_class->new_picture =
165 GST_DEBUG_FUNCPTR (gst_d3d11_vp8_dec_new_picture);
166 vp8decoder_class->start_picture =
167 GST_DEBUG_FUNCPTR (gst_d3d11_vp8_dec_start_picture);
168 vp8decoder_class->decode_picture =
169 GST_DEBUG_FUNCPTR (gst_d3d11_vp8_dec_decode_picture);
170 vp8decoder_class->end_picture =
171 GST_DEBUG_FUNCPTR (gst_d3d11_vp8_dec_end_picture);
172 vp8decoder_class->output_picture =
173 GST_DEBUG_FUNCPTR (gst_d3d11_vp8_dec_output_picture);
174 }
175
176 static void
gst_d3d11_vp8_dec_init(GstD3D11Vp8Dec * self)177 gst_d3d11_vp8_dec_init (GstD3D11Vp8Dec * self)
178 {
179 self->inner = new GstD3D11Vp8DecInner ();
180 }
181
182 static void
gst_d3d11_vp8_dec_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)183 gst_d3d11_vp8_dec_get_property (GObject * object, guint prop_id,
184 GValue * value, GParamSpec * pspec)
185 {
186 GstD3D11Vp8DecClass *klass = GST_D3D11_VP8_DEC_GET_CLASS (object);
187 GstD3D11DecoderSubClassData *cdata = &klass->class_data;
188
189 gst_d3d11_decoder_proxy_get_property (object, prop_id, value, pspec, cdata);
190 }
191
192 static void
gst_d3d11_vp8_dec_finalize(GObject * object)193 gst_d3d11_vp8_dec_finalize (GObject * object)
194 {
195 GstD3D11Vp8Dec *self = GST_D3D11_VP8_DEC (object);
196
197 delete self->inner;
198
199 G_OBJECT_CLASS (parent_class)->finalize (object);
200 }
201
202 static void
gst_d3d11_vp8_dec_set_context(GstElement * element,GstContext * context)203 gst_d3d11_vp8_dec_set_context (GstElement * element, GstContext * context)
204 {
205 GstD3D11Vp8Dec *self = GST_D3D11_VP8_DEC (element);
206 GstD3D11Vp8DecInner *inner = self->inner;
207 GstD3D11Vp8DecClass *klass = GST_D3D11_VP8_DEC_GET_CLASS (self);
208 GstD3D11DecoderSubClassData *cdata = &klass->class_data;
209
210 gst_d3d11_handle_set_context_for_adapter_luid (element,
211 context, cdata->adapter_luid, &inner->device);
212
213 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
214 }
215
216 static gboolean
gst_d3d11_vp8_dec_open(GstVideoDecoder * decoder)217 gst_d3d11_vp8_dec_open (GstVideoDecoder * decoder)
218 {
219 GstD3D11Vp8Dec *self = GST_D3D11_VP8_DEC (decoder);
220 GstD3D11Vp8DecInner *inner = self->inner;
221 GstD3D11Vp8DecClass *klass = GST_D3D11_VP8_DEC_GET_CLASS (self);
222 GstD3D11DecoderSubClassData *cdata = &klass->class_data;
223
224 if (!gst_d3d11_decoder_proxy_open (decoder,
225 cdata, &inner->device, &inner->d3d11_decoder)) {
226 GST_ERROR_OBJECT (self, "Failed to open decoder");
227 return FALSE;
228 }
229
230 return TRUE;
231 }
232
233 static gboolean
gst_d3d11_vp8_dec_close(GstVideoDecoder * decoder)234 gst_d3d11_vp8_dec_close (GstVideoDecoder * decoder)
235 {
236 GstD3D11Vp8Dec *self = GST_D3D11_VP8_DEC (decoder);
237 GstD3D11Vp8DecInner *inner = self->inner;
238
239 gst_clear_object (&inner->d3d11_decoder);
240 gst_clear_object (&inner->device);
241
242 return TRUE;
243 }
244
245 static gboolean
gst_d3d11_vp8_dec_negotiate(GstVideoDecoder * decoder)246 gst_d3d11_vp8_dec_negotiate (GstVideoDecoder * decoder)
247 {
248 GstD3D11Vp8Dec *self = GST_D3D11_VP8_DEC (decoder);
249 GstD3D11Vp8DecInner *inner = self->inner;
250
251 if (!gst_d3d11_decoder_negotiate (inner->d3d11_decoder, decoder))
252 return FALSE;
253
254 return GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder);
255 }
256
257 static gboolean
gst_d3d11_vp8_dec_decide_allocation(GstVideoDecoder * decoder,GstQuery * query)258 gst_d3d11_vp8_dec_decide_allocation (GstVideoDecoder * decoder,
259 GstQuery * query)
260 {
261 GstD3D11Vp8Dec *self = GST_D3D11_VP8_DEC (decoder);
262 GstD3D11Vp8DecInner *inner = self->inner;
263
264 if (!gst_d3d11_decoder_decide_allocation (inner->d3d11_decoder, decoder,
265 query)) {
266 return FALSE;
267 }
268
269 return GST_VIDEO_DECODER_CLASS (parent_class)->decide_allocation
270 (decoder, query);
271 }
272
273 static gboolean
gst_d3d11_vp8_dec_src_query(GstVideoDecoder * decoder,GstQuery * query)274 gst_d3d11_vp8_dec_src_query (GstVideoDecoder * decoder, GstQuery * query)
275 {
276 GstD3D11Vp8Dec *self = GST_D3D11_VP8_DEC (decoder);
277 GstD3D11Vp8DecInner *inner = self->inner;
278
279 switch (GST_QUERY_TYPE (query)) {
280 case GST_QUERY_CONTEXT:
281 if (gst_d3d11_handle_context_query (GST_ELEMENT (decoder),
282 query, inner->device)) {
283 return TRUE;
284 }
285 break;
286 default:
287 break;
288 }
289
290 return GST_VIDEO_DECODER_CLASS (parent_class)->src_query (decoder, query);
291 }
292
293 static gboolean
gst_d3d11_vp8_sink_event(GstVideoDecoder * decoder,GstEvent * event)294 gst_d3d11_vp8_sink_event (GstVideoDecoder * decoder, GstEvent * event)
295 {
296 GstD3D11Vp8Dec *self = GST_D3D11_VP8_DEC (decoder);
297 GstD3D11Vp8DecInner *inner = self->inner;
298
299 switch (GST_EVENT_TYPE (event)) {
300 case GST_EVENT_FLUSH_START:
301 if (inner->d3d11_decoder)
302 gst_d3d11_decoder_set_flushing (inner->d3d11_decoder, decoder, TRUE);
303 break;
304 case GST_EVENT_FLUSH_STOP:
305 if (inner->d3d11_decoder)
306 gst_d3d11_decoder_set_flushing (inner->d3d11_decoder, decoder, FALSE);
307 default:
308 break;
309 }
310
311 return GST_VIDEO_DECODER_CLASS (parent_class)->sink_event (decoder, event);
312 }
313
314 static GstFlowReturn
gst_d3d11_vp8_dec_new_sequence(GstVp8Decoder * decoder,const GstVp8FrameHdr * frame_hdr)315 gst_d3d11_vp8_dec_new_sequence (GstVp8Decoder * decoder,
316 const GstVp8FrameHdr * frame_hdr)
317 {
318 GstD3D11Vp8Dec *self = GST_D3D11_VP8_DEC (decoder);
319 GstD3D11Vp8DecInner *inner = self->inner;
320 GstVideoInfo info;
321
322 GST_LOG_OBJECT (self, "new sequence");
323
324 /* FIXME: support I420 */
325 inner->out_format = GST_VIDEO_FORMAT_NV12;
326 inner->width = frame_hdr->width;
327 inner->height = frame_hdr->height;
328
329 gst_video_info_set_format (&info,
330 inner->out_format, inner->width, inner->height);
331
332 if (!gst_d3d11_decoder_configure (inner->d3d11_decoder,
333 decoder->input_state, &info, inner->width, inner->height,
334 NUM_OUTPUT_VIEW)) {
335 GST_ERROR_OBJECT (self, "Failed to create decoder");
336 return GST_FLOW_NOT_NEGOTIATED;
337 }
338
339 if (!gst_video_decoder_negotiate (GST_VIDEO_DECODER (self))) {
340 GST_ERROR_OBJECT (self, "Failed to negotiate with downstream");
341 return GST_FLOW_NOT_NEGOTIATED;
342 }
343
344 return GST_FLOW_OK;
345 }
346
347 static GstFlowReturn
gst_d3d11_vp8_dec_new_picture(GstVp8Decoder * decoder,GstVideoCodecFrame * frame,GstVp8Picture * picture)348 gst_d3d11_vp8_dec_new_picture (GstVp8Decoder * decoder,
349 GstVideoCodecFrame * frame, GstVp8Picture * picture)
350 {
351 GstD3D11Vp8Dec *self = GST_D3D11_VP8_DEC (decoder);
352 GstD3D11Vp8DecInner *inner = self->inner;
353 GstBuffer *view_buffer;
354
355 view_buffer = gst_d3d11_decoder_get_output_view_buffer (inner->d3d11_decoder,
356 GST_VIDEO_DECODER (decoder));
357 if (!view_buffer) {
358 GST_DEBUG_OBJECT (self, "No available output view buffer");
359 return GST_FLOW_FLUSHING;
360 }
361
362 GST_LOG_OBJECT (self, "New output view buffer %" GST_PTR_FORMAT, view_buffer);
363
364 gst_vp8_picture_set_user_data (picture,
365 view_buffer, (GDestroyNotify) gst_buffer_unref);
366
367 GST_LOG_OBJECT (self, "New VP8 picture %p", picture);
368
369 return GST_FLOW_OK;
370 }
371
372 static GstFlowReturn
gst_d3d11_vp8_dec_start_picture(GstVp8Decoder * decoder,GstVp8Picture * picture)373 gst_d3d11_vp8_dec_start_picture (GstVp8Decoder * decoder,
374 GstVp8Picture * picture)
375 {
376 GstD3D11Vp8Dec *self = GST_D3D11_VP8_DEC (decoder);
377 GstD3D11Vp8DecInner *inner = self->inner;
378
379 inner->bitstream_buffer.resize (0);
380
381 return GST_FLOW_OK;
382 }
383
384 static ID3D11VideoDecoderOutputView *
gst_d3d11_vp8_dec_get_output_view_from_picture(GstD3D11Vp8Dec * self,GstVp8Picture * picture,guint8 * view_id)385 gst_d3d11_vp8_dec_get_output_view_from_picture (GstD3D11Vp8Dec * self,
386 GstVp8Picture * picture, guint8 * view_id)
387 {
388 GstD3D11Vp8DecInner *inner = self->inner;
389 GstBuffer *view_buffer;
390 ID3D11VideoDecoderOutputView *view;
391
392 view_buffer = (GstBuffer *) gst_vp8_picture_get_user_data (picture);
393 if (!view_buffer) {
394 GST_DEBUG_OBJECT (self, "current picture does not have output view buffer");
395 return NULL;
396 }
397
398 view =
399 gst_d3d11_decoder_get_output_view_from_buffer (inner->d3d11_decoder,
400 view_buffer, view_id);
401 if (!view) {
402 GST_DEBUG_OBJECT (self, "current picture does not have output view handle");
403 return NULL;
404 }
405
406 return view;
407 }
408
409 static void
gst_d3d11_vp8_dec_copy_frame_params(GstD3D11Vp8Dec * self,GstVp8Picture * picture,GstVp8Parser * parser,DXVA_PicParams_VP8 * params)410 gst_d3d11_vp8_dec_copy_frame_params (GstD3D11Vp8Dec * self,
411 GstVp8Picture * picture, GstVp8Parser * parser, DXVA_PicParams_VP8 * params)
412 {
413 const GstVp8FrameHdr *frame_hdr = &picture->frame_hdr;
414 gint i;
415
416 /* 0: keyframe, 1: inter */
417 params->frame_type = !frame_hdr->key_frame;
418 params->version = frame_hdr->version;
419 params->show_frame = frame_hdr->show_frame;
420 params->clamp_type = frame_hdr->clamping_type;
421
422 params->filter_type = frame_hdr->filter_type;
423 params->filter_level = frame_hdr->loop_filter_level;
424 params->sharpness_level = frame_hdr->sharpness_level;
425 params->mode_ref_lf_delta_enabled =
426 parser->mb_lf_adjust.loop_filter_adj_enable;
427 params->mode_ref_lf_delta_update =
428 parser->mb_lf_adjust.mode_ref_lf_delta_update;
429 for (i = 0; i < 4; i++) {
430 params->ref_lf_deltas[i] = parser->mb_lf_adjust.ref_frame_delta[i];
431 params->mode_lf_deltas[i] = parser->mb_lf_adjust.mb_mode_delta[i];
432 }
433 params->log2_nbr_of_dct_partitions = frame_hdr->log2_nbr_of_dct_partitions;
434 params->base_qindex = frame_hdr->quant_indices.y_ac_qi;
435 params->y1dc_delta_q = frame_hdr->quant_indices.y_dc_delta;
436 params->y2dc_delta_q = frame_hdr->quant_indices.y2_dc_delta;
437 params->y2ac_delta_q = frame_hdr->quant_indices.y2_ac_delta;
438 params->uvdc_delta_q = frame_hdr->quant_indices.uv_dc_delta;
439 params->uvac_delta_q = frame_hdr->quant_indices.uv_ac_delta;
440
441 params->ref_frame_sign_bias_golden = frame_hdr->sign_bias_golden;
442 params->ref_frame_sign_bias_altref = frame_hdr->sign_bias_alternate;
443
444 params->refresh_entropy_probs = frame_hdr->refresh_entropy_probs;
445
446 memcpy (params->vp8_coef_update_probs, frame_hdr->token_probs.prob,
447 sizeof (frame_hdr->token_probs.prob));
448
449 params->mb_no_coeff_skip = frame_hdr->mb_no_skip_coeff;
450 params->prob_skip_false = frame_hdr->prob_skip_false;
451 params->prob_intra = frame_hdr->prob_intra;
452 params->prob_last = frame_hdr->prob_last;
453 params->prob_golden = frame_hdr->prob_gf;
454
455 memcpy (params->intra_16x16_prob, frame_hdr->mode_probs.y_prob,
456 sizeof (frame_hdr->mode_probs.y_prob));
457 memcpy (params->intra_chroma_prob, frame_hdr->mode_probs.uv_prob,
458 sizeof (frame_hdr->mode_probs.uv_prob));
459 memcpy (params->vp8_mv_update_probs, frame_hdr->mv_probs.prob,
460 sizeof (frame_hdr->mv_probs.prob));
461 }
462
463 static void
gst_d3d11_vp8_dec_copy_reference_frames(GstD3D11Vp8Dec * self,DXVA_PicParams_VP8 * params)464 gst_d3d11_vp8_dec_copy_reference_frames (GstD3D11Vp8Dec * self,
465 DXVA_PicParams_VP8 * params)
466 {
467 GstVp8Decoder *decoder = GST_VP8_DECODER (self);
468 ID3D11VideoDecoderOutputView *view;
469 guint8 view_id = 0xff;
470
471 if (decoder->alt_ref_picture) {
472 view = gst_d3d11_vp8_dec_get_output_view_from_picture (self,
473 decoder->alt_ref_picture, &view_id);
474 if (!view) {
475 GST_ERROR_OBJECT (self, "picture does not have output view handle");
476 return;
477 }
478
479 params->alt_fb_idx.Index7Bits = view_id;
480 } else {
481 params->alt_fb_idx.bPicEntry = 0xff;
482 }
483
484 if (decoder->golden_ref_picture) {
485 view = gst_d3d11_vp8_dec_get_output_view_from_picture (self,
486 decoder->golden_ref_picture, &view_id);
487 if (!view) {
488 GST_ERROR_OBJECT (self, "picture does not have output view handle");
489 return;
490 }
491
492 params->gld_fb_idx.Index7Bits = view_id;
493 } else {
494 params->gld_fb_idx.bPicEntry = 0xff;
495 }
496
497 if (decoder->last_picture) {
498 view = gst_d3d11_vp8_dec_get_output_view_from_picture (self,
499 decoder->last_picture, &view_id);
500 if (!view) {
501 GST_ERROR_OBJECT (self, "picture does not have output view handle");
502 return;
503 }
504
505 params->lst_fb_idx.Index7Bits = view_id;
506 } else {
507 params->lst_fb_idx.bPicEntry = 0xff;
508 }
509 }
510
511 static void
gst_d3d11_vp8_dec_copy_segmentation_params(GstD3D11Vp8Dec * self,GstVp8Parser * parser,DXVA_PicParams_VP8 * params)512 gst_d3d11_vp8_dec_copy_segmentation_params (GstD3D11Vp8Dec * self,
513 GstVp8Parser * parser, DXVA_PicParams_VP8 * params)
514 {
515 const GstVp8Segmentation *seg = &parser->segmentation;
516 gint i;
517
518 params->stVP8Segments.segmentation_enabled = seg->segmentation_enabled;
519 params->stVP8Segments.update_mb_segmentation_map =
520 seg->update_mb_segmentation_map;
521 params->stVP8Segments.update_mb_segmentation_data =
522 seg->update_segment_feature_data;
523 params->stVP8Segments.mb_segement_abs_delta = seg->segment_feature_mode;
524
525 for (i = 0; i < 4; i++) {
526 params->stVP8Segments.segment_feature_data[0][i] =
527 seg->quantizer_update_value[i];
528 }
529
530 for (i = 0; i < 4; i++) {
531 params->stVP8Segments.segment_feature_data[1][i] = seg->lf_update_value[i];
532 }
533
534 for (i = 0; i < 3; i++) {
535 params->stVP8Segments.mb_segment_tree_probs[i] = seg->segment_prob[i];
536 }
537 }
538
539 static GstFlowReturn
gst_d3d11_vp8_dec_decode_picture(GstVp8Decoder * decoder,GstVp8Picture * picture,GstVp8Parser * parser)540 gst_d3d11_vp8_dec_decode_picture (GstVp8Decoder * decoder,
541 GstVp8Picture * picture, GstVp8Parser * parser)
542 {
543 GstD3D11Vp8Dec *self = GST_D3D11_VP8_DEC (decoder);
544 GstD3D11Vp8DecInner *inner = self->inner;
545 DXVA_PicParams_VP8 *pic_params = &inner->pic_params;
546 DXVA_Slice_VPx_Short *slice = &inner->slice;
547 ID3D11VideoDecoderOutputView *view;
548 guint8 view_id = 0xff;
549 const GstVp8FrameHdr *frame_hdr = &picture->frame_hdr;
550
551 view = gst_d3d11_vp8_dec_get_output_view_from_picture (self,
552 picture, &view_id);
553 if (!view) {
554 GST_ERROR_OBJECT (self, "current picture does not have output view handle");
555 return GST_FLOW_ERROR;
556 }
557
558 memset (pic_params, 0, sizeof (DXVA_PicParams_VP8));
559
560 pic_params->first_part_size = frame_hdr->first_part_size;
561 pic_params->width = inner->width;
562 pic_params->height = inner->height;
563 pic_params->CurrPic.Index7Bits = view_id;
564 pic_params->StatusReportFeedbackNumber = 1;
565
566 gst_d3d11_vp8_dec_copy_frame_params (self, picture, parser, pic_params);
567 gst_d3d11_vp8_dec_copy_reference_frames (self, pic_params);
568 gst_d3d11_vp8_dec_copy_segmentation_params (self, parser, pic_params);
569
570 inner->bitstream_buffer.resize (picture->size);
571 memcpy (&inner->bitstream_buffer[0], picture->data, picture->size);
572
573 slice->BSNALunitDataLocation = 0;
574 slice->SliceBytesInBuffer = inner->bitstream_buffer.size ();
575 slice->wBadSliceChopping = 0;
576
577 return GST_FLOW_OK;
578 }
579
580 static GstFlowReturn
gst_d3d11_vp8_dec_end_picture(GstVp8Decoder * decoder,GstVp8Picture * picture)581 gst_d3d11_vp8_dec_end_picture (GstVp8Decoder * decoder, GstVp8Picture * picture)
582 {
583 GstD3D11Vp8Dec *self = GST_D3D11_VP8_DEC (decoder);
584 GstD3D11Vp8DecInner *inner = self->inner;
585 ID3D11VideoDecoderOutputView *view;
586 guint8 view_id = 0xff;
587 size_t bitstream_buffer_size;
588 size_t bitstream_pos;
589 GstD3D11DecodeInputStreamArgs input_args;
590
591 if (inner->bitstream_buffer.empty ()) {
592 GST_ERROR_OBJECT (self, "No bitstream buffer to submit");
593 return GST_FLOW_ERROR;
594 }
595
596 view = gst_d3d11_vp8_dec_get_output_view_from_picture (self,
597 picture, &view_id);
598 if (!view) {
599 GST_ERROR_OBJECT (self, "current picture does not have output view handle");
600 return GST_FLOW_ERROR;
601 }
602
603 memset (&input_args, 0, sizeof (GstD3D11DecodeInputStreamArgs));
604
605 bitstream_pos = inner->bitstream_buffer.size ();
606 bitstream_buffer_size = GST_ROUND_UP_128 (bitstream_pos);
607
608 if (bitstream_buffer_size > bitstream_pos) {
609 size_t padding = bitstream_buffer_size - bitstream_pos;
610
611 /* As per DXVA spec, total amount of bitstream buffer size should be
612 * 128 bytes aligned. If actual data is not multiple of 128 bytes,
613 * the last slice data needs to be zero-padded */
614 inner->bitstream_buffer.resize (bitstream_buffer_size, 0);
615
616 inner->slice.SliceBytesInBuffer += padding;
617 }
618
619 input_args.picture_params = &inner->pic_params;
620 input_args.picture_params_size = sizeof (DXVA_PicParams_VP8);
621 input_args.slice_control = &inner->slice;
622 input_args.slice_control_size = sizeof (DXVA_Slice_VPx_Short);
623 input_args.bitstream = &inner->bitstream_buffer[0];
624 input_args.bitstream_size = inner->bitstream_buffer.size ();
625
626 if (!gst_d3d11_decoder_decode_frame (inner->d3d11_decoder, view, &input_args))
627 return GST_FLOW_ERROR;
628
629 return GST_FLOW_OK;
630 }
631
632 static GstFlowReturn
gst_d3d11_vp8_dec_output_picture(GstVp8Decoder * decoder,GstVideoCodecFrame * frame,GstVp8Picture * picture)633 gst_d3d11_vp8_dec_output_picture (GstVp8Decoder * decoder,
634 GstVideoCodecFrame * frame, GstVp8Picture * picture)
635 {
636 GstD3D11Vp8Dec *self = GST_D3D11_VP8_DEC (decoder);
637 GstD3D11Vp8DecInner *inner = self->inner;
638 GstVideoDecoder *vdec = GST_VIDEO_DECODER (decoder);
639 GstBuffer *view_buffer;
640
641 g_assert (picture->frame_hdr.show_frame);
642
643 GST_LOG_OBJECT (self, "Outputting picture %p", picture);
644
645 view_buffer = (GstBuffer *) gst_vp8_picture_get_user_data (picture);
646
647 if (!view_buffer) {
648 GST_ERROR_OBJECT (self, "Could not get output view");
649 goto error;
650 }
651
652 if (!gst_d3d11_decoder_process_output (inner->d3d11_decoder, vdec,
653 inner->width, inner->height, view_buffer, &frame->output_buffer)) {
654 GST_ERROR_OBJECT (self, "Failed to copy buffer");
655 goto error;
656 }
657
658 gst_vp8_picture_unref (picture);
659
660 return gst_video_decoder_finish_frame (vdec, frame);
661
662 error:
663 gst_vp8_picture_unref (picture);
664 gst_video_decoder_release_frame (vdec, frame);
665
666 return GST_FLOW_ERROR;
667 }
668
669 void
gst_d3d11_vp8_dec_register(GstPlugin * plugin,GstD3D11Device * device,guint rank)670 gst_d3d11_vp8_dec_register (GstPlugin * plugin, GstD3D11Device * device,
671 guint rank)
672 {
673 GType type;
674 gchar *type_name;
675 gchar *feature_name;
676 guint index = 0;
677 guint i;
678 GTypeInfo type_info = {
679 sizeof (GstD3D11Vp8DecClass),
680 NULL,
681 NULL,
682 (GClassInitFunc) gst_d3d11_vp8_dec_class_init,
683 NULL,
684 NULL,
685 sizeof (GstD3D11Vp8Dec),
686 0,
687 (GInstanceInitFunc) gst_d3d11_vp8_dec_init,
688 };
689 const GUID *profile_guid = NULL;
690 GstCaps *sink_caps = NULL;
691 GstCaps *src_caps = NULL;
692 guint max_width = 0;
693 guint max_height = 0;
694 guint resolution;
695 DXGI_FORMAT format = DXGI_FORMAT_NV12;
696
697 if (!gst_d3d11_decoder_get_supported_decoder_profile (device,
698 GST_DXVA_CODEC_VP8, GST_VIDEO_FORMAT_NV12, &profile_guid)) {
699 GST_INFO_OBJECT (device, "device does not support VP8 decoding");
700 return;
701 }
702
703 for (i = 0; i < G_N_ELEMENTS (gst_dxva_resolutions); i++) {
704 if (gst_d3d11_decoder_supports_resolution (device, profile_guid,
705 format, gst_dxva_resolutions[i].width,
706 gst_dxva_resolutions[i].height)) {
707 max_width = gst_dxva_resolutions[i].width;
708 max_height = gst_dxva_resolutions[i].height;
709
710 GST_DEBUG_OBJECT (device,
711 "device support resolution %dx%d", max_width, max_height);
712 } else {
713 break;
714 }
715 }
716
717 if (max_width == 0 || max_height == 0) {
718 GST_WARNING_OBJECT (device, "Couldn't query supported resolution");
719 return;
720 }
721
722 sink_caps = gst_caps_from_string ("video/x-vp8");
723 src_caps = gst_caps_from_string ("video/x-raw("
724 GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY "); video/x-raw");
725
726 gst_caps_set_simple (src_caps, "format", G_TYPE_STRING, "NV12", NULL);
727
728 /* To cover both landscape and portrait, select max value */
729 resolution = MAX (max_width, max_height);
730 gst_caps_set_simple (sink_caps,
731 "width", GST_TYPE_INT_RANGE, 1, resolution,
732 "height", GST_TYPE_INT_RANGE, 1, resolution, NULL);
733 gst_caps_set_simple (src_caps,
734 "width", GST_TYPE_INT_RANGE, 1, resolution,
735 "height", GST_TYPE_INT_RANGE, 1, resolution, NULL);
736
737 type_info.class_data =
738 gst_d3d11_decoder_class_data_new (device, GST_DXVA_CODEC_VP8,
739 sink_caps, src_caps);
740
741 type_name = g_strdup ("GstD3D11Vp8Dec");
742 feature_name = g_strdup ("d3d11vp8dec");
743
744 while (g_type_from_name (type_name)) {
745 index++;
746 g_free (type_name);
747 g_free (feature_name);
748 type_name = g_strdup_printf ("GstD3D11Vp8Device%dDec", index);
749 feature_name = g_strdup_printf ("d3d11vp8device%ddec", index);
750 }
751
752 type = g_type_register_static (GST_TYPE_VP8_DECODER,
753 type_name, &type_info, (GTypeFlags) 0);
754
755 /* make lower rank than default device */
756 if (rank > 0 && index != 0)
757 rank--;
758
759 if (index != 0)
760 gst_element_type_set_skip_documentation (type);
761
762 if (!gst_element_register (plugin, feature_name, rank, type))
763 GST_WARNING ("Failed to register plugin '%s'", type_name);
764
765 g_free (type_name);
766 g_free (feature_name);
767 }
768