qsv: Update SDK version to v2022.2.4
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / sys / qsv / gstqsvencoder.cpp
1 /* GStreamer
2  * Copyright (C) 2021 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 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "gstqsvencoder.h"
25 #include <mfxvideo++.h>
26 #include <string.h>
27 #include <string>
28
29 #ifdef G_OS_WIN32
30 #include "gstqsvallocator_d3d11.h"
31
32 #include <wrl.h>
33
34 /* *INDENT-OFF* */
35 using namespace Microsoft::WRL;
36 /* *INDENT-ON* */
37 #else
38 #include "gstqsvallocator_va.h"
39 #endif /* G_OS_WIN32 */
40
41 GST_DEBUG_CATEGORY_STATIC (gst_qsv_encoder_debug);
42 #define GST_CAT_DEFAULT gst_qsv_encoder_debug
43
44 GType
45 gst_qsv_coding_option_get_type (void)
46 {
47   static GType coding_opt_type = 0;
48   static const GEnumValue coding_opts[] = {
49     {MFX_CODINGOPTION_UNKNOWN, "Unknown", "unknown"},
50     {MFX_CODINGOPTION_ON, "On", "on"},
51     {MFX_CODINGOPTION_OFF, "Off", "off"},
52     {0, nullptr, nullptr}
53   };
54
55   if (g_once_init_enter (&coding_opt_type)) {
56     GType type = g_enum_register_static ("GstQsvCodingOption",
57         coding_opts);
58     g_once_init_leave (&coding_opt_type, type);
59   }
60
61   return coding_opt_type;
62 }
63
64 enum
65 {
66   PROP_0,
67   PROP_ADAPTER_LUID,
68   PROP_DEVICE_PATH,
69   PROP_TARGET_USAGE,
70   PROP_LOW_LATENCY,
71 };
72
73 #define DEFAULT_TARGET_USAGE MFX_TARGETUSAGE_BALANCED
74 #define DEFAULT_LOW_LATENCY  FALSE
75
76 typedef struct _GstQsvEncoderSurface
77 {
78   mfxFrameSurface1 surface;
79   mfxEncodeCtrl encode_control;
80
81   /* array of mfxPayload (e.g., SEI data) associated with this surface */
82   GPtrArray *payload;
83
84   /* holds ownership */
85   GstQsvFrame *qsv_frame;
86 } GstQsvEncoderSurface;
87
88 typedef struct _GstQsvEncoderTask
89 {
90   mfxSyncPoint sync_point;
91   mfxBitstream bitstream;
92 } GstQsvEncoderTask;
93
94 struct _GstQsvEncoderPrivate
95 {
96   GstObject *device;
97
98   GstVideoCodecState *input_state;
99   GstQsvAllocator *allocator;
100
101   /* API specific alignment requirement (multiple of 16 or 32) */
102   GstVideoInfo aligned_info;
103
104   mfxSession session;
105   mfxVideoParam video_param;
106
107   /* List of mfxExtBuffer configured by subclass, subclass will hold
108    * allocated memory for each mfxExtBuffer */
109   GPtrArray *extra_params;
110
111   MFXVideoENCODE *encoder;
112   GstQsvMemoryType mem_type;
113
114   /* Internal buffer pool used to allocate fallback buffer when input buffer
115    * is not compatible with expected format/type/resolution etc */
116   GstBufferPool *internal_pool;
117
118   /* Array of GstQsvEncoderSurface, holding ownership */
119   GArray *surface_pool;
120   guint next_surface_index;
121
122   /* Array of GstQsvEncoderTask, holding ownership */
123   GArray *task_pool;
124
125   GQueue free_tasks;
126   GQueue pending_tasks;
127
128   /* Properties */
129   guint target_usage;
130   gboolean low_latency;
131 };
132
133 #define gst_qsv_encoder_parent_class parent_class
134 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstQsvEncoder, gst_qsv_encoder,
135     GST_TYPE_VIDEO_ENCODER, G_ADD_PRIVATE (GstQsvEncoder);
136     GST_DEBUG_CATEGORY_INIT (gst_qsv_encoder_debug,
137         "qsvencoder", 0, "qsvencoder"));
138
139 static void gst_qsv_encoder_dispose (GObject * object);
140 static void gst_qsv_encoder_finalize (GObject * object);
141 static void gst_qsv_encoder_set_property (GObject * object, guint prop_id,
142     const GValue * value, GParamSpec * pspec);
143 static void gst_qsv_encoder_get_property (GObject * object, guint prop_id,
144     GValue * value, GParamSpec * pspec);
145
146 static void gst_qsv_encoder_set_context (GstElement * element,
147     GstContext * context);
148
149 static gboolean gst_qsv_encoder_open (GstVideoEncoder * encoder);
150 static gboolean gst_qsv_encoder_stop (GstVideoEncoder * encoder);
151 static gboolean gst_qsv_encoder_close (GstVideoEncoder * encoder);
152 static gboolean gst_qsv_encoder_set_format (GstVideoEncoder * encoder,
153     GstVideoCodecState * state);
154 static GstFlowReturn gst_qsv_encoder_handle_frame (GstVideoEncoder * encoder,
155     GstVideoCodecFrame * frame);
156 static GstFlowReturn gst_qsv_encoder_finish (GstVideoEncoder * encoder);
157 static gboolean gst_qsv_encoder_flush (GstVideoEncoder * encoder);
158 static gboolean gst_qsv_encoder_sink_query (GstVideoEncoder * encoder,
159     GstQuery * query);
160 static gboolean gst_qsv_encoder_src_query (GstVideoEncoder * encoder,
161     GstQuery * query);
162 static gboolean gst_qsv_encoder_propose_allocation (GstVideoEncoder * encoder,
163     GstQuery * query);
164
165 static void gst_qsv_encoder_surface_clear (GstQsvEncoderSurface * task);
166 static void gst_qsv_encoder_task_clear (GstQsvEncoderTask * task);
167
168 static void
169 gst_qsv_encoder_class_init (GstQsvEncoderClass * klass)
170 {
171   GObjectClass *object_class = G_OBJECT_CLASS (klass);
172   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
173   GstVideoEncoderClass *videoenc_class = GST_VIDEO_ENCODER_CLASS (klass);
174
175   object_class->dispose = gst_qsv_encoder_dispose;
176   object_class->finalize = gst_qsv_encoder_finalize;
177   object_class->set_property = gst_qsv_encoder_set_property;
178   object_class->get_property = gst_qsv_encoder_get_property;
179
180 #ifdef G_OS_WIN32
181   g_object_class_install_property (object_class, PROP_ADAPTER_LUID,
182       g_param_spec_int64 ("adapter-luid", "Adapter LUID",
183           "DXGI Adapter LUID (Locally Unique Identifier) of created device",
184           G_MININT64, G_MAXINT64, 0,
185           (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE | G_PARAM_READABLE |
186               G_PARAM_STATIC_STRINGS)));
187 #else
188   g_object_class_install_property (object_class, PROP_DEVICE_PATH,
189       g_param_spec_string ("device-path", "Device Path",
190           "DRM device path", NULL,
191           (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
192               G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
193 #endif
194
195   g_object_class_install_property (object_class, PROP_TARGET_USAGE,
196       g_param_spec_uint ("target-usage", "Target Usage",
197           "1: Best quality, 4: Balanced, 7: Best speed",
198           1, 7, DEFAULT_TARGET_USAGE,
199           (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
200
201   g_object_class_install_property (object_class, PROP_LOW_LATENCY,
202       g_param_spec_boolean ("low-latency", "Low Latency",
203           "Enables low-latency encoding", DEFAULT_LOW_LATENCY,
204           (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
205
206   element_class->set_context = GST_DEBUG_FUNCPTR (gst_qsv_encoder_set_context);
207
208   videoenc_class->open = GST_DEBUG_FUNCPTR (gst_qsv_encoder_open);
209   videoenc_class->stop = GST_DEBUG_FUNCPTR (gst_qsv_encoder_stop);
210   videoenc_class->close = GST_DEBUG_FUNCPTR (gst_qsv_encoder_close);
211   videoenc_class->set_format = GST_DEBUG_FUNCPTR (gst_qsv_encoder_set_format);
212   videoenc_class->handle_frame =
213       GST_DEBUG_FUNCPTR (gst_qsv_encoder_handle_frame);
214   videoenc_class->finish = GST_DEBUG_FUNCPTR (gst_qsv_encoder_finish);
215   videoenc_class->flush = GST_DEBUG_FUNCPTR (gst_qsv_encoder_flush);
216   videoenc_class->sink_query = GST_DEBUG_FUNCPTR (gst_qsv_encoder_sink_query);
217   videoenc_class->src_query = GST_DEBUG_FUNCPTR (gst_qsv_encoder_src_query);
218   videoenc_class->propose_allocation =
219       GST_DEBUG_FUNCPTR (gst_qsv_encoder_propose_allocation);
220 }
221
222 static void
223 gst_qsv_encoder_init (GstQsvEncoder * self)
224 {
225   GstQsvEncoderPrivate *priv;
226
227   priv = self->priv =
228       (GstQsvEncoderPrivate *) gst_qsv_encoder_get_instance_private (self);
229
230   priv->extra_params = g_ptr_array_sized_new (8);
231
232   priv->surface_pool = g_array_new (FALSE, TRUE, sizeof (GstQsvEncoderSurface));
233   g_array_set_clear_func (priv->surface_pool,
234       (GDestroyNotify) gst_qsv_encoder_surface_clear);
235
236   priv->task_pool = g_array_new (FALSE, TRUE, sizeof (GstQsvEncoderTask));
237   g_array_set_clear_func (priv->task_pool,
238       (GDestroyNotify) gst_qsv_encoder_task_clear);
239
240   g_queue_init (&priv->free_tasks);
241   g_queue_init (&priv->pending_tasks);
242
243   priv->target_usage = DEFAULT_TARGET_USAGE;
244   priv->low_latency = DEFAULT_LOW_LATENCY;
245 }
246
247 static void
248 gst_qsv_encoder_dispose (GObject * object)
249 {
250   GstQsvEncoder *self = GST_QSV_ENCODER (object);
251   GstQsvEncoderPrivate *priv = self->priv;
252
253   gst_clear_object (&priv->device);
254
255   G_OBJECT_CLASS (parent_class)->dispose (object);
256 }
257
258 static void
259 gst_qsv_encoder_finalize (GObject * object)
260 {
261   GstQsvEncoder *self = GST_QSV_ENCODER (object);
262   GstQsvEncoderPrivate *priv = self->priv;
263
264   g_ptr_array_unref (priv->extra_params);
265   g_array_unref (priv->task_pool);
266   g_array_unref (priv->surface_pool);
267
268   G_OBJECT_CLASS (parent_class)->finalize (object);
269 }
270
271 static void
272 gst_qsv_encoder_set_property (GObject * object, guint prop_id,
273     const GValue * value, GParamSpec * pspec)
274 {
275   GstQsvEncoder *self = GST_QSV_ENCODER (object);
276   GstQsvEncoderPrivate *priv = self->priv;
277
278   switch (prop_id) {
279     case PROP_TARGET_USAGE:
280       priv->target_usage = g_value_get_uint (value);
281       break;
282     case PROP_LOW_LATENCY:
283       priv->low_latency = g_value_get_boolean (value);
284       break;
285     default:
286       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
287       break;
288   }
289 }
290
291 static void
292 gst_qsv_encoder_get_property (GObject * object, guint prop_id, GValue * value,
293     GParamSpec * pspec)
294 {
295   GstQsvEncoder *self = GST_QSV_ENCODER (object);
296   GstQsvEncoderPrivate *priv = self->priv;
297   GstQsvEncoderClass *klass = GST_QSV_ENCODER_GET_CLASS (self);
298
299   switch (prop_id) {
300     case PROP_ADAPTER_LUID:
301       g_value_set_int64 (value, klass->adapter_luid);
302       break;
303     case PROP_DEVICE_PATH:
304       g_value_set_string (value, klass->display_path);
305       break;
306     case PROP_TARGET_USAGE:
307       g_value_set_uint (value, priv->target_usage);
308       break;
309     case PROP_LOW_LATENCY:
310       g_value_set_boolean (value, priv->low_latency);
311       break;
312     default:
313       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
314       break;
315   }
316 }
317
318 static void
319 gst_qsv_encoder_set_context (GstElement * element, GstContext * context)
320 {
321   GstQsvEncoder *self = GST_QSV_ENCODER (element);
322   GstQsvEncoderClass *klass = GST_QSV_ENCODER_GET_CLASS (element);
323   GstQsvEncoderPrivate *priv = self->priv;
324
325 #ifdef G_OS_WIN32
326   gst_d3d11_handle_set_context_for_adapter_luid (element,
327       context, klass->adapter_luid, (GstD3D11Device **) & priv->device);
328 #else
329   gst_va_handle_set_context (element, context, klass->display_path,
330       (GstVaDisplay **) & priv->device);
331 #endif
332
333   GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
334 }
335
336 #ifdef G_OS_WIN32
337 static gboolean
338 gst_qsv_encoder_open_platform_device (GstQsvEncoder * self)
339 {
340   GstQsvEncoderPrivate *priv = self->priv;
341   GstQsvEncoderClass *klass = GST_QSV_ENCODER_GET_CLASS (self);
342   ComPtr < ID3D10Multithread > multi_thread;
343   HRESULT hr;
344   ID3D11Device *device_handle;
345   mfxStatus status;
346   GstD3D11Device *device;
347
348   if (!gst_d3d11_ensure_element_data_for_adapter_luid (GST_ELEMENT (self),
349           klass->adapter_luid, (GstD3D11Device **) & priv->device)) {
350     GST_ERROR_OBJECT (self, "d3d11 device is unavailable");
351     return FALSE;
352   }
353
354   device = GST_D3D11_DEVICE_CAST (priv->device);
355   priv->allocator = gst_qsv_d3d11_allocator_new (device);
356
357   /* For D3D11 device handle to be used by QSV, multithread protection layer
358    * must be enabled before the MFXVideoCORE_SetHandle() call.
359    *
360    * TODO: Need to check performance impact by this mutithread protection layer,
361    * since it may have a negative impact on overall pipeline performance.
362    * If so, we should create encoding session dedicated d3d11 device and
363    * make use of shared resource */
364   device_handle = gst_d3d11_device_get_device_handle (device);
365   hr = device_handle->QueryInterface (IID_PPV_ARGS (&multi_thread));
366   if (!gst_d3d11_result (hr, device)) {
367     GST_ERROR_OBJECT (self, "ID3D10Multithread interface is unavailable");
368     return FALSE;
369   }
370
371   multi_thread->SetMultithreadProtected (TRUE);
372   status = MFXVideoCORE_SetHandle (priv->session, MFX_HANDLE_D3D11_DEVICE,
373       device_handle);
374   if (status != MFX_ERR_NONE) {
375     GST_ERROR_OBJECT (self, "Failed to set d3d11 device handle");
376     return FALSE;
377   }
378
379   /* NOTE: We never use this mfxFrameAllocator to allocate memory from our side,
380    * but required for QSV because:
381    * 1) QSV may request memory allocation for encoder's internal usage,
382    *   MFX_FOURCC_P8 for example
383    * 2) Our mfxFrameAllocator provides bridge layer for
384    *   gst_video_frame_{map,unmap} and mfxFrameAllocator::{Lock,Unlock},
385    *   including mfxFrameAllocator::GetHDL.
386    * 3) GstQsvAllocator provides GstQsvFrame pool, and therefore allocated
387    *   GstQsvFrame struct can be re-used without per-frame malloc/free
388    */
389   status = MFXVideoCORE_SetFrameAllocator (priv->session,
390       gst_qsv_allocator_get_allocator_handle (priv->allocator));
391   if (status != MFX_ERR_NONE) {
392     GST_ERROR_OBJECT (self, "Failed to set frame allocator %d", status);
393     return FALSE;
394   }
395
396   return TRUE;
397 }
398 #else
399 static gboolean
400 gst_qsv_encoder_open_platform_device (GstQsvEncoder * self)
401 {
402   GstQsvEncoderPrivate *priv = self->priv;
403   GstQsvEncoderClass *klass = GST_QSV_ENCODER_GET_CLASS (self);
404   mfxStatus status;
405   GstVaDisplay *display;
406
407   if (!gst_va_ensure_element_data (GST_ELEMENT (self), klass->display_path,
408           (GstVaDisplay **) & priv->device)) {
409     GST_ERROR_OBJECT (self, "VA display is unavailable");
410     return FALSE;
411   }
412
413   display = GST_VA_DISPLAY (priv->device);
414
415   priv->allocator = gst_qsv_va_allocator_new (display);
416
417   status = MFXVideoCORE_SetHandle (priv->session, MFX_HANDLE_VA_DISPLAY,
418       gst_va_display_get_va_dpy (display));
419   if (status != MFX_ERR_NONE) {
420     GST_ERROR_OBJECT (self, "Failed to set VA display handle");
421     return FALSE;
422   }
423
424   status = MFXVideoCORE_SetFrameAllocator (priv->session,
425       gst_qsv_allocator_get_allocator_handle (priv->allocator));
426   if (status != MFX_ERR_NONE) {
427     GST_ERROR_OBJECT (self, "Failed to set frame allocator %d", status);
428     return FALSE;
429   }
430
431   return TRUE;
432 }
433 #endif
434
435 static gboolean
436 gst_qsv_encoder_open (GstVideoEncoder * encoder)
437 {
438   GstQsvEncoder *self = GST_QSV_ENCODER (encoder);
439   GstQsvEncoderPrivate *priv = self->priv;
440   GstQsvEncoderClass *klass = GST_QSV_ENCODER_GET_CLASS (self);
441   mfxStatus status;
442
443   status = MFXCreateSession (gst_qsv_get_loader (), klass->impl_index,
444       &priv->session);
445   if (status != MFX_ERR_NONE) {
446     GST_ERROR_OBJECT (self, "Failed to create session");
447     return FALSE;
448   }
449
450   if (!gst_qsv_encoder_open_platform_device (self)) {
451     g_clear_pointer (&priv->session, MFXClose);
452     gst_clear_object (&priv->allocator);
453     gst_clear_object (&priv->device);
454
455     return FALSE;
456   }
457
458   return TRUE;
459 }
460
461 static gboolean
462 gst_qsv_encoder_reset (GstQsvEncoder * self)
463 {
464   GstQsvEncoderPrivate *priv = self->priv;
465
466   if (priv->encoder) {
467     delete priv->encoder;
468     priv->encoder = nullptr;
469   }
470
471   if (priv->internal_pool) {
472     gst_buffer_pool_set_active (priv->internal_pool, FALSE);
473     gst_clear_object (&priv->internal_pool);
474   }
475
476   g_array_set_size (priv->surface_pool, 0);
477   g_array_set_size (priv->task_pool, 0);
478   g_queue_clear (&priv->free_tasks);
479   g_queue_clear (&priv->pending_tasks);
480
481   return TRUE;
482 }
483
484 static gboolean
485 gst_qsv_encoder_stop (GstVideoEncoder * encoder)
486 {
487   GstQsvEncoder *self = GST_QSV_ENCODER (encoder);
488   GstQsvEncoderPrivate *priv = self->priv;
489
490   gst_qsv_encoder_reset (self);
491   g_clear_pointer (&priv->input_state, gst_video_codec_state_unref);
492
493   return TRUE;
494 }
495
496 static gboolean
497 gst_qsv_encoder_close (GstVideoEncoder * encoder)
498 {
499   GstQsvEncoder *self = GST_QSV_ENCODER (encoder);
500   GstQsvEncoderPrivate *priv = self->priv;
501
502   g_clear_pointer (&priv->session, MFXClose);
503   gst_clear_object (&priv->allocator);
504   gst_clear_object (&priv->device);
505
506   return TRUE;
507 }
508
509 static void
510 gst_qsv_encoder_payload_clear (mfxPayload * payload)
511 {
512   if (!payload)
513     return;
514
515   g_free (payload->Data);
516   g_free (payload);
517 }
518
519 static void
520 gst_qsv_encoder_surface_reset (GstQsvEncoderSurface * surface)
521 {
522   if (!surface)
523     return;
524
525   gst_clear_qsv_frame (&surface->qsv_frame);
526   g_ptr_array_set_size (surface->payload, 0);
527   memset (&surface->encode_control, 0, sizeof (mfxEncodeCtrl));
528 }
529
530 static void
531 gst_qsv_encoder_surface_clear (GstQsvEncoderSurface * surface)
532 {
533   if (!surface)
534     return;
535
536   gst_qsv_encoder_surface_reset (surface);
537   g_clear_pointer (&surface->payload, g_ptr_array_unref);
538   memset (&surface->surface, 0, sizeof (mfxFrameSurface1));
539 }
540
541 static void
542 gst_qsv_encoder_task_reset (GstQsvEncoder * self, GstQsvEncoderTask * task)
543 {
544   GstQsvEncoderPrivate *priv = self->priv;
545
546   if (!task)
547     return;
548
549   task->sync_point = nullptr;
550   task->bitstream.DataLength = 0;
551   g_queue_push_head (&priv->free_tasks, task);
552 }
553
554 static void
555 gst_qsv_encoder_task_clear (GstQsvEncoderTask * task)
556 {
557   if (!task)
558     return;
559
560   g_clear_pointer (&task->bitstream.Data, g_free);
561   memset (&task->bitstream, 0, sizeof (mfxBitstream));
562 }
563
564 static GstQsvEncoderSurface *
565 gst_qsv_encoder_get_next_surface (GstQsvEncoder * self)
566 {
567   GstQsvEncoderPrivate *priv = self->priv;
568   GstQsvEncoderSurface *surface = nullptr;
569
570   for (guint i = priv->next_surface_index; i < priv->surface_pool->len; i++) {
571     GstQsvEncoderSurface *iter =
572         &g_array_index (priv->surface_pool, GstQsvEncoderSurface, i);
573
574     /* This means surface is still being used by QSV */
575     if (iter->surface.Data.Locked > 0)
576       continue;
577
578     surface = iter;
579     priv->next_surface_index = i;
580     goto out;
581   }
582
583   for (guint i = 0; i < priv->next_surface_index; i++) {
584     GstQsvEncoderSurface *iter =
585         &g_array_index (priv->surface_pool, GstQsvEncoderSurface, i);
586
587     /* This means surface is still being used by QSV */
588     if (iter->surface.Data.Locked > 0)
589       continue;
590
591     surface = iter;
592     priv->next_surface_index = i;
593     goto out;
594   }
595
596   /* Magic number to avoid too large pool size */
597   if (priv->surface_pool->len > 64) {
598     GST_ERROR_OBJECT (self,
599         "No availble surface but pool size is too large already");
600     return nullptr;
601   }
602
603   /* Something went wrong, increase surface pool size */
604   GST_INFO_OBJECT (self, "No useable surfaces, increasing pool size to %d",
605       priv->surface_pool->len + 1);
606
607   g_array_set_size (priv->surface_pool, priv->surface_pool->len + 1);
608   surface = &g_array_index (priv->surface_pool, GstQsvEncoderSurface,
609       priv->surface_pool->len - 1);
610
611   memset (surface, 0, sizeof (GstQsvEncoderSurface));
612   surface->surface.Info =
613       g_array_index (priv->surface_pool, GstQsvEncoderSurface, 0).surface.Info;
614   surface->payload = g_ptr_array_new_with_free_func ((GDestroyNotify)
615       gst_qsv_encoder_payload_clear);
616
617 out:
618   priv->next_surface_index++;
619   priv->next_surface_index %= priv->surface_pool->len;
620
621   gst_qsv_encoder_surface_reset (surface);
622   return surface;
623 }
624
625 static mfxStatus
626 gst_qsv_encoder_encode_frame (GstQsvEncoder * self,
627     GstQsvEncoderSurface * surface, GstQsvEncoderTask * task, mfxU64 timestamp)
628 {
629   mfxFrameSurface1 *s;
630   GstQsvEncoderPrivate *priv = self->priv;
631   mfxStatus status;
632   guint retry_count = 0;
633   /* magic number */
634   const guint retry_threshold = 100;
635   mfxEncodeCtrl *encode_ctrl;
636
637   if (surface) {
638     s = &surface->surface;
639     s->Data.MemId = (mfxMemId) surface->qsv_frame;
640     s->Data.TimeStamp = timestamp;
641     encode_ctrl = &surface->encode_control;
642   } else {
643     /* draining */
644     s = nullptr;
645     encode_ctrl = nullptr;
646   }
647
648   do {
649     status = priv->encoder->EncodeFrameAsync (encode_ctrl,
650         s, &task->bitstream, &task->sync_point);
651
652     /* XXX: probably we should try to drain pending tasks if any in this case
653      * as documented? */
654     if (status == MFX_WRN_DEVICE_BUSY && retry_count < retry_threshold) {
655       GST_INFO_OBJECT (self, "GPU is busy, retry count (%d/%d)",
656           retry_count, retry_threshold);
657       retry_count++;
658
659       /* Magic number 10ms */
660       g_usleep (10000);
661       continue;
662     }
663
664     break;
665   } while (TRUE);
666
667   return status;
668 }
669
670 static GstVideoCodecFrame *
671 gst_qsv_encoder_find_output_frame (GstQsvEncoder * self, GstClockTime pts)
672 {
673   GList *frames, *iter;
674   GstVideoCodecFrame *ret = nullptr;
675   GstVideoCodecFrame *closest = nullptr;
676   guint64 min_pts_abs_diff = 0;
677
678   /* give up, just returns the oldest frame */
679   if (!GST_CLOCK_TIME_IS_VALID (pts))
680     return gst_video_encoder_get_oldest_frame (GST_VIDEO_ENCODER (self));
681
682   frames = gst_video_encoder_get_frames (GST_VIDEO_ENCODER (self));
683
684   for (iter = frames; iter; iter = g_list_next (iter)) {
685     GstVideoCodecFrame *frame = (GstVideoCodecFrame *) iter->data;
686     guint64 abs_diff;
687
688     if (!GST_CLOCK_TIME_IS_VALID (frame->pts))
689       continue;
690
691     if (pts == frame->pts) {
692       ret = frame;
693       break;
694     }
695
696     if (pts >= frame->pts)
697       abs_diff = pts - frame->pts;
698     else
699       abs_diff = frame->pts - pts;
700
701     if (!closest || abs_diff < min_pts_abs_diff) {
702       closest = frame;
703       min_pts_abs_diff = abs_diff;
704     }
705   }
706
707   if (!ret && closest)
708     ret = closest;
709
710   if (ret) {
711     gst_video_codec_frame_ref (ret);
712   } else {
713     ret = gst_video_encoder_get_oldest_frame (GST_VIDEO_ENCODER (self));
714   }
715
716   if (frames)
717     g_list_free_full (frames, (GDestroyNotify) gst_video_codec_frame_unref);
718
719   return ret;
720 }
721
722 static GstFlowReturn
723 gst_qsv_encoder_finish_frame (GstQsvEncoder * self, GstQsvEncoderTask * task,
724     gboolean discard)
725 {
726   GstQsvEncoderPrivate *priv = self->priv;
727   GstQsvEncoderClass *klass = GST_QSV_ENCODER_GET_CLASS (self);
728   mfxStatus status;
729   mfxBitstream *bs;
730   GstVideoCodecFrame *frame;
731   GstClockTime qsv_pts = GST_CLOCK_TIME_NONE;
732   GstClockTime qsv_dts = GST_CLOCK_TIME_NONE;
733   GstBuffer *buffer;
734   gboolean keyframe = FALSE;
735   guint retry_count = 0;
736   /* magic number */
737   const guint retry_threshold = 100;
738
739   status = MFX_ERR_NONE;
740   do {
741     /* magic number 100 ms */
742     status = MFXVideoCORE_SyncOperation (priv->session, task->sync_point, 100);
743
744     /* Retry up to 10 sec (100 ms x 100 times), that should be enough time for
745      * encoding a frame using hardware */
746     if (status == MFX_WRN_IN_EXECUTION && retry_count < retry_threshold) {
747       GST_DEBUG_OBJECT (self,
748           "Operation is still in execution, retry count (%d/%d)",
749           retry_count, retry_threshold);
750       retry_count++;
751       continue;
752     }
753
754     break;
755   } while (TRUE);
756
757   if (discard) {
758     gst_qsv_encoder_task_reset (self, task);
759     return GST_FLOW_OK;
760   }
761
762   if (status != MFX_ERR_NONE && status != MFX_ERR_NONE_PARTIAL_OUTPUT) {
763     gst_qsv_encoder_task_reset (self, task);
764
765     if (status == MFX_ERR_ABORTED) {
766       GST_INFO_OBJECT (self, "Operation was aborted");
767       return GST_FLOW_FLUSHING;
768     }
769
770     GST_WARNING_OBJECT (self, "SyncOperation returned %d (%s)",
771         QSV_STATUS_ARGS (status));
772
773     return GST_FLOW_ERROR;
774   }
775
776   bs = &task->bitstream;
777   qsv_pts = gst_qsv_timestamp_to_gst (bs->TimeStamp);
778
779   /* SDK runtime seems to report zero DTS for all fraems in case of VP9.
780    * It sounds SDK bug, but we can workaround it safely because VP9 B-frame is
781    * not supported in this implementation.
782    *
783    * Also we perfer our nanoseconds timestamp instead of QSV's timescale.
784    * So let' ignore QSV's timescale for non-{h264,h265} cases.
785    *
786    * TODO: We may need to use DTS for MPEG2 (not implemented yet)
787    */
788   if (klass->codec_id == MFX_CODEC_AVC || klass->codec_id == MFX_CODEC_HEVC)
789     qsv_dts = gst_qsv_timestamp_to_gst ((mfxU64) bs->DecodeTimeStamp);
790
791   if ((bs->FrameType & MFX_FRAMETYPE_IDR) != 0)
792     keyframe = TRUE;
793
794   if (klass->create_output_buffer) {
795     buffer = klass->create_output_buffer (self, bs);
796   } else {
797     buffer = gst_buffer_new_memdup (bs->Data + bs->DataOffset, bs->DataLength);
798   }
799   gst_qsv_encoder_task_reset (self, task);
800
801   if (!buffer) {
802     GST_ERROR_OBJECT (self, "No output buffer");
803     return GST_FLOW_ERROR;
804   }
805
806   frame = gst_qsv_encoder_find_output_frame (self, qsv_pts);
807   if (frame) {
808     if (GST_CLOCK_TIME_IS_VALID (qsv_dts)) {
809       frame->pts = qsv_pts;
810       frame->dts = qsv_dts;
811     } else {
812       frame->dts = frame->pts;
813     }
814
815     frame->output_buffer = buffer;
816
817     if (keyframe)
818       GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
819
820     return gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (self), frame);
821   }
822
823   /* Empty available frame, something went wrong but we can just push this
824    * buffer */
825   GST_WARNING_OBJECT (self, "Failed to find corresponding frame");
826   GST_BUFFER_PTS (buffer) = qsv_pts;
827   if (GST_CLOCK_TIME_IS_VALID (qsv_dts))
828     GST_BUFFER_DTS (buffer) = qsv_dts;
829   else
830     GST_BUFFER_DTS (buffer) = qsv_pts;
831
832   if (!keyframe)
833     GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
834
835   return gst_pad_push (GST_VIDEO_ENCODER_SRC_PAD (self), buffer);
836 }
837
838 static GstFlowReturn
839 gst_qsv_encoder_drain (GstQsvEncoder * self, gboolean discard)
840 {
841   GstQsvEncoderPrivate *priv = self->priv;
842   mfxStatus status = MFX_ERR_NONE;
843   GstFlowReturn ret = GST_FLOW_OK;
844   GstQsvEncoderTask *task;
845
846   if (!priv->session || !priv->encoder)
847     return GST_FLOW_OK;
848
849   GST_DEBUG_OBJECT (self, "Drain");
850
851   /* Drain pending tasks first if any */
852   while (g_queue_get_length (&priv->pending_tasks) > 0) {
853     task = (GstQsvEncoderTask *) g_queue_pop_tail (&priv->pending_tasks);
854     ret = gst_qsv_encoder_finish_frame (self, task, discard);
855   }
856
857   while (status == MFX_ERR_NONE) {
858     task = (GstQsvEncoderTask *) g_queue_pop_tail (&priv->free_tasks);
859     status = gst_qsv_encoder_encode_frame (self,
860         nullptr, task, MFX_TIMESTAMP_UNKNOWN);
861
862     /* once it's fully drained, then driver will return more data */
863     if (status == MFX_ERR_NONE && task->sync_point) {
864       ret = gst_qsv_encoder_finish_frame (self, task, discard);
865       continue;
866     }
867
868     if (status != MFX_ERR_MORE_DATA)
869       GST_WARNING_OBJECT (self, "Unexpected status return %d (%s)",
870           QSV_STATUS_ARGS (status));
871
872     g_queue_push_head (&priv->free_tasks, task);
873   }
874
875   /* Release GstQsvFrame objects */
876   for (guint i = 0; i < priv->surface_pool->len; i++) {
877     GstQsvEncoderSurface *iter =
878         &g_array_index (priv->surface_pool, GstQsvEncoderSurface, i);
879
880     if (iter->surface.Data.Locked > 0) {
881       GST_WARNING_OBJECT (self,
882           "Encoder was drained but QSV is holding surface %d", i);
883       continue;
884     }
885
886     gst_qsv_encoder_surface_reset (iter);
887   }
888
889   return ret;
890 }
891
892 #ifdef G_OS_WIN32
893 static gboolean
894 gst_qsv_encoder_prepare_d3d11_pool (GstQsvEncoder * self,
895     GstCaps * caps, GstVideoInfo * aligned_info)
896 {
897   GstQsvEncoderPrivate *priv = self->priv;
898   GstStructure *config;
899   GstD3D11AllocationParams *params;
900   GstD3D11Device *device = GST_D3D11_DEVICE_CAST (priv->device);
901   guint bind_flags = 0;
902   GstD3D11Format device_format;
903
904   gst_d3d11_device_get_format (device, GST_VIDEO_INFO_FORMAT (aligned_info),
905       &device_format);
906   if ((device_format.format_support[0] & D3D11_FORMAT_SUPPORT_RENDER_TARGET) ==
907       D3D11_FORMAT_SUPPORT_RENDER_TARGET) {
908     /* XXX: workaround for greenish artifacts
909      * https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1238
910      * bind to render target so that d3d11 memory allocator can clear texture
911      * with black color */
912     bind_flags = D3D11_BIND_RENDER_TARGET;
913   }
914
915   priv->internal_pool = gst_d3d11_buffer_pool_new (device);
916   config = gst_buffer_pool_get_config (priv->internal_pool);
917   params = gst_d3d11_allocation_params_new (device, aligned_info,
918       GST_D3D11_ALLOCATION_FLAG_DEFAULT, bind_flags,
919       D3D11_RESOURCE_MISC_SHARED);
920
921   gst_buffer_pool_config_set_d3d11_allocation_params (config, params);
922   gst_d3d11_allocation_params_free (params);
923   gst_buffer_pool_config_set_params (config, caps,
924       GST_VIDEO_INFO_SIZE (aligned_info), 0, 0);
925   gst_buffer_pool_set_config (priv->internal_pool, config);
926   gst_buffer_pool_set_active (priv->internal_pool, TRUE);
927
928   return TRUE;
929 }
930 #else
931 static gboolean
932 gst_qsv_encoder_prepare_va_pool (GstQsvEncoder * self,
933     GstCaps * caps, GstVideoInfo * aligned_info)
934 {
935   GstQsvEncoderPrivate *priv = self->priv;
936   GstAllocator *allocator;
937   GstStructure *config;
938   GArray *formats;
939   GstAllocationParams params;
940   GstVaDisplay *display = GST_VA_DISPLAY (priv->device);
941
942   formats = g_array_new (FALSE, FALSE, sizeof (GstVideoFormat));
943   g_array_append_val (formats, GST_VIDEO_INFO_FORMAT (aligned_info));
944
945   allocator = gst_va_allocator_new (display, formats);
946   if (!allocator) {
947     GST_ERROR_OBJECT (self, "Failed to create allocator");
948     return FALSE;
949   }
950
951   gst_allocation_params_init (&params);
952
953   priv->internal_pool = gst_va_pool_new_with_config (caps,
954       GST_VIDEO_INFO_SIZE (aligned_info), 0, 0,
955       VA_SURFACE_ATTRIB_USAGE_HINT_GENERIC, GST_VA_FEATURE_AUTO,
956       allocator, &params);
957   gst_object_unref (allocator);
958
959
960   if (!priv->internal_pool) {
961     GST_ERROR_OBJECT (self, "Failed to create va pool");
962     return FALSE;
963   }
964
965   config = gst_buffer_pool_get_config (priv->internal_pool);
966   gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
967   gst_buffer_pool_config_set_params (config, caps,
968       GST_VIDEO_INFO_SIZE (aligned_info), 0, 0);
969   gst_buffer_pool_set_config (priv->internal_pool, config);
970   gst_buffer_pool_set_active (priv->internal_pool, TRUE);
971
972   return TRUE;
973 }
974 #endif
975
976 /* Prepare internal pool, which is used to allocate fallback buffer
977  * when upstream buffer is not directly accessible by QSV */
978 static gboolean
979 gst_qsv_encoder_prepare_pool (GstQsvEncoder * self, GstCaps * caps,
980     GstVideoInfo * aligned_info)
981 {
982   GstQsvEncoderPrivate *priv = self->priv;
983   gboolean ret = FALSE;
984   GstCaps *aligned_caps;
985
986   if (priv->internal_pool) {
987     gst_buffer_pool_set_active (priv->internal_pool, FALSE);
988     gst_clear_object (&priv->internal_pool);
989   }
990
991   aligned_caps = gst_video_info_to_caps (aligned_info);
992
993 #ifdef G_OS_WIN32
994   ret = gst_qsv_encoder_prepare_d3d11_pool (self, aligned_caps, aligned_info);
995 #else
996   ret = gst_qsv_encoder_prepare_va_pool (self, aligned_caps, aligned_info);
997 #endif
998
999   gst_caps_unref (aligned_caps);
1000
1001   return ret;
1002 }
1003
1004 static gboolean
1005 gst_qsv_encoder_init_encode_session (GstQsvEncoder * self)
1006 {
1007   GstQsvEncoderPrivate *priv = self->priv;
1008   GstQsvEncoderClass *klass = GST_QSV_ENCODER_GET_CLASS (self);
1009   GstVideoInfo *info = &priv->input_state->info;
1010   GstCaps *caps = priv->input_state->caps;
1011   mfxVideoParam param;
1012   mfxFrameInfo *frame_info;
1013   mfxFrameAllocRequest alloc_request;
1014   mfxStatus status;
1015   MFXVideoENCODE *encoder_handle = nullptr;
1016   guint bitstream_size;
1017   gboolean ret;
1018   guint64 min_delay_frames, max_delay_frames;
1019   GstClockTime min_latency, max_latency;
1020
1021   gst_qsv_encoder_drain (self, FALSE);
1022   gst_qsv_encoder_reset (self);
1023
1024   encoder_handle = new MFXVideoENCODE (priv->session);
1025
1026   memset (&param, 0, sizeof (mfxVideoParam));
1027
1028   g_ptr_array_set_size (priv->extra_params, 0);
1029   g_assert (klass->set_format);
1030   if (!klass->set_format (self, priv->input_state, &param, priv->extra_params)) {
1031     GST_ERROR_OBJECT (self, "Subclass failed to set format");
1032     goto error;
1033   }
1034
1035   /* LowPower mode supports smaller set of features, don't enable it for now */
1036   param.mfx.LowPower = MFX_CODINGOPTION_OFF;
1037   if (priv->low_latency)
1038     param.AsyncDepth = 1;
1039   else
1040     param.AsyncDepth = 4;
1041
1042   param.mfx.TargetUsage = priv->target_usage;
1043
1044   frame_info = &param.mfx.FrameInfo;
1045
1046   gst_video_info_set_interlaced_format (&priv->aligned_info,
1047       GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_INTERLACE_MODE (info),
1048       frame_info->Width, frame_info->Height);
1049
1050   /* Always video memory, even when upstream is non-hardware element */
1051   priv->mem_type = GST_QSV_VIDEO_MEMORY | GST_QSV_ENCODER_IN_MEMORY;
1052   param.IOPattern = MFX_IOPATTERN_IN_VIDEO_MEMORY;
1053   if (!gst_qsv_encoder_prepare_pool (self, caps, &priv->aligned_info)) {
1054     GST_ERROR_OBJECT (self, "Failed to prepare pool");
1055     goto error;
1056   }
1057
1058   status = encoder_handle->Query (&param, &param);
1059   /* If device is unhappy with LowPower = OFF, try again with unknown */
1060   if (status < MFX_ERR_NONE) {
1061     GST_INFO_OBJECT (self, "LowPower - OFF returned %d (%s)",
1062         QSV_STATUS_ARGS (status));
1063     param.mfx.LowPower = MFX_CODINGOPTION_UNKNOWN;
1064     status = encoder_handle->Query (&param, &param);
1065   }
1066   QSV_CHECK_STATUS (self, status, MFXVideoENCODE::Query);
1067
1068   status = encoder_handle->QueryIOSurf (&param, &alloc_request);
1069   QSV_CHECK_STATUS (self, status, MFXVideoENCODE::QueryIOSurf);
1070
1071   status = encoder_handle->Init (&param);
1072   QSV_CHECK_STATUS (self, status, MFXVideoENCODE::Init);
1073
1074   status = encoder_handle->GetVideoParam (&param);
1075   QSV_CHECK_STATUS (self, status, MFXVideoENCODE::GetVideoParam);
1076
1077   GST_DEBUG_OBJECT (self, "NumFrameSuggested: %d, AsyncDepth %d",
1078       alloc_request.NumFrameSuggested, param.AsyncDepth);
1079
1080   g_assert (klass->set_output_state);
1081   ret = klass->set_output_state (self, priv->input_state, priv->session);
1082   if (!ret) {
1083     GST_ERROR_OBJECT (self, "Subclass failed to set output state");
1084     goto error;
1085   }
1086
1087   /* Prepare surface pool with size NumFrameSuggested, then if it's not
1088    * sufficient while encoding, we can increse the pool size dynamically
1089    * if needed */
1090   g_array_set_size (priv->surface_pool, alloc_request.NumFrameSuggested);
1091   for (guint i = 0; i < priv->surface_pool->len; i++) {
1092     GstQsvEncoderSurface *surface = &g_array_index (priv->surface_pool,
1093         GstQsvEncoderSurface, i);
1094
1095     surface->surface.Info = param.mfx.FrameInfo;
1096     surface->payload = g_ptr_array_new_with_free_func ((GDestroyNotify)
1097         gst_qsv_encoder_payload_clear);
1098   }
1099   priv->next_surface_index = 0;
1100
1101   g_array_set_size (priv->task_pool, param.AsyncDepth);
1102   if (klass->codec_id == MFX_CODEC_JPEG) {
1103     gdouble factor = 4.0;
1104
1105     /* jpeg zero returns buffer size */
1106     switch (GST_VIDEO_INFO_FORMAT (info)) {
1107       case GST_VIDEO_FORMAT_NV12:
1108         factor = 1.5;
1109         break;
1110       case GST_VIDEO_FORMAT_YUY2:
1111         factor = 2.0;
1112         break;
1113       default:
1114         break;
1115     }
1116     bitstream_size = (guint)
1117         (factor * GST_VIDEO_INFO_WIDTH (info) * GST_VIDEO_INFO_HEIGHT (info));
1118   } else {
1119     bitstream_size =
1120         (guint) param.mfx.BufferSizeInKB * param.mfx.BRCParamMultiplier * 1024;
1121   }
1122
1123   for (guint i = 0; i < priv->task_pool->len; i++) {
1124     GstQsvEncoderTask *task = &g_array_index (priv->task_pool,
1125         GstQsvEncoderTask, i);
1126
1127     task->bitstream.Data = (mfxU8 *) g_malloc (bitstream_size);
1128     task->bitstream.MaxLength = bitstream_size;
1129
1130     g_queue_push_head (&priv->free_tasks, task);
1131   }
1132
1133   min_delay_frames = priv->task_pool->len;
1134   /* takes the number of bframes into account */
1135   if (param.mfx.GopRefDist > 1)
1136     min_delay_frames += (param.mfx.GopRefDist - 1);
1137   max_delay_frames = priv->surface_pool->len + priv->task_pool->len;
1138
1139   min_latency = gst_util_uint64_scale (min_delay_frames * GST_SECOND,
1140       param.mfx.FrameInfo.FrameRateExtD, param.mfx.FrameInfo.FrameRateExtN);
1141   max_latency = gst_util_uint64_scale (max_delay_frames * GST_SECOND,
1142       param.mfx.FrameInfo.FrameRateExtD, param.mfx.FrameInfo.FrameRateExtN);
1143   gst_video_encoder_set_latency (GST_VIDEO_ENCODER (self),
1144       min_latency, max_latency);
1145
1146   priv->video_param = param;
1147   priv->encoder = encoder_handle;
1148
1149   return TRUE;
1150
1151 error:
1152   if (encoder_handle)
1153     delete encoder_handle;
1154
1155   gst_qsv_encoder_reset (self);
1156
1157   return FALSE;
1158 }
1159
1160 static gboolean
1161 gst_qsv_encoder_reset_encode_session (GstQsvEncoder * self)
1162 {
1163   GstQsvEncoderPrivate *priv = self->priv;
1164   GPtrArray *extra_params = priv->extra_params;
1165   mfxStatus status;
1166   mfxExtEncoderResetOption reset_opt;
1167
1168   if (!priv->encoder) {
1169     GST_WARNING_OBJECT (self, "Encoder was not configured");
1170     return gst_qsv_encoder_init_encode_session (self);
1171   }
1172
1173   reset_opt.Header.BufferId = MFX_EXTBUFF_ENCODER_RESET_OPTION;
1174   reset_opt.Header.BufferSz = sizeof (mfxExtEncoderResetOption);
1175   reset_opt.StartNewSequence = MFX_CODINGOPTION_OFF;
1176
1177   gst_qsv_encoder_drain (self, FALSE);
1178
1179   g_ptr_array_add (extra_params, &reset_opt);
1180   priv->video_param.ExtParam = (mfxExtBuffer **) extra_params->pdata;
1181   priv->video_param.NumExtParam = extra_params->len;
1182
1183   status = priv->encoder->Reset (&priv->video_param);
1184   g_ptr_array_remove_index (extra_params, extra_params->len - 1);
1185   priv->video_param.NumExtParam = extra_params->len;
1186
1187   if (status != MFX_ERR_NONE) {
1188     GST_WARNING_OBJECT (self, "MFXVideoENCODE_Reset returned %d (%s)",
1189         QSV_STATUS_ARGS (status));
1190     return gst_qsv_encoder_init_encode_session (self);
1191   }
1192
1193   GST_DEBUG_OBJECT (self, "Encode session reset done");
1194
1195   return TRUE;
1196 }
1197
1198 static gboolean
1199 gst_qsv_encoder_set_format (GstVideoEncoder * encoder,
1200     GstVideoCodecState * state)
1201 {
1202   GstQsvEncoder *self = GST_QSV_ENCODER (encoder);
1203   GstQsvEncoderPrivate *priv = self->priv;
1204
1205   g_clear_pointer (&priv->input_state, gst_video_codec_state_unref);
1206   priv->input_state = gst_video_codec_state_ref (state);
1207
1208   return gst_qsv_encoder_init_encode_session (self);
1209 }
1210
1211 static mfxU16
1212 gst_qsv_encoder_get_pic_struct (GstQsvEncoder * self,
1213     GstVideoCodecFrame * frame)
1214 {
1215   GstQsvEncoderClass *klass = GST_QSV_ENCODER_GET_CLASS (self);
1216   GstQsvEncoderPrivate *priv = self->priv;
1217   GstVideoInfo *info = &priv->input_state->info;
1218
1219   if (klass->codec_id != MFX_CODEC_AVC)
1220     return MFX_PICSTRUCT_PROGRESSIVE;
1221
1222   if (!GST_VIDEO_INFO_IS_INTERLACED (info))
1223     return MFX_PICSTRUCT_PROGRESSIVE;
1224
1225   if (GST_VIDEO_INFO_INTERLACE_MODE (info) == GST_VIDEO_INTERLACE_MODE_MIXED) {
1226     if (!GST_BUFFER_FLAG_IS_SET (frame->input_buffer,
1227             GST_VIDEO_BUFFER_FLAG_INTERLACED)) {
1228       return MFX_PICSTRUCT_PROGRESSIVE;
1229     }
1230
1231     if (GST_BUFFER_FLAG_IS_SET (frame->input_buffer, GST_VIDEO_BUFFER_FLAG_TFF))
1232       return MFX_PICSTRUCT_FIELD_TFF;
1233
1234     return MFX_PICSTRUCT_FIELD_BFF;
1235   }
1236
1237   switch (GST_VIDEO_INFO_FIELD_ORDER (info)) {
1238     case GST_VIDEO_FIELD_ORDER_TOP_FIELD_FIRST:
1239       return MFX_PICSTRUCT_FIELD_TFF;
1240       break;
1241     case GST_VIDEO_FIELD_ORDER_BOTTOM_FIELD_FIRST:
1242       return MFX_PICSTRUCT_FIELD_BFF;
1243       break;
1244     default:
1245       break;
1246   }
1247
1248   if (GST_BUFFER_FLAG_IS_SET (frame->input_buffer, GST_VIDEO_BUFFER_FLAG_TFF))
1249     return MFX_PICSTRUCT_FIELD_TFF;
1250
1251   return MFX_PICSTRUCT_FIELD_BFF;
1252 }
1253
1254 static GstFlowReturn
1255 gst_qsv_encoder_handle_frame (GstVideoEncoder * encoder,
1256     GstVideoCodecFrame * frame)
1257 {
1258   GstQsvEncoder *self = GST_QSV_ENCODER (encoder);
1259   GstQsvEncoderPrivate *priv = self->priv;
1260   GstQsvEncoderClass *klass = GST_QSV_ENCODER_GET_CLASS (self);
1261   GstFlowReturn ret = GST_FLOW_ERROR;
1262   GstQsvEncoderSurface *surface;
1263   GstQsvEncoderTask *task;
1264   mfxU64 timestamp;
1265   mfxStatus status;
1266
1267   if (klass->check_reconfigure && priv->encoder) {
1268     GstQsvEncoderReconfigure reconfigure;
1269
1270     reconfigure = klass->check_reconfigure (self, priv->session,
1271         &priv->video_param, priv->extra_params);
1272
1273     switch (reconfigure) {
1274       case GST_QSV_ENCODER_RECONFIGURE_BITRATE:
1275         if (!gst_qsv_encoder_reset_encode_session (self)) {
1276           GST_ERROR_OBJECT (self, "Failed to reset session");
1277           gst_video_encoder_finish_frame (encoder, frame);
1278
1279           return GST_FLOW_ERROR;
1280         }
1281         break;
1282       case GST_QSV_ENCODER_RECONFIGURE_FULL:
1283         if (!gst_qsv_encoder_init_encode_session (self)) {
1284           GST_ERROR_OBJECT (self, "Failed to init session");
1285           gst_video_encoder_finish_frame (encoder, frame);
1286
1287           return GST_FLOW_ERROR;
1288         }
1289         break;
1290       default:
1291         break;
1292     }
1293   }
1294
1295   if (!priv->encoder) {
1296     GST_ERROR_OBJECT (self, "Encoder object was not configured");
1297     gst_video_encoder_finish_frame (encoder, frame);
1298
1299     return GST_FLOW_NOT_NEGOTIATED;
1300   }
1301
1302   surface = gst_qsv_encoder_get_next_surface (self);
1303   if (!surface) {
1304     GST_ERROR_OBJECT (self, "No available surface");
1305     goto out;
1306   }
1307
1308   task = (GstQsvEncoderTask *) g_queue_pop_tail (&priv->free_tasks);
1309   g_assert (task);
1310
1311   surface->qsv_frame =
1312       gst_qsv_allocator_acquire_frame (priv->allocator, priv->mem_type,
1313       &priv->input_state->info, gst_buffer_ref (frame->input_buffer),
1314       priv->internal_pool);
1315
1316   if (!surface->qsv_frame) {
1317     GST_ERROR_OBJECT (self, "Failed to wrap buffer with qsv frame");
1318     gst_qsv_encoder_task_reset (self, task);
1319     goto out;
1320   }
1321
1322   surface->surface.Info.PicStruct =
1323       gst_qsv_encoder_get_pic_struct (self, frame);
1324
1325   if (GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame)) {
1326     surface->encode_control.FrameType =
1327         MFX_FRAMETYPE_IDR | MFX_FRAMETYPE_I | MFX_FRAMETYPE_REF;
1328   } else {
1329     surface->encode_control.FrameType = MFX_FRAMETYPE_UNKNOWN;
1330   }
1331
1332   if (klass->attach_payload) {
1333     klass->attach_payload (self, frame, surface->payload);
1334     if (surface->payload->len > 0) {
1335       surface->encode_control.NumPayload = surface->payload->len;
1336       surface->encode_control.Payload = (mfxPayload **) surface->payload->pdata;
1337     }
1338   }
1339
1340   timestamp = gst_qsv_timestamp_from_gst (frame->pts);
1341   status = gst_qsv_encoder_encode_frame (self, surface, task, timestamp);
1342   if (status != MFX_ERR_NONE && status != MFX_ERR_MORE_DATA) {
1343     GST_ERROR_OBJECT (self, "Failed to encode frame, ret %d (%s)",
1344         QSV_STATUS_ARGS (status));
1345     gst_qsv_encoder_task_reset (self, task);
1346     goto out;
1347   }
1348
1349   if (status == MFX_ERR_NONE && task->sync_point) {
1350     g_queue_push_head (&priv->pending_tasks, task);
1351   } else {
1352     gst_qsv_encoder_task_reset (self, task);
1353   }
1354
1355   ret = GST_FLOW_OK;
1356   /* Do not sync immediately, but record tasks which have output buffer here
1357    * to improve throughput.
1358    * In this way, hardware may be able to run encoding job from its background
1359    * threads (if any). We will do sync only when there's no more free task item
1360    */
1361   while (g_queue_get_length (&priv->pending_tasks) >= priv->task_pool->len) {
1362     GstQsvEncoderTask *task =
1363         (GstQsvEncoderTask *) g_queue_pop_tail (&priv->pending_tasks);
1364     ret = gst_qsv_encoder_finish_frame (self, task, FALSE);
1365   }
1366
1367 out:
1368   gst_video_codec_frame_unref (frame);
1369
1370   return ret;
1371 }
1372
1373 static GstFlowReturn
1374 gst_qsv_encoder_finish (GstVideoEncoder * encoder)
1375 {
1376   GstQsvEncoder *self = GST_QSV_ENCODER (encoder);
1377
1378   return gst_qsv_encoder_drain (self, FALSE);
1379 }
1380
1381 static gboolean
1382 gst_qsv_encoder_flush (GstVideoEncoder * encoder)
1383 {
1384   GstQsvEncoder *self = GST_QSV_ENCODER (encoder);
1385
1386   gst_qsv_encoder_drain (self, TRUE);
1387
1388   return TRUE;
1389 }
1390
1391 static gboolean
1392 gst_qsv_encoder_handle_context_query (GstQsvEncoder * self, GstQuery * query)
1393 {
1394   GstQsvEncoderPrivate *priv = self->priv;
1395
1396 #ifdef G_OS_WIN32
1397   return gst_d3d11_handle_context_query (GST_ELEMENT (self), query,
1398       (GstD3D11Device *) priv->device);
1399 #else
1400   return gst_va_handle_context_query (GST_ELEMENT (self), query,
1401       (GstVaDisplay *) priv->device);
1402 #endif
1403 }
1404
1405 static gboolean
1406 gst_qsv_encoder_sink_query (GstVideoEncoder * encoder, GstQuery * query)
1407 {
1408   GstQsvEncoder *self = GST_QSV_ENCODER (encoder);
1409
1410   switch (GST_QUERY_TYPE (query)) {
1411     case GST_QUERY_CONTEXT:
1412       if (gst_qsv_encoder_handle_context_query (self, query))
1413         return TRUE;
1414       break;
1415     default:
1416       break;
1417   }
1418
1419   return GST_VIDEO_ENCODER_CLASS (parent_class)->sink_query (encoder, query);
1420 }
1421
1422 static gboolean
1423 gst_qsv_encoder_src_query (GstVideoEncoder * encoder, GstQuery * query)
1424 {
1425   GstQsvEncoder *self = GST_QSV_ENCODER (encoder);
1426
1427   switch (GST_QUERY_TYPE (query)) {
1428     case GST_QUERY_CONTEXT:
1429       if (gst_qsv_encoder_handle_context_query (self, query))
1430         return TRUE;
1431       break;
1432     default:
1433       break;
1434   }
1435
1436   return GST_VIDEO_ENCODER_CLASS (parent_class)->src_query (encoder, query);
1437 }
1438
1439 #ifdef G_OS_WIN32
1440 static gboolean
1441 gst_qsv_encoder_propose_allocation (GstVideoEncoder * encoder, GstQuery * query)
1442 {
1443   GstQsvEncoder *self = GST_QSV_ENCODER (encoder);
1444   GstQsvEncoderPrivate *priv = self->priv;
1445   GstD3D11Device *device = GST_D3D11_DEVICE (priv->device);
1446   GstVideoInfo info;
1447   GstBufferPool *pool;
1448   GstCaps *caps;
1449   guint size;
1450   GstStructure *config;
1451   GstCapsFeatures *features;
1452   gboolean is_d3d11 = FALSE;
1453
1454   gst_query_parse_allocation (query, &caps, nullptr);
1455   if (!caps) {
1456     GST_WARNING_OBJECT (self, "null caps in query");
1457     return FALSE;
1458   }
1459
1460   if (!gst_video_info_from_caps (&info, caps)) {
1461     GST_WARNING_OBJECT (self, "Failed to convert caps into info");
1462     return FALSE;
1463   }
1464
1465   features = gst_caps_get_features (caps, 0);
1466   if (features && gst_caps_features_contains (features,
1467           GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY)) {
1468     GST_DEBUG_OBJECT (self, "upstream support d3d11 memory");
1469     pool = gst_d3d11_buffer_pool_new (device);
1470     is_d3d11 = TRUE;
1471   } else {
1472     pool = gst_video_buffer_pool_new ();
1473   }
1474
1475   config = gst_buffer_pool_get_config (pool);
1476   gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
1477
1478   if (is_d3d11) {
1479     GstD3D11AllocationParams *d3d11_params;
1480     GstVideoAlignment align;
1481
1482     /* d3d11 buffer pool doesn't support generic video alignment
1483      * because memory layout of CPU accessible staging texture is uncontrollable.
1484      * Do D3D11 specific handling */
1485     gst_video_alignment_reset (&align);
1486
1487     align.padding_right = GST_VIDEO_INFO_WIDTH (&priv->aligned_info) -
1488         GST_VIDEO_INFO_WIDTH (&info);
1489     align.padding_bottom = GST_VIDEO_INFO_HEIGHT (&priv->aligned_info) -
1490         GST_VIDEO_INFO_HEIGHT (&info);
1491
1492     d3d11_params = gst_d3d11_allocation_params_new (device, &info,
1493         GST_D3D11_ALLOCATION_FLAG_DEFAULT, 0, 0);
1494
1495     gst_d3d11_allocation_params_alignment (d3d11_params, &align);
1496     gst_buffer_pool_config_set_d3d11_allocation_params (config, d3d11_params);
1497     gst_d3d11_allocation_params_free (d3d11_params);
1498   } else {
1499     gst_buffer_pool_config_add_option (config,
1500         GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
1501   }
1502
1503   size = GST_VIDEO_INFO_SIZE (&info);
1504   gst_buffer_pool_config_set_params (config,
1505       caps, size, priv->surface_pool->len, 0);
1506
1507   if (!gst_buffer_pool_set_config (pool, config)) {
1508     GST_WARNING_OBJECT (self, "Failed to set pool config");
1509     gst_object_unref (pool);
1510     return FALSE;
1511   }
1512
1513   /* d3d11 buffer pool will update actual CPU accessible buffer size based on
1514    * allocated staging texture per gst_buffer_pool_set_config() call,
1515    * need query again to get the size */
1516   config = gst_buffer_pool_get_config (pool);
1517   gst_buffer_pool_config_get_params (config, nullptr, &size, nullptr, nullptr);
1518   gst_structure_free (config);
1519
1520   gst_query_add_allocation_pool (query, pool, size, priv->surface_pool->len, 0);
1521   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, nullptr);
1522   gst_object_unref (pool);
1523
1524   return TRUE;
1525 }
1526 #else
1527 static gboolean
1528 gst_qsv_encoder_propose_allocation (GstVideoEncoder * encoder, GstQuery * query)
1529 {
1530   GstQsvEncoder *self = GST_QSV_ENCODER (encoder);
1531   GstQsvEncoderPrivate *priv = self->priv;
1532   GstVideoInfo info;
1533   GstAllocator *allocator = nullptr;
1534   GstBufferPool *pool;
1535   GstCaps *caps;
1536   guint size;
1537   GstStructure *config;
1538   GstVideoAlignment align;
1539   GstAllocationParams params;
1540   GArray *formats;
1541
1542   gst_query_parse_allocation (query, &caps, nullptr);
1543   if (!caps) {
1544     GST_WARNING_OBJECT (self, "null caps in query");
1545     return FALSE;
1546   }
1547
1548   if (!gst_video_info_from_caps (&info, caps)) {
1549     GST_WARNING_OBJECT (self, "Failed to convert caps into info");
1550     return FALSE;
1551   }
1552
1553   gst_allocation_params_init (&params);
1554
1555   formats = g_array_new (FALSE, FALSE, sizeof (GstVideoFormat));
1556   g_array_append_val (formats, GST_VIDEO_INFO_FORMAT (&info));
1557
1558   allocator = gst_va_allocator_new (GST_VA_DISPLAY (priv->device), formats);
1559   if (!allocator) {
1560     GST_ERROR_OBJECT (self, "Failed to create allocator");
1561     return FALSE;
1562   }
1563
1564   pool = gst_va_pool_new_with_config (caps,
1565       GST_VIDEO_INFO_SIZE (&info), priv->surface_pool->len, 0,
1566       VA_SURFACE_ATTRIB_USAGE_HINT_GENERIC, GST_VA_FEATURE_AUTO,
1567       allocator, &params);
1568
1569   if (!pool) {
1570     GST_ERROR_OBJECT (self, "Failed to create va pool");
1571     gst_object_unref (allocator);
1572
1573     return FALSE;
1574   }
1575
1576   gst_video_alignment_reset (&align);
1577   align.padding_right = GST_VIDEO_INFO_WIDTH (&priv->aligned_info) -
1578       GST_VIDEO_INFO_WIDTH (&info);
1579   align.padding_bottom = GST_VIDEO_INFO_HEIGHT (&priv->aligned_info) -
1580       GST_VIDEO_INFO_HEIGHT (&info);
1581
1582   config = gst_buffer_pool_get_config (pool);
1583   gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
1584   gst_buffer_pool_config_add_option (config,
1585       GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
1586   gst_buffer_pool_config_set_video_alignment (config, &align);
1587
1588   gst_buffer_pool_config_set_params (config,
1589       caps, GST_VIDEO_INFO_SIZE (&info), priv->surface_pool->len, 0);
1590
1591   if (!gst_buffer_pool_set_config (pool, config)) {
1592     GST_ERROR_OBJECT (self, "Failed to set pool config");
1593     gst_clear_object (&allocator);
1594     gst_object_unref (pool);
1595     return FALSE;
1596   }
1597
1598   if (allocator)
1599     gst_query_add_allocation_param (query, allocator, &params);
1600
1601   config = gst_buffer_pool_get_config (pool);
1602   gst_buffer_pool_config_get_params (config, nullptr, &size, nullptr, nullptr);
1603   gst_structure_free (config);
1604
1605   gst_query_add_allocation_pool (query, pool, size, priv->surface_pool->len, 0);
1606   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, nullptr);
1607
1608   gst_clear_object (&allocator);
1609   gst_object_unref (pool);
1610
1611   return TRUE;
1612 }
1613 #endif