va: baseenc: Do not use codec frame structure again after finish_frame().
[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 (GstVaBaseEnc * base)
63 {
64   GstVaBaseEncClass *klass = GST_VA_BASE_ENC_GET_CLASS (base);
65
66   base->frame_duration = GST_CLOCK_TIME_NONE;
67
68   base->width = 0;
69   base->height = 0;
70   base->profile = VAProfileNone;
71   base->entrypoint = klass->entrypoint;
72   base->rt_format = 0;
73   base->codedbuf_size = 0;
74 }
75
76 static void
77 _flush_all_frames (GstVaBaseEnc * base)
78 {
79   g_queue_clear_full (&base->reorder_list,
80       (GDestroyNotify) gst_video_codec_frame_unref);
81   g_queue_clear_full (&base->output_list,
82       (GDestroyNotify) gst_video_codec_frame_unref);
83   g_queue_clear_full (&base->ref_list,
84       (GDestroyNotify) gst_video_codec_frame_unref);
85 }
86
87 static gboolean
88 gst_va_base_enc_open (GstVideoEncoder * venc)
89 {
90   GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
91   GstVaBaseEncClass *klass = GST_VA_BASE_ENC_GET_CLASS (venc);
92   gboolean ret = FALSE;
93
94   if (!gst_va_ensure_element_data (venc, klass->render_device_path,
95           &base->display))
96     return FALSE;
97
98   g_object_notify (G_OBJECT (base), "device-path");
99
100   if (!g_atomic_pointer_get (&base->encoder)) {
101     GstVaEncoder *va_encoder;
102
103     va_encoder = gst_va_encoder_new (base->display, klass->codec,
104         klass->entrypoint);
105     if (va_encoder)
106       ret = TRUE;
107
108     gst_object_replace ((GstObject **) (&base->encoder),
109         (GstObject *) va_encoder);
110     gst_clear_object (&va_encoder);
111   } else {
112     ret = TRUE;
113   }
114
115   return ret;
116 }
117
118 static gboolean
119 gst_va_base_enc_start (GstVideoEncoder * venc)
120 {
121   GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
122   GstVaBaseEncClass *klass = GST_VA_BASE_ENC_GET_CLASS (base);
123
124   klass->reset_state (base);
125
126   base->input_frame_count = 0;
127   base->output_frame_count = 0;
128
129   base->input_state = NULL;
130
131   /* Set the minimum pts to some huge value (1000 hours). This keeps
132    * the dts at the start of the stream from needing to be
133    * negative. */
134   base->start_pts = GST_SECOND * 60 * 60 * 1000;
135   gst_video_encoder_set_min_pts (venc, base->start_pts);
136
137   return TRUE;
138 }
139
140 static gboolean
141 gst_va_base_enc_close (GstVideoEncoder * venc)
142 {
143   GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
144
145   gst_clear_object (&base->encoder);
146   gst_clear_object (&base->display);
147
148   return TRUE;
149 }
150
151 static gboolean
152 gst_va_base_enc_stop (GstVideoEncoder * venc)
153 {
154   GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
155
156   _flush_all_frames (base);
157
158   if (!gst_va_encoder_close (base->encoder)) {
159     GST_ERROR_OBJECT (base, "Failed to close the VA encoder");
160     return FALSE;
161   }
162
163   if (base->priv->raw_pool)
164     gst_buffer_pool_set_active (base->priv->raw_pool, FALSE);
165   gst_clear_object (&base->priv->raw_pool);
166
167   if (base->input_state)
168     gst_video_codec_state_unref (base->input_state);
169
170   return TRUE;
171 }
172
173 static GstCaps *
174 gst_va_base_enc_get_caps (GstVideoEncoder * venc, GstCaps * filter)
175 {
176   GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
177   GstCaps *caps = NULL, *tmp;
178
179   if (base->encoder)
180     caps = gst_va_encoder_get_sinkpad_caps (base->encoder);
181
182   if (caps) {
183     if (filter) {
184       tmp = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
185       gst_caps_unref (caps);
186       caps = tmp;
187     }
188   } else {
189     caps = gst_video_encoder_proxy_getcaps (venc, NULL, filter);
190   }
191
192   GST_LOG_OBJECT (base, "Returning caps %" GST_PTR_FORMAT, caps);
193   return caps;
194 }
195
196 static GstBufferPool *
197 _get_sinkpad_pool (GstVaBaseEnc * base)
198 {
199   GstAllocator *allocator;
200   GstAllocationParams params = { 0, };
201   guint size, usage_hint = 0;
202   GArray *surface_formats = NULL;
203   GstCaps *caps;
204
205   if (base->priv->raw_pool)
206     return base->priv->raw_pool;
207
208   g_assert (base->input_state);
209   caps = gst_caps_copy (base->input_state->caps);
210   gst_caps_set_features_simple (caps,
211       gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_VA));
212
213   gst_allocation_params_init (&params);
214
215   size = GST_VIDEO_INFO_SIZE (&base->input_state->info);
216
217   surface_formats = gst_va_encoder_get_surface_formats (base->encoder);
218
219   allocator = gst_va_allocator_new (base->display, surface_formats);
220
221   base->priv->raw_pool = gst_va_pool_new_with_config (caps, size, 1, 0,
222       usage_hint, GST_VA_FEATURE_AUTO, allocator, &params);
223   if (!base->priv->raw_pool) {
224     gst_object_unref (allocator);
225     return NULL;
226   }
227
228   gst_va_allocator_get_format (allocator, &base->priv->sinkpad_info, NULL,
229       NULL);
230
231   gst_object_unref (allocator);
232
233   gst_buffer_pool_set_active (base->priv->raw_pool, TRUE);
234
235   return base->priv->raw_pool;
236 }
237
238 static gboolean
239 _try_import_buffer (GstVaBaseEnc * base, GstBuffer * inbuf)
240 {
241   VASurfaceID surface;
242
243   /* The VA buffer. */
244   surface = gst_va_buffer_get_surface (inbuf);
245   if (surface != VA_INVALID_ID)
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   GstFlowReturn ret;
457   GstBuffer *buf;
458
459   if (base_class->prepare_output)
460     base_class->prepare_output (base, frame);
461
462   enc_picture =
463       *((GstVaEncodePicture **) gst_video_codec_frame_get_user_data (frame));
464
465   buf = gst_va_base_enc_create_output_buffer (base, enc_picture);
466   if (!buf) {
467     GST_ERROR_OBJECT (base, "Failed to create output buffer");
468     goto error;
469   }
470
471   gst_buffer_replace (&frame->output_buffer, buf);
472   gst_clear_buffer (&buf);
473
474   GST_LOG_OBJECT (base, "Push to downstream: frame system_frame_number: %d,"
475       " pts: %" GST_TIME_FORMAT ", dts: %" GST_TIME_FORMAT
476       " duration: %" GST_TIME_FORMAT ", buffer size: %" G_GSIZE_FORMAT,
477       frame->system_frame_number, GST_TIME_ARGS (frame->pts),
478       GST_TIME_ARGS (frame->dts), GST_TIME_ARGS (frame->duration),
479       gst_buffer_get_size (frame->output_buffer));
480
481   ret = gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (base), frame);
482   return ret;
483
484 error:
485   gst_clear_buffer (&frame->output_buffer);
486   gst_clear_buffer (&buf);
487   gst_video_encoder_finish_frame (GST_VIDEO_ENCODER (base), frame);
488
489   return GST_FLOW_ERROR;
490 }
491
492 static GstFlowReturn
493 _push_out_one_buffer (GstVaBaseEnc * base)
494 {
495   GstVideoCodecFrame *frame_out;
496   GstFlowReturn ret;
497   guint32 system_frame_number;
498
499   frame_out = g_queue_pop_head (&base->output_list);
500   gst_video_codec_frame_unref (frame_out);
501
502   system_frame_number = frame_out->system_frame_number;
503
504   ret = _push_buffer_to_downstream (base, frame_out);
505
506   if (ret != GST_FLOW_OK)
507     GST_ERROR_OBJECT (base, "fails to push one buffer, "
508         "system_frame_number %d", system_frame_number);
509
510   return ret;
511 }
512
513 static GstFlowReturn
514 gst_va_base_enc_handle_frame (GstVideoEncoder * venc,
515     GstVideoCodecFrame * frame)
516 {
517   GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
518   GstVaBaseEncClass *base_class = GST_VA_BASE_ENC_GET_CLASS (base);
519   GstFlowReturn ret;
520   GstBuffer *in_buf = NULL;
521   GstVideoCodecFrame *frame_encode = NULL;
522
523   GST_LOG_OBJECT (venc,
524       "handle frame id %d, dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT,
525       frame->system_frame_number,
526       GST_TIME_ARGS (GST_BUFFER_DTS (frame->input_buffer)),
527       GST_TIME_ARGS (GST_BUFFER_PTS (frame->input_buffer)));
528
529   ret = gst_va_base_enc_import_input_buffer (base,
530       frame->input_buffer, &in_buf);
531   if (ret != GST_FLOW_OK)
532     goto error_buffer_invalid;
533
534   gst_buffer_replace (&frame->input_buffer, in_buf);
535   gst_clear_buffer (&in_buf);
536
537   if (!base_class->new_frame (base, frame))
538     goto error_new_frame;
539
540   if (!base_class->reorder_frame (base, frame, FALSE, &frame_encode))
541     goto error_reorder;
542
543   /* pass it to reorder list and we should not use it again. */
544   frame = NULL;
545
546   while (frame_encode) {
547     ret = base_class->encode_frame (base, frame_encode, FALSE);
548     if (ret != GST_FLOW_OK)
549       goto error_encode;
550
551     while (g_queue_get_length (&base->output_list) > 0) {
552       ret = _push_out_one_buffer (base);
553       if (ret != GST_FLOW_OK)
554         goto error_push_buffer;
555     }
556
557     frame_encode = NULL;
558     if (!base_class->reorder_frame (base, NULL, FALSE, &frame_encode))
559       goto error_reorder;
560   }
561
562   return ret;
563
564 error_buffer_invalid:
565   {
566     GST_ELEMENT_ERROR (venc, STREAM, ENCODE,
567         ("Failed to import the input frame."), (NULL));
568     gst_clear_buffer (&in_buf);
569     gst_clear_buffer (&frame->output_buffer);
570     gst_video_encoder_finish_frame (venc, frame);
571     return ret;
572   }
573 error_new_frame:
574   {
575     GST_ELEMENT_ERROR (venc, STREAM, ENCODE,
576         ("Failed to create the input frame."), (NULL));
577     gst_clear_buffer (&frame->output_buffer);
578     gst_video_encoder_finish_frame (venc, frame);
579     return GST_FLOW_ERROR;
580   }
581 error_reorder:
582   {
583     GST_ELEMENT_ERROR (venc, STREAM, ENCODE,
584         ("Failed to reorder the input frame."), (NULL));
585     gst_clear_buffer (&frame->output_buffer);
586     gst_video_encoder_finish_frame (venc, frame);
587     return GST_FLOW_ERROR;
588   }
589 error_encode:
590   {
591     GST_ELEMENT_ERROR (venc, STREAM, ENCODE,
592         ("Failed to encode the frame."), (NULL));
593     gst_clear_buffer (&frame_encode->output_buffer);
594     gst_video_encoder_finish_frame (venc, frame_encode);
595     return ret;
596   }
597 error_push_buffer:
598   GST_ELEMENT_ERROR (venc, STREAM, ENCODE,
599       ("Failed to push the buffer."), (NULL));
600   return ret;
601 }
602
603 static GstFlowReturn
604 gst_va_base_enc_drain (GstVideoEncoder * venc)
605 {
606   GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
607   GstVaBaseEncClass *base_class = GST_VA_BASE_ENC_GET_CLASS (base);
608   GstFlowReturn ret = GST_FLOW_OK;
609   GstVideoCodecFrame *frame_enc = NULL;
610   gboolean is_last = FALSE;
611
612   GST_DEBUG_OBJECT (base, "Encoder is draining");
613
614   /* Kickout all cached frames */
615   if (!base_class->reorder_frame (base, NULL, TRUE, &frame_enc)) {
616     ret = GST_FLOW_ERROR;
617     goto error_and_purge_all;
618   }
619
620   while (frame_enc) {
621     is_last = FALSE;
622
623     if (g_queue_is_empty (&base->reorder_list))
624       is_last = TRUE;
625
626     ret = base_class->encode_frame (base, frame_enc, is_last);
627     if (ret != GST_FLOW_OK)
628       goto error_and_purge_all;
629
630     frame_enc = NULL;
631
632     ret = _push_out_one_buffer (base);
633     if (ret != GST_FLOW_OK)
634       goto error_and_purge_all;
635
636     if (!base_class->reorder_frame (base, NULL, TRUE, &frame_enc)) {
637       ret = GST_FLOW_ERROR;
638       goto error_and_purge_all;
639     }
640   }
641
642   g_assert (g_queue_is_empty (&base->reorder_list));
643
644   /* Output all frames. */
645   while (!g_queue_is_empty (&base->output_list)) {
646     ret = _push_out_one_buffer (base);
647     if (ret != GST_FLOW_OK)
648       goto error_and_purge_all;
649   }
650
651   /* Also clear the reference list. */
652   g_queue_clear_full (&base->ref_list,
653       (GDestroyNotify) gst_video_codec_frame_unref);
654
655   return GST_FLOW_OK;
656
657 error_and_purge_all:
658   if (frame_enc) {
659     gst_clear_buffer (&frame_enc->output_buffer);
660     gst_video_encoder_finish_frame (venc, frame_enc);
661   }
662
663   if (!g_queue_is_empty (&base->output_list)) {
664     GST_WARNING_OBJECT (base, "Still %d frame in the output list"
665         " after drain", g_queue_get_length (&base->output_list));
666     while (!g_queue_is_empty (&base->output_list)) {
667       frame_enc = g_queue_pop_head (&base->output_list);
668       gst_video_codec_frame_unref (frame_enc);
669       gst_clear_buffer (&frame_enc->output_buffer);
670       gst_video_encoder_finish_frame (venc, frame_enc);
671     }
672   }
673
674   if (!g_queue_is_empty (&base->reorder_list)) {
675     GST_WARNING_OBJECT (base, "Still %d frame in the reorder list"
676         " after drain", g_queue_get_length (&base->reorder_list));
677     while (!g_queue_is_empty (&base->reorder_list)) {
678       frame_enc = g_queue_pop_head (&base->reorder_list);
679       gst_video_codec_frame_unref (frame_enc);
680       gst_clear_buffer (&frame_enc->output_buffer);
681       gst_video_encoder_finish_frame (venc, frame_enc);
682     }
683   }
684
685   /* Also clear the reference list. */
686   g_queue_clear_full (&base->ref_list,
687       (GDestroyNotify) gst_video_codec_frame_unref);
688
689   return ret;
690 }
691
692 static GstFlowReturn
693 gst_va_base_enc_finish (GstVideoEncoder * venc)
694 {
695   return gst_va_base_enc_drain (venc);
696 }
697
698 static gboolean
699 gst_va_base_enc_set_format (GstVideoEncoder * venc, GstVideoCodecState * state)
700 {
701   GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
702   GstVaBaseEncClass *base_class = GST_VA_BASE_ENC_GET_CLASS (base);
703
704   g_return_val_if_fail (state->caps != NULL, FALSE);
705
706   if (base->input_state)
707     gst_video_codec_state_unref (base->input_state);
708   base->input_state = gst_video_codec_state_ref (state);
709
710   if (gst_va_base_enc_drain (venc) != GST_FLOW_OK)
711     return FALSE;
712
713   if (!gst_va_encoder_close (base->encoder)) {
714     GST_ERROR_OBJECT (base, "Failed to close the VA encoder");
715     return FALSE;
716   }
717
718   if (!base_class->reconfig (base)) {
719     GST_ERROR_OBJECT (base, "Reconfig the encoder error");
720     return FALSE;
721   }
722
723   /* Sub class should open the encoder if reconfig succeeds. */
724   g_assert (gst_va_encoder_is_open (base->encoder));
725
726   return TRUE;
727 }
728
729 static gboolean
730 gst_va_base_enc_flush (GstVideoEncoder * venc)
731 {
732   _flush_all_frames (GST_VA_BASE_ENC (venc));
733   return TRUE;
734 }
735
736 static gboolean
737 _query_context (GstVaBaseEnc * base, GstQuery * query)
738 {
739   GstVaDisplay *display = NULL;
740   gboolean ret;
741
742   gst_object_replace ((GstObject **) & display, (GstObject *) base->display);
743   ret = gst_va_handle_context_query (GST_ELEMENT_CAST (base), query, display);
744   gst_clear_object (&display);
745
746   return ret;
747 }
748
749 static gboolean
750 gst_va_base_enc_src_query (GstVideoEncoder * venc, GstQuery * query)
751 {
752   GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
753   gboolean ret = FALSE;
754
755   switch (GST_QUERY_TYPE (query)) {
756     case GST_QUERY_CONTEXT:{
757       ret = _query_context (base, query);
758       break;
759     }
760     case GST_QUERY_CAPS:{
761       GstCaps *caps = NULL, *tmp, *filter = NULL;
762       GstVaEncoder *va_encoder = NULL;
763       gboolean fixed_caps;
764
765       gst_object_replace ((GstObject **) & va_encoder,
766           (GstObject *) base->encoder);
767
768       gst_query_parse_caps (query, &filter);
769
770       fixed_caps = GST_PAD_IS_FIXED_CAPS (GST_VIDEO_ENCODER_SRC_PAD (venc));
771
772       if (!fixed_caps && va_encoder)
773         caps = gst_va_encoder_get_srcpad_caps (va_encoder);
774
775       gst_clear_object (&va_encoder);
776
777       if (caps) {
778         if (filter) {
779           tmp = gst_caps_intersect_full (filter, caps,
780               GST_CAPS_INTERSECT_FIRST);
781           gst_caps_unref (caps);
782           caps = tmp;
783         }
784
785         GST_LOG_OBJECT (base, "Returning caps %" GST_PTR_FORMAT, caps);
786         gst_query_set_caps_result (query, caps);
787         gst_caps_unref (caps);
788         ret = TRUE;
789         break;
790       }
791       /* else jump to default */
792     }
793     default:
794       ret = GST_VIDEO_ENCODER_CLASS (parent_class)->src_query (venc, query);
795       break;
796   }
797
798   return ret;
799 }
800
801 static gboolean
802 gst_va_base_enc_sink_query (GstVideoEncoder * venc, GstQuery * query)
803 {
804   GstVaBaseEnc *base = GST_VA_BASE_ENC (venc);
805
806   if (GST_QUERY_TYPE (query) == GST_QUERY_CONTEXT)
807     return _query_context (base, query);
808
809   return GST_VIDEO_ENCODER_CLASS (parent_class)->sink_query (venc, query);
810 }
811
812 static void
813 gst_va_base_enc_set_context (GstElement * element, GstContext * context)
814 {
815   GstVaDisplay *old_display, *new_display;
816   GstVaBaseEnc *base = GST_VA_BASE_ENC (element);
817   GstVaBaseEncClass *klass = GST_VA_BASE_ENC_GET_CLASS (base);
818   gboolean ret;
819
820   old_display = base->display ? gst_object_ref (base->display) : NULL;
821
822   ret = gst_va_handle_set_context (element, context, klass->render_device_path,
823       &base->display);
824
825   new_display = base->display ? gst_object_ref (base->display) : NULL;
826
827   if (!ret || (old_display && new_display && old_display != new_display
828           && base->encoder)) {
829     GST_ELEMENT_WARNING (element, RESOURCE, BUSY,
830         ("Can't replace VA display while operating"), (NULL));
831   }
832
833   gst_clear_object (&old_display);
834   gst_clear_object (&new_display);
835
836   GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
837 }
838
839 static void
840 gst_va_base_enc_get_property (GObject * object, guint prop_id,
841     GValue * value, GParamSpec * pspec)
842 {
843   GstVaBaseEnc *base = GST_VA_BASE_ENC (object);
844
845   switch (prop_id) {
846     case PROP_DEVICE_PATH:{
847       if (!(base->display && GST_IS_VA_DISPLAY_DRM (base->display))) {
848         g_value_set_string (value, NULL);
849         return;
850       }
851       g_object_get_property (G_OBJECT (base->display), "path", value);
852       break;
853     }
854     default:
855       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
856   }
857 }
858
859 static void
860 gst_va_base_enc_init (GstVaBaseEnc * self)
861 {
862   g_queue_init (&self->reorder_list);
863   g_queue_init (&self->ref_list);
864   g_queue_init (&self->output_list);
865
866   self->priv = gst_va_base_enc_get_instance_private (self);
867 }
868
869 static void
870 gst_va_base_enc_dispose (GObject * object)
871 {
872   _flush_all_frames (GST_VA_BASE_ENC (object));
873   gst_va_base_enc_close (GST_VIDEO_ENCODER (object));
874
875   G_OBJECT_CLASS (parent_class)->dispose (object);
876 }
877
878 void
879 gst_va_base_enc_class_init (GstVaBaseEncClass * klass)
880 {
881   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
882   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
883   GstVideoEncoderClass *encoder_class = GST_VIDEO_ENCODER_CLASS (klass);
884
885   gobject_class->get_property = gst_va_base_enc_get_property;
886   gobject_class->dispose = gst_va_base_enc_dispose;
887
888   element_class->set_context = GST_DEBUG_FUNCPTR (gst_va_base_enc_set_context);
889
890   encoder_class->open = GST_DEBUG_FUNCPTR (gst_va_base_enc_open);
891   encoder_class->close = GST_DEBUG_FUNCPTR (gst_va_base_enc_close);
892   encoder_class->start = GST_DEBUG_FUNCPTR (gst_va_base_enc_start);
893   encoder_class->stop = GST_DEBUG_FUNCPTR (gst_va_base_enc_stop);
894   encoder_class->getcaps = GST_DEBUG_FUNCPTR (gst_va_base_enc_get_caps);
895   encoder_class->src_query = GST_DEBUG_FUNCPTR (gst_va_base_enc_src_query);
896   encoder_class->sink_query = GST_DEBUG_FUNCPTR (gst_va_base_enc_sink_query);
897   encoder_class->propose_allocation =
898       GST_DEBUG_FUNCPTR (gst_va_base_enc_propose_allocation);
899   encoder_class->handle_frame =
900       GST_DEBUG_FUNCPTR (gst_va_base_enc_handle_frame);
901   encoder_class->set_format = GST_DEBUG_FUNCPTR (gst_va_base_enc_set_format);
902   encoder_class->finish = GST_DEBUG_FUNCPTR (gst_va_base_enc_finish);
903   encoder_class->flush = GST_DEBUG_FUNCPTR (gst_va_base_enc_flush);
904
905   klass->reset_state = GST_DEBUG_FUNCPTR (gst_va_base_enc_reset_state);
906
907   properties[PROP_DEVICE_PATH] = g_param_spec_string ("device-path",
908       "Device Path", "DRM device path", NULL,
909       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
910
911   g_object_class_install_properties (gobject_class, N_PROPERTIES, properties);
912
913   gst_type_mark_as_plugin_api (GST_TYPE_VA_BASE_ENC, 0);
914 }
915
916 /*********************** Helper Functions ****************************/
917 gboolean
918 gst_va_base_enc_add_rate_control_parameter (GstVaBaseEnc * base,
919     GstVaEncodePicture * picture, guint32 rc_mode,
920     guint max_bitrate_bits, guint target_percentage,
921     guint32 qp_i, guint32 min_qp, guint32 max_qp, guint32 mbbrc)
922 {
923   uint32_t window_size;
924   struct VAEncMiscParameterRateControlWrap
925   {
926     VAEncMiscParameterType type;
927     VAEncMiscParameterRateControl rate_control;
928   } rate_control;
929
930   if (rc_mode == VA_RC_NONE || rc_mode == VA_RC_CQP)
931     return TRUE;
932
933   window_size = rc_mode == VA_RC_VBR ? max_bitrate_bits / 2 : max_bitrate_bits;
934
935   /* *INDENT-OFF* */
936   rate_control = (struct VAEncMiscParameterRateControlWrap) {
937     .type = VAEncMiscParameterTypeRateControl,
938     .rate_control = {
939       .bits_per_second = max_bitrate_bits,
940       .target_percentage = target_percentage,
941       .window_size = window_size,
942       .initial_qp = qp_i,
943       .min_qp = min_qp,
944       .max_qp = max_qp,
945       .rc_flags.bits.mb_rate_control = mbbrc,
946       .quality_factor = 0,
947     },
948   };
949   /* *INDENT-ON* */
950
951   if (!gst_va_encoder_add_param (base->encoder, picture,
952           VAEncMiscParameterBufferType, &rate_control, sizeof (rate_control))) {
953     GST_ERROR_OBJECT (base, "Failed to create the race control parameter");
954     return FALSE;
955   }
956
957   return TRUE;
958 }
959
960 gboolean
961 gst_va_base_enc_add_quality_level_parameter (GstVaBaseEnc * base,
962     GstVaEncodePicture * picture, guint target_usage)
963 {
964   /* *INDENT-OFF* */
965   struct
966   {
967     VAEncMiscParameterType type;
968     VAEncMiscParameterBufferQualityLevel ql;
969   } quality_level = {
970     .type = VAEncMiscParameterTypeQualityLevel,
971     .ql.quality_level = target_usage,
972   };
973   /* *INDENT-ON* */
974
975   if (target_usage == 0)
976     return TRUE;
977
978   if (!gst_va_encoder_add_param (base->encoder, picture,
979           VAEncMiscParameterBufferType, &quality_level,
980           sizeof (quality_level))) {
981     GST_ERROR_OBJECT (base, "Failed to create the quality level parameter");
982     return FALSE;
983   }
984
985   return TRUE;
986 }
987
988 gboolean
989 gst_va_base_enc_add_frame_rate_parameter (GstVaBaseEnc * base,
990     GstVaEncodePicture * picture)
991 {
992   /* *INDENT-OFF* */
993   struct
994   {
995     VAEncMiscParameterType type;
996     VAEncMiscParameterFrameRate fr;
997   } framerate = {
998     .type = VAEncMiscParameterTypeFrameRate,
999     /* denominator = framerate >> 16 & 0xffff;
1000      * numerator   = framerate & 0xffff; */
1001     .fr.framerate =
1002         (GST_VIDEO_INFO_FPS_N (&base->input_state->info) & 0xffff) |
1003         ((GST_VIDEO_INFO_FPS_D (&base->input_state->info) & 0xffff) << 16)
1004   };
1005   /* *INDENT-ON* */
1006
1007   if (!gst_va_encoder_add_param (base->encoder, picture,
1008           VAEncMiscParameterBufferType, &framerate, sizeof (framerate))) {
1009     GST_ERROR_OBJECT (base, "Failed to create the frame rate parameter");
1010     return FALSE;
1011   }
1012
1013   return TRUE;
1014 }
1015
1016 gboolean
1017 gst_va_base_enc_add_hrd_parameter (GstVaBaseEnc * base,
1018     GstVaEncodePicture * picture, guint32 rc_mode, guint cpb_length_bits)
1019 {
1020   /* *INDENT-OFF* */
1021   struct
1022   {
1023     VAEncMiscParameterType type;
1024     VAEncMiscParameterHRD hrd;
1025   } hrd = {
1026     .type = VAEncMiscParameterTypeHRD,
1027     .hrd = {
1028       .buffer_size = cpb_length_bits,
1029       .initial_buffer_fullness = cpb_length_bits / 2,
1030     },
1031   };
1032   /* *INDENT-ON* */
1033
1034   if (rc_mode == VA_RC_NONE || rc_mode == VA_RC_CQP || rc_mode == VA_RC_VCM)
1035     return TRUE;
1036
1037   if (!gst_va_encoder_add_param (base->encoder, picture,
1038           VAEncMiscParameterBufferType, &hrd, sizeof (hrd))) {
1039     GST_ERROR_OBJECT (base, "Failed to create the HRD parameter");
1040     return FALSE;
1041   }
1042
1043   return TRUE;
1044 }
1045
1046 gboolean
1047 gst_va_base_enc_add_trellis_parameter (GstVaBaseEnc * base,
1048     GstVaEncodePicture * picture, gboolean use_trellis)
1049 {
1050   /* *INDENT-OFF* */
1051   struct
1052   {
1053     VAEncMiscParameterType type;
1054     VAEncMiscParameterQuantization tr;
1055   } trellis = {
1056     .type = VAEncMiscParameterTypeQuantization,
1057     .tr.quantization_flags.bits = {
1058        .disable_trellis = 0,
1059        .enable_trellis_I = 1,
1060        .enable_trellis_B = 1,
1061        .enable_trellis_P = 1,
1062     },
1063   };
1064   /* *INDENT-ON* */
1065
1066   if (!use_trellis)
1067     return TRUE;
1068
1069   if (!gst_va_encoder_add_param (base->encoder, picture,
1070           VAEncMiscParameterBufferType, &trellis, sizeof (trellis))) {
1071     GST_ERROR_OBJECT (base, "Failed to create the trellis parameter");
1072     return FALSE;
1073   }
1074
1075   return TRUE;
1076 }
1077
1078 void
1079 gst_va_base_enc_add_codec_tag (GstVaBaseEnc * base, const gchar * codec_name)
1080 {
1081   GstVideoEncoder *venc = GST_VIDEO_ENCODER (base);
1082   GstTagList *tags = gst_tag_list_new_empty ();
1083   const gchar *encoder_name;
1084   guint bitrate = 0;
1085
1086   g_object_get (venc, "bitrate", &bitrate, NULL);
1087   if (bitrate > 0)
1088     gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_NOMINAL_BITRATE,
1089         bitrate, NULL);
1090
1091   if ((encoder_name =
1092           gst_element_class_get_metadata (GST_ELEMENT_GET_CLASS (venc),
1093               GST_ELEMENT_METADATA_LONGNAME)))
1094     gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER,
1095         encoder_name, NULL);
1096
1097   gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CODEC, codec_name,
1098       NULL);
1099
1100   gst_video_encoder_merge_tags (venc, tags, GST_TAG_MERGE_REPLACE);
1101   gst_tag_list_unref (tags);
1102 }