• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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