va: Fix some code defects
[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   if (!gst_buffer_pool_set_active (base->priv->raw_pool, TRUE)) {
233     GST_WARNING_OBJECT (base, "Failed to activate sinkpad pool");
234     return NULL;
235   }
236
237   return base->priv->raw_pool;
238 }
239
240 static gboolean
241 _try_import_buffer (GstVaBaseEnc * base, GstBuffer * inbuf)
242 {
243   VASurfaceID surface;
244
245   /* The VA buffer. */
246   surface = gst_va_buffer_get_surface (inbuf);
247   if (surface != VA_INVALID_ID &&
248       (gst_va_buffer_peek_display (inbuf) == base->display))
249     return TRUE;
250
251   /* TODO: DMA buffer. */
252
253   return FALSE;
254 }
255
256 static GstFlowReturn
257 gst_va_base_enc_import_input_buffer (GstVaBaseEnc * base,
258     GstBuffer * inbuf, GstBuffer ** buf)
259 {
260   GstBuffer *buffer = NULL;
261   GstBufferPool *pool;
262   GstFlowReturn ret;
263   GstVideoFrame in_frame, out_frame;
264   gboolean imported, copied;
265
266   imported = _try_import_buffer (base, inbuf);
267   if (imported) {
268     *buf = gst_buffer_ref (inbuf);
269     return GST_FLOW_OK;
270   }
271
272   /* input buffer doesn't come from a vapool, thus it is required to
273    * have a pool, grab from it a new buffer and copy the input
274    * buffer to the new one */
275   if (!(pool = _get_sinkpad_pool (base)))
276     return GST_FLOW_ERROR;
277
278   ret = gst_buffer_pool_acquire_buffer (pool, &buffer, NULL);
279   if (ret != GST_FLOW_OK)
280     return ret;
281
282   GST_LOG_OBJECT (base, "copying input frame");
283
284   if (!gst_video_frame_map (&in_frame, &base->input_state->info,
285           inbuf, GST_MAP_READ))
286     goto invalid_buffer;
287   if (!gst_video_frame_map (&out_frame, &base->priv->sinkpad_info, buffer,
288           GST_MAP_WRITE)) {
289     gst_video_frame_unmap (&in_frame);
290     goto invalid_buffer;
291   }
292
293   copied = gst_video_frame_copy (&out_frame, &in_frame);
294
295   gst_video_frame_unmap (&out_frame);
296   gst_video_frame_unmap (&in_frame);
297
298   if (!copied)
299     goto invalid_buffer;
300
301   /* strictly speaking this is not needed but let's play safe */
302   if (!gst_buffer_copy_into (buffer, inbuf, GST_BUFFER_COPY_FLAGS |
303           GST_BUFFER_COPY_TIMESTAMPS, 0, -1))
304     return GST_FLOW_ERROR;
305
306   *buf = buffer;
307
308   return GST_FLOW_OK;
309
310 invalid_buffer:
311   {
312     GST_ELEMENT_WARNING (base, CORE, NOT_IMPLEMENTED, (NULL),
313         ("invalid video buffer received"));
314     if (buffer)
315       gst_buffer_unref (buffer);
316     return GST_FLOW_ERROR;
317   }
318 }
319
320 static GstBuffer *
321 gst_va_base_enc_create_output_buffer (GstVaBaseEnc * base,
322     GstVaEncodePicture * picture)
323 {
324   guint coded_size;
325   goffset offset;
326   GstBuffer *buf = NULL;
327   VASurfaceID surface;
328   VACodedBufferSegment *seg, *seg_list;
329
330   /* Wait for encoding to finish */
331   surface = gst_va_encode_picture_get_raw_surface (picture);
332   if (!va_sync_surface (base->display, surface))
333     goto error;
334
335   seg_list = NULL;
336   if (!va_map_buffer (base->display, picture->coded_buffer,
337           (gpointer *) & seg_list))
338     goto error;
339
340   if (!seg_list) {
341     va_unmap_buffer (base->display, picture->coded_buffer);
342     GST_WARNING_OBJECT (base, "coded buffer has no segment list");
343     goto error;
344   }
345
346   coded_size = 0;
347   for (seg = seg_list; seg; seg = seg->next)
348     coded_size += seg->size;
349
350   buf = gst_video_encoder_allocate_output_buffer (GST_VIDEO_ENCODER_CAST (base),
351       coded_size);
352   if (!buf) {
353     va_unmap_buffer (base->display, picture->coded_buffer);
354     GST_ERROR_OBJECT (base, "Failed to allocate output buffer, size %d",
355         coded_size);
356     goto error;
357   }
358
359   offset = 0;
360   for (seg = seg_list; seg; seg = seg->next) {
361     gsize write_size;
362
363     write_size = gst_buffer_fill (buf, offset, seg->buf, seg->size);
364     if (write_size != seg->size) {
365       GST_WARNING_OBJECT (base, "Segment size is %d, but copied %"
366           G_GSIZE_FORMAT, seg->size, write_size);
367       break;
368     }
369     offset += seg->size;
370   }
371
372   va_unmap_buffer (base->display, picture->coded_buffer);
373
374   return buf;
375
376 error:
377   gst_clear_buffer (&buf);
378   return NULL;
379 }
380
381 static GstAllocator *
382 _allocator_from_caps (GstVaBaseEnc * base, GstCaps * caps)
383 {
384   GstAllocator *allocator = NULL;
385
386   if (gst_caps_is_dmabuf (caps)) {
387     allocator = gst_va_dmabuf_allocator_new (base->display);
388   } else {
389     GArray *surface_formats =
390         gst_va_encoder_get_surface_formats (base->encoder);
391     allocator = gst_va_allocator_new (base->display, surface_formats);
392   }
393
394   return allocator;
395 }
396
397 static gboolean
398 gst_va_base_enc_propose_allocation (GstVideoEncoder * venc, GstQuery * query)
399 {
400   GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
401   GstAllocator *allocator = NULL;
402   GstAllocationParams params = { 0, };
403   GstBufferPool *pool;
404   GstCaps *caps;
405   GstVideoInfo info;
406   gboolean need_pool = FALSE;
407   guint size, usage_hint = 0;
408
409   gst_query_parse_allocation (query, &caps, &need_pool);
410   if (!caps)
411     return FALSE;
412
413   if (!gst_video_info_from_caps (&info, caps)) {
414     GST_ERROR_OBJECT (base, "Cannot parse caps %" GST_PTR_FORMAT, caps);
415     return FALSE;
416   }
417
418   size = GST_VIDEO_INFO_SIZE (&info);
419
420   gst_allocation_params_init (&params);
421
422   if (!(allocator = _allocator_from_caps (base, caps)))
423     return FALSE;
424
425   pool = gst_va_pool_new_with_config (caps, size, 1, 0, usage_hint,
426       GST_VA_FEATURE_AUTO, allocator, &params);
427   if (!pool) {
428     gst_object_unref (allocator);
429     goto config_failed;
430   }
431
432   gst_query_add_allocation_param (query, allocator, &params);
433   gst_query_add_allocation_pool (query, pool, size, 0, 0);
434
435   GST_DEBUG_OBJECT (base,
436       "proposing %" GST_PTR_FORMAT " with allocator %" GST_PTR_FORMAT,
437       pool, allocator);
438
439   gst_object_unref (allocator);
440   gst_object_unref (pool);
441
442   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
443
444   return TRUE;
445
446   /* ERRORS */
447 config_failed:
448   {
449     GST_ERROR_OBJECT (base, "failed to set config");
450     return FALSE;
451   }
452 }
453
454 static GstFlowReturn
455 _push_buffer_to_downstream (GstVaBaseEnc * base, GstVideoCodecFrame * frame)
456 {
457   GstVaEncodePicture *enc_picture;
458   GstVaBaseEncClass *base_class = GST_VA_BASE_ENC_GET_CLASS (base);
459   GstBuffer *buf;
460
461   if (base_class->prepare_output)
462     base_class->prepare_output (base, frame);
463
464   enc_picture =
465       *((GstVaEncodePicture **) gst_video_codec_frame_get_user_data (frame));
466
467   buf = gst_va_base_enc_create_output_buffer (base, enc_picture);
468   if (!buf) {
469     GST_ERROR_OBJECT (base, "Failed to create output buffer");
470     goto error;
471   }
472
473   gst_buffer_replace (&frame->output_buffer, buf);
474   gst_clear_buffer (&buf);
475
476   GST_LOG_OBJECT (base, "Push to downstream: frame system_frame_number: %d,"
477       " pts: %" GST_TIME_FORMAT ", dts: %" GST_TIME_FORMAT
478       " duration: %" GST_TIME_FORMAT ", buffer size: %" G_GSIZE_FORMAT,
479       frame->system_frame_number, GST_TIME_ARGS (frame->pts),
480       GST_TIME_ARGS (frame->dts), GST_TIME_ARGS (frame->duration),
481       gst_buffer_get_size (frame->output_buffer));
482
483   return gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (base), frame);
484
485 error:
486   gst_clear_buffer (&frame->output_buffer);
487   gst_clear_buffer (&buf);
488   gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (base), frame);
489
490   return GST_FLOW_ERROR;
491 }
492
493 static GstFlowReturn
494 _push_out_one_buffer (GstVaBaseEnc * base)
495 {
496   GstVideoCodecFrame *frame_out;
497   GstFlowReturn ret;
498   guint32 system_frame_number;
499
500   frame_out = g_queue_pop_head (&base->output_list);
501   gst_video_codec_frame_unref (frame_out);
502
503   system_frame_number = frame_out->system_frame_number;
504
505   ret = _push_buffer_to_downstream (base, frame_out);
506
507   if (ret != GST_FLOW_OK) {
508     GST_DEBUG_OBJECT (base, "fails to push one buffer, system_frame_number "
509         "%d: %s", system_frame_number, gst_flow_get_name (ret));
510   }
511
512   return ret;
513 }
514
515 static GstFlowReturn
516 gst_va_base_enc_drain (GstVideoEncoder * venc)
517 {
518   GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
519   GstVaBaseEncClass *base_class = GST_VA_BASE_ENC_GET_CLASS (base);
520   GstFlowReturn ret = GST_FLOW_OK;
521   GstVideoCodecFrame *frame_enc = NULL;
522   gboolean is_last = FALSE;
523
524   GST_DEBUG_OBJECT (base, "Encoder is draining");
525
526   /* Kickout all cached frames */
527   if (!base_class->reorder_frame (base, NULL, TRUE, &frame_enc)) {
528     ret = GST_FLOW_ERROR;
529     goto error_and_purge_all;
530   }
531
532   while (frame_enc) {
533     is_last = FALSE;
534
535     if (g_queue_is_empty (&base->reorder_list))
536       is_last = TRUE;
537
538     ret = base_class->encode_frame (base, frame_enc, is_last);
539     if (ret != GST_FLOW_OK)
540       goto error_and_purge_all;
541
542     frame_enc = NULL;
543
544     ret = _push_out_one_buffer (base);
545     if (ret != GST_FLOW_OK)
546       goto error_and_purge_all;
547
548     if (!base_class->reorder_frame (base, NULL, TRUE, &frame_enc)) {
549       ret = GST_FLOW_ERROR;
550       goto error_and_purge_all;
551     }
552   }
553
554   g_assert (g_queue_is_empty (&base->reorder_list));
555
556   /* Output all frames. */
557   while (!g_queue_is_empty (&base->output_list)) {
558     ret = _push_out_one_buffer (base);
559     if (ret != GST_FLOW_OK)
560       goto error_and_purge_all;
561   }
562
563   /* Also clear the reference list. */
564   g_queue_clear_full (&base->ref_list,
565       (GDestroyNotify) gst_video_codec_frame_unref);
566
567   return GST_FLOW_OK;
568
569 error_and_purge_all:
570   if (frame_enc) {
571     gst_clear_buffer (&frame_enc->output_buffer);
572     gst_video_encoder_finish_frame (venc, frame_enc);
573   }
574
575   if (!g_queue_is_empty (&base->output_list)) {
576     GST_WARNING_OBJECT (base, "Still %d frame in the output list"
577         " after drain", g_queue_get_length (&base->output_list));
578     while (!g_queue_is_empty (&base->output_list)) {
579       frame_enc = g_queue_pop_head (&base->output_list);
580       gst_video_codec_frame_unref (frame_enc);
581       gst_clear_buffer (&frame_enc->output_buffer);
582       gst_video_encoder_finish_frame (venc, frame_enc);
583     }
584   }
585
586   if (!g_queue_is_empty (&base->reorder_list)) {
587     GST_WARNING_OBJECT (base, "Still %d frame in the reorder list"
588         " after drain", g_queue_get_length (&base->reorder_list));
589     while (!g_queue_is_empty (&base->reorder_list)) {
590       frame_enc = g_queue_pop_head (&base->reorder_list);
591       gst_video_codec_frame_unref (frame_enc);
592       gst_clear_buffer (&frame_enc->output_buffer);
593       gst_video_encoder_finish_frame (venc, frame_enc);
594     }
595   }
596
597   /* Also clear the reference list. */
598   g_queue_clear_full (&base->ref_list,
599       (GDestroyNotify) gst_video_codec_frame_unref);
600
601   return ret;
602 }
603
604 static gboolean
605 gst_va_base_enc_reset (GstVaBaseEnc * base)
606 {
607   GstVaBaseEncClass *base_class = GST_VA_BASE_ENC_GET_CLASS (base);
608
609   GST_DEBUG_OBJECT (base, "Reconfiguration");
610   if (gst_va_base_enc_drain (GST_VIDEO_ENCODER (base)) != GST_FLOW_OK)
611     return FALSE;
612
613   if (!base_class->reconfig (base)) {
614     GST_ERROR_OBJECT (base, "Error at reconfiguration error");
615     return FALSE;
616   }
617
618   return TRUE;
619 }
620
621 static GstFlowReturn
622 gst_va_base_enc_handle_frame (GstVideoEncoder * venc,
623     GstVideoCodecFrame * frame)
624 {
625   GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
626   GstVaBaseEncClass *base_class = GST_VA_BASE_ENC_GET_CLASS (base);
627   GstFlowReturn ret;
628   GstBuffer *in_buf = NULL;
629   GstVideoCodecFrame *frame_encode = NULL;
630
631   GST_LOG_OBJECT (venc,
632       "handle frame id %d, dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT,
633       frame->system_frame_number,
634       GST_TIME_ARGS (GST_BUFFER_DTS (frame->input_buffer)),
635       GST_TIME_ARGS (GST_BUFFER_PTS (frame->input_buffer)));
636
637   if (g_atomic_int_compare_and_exchange (&base->reconf, TRUE, FALSE)) {
638     if (!gst_va_base_enc_reset (base))
639       return GST_FLOW_ERROR;
640   }
641
642   ret = gst_va_base_enc_import_input_buffer (base,
643       frame->input_buffer, &in_buf);
644   if (ret != GST_FLOW_OK)
645     goto error_buffer_invalid;
646
647   gst_buffer_replace (&frame->input_buffer, in_buf);
648   gst_clear_buffer (&in_buf);
649
650   if (!base_class->new_frame (base, frame))
651     goto error_new_frame;
652
653   if (!base_class->reorder_frame (base, frame, FALSE, &frame_encode))
654     goto error_reorder;
655
656   /* pass it to reorder list and we should not use it again. */
657   frame = NULL;
658
659   while (frame_encode) {
660     ret = base_class->encode_frame (base, frame_encode, FALSE);
661     if (ret != GST_FLOW_OK)
662       goto error_encode;
663
664     while (g_queue_get_length (&base->output_list) > 0)
665       ret = _push_out_one_buffer (base);
666
667     frame_encode = NULL;
668     if (!base_class->reorder_frame (base, NULL, FALSE, &frame_encode))
669       goto error_reorder;
670   }
671
672   return ret;
673
674 error_buffer_invalid:
675   {
676     GST_ELEMENT_ERROR (venc, STREAM, ENCODE,
677         ("Failed to import the input frame: %s.", gst_flow_get_name (ret)),
678         (NULL));
679     gst_clear_buffer (&in_buf);
680     gst_clear_buffer (&frame->output_buffer);
681     gst_video_encoder_finish_frame (venc, frame);
682     return ret;
683   }
684 error_new_frame:
685   {
686     GST_ELEMENT_ERROR (venc, STREAM, ENCODE,
687         ("Failed to create the input frame."), (NULL));
688     gst_clear_buffer (&frame->output_buffer);
689     gst_video_encoder_finish_frame (venc, frame);
690     return GST_FLOW_ERROR;
691   }
692 error_reorder:
693   {
694     GST_ELEMENT_ERROR (venc, STREAM, ENCODE,
695         ("Failed to reorder the input frame."), (NULL));
696     if (frame) {
697       gst_clear_buffer (&frame->output_buffer);
698       gst_video_encoder_finish_frame (venc, frame);
699     }
700     return GST_FLOW_ERROR;
701   }
702 error_encode:
703   {
704     GST_ELEMENT_ERROR (venc, STREAM, ENCODE,
705         ("Failed to encode the frame %s.", gst_flow_get_name (ret)), (NULL));
706     gst_clear_buffer (&frame_encode->output_buffer);
707     gst_video_encoder_finish_frame (venc, frame_encode);
708     return ret;
709   }
710 }
711
712 static GstFlowReturn
713 gst_va_base_enc_finish (GstVideoEncoder * venc)
714 {
715   return gst_va_base_enc_drain (venc);
716 }
717
718 static gboolean
719 gst_va_base_enc_set_format (GstVideoEncoder * venc, GstVideoCodecState * state)
720 {
721   GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
722
723   g_return_val_if_fail (state->caps != NULL, FALSE);
724
725   if (base->input_state)
726     gst_video_codec_state_unref (base->input_state);
727   base->input_state = gst_video_codec_state_ref (state);
728
729   if (!gst_va_base_enc_reset (base))
730     return FALSE;
731
732   /* Sub class should open the encoder if reconfig succeeds. */
733   return gst_va_encoder_is_open (base->encoder);
734 }
735
736 static gboolean
737 gst_va_base_enc_flush (GstVideoEncoder * venc)
738 {
739   _flush_all_frames (GST_VA_BASE_ENC (venc));
740   return TRUE;
741 }
742
743 static gboolean
744 _query_context (GstVaBaseEnc * base, GstQuery * query)
745 {
746   GstVaDisplay *display = NULL;
747   gboolean ret;
748
749   gst_object_replace ((GstObject **) & display, (GstObject *) base->display);
750   ret = gst_va_handle_context_query (GST_ELEMENT_CAST (base), query, display);
751   gst_clear_object (&display);
752
753   return ret;
754 }
755
756 static gboolean
757 gst_va_base_enc_src_query (GstVideoEncoder * venc, GstQuery * query)
758 {
759   GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
760   gboolean ret = FALSE;
761
762   switch (GST_QUERY_TYPE (query)) {
763     case GST_QUERY_CONTEXT:{
764       ret = _query_context (base, query);
765       break;
766     }
767     case GST_QUERY_CAPS:{
768       GstCaps *caps = NULL, *tmp, *filter = NULL;
769       GstVaEncoder *va_encoder = NULL;
770       gboolean fixed_caps;
771
772       gst_object_replace ((GstObject **) & va_encoder,
773           (GstObject *) base->encoder);
774
775       gst_query_parse_caps (query, &filter);
776
777       fixed_caps = GST_PAD_IS_FIXED_CAPS (GST_VIDEO_ENCODER_SRC_PAD (venc));
778
779       if (!fixed_caps && va_encoder)
780         caps = gst_va_encoder_get_srcpad_caps (va_encoder);
781
782       gst_clear_object (&va_encoder);
783
784       if (caps) {
785         if (filter) {
786           tmp = gst_caps_intersect_full (filter, caps,
787               GST_CAPS_INTERSECT_FIRST);
788           gst_caps_unref (caps);
789           caps = tmp;
790         }
791
792         GST_LOG_OBJECT (base, "Returning caps %" GST_PTR_FORMAT, caps);
793         gst_query_set_caps_result (query, caps);
794         gst_caps_unref (caps);
795         ret = TRUE;
796         break;
797       }
798       /* else jump to default */
799     }
800     default:
801       ret = GST_VIDEO_ENCODER_CLASS (parent_class)->src_query (venc, query);
802       break;
803   }
804
805   return ret;
806 }
807
808 static gboolean
809 gst_va_base_enc_sink_query (GstVideoEncoder * venc, GstQuery * query)
810 {
811   GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
812
813   if (GST_QUERY_TYPE (query) == GST_QUERY_CONTEXT)
814     return _query_context (base, query);
815
816   return GST_VIDEO_ENCODER_CLASS (parent_class)->sink_query (venc, query);
817 }
818
819 static void
820 gst_va_base_enc_set_context (GstElement * element, GstContext * context)
821 {
822   GstVaDisplay *old_display, *new_display;
823   GstVaBaseEnc *base = GST_VA_BASE_ENC (element);
824   GstVaBaseEncClass *klass = GST_VA_BASE_ENC_GET_CLASS (base);
825   gboolean ret;
826
827   old_display = base->display ? gst_object_ref (base->display) : NULL;
828
829   ret = gst_va_handle_set_context (element, context, klass->render_device_path,
830       &base->display);
831
832   new_display = base->display ? gst_object_ref (base->display) : NULL;
833
834   if (!ret || (old_display && new_display && old_display != new_display
835           && base->encoder)) {
836     GST_ELEMENT_WARNING (element, RESOURCE, BUSY,
837         ("Can't replace VA display while operating"), (NULL));
838   }
839
840   gst_clear_object (&old_display);
841   gst_clear_object (&new_display);
842
843   GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
844 }
845
846 static void
847 gst_va_base_enc_get_property (GObject * object, guint prop_id,
848     GValue * value, GParamSpec * pspec)
849 {
850   GstVaBaseEnc *base = GST_VA_BASE_ENC (object);
851
852   switch (prop_id) {
853     case PROP_DEVICE_PATH:{
854       if (!(base->display && GST_IS_VA_DISPLAY_DRM (base->display))) {
855         g_value_set_string (value, NULL);
856         return;
857       }
858       g_object_get_property (G_OBJECT (base->display), "path", value);
859       break;
860     }
861     default:
862       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
863   }
864 }
865
866 static void
867 gst_va_base_enc_init (GstVaBaseEnc * self)
868 {
869   g_queue_init (&self->reorder_list);
870   g_queue_init (&self->ref_list);
871   g_queue_init (&self->output_list);
872
873   self->priv = gst_va_base_enc_get_instance_private (self);
874 }
875
876 static void
877 gst_va_base_enc_dispose (GObject * object)
878 {
879   _flush_all_frames (GST_VA_BASE_ENC (object));
880   gst_va_base_enc_close (GST_VIDEO_ENCODER (object));
881
882   G_OBJECT_CLASS (parent_class)->dispose (object);
883 }
884
885 void
886 gst_va_base_enc_class_init (GstVaBaseEncClass * klass)
887 {
888   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
889   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
890   GstVideoEncoderClass *encoder_class = GST_VIDEO_ENCODER_CLASS (klass);
891
892   gobject_class->get_property = gst_va_base_enc_get_property;
893   gobject_class->dispose = gst_va_base_enc_dispose;
894
895   element_class->set_context = GST_DEBUG_FUNCPTR (gst_va_base_enc_set_context);
896
897   encoder_class->open = GST_DEBUG_FUNCPTR (gst_va_base_enc_open);
898   encoder_class->close = GST_DEBUG_FUNCPTR (gst_va_base_enc_close);
899   encoder_class->start = GST_DEBUG_FUNCPTR (gst_va_base_enc_start);
900   encoder_class->stop = GST_DEBUG_FUNCPTR (gst_va_base_enc_stop);
901   encoder_class->getcaps = GST_DEBUG_FUNCPTR (gst_va_base_enc_get_caps);
902   encoder_class->src_query = GST_DEBUG_FUNCPTR (gst_va_base_enc_src_query);
903   encoder_class->sink_query = GST_DEBUG_FUNCPTR (gst_va_base_enc_sink_query);
904   encoder_class->propose_allocation =
905       GST_DEBUG_FUNCPTR (gst_va_base_enc_propose_allocation);
906   encoder_class->handle_frame =
907       GST_DEBUG_FUNCPTR (gst_va_base_enc_handle_frame);
908   encoder_class->set_format = GST_DEBUG_FUNCPTR (gst_va_base_enc_set_format);
909   encoder_class->finish = GST_DEBUG_FUNCPTR (gst_va_base_enc_finish);
910   encoder_class->flush = GST_DEBUG_FUNCPTR (gst_va_base_enc_flush);
911
912   klass->reset_state = GST_DEBUG_FUNCPTR (gst_va_base_enc_reset_state_default);
913
914   /**
915    * GstVaBaseEnc:device-path:
916    *
917    * It shows the DRM device path used for the VA operation, if any.
918    */
919   properties[PROP_DEVICE_PATH] = g_param_spec_string ("device-path",
920       "Device Path", "DRM device path", NULL,
921       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
922
923   g_object_class_install_properties (gobject_class, N_PROPERTIES, properties);
924
925   gst_type_mark_as_plugin_api (GST_TYPE_VA_BASE_ENC, 0);
926 }
927
928 /*********************** Helper Functions ****************************/
929 gboolean
930 gst_va_base_enc_add_rate_control_parameter (GstVaBaseEnc * base,
931     GstVaEncodePicture * picture, guint32 rc_mode,
932     guint max_bitrate_bits, guint target_percentage,
933     guint32 qp_i, guint32 min_qp, guint32 max_qp, guint32 mbbrc)
934 {
935   uint32_t window_size;
936   struct VAEncMiscParameterRateControlWrap
937   {
938     VAEncMiscParameterType type;
939     VAEncMiscParameterRateControl rate_control;
940   } rate_control;
941
942   if (rc_mode == VA_RC_NONE || rc_mode == VA_RC_CQP)
943     return TRUE;
944
945   window_size = rc_mode == VA_RC_VBR ? max_bitrate_bits / 2 : max_bitrate_bits;
946
947   /* *INDENT-OFF* */
948   rate_control = (struct VAEncMiscParameterRateControlWrap) {
949     .type = VAEncMiscParameterTypeRateControl,
950     .rate_control = {
951       .bits_per_second = max_bitrate_bits,
952       .target_percentage = target_percentage,
953       .window_size = window_size,
954       .initial_qp = qp_i,
955       .min_qp = min_qp,
956       .max_qp = max_qp,
957       .rc_flags.bits.mb_rate_control = mbbrc,
958       .quality_factor = 0,
959     },
960   };
961   /* *INDENT-ON* */
962
963   if (!gst_va_encoder_add_param (base->encoder, picture,
964           VAEncMiscParameterBufferType, &rate_control, sizeof (rate_control))) {
965     GST_ERROR_OBJECT (base, "Failed to create the race control parameter");
966     return FALSE;
967   }
968
969   return TRUE;
970 }
971
972 gboolean
973 gst_va_base_enc_add_quality_level_parameter (GstVaBaseEnc * base,
974     GstVaEncodePicture * picture, guint target_usage)
975 {
976   /* *INDENT-OFF* */
977   struct
978   {
979     VAEncMiscParameterType type;
980     VAEncMiscParameterBufferQualityLevel ql;
981   } quality_level = {
982     .type = VAEncMiscParameterTypeQualityLevel,
983     .ql.quality_level = target_usage,
984   };
985   /* *INDENT-ON* */
986
987   if (target_usage == 0)
988     return TRUE;
989
990   if (!gst_va_encoder_add_param (base->encoder, picture,
991           VAEncMiscParameterBufferType, &quality_level,
992           sizeof (quality_level))) {
993     GST_ERROR_OBJECT (base, "Failed to create the quality level parameter");
994     return FALSE;
995   }
996
997   return TRUE;
998 }
999
1000 gboolean
1001 gst_va_base_enc_add_frame_rate_parameter (GstVaBaseEnc * base,
1002     GstVaEncodePicture * picture)
1003 {
1004   /* *INDENT-OFF* */
1005   struct
1006   {
1007     VAEncMiscParameterType type;
1008     VAEncMiscParameterFrameRate fr;
1009   } framerate = {
1010     .type = VAEncMiscParameterTypeFrameRate,
1011     /* denominator = framerate >> 16 & 0xffff;
1012      * numerator   = framerate & 0xffff; */
1013     .fr.framerate =
1014         (GST_VIDEO_INFO_FPS_N (&base->input_state->info) & 0xffff) |
1015         ((GST_VIDEO_INFO_FPS_D (&base->input_state->info) & 0xffff) << 16)
1016   };
1017   /* *INDENT-ON* */
1018
1019   if (!gst_va_encoder_add_param (base->encoder, picture,
1020           VAEncMiscParameterBufferType, &framerate, sizeof (framerate))) {
1021     GST_ERROR_OBJECT (base, "Failed to create the frame rate parameter");
1022     return FALSE;
1023   }
1024
1025   return TRUE;
1026 }
1027
1028 gboolean
1029 gst_va_base_enc_add_hrd_parameter (GstVaBaseEnc * base,
1030     GstVaEncodePicture * picture, guint32 rc_mode, guint cpb_length_bits)
1031 {
1032   /* *INDENT-OFF* */
1033   struct
1034   {
1035     VAEncMiscParameterType type;
1036     VAEncMiscParameterHRD hrd;
1037   } hrd = {
1038     .type = VAEncMiscParameterTypeHRD,
1039     .hrd = {
1040       .buffer_size = cpb_length_bits,
1041       .initial_buffer_fullness = cpb_length_bits / 2,
1042     },
1043   };
1044   /* *INDENT-ON* */
1045
1046   if (rc_mode == VA_RC_NONE || rc_mode == VA_RC_CQP || rc_mode == VA_RC_VCM)
1047     return TRUE;
1048
1049   if (!gst_va_encoder_add_param (base->encoder, picture,
1050           VAEncMiscParameterBufferType, &hrd, sizeof (hrd))) {
1051     GST_ERROR_OBJECT (base, "Failed to create the HRD parameter");
1052     return FALSE;
1053   }
1054
1055   return TRUE;
1056 }
1057
1058 gboolean
1059 gst_va_base_enc_add_trellis_parameter (GstVaBaseEnc * base,
1060     GstVaEncodePicture * picture, gboolean use_trellis)
1061 {
1062   /* *INDENT-OFF* */
1063   struct
1064   {
1065     VAEncMiscParameterType type;
1066     VAEncMiscParameterQuantization tr;
1067   } trellis = {
1068     .type = VAEncMiscParameterTypeQuantization,
1069     .tr.quantization_flags.bits = {
1070        .disable_trellis = 0,
1071        .enable_trellis_I = 1,
1072        .enable_trellis_B = 1,
1073        .enable_trellis_P = 1,
1074     },
1075   };
1076   /* *INDENT-ON* */
1077
1078   if (!use_trellis)
1079     return TRUE;
1080
1081   if (!gst_va_encoder_add_param (base->encoder, picture,
1082           VAEncMiscParameterBufferType, &trellis, sizeof (trellis))) {
1083     GST_ERROR_OBJECT (base, "Failed to create the trellis parameter");
1084     return FALSE;
1085   }
1086
1087   return TRUE;
1088 }
1089
1090 void
1091 gst_va_base_enc_add_codec_tag (GstVaBaseEnc * base, const gchar * codec_name)
1092 {
1093   GstVideoEncoder *venc = GST_VIDEO_ENCODER (base);
1094   GstTagList *tags = gst_tag_list_new_empty ();
1095   const gchar *encoder_name;
1096   guint bitrate = 0;
1097
1098   g_object_get (venc, "bitrate", &bitrate, NULL);
1099   if (bitrate > 0)
1100     gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_NOMINAL_BITRATE,
1101         bitrate, NULL);
1102
1103   if ((encoder_name =
1104           gst_element_class_get_metadata (GST_ELEMENT_GET_CLASS (venc),
1105               GST_ELEMENT_METADATA_LONGNAME)))
1106     gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER,
1107         encoder_name, NULL);
1108
1109   gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CODEC, codec_name,
1110       NULL);
1111
1112   gst_video_encoder_merge_tags (venc, tags, GST_TAG_MERGE_REPLACE);
1113   gst_tag_list_unref (tags);
1114 }
1115
1116 void
1117 gst_va_base_enc_reset_state (GstVaBaseEnc * base)
1118 {
1119   GstVaBaseEncClass *klass = GST_VA_BASE_ENC_GET_CLASS (base);
1120
1121   g_assert (klass->reset_state);
1122   klass->reset_state (base);
1123 }
1124
1125 /* *INDENT-OFF* */
1126 #define UPDATE_PROPERTY                         \
1127   GST_OBJECT_LOCK (base);                       \
1128   if (*old_val == new_val) {                    \
1129     GST_OBJECT_UNLOCK (base);                   \
1130     return;                                     \
1131   }                                             \
1132   *old_val = new_val;                                                   \
1133   GST_OBJECT_UNLOCK (base);                                             \
1134   if (pspec)                                                            \
1135     g_object_notify_by_pspec (G_OBJECT (base), pspec);                  \
1136
1137 void
1138 gst_va_base_enc_update_property_uint (GstVaBaseEnc * base, guint32 * old_val,
1139     guint32 new_val, GParamSpec * pspec)
1140 {
1141   UPDATE_PROPERTY
1142 }
1143
1144 void
1145 gst_va_base_enc_update_property_bool (GstVaBaseEnc * base, gboolean * old_val,
1146     gboolean new_val, GParamSpec * pspec)
1147 {
1148   UPDATE_PROPERTY
1149 }
1150
1151 #undef UPDATE_PROPERTY
1152 /* *INDENT-ON* */