2cadb5d497cf4278f4c03c540278d0b7fc22367a
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / sys / va / gstvabaseenc.c
1 /* GStreamer
2  *  Copyright (C) 2022 Intel Corporation
3  *     Author: He Junyan <junyan.he@intel.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the0
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #include "gstvabaseenc.h"
22
23 #include <gst/va/gstva.h>
24 #include <gst/va/vasurfaceimage.h>
25
26 #include "vacompat.h"
27 #include "gstvacaps.h"
28
29 #define GST_CAT_DEFAULT gst_va_base_enc_debug
30 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
31
32 struct _GstVaBaseEncPrivate
33 {
34   GstVideoInfo sinkpad_info;
35   GstBufferPool *raw_pool;
36 };
37
38 enum
39 {
40   PROP_DEVICE_PATH = 1,
41   N_PROPERTIES
42 };
43
44 static GParamSpec *properties[N_PROPERTIES];
45
46 /**
47  * GstVaBaseEnc:
48  *
49  * A base class implementation for VA-API Encoders.
50  *
51  * Since: 1.22
52  */
53 /* *INDENT-OFF* */
54 #define gst_va_base_enc_parent_class parent_class
55 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstVaBaseEnc, gst_va_base_enc,
56     GST_TYPE_VIDEO_ENCODER, G_ADD_PRIVATE (GstVaBaseEnc)
57     GST_DEBUG_CATEGORY_INIT (gst_va_base_enc_debug,
58         "vabaseenc", 0, "vabaseenc element"););
59 /* *INDENT-ON* */
60
61 static void
62 gst_va_base_enc_reset_state_default (GstVaBaseEnc * base)
63 {
64   base->frame_duration = GST_CLOCK_TIME_NONE;
65
66   base->width = 0;
67   base->height = 0;
68   base->profile = VAProfileNone;
69   base->rt_format = 0;
70   base->codedbuf_size = 0;
71   g_atomic_int_set (&base->reconf, FALSE);
72 }
73
74 static void
75 _flush_all_frames (GstVaBaseEnc * base)
76 {
77   g_queue_clear_full (&base->reorder_list,
78       (GDestroyNotify) gst_video_codec_frame_unref);
79   g_queue_clear_full (&base->output_list,
80       (GDestroyNotify) gst_video_codec_frame_unref);
81   g_queue_clear_full (&base->ref_list,
82       (GDestroyNotify) gst_video_codec_frame_unref);
83 }
84
85 static gboolean
86 gst_va_base_enc_open (GstVideoEncoder * venc)
87 {
88   GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
89   GstVaBaseEncClass *klass = GST_VA_BASE_ENC_GET_CLASS (venc);
90   gboolean ret = FALSE;
91
92   if (!gst_va_ensure_element_data (venc, klass->render_device_path,
93           &base->display))
94     return FALSE;
95
96   g_object_notify (G_OBJECT (base), "device-path");
97
98   if (!g_atomic_pointer_get (&base->encoder)) {
99     GstVaEncoder *va_encoder;
100
101     va_encoder = gst_va_encoder_new (base->display, klass->codec,
102         klass->entrypoint);
103     if (va_encoder)
104       ret = TRUE;
105
106     gst_object_replace ((GstObject **) (&base->encoder),
107         (GstObject *) va_encoder);
108     gst_clear_object (&va_encoder);
109   } else {
110     ret = TRUE;
111   }
112
113   return ret;
114 }
115
116 static gboolean
117 gst_va_base_enc_start (GstVideoEncoder * venc)
118 {
119   GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
120
121   gst_va_base_enc_reset_state (base);
122
123   base->input_frame_count = 0;
124   base->output_frame_count = 0;
125
126   base->input_state = NULL;
127
128   /* Set the minimum pts to some huge value (1000 hours). This keeps
129    * the dts at the start of the stream from needing to be
130    * negative. */
131   base->start_pts = GST_SECOND * 60 * 60 * 1000;
132   gst_video_encoder_set_min_pts (venc, base->start_pts);
133
134   return TRUE;
135 }
136
137 static gboolean
138 gst_va_base_enc_close (GstVideoEncoder * venc)
139 {
140   GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
141
142   gst_clear_object (&base->encoder);
143   gst_clear_object (&base->display);
144
145   return TRUE;
146 }
147
148 static gboolean
149 gst_va_base_enc_stop (GstVideoEncoder * venc)
150 {
151   GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
152
153   _flush_all_frames (base);
154
155   if (!gst_va_encoder_close (base->encoder)) {
156     GST_ERROR_OBJECT (base, "Failed to close the VA encoder");
157     return FALSE;
158   }
159
160   if (base->priv->raw_pool)
161     gst_buffer_pool_set_active (base->priv->raw_pool, FALSE);
162   gst_clear_object (&base->priv->raw_pool);
163
164   if (base->input_state)
165     gst_video_codec_state_unref (base->input_state);
166
167   return TRUE;
168 }
169
170 static GstCaps *
171 gst_va_base_enc_get_caps (GstVideoEncoder * venc, GstCaps * filter)
172 {
173   GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
174   GstCaps *caps = NULL, *tmp;
175
176   if (base->encoder)
177     caps = gst_va_encoder_get_sinkpad_caps (base->encoder);
178
179   if (caps) {
180     if (filter) {
181       tmp = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
182       gst_caps_unref (caps);
183       caps = tmp;
184     }
185   } else {
186     caps = gst_video_encoder_proxy_getcaps (venc, NULL, filter);
187   }
188
189   GST_LOG_OBJECT (base, "Returning caps %" GST_PTR_FORMAT, caps);
190   return caps;
191 }
192
193 static GstBufferPool *
194 _get_sinkpad_pool (GstVaBaseEnc * base)
195 {
196   GstAllocator *allocator;
197   GstAllocationParams params = { 0, };
198   guint size, usage_hint = 0;
199   GArray *surface_formats = NULL;
200   GstCaps *caps = NULL;
201
202   if (base->priv->raw_pool)
203     return base->priv->raw_pool;
204
205   g_assert (base->input_state);
206   caps = gst_caps_copy (base->input_state->caps);
207   gst_caps_set_features_simple (caps,
208       gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_VA));
209
210   gst_allocation_params_init (&params);
211
212   size = GST_VIDEO_INFO_SIZE (&base->input_state->info);
213
214   surface_formats = gst_va_encoder_get_surface_formats (base->encoder);
215
216   allocator = gst_va_allocator_new (base->display, surface_formats);
217
218   base->priv->raw_pool = gst_va_pool_new_with_config (caps, size, 1, 0,
219       usage_hint, GST_VA_FEATURE_AUTO, allocator, &params);
220   gst_clear_caps (&caps);
221
222   if (!base->priv->raw_pool) {
223     gst_object_unref (allocator);
224     return NULL;
225   }
226
227   gst_va_allocator_get_format (allocator, &base->priv->sinkpad_info, NULL,
228       NULL);
229
230   gst_object_unref (allocator);
231
232   gst_buffer_pool_set_active (base->priv->raw_pool, TRUE);
233
234   return base->priv->raw_pool;
235 }
236
237 static gboolean
238 _try_import_buffer (GstVaBaseEnc * base, GstBuffer * inbuf)
239 {
240   VASurfaceID surface;
241
242   /* The VA buffer. */
243   surface = gst_va_buffer_get_surface (inbuf);
244   if (surface != VA_INVALID_ID &&
245       (gst_va_buffer_peek_display (inbuf) == base->display))
246     return TRUE;
247
248   /* TODO: DMA buffer. */
249
250   return FALSE;
251 }
252
253 static GstFlowReturn
254 gst_va_base_enc_import_input_buffer (GstVaBaseEnc * base,
255     GstBuffer * inbuf, GstBuffer ** buf)
256 {
257   GstBuffer *buffer = NULL;
258   GstBufferPool *pool;
259   GstFlowReturn ret;
260   GstVideoFrame in_frame, out_frame;
261   gboolean imported, copied;
262
263   imported = _try_import_buffer (base, inbuf);
264   if (imported) {
265     *buf = gst_buffer_ref (inbuf);
266     return GST_FLOW_OK;
267   }
268
269   /* input buffer doesn't come from a vapool, thus it is required to
270    * have a pool, grab from it a new buffer and copy the input
271    * buffer to the new one */
272   if (!(pool = _get_sinkpad_pool (base)))
273     return GST_FLOW_ERROR;
274
275   ret = gst_buffer_pool_acquire_buffer (pool, &buffer, NULL);
276   if (ret != GST_FLOW_OK)
277     return ret;
278
279   GST_LOG_OBJECT (base, "copying input frame");
280
281   if (!gst_video_frame_map (&in_frame, &base->input_state->info,
282           inbuf, GST_MAP_READ))
283     goto invalid_buffer;
284   if (!gst_video_frame_map (&out_frame, &base->priv->sinkpad_info, buffer,
285           GST_MAP_WRITE)) {
286     gst_video_frame_unmap (&in_frame);
287     goto invalid_buffer;
288   }
289
290   copied = gst_video_frame_copy (&out_frame, &in_frame);
291
292   gst_video_frame_unmap (&out_frame);
293   gst_video_frame_unmap (&in_frame);
294
295   if (!copied)
296     goto invalid_buffer;
297
298   /* strictly speaking this is not needed but let's play safe */
299   if (!gst_buffer_copy_into (buffer, inbuf, GST_BUFFER_COPY_FLAGS |
300           GST_BUFFER_COPY_TIMESTAMPS, 0, -1))
301     return GST_FLOW_ERROR;
302
303   *buf = buffer;
304
305   return GST_FLOW_OK;
306
307 invalid_buffer:
308   {
309     GST_ELEMENT_WARNING (base, CORE, NOT_IMPLEMENTED, (NULL),
310         ("invalid video buffer received"));
311     if (buffer)
312       gst_buffer_unref (buffer);
313     return GST_FLOW_ERROR;
314   }
315 }
316
317 static GstBuffer *
318 gst_va_base_enc_create_output_buffer (GstVaBaseEnc * base,
319     GstVaEncodePicture * picture)
320 {
321   guint coded_size;
322   goffset offset;
323   GstBuffer *buf = NULL;
324   VASurfaceID surface;
325   VACodedBufferSegment *seg, *seg_list;
326
327   /* Wait for encoding to finish */
328   surface = gst_va_encode_picture_get_raw_surface (picture);
329   if (!va_sync_surface (base->display, surface))
330     goto error;
331
332   seg_list = NULL;
333   if (!va_map_buffer (base->display, picture->coded_buffer,
334           (gpointer *) & seg_list))
335     goto error;
336
337   if (!seg_list) {
338     va_unmap_buffer (base->display, picture->coded_buffer);
339     GST_WARNING_OBJECT (base, "coded buffer has no segment list");
340     goto error;
341   }
342
343   coded_size = 0;
344   for (seg = seg_list; seg; seg = seg->next)
345     coded_size += seg->size;
346
347   buf = gst_video_encoder_allocate_output_buffer (GST_VIDEO_ENCODER_CAST (base),
348       coded_size);
349   if (!buf) {
350     va_unmap_buffer (base->display, picture->coded_buffer);
351     GST_ERROR_OBJECT (base, "Failed to allocate output buffer, size %d",
352         coded_size);
353     goto error;
354   }
355
356   offset = 0;
357   for (seg = seg_list; seg; seg = seg->next) {
358     gsize write_size;
359
360     write_size = gst_buffer_fill (buf, offset, seg->buf, seg->size);
361     if (write_size != seg->size) {
362       GST_WARNING_OBJECT (base, "Segment size is %d, but copied %"
363           G_GSIZE_FORMAT, seg->size, write_size);
364       break;
365     }
366     offset += seg->size;
367   }
368
369   va_unmap_buffer (base->display, picture->coded_buffer);
370
371   return buf;
372
373 error:
374   gst_clear_buffer (&buf);
375   return NULL;
376 }
377
378 static GstAllocator *
379 _allocator_from_caps (GstVaBaseEnc * base, GstCaps * caps)
380 {
381   GstAllocator *allocator = NULL;
382
383   if (gst_caps_is_dmabuf (caps)) {
384     allocator = gst_va_dmabuf_allocator_new (base->display);
385   } else {
386     GArray *surface_formats =
387         gst_va_encoder_get_surface_formats (base->encoder);
388     allocator = gst_va_allocator_new (base->display, surface_formats);
389   }
390
391   return allocator;
392 }
393
394 static gboolean
395 gst_va_base_enc_propose_allocation (GstVideoEncoder * venc, GstQuery * query)
396 {
397   GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
398   GstAllocator *allocator = NULL;
399   GstAllocationParams params = { 0, };
400   GstBufferPool *pool;
401   GstCaps *caps;
402   GstVideoInfo info;
403   gboolean need_pool = FALSE;
404   guint size, usage_hint = 0;
405
406   gst_query_parse_allocation (query, &caps, &need_pool);
407   if (!caps)
408     return FALSE;
409
410   if (!gst_video_info_from_caps (&info, caps)) {
411     GST_ERROR_OBJECT (base, "Cannot parse caps %" GST_PTR_FORMAT, caps);
412     return FALSE;
413   }
414
415   size = GST_VIDEO_INFO_SIZE (&info);
416
417   gst_allocation_params_init (&params);
418
419   if (!(allocator = _allocator_from_caps (base, caps)))
420     return FALSE;
421
422   pool = gst_va_pool_new_with_config (caps, size, 1, 0, usage_hint,
423       GST_VA_FEATURE_AUTO, allocator, &params);
424   if (!pool) {
425     gst_object_unref (allocator);
426     goto config_failed;
427   }
428
429   gst_query_add_allocation_param (query, allocator, &params);
430   gst_query_add_allocation_pool (query, pool, size, 0, 0);
431
432   GST_DEBUG_OBJECT (base,
433       "proposing %" GST_PTR_FORMAT " with allocator %" GST_PTR_FORMAT,
434       pool, allocator);
435
436   gst_object_unref (allocator);
437   gst_object_unref (pool);
438
439   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
440
441   return TRUE;
442
443   /* ERRORS */
444 config_failed:
445   {
446     GST_ERROR_OBJECT (base, "failed to set config");
447     return FALSE;
448   }
449 }
450
451 static GstFlowReturn
452 _push_buffer_to_downstream (GstVaBaseEnc * base, GstVideoCodecFrame * frame)
453 {
454   GstVaEncodePicture *enc_picture;
455   GstVaBaseEncClass *base_class = GST_VA_BASE_ENC_GET_CLASS (base);
456   GstBuffer *buf;
457
458   if (base_class->prepare_output)
459     base_class->prepare_output (base, frame);
460
461   enc_picture =
462       *((GstVaEncodePicture **) gst_video_codec_frame_get_user_data (frame));
463
464   buf = gst_va_base_enc_create_output_buffer (base, enc_picture);
465   if (!buf) {
466     GST_ERROR_OBJECT (base, "Failed to create output buffer");
467     goto error;
468   }
469
470   gst_buffer_replace (&frame->output_buffer, buf);
471   gst_clear_buffer (&buf);
472
473   GST_LOG_OBJECT (base, "Push to downstream: frame system_frame_number: %d,"
474       " pts: %" GST_TIME_FORMAT ", dts: %" GST_TIME_FORMAT
475       " duration: %" GST_TIME_FORMAT ", buffer size: %" G_GSIZE_FORMAT,
476       frame->system_frame_number, GST_TIME_ARGS (frame->pts),
477       GST_TIME_ARGS (frame->dts), GST_TIME_ARGS (frame->duration),
478       gst_buffer_get_size (frame->output_buffer));
479
480   return gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (base), frame);
481
482 error:
483   gst_clear_buffer (&frame->output_buffer);
484   gst_clear_buffer (&buf);
485   gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (base), frame);
486
487   return GST_FLOW_ERROR;
488 }
489
490 static GstFlowReturn
491 _push_out_one_buffer (GstVaBaseEnc * base)
492 {
493   GstVideoCodecFrame *frame_out;
494   GstFlowReturn ret;
495   guint32 system_frame_number;
496
497   frame_out = g_queue_pop_head (&base->output_list);
498   gst_video_codec_frame_unref (frame_out);
499
500   system_frame_number = frame_out->system_frame_number;
501
502   ret = _push_buffer_to_downstream (base, frame_out);
503
504   if (ret != GST_FLOW_OK) {
505     GST_DEBUG_OBJECT (base, "fails to push one buffer, system_frame_number "
506         "%d: %s", system_frame_number, gst_flow_get_name (ret));
507   }
508
509   return ret;
510 }
511
512 static GstFlowReturn
513 gst_va_base_enc_drain (GstVideoEncoder * venc)
514 {
515   GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
516   GstVaBaseEncClass *base_class = GST_VA_BASE_ENC_GET_CLASS (base);
517   GstFlowReturn ret = GST_FLOW_OK;
518   GstVideoCodecFrame *frame_enc = NULL;
519   gboolean is_last = FALSE;
520
521   GST_DEBUG_OBJECT (base, "Encoder is draining");
522
523   /* Kickout all cached frames */
524   if (!base_class->reorder_frame (base, NULL, TRUE, &frame_enc)) {
525     ret = GST_FLOW_ERROR;
526     goto error_and_purge_all;
527   }
528
529   while (frame_enc) {
530     is_last = FALSE;
531
532     if (g_queue_is_empty (&base->reorder_list))
533       is_last = TRUE;
534
535     ret = base_class->encode_frame (base, frame_enc, is_last);
536     if (ret != GST_FLOW_OK)
537       goto error_and_purge_all;
538
539     frame_enc = NULL;
540
541     ret = _push_out_one_buffer (base);
542     if (ret != GST_FLOW_OK)
543       goto error_and_purge_all;
544
545     if (!base_class->reorder_frame (base, NULL, TRUE, &frame_enc)) {
546       ret = GST_FLOW_ERROR;
547       goto error_and_purge_all;
548     }
549   }
550
551   g_assert (g_queue_is_empty (&base->reorder_list));
552
553   /* Output all frames. */
554   while (!g_queue_is_empty (&base->output_list)) {
555     ret = _push_out_one_buffer (base);
556     if (ret != GST_FLOW_OK)
557       goto error_and_purge_all;
558   }
559
560   /* Also clear the reference list. */
561   g_queue_clear_full (&base->ref_list,
562       (GDestroyNotify) gst_video_codec_frame_unref);
563
564   return GST_FLOW_OK;
565
566 error_and_purge_all:
567   if (frame_enc) {
568     gst_clear_buffer (&frame_enc->output_buffer);
569     gst_video_encoder_finish_frame (venc, frame_enc);
570   }
571
572   if (!g_queue_is_empty (&base->output_list)) {
573     GST_WARNING_OBJECT (base, "Still %d frame in the output list"
574         " after drain", g_queue_get_length (&base->output_list));
575     while (!g_queue_is_empty (&base->output_list)) {
576       frame_enc = g_queue_pop_head (&base->output_list);
577       gst_video_codec_frame_unref (frame_enc);
578       gst_clear_buffer (&frame_enc->output_buffer);
579       gst_video_encoder_finish_frame (venc, frame_enc);
580     }
581   }
582
583   if (!g_queue_is_empty (&base->reorder_list)) {
584     GST_WARNING_OBJECT (base, "Still %d frame in the reorder list"
585         " after drain", g_queue_get_length (&base->reorder_list));
586     while (!g_queue_is_empty (&base->reorder_list)) {
587       frame_enc = g_queue_pop_head (&base->reorder_list);
588       gst_video_codec_frame_unref (frame_enc);
589       gst_clear_buffer (&frame_enc->output_buffer);
590       gst_video_encoder_finish_frame (venc, frame_enc);
591     }
592   }
593
594   /* Also clear the reference list. */
595   g_queue_clear_full (&base->ref_list,
596       (GDestroyNotify) gst_video_codec_frame_unref);
597
598   return ret;
599 }
600
601 static gboolean
602 gst_va_base_enc_reset (GstVaBaseEnc * base)
603 {
604   GstVaBaseEncClass *base_class = GST_VA_BASE_ENC_GET_CLASS (base);
605
606   GST_DEBUG_OBJECT (base, "Reconfiguration");
607   if (gst_va_base_enc_drain (GST_VIDEO_ENCODER (base)) != GST_FLOW_OK)
608     return FALSE;
609
610   if (!base_class->reconfig (base)) {
611     GST_ERROR_OBJECT (base, "Error at reconfiguration error");
612     return FALSE;
613   }
614
615   return TRUE;
616 }
617
618 static GstFlowReturn
619 gst_va_base_enc_handle_frame (GstVideoEncoder * venc,
620     GstVideoCodecFrame * frame)
621 {
622   GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
623   GstVaBaseEncClass *base_class = GST_VA_BASE_ENC_GET_CLASS (base);
624   GstFlowReturn ret;
625   GstBuffer *in_buf = NULL;
626   GstVideoCodecFrame *frame_encode = NULL;
627
628   GST_LOG_OBJECT (venc,
629       "handle frame id %d, dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT,
630       frame->system_frame_number,
631       GST_TIME_ARGS (GST_BUFFER_DTS (frame->input_buffer)),
632       GST_TIME_ARGS (GST_BUFFER_PTS (frame->input_buffer)));
633
634   if (g_atomic_int_compare_and_exchange (&base->reconf, TRUE, FALSE)) {
635     if (!gst_va_base_enc_reset (base))
636       return GST_FLOW_ERROR;
637   }
638
639   ret = gst_va_base_enc_import_input_buffer (base,
640       frame->input_buffer, &in_buf);
641   if (ret != GST_FLOW_OK)
642     goto error_buffer_invalid;
643
644   gst_buffer_replace (&frame->input_buffer, in_buf);
645   gst_clear_buffer (&in_buf);
646
647   if (!base_class->new_frame (base, frame))
648     goto error_new_frame;
649
650   if (!base_class->reorder_frame (base, frame, FALSE, &frame_encode))
651     goto error_reorder;
652
653   /* pass it to reorder list and we should not use it again. */
654   frame = NULL;
655
656   while (frame_encode) {
657     ret = base_class->encode_frame (base, frame_encode, FALSE);
658     if (ret != GST_FLOW_OK)
659       goto error_encode;
660
661     while (g_queue_get_length (&base->output_list) > 0)
662       ret = _push_out_one_buffer (base);
663
664     frame_encode = NULL;
665     if (!base_class->reorder_frame (base, NULL, FALSE, &frame_encode))
666       goto error_reorder;
667   }
668
669   return ret;
670
671 error_buffer_invalid:
672   {
673     GST_ELEMENT_ERROR (venc, STREAM, ENCODE,
674         ("Failed to import the input frame: %s.", gst_flow_get_name (ret)),
675         (NULL));
676     gst_clear_buffer (&in_buf);
677     gst_clear_buffer (&frame->output_buffer);
678     gst_video_encoder_finish_frame (venc, frame);
679     return ret;
680   }
681 error_new_frame:
682   {
683     GST_ELEMENT_ERROR (venc, STREAM, ENCODE,
684         ("Failed to create the input frame."), (NULL));
685     gst_clear_buffer (&frame->output_buffer);
686     gst_video_encoder_finish_frame (venc, frame);
687     return GST_FLOW_ERROR;
688   }
689 error_reorder:
690   {
691     GST_ELEMENT_ERROR (venc, STREAM, ENCODE,
692         ("Failed to reorder the input frame."), (NULL));
693     gst_clear_buffer (&frame->output_buffer);
694     gst_video_encoder_finish_frame (venc, frame);
695     return GST_FLOW_ERROR;
696   }
697 error_encode:
698   {
699     GST_ELEMENT_ERROR (venc, STREAM, ENCODE,
700         ("Failed to encode the frame %s.", gst_flow_get_name (ret)), (NULL));
701     gst_clear_buffer (&frame_encode->output_buffer);
702     gst_video_encoder_finish_frame (venc, frame_encode);
703     return ret;
704   }
705 }
706
707 static GstFlowReturn
708 gst_va_base_enc_finish (GstVideoEncoder * venc)
709 {
710   return gst_va_base_enc_drain (venc);
711 }
712
713 static gboolean
714 gst_va_base_enc_set_format (GstVideoEncoder * venc, GstVideoCodecState * state)
715 {
716   GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
717
718   g_return_val_if_fail (state->caps != NULL, FALSE);
719
720   if (base->input_state)
721     gst_video_codec_state_unref (base->input_state);
722   base->input_state = gst_video_codec_state_ref (state);
723
724   if (!gst_va_base_enc_reset (base))
725     return FALSE;
726
727   /* Sub class should open the encoder if reconfig succeeds. */
728   return gst_va_encoder_is_open (base->encoder);
729 }
730
731 static gboolean
732 gst_va_base_enc_flush (GstVideoEncoder * venc)
733 {
734   _flush_all_frames (GST_VA_BASE_ENC (venc));
735   return TRUE;
736 }
737
738 static gboolean
739 _query_context (GstVaBaseEnc * base, GstQuery * query)
740 {
741   GstVaDisplay *display = NULL;
742   gboolean ret;
743
744   gst_object_replace ((GstObject **) & display, (GstObject *) base->display);
745   ret = gst_va_handle_context_query (GST_ELEMENT_CAST (base), query, display);
746   gst_clear_object (&display);
747
748   return ret;
749 }
750
751 static gboolean
752 gst_va_base_enc_src_query (GstVideoEncoder * venc, GstQuery * query)
753 {
754   GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
755   gboolean ret = FALSE;
756
757   switch (GST_QUERY_TYPE (query)) {
758     case GST_QUERY_CONTEXT:{
759       ret = _query_context (base, query);
760       break;
761     }
762     case GST_QUERY_CAPS:{
763       GstCaps *caps = NULL, *tmp, *filter = NULL;
764       GstVaEncoder *va_encoder = NULL;
765       gboolean fixed_caps;
766
767       gst_object_replace ((GstObject **) & va_encoder,
768           (GstObject *) base->encoder);
769
770       gst_query_parse_caps (query, &filter);
771
772       fixed_caps = GST_PAD_IS_FIXED_CAPS (GST_VIDEO_ENCODER_SRC_PAD (venc));
773
774       if (!fixed_caps && va_encoder)
775         caps = gst_va_encoder_get_srcpad_caps (va_encoder);
776
777       gst_clear_object (&va_encoder);
778
779       if (caps) {
780         if (filter) {
781           tmp = gst_caps_intersect_full (filter, caps,
782               GST_CAPS_INTERSECT_FIRST);
783           gst_caps_unref (caps);
784           caps = tmp;
785         }
786
787         GST_LOG_OBJECT (base, "Returning caps %" GST_PTR_FORMAT, caps);
788         gst_query_set_caps_result (query, caps);
789         gst_caps_unref (caps);
790         ret = TRUE;
791         break;
792       }
793       /* else jump to default */
794     }
795     default:
796       ret = GST_VIDEO_ENCODER_CLASS (parent_class)->src_query (venc, query);
797       break;
798   }
799
800   return ret;
801 }
802
803 static gboolean
804 gst_va_base_enc_sink_query (GstVideoEncoder * venc, GstQuery * query)
805 {
806   GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
807
808   if (GST_QUERY_TYPE (query) == GST_QUERY_CONTEXT)
809     return _query_context (base, query);
810
811   return GST_VIDEO_ENCODER_CLASS (parent_class)->sink_query (venc, query);
812 }
813
814 static void
815 gst_va_base_enc_set_context (GstElement * element, GstContext * context)
816 {
817   GstVaDisplay *old_display, *new_display;
818   GstVaBaseEnc *base = GST_VA_BASE_ENC (element);
819   GstVaBaseEncClass *klass = GST_VA_BASE_ENC_GET_CLASS (base);
820   gboolean ret;
821
822   old_display = base->display ? gst_object_ref (base->display) : NULL;
823
824   ret = gst_va_handle_set_context (element, context, klass->render_device_path,
825       &base->display);
826
827   new_display = base->display ? gst_object_ref (base->display) : NULL;
828
829   if (!ret || (old_display && new_display && old_display != new_display
830           && base->encoder)) {
831     GST_ELEMENT_WARNING (element, RESOURCE, BUSY,
832         ("Can't replace VA display while operating"), (NULL));
833   }
834
835   gst_clear_object (&old_display);
836   gst_clear_object (&new_display);
837
838   GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
839 }
840
841 static void
842 gst_va_base_enc_get_property (GObject * object, guint prop_id,
843     GValue * value, GParamSpec * pspec)
844 {
845   GstVaBaseEnc *base = GST_VA_BASE_ENC (object);
846
847   switch (prop_id) {
848     case PROP_DEVICE_PATH:{
849       if (!(base->display && GST_IS_VA_DISPLAY_DRM (base->display))) {
850         g_value_set_string (value, NULL);
851         return;
852       }
853       g_object_get_property (G_OBJECT (base->display), "path", value);
854       break;
855     }
856     default:
857       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
858   }
859 }
860
861 static void
862 gst_va_base_enc_init (GstVaBaseEnc * self)
863 {
864   g_queue_init (&self->reorder_list);
865   g_queue_init (&self->ref_list);
866   g_queue_init (&self->output_list);
867
868   self->priv = gst_va_base_enc_get_instance_private (self);
869 }
870
871 static void
872 gst_va_base_enc_dispose (GObject * object)
873 {
874   _flush_all_frames (GST_VA_BASE_ENC (object));
875   gst_va_base_enc_close (GST_VIDEO_ENCODER (object));
876
877   G_OBJECT_CLASS (parent_class)->dispose (object);
878 }
879
880 void
881 gst_va_base_enc_class_init (GstVaBaseEncClass * klass)
882 {
883   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
884   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
885   GstVideoEncoderClass *encoder_class = GST_VIDEO_ENCODER_CLASS (klass);
886
887   gobject_class->get_property = gst_va_base_enc_get_property;
888   gobject_class->dispose = gst_va_base_enc_dispose;
889
890   element_class->set_context = GST_DEBUG_FUNCPTR (gst_va_base_enc_set_context);
891
892   encoder_class->open = GST_DEBUG_FUNCPTR (gst_va_base_enc_open);
893   encoder_class->close = GST_DEBUG_FUNCPTR (gst_va_base_enc_close);
894   encoder_class->start = GST_DEBUG_FUNCPTR (gst_va_base_enc_start);
895   encoder_class->stop = GST_DEBUG_FUNCPTR (gst_va_base_enc_stop);
896   encoder_class->getcaps = GST_DEBUG_FUNCPTR (gst_va_base_enc_get_caps);
897   encoder_class->src_query = GST_DEBUG_FUNCPTR (gst_va_base_enc_src_query);
898   encoder_class->sink_query = GST_DEBUG_FUNCPTR (gst_va_base_enc_sink_query);
899   encoder_class->propose_allocation =
900       GST_DEBUG_FUNCPTR (gst_va_base_enc_propose_allocation);
901   encoder_class->handle_frame =
902       GST_DEBUG_FUNCPTR (gst_va_base_enc_handle_frame);
903   encoder_class->set_format = GST_DEBUG_FUNCPTR (gst_va_base_enc_set_format);
904   encoder_class->finish = GST_DEBUG_FUNCPTR (gst_va_base_enc_finish);
905   encoder_class->flush = GST_DEBUG_FUNCPTR (gst_va_base_enc_flush);
906
907   klass->reset_state = GST_DEBUG_FUNCPTR (gst_va_base_enc_reset_state_default);
908
909   /**
910    * GstVaBaseEnc:device-path:
911    *
912    * It shows the DRM device path used for the VA operation, if any.
913    */
914   properties[PROP_DEVICE_PATH] = g_param_spec_string ("device-path",
915       "Device Path", "DRM device path", NULL,
916       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
917
918   g_object_class_install_properties (gobject_class, N_PROPERTIES, properties);
919
920   gst_type_mark_as_plugin_api (GST_TYPE_VA_BASE_ENC, 0);
921 }
922
923 /*********************** Helper Functions ****************************/
924 gboolean
925 gst_va_base_enc_add_rate_control_parameter (GstVaBaseEnc * base,
926     GstVaEncodePicture * picture, guint32 rc_mode,
927     guint max_bitrate_bits, guint target_percentage,
928     guint32 qp_i, guint32 min_qp, guint32 max_qp, guint32 mbbrc)
929 {
930   uint32_t window_size;
931   struct VAEncMiscParameterRateControlWrap
932   {
933     VAEncMiscParameterType type;
934     VAEncMiscParameterRateControl rate_control;
935   } rate_control;
936
937   if (rc_mode == VA_RC_NONE || rc_mode == VA_RC_CQP)
938     return TRUE;
939
940   window_size = rc_mode == VA_RC_VBR ? max_bitrate_bits / 2 : max_bitrate_bits;
941
942   /* *INDENT-OFF* */
943   rate_control = (struct VAEncMiscParameterRateControlWrap) {
944     .type = VAEncMiscParameterTypeRateControl,
945     .rate_control = {
946       .bits_per_second = max_bitrate_bits,
947       .target_percentage = target_percentage,
948       .window_size = window_size,
949       .initial_qp = qp_i,
950       .min_qp = min_qp,
951       .max_qp = max_qp,
952       .rc_flags.bits.mb_rate_control = mbbrc,
953       .quality_factor = 0,
954     },
955   };
956   /* *INDENT-ON* */
957
958   if (!gst_va_encoder_add_param (base->encoder, picture,
959           VAEncMiscParameterBufferType, &rate_control, sizeof (rate_control))) {
960     GST_ERROR_OBJECT (base, "Failed to create the race control parameter");
961     return FALSE;
962   }
963
964   return TRUE;
965 }
966
967 gboolean
968 gst_va_base_enc_add_quality_level_parameter (GstVaBaseEnc * base,
969     GstVaEncodePicture * picture, guint target_usage)
970 {
971   /* *INDENT-OFF* */
972   struct
973   {
974     VAEncMiscParameterType type;
975     VAEncMiscParameterBufferQualityLevel ql;
976   } quality_level = {
977     .type = VAEncMiscParameterTypeQualityLevel,
978     .ql.quality_level = target_usage,
979   };
980   /* *INDENT-ON* */
981
982   if (target_usage == 0)
983     return TRUE;
984
985   if (!gst_va_encoder_add_param (base->encoder, picture,
986           VAEncMiscParameterBufferType, &quality_level,
987           sizeof (quality_level))) {
988     GST_ERROR_OBJECT (base, "Failed to create the quality level parameter");
989     return FALSE;
990   }
991
992   return TRUE;
993 }
994
995 gboolean
996 gst_va_base_enc_add_frame_rate_parameter (GstVaBaseEnc * base,
997     GstVaEncodePicture * picture)
998 {
999   /* *INDENT-OFF* */
1000   struct
1001   {
1002     VAEncMiscParameterType type;
1003     VAEncMiscParameterFrameRate fr;
1004   } framerate = {
1005     .type = VAEncMiscParameterTypeFrameRate,
1006     /* denominator = framerate >> 16 & 0xffff;
1007      * numerator   = framerate & 0xffff; */
1008     .fr.framerate =
1009         (GST_VIDEO_INFO_FPS_N (&base->input_state->info) & 0xffff) |
1010         ((GST_VIDEO_INFO_FPS_D (&base->input_state->info) & 0xffff) << 16)
1011   };
1012   /* *INDENT-ON* */
1013
1014   if (!gst_va_encoder_add_param (base->encoder, picture,
1015           VAEncMiscParameterBufferType, &framerate, sizeof (framerate))) {
1016     GST_ERROR_OBJECT (base, "Failed to create the frame rate parameter");
1017     return FALSE;
1018   }
1019
1020   return TRUE;
1021 }
1022
1023 gboolean
1024 gst_va_base_enc_add_hrd_parameter (GstVaBaseEnc * base,
1025     GstVaEncodePicture * picture, guint32 rc_mode, guint cpb_length_bits)
1026 {
1027   /* *INDENT-OFF* */
1028   struct
1029   {
1030     VAEncMiscParameterType type;
1031     VAEncMiscParameterHRD hrd;
1032   } hrd = {
1033     .type = VAEncMiscParameterTypeHRD,
1034     .hrd = {
1035       .buffer_size = cpb_length_bits,
1036       .initial_buffer_fullness = cpb_length_bits / 2,
1037     },
1038   };
1039   /* *INDENT-ON* */
1040
1041   if (rc_mode == VA_RC_NONE || rc_mode == VA_RC_CQP || rc_mode == VA_RC_VCM)
1042     return TRUE;
1043
1044   if (!gst_va_encoder_add_param (base->encoder, picture,
1045           VAEncMiscParameterBufferType, &hrd, sizeof (hrd))) {
1046     GST_ERROR_OBJECT (base, "Failed to create the HRD parameter");
1047     return FALSE;
1048   }
1049
1050   return TRUE;
1051 }
1052
1053 gboolean
1054 gst_va_base_enc_add_trellis_parameter (GstVaBaseEnc * base,
1055     GstVaEncodePicture * picture, gboolean use_trellis)
1056 {
1057   /* *INDENT-OFF* */
1058   struct
1059   {
1060     VAEncMiscParameterType type;
1061     VAEncMiscParameterQuantization tr;
1062   } trellis = {
1063     .type = VAEncMiscParameterTypeQuantization,
1064     .tr.quantization_flags.bits = {
1065        .disable_trellis = 0,
1066        .enable_trellis_I = 1,
1067        .enable_trellis_B = 1,
1068        .enable_trellis_P = 1,
1069     },
1070   };
1071   /* *INDENT-ON* */
1072
1073   if (!use_trellis)
1074     return TRUE;
1075
1076   if (!gst_va_encoder_add_param (base->encoder, picture,
1077           VAEncMiscParameterBufferType, &trellis, sizeof (trellis))) {
1078     GST_ERROR_OBJECT (base, "Failed to create the trellis parameter");
1079     return FALSE;
1080   }
1081
1082   return TRUE;
1083 }
1084
1085 void
1086 gst_va_base_enc_add_codec_tag (GstVaBaseEnc * base, const gchar * codec_name)
1087 {
1088   GstVideoEncoder *venc = GST_VIDEO_ENCODER (base);
1089   GstTagList *tags = gst_tag_list_new_empty ();
1090   const gchar *encoder_name;
1091   guint bitrate = 0;
1092
1093   g_object_get (venc, "bitrate", &bitrate, NULL);
1094   if (bitrate > 0)
1095     gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_NOMINAL_BITRATE,
1096         bitrate, NULL);
1097
1098   if ((encoder_name =
1099           gst_element_class_get_metadata (GST_ELEMENT_GET_CLASS (venc),
1100               GST_ELEMENT_METADATA_LONGNAME)))
1101     gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER,
1102         encoder_name, NULL);
1103
1104   gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CODEC, codec_name,
1105       NULL);
1106
1107   gst_video_encoder_merge_tags (venc, tags, GST_TAG_MERGE_REPLACE);
1108   gst_tag_list_unref (tags);
1109 }
1110
1111 void
1112 gst_va_base_enc_reset_state (GstVaBaseEnc * base)
1113 {
1114   GstVaBaseEncClass *klass = GST_VA_BASE_ENC_GET_CLASS (base);
1115
1116   g_assert (klass->reset_state);
1117   klass->reset_state (base);
1118 }
1119
1120 /* *INDENT-OFF* */
1121 #define UPDATE_PROPERTY                         \
1122   GST_OBJECT_LOCK (base);                       \
1123   if (*old_val == new_val) {                    \
1124     GST_OBJECT_UNLOCK (base);                   \
1125     return;                                     \
1126   }                                             \
1127   *old_val = new_val;                                                   \
1128   GST_OBJECT_UNLOCK (base);                                             \
1129   if (pspec)                                                            \
1130     g_object_notify_by_pspec (G_OBJECT (base), pspec);                  \
1131
1132 void
1133 gst_va_base_enc_update_property_uint (GstVaBaseEnc * base, guint32 * old_val,
1134     guint32 new_val, GParamSpec * pspec)
1135 {
1136   UPDATE_PROPERTY
1137 }
1138
1139 void
1140 gst_va_base_enc_update_property_bool (GstVaBaseEnc * base, gboolean * old_val,
1141     gboolean new_val, GParamSpec * pspec)
1142 {
1143   UPDATE_PROPERTY
1144 }
1145
1146 #undef UPDATE_PROPERTY
1147 /* *INDENT-ON* */