vp8: propagate PTS from demux frame.
[vaapi:gstreamer-vaapi.git] / gst-libs / gst / vaapi / gstvaapidecoder_vp8.c
1 /*
2  *  gstvaapidecoder_vp8.c - VP8 decoder
3  *
4  *  Copyright (C) 2013-2014 Intel Corporation
5  *    Author: Halley Zhao <halley.zhao@intel.com>
6  *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
7  *
8  *  This library is free software; you can redistribute it and/or
9  *  modify it under the terms of the GNU Lesser General Public License
10  *  as published by the Free Software Foundation; either version 2.1
11  *  of the License, or (at your option) any later version.
12  *
13  *  This library is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  *  Lesser General Public License for more details.
17  *
18  *  You should have received a copy of the GNU Lesser General Public
19  *  License along with this library; if not, write to the Free
20  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  *  Boston, MA 02110-1301 USA
22  */
23
24 /**
25  * SECTION:gstvaapidecoder_vp8
26  * @short_description: VP8 decoder
27  */
28
29 #include "sysdeps.h"
30 #include <gst/codecparsers/gstvp8parser.h>
31 #include "gstvaapidecoder_vp8.h"
32 #include "gstvaapidecoder_objects.h"
33 #include "gstvaapidecoder_priv.h"
34 #include "gstvaapidisplay_priv.h"
35 #include "gstvaapiobject_priv.h"
36
37 #include "gstvaapicompat.h"
38 #include <va/va_dec_vp8.h>
39
40 #define DEBUG 1
41 #include "gstvaapidebug.h"
42
43 #define GST_VAAPI_DECODER_VP8_CAST(decoder) \
44   ((GstVaapiDecoderVp8 *)(decoder))
45
46 typedef struct _GstVaapiDecoderVp8Private GstVaapiDecoderVp8Private;
47 typedef struct _GstVaapiDecoderVp8Class GstVaapiDecoderVp8Class;
48
49 struct _GstVaapiDecoderVp8Private
50 {
51   GstVaapiProfile profile;
52   guint width;
53   guint height;
54   GstVp8Parser parser;
55   GstVp8FrameHdr frame_hdr;
56   GstVaapiPicture *last_picture;
57   GstVaapiPicture *golden_ref_picture;
58   GstVaapiPicture *alt_ref_picture;
59   GstVaapiPicture *current_picture;
60   guint size_changed:1;
61 };
62
63 /**
64  * GstVaapiDecoderVp8:
65  *
66  * A decoder based on Vp8.
67  */
68 struct _GstVaapiDecoderVp8
69 {
70   /*< private >*/
71   GstVaapiDecoder parent_instance;
72
73   GstVaapiDecoderVp8Private priv;
74 };
75
76 /**
77  * GstVaapiDecoderVp8Class:
78  *
79  * A decoder class based on Vp8.
80  */
81 struct _GstVaapiDecoderVp8Class
82 {
83   /*< private >*/
84   GstVaapiDecoderClass parent_class;
85 };
86
87 static GstVaapiDecoderStatus
88 get_status (GstVp8ParserResult result)
89 {
90   GstVaapiDecoderStatus status;
91
92   switch (result) {
93     case GST_VP8_PARSER_OK:
94       status = GST_VAAPI_DECODER_STATUS_SUCCESS;
95       break;
96     case GST_VP8_PARSER_ERROR:
97       status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
98       break;
99     default:
100       status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
101       break;
102   }
103   return status;
104 }
105
106 static void
107 gst_vaapi_decoder_vp8_close (GstVaapiDecoderVp8 * decoder)
108 {
109   GstVaapiDecoderVp8Private *const priv = &decoder->priv;
110
111   gst_vaapi_picture_replace (&priv->last_picture, NULL);
112   gst_vaapi_picture_replace (&priv->golden_ref_picture, NULL);
113   gst_vaapi_picture_replace (&priv->alt_ref_picture, NULL);
114   gst_vaapi_picture_replace (&priv->current_picture, NULL);
115 }
116
117 static gboolean
118 gst_vaapi_decoder_vp8_open (GstVaapiDecoderVp8 * decoder)
119 {
120   GstVaapiDecoderVp8Private *const priv = &decoder->priv;
121
122   gst_vaapi_decoder_vp8_close (decoder);
123   gst_vp8_parser_init (&priv->parser);
124   return TRUE;
125 }
126
127 static void
128 gst_vaapi_decoder_vp8_destroy (GstVaapiDecoder * base_decoder)
129 {
130   GstVaapiDecoderVp8 *const decoder = GST_VAAPI_DECODER_VP8_CAST (base_decoder);
131
132   gst_vaapi_decoder_vp8_close (decoder);
133 }
134
135 static gboolean
136 gst_vaapi_decoder_vp8_create (GstVaapiDecoder * base_decoder)
137 {
138   GstVaapiDecoderVp8 *const decoder = GST_VAAPI_DECODER_VP8_CAST (base_decoder);
139   GstVaapiDecoderVp8Private *const priv = &decoder->priv;
140
141   if (!gst_vaapi_decoder_vp8_open (decoder))
142     return FALSE;
143
144   priv->profile = GST_VAAPI_PROFILE_UNKNOWN;
145   return TRUE;
146 }
147
148 static GstVaapiDecoderStatus
149 ensure_context (GstVaapiDecoderVp8 * decoder)
150 {
151   GstVaapiDecoderVp8Private *const priv = &decoder->priv;
152   const GstVaapiProfile profile = GST_VAAPI_PROFILE_VP8;
153   const GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_VLD;
154   gboolean reset_context = FALSE;
155
156   if (priv->profile != profile) {
157     if (!gst_vaapi_display_has_decoder (GST_VAAPI_DECODER_DISPLAY (decoder),
158             profile, entrypoint))
159       return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
160
161     priv->profile = profile;
162     reset_context = TRUE;
163   }
164
165   if (priv->size_changed) {
166     GST_DEBUG ("size changed");
167     priv->size_changed = FALSE;
168     reset_context = TRUE;
169   }
170
171   if (reset_context) {
172     GstVaapiContextInfo info;
173
174     info.profile = priv->profile;
175     info.entrypoint = entrypoint;
176     info.width = priv->width;
177     info.height = priv->height;
178     info.ref_frames = 3;
179     reset_context =
180         gst_vaapi_decoder_ensure_context (GST_VAAPI_DECODER (decoder), &info);
181
182     if (!reset_context)
183       return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
184   }
185   return GST_VAAPI_DECODER_STATUS_SUCCESS;
186 }
187
188 static GstVaapiDecoderStatus
189 ensure_quant_matrix (GstVaapiDecoderVp8 * decoder, GstVaapiPicture * picture)
190 {
191   GstVaapiDecoderVp8Private *const priv = &decoder->priv;
192   GstVp8FrameHdr *const frame_hdr = &priv->frame_hdr;
193   GstVp8Segmentation *const seg = &priv->parser.segmentation;
194   VAIQMatrixBufferVP8 *iq_matrix;
195   const gint8 QI_MAX = 127;
196   gint8 qi, qi_base;
197   gint i;
198
199   picture->iq_matrix = GST_VAAPI_IQ_MATRIX_NEW (VP8, decoder);
200   if (!picture->iq_matrix) {
201     GST_ERROR ("failed to allocate IQ matrix");
202     return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
203   }
204   iq_matrix = picture->iq_matrix->param;
205
206   /* Fill in VAIQMatrixBufferVP8 */
207   for (i = 0; i < 4; i++) {
208     if (seg->segmentation_enabled) {
209       qi_base = seg->quantizer_update_value[i];
210       if (!seg->segment_feature_mode)   // 0 means delta update
211         qi_base += frame_hdr->quant_indices.y_ac_qi;
212     } else
213       qi_base = frame_hdr->quant_indices.y_ac_qi;
214
215     qi = qi_base;
216     iq_matrix->quantization_index[i][0] = CLAMP (qi, 0, QI_MAX);
217     qi = qi_base + frame_hdr->quant_indices.y_dc_delta;
218     iq_matrix->quantization_index[i][1] = CLAMP (qi, 0, QI_MAX);
219     qi = qi_base + frame_hdr->quant_indices.y2_dc_delta;
220     iq_matrix->quantization_index[i][2] = CLAMP (qi, 0, QI_MAX);
221     qi = qi_base + frame_hdr->quant_indices.y2_ac_delta;
222     iq_matrix->quantization_index[i][3] = CLAMP (qi, 0, QI_MAX);
223     qi = qi_base + frame_hdr->quant_indices.uv_dc_delta;
224     iq_matrix->quantization_index[i][4] = CLAMP (qi, 0, QI_MAX);
225     qi = qi_base + frame_hdr->quant_indices.uv_ac_delta;
226     iq_matrix->quantization_index[i][5] = CLAMP (qi, 0, QI_MAX);
227   }
228   return GST_VAAPI_DECODER_STATUS_SUCCESS;
229 }
230
231 static GstVaapiDecoderStatus
232 ensure_probability_table (GstVaapiDecoderVp8 * decoder,
233     GstVaapiPicture * picture)
234 {
235   GstVaapiDecoderVp8Private *const priv = &decoder->priv;
236   GstVp8FrameHdr *const frame_hdr = &priv->frame_hdr;
237   VAProbabilityDataBufferVP8 *prob_table;
238
239   picture->prob_table = GST_VAAPI_PROBABILITY_TABLE_NEW (VP8, decoder);
240   if (!picture->prob_table) {
241     GST_ERROR ("failed to allocate probality table");
242     return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
243   }
244   prob_table = picture->prob_table->param;
245
246   /* Fill in VAProbabilityDataBufferVP8 */
247   memcpy (prob_table->dct_coeff_probs, frame_hdr->token_probs.prob,
248       sizeof (frame_hdr->token_probs.prob));
249
250   return GST_VAAPI_DECODER_STATUS_SUCCESS;
251 }
252
253 static void
254 init_picture (GstVaapiDecoderVp8 * decoder, GstVaapiPicture * picture)
255 {
256   GstVaapiDecoderVp8Private *const priv = &decoder->priv;
257   GstVp8FrameHdr *const frame_hdr = &priv->frame_hdr;
258
259   picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
260   picture->type = frame_hdr->key_frame ? GST_VAAPI_PICTURE_TYPE_I :
261       GST_VAAPI_PICTURE_TYPE_P;
262   picture->pts = GST_VAAPI_DECODER_CODEC_FRAME(decoder)->pts;
263
264   if (!frame_hdr->show_frame)
265     GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_SKIPPED);
266 }
267
268 static gboolean
269 fill_picture (GstVaapiDecoderVp8 * decoder, GstVaapiPicture * picture)
270 {
271   GstVaapiDecoderVp8Private *const priv = &decoder->priv;
272   VAPictureParameterBufferVP8 *const pic_param = picture->param;
273   GstVp8Parser *const parser = &priv->parser;
274   GstVp8FrameHdr *const frame_hdr = &priv->frame_hdr;
275   GstVp8Segmentation *const seg = &parser->segmentation;
276   gint i, filter_levels;
277
278   /* Fill in VAPictureParameterBufferVP8 */
279   pic_param->frame_width = priv->width;
280   pic_param->frame_height = priv->height;
281
282   pic_param->last_ref_frame = VA_INVALID_SURFACE;
283   pic_param->golden_ref_frame = VA_INVALID_SURFACE;
284   pic_param->alt_ref_frame = VA_INVALID_SURFACE;
285   if (!frame_hdr->key_frame) {
286     if (priv->last_picture)
287       pic_param->last_ref_frame = priv->last_picture->surface_id;
288     if (priv->golden_ref_picture)
289       pic_param->golden_ref_frame = priv->golden_ref_picture->surface_id;
290     if (priv->alt_ref_picture)
291       pic_param->alt_ref_frame = priv->alt_ref_picture->surface_id;
292   }
293   pic_param->out_of_loop_frame = VA_INVALID_SURFACE;    // not used currently
294
295   pic_param->pic_fields.value = 0;
296   pic_param->pic_fields.bits.key_frame = !frame_hdr->key_frame;
297   pic_param->pic_fields.bits.version = frame_hdr->version;
298   pic_param->pic_fields.bits.segmentation_enabled = seg->segmentation_enabled;
299   pic_param->pic_fields.bits.update_mb_segmentation_map =
300       seg->update_mb_segmentation_map;
301   pic_param->pic_fields.bits.update_segment_feature_data =
302       seg->update_segment_feature_data;
303   pic_param->pic_fields.bits.filter_type = frame_hdr->filter_type;
304   pic_param->pic_fields.bits.sharpness_level = frame_hdr->sharpness_level;
305   pic_param->pic_fields.bits.loop_filter_adj_enable =
306       parser->mb_lf_adjust.loop_filter_adj_enable;
307   pic_param->pic_fields.bits.mode_ref_lf_delta_update =
308       parser->mb_lf_adjust.mode_ref_lf_delta_update;
309   pic_param->pic_fields.bits.sign_bias_golden = frame_hdr->sign_bias_golden;
310   pic_param->pic_fields.bits.sign_bias_alternate =
311       frame_hdr->sign_bias_alternate;
312   pic_param->pic_fields.bits.mb_no_coeff_skip = frame_hdr->mb_no_skip_coeff;
313
314   for (i = 0; i < 3; i++)
315     pic_param->mb_segment_tree_probs[i] = seg->segment_prob[i];
316
317   for (i = 0; i < 4; i++) {
318     if (seg->segmentation_enabled) {
319       pic_param->loop_filter_level[i] = seg->lf_update_value[i];
320       if (!seg->segment_feature_mode)
321         pic_param->loop_filter_level[i] += frame_hdr->loop_filter_level;
322     } else
323       pic_param->loop_filter_level[i] = frame_hdr->loop_filter_level;
324
325     pic_param->loop_filter_deltas_ref_frame[i] =
326         parser->mb_lf_adjust.ref_frame_delta[i];
327     pic_param->loop_filter_deltas_mode[i] =
328         parser->mb_lf_adjust.mb_mode_delta[i];
329   }
330
331   /* In decoding, the only loop filter settings that matter are those
332      in the frame header (9.1) */
333   filter_levels = pic_param->loop_filter_level[0];
334   if (seg->segmentation_enabled) {
335     for (i = 1; i < 4; i++)
336       filter_levels |= pic_param->loop_filter_level[i];
337   }
338   pic_param->pic_fields.bits.loop_filter_disable = filter_levels == 0;
339
340   pic_param->prob_skip_false = frame_hdr->prob_skip_false;
341   pic_param->prob_intra = frame_hdr->prob_intra;
342   pic_param->prob_last = frame_hdr->prob_last;
343   pic_param->prob_gf = frame_hdr->prob_gf;
344
345   memcpy (pic_param->y_mode_probs, frame_hdr->mode_probs.y_prob,
346       sizeof (frame_hdr->mode_probs.y_prob));
347   memcpy (pic_param->uv_mode_probs, frame_hdr->mode_probs.uv_prob,
348       sizeof (frame_hdr->mode_probs.uv_prob));
349   memcpy (pic_param->mv_probs, frame_hdr->mv_probs.prob,
350       sizeof (frame_hdr->mv_probs));
351
352   pic_param->bool_coder_ctx.range = frame_hdr->rd_range;
353   pic_param->bool_coder_ctx.value = frame_hdr->rd_value;
354   pic_param->bool_coder_ctx.count = frame_hdr->rd_count;
355
356   return TRUE;
357 }
358
359 static gboolean
360 fill_slice (GstVaapiDecoderVp8 * decoder, GstVaapiSlice * slice)
361 {
362   GstVaapiDecoderVp8Private *const priv = &decoder->priv;
363   VASliceParameterBufferVP8 *const slice_param = slice->param;
364   GstVp8FrameHdr *const frame_hdr = &priv->frame_hdr;
365   gint i;
366
367   /* Fill in VASliceParameterBufferVP8 */
368   slice_param->slice_data_offset = frame_hdr->data_chunk_size;
369   slice_param->macroblock_offset = frame_hdr->header_size;
370   slice_param->num_of_partitions =
371       (1 << frame_hdr->log2_nbr_of_dct_partitions) + 1;
372
373   slice_param->partition_size[0] =
374       frame_hdr->first_part_size - ((slice_param->macroblock_offset + 7) >> 3);
375   for (i = 1; i < slice_param->num_of_partitions; i++)
376     slice_param->partition_size[i] = frame_hdr->partition_size[i - 1];
377   for (; i < G_N_ELEMENTS (slice_param->partition_size); i++)
378     slice_param->partition_size[i] = 0;
379
380   return TRUE;
381 }
382
383 static GstVaapiDecoderStatus
384 decode_slice (GstVaapiDecoderVp8 * decoder, GstVaapiPicture * picture,
385     const guchar * buf, guint buf_size)
386 {
387   GstVaapiSlice *slice;
388
389   slice = GST_VAAPI_SLICE_NEW (VP8, decoder, buf, buf_size);
390   if (!slice) {
391     GST_ERROR ("failed to allocate slice");
392     return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
393   }
394
395   if (!fill_slice (decoder, slice)) {
396     gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (slice));
397     return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
398   }
399
400   gst_vaapi_picture_add_slice (GST_VAAPI_PICTURE_CAST (picture), slice);
401   return GST_VAAPI_DECODER_STATUS_SUCCESS;
402 }
403
404 static GstVaapiDecoderStatus
405 decode_picture (GstVaapiDecoderVp8 * decoder, const guchar * buf,
406     guint buf_size)
407 {
408   GstVaapiDecoderVp8Private *const priv = &decoder->priv;
409   GstVaapiPicture *picture;
410   GstVaapiDecoderStatus status;
411
412   status = ensure_context (decoder);
413   if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
414     return status;
415
416   /* Create new picture */
417   picture = GST_VAAPI_PICTURE_NEW (VP8, decoder);
418   if (!picture) {
419     GST_ERROR ("failed to allocate picture");
420     return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
421   }
422   gst_vaapi_picture_replace (&priv->current_picture, picture);
423   gst_vaapi_picture_unref (picture);
424
425   status = ensure_quant_matrix (decoder, picture);
426   if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
427     return status;
428
429   status = ensure_probability_table (decoder, picture);
430   if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
431     return status;
432
433   init_picture (decoder, picture);
434   if (!fill_picture (decoder, picture))
435     return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
436
437   return decode_slice (decoder, picture, buf, buf_size);
438 }
439
440 static void
441 update_ref_frames (GstVaapiDecoderVp8 * decoder)
442 {
443   GstVaapiDecoderVp8Private *const priv = &decoder->priv;
444   GstVaapiPicture *picture = priv->current_picture;
445   GstVp8FrameHdr *const frame_hdr = &priv->frame_hdr;
446
447   // update picture reference
448   if (frame_hdr->key_frame) {
449     gst_vaapi_picture_replace (&priv->golden_ref_picture, picture);
450     gst_vaapi_picture_replace (&priv->alt_ref_picture, picture);
451   } else {
452     // process refresh_alternate_frame/copy_buffer_to_alternate first
453     if (frame_hdr->refresh_alternate_frame) {
454       gst_vaapi_picture_replace (&priv->alt_ref_picture, picture);
455     } else {
456       switch (frame_hdr->copy_buffer_to_alternate) {
457         case 0:
458           // do nothing
459           break;
460         case 1:
461           gst_vaapi_picture_replace (&priv->alt_ref_picture,
462               priv->last_picture);
463           break;
464         case 2:
465           gst_vaapi_picture_replace (&priv->alt_ref_picture,
466               priv->golden_ref_picture);
467           break;
468         default:
469           GST_WARNING
470               ("WARNING: VP8 decoder: unrecognized copy_buffer_to_alternate");
471       }
472     }
473
474     if (frame_hdr->refresh_golden_frame) {
475       gst_vaapi_picture_replace (&priv->golden_ref_picture, picture);
476     } else {
477       switch (frame_hdr->copy_buffer_to_golden) {
478         case 0:
479           // do nothing
480           break;
481         case 1:
482           gst_vaapi_picture_replace (&priv->golden_ref_picture,
483               priv->last_picture);
484           break;
485         case 2:
486           gst_vaapi_picture_replace (&priv->golden_ref_picture,
487               priv->alt_ref_picture);
488           break;
489         default:
490           GST_WARNING
491               ("WARNING: VP8 decoder: unrecognized copy_buffer_to_golden");
492       }
493     }
494   }
495   if (frame_hdr->key_frame || frame_hdr->refresh_last)
496     gst_vaapi_picture_replace (&priv->last_picture, picture);
497 }
498
499 static GstVaapiDecoderStatus
500 decode_current_picture (GstVaapiDecoderVp8 * decoder)
501 {
502   GstVaapiDecoderVp8Private *const priv = &decoder->priv;
503   GstVaapiPicture *const picture = priv->current_picture;
504
505   if (!picture)
506     return GST_VAAPI_DECODER_STATUS_SUCCESS;
507
508   update_ref_frames (decoder);
509   if (!gst_vaapi_picture_decode (picture))
510     goto error;
511   if (!gst_vaapi_picture_output (picture))
512     goto error;
513   gst_vaapi_picture_replace (&priv->current_picture, NULL);
514   return GST_VAAPI_DECODER_STATUS_SUCCESS;
515
516 error:
517   /* XXX: fix for cases where first field failed to be decoded */
518   gst_vaapi_picture_replace (&priv->current_picture, NULL);
519   return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
520 }
521
522 static GstVaapiDecoderStatus
523 parse_frame_header (GstVaapiDecoderVp8 * decoder, const guchar * buf,
524     guint buf_size, GstVp8FrameHdr * frame_hdr)
525 {
526   GstVaapiDecoderVp8Private *const priv = &decoder->priv;
527   GstVp8ParserResult result;
528
529   memset (frame_hdr, 0, sizeof (*frame_hdr));
530   result = gst_vp8_parser_parse_frame_header (&priv->parser, frame_hdr,
531       buf, buf_size);
532   if (result != GST_VP8_PARSER_OK)
533     return get_status (result);
534
535   if (frame_hdr->key_frame &&
536       (frame_hdr->width != priv->width || frame_hdr->height != priv->height)) {
537     priv->width = frame_hdr->width;
538     priv->height = frame_hdr->height;
539     priv->size_changed = TRUE;
540   }
541   return GST_VAAPI_DECODER_STATUS_SUCCESS;
542 }
543
544 static GstVaapiDecoderStatus
545 gst_vaapi_decoder_vp8_parse (GstVaapiDecoder * base_decoder,
546     GstAdapter * adapter, gboolean at_eos, GstVaapiDecoderUnit * unit)
547 {
548   guint flags = 0;
549
550   unit->size = gst_adapter_available (adapter);
551
552   /* The whole frame is available */
553   flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
554   flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE;
555   flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END;
556   GST_VAAPI_DECODER_UNIT_FLAG_SET (unit, flags);
557   return GST_VAAPI_DECODER_STATUS_SUCCESS;
558
559 }
560
561 static GstVaapiDecoderStatus
562 decode_buffer (GstVaapiDecoderVp8 * decoder, const guchar * buf, guint buf_size)
563 {
564   GstVaapiDecoderVp8Private *const priv = &decoder->priv;
565   GstVaapiDecoderStatus status;
566
567   status = parse_frame_header (decoder, buf, buf_size, &priv->frame_hdr);
568   if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
569     return status;
570
571   return decode_picture (decoder, buf, buf_size);
572 }
573
574 GstVaapiDecoderStatus
575 gst_vaapi_decoder_vp8_decode (GstVaapiDecoder * base_decoder,
576     GstVaapiDecoderUnit * unit)
577 {
578   GstVaapiDecoderVp8 *const decoder = GST_VAAPI_DECODER_VP8_CAST (base_decoder);
579   GstVaapiDecoderStatus status;
580   GstBuffer *const buffer =
581       GST_VAAPI_DECODER_CODEC_FRAME (decoder)->input_buffer;
582   GstMapInfo map_info;
583
584   if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ)) {
585     GST_ERROR ("failed to map buffer");
586     return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
587   }
588
589   status = decode_buffer (decoder, map_info.data + unit->offset, unit->size);
590   gst_buffer_unmap (buffer, &map_info);
591   if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
592     return status;
593   return GST_VAAPI_DECODER_STATUS_SUCCESS;
594 }
595
596 static GstVaapiDecoderStatus
597 gst_vaapi_decoder_vp8_start_frame (GstVaapiDecoder * base_decoder,
598     GstVaapiDecoderUnit * base_unit)
599 {
600   return GST_VAAPI_DECODER_STATUS_SUCCESS;
601 }
602
603 static GstVaapiDecoderStatus
604 gst_vaapi_decoder_vp8_end_frame (GstVaapiDecoder * base_decoder)
605 {
606   GstVaapiDecoderVp8 *const decoder = GST_VAAPI_DECODER_VP8_CAST (base_decoder);
607
608   return decode_current_picture (decoder);
609 }
610
611 static GstVaapiDecoderStatus
612 gst_vaapi_decoder_vp8_flush (GstVaapiDecoder * base_decoder)
613 {
614   return GST_VAAPI_DECODER_STATUS_SUCCESS;
615 }
616
617 static void
618 gst_vaapi_decoder_vp8_class_init (GstVaapiDecoderVp8Class * klass)
619 {
620   GstVaapiMiniObjectClass *const object_class =
621       GST_VAAPI_MINI_OBJECT_CLASS (klass);
622   GstVaapiDecoderClass *const decoder_class = GST_VAAPI_DECODER_CLASS (klass);
623
624   object_class->size = sizeof (GstVaapiDecoderVp8);
625   object_class->finalize = (GDestroyNotify) gst_vaapi_decoder_finalize;
626
627   decoder_class->create = gst_vaapi_decoder_vp8_create;
628   decoder_class->destroy = gst_vaapi_decoder_vp8_destroy;
629   decoder_class->parse = gst_vaapi_decoder_vp8_parse;
630   decoder_class->decode = gst_vaapi_decoder_vp8_decode;
631   decoder_class->start_frame = gst_vaapi_decoder_vp8_start_frame;
632   decoder_class->end_frame = gst_vaapi_decoder_vp8_end_frame;
633   decoder_class->flush = gst_vaapi_decoder_vp8_flush;
634 }
635
636 static inline const GstVaapiDecoderClass *
637 gst_vaapi_decoder_vp8_class (void)
638 {
639   static GstVaapiDecoderVp8Class g_class;
640   static gsize g_class_init = FALSE;
641
642   if (g_once_init_enter (&g_class_init)) {
643     gst_vaapi_decoder_vp8_class_init (&g_class);
644     g_once_init_leave (&g_class_init, TRUE);
645   }
646   return GST_VAAPI_DECODER_CLASS (&g_class);
647 }
648
649 /**
650  * gst_vaapi_decoder_vp8_new:
651  * @display: a #GstVaapiDisplay
652  * @caps: a #GstCaps holding codec information
653  *
654  * Creates a new #GstVaapiDecoder for VP8 decoding.  The @caps can
655  * hold extra information like codec-data and pictured coded size.
656  *
657  * Return value: the newly allocated #GstVaapiDecoder object
658  */
659 GstVaapiDecoder *
660 gst_vaapi_decoder_vp8_new (GstVaapiDisplay * display, GstCaps * caps)
661 {
662   return gst_vaapi_decoder_new (gst_vaapi_decoder_vp8_class (), display, caps);
663 }