vaapidecoder, vaapidecode: signal the interlacing property in caps
[vaapi:sree-gstreamer-vaapi.git] / gst-libs / gst / vaapi / gstvaapidecoder.c
1 /*
2  *  gstvaapidecoder.c - VA decoder abstraction
3  *
4  *  Copyright (C) 2010-2011 Splitted-Desktop Systems
5  *  Copyright (C) 2011-2012 Intel Corporation
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Lesser General Public License
9  *  as published by the Free Software Foundation; either version 2.1
10  *  of the License, or (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public
18  *  License along with this library; if not, write to the Free
19  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  *  Boston, MA 02110-1301 USA
21  */
22
23 /**
24  * SECTION:gstvaapidecoder
25  * @short_description: VA decoder abstraction
26  */
27
28 #include "sysdeps.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 enum {
41     PROP_0,
42
43     PROP_DISPLAY,
44     PROP_CAPS,
45
46     N_PROPERTIES
47 };
48
49 static GParamSpec *g_properties[N_PROPERTIES] = { NULL, };
50
51 static void
52 destroy_buffer(GstBuffer *buffer)
53 {
54     gst_buffer_unref(buffer);
55 }
56
57 static gboolean
58 push_buffer(GstVaapiDecoder *decoder, GstBuffer *buffer)
59 {
60     GstVaapiDecoderPrivate * const priv = decoder->priv;
61
62     if (!buffer) {
63         buffer = gst_buffer_new();
64         if (!buffer)
65             return FALSE;
66         GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_EOS);
67     }
68
69     GST_DEBUG("queue encoded data buffer %p (%d bytes)",
70               buffer, gst_buffer_get_size(buffer));
71
72     g_queue_push_tail(priv->buffers, buffer);
73     return TRUE;
74 }
75
76 static void
77 push_back_buffer(GstVaapiDecoder *decoder, GstBuffer *buffer)
78 {
79     GstVaapiDecoderPrivate * const priv = decoder->priv;
80
81     GST_DEBUG("requeue encoded data buffer %p (%d bytes)",
82               buffer, gst_buffer_get_size(buffer));
83
84     g_queue_push_head(priv->buffers, buffer);
85 }
86
87 static GstBuffer *
88 pop_buffer(GstVaapiDecoder *decoder)
89 {
90     GstVaapiDecoderPrivate * const priv = decoder->priv;
91     GstBuffer *buffer;
92
93     buffer = g_queue_pop_head(priv->buffers);
94     if (!buffer)
95         return NULL;
96
97     GST_DEBUG("dequeue buffer %p for decoding (%d bytes)",
98               buffer, gst_buffer_get_size(buffer));
99
100     return buffer;
101 }
102
103 static GstVaapiDecoderStatus
104 decode_step(GstVaapiDecoder *decoder)
105 {
106     GstVaapiDecoderStatus status;
107     GstBuffer *buffer;
108
109     /* Decoding will fail if there is no surface left */
110     status = gst_vaapi_decoder_check_status(decoder);
111     if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
112         return status;
113
114     do {
115         buffer = pop_buffer(decoder);
116         if (!buffer)
117             return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
118
119         /*status = GST_VAAPI_DECODER_GET_CLASS(decoder)->decode(decoder, buffer);*/
120         GST_DEBUG("decode frame (status = %d)", status);
121         if (status != GST_VAAPI_DECODER_STATUS_SUCCESS && GST_BUFFER_IS_EOS(buffer))
122             status = GST_VAAPI_DECODER_STATUS_END_OF_STREAM;
123         gst_buffer_unref(buffer);
124     } while (status == GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA);
125     return status;
126 }
127
128 static inline void
129 push_surface(GstVaapiDecoder *decoder, GstVaapiSurfaceProxy *proxy)
130 {
131     GstVaapiDecoderPrivate * const priv = decoder->priv;
132     GstClockTime duration;
133
134     GST_DEBUG("queue decoded surface %" GST_VAAPI_ID_FORMAT,
135               GST_VAAPI_ID_ARGS(gst_vaapi_surface_proxy_get_surface_id(proxy)));
136
137     if (priv->fps_n && priv->fps_d) {
138         /* Actual field duration is computed in vaapipostproc */
139         duration = gst_util_uint64_scale(GST_SECOND, priv->fps_d, priv->fps_n);
140         gst_vaapi_surface_proxy_set_duration(proxy, duration);
141     }
142     g_queue_push_tail(priv->surfaces, proxy);
143 }
144
145 static inline GstVaapiSurfaceProxy *
146 pop_surface(GstVaapiDecoder *decoder)
147 {
148     GstVaapiDecoderPrivate * const priv = decoder->priv;
149
150     return g_queue_pop_head(priv->surfaces);
151 }
152
153 static inline void
154 set_codec_data(GstVaapiDecoder *decoder, GstBuffer *codec_data)
155 {
156     GstVaapiDecoderPrivate * const priv = decoder->priv;
157
158     if (priv->codec_data) {
159         gst_buffer_unref(priv->codec_data);
160         priv->codec_data = NULL;
161     }
162
163     if (codec_data)
164         priv->codec_data = gst_buffer_ref(codec_data);
165 }
166
167 static void
168 set_caps(GstVaapiDecoder *decoder, GstCaps *caps)
169 {
170     GstVaapiDecoderPrivate * const priv = decoder->priv;
171     GstStructure * const structure = gst_caps_get_structure(caps, 0);
172     GstVaapiProfile profile;
173     const GValue *v_codec_data;
174     gint v1, v2;
175     gboolean b;
176     const gchar *interlaced_mode;
177
178     profile = gst_vaapi_profile_from_caps(caps);
179     if (!profile)
180         return;
181
182     priv->caps = gst_caps_copy(caps);
183
184     priv->codec = gst_vaapi_profile_get_codec(profile);
185     if (!priv->codec)
186         return;
187
188     if (gst_structure_get_int(structure, "width", &v1))
189         priv->width = v1;
190     if (gst_structure_get_int(structure, "height", &v2))
191         priv->height = v2;
192
193     if (gst_structure_get_fraction(structure, "framerate", &v1, &v2)) {
194         priv->fps_n = v1;
195         priv->fps_d = v2;
196     }
197
198     if (gst_structure_get_fraction(structure, "pixel-aspect-ratio", &v1, &v2)) {
199         priv->par_n = v1;
200         priv->par_d = v2;
201     }
202
203     interlaced_mode = gst_structure_get_string(structure, "interlace-mode");
204     if (interlaced_mode && g_strcmp0 (interlaced_mode, "progressive"))
205         priv->is_interlaced = TRUE;
206     
207     v_codec_data = gst_structure_get_value(structure, "codec_data");
208     if (v_codec_data)
209         set_codec_data(decoder, gst_value_get_buffer(v_codec_data));
210 }
211
212 static void
213 clear_queue(GQueue *q, GDestroyNotify destroy)
214 {
215     while (!g_queue_is_empty(q))
216         destroy(g_queue_pop_head(q));
217 }
218
219 static void
220 gst_vaapi_decoder_finalize(GObject *object)
221 {
222     GstVaapiDecoder * const        decoder = GST_VAAPI_DECODER(object);
223     GstVaapiDecoderPrivate * const priv    = decoder->priv;
224
225     set_codec_data(decoder, NULL);
226
227     if (priv->caps) {
228         gst_caps_unref(priv->caps);
229         priv->caps = NULL;
230     }
231
232     if (priv->context) {
233         g_object_unref(priv->context);
234         priv->context = NULL;
235         priv->va_context = VA_INVALID_ID;
236     }
237  
238     if (priv->buffers) {
239         clear_queue(priv->buffers, (GDestroyNotify)destroy_buffer);
240         g_queue_free(priv->buffers);
241         priv->buffers = NULL;
242     }
243
244     if (priv->surfaces) {
245         clear_queue(priv->surfaces, (GDestroyNotify)g_object_unref);
246         g_queue_free(priv->surfaces);
247         priv->surfaces = NULL;
248     }
249
250     if (priv->display) {
251         g_object_unref(priv->display);
252         priv->display = NULL;
253         priv->va_display = NULL;
254     }
255
256     G_OBJECT_CLASS(gst_vaapi_decoder_parent_class)->finalize(object);
257 }
258
259 static void
260 gst_vaapi_decoder_set_property(
261     GObject      *object,
262     guint         prop_id,
263     const GValue *value,
264     GParamSpec   *pspec
265 )
266 {
267     GstVaapiDecoder * const        decoder = GST_VAAPI_DECODER(object);
268     GstVaapiDecoderPrivate * const priv    = decoder->priv;
269
270     switch (prop_id) {
271     case PROP_DISPLAY:
272         priv->display = g_object_ref(g_value_get_object(value));
273         if (priv->display)
274             priv->va_display = gst_vaapi_display_get_display(priv->display);
275         else
276             priv->va_display = NULL;
277         break;
278     case PROP_CAPS:
279         set_caps(decoder, g_value_get_pointer(value));
280         break;
281     default:
282         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
283         break;
284     }
285 }
286
287 static void
288 gst_vaapi_decoder_get_property(
289     GObject    *object,
290     guint       prop_id,
291     GValue     *value,
292     GParamSpec *pspec
293 )
294 {
295     GstVaapiDecoderPrivate * const priv = GST_VAAPI_DECODER(object)->priv;
296
297     switch (prop_id) {
298     case PROP_DISPLAY:
299         g_value_set_object(value, priv->display);
300         break;
301     case PROP_CAPS:
302         gst_value_set_caps(value, priv->caps);
303         break;
304     default:
305         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
306         break;
307     }
308 }
309
310 static void
311 gst_vaapi_decoder_class_init(GstVaapiDecoderClass *klass)
312 {
313     GObjectClass * const object_class = G_OBJECT_CLASS(klass);
314
315     g_type_class_add_private(klass, sizeof(GstVaapiDecoderPrivate));
316
317     object_class->finalize     = gst_vaapi_decoder_finalize;
318     object_class->set_property = gst_vaapi_decoder_set_property;
319     object_class->get_property = gst_vaapi_decoder_get_property;
320
321     /**
322      * GstVaapiDecoder:display:
323      *
324      * The #GstVaapiDisplay this decoder is bound to.
325      */
326     g_properties[PROP_DISPLAY] =
327          g_param_spec_object("display",
328                              "Display",
329                              "The GstVaapiDisplay this decoder is bound to",
330                              GST_VAAPI_TYPE_DISPLAY,
331                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY);
332
333     g_properties[PROP_CAPS] =
334          g_param_spec_pointer("caps",
335                               "Decoder caps",
336                               "The decoder caps",
337                               G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY);
338
339     g_object_class_install_properties(object_class, N_PROPERTIES, g_properties);
340 }
341
342 static void
343 gst_vaapi_decoder_init(GstVaapiDecoder *decoder)
344 {
345     GstVaapiDecoderPrivate *priv = GST_VAAPI_DECODER_GET_PRIVATE(decoder);
346
347     decoder->priv               = priv;
348     priv->display               = NULL;
349     priv->va_display            = NULL;
350     priv->context               = NULL;
351     priv->va_context            = VA_INVALID_ID;
352     priv->caps                  = NULL;
353     priv->codec                 = 0;
354     priv->codec_data            = NULL;
355     priv->pool                  = NULL;
356     priv->width                 = 0;
357     priv->height                = 0;
358     priv->fps_n                 = 0;
359     priv->fps_d                 = 0;
360     priv->par_n                 = 0;
361     priv->par_d                 = 0;
362     priv->buffers               = g_queue_new();
363     priv->surfaces              = g_queue_new();
364     priv->surface_buffers       = g_queue_new();
365     priv->is_interlaced         = FALSE;
366 }
367
368 /**
369  * gst_vaapi_decoder_get_codec:
370  * @decoder: a #GstVaapiDecoder
371  *
372  * Retrieves the @decoder codec type.
373  *
374  * Return value: the #GstVaapiCodec type for @decoder
375  */
376 GstVaapiCodec
377 gst_vaapi_decoder_get_codec(GstVaapiDecoder *decoder)
378 {
379     g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), (GstVaapiCodec)0);
380
381     return decoder->priv->codec;
382 }
383
384 /**
385  * gst_vaapi_decoder_get_caps:
386  * @decoder: a #GstVaapiDecoder
387  *
388  * Retrieves the @decoder caps. The deocder owns the returned caps, so
389  * use gst_caps_ref() whenever necessary.
390  *
391  * Return value: the @decoder caps
392  */
393 GstCaps *
394 gst_vaapi_decoder_get_caps(GstVaapiDecoder *decoder)
395 {
396     return decoder->priv->caps;
397 }
398
399 /**
400  * gst_vaapi_decoder_put_buffer:
401  * @decoder: a #GstVaapiDecoder
402  * @buf: a #GstBuffer
403  *
404  * Queues a #GstBuffer to the HW decoder. The decoder holds a
405  * reference to @buf.
406  *
407  * Caller can notify an End-Of-Stream with @buf set to %NULL.
408  *
409  * Return value: %TRUE on success
410  */
411 gboolean
412 gst_vaapi_decoder_put_buffer(GstVaapiDecoder *decoder, GstBuffer *buf)
413 {
414     g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), FALSE);
415
416     return push_buffer(decoder, buf ? gst_buffer_ref(buf) : NULL);
417 }
418
419 /**
420  * gst_vaapi_decoder_get_surface_proxy:
421  * @decoder: a #GstVaapiDecoder
422  *
423  * Return value: a #GstVaapiSurfaceProxy holding the decoded surface,
424  *   or %NULL if none is available (e.g. an error). Caller owns the
425  *   returned object. g_object_unref() after usage.
426 */
427 GstVaapiSurfaceProxy *
428 gst_vaapi_decoder_get_surface_proxy(GstVaapiDecoder *decoder)
429 {
430   return pop_surface(decoder);
431 }
432
433 /**
434  * gst_vaapi_decoder_get_surface:
435  * @decoder: a #GstVaapiDecoder
436  * @pstatus: return location for the decoder status, or %NULL
437  *
438  * Flushes encoded buffers to the decoder and returns a decoded
439  * surface, if any.
440  *
441  * Return value: a #GstVaapiSurfaceProxy holding the decoded surface,
442  *   or %NULL if none is available (e.g. an error). Caller owns the
443  *   returned object. g_object_unref() after usage.
444  */
445 GstVaapiSurfaceProxy *
446 gst_vaapi_decoder_get_surface(
447     GstVaapiDecoder       *decoder,
448     GstVaapiDecoderStatus *pstatus
449 )
450 {
451     GstVaapiSurfaceProxy *proxy;
452     GstVaapiDecoderStatus status;
453
454     if (pstatus)
455         *pstatus = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
456
457     g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), NULL);
458
459     proxy = pop_surface(decoder);
460     if (!proxy) {
461         do {
462             status = decode_step(decoder);
463         } while (status == GST_VAAPI_DECODER_STATUS_SUCCESS);
464         proxy = pop_surface(decoder);
465     }
466
467     if (proxy)
468         status = GST_VAAPI_DECODER_STATUS_SUCCESS;
469
470     if (pstatus)
471         *pstatus = status;
472     return proxy;
473 }
474 static inline GstBuffer *
475 pop_surface_buffer(GstVaapiDecoder *decoder)
476 {
477     GstVaapiDecoderPrivate * const priv = decoder->priv;
478
479     return g_queue_pop_head(priv->surface_buffers);
480 }
481
482 static inline void
483 push_surface_buffer (GstVaapiDecoder *decoder, GstBuffer *buffer)
484 {
485     GstVaapiDecoderPrivate * const priv = decoder->priv;
486
487     g_queue_push_tail(priv->surface_buffers, buffer);
488 }
489
490 /**
491  * gst_vaapi_decoder_start:
492  * @decoder: a #GstVaapiDecoder
493  * 
494  * Called when the element start processing
495  */
496 gboolean
497 gst_vaapi_decoder_start(GstVaapiDecoder *decoder)
498 {
499      GstVaapiDecoderClass *dec_class;
500      if (decoder) 
501         dec_class = GST_VAAPI_DECODER_GET_CLASS(decoder);
502      if (decoder && dec_class->start)
503          return  dec_class->start(decoder);
504      else 
505         GST_DEBUG("start() virtual method is not implemented or the decoder is not yet started");
506
507     return TRUE;
508 }
509    
510 /**
511  * gst_vaapi_decoder_parse:
512  * @decoder: a #GstVaapiDecoder
513  * @adapter: a #GstAdapter which has encoded data to parse (owned by GstVideoDecoder)
514  * @toadd  : size of data to be added to GstVideoCodecFrame
515  *
516  * Parse the data from adapter.
517  * If the function returns GST_VAAPI_DECODER_STATUS_SUCCESS with toadd==0,
518  * then it is the indication for vaapidecode to call finish_frame()
519  *
520  * Return value: status of parsing as a #GstVaapiDecoderStatus
521  */
522 GstVaapiDecoderStatus
523 gst_vaapi_decoder_parse(
524     GstVaapiDecoder *decoder, 
525     GstAdapter *adapter, 
526     guint *toadd, 
527     gboolean *have_frame)
528 {
529     GstVaapiDecoderStatus status;
530     guint tries = 0;
531 /*Fixme*/
532     for (tries=0; tries<100; tries++) {
533         status = gst_vaapi_decoder_check_status(decoder);
534         
535         if (status == GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE) 
536         {
537             GST_DEBUG ("Waiting to get the free surface, 10ms in each try");
538             g_usleep(10000);
539         }
540         else
541             break;
542         
543     }
544
545     if (tries==100)
546         goto error_decode_timeout;
547     
548     status = GST_VAAPI_DECODER_GET_CLASS(decoder)->parse(decoder, adapter, toadd, have_frame);
549     GST_DEBUG("decode frame (status = %d)", status);
550  
551     return status; 
552
553 error_decode_timeout:
554     {
555         GST_DEBUG("decode timeout. Decoder required a VA surface but none "
556                   "got available within one second");
557         return GST_FLOW_EOS;
558     }
559 }
560
561 /**
562  * gst_vaapi_decoder_decide_allocation
563  * @decoder: a #GstVaapiDecoder
564  * @Query: query contains the result of downstream allocation query 
565  */
566 gboolean
567 gst_vaapi_decoder_decide_allocation(
568     GstVaapiDecoder *decoder,
569     GstQuery *query
570 )
571 {  
572     GstBufferPool *pool = NULL, *old_pool = NULL;
573     GstAllocator  *allocator = NULL;
574     GstCaps *pool_caps, *new_caps;
575     GstStructure *config, *structure;
576     guint size = 0, min_buffers, max_buffers;
577     gboolean result;
578     guint num_pools;
579     guint i;
580     static GstAllocationParams params = { 0, 15, 0, 0, };
581
582     GstVaapiDecoderPrivate * const priv = decoder->priv;
583
584     /* Fixme: Add a namespace for GST_VAAPI_SURFACE_META, so that any element other than vaapisink 
585               should not be allowed to add this option */
586
587     num_pools = gst_query_get_n_allocation_pools (query);
588     GST_DEBUG("Query has %d pools", num_pools);
589     
590     for (i=0; i<num_pools; i++){
591         gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min_buffers, &max_buffers);
592
593         config = gst_buffer_pool_get_config(pool);
594         /*query might have many pools.If vaapisink is the renderer, then query should have a pool with VAAPI_SURFACE_META option*/
595         if (gst_buffer_pool_config_has_option (config, GST_BUFFER_POOL_OPTION_VAAPI_SURFACE_META)) {
596
597             GST_DEBUG_OBJECT(decoder, "vaapisink is the renderer, use the pool supplied by vaapisink");
598
599             gst_buffer_pool_config_get_params (config, &pool_caps, &size, &min_buffers, &max_buffers);
600             break;
601         } else
602             pool = NULL;
603     }
604
605     if(!pool) { 
606         new_caps = gst_caps_new_simple(
607             "video/x-raw",
608             "format", G_TYPE_STRING, "NV12",
609             "type", G_TYPE_STRING, "vaapi",
610             "width",  G_TYPE_INT, priv->width,
611             "height", G_TYPE_INT, priv->height,
612             NULL
613         );
614         if (!new_caps)
615             goto failed_caps;
616
617         pool = gst_vaapi_surface_pool_new(
618             priv->display,
619             new_caps
620         );
621         
622         if (!pool)
623             goto failed_pool;
624         
625         if(config) 
626             gst_buffer_pool_config_get_params(config, &pool_caps, &size, NULL, NULL);
627         
628         min_buffers = 8;
629         max_buffers = 0;
630
631         structure = gst_buffer_pool_get_config (pool);
632         gst_buffer_pool_config_set_params (structure, new_caps, size, min_buffers, max_buffers);
633         allocator = gst_allocator_find(GST_VAAPI_SURFACE_ALLOCATOR_NAME);
634         gst_buffer_pool_config_set_allocator (structure, allocator, &params);
635     
636         if (!gst_buffer_pool_set_config (pool, structure))
637             goto failed_config;
638
639     
640         gst_query_add_allocation_pool (query, (GstBufferPool *)pool, size, min_buffers, max_buffers);
641
642     } 
643
644     if (priv->pool) {
645         old_pool   = priv->pool;
646         priv->pool = pool;
647         if (old_pool)
648             gst_object_unref (old_pool);
649     }
650
651     priv->pool = pool;
652
653     result = GST_VAAPI_DECODER_GET_CLASS(decoder)->decide_allocation(decoder, pool);
654
655     GST_DEBUG("decide_allocation status: %d ",result);
656     return result;
657
658 failed_caps:
659     {
660         GST_ERROR_OBJECT(pool, "failed to create the caps for surface pool");
661         return FALSE;
662     }  
663 failed_pool:
664     {
665         GST_ERROR_OBJECT(pool, "failed to create the surface pool from decoder");
666         return FALSE;
667     }
668 failed_config:
669     {
670         GST_ERROR_OBJECT(pool, "failed to set the config in pool");
671         return FALSE;
672     }
673 }
674
675 /**
676  * gst_vaapi_decoder_get_surface2:
677  * @decoder: a #GstVaapiDecoder
678  * @frame: a #GstVideoCodecFrame to decode
679  * @pstatus: return location for the decoder status, or %NULL
680  *
681  * Flushes encoded buffers to the decoder and returns a decoded
682  * surface, if any.
683  *
684  * Return value: a #GstVaapiSurfaceProxy holding the decoded surface,
685  *   or %NULL if none is available (e.g. an error). Caller owns the
686  *   returned object. g_object_unref() after usage.
687  */
688 GstVaapiSurfaceProxy *
689 gst_vaapi_decoder_get_surface2(
690     GstVaapiDecoder       *decoder,
691     GstVideoCodecFrame    *frame,
692     GstVaapiDecoderStatus *pstatus
693
694 {
695     GstVaapiSurfaceProxy *proxy = NULL;
696     GstVaapiDecoderStatus status;
697
698     if (pstatus)
699         *pstatus = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
700
701     g_return_val_if_fail(GST_VAAPI_IS_DECODER(decoder), NULL);
702
703     if (!frame)
704         return NULL;
705
706     status = GST_VAAPI_DECODER_GET_CLASS(decoder)->decode(decoder, frame);
707     GST_DEBUG("decode frame (status = %d)", status);
708     
709     proxy = pop_surface(decoder);
710
711     if (proxy)
712         status = GST_VAAPI_DECODER_STATUS_SUCCESS;
713     if (pstatus)
714         *pstatus = status;
715
716     return proxy;
717 }
718 /** gst_vaapi_decoder_reset
719  * @decoder: a $GstVaapiDecoder
720  *
721  * Allows to perform post-seek semantics reset (eg: clear the buffers queued)
722  */
723 gboolean
724 gst_vaapi_decoder_reset(GstVaapiDecoder * decoder)
725 {
726     gboolean res;
727     
728     res = GST_VAAPI_DECODER_GET_CLASS(decoder)->reset(decoder);
729    
730     return res; 
731 }
732
733 /**
734  * gst_vaapi_decoder_start:
735  * @decoder: a #GstVaapiDecoder
736  * 
737  * Called when the element start processing
738  */
739 gboolean
740 gst_vaapi_decoder_stop(GstVaapiDecoder *decoder)
741 {
742      GstVaapiDecoderClass *dec_class;
743
744      if(decoder)
745          dec_class = GST_VAAPI_DECODER_GET_CLASS(decoder);
746      if (decoder && dec_class->stop)
747          return  dec_class->stop(decoder);
748      else 
749         GST_DEBUG("stop() virtual method is not implemented");
750      
751      return TRUE;
752 }
753
754 void
755 gst_vaapi_decoder_set_picture_size(
756     GstVaapiDecoder    *decoder,
757     guint               width,
758     guint               height
759 )
760 {
761     GstVaapiDecoderPrivate * const priv = decoder->priv;
762     gboolean size_changed = FALSE;
763
764     if (priv->width != width) {
765         GST_DEBUG("picture width changed to %d", width);
766         priv->width = width;
767         gst_caps_set_simple(priv->caps, "width", G_TYPE_INT, width, NULL);
768         size_changed = TRUE;
769     }
770
771     if (priv->height != height) {
772         GST_DEBUG("picture height changed to %d", height);
773         priv->height = height;
774         gst_caps_set_simple(priv->caps, "height", G_TYPE_INT, height, NULL);
775         size_changed = TRUE;
776     }
777
778     if (size_changed)
779         g_object_notify_by_pspec(G_OBJECT(decoder), g_properties[PROP_CAPS]);
780 }
781
782 void
783 gst_vaapi_decoder_set_framerate(
784     GstVaapiDecoder    *decoder,
785     guint               fps_n,
786     guint               fps_d
787 )
788 {
789     GstVaapiDecoderPrivate * const priv = decoder->priv;
790
791     if (!fps_n || !fps_d)
792         return;
793
794     if (priv->fps_n != fps_n || priv->fps_d != fps_d) {
795         GST_DEBUG("framerate changed to %u/%u", fps_n, fps_d);
796         priv->fps_n = fps_n;
797         priv->fps_d = fps_d;
798         gst_caps_set_simple(
799             priv->caps,
800             "framerate", GST_TYPE_FRACTION, fps_n, fps_d,
801             NULL
802         );
803         g_object_notify_by_pspec(G_OBJECT(decoder), g_properties[PROP_CAPS]);
804     }
805 }
806
807 void
808 gst_vaapi_decoder_set_pixel_aspect_ratio(
809     GstVaapiDecoder    *decoder,
810     guint               par_n,
811     guint               par_d
812 )
813 {
814     GstVaapiDecoderPrivate * const priv = decoder->priv;
815
816     if (!par_n || !par_d)
817         return;
818
819     if (priv->par_n != par_n || priv->par_d != par_d) {
820         GST_DEBUG("pixel-aspect-ratio changed to %u/%u", par_n, par_d);
821         priv->par_n = par_n;
822         priv->par_d = par_d;
823         gst_caps_set_simple(
824             priv->caps,
825             "pixel-aspect-ratio", GST_TYPE_FRACTION, par_n, par_d,
826             NULL
827         );
828         g_object_notify_by_pspec(G_OBJECT(decoder), g_properties[PROP_CAPS]);
829     }
830 }
831
832 void
833 gst_vaapi_decoder_set_interlaced(GstVaapiDecoder *decoder, gboolean interlaced)
834 {
835     GstVaapiDecoderPrivate * const priv = decoder->priv;
836
837     if (priv->is_interlaced != interlaced) {
838         GST_DEBUG("interlaced changed to %s", interlaced ? "true" : "false");
839         priv->is_interlaced = interlaced;
840         
841         gst_caps_set_simple(
842             priv->caps,
843             "interlace-mode", G_TYPE_STRING, (interlaced ? "mixed" : "progressive"),
844             NULL
845         );
846         g_object_notify_by_pspec(G_OBJECT(decoder), g_properties[PROP_CAPS]);
847     }
848 }
849
850 void
851 gst_vaapi_decoder_emit_caps_change(
852     GstVaapiDecoder   *decoder,
853     guint width,
854     guint height
855 )
856 {
857     gst_vaapi_decoder_set_picture_size(decoder, width, height);
858     g_object_notify_by_pspec(G_OBJECT(decoder), g_properties[PROP_CAPS]);
859 }
860
861 gboolean
862 gst_vaapi_decoder_ensure_context(
863     GstVaapiDecoder     *decoder,
864     GstVaapiContextInfo *cip
865 )
866 {
867     GstVaapiDecoderPrivate * const priv = decoder->priv;
868
869     gst_vaapi_decoder_set_picture_size(decoder, cip->width, cip->height);
870                 
871     if (priv->context) {
872         if (!gst_vaapi_context_reset_full(priv->context, cip))
873             return FALSE;
874     }
875     else {
876         priv->context = gst_vaapi_context_new_full(priv->display, cip);
877         if (!priv->context)
878             return FALSE;
879     }
880     priv->va_context = gst_vaapi_context_get_id(priv->context);
881     return TRUE;
882 }
883
884 gboolean
885 gst_vaapi_decoder_push_buffer_sub(
886     GstVaapiDecoder *decoder,
887     GstBuffer       *buffer,
888     guint            offset,
889     guint            size
890 )
891 {
892     GstBuffer *subbuffer;
893
894     /*Fixme*/
895     return FALSE;
896     /*subbuffer = gst_buffer_create_sub(buffer, offset, size);
897     if (!subbuffer)
898         return FALSE;
899
900     push_back_buffer(decoder, subbuffer);*/
901     return TRUE;
902 }
903
904 void
905 gst_vaapi_decoder_push_surface_proxy(
906     GstVaapiDecoder      *decoder,
907     GstVaapiSurfaceProxy *proxy
908 )
909 {
910     push_surface(decoder, proxy);
911 }
912
913 GstVaapiDecoderStatus
914 gst_vaapi_decoder_check_status(GstVaapiDecoder *decoder)
915 {
916     GstVaapiDecoderPrivate * const priv = decoder->priv;
917     GstVaapiSurfacePool *pool;
918     GstBuffer *buffer;
919     GstBufferPoolAcquireParams params = {0, };
920     GstFlowReturn ret;
921     GstVaapiDecoderStatus status = GST_VAAPI_DECODER_STATUS_SUCCESS;
922 /*Fixme: This might be  bit expensive operation ..? */
923 #if 0    
924     if (priv->context) {
925        pool = gst_vaapi_context_get_surface_pool(priv->context);
926
927        if (pool && !GST_BUFFER_POOL_IS_FLUSHING((GST_BUFFER_POOL(pool)))) {
928            params.flags = GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT;
929            ret = gst_buffer_pool_acquire_buffer((GstBufferPool *)pool, &buffer,&params);
930            
931            if (ret != GST_FLOW_OK) 
932                status = GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE;
933            else if (ret == GST_FLOW_OK) {
934                status = GST_VAAPI_DECODER_STATUS_SUCCESS;
935                gst_buffer_pool_release_buffer((GstBufferPool *)pool, buffer);
936            }
937        }
938        if(pool)
939            gst_object_unref(GST_OBJECT(pool));  
940     }
941 #endif
942     return status;
943 }