• 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-mfvp9enc
22  * @title: mfvp9enc
23  *
24  * This element encodes raw video into VP9 compressed data.
25  *
26  * ## Example pipelines
27  * |[
28  * gst-launch-1.0 -v videotestsrc ! mfvp9enc ! matroskamux ! filesink location=videotestsrc.mkv
29  * ]| This example pipeline will encode a test video source to VP9 using
30  * Media Foundation encoder, and muxes it in a mkv container.
31  */
32 
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36 
37 #include <gst/gst.h>
38 #include "gstmfvideoenc.h"
39 #include "gstmfvp9enc.h"
40 #include <wrl.h>
41 
42 /* *INDENT-OFF* */
43 using namespace Microsoft::WRL;
44 /* *INDENT-ON* */
45 
46 GST_DEBUG_CATEGORY (gst_mf_vp9_enc_debug);
47 #define GST_CAT_DEFAULT gst_mf_vp9_enc_debug
48 
49 enum
50 {
51   GST_MF_VP9_ENC_RC_MODE_CBR = 0,
52   GST_MF_VP9_ENC_RC_MODE_QUALITY,
53 };
54 
55 #define GST_TYPE_MF_VP9_ENC_RC_MODE (gst_mf_vp9_enc_rc_mode_get_type())
56 static GType
gst_mf_vp9_enc_rc_mode_get_type(void)57 gst_mf_vp9_enc_rc_mode_get_type (void)
58 {
59   static GType rc_mode_type = 0;
60 
61   static const GEnumValue rc_mode_types[] = {
62     {GST_MF_VP9_ENC_RC_MODE_CBR, "Constant bitrate", "cbr"},
63     {GST_MF_VP9_ENC_RC_MODE_QUALITY, "Quality-based variable bitrate", "qvbr"},
64     {0, NULL, NULL}
65   };
66 
67   if (!rc_mode_type) {
68     rc_mode_type = g_enum_register_static ("GstMFVP9EncRCMode", rc_mode_types);
69   }
70   return rc_mode_type;
71 }
72 
73 enum
74 {
75   GST_MF_VP9_ENC_CONTENT_TYPE_UNKNOWN,
76   GST_MF_VP9_ENC_CONTENT_TYPE_FIXED_CAMERA_ANGLE,
77 };
78 
79 #define GST_TYPE_MF_VP9_ENC_CONTENT_TYPE (gst_mf_vp9_enc_content_type_get_type())
80 static GType
gst_mf_vp9_enc_content_type_get_type(void)81 gst_mf_vp9_enc_content_type_get_type (void)
82 {
83   static GType content_type = 0;
84 
85   static const GEnumValue content_types[] = {
86     {GST_MF_VP9_ENC_CONTENT_TYPE_UNKNOWN, "Unknown", "unknown"},
87     {GST_MF_VP9_ENC_CONTENT_TYPE_FIXED_CAMERA_ANGLE,
88         "Fixed Camera Angle, such as a webcam", "fixed"},
89     {0, NULL, NULL}
90   };
91 
92   if (!content_type) {
93     content_type =
94         g_enum_register_static ("GstMFVP9EncContentType", content_types);
95   }
96   return content_type;
97 }
98 
99 enum
100 {
101   PROP_0,
102   PROP_BITRATE,
103   PROP_RC_MODE,
104   PROP_MAX_BITRATE,
105   PROP_QUALITY_VS_SPEED,
106   PROP_GOP_SIZE,
107   PROP_THREADS,
108   PROP_CONTENT_TYPE,
109   PROP_LOW_LATENCY,
110   PROP_D3D11_AWARE,
111   PROP_ADAPTER_LUID,
112 };
113 
114 #define DEFAULT_BITRATE (2 * 1024)
115 #define DEFAULT_RC_MODE GST_MF_VP9_ENC_RC_MODE_CBR
116 #define DEFAULT_MAX_BITRATE 0
117 #define DEFAULT_QUALITY_VS_SPEED 50
118 #define DEFAULT_GOP_SIZE -1
119 #define DEFAULT_THREADS 0
120 #define DEFAULT_CONTENT_TYPE GST_MF_VP9_ENC_CONTENT_TYPE_UNKNOWN
121 #define DEFAULT_LOW_LATENCY FALSE
122 
123 typedef struct _GstMFVP9Enc
124 {
125   GstMFVideoEnc parent;
126 
127   /* properties */
128   guint bitrate;
129 
130   /* device dependent properties */
131   guint rc_mode;
132   guint max_bitrate;
133   guint quality_vs_speed;
134   guint gop_size;
135   guint threads;
136   guint content_type;
137   gboolean low_latency;
138 } GstMFVP9Enc;
139 
140 typedef struct _GstMFVP9EncClass
141 {
142   GstMFVideoEncClass parent_class;
143 } GstMFVP9EncClass;
144 
145 static GstElementClass *parent_class = NULL;
146 
147 static void gst_mf_vp9_enc_get_property (GObject * object, guint prop_id,
148     GValue * value, GParamSpec * pspec);
149 static void gst_mf_vp9_enc_set_property (GObject * object, guint prop_id,
150     const GValue * value, GParamSpec * pspec);
151 static gboolean gst_mf_vp9_enc_set_option (GstMFVideoEnc * mfenc,
152     GstVideoCodecState * state, IMFMediaType * output_type);
153 static gboolean gst_mf_vp9_enc_set_src_caps (GstMFVideoEnc * mfenc,
154     GstVideoCodecState * state, IMFMediaType * output_type);
155 
156 static void
gst_mf_vp9_enc_class_init(GstMFVP9EncClass * klass,gpointer data)157 gst_mf_vp9_enc_class_init (GstMFVP9EncClass * klass, gpointer data)
158 {
159   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
160   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
161   GstMFVideoEncClass *mfenc_class = GST_MF_VIDEO_ENC_CLASS (klass);
162   GstMFVideoEncClassData *cdata = (GstMFVideoEncClassData *) data;
163   GstMFVideoEncDeviceCaps *device_caps = &cdata->device_caps;
164   gchar *long_name;
165   gchar *classification;
166 
167   parent_class = (GstElementClass *) g_type_class_peek_parent (klass);
168 
169   gobject_class->get_property = gst_mf_vp9_enc_get_property;
170   gobject_class->set_property = gst_mf_vp9_enc_set_property;
171 
172   g_object_class_install_property (gobject_class, PROP_BITRATE,
173       g_param_spec_uint ("bitrate", "Bitrate", "Bitrate in kbit/sec", 1,
174           (G_MAXUINT >> 10), DEFAULT_BITRATE,
175           (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
176 
177   if (device_caps->rc_mode) {
178     g_object_class_install_property (gobject_class, PROP_RC_MODE,
179         g_param_spec_enum ("rc-mode", "Rate Control Mode",
180             "Rate Control Mode",
181             GST_TYPE_MF_VP9_ENC_RC_MODE, DEFAULT_RC_MODE,
182             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
183                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
184 
185     /* NOTE: documentation will be done by only for default device */
186     if (cdata->is_default) {
187       gst_type_mark_as_plugin_api (GST_TYPE_MF_VP9_ENC_RC_MODE,
188           (GstPluginAPIFlags) 0);
189     }
190   }
191 
192   if (device_caps->max_bitrate) {
193     g_object_class_install_property (gobject_class, PROP_MAX_BITRATE,
194         g_param_spec_uint ("max-bitrate", "Max Bitrate",
195             "The maximum bitrate applied when rc-mode is \"pcvbr\" in kbit/sec "
196             "(0 = MFT default)", 0, (G_MAXUINT >> 10),
197             DEFAULT_MAX_BITRATE,
198             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
199                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
200   }
201 
202   if (device_caps->quality_vs_speed) {
203     g_object_class_install_property (gobject_class, PROP_QUALITY_VS_SPEED,
204         g_param_spec_uint ("quality-vs-speed", "Quality Vs Speed",
205             "Quality and speed tradeoff, [0, 33]: Low complexity, "
206             "[34, 66]: Medium complexity, [67, 100]: High complexity", 0, 100,
207             DEFAULT_QUALITY_VS_SPEED,
208             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
209                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
210   }
211 
212   if (device_caps->gop_size) {
213     g_object_class_install_property (gobject_class, PROP_GOP_SIZE,
214         g_param_spec_int ("gop-size", "GOP size",
215             "The number of pictures from one GOP header to the next. "
216             "Depending on GPU vendor implementation, zero gop-size might "
217             "produce only one keyframe at the beginning (-1 for automatic)",
218             -1, G_MAXINT, DEFAULT_GOP_SIZE,
219             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
220                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
221   }
222 
223   if (device_caps->threads) {
224     g_object_class_install_property (gobject_class, PROP_THREADS,
225         g_param_spec_uint ("threads", "Threads",
226             "The number of worker threads used by a encoder, "
227             "(0 = MFT default)", 0, 16,
228             DEFAULT_THREADS,
229             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
230                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
231   }
232 
233   if (device_caps->content_type) {
234     g_object_class_install_property (gobject_class, PROP_CONTENT_TYPE,
235         g_param_spec_enum ("content-type", "Content Type",
236             "Indicates the type of video content",
237             GST_TYPE_MF_VP9_ENC_CONTENT_TYPE, DEFAULT_CONTENT_TYPE,
238             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
239                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
240 
241     /* NOTE: documentation will be done by only for default device */
242     if (cdata->is_default) {
243       gst_type_mark_as_plugin_api (GST_TYPE_MF_VP9_ENC_CONTENT_TYPE,
244           (GstPluginAPIFlags) 0);
245     }
246   }
247 
248   if (device_caps->low_latency) {
249     g_object_class_install_property (gobject_class, PROP_LOW_LATENCY,
250         g_param_spec_boolean ("low-latency", "Low Latency",
251             "Enable low latency encoding",
252             DEFAULT_LOW_LATENCY,
253             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
254                 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
255   }
256 
257   /**
258    * GstMFVP9Enc:d3d11-aware:
259    *
260    * Whether element supports Direct3D11 texture as an input or not
261    *
262    * Since: 1.20
263    */
264   g_object_class_install_property (gobject_class, PROP_D3D11_AWARE,
265       g_param_spec_boolean ("d3d11-aware", "D3D11 Aware",
266           "Whether device can support Direct3D11 interop",
267           device_caps->d3d11_aware,
268           (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
269 
270   /**
271    * GstMFVP9Enc:adapter-luid:
272    *
273    * DXGI Adapter LUID for this elemenet
274    *
275    * Since: 1.20
276    */
277   if (device_caps->d3d11_aware) {
278     g_object_class_install_property (gobject_class, PROP_ADAPTER_LUID,
279         g_param_spec_int64 ("adapter-luid", "Adapter LUID",
280             "DXGI Adapter LUID (Locally Unique Identifier) of created device",
281             G_MININT64, G_MAXINT64, device_caps->adapter_luid,
282             (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
283                 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
284   }
285 
286   long_name = g_strdup_printf ("Media Foundation %s", cdata->device_name);
287   classification = g_strdup_printf ("Codec/Encoder/Video%s",
288       (cdata->enum_flags & MFT_ENUM_FLAG_HARDWARE) == MFT_ENUM_FLAG_HARDWARE ?
289       "/Hardware" : "");
290   gst_element_class_set_metadata (element_class, long_name,
291       classification,
292       "Microsoft Media Foundation VP9 Encoder",
293       "Seungha Yang <seungha@centricular.com>");
294   g_free (long_name);
295   g_free (classification);
296 
297   gst_element_class_add_pad_template (element_class,
298       gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
299           cdata->sink_caps));
300   gst_element_class_add_pad_template (element_class,
301       gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
302           cdata->src_caps));
303 
304   mfenc_class->set_option = GST_DEBUG_FUNCPTR (gst_mf_vp9_enc_set_option);
305   mfenc_class->set_src_caps = GST_DEBUG_FUNCPTR (gst_mf_vp9_enc_set_src_caps);
306 
307   mfenc_class->codec_id = MFVideoFormat_VP90;
308   mfenc_class->enum_flags = cdata->enum_flags;
309   mfenc_class->device_index = cdata->device_index;
310   mfenc_class->device_caps = *device_caps;
311 
312   g_free (cdata->device_name);
313   gst_caps_unref (cdata->sink_caps);
314   gst_caps_unref (cdata->src_caps);
315   g_free (cdata);
316 }
317 
318 static void
gst_mf_vp9_enc_init(GstMFVP9Enc * self)319 gst_mf_vp9_enc_init (GstMFVP9Enc * self)
320 {
321   self->bitrate = DEFAULT_BITRATE;
322   self->rc_mode = DEFAULT_RC_MODE;
323   self->max_bitrate = DEFAULT_MAX_BITRATE;
324   self->quality_vs_speed = DEFAULT_QUALITY_VS_SPEED;
325   self->gop_size = DEFAULT_GOP_SIZE;
326   self->threads = DEFAULT_THREADS;
327   self->content_type = DEFAULT_CONTENT_TYPE;
328   self->low_latency = DEFAULT_LOW_LATENCY;
329 }
330 
331 static void
gst_mf_vp9_enc_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)332 gst_mf_vp9_enc_get_property (GObject * object, guint prop_id,
333     GValue * value, GParamSpec * pspec)
334 {
335   GstMFVP9Enc *self = (GstMFVP9Enc *) (object);
336   GstMFVideoEncClass *klass = GST_MF_VIDEO_ENC_GET_CLASS (object);
337 
338   switch (prop_id) {
339     case PROP_BITRATE:
340       g_value_set_uint (value, self->bitrate);
341       break;
342     case PROP_RC_MODE:
343       g_value_set_enum (value, self->rc_mode);
344       break;
345     case PROP_MAX_BITRATE:
346       g_value_set_uint (value, self->max_bitrate);
347       break;
348     case PROP_QUALITY_VS_SPEED:
349       g_value_set_uint (value, self->quality_vs_speed);
350       break;
351     case PROP_GOP_SIZE:
352       g_value_set_int (value, self->gop_size);
353       break;
354     case PROP_THREADS:
355       g_value_set_uint (value, self->threads);
356       break;
357     case PROP_CONTENT_TYPE:
358       g_value_set_enum (value, self->content_type);
359       break;
360     case PROP_LOW_LATENCY:
361       g_value_set_boolean (value, self->low_latency);
362       break;
363     case PROP_D3D11_AWARE:
364       g_value_set_boolean (value, klass->device_caps.d3d11_aware);
365       break;
366     case PROP_ADAPTER_LUID:
367       g_value_set_int64 (value, klass->device_caps.adapter_luid);
368       break;
369     default:
370       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
371       break;
372   }
373 }
374 
375 static void
gst_mf_vp9_enc_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)376 gst_mf_vp9_enc_set_property (GObject * object, guint prop_id,
377     const GValue * value, GParamSpec * pspec)
378 {
379   GstMFVP9Enc *self = (GstMFVP9Enc *) (object);
380 
381   switch (prop_id) {
382     case PROP_BITRATE:
383       self->bitrate = g_value_get_uint (value);
384       break;
385     case PROP_RC_MODE:
386       self->rc_mode = g_value_get_enum (value);
387       break;
388     case PROP_MAX_BITRATE:
389       self->max_bitrate = g_value_get_uint (value);
390       break;
391     case PROP_QUALITY_VS_SPEED:
392       self->quality_vs_speed = g_value_get_uint (value);
393       break;
394     case PROP_GOP_SIZE:
395       self->gop_size = g_value_get_int (value);
396       break;
397     case PROP_THREADS:
398       self->threads = g_value_get_uint (value);
399       break;
400     case PROP_CONTENT_TYPE:
401       self->content_type = g_value_get_enum (value);
402       break;
403     case PROP_LOW_LATENCY:
404       self->low_latency = g_value_get_boolean (value);
405       break;
406     default:
407       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
408       break;
409   }
410 }
411 
412 static guint
gst_mf_vp9_enc_rc_mode_to_enum(guint rc_mode)413 gst_mf_vp9_enc_rc_mode_to_enum (guint rc_mode)
414 {
415   switch (rc_mode) {
416     case GST_MF_VP9_ENC_RC_MODE_CBR:
417       return eAVEncCommonRateControlMode_CBR;
418     case GST_MF_VP9_ENC_RC_MODE_QUALITY:
419       return eAVEncCommonRateControlMode_Quality;
420     default:
421       return G_MAXUINT;
422   }
423 }
424 
425 static guint
gst_mf_vp9_enc_content_type_to_enum(guint rc_mode)426 gst_mf_vp9_enc_content_type_to_enum (guint rc_mode)
427 {
428   switch (rc_mode) {
429     case GST_MF_VP9_ENC_CONTENT_TYPE_UNKNOWN:
430       return eAVEncVideoContentType_Unknown;
431     case GST_MF_VP9_ENC_CONTENT_TYPE_FIXED_CAMERA_ANGLE:
432       return eAVEncVideoContentType_FixedCameraAngle;
433     default:
434       return G_MAXUINT;
435   }
436 }
437 
438 #define WARNING_HR(hr,func) \
439   G_STMT_START { \
440     if (!gst_mf_result (hr)) { \
441       GST_WARNING_OBJECT (self, G_STRINGIFY(func) " failed, hr: 0x%x", (guint) hr); \
442     } \
443   } G_STMT_END
444 
445 static gboolean
gst_mf_vp9_enc_set_option(GstMFVideoEnc * mfenc,GstVideoCodecState * state,IMFMediaType * output_type)446 gst_mf_vp9_enc_set_option (GstMFVideoEnc * mfenc, GstVideoCodecState * state,
447     IMFMediaType * output_type)
448 {
449   GstMFVP9Enc *self = (GstMFVP9Enc *) mfenc;
450   GstMFVideoEncClass *klass = GST_MF_VIDEO_ENC_GET_CLASS (mfenc);
451   GstMFVideoEncDeviceCaps *device_caps = &klass->device_caps;
452   HRESULT hr;
453   GstMFTransform *transform = mfenc->transform;
454 
455   hr = output_type->SetGUID (MF_MT_SUBTYPE, MFVideoFormat_VP90);
456   if (!gst_mf_result (hr))
457     return FALSE;
458 
459   if (!gst_mf_result (hr))
460     return FALSE;
461 
462   hr = output_type->SetUINT32 (MF_MT_AVG_BITRATE,
463       MIN (self->bitrate * 1024, G_MAXUINT - 1));
464   if (!gst_mf_result (hr))
465     return FALSE;
466 
467   if (device_caps->rc_mode) {
468     guint rc_mode;
469     rc_mode = gst_mf_vp9_enc_rc_mode_to_enum (self->rc_mode);
470     if (rc_mode != G_MAXUINT) {
471       hr = gst_mf_transform_set_codec_api_uint32 (transform,
472           &CODECAPI_AVEncCommonRateControlMode, rc_mode);
473       WARNING_HR (hr, CODECAPI_AVEncCommonRateControlMode);
474     }
475   }
476 
477   if (device_caps->max_bitrate && self->max_bitrate > 0) {
478     hr = gst_mf_transform_set_codec_api_uint32 (transform,
479         &CODECAPI_AVEncCommonMaxBitRate,
480         MIN (self->max_bitrate * 1024, G_MAXUINT - 1));
481     WARNING_HR (hr, CODECAPI_AVEncCommonMaxBitRate);
482   }
483 
484   if (device_caps->quality_vs_speed) {
485     hr = gst_mf_transform_set_codec_api_uint32 (transform,
486         &CODECAPI_AVEncCommonQualityVsSpeed, self->quality_vs_speed);
487     WARNING_HR (hr, CODECAPI_AVEncCommonQualityVsSpeed);
488   }
489 
490   if (device_caps->gop_size) {
491     GstVideoInfo *info = &state->info;
492     gint gop_size = self->gop_size;
493     gint fps_n, fps_d;
494 
495     /* Set default value (10 sec or 250 frames) like that of x264enc */
496     if (gop_size < 0) {
497       fps_n = GST_VIDEO_INFO_FPS_N (info);
498       fps_d = GST_VIDEO_INFO_FPS_D (info);
499       if (fps_n <= 0 || fps_d <= 0) {
500         gop_size = 250;
501       } else {
502         gop_size = 10 * fps_n / fps_d;
503       }
504 
505       GST_DEBUG_OBJECT (self, "Update GOP size to %d", gop_size);
506     }
507 
508     hr = gst_mf_transform_set_codec_api_uint32 (transform,
509         &CODECAPI_AVEncMPVGOPSize, gop_size);
510     WARNING_HR (hr, CODECAPI_AVEncMPVGOPSize);
511   }
512 
513   if (device_caps->threads) {
514     hr = gst_mf_transform_set_codec_api_uint32 (transform,
515         &CODECAPI_AVEncNumWorkerThreads, self->threads);
516     WARNING_HR (hr, CODECAPI_AVEncNumWorkerThreads);
517   }
518 
519   if (device_caps->content_type) {
520     guint content_type;
521     content_type = gst_mf_vp9_enc_content_type_to_enum (self->content_type);
522     if (content_type != G_MAXUINT) {
523       hr = gst_mf_transform_set_codec_api_uint32 (transform,
524           &CODECAPI_AVEncVideoContentType, content_type);
525       WARNING_HR (hr, CODECAPI_AVEncVideoContentType);
526     }
527   }
528 
529   if (device_caps->low_latency) {
530     hr = gst_mf_transform_set_codec_api_boolean (transform,
531         &CODECAPI_AVLowLatencyMode, self->low_latency);
532     WARNING_HR (hr, CODECAPI_AVLowLatencyMode);
533   }
534 
535   return TRUE;
536 }
537 
538 static gboolean
gst_mf_vp9_enc_set_src_caps(GstMFVideoEnc * mfenc,GstVideoCodecState * state,IMFMediaType * output_type)539 gst_mf_vp9_enc_set_src_caps (GstMFVideoEnc * mfenc,
540     GstVideoCodecState * state, IMFMediaType * output_type)
541 {
542   GstMFVP9Enc *self = (GstMFVP9Enc *) mfenc;
543   GstVideoCodecState *out_state;
544   GstStructure *s;
545   GstCaps *out_caps;
546   GstTagList *tags;
547 
548   out_caps = gst_caps_new_empty_simple ("video/x-vp9");
549   s = gst_caps_get_structure (out_caps, 0);
550 
551   out_state = gst_video_encoder_set_output_state (GST_VIDEO_ENCODER (self),
552       out_caps, state);
553 
554   GST_INFO_OBJECT (self, "output caps: %" GST_PTR_FORMAT, out_state->caps);
555 
556   /* encoder will keep it around for us */
557   gst_video_codec_state_unref (out_state);
558 
559   tags = gst_tag_list_new_empty ();
560   gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER,
561       gst_element_get_metadata (GST_ELEMENT_CAST (self),
562           GST_ELEMENT_METADATA_LONGNAME), NULL);
563   gst_video_encoder_merge_tags (GST_VIDEO_ENCODER (self), tags,
564       GST_TAG_MERGE_REPLACE);
565   gst_tag_list_unref (tags);
566 
567   return TRUE;
568 }
569 
570 void
gst_mf_vp9_enc_plugin_init(GstPlugin * plugin,guint rank,GList * d3d11_device)571 gst_mf_vp9_enc_plugin_init (GstPlugin * plugin, guint rank,
572     GList * d3d11_device)
573 {
574   GTypeInfo type_info = {
575     sizeof (GstMFVP9EncClass),
576     NULL,
577     NULL,
578     (GClassInitFunc) gst_mf_vp9_enc_class_init,
579     NULL,
580     NULL,
581     sizeof (GstMFVP9Enc),
582     0,
583     (GInstanceInitFunc) gst_mf_vp9_enc_init,
584   };
585   GUID subtype = MFVideoFormat_VP90;
586 
587   GST_DEBUG_CATEGORY_INIT (gst_mf_vp9_enc_debug, "mfvp9enc", 0, "mfvp9enc");
588 
589   gst_mf_video_enc_register (plugin, rank, &subtype, &type_info, d3d11_device);
590 }
591