Add gst_vaapi_decoder_pause().
[vaapi:gstreamer-vaapi.git] / gst-libs / gst / vaapi / gstvaapidecoder.c
1 /*
2  *  gstvaapidecoder.c - VA decoder abstraction
3  *
4  *  gstreamer-vaapi (C) 2010 Splitted-Desktop Systems
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
19  */
20
21 /**
22  * SECTION:gstvaapidecoder
23  * @short_description: VA decoder abstraction
24  */
25
26 #include "config.h"
27 #include <assert.h>
28 #include <string.h>
29 #include "gstvaapicompat.h"
30 #include "gstvaapidecoder.h"
31 #include "gstvaapidecoder_priv.h"
32 #include "gstvaapiutils.h"
33 #include "gstvaapi_priv.h"
34
35 #define DEBUG 1
36 #include "gstvaapidebug.h"
37
38 G_DEFINE_TYPE(GstVaapiDecoder, gst_vaapi_decoder, G_TYPE_OBJECT);
39
40 /* XXX: Make it a GstVaapiDecodedSurface + propagate PTS */
41 typedef struct _DecodedSurface DecodedSurface;
42 struct _DecodedSurface {
43     GstVaapiSurfaceProxy *proxy;
44     GstVaapiDecoderStatus status;
45 };
46
47 enum {
48     PROP_0,
49
50     PROP_DISPLAY,
51     PROP_CODEC,
52     PROP_CODEC_DATA
53 };
54
55 /* Wait _at most_ 10 ms for encoded buffers between each decoding step */
56 #define GST_VAAPI_DECODER_TIMEOUT (10000)
57
58 static GstBuffer *
59 pop_buffer(GstVaapiDecoder *decoder);
60
61 static gboolean
62 push_surface(GstVaapiDecoder *decoder, GstVaapiSurface *surface);
63
64 static DecodedSurface *
65 pop_surface(GstVaapiDecoder *decoder, GTimeVal *end_time);
66
67 static void
68 decoder_task(gpointer data)
69 {
70     GstVaapiDecoder * const decoder = GST_VAAPI_DECODER_CAST(data);
71     GstVaapiDecoderPrivate * const priv = decoder->priv;
72     GstVaapiDecoderClass * const klass = GST_VAAPI_DECODER_GET_CLASS(decoder);
73     GstBuffer *buffer;
74
75     buffer = pop_buffer(decoder);
76     if (!buffer)
77         return;
78
79     priv->decoder_status = klass->decode(decoder, buffer);
80     GST_DEBUG("decode frame (status = %d)", priv->decoder_status);
81
82     switch (priv->decoder_status) {
83     case GST_VAAPI_DECODER_STATUS_SUCCESS:
84     case GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA:
85         break;
86     default:
87         /*  Send an empty surface to signal an error */
88         push_surface(decoder, NULL);
89         gst_task_pause(priv->decoder_task);
90         break;
91     }
92 }
93
94 static void
95 update_clock(GstVaapiDecoder *decoder, GstBuffer *buffer)
96 {
97     GstVaapiDecoderPrivate * const priv = decoder->priv;
98     GstClockTime timestamp, duration;
99
100     timestamp = GST_BUFFER_TIMESTAMP(buffer);
101     duration  = GST_BUFFER_DURATION(buffer);
102
103     if (GST_CLOCK_TIME_IS_VALID(duration)) {
104         if (GST_CLOCK_TIME_IS_VALID(timestamp))
105             priv->surface_timestamp = timestamp;
106         priv->surface_duration = duration;
107     }
108     else {
109         /* Assumes those are user-generated buffers with no timestamp
110            or duration information. Try to rely on "framerate". */
111         if (!GST_CLOCK_TIME_IS_VALID(priv->surface_timestamp))
112             priv->surface_timestamp = 0;
113         priv->surface_duration =
114             gst_util_uint64_scale_int(GST_SECOND, priv->fps_d, priv->fps_n);
115     }
116 }
117
118 static inline void
119 init_buffer(GstBuffer *buffer, const guchar *buf, guint buf_size)
120 {
121     GST_BUFFER_DATA(buffer)      = (guint8 *)buf;
122     GST_BUFFER_SIZE(buffer)      = buf_size;
123     GST_BUFFER_TIMESTAMP(buffer) = GST_CLOCK_TIME_NONE;
124     GST_BUFFER_DURATION(buffer)  = GST_CLOCK_TIME_NONE;
125 }
126
127 static inline GstBuffer *
128 create_eos_buffer(void)
129 {
130     GstBuffer *buffer;
131
132     buffer = gst_buffer_new();
133     if (!buffer)
134         return NULL;
135
136     init_buffer(buffer, NULL, 0);
137     GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_EOS);
138     return buffer;
139 }
140
141 static GstBuffer *
142 create_buffer(const guchar *buf, guint buf_size, gboolean copy)
143 {
144     GstBuffer *buffer;
145
146     if (!buf || !buf_size)
147         return NULL;
148
149     buffer = gst_buffer_new();
150     if (!buffer)
151         return NULL;
152
153     if (copy) {
154         buffer->malloc_data = g_malloc(buf_size);
155         if (!buffer->malloc_data) {
156             gst_buffer_unref(buffer);
157             return NULL;
158         }
159         memcpy(buffer->malloc_data, buf, buf_size);
160         buf = buffer->malloc_data;
161     }
162     init_buffer(buffer, buf, buf_size);
163     return buffer;
164 }
165
166 static gboolean
167 push_buffer(GstVaapiDecoder *decoder, GstBuffer *buffer)
168 {
169     GstVaapiDecoderPrivate * const priv = decoder->priv;
170
171     if (!buffer) {
172         buffer = create_eos_buffer();
173         if (!buffer)
174             return FALSE;
175     }
176
177     GST_DEBUG("queue encoded data buffer %p (%d bytes)",
178               buffer, GST_BUFFER_SIZE(buffer));
179
180     g_async_queue_push(priv->buffers, buffer);
181     return TRUE;
182 }
183
184 static GstBuffer *
185 pop_buffer(GstVaapiDecoder *decoder)
186 {
187     GstVaapiDecoderPrivate * const priv = decoder->priv;
188     GTimeVal end_time;
189     GstBuffer *buffer;
190
191     g_get_current_time(&end_time);
192     g_time_val_add(&end_time, GST_VAAPI_DECODER_TIMEOUT);
193
194     buffer = g_async_queue_timed_pop(priv->buffers, &end_time);
195     if (!buffer)
196         return NULL;
197
198     GST_DEBUG("dequeue buffer %p for decoding (%d bytes)",
199               buffer, GST_BUFFER_SIZE(buffer));
200
201     update_clock(decoder, buffer);
202     return buffer;
203 }
204
205 static inline DecodedSurface *
206 create_surface(void)
207 {
208     return g_slice_new0(DecodedSurface);
209 }
210
211 static inline void
212 destroy_surface(DecodedSurface *ds)
213 {
214     g_slice_free(DecodedSurface, ds);
215 }
216
217 static gboolean
218 push_surface(GstVaapiDecoder *decoder, GstVaapiSurface *surface)
219 {
220     GstVaapiDecoderPrivate * const priv = decoder->priv;
221     DecodedSurface *ds;
222
223     ds = create_surface();
224     if (!ds)
225         return FALSE;
226
227     if (surface) {
228         GST_DEBUG("queue decoded surface %" GST_VAAPI_ID_FORMAT,
229                   GST_VAAPI_ID_ARGS(GST_VAAPI_OBJECT_ID(surface)));
230         ds->proxy = gst_vaapi_surface_proxy_new(priv->context, surface);
231         if (ds->proxy) {
232             ds->status = GST_VAAPI_DECODER_STATUS_SUCCESS;
233             gst_vaapi_surface_proxy_set_timestamp(
234                 ds->proxy, priv->surface_timestamp);
235         }
236         else
237             ds->status = GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
238     }
239     else
240         ds->status = priv->decoder_status;
241
242     g_async_queue_push(priv->surfaces, ds);
243     return TRUE;
244 }
245
246 static inline DecodedSurface *
247 pop_surface(GstVaapiDecoder *decoder, GTimeVal *end_time)
248 {
249     GstVaapiDecoderPrivate * const priv = decoder->priv;
250
251     if (!gst_vaapi_decoder_start(decoder))
252         return NULL;
253
254     return g_async_queue_timed_pop(priv->surfaces, end_time);
255 }
256
257 static inline void
258 set_codec_data(GstVaapiDecoder *decoder, GstBuffer *codec_data)
259 {
260     GstVaapiDecoderPrivate * const priv = decoder->priv;
261
262     if (priv->codec_data) {
263         gst_buffer_unref(priv->codec_data);
264         priv->codec_data = NULL;
265     }
266
267     if (codec_data)
268         priv->codec_data = gst_buffer_ref(codec_data);
269 }
270
271 static void
272 clear_async_queue(GAsyncQueue *q, GDestroyNotify destroy)
273 {
274     guint i, qlen = g_async_queue_length(q);
275
276     for (i = 0; i < qlen; i++)
277         destroy(g_async_queue_pop(q));
278 }
279
280 static void
281 gst_vaapi_decoder_finalize(GObject *object)
282 {
283     GstVaapiDecoder * const        decoder = GST_VAAPI_DECODER(object);
284     GstVaapiDecoderPrivate * const priv    = decoder->priv;
285
286     gst_vaapi_decoder_stop(decoder);
287
288     set_codec_data(decoder, NULL);
289
290     if (priv->context) {
291         g_object_unref(priv->context);
292         priv->context = NULL;
293     }
294
295     if (priv->buffers) {
296         clear_async_queue(priv->buffers, (GDestroyNotify)gst_buffer_unref);
297         g_async_queue_unref(priv->buffers);
298         priv->buffers = NULL;
299     }
300
301     if (priv->surfaces) {
302         clear_async_queue(priv->surfaces, (GDestroyNotify)destroy_surface);
303         g_async_queue_unref(priv->surfaces);
304         priv->surfaces = NULL;
305     }
306
307     if (priv->display) {
308         g_object_unref(priv->display);
309         priv->display = NULL;
310     }
311
312     G_OBJECT_CLASS(gst_vaapi_decoder_parent_class)->finalize(object);
313 }
314
315 static void
316 gst_vaapi_decoder_set_property(
317     GObject      *object,
318     guint         prop_id,
319     const GValue *value,
320     GParamSpec   *pspec
321 )
322 {
323     GstVaapiDecoderPrivate * const priv = GST_VAAPI_DECODER(object)->priv;
324
325     switch (prop_id) {
326     case PROP_DISPLAY:
327         priv->display = g_object_ref(g_value_get_object(value));
328         break;
329     case PROP_CODEC:
330         priv->codec = g_value_get_uint(value);
331         break;
332     case PROP_CODEC_DATA:
333         set_codec_data(GST_VAAPI_DECODER(object), gst_value_get_buffer(value));
334         break;
335     default:
336         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
337         break;
338     }
339 }
340
341 static void
342 gst_vaapi_decoder_get_property(
343     GObject    *object,
344     guint       prop_id,
345     GValue     *value,
346     GParamSpec *pspec
347 )
348 {
349     GstVaapiDecoderPrivate * const priv = GST_VAAPI_DECODER(object)->priv;
350
351     switch (prop_id) {
352     case PROP_DISPLAY:
353         g_value_set_object(value, priv->display);
354         break;
355     case PROP_CODEC:
356         g_value_set_uint(value, priv->codec);
357         break;
358     case PROP_CODEC_DATA:
359         gst_value_set_buffer(value, priv->codec_data);
360         break;
361     default:
362         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
363         break;
364     }
365 }
366
367 static void
368 gst_vaapi_decoder_class_init(GstVaapiDecoderClass *klass)
369 {
370     GObjectClass * const object_class = G_OBJECT_CLASS(klass);
371
372     g_type_class_add_private(klass, sizeof(GstVaapiDecoderPrivate));
373
374     object_class->finalize     = gst_vaapi_decoder_finalize;
375     object_class->set_property = gst_vaapi_decoder_set_property;
376     object_class->get_property = gst_vaapi_decoder_get_property;
377
378     /**
379      * GstVaapiDecoder:display:
380      *
381      * The #GstVaapiDisplay this decoder is bound to.
382      */
383     g_object_class_install_property
384         (object_class,
385          PROP_DISPLAY,
386          g_param_spec_object("display",
387                              "Display",
388                              "The GstVaapiDisplay this decoder is bound to",
389                              GST_VAAPI_TYPE_DISPLAY,
390                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
391
392     g_object_class_install_property
393         (object_class,
394          PROP_CODEC,
395          g_param_spec_uint("codec",
396                            "Codec",
397                            "The codec handled by the decoder",
398                            0, G_MAXINT32, 0,
399                            G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
400
401     g_object_class_install_property
402         (object_class,
403          PROP_CODEC_DATA,
404          gst_param_spec_mini_object("codec-data",
405                                     "Codec data",
406                                     "Extra codec data",
407                                     GST_TYPE_BUFFER,
408                                     G_PARAM_WRITABLE|G_PARAM_CONSTRUCT_ONLY));
409 }
410
411 static void
412 gst_vaapi_decoder_init(GstVaapiDecoder *decoder)
413 {
414     GstVaapiDecoderPrivate *priv = GST_VAAPI_DECODER_GET_PRIVATE(decoder);
415
416     decoder->priv               = priv;
417     priv->context               = NULL;
418     priv->codec                 = 0;
419     priv->codec_data            = NULL;
420     priv->fps_n                 = 1000;
421     priv->fps_d                 = 30;
422     priv->surface_timestamp     = GST_CLOCK_TIME_NONE;
423     priv->surface_duration      = GST_CLOCK_TIME_NONE;
424     priv->buffers               = g_async_queue_new();
425     priv->surfaces              = g_async_queue_new();
426     priv->decoder_task          = NULL;
427
428     g_static_rec_mutex_init(&priv->decoder_task_lock);
429 }
430
431 /**
432  * gst_vaapi_decoder_start:
433  * @decoder: a #GstVaapiDecoder
434  *
435  * Starts the decoder. This creates the internal decoder thread, if
436  * necessary.
437  *
438  * Return value: %TRUE on success
439  */
440 gboolean
441 gst_vaapi_decoder_start(GstVaapiDecoder *decoder)
442 {
443     g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), FALSE);
444
445     if (decoder->priv->decoder_task)
446         return TRUE;
447
448     decoder->priv->decoder_task = gst_task_create(decoder_task, decoder);
449     if (!decoder->priv->decoder_task)
450         return FALSE;
451
452     gst_task_set_lock(decoder->priv->decoder_task, &decoder->priv->decoder_task_lock);
453     return gst_task_start(decoder->priv->decoder_task);
454 }
455
456 /**
457  * gst_vaapi_decoder_pause:
458  * @decoder: a #GstVaapiDecoder
459  *
460  * Pauses the decoder. It can be made active again through
461  * gst_vaapi_decoder_start() or definitely stopped through
462  * gst_vaapi_decoder_stop().
463  *
464  * Return value: %TRUE on success
465  */
466 gboolean
467 gst_vaapi_decoder_pause(GstVaapiDecoder *decoder)
468 {
469     g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), FALSE);
470
471     return gst_task_pause(decoder->priv->decoder_task);
472 }
473
474 /**
475  * gst_vaapi_decoder_stop:
476  * @decoder: a #GstVaapiDecoder
477  *
478  * Stops the decoder. This destroys any decoding thread that was
479  * previously created by gst_vaapi_decoder_start(). Only
480  * gst_vaapi_decoder_get_surface() on the queued surfaces will be
481  * allowed at this point.
482  *
483  * Return value: %FALSE on success
484  */
485 gboolean
486 gst_vaapi_decoder_stop(GstVaapiDecoder *decoder)
487 {
488     gboolean success;
489
490     g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), FALSE);
491
492     if (!decoder->priv->decoder_task)
493         return FALSE;
494
495     success = gst_task_join(decoder->priv->decoder_task);
496     g_object_unref(decoder->priv->decoder_task);
497     decoder->priv->decoder_task = NULL;
498     return success;
499 }
500
501 /**
502  * gst_vaapi_decoder_get_frame_rate:
503  * @decoder: a #GstVaapiDecoder
504  * @num: return location for the numerator of the frame rate
505  * @den: return location for the denominator of the frame rate
506  *
507  * Retrieves the current frame rate as the fraction @num / @den. The
508  * default frame rate is 30 fps.
509  */
510 void
511 gst_vaapi_decoder_get_frame_rate(
512     GstVaapiDecoder *decoder,
513     guint           *num,
514     guint           *den
515 )
516 {
517     g_return_if_fail(GST_VAAPI_IS_DECODER(decoder));
518
519     if (num)
520         *num = decoder->priv->fps_n;
521
522     if (den)
523         *den = decoder->priv->fps_d;
524 }
525
526 /**
527  * gst_vaapi_decoder_set_frame_rate:
528  * @decoder: a #GstVaapiDecoder
529  * @num: the numerator of the frame rate
530  * @den: the denominator of the frame rate
531  *
532  * Sets the frame rate for the stream to @num / @den. By default, the
533  * decoder will use the frame rate encoded in the elementary stream.
534  * If none is available, the decoder will default to 30 fps.
535  */
536 void
537 gst_vaapi_decoder_set_frame_rate(
538     GstVaapiDecoder *decoder,
539     guint            num,
540     guint            den
541 )
542 {
543     g_return_if_fail(GST_VAAPI_IS_DECODER(decoder));
544
545     decoder->priv->fps_n = num;
546     decoder->priv->fps_d = den;
547 }
548
549 /**
550  * gst_vaapi_decoder_put_buffer_data:
551  * @decoder: a #GstVaapiDecoder
552  * @buf: pointer to buffer data
553  * @buf_size: size of buffer data in bytes
554  *
555  * Queues @buf_size bytes from the data @buf to the HW decoder. The
556  * caller is responsible for making sure @buf is live beyond this
557  * function. So, this function is mostly useful with static data
558  * buffers. gst_vaapi_decoder_put_buffer_data_copy() does the same but
559  * copies the data.
560  *
561  * Caller can notify an End-Of-Stream with @buf set to %NULL and
562  * @buf_size set to zero.
563  *
564  * Return value: %TRUE on success
565  */
566 gboolean
567 gst_vaapi_decoder_put_buffer_data(
568     GstVaapiDecoder *decoder,
569     const guchar    *buf,
570     guint            buf_size
571 )
572 {
573     g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), FALSE);
574
575     return push_buffer(decoder, create_buffer(buf, buf_size, FALSE));
576 }
577
578 /**
579  * gst_vaapi_decoder_put_buffer_data_copy:
580  * @decoder: a #GstVaapiDecoder
581  * @buf: pointer to buffer data
582  * @buf_size: size of buffer data in bytes
583  *
584  * Queues a copy of @buf to the HW decoder.
585  *
586  * Caller can notify an End-Of-Stream with @buf set to %NULL and
587  * @buf_size set to zero.
588  *
589  * Return value: %TRUE on success
590  */
591 gboolean
592 gst_vaapi_decoder_put_buffer_data_copy(
593     GstVaapiDecoder *decoder,
594     const guchar    *buf,
595     guint            buf_size
596 )
597 {
598     g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), FALSE);
599
600     return push_buffer(decoder, create_buffer(buf, buf_size, TRUE));
601 }
602
603 /**
604  * gst_vaapi_decoder_put_buffer:
605  * @decoder: a #GstVaapiDecoder
606  * @buf: a #GstBuffer
607  *
608  * Queues a #GstBuffer to the HW decoder. The decoder holds a
609  * reference to @buf.
610  *
611  * Caller can notify an End-Of-Stream with @buf set to %NULL.
612  *
613  * Return value: %TRUE on success
614  */
615 gboolean
616 gst_vaapi_decoder_put_buffer(GstVaapiDecoder *decoder, GstBuffer *buf)
617 {
618     g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), FALSE);
619
620     return push_buffer(decoder, buf ? gst_buffer_ref(buf) : NULL);
621 }
622
623 /**
624  * gst_vaapi_decoder_get_surface:
625  * @decoder: a #GstVaapiDecoder
626  * @pstatus: return location for the decoder status, or %NULL
627  *
628  * Waits for a decoded surface to arrive. This functions blocks until
629  * the @decoder has a surface ready for the caller. @pstatus is
630  * optional but it can help to know what went wrong during the
631  * decoding process.
632  *
633  * Return value: a #GstVaapiSurfaceProxy holding the decoded surface,
634  *   or %NULL if none is available (e.g. an error). Caller owns the
635  *   returned object. g_object_unref() after usage.
636  */
637 static GstVaapiSurfaceProxy *
638 _gst_vaapi_decoder_get_surface(
639     GstVaapiDecoder       *decoder,
640     GTimeVal              *end_time,
641     GstVaapiDecoderStatus *pstatus
642 )
643 {
644     GstVaapiDecoderStatus status;
645     GstVaapiSurfaceProxy *proxy;
646     DecodedSurface *ds;
647
648     ds = pop_surface(decoder, end_time);
649     if (ds) {
650         proxy  = ds->proxy;
651         status = ds->status;
652         destroy_surface(ds);
653     }
654     else {
655         proxy  = NULL;
656         status = GST_VAAPI_DECODER_STATUS_TIMEOUT;
657     }
658
659     if (pstatus)
660         *pstatus = status;
661     return proxy;
662 }
663
664 GstVaapiSurfaceProxy *
665 gst_vaapi_decoder_get_surface(
666     GstVaapiDecoder       *decoder,
667     GstVaapiDecoderStatus *pstatus
668 )
669 {
670     g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), NULL);
671
672     return _gst_vaapi_decoder_get_surface(decoder, NULL, pstatus);
673 }
674
675 /**
676  * gst_vaapi_decoder_timed_get_surface:
677  * @decoder: a #GstVaapiDecoder
678  * @timeout: the number of microseconds to wait for the decoded surface
679  * @pstatus: return location for the decoder status, or %NULL
680  *
681  * Waits for a decoded surface to arrive. This function blocks for at
682  * least @timeout microseconds. @pstatus is optional but it can help
683  * to know what went wrong during the decoding process.
684  *
685  * Return value: a #GstVaapiSurfaceProxy holding the decoded surface,
686  *   or %NULL if none is available (e.g. an error). Caller owns the
687  *   returned object. g_object_unref() after usage.
688  */
689 GstVaapiSurfaceProxy *
690 gst_vaapi_decoder_timed_get_surface(
691     GstVaapiDecoder       *decoder,
692     guint32                timeout,
693     GstVaapiDecoderStatus *pstatus
694 )
695 {
696     GTimeVal end_time;
697
698     g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), NULL);
699
700     g_get_current_time(&end_time);
701     g_time_val_add(&end_time, timeout);
702
703     return _gst_vaapi_decoder_get_surface(decoder, &end_time, pstatus);
704 }
705
706 gboolean
707 gst_vaapi_decoder_ensure_context(
708     GstVaapiDecoder    *decoder,
709     GstVaapiProfile     profile,
710     GstVaapiEntrypoint  entrypoint,
711     guint               width,
712     guint               height
713 )
714 {
715     GstVaapiDecoderPrivate * const priv = decoder->priv;
716
717     if (priv->context)
718         return gst_vaapi_context_reset(priv->context,
719                                        profile, entrypoint, width, height);
720
721     priv->context = gst_vaapi_context_new(
722         priv->display,
723         profile,
724         entrypoint,
725         width,
726         height
727     );
728     return priv->context != NULL;
729 }
730
731 gboolean
732 gst_vaapi_decoder_push_surface(
733     GstVaapiDecoder *decoder,
734     GstVaapiSurface *surface
735 )
736 {
737     return push_surface(decoder, surface);
738 }