context: clean-ups. Strip down APIs.
[vaapi: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  *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
6  *  Copyright (C) 2011-2014 Intel Corporation
7  *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
8  *
9  *  This library is free software; you can redistribute it and/or
10  *  modify it under the terms of the GNU Lesser General Public License
11  *  as published by the Free Software Foundation; either version 2.1
12  *  of the License, or (at your option) any later version.
13  *
14  *  This library is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  *  Lesser General Public License for more details.
18  *
19  *  You should have received a copy of the GNU Lesser General Public
20  *  License along with this library; if not, write to the Free
21  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  *  Boston, MA 02110-1301 USA
23  */
24
25 /**
26  * SECTION:gstvaapidecoder
27  * @short_description: VA decoder abstraction
28  */
29
30 #include "sysdeps.h"
31 #include "gstvaapicompat.h"
32 #include "gstvaapidecoder.h"
33 #include "gstvaapidecoder_priv.h"
34 #include "gstvaapiparser_frame.h"
35 #include "gstvaapisurfaceproxy_priv.h"
36 #include "gstvaapiutils.h"
37
38 #define DEBUG 1
39 #include "gstvaapidebug.h"
40
41 static void
42 drop_frame(GstVaapiDecoder *decoder, GstVideoCodecFrame *frame);
43
44 static void
45 parser_state_finalize(GstVaapiParserState *ps)
46 {
47     if (ps->input_adapter) {
48         gst_adapter_clear(ps->input_adapter);
49         g_object_unref(ps->input_adapter);
50         ps->input_adapter = NULL;
51     }
52
53     if (ps->output_adapter) {
54         gst_adapter_clear(ps->output_adapter);
55         g_object_unref(ps->output_adapter);
56         ps->output_adapter = NULL;
57     }
58
59     if (ps->next_unit_pending) {
60         gst_vaapi_decoder_unit_clear(&ps->next_unit);
61         ps->next_unit_pending = FALSE;
62     }
63 }
64
65 static gboolean
66 parser_state_init(GstVaapiParserState *ps)
67 {
68     memset(ps, 0, sizeof(*ps));
69
70     ps->input_adapter = gst_adapter_new();
71     if (!ps->input_adapter)
72         return FALSE;
73
74     ps->output_adapter = gst_adapter_new();
75     if (!ps->output_adapter)
76         return FALSE;
77     return TRUE;
78 }
79
80 static void
81 parser_state_prepare(GstVaapiParserState *ps, GstAdapter *adapter)
82 {
83     /* XXX: check we really have a continuity from the previous call */
84     if (ps->current_adapter != adapter)
85         goto reset;
86     return;
87
88 reset:
89     ps->current_adapter = adapter;
90     ps->input_offset1 = -1;
91     ps->input_offset2 = -1;
92 }
93
94 static gboolean
95 push_buffer(GstVaapiDecoder *decoder, GstBuffer *buffer)
96 {
97     if (!buffer) {
98         buffer = gst_buffer_new();
99         if (!buffer)
100             return FALSE;
101         GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_EOS);
102     }
103
104     GST_DEBUG("queue encoded data buffer %p (%zu bytes)",
105               buffer, gst_buffer_get_size(buffer));
106
107     g_async_queue_push(decoder->buffers, buffer);
108     return TRUE;
109 }
110
111 static GstBuffer *
112 pop_buffer(GstVaapiDecoder *decoder)
113 {
114     GstBuffer *buffer;
115
116     buffer = g_async_queue_try_pop(decoder->buffers);
117     if (!buffer)
118         return NULL;
119
120     GST_DEBUG("dequeue buffer %p for decoding (%zu bytes)",
121               buffer, gst_buffer_get_size(buffer));
122
123     return buffer;
124 }
125
126 static GstVaapiDecoderStatus
127 do_parse(GstVaapiDecoder *decoder,
128     GstVideoCodecFrame *base_frame, GstAdapter *adapter, gboolean at_eos,
129     guint *got_unit_size_ptr, gboolean *got_frame_ptr)
130 {
131     GstVaapiParserState * const ps = &decoder->parser_state;
132     GstVaapiParserFrame *frame;
133     GstVaapiDecoderUnit *unit;
134     GstVaapiDecoderStatus status;
135
136     *got_unit_size_ptr = 0;
137     *got_frame_ptr = FALSE;
138
139     frame = gst_video_codec_frame_get_user_data(base_frame);
140     if (!frame) {
141         GstVideoCodecState * const codec_state = decoder->codec_state;
142         frame = gst_vaapi_parser_frame_new(codec_state->info.width,
143             codec_state->info.height);
144         if (!frame)
145             return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
146         gst_video_codec_frame_set_user_data(base_frame,
147             frame, (GDestroyNotify)gst_vaapi_mini_object_unref);
148     }
149
150     parser_state_prepare(ps, adapter);
151
152     unit = &ps->next_unit;
153     if (ps->next_unit_pending) {
154         ps->next_unit_pending = FALSE;
155         goto got_unit;
156     }
157     gst_vaapi_decoder_unit_init(unit);
158
159     ps->current_frame = base_frame;
160     status = GST_VAAPI_DECODER_GET_CLASS(decoder)->parse(decoder,
161         adapter, at_eos, unit);
162     if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
163         if (at_eos && frame->units->len > 0 &&
164             status == GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA) {
165             /* XXX: assume the frame is complete at <EOS> */
166             *got_frame_ptr = TRUE;
167             return GST_VAAPI_DECODER_STATUS_SUCCESS;
168         }
169         return status;
170     }
171
172     if (GST_VAAPI_DECODER_UNIT_IS_FRAME_START(unit) && frame->units->len > 0) {
173         ps->next_unit_pending = TRUE;
174         *got_frame_ptr = TRUE;
175         return GST_VAAPI_DECODER_STATUS_SUCCESS;
176     }
177
178 got_unit:
179     gst_vaapi_parser_frame_append_unit(frame, unit);
180     *got_unit_size_ptr = unit->size;
181     *got_frame_ptr = GST_VAAPI_DECODER_UNIT_IS_FRAME_END(unit);
182     return GST_VAAPI_DECODER_STATUS_SUCCESS;
183 }
184
185 static GstVaapiDecoderStatus
186 do_decode_units(GstVaapiDecoder *decoder, GArray *units)
187 {
188     GstVaapiDecoderClass * const klass = GST_VAAPI_DECODER_GET_CLASS(decoder);
189     GstVaapiDecoderStatus status;
190     guint i;
191
192     for (i = 0; i < units->len; i++) {
193         GstVaapiDecoderUnit * const unit =
194             &g_array_index(units, GstVaapiDecoderUnit, i);
195         if (GST_VAAPI_DECODER_UNIT_IS_SKIPPED(unit))
196             continue;
197         status = klass->decode(decoder, unit);
198         if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
199             return status;
200     }
201     return GST_VAAPI_DECODER_STATUS_SUCCESS;
202 }
203
204 static GstVaapiDecoderStatus
205 do_decode_1(GstVaapiDecoder *decoder, GstVaapiParserFrame *frame)
206 {
207     GstVaapiDecoderClass * const klass = GST_VAAPI_DECODER_GET_CLASS(decoder);
208     GstVaapiDecoderStatus status;
209
210     if (frame->pre_units->len > 0) {
211         status = do_decode_units(decoder, frame->pre_units);
212         if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
213             return status;
214     }
215
216     if (frame->units->len > 0) {
217         if (klass->start_frame) {
218             GstVaapiDecoderUnit * const unit =
219                 &g_array_index(frame->units, GstVaapiDecoderUnit, 0);
220             status = klass->start_frame(decoder, unit);
221             if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
222                 return status;
223         }
224
225         status = do_decode_units(decoder, frame->units);
226         if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
227             return status;
228
229         if (klass->end_frame) {
230             status = klass->end_frame(decoder);
231             if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
232                 return status;
233         }
234     }
235
236     if (frame->post_units->len > 0) {
237         status = do_decode_units(decoder, frame->post_units);
238         if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
239             return status;
240     }
241
242     /* Drop frame if there is no slice data unit in there */
243     if (G_UNLIKELY(frame->units->len == 0))
244         return GST_VAAPI_DECODER_STATUS_DROP_FRAME;
245     return GST_VAAPI_DECODER_STATUS_SUCCESS;
246 }
247
248 static inline GstVaapiDecoderStatus
249 do_decode(GstVaapiDecoder *decoder, GstVideoCodecFrame *base_frame)
250 {
251     GstVaapiParserState * const ps = &decoder->parser_state;
252     GstVaapiParserFrame * const frame = base_frame->user_data;
253     GstVaapiDecoderStatus status;
254
255     ps->current_frame = base_frame;
256
257     gst_vaapi_parser_frame_ref(frame);
258     status = do_decode_1(decoder, frame);
259     gst_vaapi_parser_frame_unref(frame);
260
261     switch ((guint)status) {
262     case GST_VAAPI_DECODER_STATUS_DROP_FRAME:
263         drop_frame(decoder, base_frame);
264         status = GST_VAAPI_DECODER_STATUS_SUCCESS;
265         break;
266     }
267     return status;
268 }
269
270 static inline GstVaapiDecoderStatus
271 do_flush(GstVaapiDecoder *decoder)
272 {
273     GstVaapiDecoderClass * const klass = GST_VAAPI_DECODER_GET_CLASS(decoder);
274
275     if (klass->flush)
276         return klass->flush(decoder);
277     return GST_VAAPI_DECODER_STATUS_SUCCESS;
278 }
279
280 static GstVaapiDecoderStatus
281 decode_step(GstVaapiDecoder *decoder)
282 {
283     GstVaapiParserState * const ps = &decoder->parser_state;
284     GstVaapiDecoderStatus status;
285     GstBuffer *buffer;
286     gboolean got_frame;
287     guint got_unit_size, input_size;
288
289     status = gst_vaapi_decoder_check_status(decoder);
290     if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
291         return status;
292
293     /* Fill adapter with all buffers we have in the queue */
294     for (;;) {
295         buffer = pop_buffer(decoder);
296         if (!buffer)
297             break;
298
299         ps->at_eos = GST_BUFFER_IS_EOS(buffer);
300         if (!ps->at_eos)
301             gst_adapter_push(ps->input_adapter, buffer);
302     }
303
304     /* Parse and decode all decode units */
305     input_size = gst_adapter_available(ps->input_adapter);
306     if (input_size == 0) {
307         if (ps->at_eos)
308             return GST_VAAPI_DECODER_STATUS_END_OF_STREAM;
309         return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
310     }
311
312     do {
313         if (!ps->current_frame) {
314             ps->current_frame = g_slice_new0(GstVideoCodecFrame);
315             if (!ps->current_frame)
316                 return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
317             ps->current_frame->ref_count = 1;
318             ps->current_frame->system_frame_number = ps->current_frame_number++;
319         }
320
321         status = do_parse(decoder, ps->current_frame, ps->input_adapter,
322             ps->at_eos, &got_unit_size, &got_frame);
323         GST_DEBUG("parse frame (status = %d)", status);
324         if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
325             if (status == GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA && ps->at_eos)
326                 status = GST_VAAPI_DECODER_STATUS_END_OF_STREAM;
327             break;
328         }
329
330         if (got_unit_size > 0) {
331             buffer = gst_adapter_take_buffer(ps->input_adapter, got_unit_size);
332             input_size -= got_unit_size;
333
334             if (gst_adapter_available(ps->output_adapter) == 0) {
335                 ps->current_frame->pts =
336                     gst_adapter_prev_timestamp(ps->input_adapter, NULL);
337             }
338             gst_adapter_push(ps->output_adapter, buffer);
339         }
340
341         if (got_frame) {
342             ps->current_frame->input_buffer = gst_adapter_take_buffer(
343                 ps->output_adapter,
344                 gst_adapter_available(ps->output_adapter));
345
346             status = do_decode(decoder, ps->current_frame);
347             GST_DEBUG("decode frame (status = %d)", status);
348
349             gst_video_codec_frame_unref(ps->current_frame);
350             ps->current_frame = NULL;
351             break;
352         }
353     } while (input_size > 0);
354     return status;
355 }
356
357 static void
358 drop_frame(GstVaapiDecoder *decoder, GstVideoCodecFrame *frame)
359 {
360     GST_DEBUG("drop frame %d", frame->system_frame_number);
361
362     /* no surface proxy */
363     gst_video_codec_frame_set_user_data(frame, NULL, NULL);
364
365     frame->pts = GST_CLOCK_TIME_NONE;
366     GST_VIDEO_CODEC_FRAME_FLAG_SET(frame,
367         GST_VIDEO_CODEC_FRAME_FLAG_DECODE_ONLY);
368
369     g_async_queue_push(decoder->frames, gst_video_codec_frame_ref(frame));
370 }
371
372 static inline void
373 push_frame(GstVaapiDecoder *decoder, GstVideoCodecFrame *frame)
374 {
375     GstVaapiSurfaceProxy * const proxy = frame->user_data;
376
377     GST_DEBUG("push frame %d (surface 0x%08x)", frame->system_frame_number,
378         GST_VAAPI_SURFACE_PROXY_SURFACE_ID(proxy));
379
380     g_async_queue_push(decoder->frames, gst_video_codec_frame_ref(frame));
381 }
382
383 static inline GstVideoCodecFrame *
384 pop_frame(GstVaapiDecoder *decoder, guint64 timeout)
385 {
386     GstVideoCodecFrame *frame;
387     GstVaapiSurfaceProxy *proxy;
388
389     if (G_LIKELY(timeout > 0))
390         frame = g_async_queue_timeout_pop(decoder->frames, timeout);
391     else
392         frame = g_async_queue_try_pop(decoder->frames);
393     if (!frame)
394         return NULL;
395
396     proxy = frame->user_data;
397     GST_DEBUG("pop frame %d (surface 0x%08x)", frame->system_frame_number,
398         proxy ? GST_VAAPI_SURFACE_PROXY_SURFACE_ID(proxy) : VA_INVALID_ID);
399
400     return frame;
401 }
402
403 static gboolean
404 set_caps(GstVaapiDecoder *decoder, const GstCaps *caps)
405 {
406     GstVideoCodecState * const codec_state = decoder->codec_state;
407     GstStructure * const structure = gst_caps_get_structure(caps, 0);
408     GstVaapiProfile profile;
409     const GValue *v_codec_data;
410
411     profile = gst_vaapi_profile_from_caps(caps);
412     if (!profile)
413         return FALSE;
414
415     decoder->codec = gst_vaapi_profile_get_codec(profile);
416     if (!decoder->codec)
417         return FALSE;
418
419     if (!gst_video_info_from_caps(&codec_state->info, caps))
420         return FALSE;
421
422     codec_state->caps = gst_caps_copy(caps);
423
424     v_codec_data = gst_structure_get_value(structure, "codec_data");
425     if (v_codec_data)
426         gst_buffer_replace(&codec_state->codec_data,
427             gst_value_get_buffer(v_codec_data));
428     return TRUE;
429 }
430
431 static inline GstCaps *
432 get_caps(GstVaapiDecoder *decoder)
433 {
434     return GST_VAAPI_DECODER_CODEC_STATE(decoder)->caps;
435 }
436
437 static void
438 notify_codec_state_changed(GstVaapiDecoder *decoder)
439 {
440     if (decoder->codec_state_changed_func)
441         decoder->codec_state_changed_func(decoder, decoder->codec_state,
442             decoder->codec_state_changed_data);
443 }
444
445 void
446 gst_vaapi_decoder_finalize(GstVaapiDecoder *decoder)
447 {
448     const GstVaapiDecoderClass * const klass =
449         GST_VAAPI_DECODER_GET_CLASS(decoder);
450
451     if (klass->destroy)
452         klass->destroy(decoder);
453
454     gst_video_codec_state_unref(decoder->codec_state);
455     decoder->codec_state = NULL;
456
457     parser_state_finalize(&decoder->parser_state);
458  
459     if (decoder->buffers) {
460         g_async_queue_unref(decoder->buffers);
461         decoder->buffers = NULL;
462     }
463
464     if (decoder->frames) {
465         g_async_queue_unref(decoder->frames);
466         decoder->frames = NULL;
467     }
468
469     gst_vaapi_object_replace(&decoder->context, NULL);
470     decoder->va_context = VA_INVALID_ID;
471
472     gst_vaapi_display_replace(&decoder->display, NULL);
473     decoder->va_display = NULL;
474 }
475
476 static gboolean
477 gst_vaapi_decoder_init(GstVaapiDecoder *decoder, GstVaapiDisplay *display,
478     GstCaps *caps)
479 {
480     const GstVaapiDecoderClass * const klass =
481         GST_VAAPI_DECODER_GET_CLASS(decoder);
482     GstVideoCodecState *codec_state;
483     guint sub_size;
484
485     parser_state_init(&decoder->parser_state);
486
487     codec_state = g_slice_new0(GstVideoCodecState);
488     codec_state->ref_count = 1;
489     gst_video_info_init(&codec_state->info);
490
491     decoder->user_data   = NULL;
492     decoder->display     = gst_vaapi_display_ref(display);
493     decoder->va_display  = GST_VAAPI_DISPLAY_VADISPLAY(display);
494     decoder->context     = NULL;
495     decoder->va_context  = VA_INVALID_ID;
496     decoder->codec       = 0;
497     decoder->codec_state = codec_state;
498     decoder->codec_state_changed_func = NULL;
499     decoder->codec_state_changed_data = NULL;
500
501     decoder->buffers = g_async_queue_new_full((GDestroyNotify)gst_buffer_unref);
502     decoder->frames  = g_async_queue_new_full((GDestroyNotify)
503         gst_video_codec_frame_unref);
504
505     if (!set_caps(decoder, caps))
506         return FALSE;
507
508     sub_size = GST_VAAPI_MINI_OBJECT_CLASS(klass)->size - sizeof(*decoder);
509     if (sub_size > 0)
510         memset(((guchar *)decoder) + sizeof(*decoder), 0, sub_size);
511
512     if (klass->create && !klass->create(decoder))
513         return FALSE;
514     return TRUE;
515 }
516
517 GstVaapiDecoder *
518 gst_vaapi_decoder_new(const GstVaapiDecoderClass *klass,
519     GstVaapiDisplay *display, GstCaps *caps)
520 {
521     GstVaapiDecoder *decoder;
522
523     g_return_val_if_fail(display != NULL, NULL);
524     g_return_val_if_fail(GST_IS_CAPS(caps), NULL);
525
526     decoder = (GstVaapiDecoder *)
527         gst_vaapi_mini_object_new(GST_VAAPI_MINI_OBJECT_CLASS(klass));
528     if (!decoder)
529         return NULL;
530
531     if (!gst_vaapi_decoder_init(decoder, display, caps))
532         goto error;
533     return decoder;
534
535 error:
536     gst_vaapi_decoder_unref(decoder);
537     return NULL;
538 }
539
540 /**
541  * gst_vaapi_decoder_ref:
542  * @decoder: a #GstVaapiDecoder
543  *
544  * Atomically increases the reference count of the given @decoder by one.
545  *
546  * Returns: The same @decoder argument
547  */
548 GstVaapiDecoder *
549 gst_vaapi_decoder_ref(GstVaapiDecoder *decoder)
550 {
551     return gst_vaapi_object_ref(decoder);
552 }
553
554 /**
555  * gst_vaapi_decoder_unref:
556  * @decoder: a #GstVaapiDecoder
557  *
558  * Atomically decreases the reference count of the @decoder by one. If
559  * the reference count reaches zero, the decoder will be free'd.
560  */
561 void
562 gst_vaapi_decoder_unref(GstVaapiDecoder *decoder)
563 {
564     gst_vaapi_object_unref(decoder);
565 }
566
567 /**
568  * gst_vaapi_decoder_replace:
569  * @old_decoder_ptr: a pointer to a #GstVaapiDecoder
570  * @new_decoder: a #GstVaapiDecoder
571  *
572  * Atomically replaces the decoder decoder held in @old_decoder_ptr
573  * with @new_decoder. This means that @old_decoder_ptr shall reference
574  * a valid decoder. However, @new_decoder can be NULL.
575  */
576 void
577 gst_vaapi_decoder_replace(GstVaapiDecoder **old_decoder_ptr,
578     GstVaapiDecoder *new_decoder)
579 {
580     gst_vaapi_object_replace(old_decoder_ptr, new_decoder);
581 }
582
583 /**
584  * gst_vaapi_decoder_get_user_data:
585  * @decoder: a #GstVaapiDecoder
586  *
587  * Retrieves the user-defined data associated with the @decoder, if any.
588  *
589  * Return value: the user-defined data associated with the @decoder
590  */
591 gpointer
592 gst_vaapi_decoder_get_user_data(GstVaapiDecoder *decoder)
593 {
594     g_return_val_if_fail(decoder != NULL, NULL);
595
596     return decoder->user_data;
597 }
598
599 /**
600  * gst_vaapi_decoder_set_user_data:
601  * @decoder: a #GstVaapiDecoder
602  * @user_data: the pointer to user-defined data
603  *
604  * Associates user-defined @user_data to the @decoder. Retrieve the
605  * attached value with gst_vaapi_decoder_get_user_data() function.
606  */
607 void
608 gst_vaapi_decoder_set_user_data(GstVaapiDecoder *decoder, gpointer user_data)
609 {
610     g_return_if_fail(decoder != NULL);
611
612     decoder->user_data = user_data;
613 }
614
615 /**
616  * gst_vaapi_decoder_get_codec:
617  * @decoder: a #GstVaapiDecoder
618  *
619  * Retrieves the @decoder codec type.
620  *
621  * Return value: the #GstVaapiCodec type for @decoder
622  */
623 GstVaapiCodec
624 gst_vaapi_decoder_get_codec(GstVaapiDecoder *decoder)
625 {
626     g_return_val_if_fail(decoder != NULL, (GstVaapiCodec)0);
627
628     return decoder->codec;
629 }
630
631 /**
632  * gst_vaapi_decoder_get_codec_state:
633  * @decoder: a #GstVaapiDecoder
634  *
635  * Retrieves the @decoder codec state. The decoder owns the returned
636  * #GstVideoCodecState structure, so use gst_video_codec_state_ref()
637  * whenever necessary.
638  *
639  * Return value: the #GstVideoCodecState object for @decoder
640  */
641 GstVideoCodecState *
642 gst_vaapi_decoder_get_codec_state(GstVaapiDecoder *decoder)
643 {
644     g_return_val_if_fail(decoder != NULL, NULL);
645
646     return GST_VAAPI_DECODER_CODEC_STATE(decoder);
647 }
648
649 /**
650  * gst_vaapi_decoder_set_codec_state_changed_func:
651  * @decoder: a #GstVaapiDecoder
652  * @func: the function to call when codec state changed
653  * @user_data: a pointer to user-defined data
654  *
655  * Sets @func as the function to call whenever the @decoder codec
656  * state changes.
657  */
658 void
659 gst_vaapi_decoder_set_codec_state_changed_func(GstVaapiDecoder *decoder,
660     GstVaapiDecoderStateChangedFunc func, gpointer user_data)
661 {
662     g_return_if_fail(decoder != NULL);
663
664     decoder->codec_state_changed_func = func;
665     decoder->codec_state_changed_data = user_data;
666 }
667
668 /**
669  * gst_vaapi_decoder_get_caps:
670  * @decoder: a #GstVaapiDecoder
671  *
672  * Retrieves the @decoder caps. The decoder owns the returned caps, so
673  * use gst_caps_ref() whenever necessary.
674  *
675  * Return value: the @decoder caps
676  */
677 GstCaps *
678 gst_vaapi_decoder_get_caps(GstVaapiDecoder *decoder)
679 {
680     return get_caps(decoder);
681 }
682
683 /**
684  * gst_vaapi_decoder_put_buffer:
685  * @decoder: a #GstVaapiDecoder
686  * @buf: a #GstBuffer
687  *
688  * Queues a #GstBuffer to the HW decoder. The decoder holds a
689  * reference to @buf.
690  *
691  * Caller can notify an End-Of-Stream with @buf set to %NULL. However,
692  * if an empty buffer is passed, i.e. a buffer with %NULL data pointer
693  * or size equals to zero, then the function ignores this buffer and
694  * returns %TRUE.
695  *
696  * Return value: %TRUE on success
697  */
698 gboolean
699 gst_vaapi_decoder_put_buffer(GstVaapiDecoder *decoder, GstBuffer *buf)
700 {
701     g_return_val_if_fail(decoder != NULL, FALSE);
702
703     if (buf) {
704         if (gst_buffer_get_size(buf) == 0)
705             return TRUE;
706         buf = gst_buffer_ref(buf);
707     }
708     return push_buffer(decoder, buf);
709 }
710
711 /**
712  * gst_vaapi_decoder_get_surface:
713  * @decoder: a #GstVaapiDecoder
714  * @out_proxy_ptr: the next decoded surface as a #GstVaapiSurfaceProxy
715  *
716  * Flushes encoded buffers to the decoder and returns a decoded
717  * surface, if any.
718  *
719  * On successful return, *@out_proxy_ptr contains the decoded surface
720  * as a #GstVaapiSurfaceProxy. The caller owns this object, so
721  * gst_vaapi_surface_proxy_unref() shall be called after usage.
722  *
723  * Return value: a #GstVaapiDecoderStatus
724  */
725 GstVaapiDecoderStatus
726 gst_vaapi_decoder_get_surface(GstVaapiDecoder *decoder,
727     GstVaapiSurfaceProxy **out_proxy_ptr)
728 {
729     GstVideoCodecFrame *frame;
730     GstVaapiDecoderStatus status;
731
732     g_return_val_if_fail(decoder != NULL,
733         GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
734     g_return_val_if_fail(out_proxy_ptr != NULL,
735         GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
736
737     do {
738         frame = pop_frame(decoder, 0);
739         while (frame) {
740             if (!GST_VIDEO_CODEC_FRAME_IS_DECODE_ONLY(frame)) {
741                 GstVaapiSurfaceProxy * const proxy = frame->user_data;
742                 proxy->timestamp = frame->pts;
743                 proxy->duration = frame->duration;
744                 *out_proxy_ptr = gst_vaapi_surface_proxy_ref(proxy);
745                 gst_video_codec_frame_unref(frame);
746                 return GST_VAAPI_DECODER_STATUS_SUCCESS;
747             }
748             gst_video_codec_frame_unref(frame);
749             frame = pop_frame(decoder, 0);
750         }
751         status = decode_step(decoder);
752     } while (status == GST_VAAPI_DECODER_STATUS_SUCCESS);
753
754     *out_proxy_ptr = NULL;
755     return status;
756 }
757
758 /**
759  * gst_vaapi_decoder_get_frame:
760  * @decoder: a #GstVaapiDecoder
761  * @out_frame_ptr: the next decoded frame as a #GstVideoCodecFrame
762  *
763  * On successful return, *@out_frame_ptr contains the next decoded
764  * frame available as a #GstVideoCodecFrame. The caller owns this
765  * object, so gst_video_codec_frame_unref() shall be called after
766  * usage. Otherwise, @GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA is
767  * returned if no decoded frame is available.
768  *
769  * The actual surface is available as a #GstVaapiSurfaceProxy attached
770  * to the user-data anchor of the output frame. Ownership of the proxy
771  * is transferred to the frame.
772  *
773  * This is equivalent to gst_vaapi_decoder_get_frame_with_timeout()
774  * with a timeout value of zero.
775  *
776  * Return value: a #GstVaapiDecoderStatus
777  */
778 GstVaapiDecoderStatus
779 gst_vaapi_decoder_get_frame(GstVaapiDecoder *decoder,
780     GstVideoCodecFrame **out_frame_ptr)
781 {
782     return gst_vaapi_decoder_get_frame_with_timeout(decoder, out_frame_ptr, 0);
783 }
784
785 /**
786  * gst_vaapi_decoder_get_frame_with_timeout:
787  * @decoder: a #GstVaapiDecoder
788  * @out_frame_ptr: the next decoded frame as a #GstVideoCodecFrame
789  * @timeout: the number of microseconds to wait for the frame, at most
790  *
791  * On successful return, *@out_frame_ptr contains the next decoded
792  * frame available as a #GstVideoCodecFrame. The caller owns this
793  * object, so gst_video_codec_frame_unref() shall be called after
794  * usage. Otherwise, @GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA is
795  * returned if no decoded frame is available.
796  *
797  * The actual surface is available as a #GstVaapiSurfaceProxy attached
798  * to the user-data anchor of the output frame. Ownership of the proxy
799  * is transferred to the frame.
800  *
801  * Return value: a #GstVaapiDecoderStatus
802  */
803 GstVaapiDecoderStatus
804 gst_vaapi_decoder_get_frame_with_timeout(GstVaapiDecoder *decoder,
805     GstVideoCodecFrame **out_frame_ptr, guint64 timeout)
806 {
807     GstVideoCodecFrame *out_frame;
808
809     g_return_val_if_fail(decoder != NULL,
810         GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
811     g_return_val_if_fail(out_frame_ptr != NULL,
812         GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
813
814     out_frame = pop_frame(decoder, timeout);
815     if (!out_frame)
816         return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
817
818 #if !GST_CHECK_VERSION(1,0,0)
819     if (!GST_VIDEO_CODEC_FRAME_IS_DECODE_ONLY(out_frame)) {
820         const guint flags = GST_VAAPI_SURFACE_PROXY_FLAGS(out_frame->user_data);
821         guint out_flags = 0;
822
823         if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_TFF)
824             out_flags |= GST_VIDEO_CODEC_FRAME_FLAG_TFF;
825         if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_RFF)
826             out_flags |= GST_VIDEO_CODEC_FRAME_FLAG_RFF;
827         if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_ONEFIELD)
828             out_flags |= GST_VIDEO_CODEC_FRAME_FLAG_ONEFIELD;
829         GST_VIDEO_CODEC_FRAME_FLAG_SET(out_frame, out_flags);
830     }
831 #endif
832
833     *out_frame_ptr = out_frame;
834     return GST_VAAPI_DECODER_STATUS_SUCCESS;
835 }
836
837 void
838 gst_vaapi_decoder_set_picture_size(
839     GstVaapiDecoder    *decoder,
840     guint               width,
841     guint               height
842 )
843 {
844     GstVideoCodecState * const codec_state = decoder->codec_state;
845     gboolean size_changed = FALSE;
846
847     if (codec_state->info.width != width) {
848         GST_DEBUG("picture width changed to %d", width);
849         codec_state->info.width = width;
850         gst_caps_set_simple(codec_state->caps,
851             "width", G_TYPE_INT, width, NULL);
852         size_changed = TRUE;
853     }
854
855     if (codec_state->info.height != height) {
856         GST_DEBUG("picture height changed to %d", height);
857         codec_state->info.height = height;
858         gst_caps_set_simple(codec_state->caps,
859             "height", G_TYPE_INT, height, NULL);
860         size_changed = TRUE;
861     }
862
863     if (size_changed)
864         notify_codec_state_changed(decoder);
865 }
866
867 void
868 gst_vaapi_decoder_set_framerate(
869     GstVaapiDecoder    *decoder,
870     guint               fps_n,
871     guint               fps_d
872 )
873 {
874     GstVideoCodecState * const codec_state = decoder->codec_state;
875
876     if (!fps_n || !fps_d)
877         return;
878
879     if (codec_state->info.fps_n != fps_n || codec_state->info.fps_d != fps_d) {
880         GST_DEBUG("framerate changed to %u/%u", fps_n, fps_d);
881         codec_state->info.fps_n = fps_n;
882         codec_state->info.fps_d = fps_d;
883         gst_caps_set_simple(codec_state->caps,
884             "framerate", GST_TYPE_FRACTION, fps_n, fps_d, NULL);
885         notify_codec_state_changed(decoder);
886     }
887 }
888
889 void
890 gst_vaapi_decoder_set_pixel_aspect_ratio(
891     GstVaapiDecoder    *decoder,
892     guint               par_n,
893     guint               par_d
894 )
895 {
896     GstVideoCodecState * const codec_state = decoder->codec_state;
897
898     if (!par_n || !par_d)
899         return;
900
901     if (codec_state->info.par_n != par_n || codec_state->info.par_d != par_d) {
902         GST_DEBUG("pixel-aspect-ratio changed to %u/%u", par_n, par_d);
903         codec_state->info.par_n = par_n;
904         codec_state->info.par_d = par_d;
905         gst_caps_set_simple(codec_state->caps,
906             "pixel-aspect-ratio", GST_TYPE_FRACTION, par_n, par_d, NULL);
907         notify_codec_state_changed(decoder);
908     }
909 }
910
911 static const gchar *
912 gst_interlace_mode_to_string(GstVideoInterlaceMode mode)
913 {
914     switch (mode) {
915     case GST_VIDEO_INTERLACE_MODE_PROGRESSIVE:  return "progressive";
916     case GST_VIDEO_INTERLACE_MODE_INTERLEAVED:  return "interleaved";
917     case GST_VIDEO_INTERLACE_MODE_MIXED:        return "mixed";
918     }
919     return "<unknown>";
920 }
921
922 void
923 gst_vaapi_decoder_set_interlace_mode(GstVaapiDecoder *decoder,
924     GstVideoInterlaceMode mode)
925 {
926     GstVideoCodecState * const codec_state = decoder->codec_state;
927
928     if (codec_state->info.interlace_mode != mode) {
929         GST_DEBUG("interlace mode changed to %s",
930                   gst_interlace_mode_to_string(mode));
931         codec_state->info.interlace_mode = mode;
932         gst_caps_set_simple(codec_state->caps, "interlaced",
933             G_TYPE_BOOLEAN, mode != GST_VIDEO_INTERLACE_MODE_PROGRESSIVE, NULL);
934         notify_codec_state_changed(decoder);
935     }
936 }
937
938 void
939 gst_vaapi_decoder_set_interlaced(GstVaapiDecoder *decoder, gboolean interlaced)
940 {
941     gst_vaapi_decoder_set_interlace_mode(decoder,
942         (interlaced ?
943          GST_VIDEO_INTERLACE_MODE_INTERLEAVED :
944          GST_VIDEO_INTERLACE_MODE_PROGRESSIVE));
945 }
946
947 gboolean
948 gst_vaapi_decoder_ensure_context(
949     GstVaapiDecoder     *decoder,
950     GstVaapiContextInfo *cip
951 )
952 {
953     gst_vaapi_decoder_set_picture_size(decoder, cip->width, cip->height);
954
955     if (decoder->context) {
956         if (!gst_vaapi_context_reset(decoder->context, cip))
957             return FALSE;
958     }
959     else {
960         decoder->context = gst_vaapi_context_new(decoder->display, cip);
961         if (!decoder->context)
962             return FALSE;
963     }
964     decoder->va_context = gst_vaapi_context_get_id(decoder->context);
965     return TRUE;
966 }
967
968 void
969 gst_vaapi_decoder_push_frame(GstVaapiDecoder *decoder,
970     GstVideoCodecFrame *frame)
971 {
972     push_frame(decoder, frame);
973 }
974
975 GstVaapiDecoderStatus
976 gst_vaapi_decoder_check_status(GstVaapiDecoder *decoder)
977 {
978     if (decoder->context &&
979         gst_vaapi_context_get_surface_count(decoder->context) < 1)
980         return GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE;
981     return GST_VAAPI_DECODER_STATUS_SUCCESS;
982 }
983
984 GstVaapiDecoderStatus
985 gst_vaapi_decoder_parse(GstVaapiDecoder *decoder,
986     GstVideoCodecFrame *base_frame, GstAdapter *adapter, gboolean at_eos,
987     guint *got_unit_size_ptr, gboolean *got_frame_ptr)
988 {
989     g_return_val_if_fail(decoder != NULL,
990         GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
991     g_return_val_if_fail(base_frame != NULL,
992         GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
993     g_return_val_if_fail(adapter != NULL,
994         GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
995     g_return_val_if_fail(got_unit_size_ptr != NULL,
996         GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
997     g_return_val_if_fail(got_frame_ptr != NULL,
998         GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
999
1000     return do_parse(decoder, base_frame, adapter, at_eos,
1001         got_unit_size_ptr, got_frame_ptr);
1002 }
1003
1004 GstVaapiDecoderStatus
1005 gst_vaapi_decoder_decode(GstVaapiDecoder *decoder, GstVideoCodecFrame *frame)
1006 {
1007     GstVaapiDecoderStatus status;
1008
1009     g_return_val_if_fail(decoder != NULL,
1010         GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
1011     g_return_val_if_fail(frame != NULL,
1012         GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
1013     g_return_val_if_fail(frame->user_data != NULL,
1014         GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
1015
1016     status = gst_vaapi_decoder_check_status(decoder);
1017     if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
1018         return status;
1019     return do_decode(decoder, frame);
1020 }
1021
1022 GstVaapiDecoderStatus
1023 gst_vaapi_decoder_flush(GstVaapiDecoder *decoder)
1024 {
1025     g_return_val_if_fail(decoder != NULL,
1026         GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
1027
1028     return do_flush(decoder);
1029 }
1030
1031 GstVaapiDecoderStatus
1032 gst_vaapi_decoder_decode_codec_data(GstVaapiDecoder *decoder)
1033 {
1034     GstVaapiDecoderClass * const klass = GST_VAAPI_DECODER_GET_CLASS(decoder);
1035     GstBuffer * const codec_data = GST_VAAPI_DECODER_CODEC_DATA(decoder);
1036     GstVaapiDecoderStatus status;
1037     GstMapInfo map_info;
1038     const guchar *buf;
1039     guint buf_size;
1040
1041     if (!codec_data)
1042         return GST_VAAPI_DECODER_STATUS_SUCCESS;
1043
1044     /* FIXME: add a meaningful error code? */
1045     if (!klass->decode_codec_data)
1046         return GST_VAAPI_DECODER_STATUS_SUCCESS;
1047
1048     if (!gst_buffer_map(codec_data, &map_info, GST_MAP_READ)) {
1049         GST_ERROR("failed to map buffer");
1050         return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
1051     }
1052
1053     buf      = map_info.data;
1054     buf_size = map_info.size;
1055     if (G_LIKELY(buf && buf_size > 0))
1056         status = klass->decode_codec_data(decoder, buf, buf_size);
1057     else
1058         status = GST_VAAPI_DECODER_STATUS_SUCCESS;
1059     gst_buffer_unmap(codec_data, &map_info);
1060     return status;
1061 }