3f30f0bf73f8b1a0b6d9b8e4c4c281dcdb9a4358
[platform/upstream/gstreamer-vaapi.git] / gst-libs / gst / vaapi / gstvaapidecoder_mpeg2.c
1 /*
2  *  gstvaapidecoder_mpeg2.c - MPEG-2 decoder
3  *
4  *  Copyright (C) 2011-2013 Intel Corporation
5  *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
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_mpeg2
25  * @short_description: MPEG-2 decoder
26  */
27
28 #include "sysdeps.h"
29 #include <string.h>
30 #include <gst/base/gstbitreader.h>
31 #include <gst/codecparsers/gstmpegvideoparser.h>
32 #include "gstvaapidecoder_mpeg2.h"
33 #include "gstvaapidecoder_objects.h"
34 #include "gstvaapidecoder_dpb.h"
35 #include "gstvaapidecoder_priv.h"
36 #include "gstvaapidisplay_priv.h"
37 #include "gstvaapiobject_priv.h"
38
39 #define DEBUG 1
40 #include "gstvaapidebug.h"
41
42 /* ------------------------------------------------------------------------- */
43 /* --- PTS Generator                                                     --- */
44 /* ------------------------------------------------------------------------- */
45
46 typedef struct _PTSGenerator PTSGenerator;
47 struct _PTSGenerator {
48     GstClockTime        gop_pts; // Current GOP PTS
49     GstClockTime        max_pts; // Max picture PTS
50     guint               gop_tsn; // Absolute GOP TSN
51     guint               max_tsn; // Max picture TSN, relative to last GOP TSN
52     guint               ovl_tsn; // How many times TSN overflowed since GOP
53     guint               lst_tsn; // Last picture TSN
54     guint               fps_n;
55     guint               fps_d;
56 };
57
58 static void
59 pts_init(PTSGenerator *tsg)
60 {
61     tsg->gop_pts = GST_CLOCK_TIME_NONE;
62     tsg->max_pts = GST_CLOCK_TIME_NONE;
63     tsg->gop_tsn = 0;
64     tsg->max_tsn = 0;
65     tsg->ovl_tsn = 0;
66     tsg->lst_tsn = 0;
67     tsg->fps_n   = 0;
68     tsg->fps_d   = 0;
69 }
70
71 static inline GstClockTime
72 pts_get_duration(PTSGenerator *tsg, guint num_frames)
73 {
74     return gst_util_uint64_scale(num_frames,
75                                  GST_SECOND * tsg->fps_d, tsg->fps_n);
76 }
77
78 static inline guint
79 pts_get_poc(PTSGenerator *tsg)
80 {
81     return tsg->gop_tsn + tsg->ovl_tsn * 1024 + tsg->lst_tsn;
82 }
83
84 static void
85 pts_set_framerate(PTSGenerator *tsg, guint fps_n, guint fps_d)
86 {
87     tsg->fps_n = fps_n;
88     tsg->fps_d = fps_d;
89 }
90
91 static void
92 pts_sync(PTSGenerator *tsg, GstClockTime gop_pts)
93 {
94     guint gop_tsn;
95
96     if (!GST_CLOCK_TIME_IS_VALID(gop_pts) ||
97         (GST_CLOCK_TIME_IS_VALID(tsg->max_pts) && tsg->max_pts >= gop_pts)) {
98         /* Invalid GOP PTS, interpolate from the last known picture PTS */
99         if (GST_CLOCK_TIME_IS_VALID(tsg->max_pts)) {
100             gop_pts = tsg->max_pts + pts_get_duration(tsg, 1);
101             gop_tsn = tsg->gop_tsn + tsg->ovl_tsn * 1024 + tsg->max_tsn + 1;
102         }
103         else {
104             gop_pts = 0;
105             gop_tsn = 0;
106         }
107     }
108     else {
109         /* Interpolate GOP TSN from this valid PTS */
110         if (GST_CLOCK_TIME_IS_VALID(tsg->gop_pts))
111             gop_tsn = tsg->gop_tsn + gst_util_uint64_scale(
112                 gop_pts - tsg->gop_pts + pts_get_duration(tsg, 1) - 1,
113                 tsg->fps_n, GST_SECOND * tsg->fps_d);
114         else
115             gop_tsn = 0;
116     }
117
118     tsg->gop_pts = gop_pts;
119     tsg->gop_tsn = gop_tsn;
120     tsg->max_tsn = 0;
121     tsg->ovl_tsn = 0;
122     tsg->lst_tsn = 0;
123 }
124
125 static GstClockTime
126 pts_eval(PTSGenerator *tsg, GstClockTime pic_pts, guint pic_tsn)
127 {
128     GstClockTime pts;
129
130     if (!GST_CLOCK_TIME_IS_VALID(tsg->gop_pts))
131         tsg->gop_pts = 0;
132
133     pts = tsg->gop_pts + pts_get_duration(tsg, tsg->ovl_tsn * 1024 + pic_tsn);
134
135     if (!GST_CLOCK_TIME_IS_VALID(tsg->max_pts) || tsg->max_pts < pts)
136         tsg->max_pts = pts;
137
138     if (tsg->max_tsn < pic_tsn)
139         tsg->max_tsn = pic_tsn;
140     else if (tsg->max_tsn == 1023 && pic_tsn < tsg->lst_tsn) { /* TSN wrapped */
141         tsg->max_tsn = pic_tsn;
142         tsg->ovl_tsn++;
143     }
144     tsg->lst_tsn = pic_tsn;
145     return pts;
146 }
147
148 /* ------------------------------------------------------------------------- */
149 /* --- MPEG-2 Parser Info                                                --- */
150 /* ------------------------------------------------------------------------- */
151
152 typedef struct _GstVaapiParserInfoMpeg2 GstVaapiParserInfoMpeg2;
153 struct _GstVaapiParserInfoMpeg2 {
154     GstVaapiMiniObject  parent_instance;
155     GstMpegVideoPacket  packet;
156     guint8              extension_type; /* for Extension packets */
157     union {
158         GstMpegVideoSequenceHdr         seq_hdr;
159         GstMpegVideoSequenceExt         seq_ext;
160         GstMpegVideoSequenceDisplayExt  seq_display_ext;
161         GstMpegVideoSequenceScalableExt seq_scalable_ext;
162         GstMpegVideoGop                 gop;
163         GstMpegVideoQuantMatrixExt      quant_matrix;
164         GstMpegVideoPictureHdr          pic_hdr;
165         GstMpegVideoPictureExt          pic_ext;
166         GstMpegVideoSliceHdr            slice_hdr;
167     }                                   data;
168 };
169
170 static inline const GstVaapiMiniObjectClass *
171 gst_vaapi_parser_info_mpeg2_class(void)
172 {
173     static const GstVaapiMiniObjectClass GstVaapiParserInfoMpeg2Class = {
174         sizeof(GstVaapiParserInfoMpeg2),
175         NULL
176     };
177     return &GstVaapiParserInfoMpeg2Class;
178 }
179
180 static inline GstVaapiParserInfoMpeg2 *
181 gst_vaapi_parser_info_mpeg2_new(void)
182 {
183     return (GstVaapiParserInfoMpeg2 *)
184         gst_vaapi_mini_object_new(gst_vaapi_parser_info_mpeg2_class());
185 }
186
187 static inline GstVaapiParserInfoMpeg2 *
188 gst_vaapi_parser_info_mpeg2_ensure(GstVaapiParserInfoMpeg2 **pi_ptr)
189 {
190     GstVaapiParserInfoMpeg2 *pi = *pi_ptr;
191
192     if (G_LIKELY(pi != NULL))
193         return pi;
194
195     *pi_ptr = pi = gst_vaapi_parser_info_mpeg2_new();
196     return pi;
197 }
198
199 #define gst_vaapi_parser_info_mpeg2_ref(pi) \
200     gst_vaapi_mini_object_ref(GST_VAAPI_MINI_OBJECT(pi))
201
202 #define gst_vaapi_parser_info_mpeg2_unref(pi) \
203     gst_vaapi_mini_object_unref(GST_VAAPI_MINI_OBJECT(pi))
204
205 #define gst_vaapi_parser_info_mpeg2_replace(old_pi_ptr, new_pi)         \
206     gst_vaapi_mini_object_replace((GstVaapiMiniObject **)(old_pi_ptr),  \
207         (GstVaapiMiniObject *)(new_pi))
208
209 /* ------------------------------------------------------------------------- */
210 /* --- MPEG-2 Decoder                                                    --- */
211 /* ------------------------------------------------------------------------- */
212
213 #define GST_VAAPI_DECODER_MPEG2_CAST(decoder) \
214     ((GstVaapiDecoderMpeg2 *)(decoder))
215
216 typedef struct _GstVaapiDecoderMpeg2Private     GstVaapiDecoderMpeg2Private;
217 typedef struct _GstVaapiDecoderMpeg2Class       GstVaapiDecoderMpeg2Class;
218
219 typedef enum {
220     GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR    = 1 << 0,
221     GST_MPEG_VIDEO_STATE_GOT_SEQ_EXT    = 1 << 1,
222     GST_MPEG_VIDEO_STATE_GOT_PIC_HDR    = 1 << 2,
223     GST_MPEG_VIDEO_STATE_GOT_PIC_EXT    = 1 << 3,
224     GST_MPEG_VIDEO_STATE_GOT_SLICE      = 1 << 4,
225
226     GST_MPEG_VIDEO_STATE_VALID_SEQ_HEADERS = (
227         GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR|
228         GST_MPEG_VIDEO_STATE_GOT_SEQ_EXT),
229     GST_MPEG_VIDEO_STATE_VALID_PIC_HEADERS = (
230         GST_MPEG_VIDEO_STATE_GOT_PIC_HDR|
231         GST_MPEG_VIDEO_STATE_GOT_PIC_EXT),
232     GST_MPEG_VIDEO_STATE_VALID_PICTURE = (
233         GST_MPEG_VIDEO_STATE_VALID_SEQ_HEADERS|
234         GST_MPEG_VIDEO_STATE_VALID_PIC_HEADERS|
235         GST_MPEG_VIDEO_STATE_GOT_SLICE)
236 } GstMpegVideoState;
237
238 struct _GstVaapiDecoderMpeg2Private {
239     GstVaapiProfile             profile;
240     GstVaapiProfile             hw_profile;
241     guint                       width;
242     guint                       height;
243     guint                       fps_n;
244     guint                       fps_d;
245     guint                       state;
246     GstVaapiRectangle           crop_rect;
247     GstVaapiParserInfoMpeg2    *seq_hdr;
248     GstVaapiParserInfoMpeg2    *seq_ext;
249     GstVaapiParserInfoMpeg2    *seq_display_ext;
250     GstVaapiParserInfoMpeg2    *seq_scalable_ext;
251     GstVaapiParserInfoMpeg2    *gop;
252     GstVaapiParserInfoMpeg2    *pic_hdr;
253     GstVaapiParserInfoMpeg2    *pic_ext;
254     GstVaapiParserInfoMpeg2    *pic_display_ext;
255     GstVaapiParserInfoMpeg2    *quant_matrix;
256     GstVaapiParserInfoMpeg2    *slice_hdr;
257     GstVaapiPicture            *current_picture;
258     GstVaapiDpb                *dpb;
259     PTSGenerator                tsg;
260     guint                       is_opened               : 1;
261     guint                       size_changed            : 1;
262     guint                       profile_changed         : 1;
263     guint                       quant_matrix_changed    : 1;
264     guint                       progressive_sequence    : 1;
265     guint                       closed_gop              : 1;
266     guint                       broken_link             : 1;
267 };
268
269 /**
270  * GstVaapiDecoderMpeg2:
271  *
272  * A decoder based on Mpeg2.
273  */
274 struct _GstVaapiDecoderMpeg2 {
275     /*< private >*/
276     GstVaapiDecoder             parent_instance;
277     GstVaapiDecoderMpeg2Private priv;
278 };
279
280 /**
281  * GstVaapiDecoderMpeg2Class:
282  *
283  * A decoder class based on Mpeg2.
284  */
285 struct _GstVaapiDecoderMpeg2Class {
286     /*< private >*/
287     GstVaapiDecoderClass parent_class;
288 };
289
290 static void
291 gst_vaapi_decoder_mpeg2_close(GstVaapiDecoderMpeg2 *decoder)
292 {
293     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
294
295     gst_vaapi_picture_replace(&priv->current_picture, NULL);
296
297     gst_vaapi_parser_info_mpeg2_replace(&priv->seq_hdr, NULL);
298     gst_vaapi_parser_info_mpeg2_replace(&priv->seq_ext, NULL);
299     gst_vaapi_parser_info_mpeg2_replace(&priv->seq_display_ext, NULL);
300     gst_vaapi_parser_info_mpeg2_replace(&priv->seq_scalable_ext, NULL);
301     gst_vaapi_parser_info_mpeg2_replace(&priv->gop, NULL);
302     gst_vaapi_parser_info_mpeg2_replace(&priv->pic_hdr, NULL);
303     gst_vaapi_parser_info_mpeg2_replace(&priv->pic_ext, NULL);
304     gst_vaapi_parser_info_mpeg2_replace(&priv->pic_display_ext, NULL);
305     gst_vaapi_parser_info_mpeg2_replace(&priv->quant_matrix, NULL);
306     gst_vaapi_parser_info_mpeg2_replace(&priv->slice_hdr, NULL);
307
308     gst_vaapi_dpb_replace(&priv->dpb, NULL);
309 }
310
311 static gboolean
312 gst_vaapi_decoder_mpeg2_open(GstVaapiDecoderMpeg2 *decoder)
313 {
314     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
315
316     gst_vaapi_decoder_mpeg2_close(decoder);
317
318     priv->dpb = gst_vaapi_dpb_new(2);
319     if (!priv->dpb)
320         return FALSE;
321
322     pts_init(&priv->tsg);
323     return TRUE;
324 }
325
326 static void
327 gst_vaapi_decoder_mpeg2_destroy(GstVaapiDecoder *base_decoder)
328 {
329     GstVaapiDecoderMpeg2 * const decoder =
330         GST_VAAPI_DECODER_MPEG2_CAST(base_decoder);
331
332     gst_vaapi_decoder_mpeg2_close(decoder);
333 }
334
335 static gboolean
336 gst_vaapi_decoder_mpeg2_create(GstVaapiDecoder *base_decoder)
337 {
338     GstVaapiDecoderMpeg2 * const decoder =
339         GST_VAAPI_DECODER_MPEG2_CAST(base_decoder);
340     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
341
342     priv->hw_profile            = GST_VAAPI_PROFILE_UNKNOWN;
343     priv->profile               = GST_VAAPI_PROFILE_MPEG2_SIMPLE;
344     priv->profile_changed       = TRUE; /* Allow fallbacks to work */
345     return TRUE;
346 }
347
348 static inline void
349 copy_quant_matrix(guint8 dst[64], const guint8 src[64])
350 {
351     memcpy(dst, src, 64);
352 }
353
354 static const char *
355 get_profile_str(GstVaapiProfile profile)
356 {
357     char *str;
358
359     switch (profile) {
360     case GST_VAAPI_PROFILE_MPEG2_SIMPLE:    str = "simple";     break;
361     case GST_VAAPI_PROFILE_MPEG2_MAIN:      str = "main";       break;
362     case GST_VAAPI_PROFILE_MPEG2_HIGH:      str = "high";       break;
363     default:                                str = "<unknown>";  break;
364     }
365     return str;
366 }
367
368 static GstVaapiProfile
369 get_profile(GstVaapiDecoderMpeg2 *decoder, GstVaapiEntrypoint entrypoint)
370 {
371     GstVaapiDisplay * const va_display = GST_VAAPI_DECODER_DISPLAY(decoder);
372     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
373     GstVaapiProfile profile = priv->profile;
374
375     do {
376         /* Return immediately if the exact same profile was found */
377         if (gst_vaapi_display_has_decoder(va_display, profile, entrypoint))
378             break;
379
380         /* Otherwise, try to map to a higher profile */
381         switch (profile) {
382         case GST_VAAPI_PROFILE_MPEG2_SIMPLE:
383             profile = GST_VAAPI_PROFILE_MPEG2_MAIN;
384             break;
385         case GST_VAAPI_PROFILE_MPEG2_MAIN:
386             profile = GST_VAAPI_PROFILE_MPEG2_HIGH;
387             break;
388         case GST_VAAPI_PROFILE_MPEG2_HIGH:
389             // Try to map to main profile if no high profile specific bits used
390             if (priv->profile == profile &&
391                 !priv->seq_scalable_ext &&
392                 (priv->seq_ext &&
393                  priv->seq_ext->data.seq_ext.chroma_format == 1)) {
394                 profile = GST_VAAPI_PROFILE_MPEG2_MAIN;
395                 break;
396             }
397             // fall-through
398         default:
399             profile = GST_VAAPI_PROFILE_UNKNOWN;
400             break;
401         }
402     } while (profile != GST_VAAPI_PROFILE_UNKNOWN);
403
404     if (profile != priv->profile)
405         GST_INFO("forced %s profile to %s profile",
406                  get_profile_str(priv->profile), get_profile_str(profile));
407     return profile;
408 }
409
410 static GstVaapiDecoderStatus
411 ensure_context(GstVaapiDecoderMpeg2 *decoder)
412 {
413     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
414     GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_VLD;
415     gboolean reset_context = FALSE;
416
417     if (priv->profile_changed) {
418         GST_DEBUG("profile changed");
419         priv->profile_changed = FALSE;
420         reset_context         = TRUE;
421
422         priv->hw_profile = get_profile(decoder, entrypoint);
423         if (priv->hw_profile == GST_VAAPI_PROFILE_UNKNOWN)
424             return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
425     }
426
427     if (priv->size_changed) {
428         GST_DEBUG("size changed");
429         priv->size_changed = FALSE;
430         reset_context      = TRUE;
431     }
432
433     if (reset_context) {
434         GstVaapiContextInfo info;
435
436         info.profile    = priv->hw_profile;
437         info.entrypoint = entrypoint;
438         info.chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420;
439         info.width      = priv->width;
440         info.height     = priv->height;
441         info.ref_frames = 2;
442         reset_context   = gst_vaapi_decoder_ensure_context(
443             GST_VAAPI_DECODER_CAST(decoder),
444             &info
445         );
446         if (!reset_context)
447             return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
448     }
449     return GST_VAAPI_DECODER_STATUS_SUCCESS;
450 }
451
452 static GstVaapiDecoderStatus
453 ensure_quant_matrix(GstVaapiDecoderMpeg2 *decoder, GstVaapiPicture *picture)
454 {
455     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
456     GstMpegVideoSequenceHdr * const seq_hdr = &priv->seq_hdr->data.seq_hdr;
457     VAIQMatrixBufferMPEG2 *iq_matrix;
458     guint8 *intra_quant_matrix = NULL;
459     guint8 *non_intra_quant_matrix = NULL;
460     guint8 *chroma_intra_quant_matrix = NULL;
461     guint8 *chroma_non_intra_quant_matrix = NULL;
462
463     if (!priv->quant_matrix_changed)
464         return GST_VAAPI_DECODER_STATUS_SUCCESS;
465
466     priv->quant_matrix_changed = FALSE;
467
468     picture->iq_matrix = GST_VAAPI_IQ_MATRIX_NEW(MPEG2, decoder);
469     if (!picture->iq_matrix) {
470         GST_ERROR("failed to allocate IQ matrix");
471         return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
472     }
473     iq_matrix = picture->iq_matrix->param;
474
475     intra_quant_matrix     = seq_hdr->intra_quantizer_matrix;
476     non_intra_quant_matrix = seq_hdr->non_intra_quantizer_matrix;
477
478     if (priv->quant_matrix) {
479         GstMpegVideoQuantMatrixExt * const quant_matrix =
480             &priv->quant_matrix->data.quant_matrix;
481         if (quant_matrix->load_intra_quantiser_matrix)
482             intra_quant_matrix = quant_matrix->intra_quantiser_matrix;
483         if (quant_matrix->load_non_intra_quantiser_matrix)
484             non_intra_quant_matrix = quant_matrix->non_intra_quantiser_matrix;
485         if (quant_matrix->load_chroma_intra_quantiser_matrix)
486             chroma_intra_quant_matrix = quant_matrix->chroma_intra_quantiser_matrix;
487         if (quant_matrix->load_chroma_non_intra_quantiser_matrix)
488             chroma_non_intra_quant_matrix = quant_matrix->chroma_non_intra_quantiser_matrix;
489     }
490
491     iq_matrix->load_intra_quantiser_matrix = intra_quant_matrix != NULL;
492     if (intra_quant_matrix)
493         copy_quant_matrix(iq_matrix->intra_quantiser_matrix,
494                           intra_quant_matrix);
495
496     iq_matrix->load_non_intra_quantiser_matrix = non_intra_quant_matrix != NULL;
497     if (non_intra_quant_matrix)
498         copy_quant_matrix(iq_matrix->non_intra_quantiser_matrix,
499                           non_intra_quant_matrix);
500
501     iq_matrix->load_chroma_intra_quantiser_matrix = chroma_intra_quant_matrix != NULL;
502     if (chroma_intra_quant_matrix)
503         copy_quant_matrix(iq_matrix->chroma_intra_quantiser_matrix,
504                           chroma_intra_quant_matrix);
505
506     iq_matrix->load_chroma_non_intra_quantiser_matrix = chroma_non_intra_quant_matrix != NULL;
507     if (chroma_non_intra_quant_matrix)
508         copy_quant_matrix(iq_matrix->chroma_non_intra_quantiser_matrix,
509                           chroma_non_intra_quant_matrix);
510     return GST_VAAPI_DECODER_STATUS_SUCCESS;
511 }
512
513 static inline gboolean
514 is_valid_state(GstVaapiDecoderMpeg2 *decoder, guint state)
515 {
516     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
517
518     return (priv->state & state) == state;
519 }
520
521 static GstVaapiDecoderStatus
522 decode_current_picture(GstVaapiDecoderMpeg2 *decoder)
523 {
524     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
525     GstVaapiPicture * const picture = priv->current_picture;
526
527     if (!is_valid_state(decoder, GST_MPEG_VIDEO_STATE_VALID_PICTURE))
528         goto drop_frame;
529     priv->state &= GST_MPEG_VIDEO_STATE_VALID_SEQ_HEADERS;
530
531     if (!picture)
532         return GST_VAAPI_DECODER_STATUS_SUCCESS;
533
534     if (!gst_vaapi_picture_decode(picture))
535         goto error;
536     if (GST_VAAPI_PICTURE_IS_COMPLETE(picture)) {
537         if (!gst_vaapi_dpb_add(priv->dpb, picture))
538             goto error;
539         gst_vaapi_picture_replace(&priv->current_picture, NULL);
540     }
541     return GST_VAAPI_DECODER_STATUS_SUCCESS;
542
543 error:
544     /* XXX: fix for cases where first field failed to be decoded */
545     gst_vaapi_picture_replace(&priv->current_picture, NULL);
546     return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
547
548 drop_frame:
549     priv->state &= GST_MPEG_VIDEO_STATE_VALID_SEQ_HEADERS;
550     return GST_VAAPI_DECODER_STATUS_DROP_FRAME;
551 }
552
553 static GstVaapiDecoderStatus
554 parse_sequence(GstVaapiDecoderMpeg2 *decoder,
555     GstVaapiDecoderUnit *unit, const GstMpegVideoPacket *packet)
556 {
557     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
558     GstMpegVideoSequenceHdr *seq_hdr;
559
560     priv->state = 0;
561
562     if (!gst_vaapi_parser_info_mpeg2_ensure(&priv->seq_hdr)) {
563         GST_ERROR("failed to allocate parser info for sequence header");
564         return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
565     }
566
567     seq_hdr = &priv->seq_hdr->data.seq_hdr;
568
569     if (!gst_mpeg_video_packet_parse_sequence_header(packet, seq_hdr)) {
570         GST_ERROR("failed to parse sequence header");
571         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
572     }
573
574     gst_vaapi_decoder_unit_set_parsed_info(unit, seq_hdr, NULL);
575     return GST_VAAPI_DECODER_STATUS_SUCCESS;
576 }
577
578 static GstVaapiDecoderStatus
579 decode_sequence(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnit *unit)
580 {
581     GstVaapiDecoder * const base_decoder = GST_VAAPI_DECODER_CAST(decoder);
582     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
583     GstMpegVideoSequenceHdr * const seq_hdr = unit->parsed_info;
584
585     gst_vaapi_parser_info_mpeg2_replace(&priv->seq_ext, NULL);
586     gst_vaapi_parser_info_mpeg2_replace(&priv->seq_display_ext, NULL);
587     gst_vaapi_parser_info_mpeg2_replace(&priv->seq_scalable_ext, NULL);
588     gst_vaapi_parser_info_mpeg2_replace(&priv->quant_matrix, NULL);
589     gst_vaapi_parser_info_mpeg2_replace(&priv->pic_display_ext, NULL);
590
591     priv->fps_n = seq_hdr->fps_n;
592     priv->fps_d = seq_hdr->fps_d;
593     pts_set_framerate(&priv->tsg, priv->fps_n, priv->fps_d);
594     gst_vaapi_decoder_set_framerate(base_decoder, priv->fps_n, priv->fps_d);
595
596     priv->width                 = seq_hdr->width;
597     priv->height                = seq_hdr->height;
598     priv->size_changed          = TRUE;
599     priv->quant_matrix_changed  = TRUE;
600     priv->progressive_sequence  = TRUE;
601
602     priv->state |= GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR;
603     return GST_VAAPI_DECODER_STATUS_SUCCESS;
604 }
605
606 static GstVaapiDecoderStatus
607 parse_sequence_ext(GstVaapiDecoderMpeg2 *decoder,
608     GstVaapiDecoderUnit *unit, const GstMpegVideoPacket *packet)
609 {
610     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
611     GstMpegVideoSequenceExt *seq_ext;
612
613     priv->state &= GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR;
614
615     if (!gst_vaapi_parser_info_mpeg2_ensure(&priv->seq_ext)) {
616         GST_ERROR("failed to allocate parser info for sequence extension");
617         return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
618     }
619
620     seq_ext = &priv->seq_ext->data.seq_ext;
621
622     if (!gst_mpeg_video_packet_parse_sequence_extension(packet, seq_ext)) {
623         GST_ERROR("failed to parse sequence-extension");
624         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
625     }
626
627     gst_vaapi_decoder_unit_set_parsed_info(unit, seq_ext, NULL);
628     return GST_VAAPI_DECODER_STATUS_SUCCESS;
629 }
630
631 static GstVaapiDecoderStatus
632 decode_sequence_ext(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnit *unit)
633 {
634     GstVaapiDecoder * const base_decoder = GST_VAAPI_DECODER_CAST(decoder);
635     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
636     GstMpegVideoSequenceExt * const seq_ext = unit->parsed_info;
637     GstVaapiProfile profile;
638     guint width, height;
639
640     if (!is_valid_state(decoder, GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR))
641         return GST_VAAPI_DECODER_STATUS_SUCCESS;
642
643     priv->progressive_sequence = seq_ext->progressive;
644     gst_vaapi_decoder_set_interlaced(base_decoder, !priv->progressive_sequence);
645
646     width  = (priv->width  & 0x0fff) | ((guint32)seq_ext->horiz_size_ext << 12);
647     height = (priv->height & 0x0fff) | ((guint32)seq_ext->vert_size_ext  << 12);
648     GST_DEBUG("video resolution %ux%u", width, height);
649
650     if (seq_ext->fps_n_ext && seq_ext->fps_d_ext) {
651         priv->fps_n *= seq_ext->fps_n_ext + 1;
652         priv->fps_d *= seq_ext->fps_d_ext + 1;
653         pts_set_framerate(&priv->tsg, priv->fps_n, priv->fps_d);
654         gst_vaapi_decoder_set_framerate(base_decoder, priv->fps_n, priv->fps_d);
655     }
656
657     if (priv->width != width) {
658         priv->width = width;
659         priv->size_changed = TRUE;
660     }
661
662     if (priv->height != height) {
663         priv->height = height;
664         priv->size_changed = TRUE;
665     }
666
667     switch (seq_ext->profile) {
668     case GST_MPEG_VIDEO_PROFILE_SIMPLE:
669         profile = GST_VAAPI_PROFILE_MPEG2_SIMPLE;
670         break;
671     case GST_MPEG_VIDEO_PROFILE_MAIN:
672         profile = GST_VAAPI_PROFILE_MPEG2_MAIN;
673         break;
674     case GST_MPEG_VIDEO_PROFILE_HIGH:
675         profile = GST_VAAPI_PROFILE_MPEG2_HIGH;
676         break;
677     default:
678         GST_ERROR("unsupported profile %d", seq_ext->profile);
679         return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
680     }
681     if (priv->profile != profile) {
682         priv->profile = profile;
683         priv->profile_changed = TRUE;
684     }
685
686     priv->state |= GST_MPEG_VIDEO_STATE_GOT_SEQ_EXT;
687     return GST_VAAPI_DECODER_STATUS_SUCCESS;
688 }
689
690 static GstVaapiDecoderStatus
691 parse_sequence_display_ext(GstVaapiDecoderMpeg2 *decoder,
692     GstVaapiDecoderUnit *unit, const GstMpegVideoPacket *packet)
693 {
694     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
695     GstMpegVideoSequenceDisplayExt *seq_display_ext;
696
697     if (!gst_vaapi_parser_info_mpeg2_ensure(&priv->seq_display_ext)) {
698         GST_ERROR("failed to allocate parser info for sequence display extension");
699         return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
700     }
701
702     seq_display_ext = &priv->seq_display_ext->data.seq_display_ext;
703
704     if (!gst_mpeg_video_packet_parse_sequence_display_extension(packet,
705             seq_display_ext)) {
706         GST_ERROR("failed to parse sequence-display-extension");
707         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
708     }
709
710     gst_vaapi_decoder_unit_set_parsed_info(unit, seq_display_ext, NULL);
711     return GST_VAAPI_DECODER_STATUS_SUCCESS;
712 }
713
714 static GstVaapiDecoderStatus
715 decode_sequence_display_ext(GstVaapiDecoderMpeg2 *decoder,
716     GstVaapiDecoderUnit *unit)
717 {
718     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
719     GstMpegVideoSequenceDisplayExt *seq_display_ext;
720
721     seq_display_ext = priv->seq_display_ext ?
722         &priv->seq_display_ext->data.seq_display_ext : NULL;
723
724     /* Update cropping rectangle */
725     if (seq_display_ext) {
726         GstVaapiRectangle * const crop_rect = &priv->crop_rect;
727         crop_rect->x = 0;
728         crop_rect->y = 0;
729         crop_rect->width = seq_display_ext->display_horizontal_size;
730         crop_rect->height = seq_display_ext->display_vertical_size;
731     }
732
733     /* XXX: handle color primaries */
734     return GST_VAAPI_DECODER_STATUS_SUCCESS;
735 }
736
737 static GstVaapiDecoderStatus
738 parse_sequence_scalable_ext(GstVaapiDecoderMpeg2 *decoder,
739     GstVaapiDecoderUnit *unit, const GstMpegVideoPacket *packet)
740 {
741     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
742     GstMpegVideoSequenceScalableExt *seq_scalable_ext;
743
744     if (!gst_vaapi_parser_info_mpeg2_ensure(&priv->seq_scalable_ext)) {
745         GST_ERROR("failed to allocate parser info for sequence scalable extension");
746         return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
747     }
748
749     seq_scalable_ext = &priv->seq_scalable_ext->data.seq_scalable_ext;
750
751     if (!gst_mpeg_video_packet_parse_sequence_scalable_extension(packet,
752             seq_scalable_ext)) {
753         GST_ERROR("failed to parse sequence-scalable-extension");
754         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
755     }
756
757     gst_vaapi_decoder_unit_set_parsed_info(unit, seq_scalable_ext, NULL);
758     return GST_VAAPI_DECODER_STATUS_SUCCESS;
759 }
760
761 static GstVaapiDecoderStatus
762 decode_sequence_scalable_ext(GstVaapiDecoderMpeg2 *decoder,
763     GstVaapiDecoderUnit *unit)
764 {
765     /* XXX: unsupported header -- ignore */
766     return GST_VAAPI_DECODER_STATUS_SUCCESS;
767 }
768
769 static GstVaapiDecoderStatus
770 decode_sequence_end(GstVaapiDecoderMpeg2 *decoder)
771 {
772     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
773
774     gst_vaapi_dpb_flush(priv->dpb);
775     return GST_VAAPI_DECODER_STATUS_SUCCESS;
776 }
777
778 static GstVaapiDecoderStatus
779 parse_quant_matrix_ext(GstVaapiDecoderMpeg2 *decoder,
780     GstVaapiDecoderUnit *unit, const GstMpegVideoPacket *packet)
781 {
782     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
783     GstMpegVideoQuantMatrixExt *quant_matrix;
784
785     if (!gst_vaapi_parser_info_mpeg2_ensure(&priv->quant_matrix)) {
786         GST_ERROR("failed to allocate parser info for quantization matrix");
787         return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
788     }
789
790     quant_matrix = &priv->quant_matrix->data.quant_matrix;
791
792     if (!gst_mpeg_video_packet_parse_quant_matrix_extension(packet,
793             quant_matrix)) {
794         GST_ERROR("failed to parse quant-matrix-extension");
795         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
796     }
797
798     gst_vaapi_decoder_unit_set_parsed_info(unit, quant_matrix, NULL);
799     return GST_VAAPI_DECODER_STATUS_SUCCESS;
800 }
801
802 static GstVaapiDecoderStatus
803 decode_quant_matrix_ext(GstVaapiDecoderMpeg2 *decoder,
804     GstVaapiDecoderUnit *unit)
805 {
806     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
807
808     priv->quant_matrix_changed = TRUE;
809     return GST_VAAPI_DECODER_STATUS_SUCCESS;
810 }
811
812 static GstVaapiDecoderStatus
813 parse_gop(GstVaapiDecoderMpeg2 *decoder,
814     GstVaapiDecoderUnit *unit, const GstMpegVideoPacket *packet)
815 {
816     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
817     GstMpegVideoGop *gop;
818
819     if (!gst_vaapi_parser_info_mpeg2_ensure(&priv->gop)) {
820         GST_ERROR("failed to allocate parser info for GOP");
821         return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
822     }
823
824     gop = &priv->gop->data.gop;
825
826     if (!gst_mpeg_video_packet_parse_gop(packet, gop)) {
827         GST_ERROR("failed to parse GOP");
828         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
829     }
830
831     gst_vaapi_decoder_unit_set_parsed_info(unit, gop, NULL);
832     return GST_VAAPI_DECODER_STATUS_SUCCESS;
833 }
834
835 static GstVaapiDecoderStatus
836 decode_gop(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnit *unit)
837 {
838     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
839     GstMpegVideoGop * const gop = unit->parsed_info;
840
841     priv->closed_gop  = gop->closed_gop;
842     priv->broken_link = gop->broken_link;
843
844     GST_DEBUG("GOP %02u:%02u:%02u:%02u (closed_gop %d, broken_link %d)",
845               gop->hour, gop->minute, gop->second, gop->frame,
846               priv->closed_gop, priv->broken_link);
847
848     pts_sync(&priv->tsg, GST_VAAPI_DECODER_CODEC_FRAME(decoder)->pts);
849     return GST_VAAPI_DECODER_STATUS_SUCCESS;
850 }
851
852 static GstVaapiDecoderStatus
853 parse_picture(GstVaapiDecoderMpeg2 *decoder,
854     GstVaapiDecoderUnit *unit, const GstMpegVideoPacket *packet)
855 {
856     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
857     GstMpegVideoPictureHdr *pic_hdr;
858
859     priv->state &= (GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR|
860                     GST_MPEG_VIDEO_STATE_GOT_SEQ_EXT);
861
862     if (!gst_vaapi_parser_info_mpeg2_ensure(&priv->pic_hdr)) {
863         GST_ERROR("failed to allocate parser info for picture header");
864         return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
865     }
866
867     pic_hdr = &priv->pic_hdr->data.pic_hdr;
868
869     if (!gst_mpeg_video_packet_parse_picture_header(packet, pic_hdr)) {
870         GST_ERROR("failed to parse picture header");
871         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
872     }
873
874     gst_vaapi_decoder_unit_set_parsed_info(unit, pic_hdr, NULL);
875     return GST_VAAPI_DECODER_STATUS_SUCCESS;
876 }
877
878 static GstVaapiDecoderStatus
879 decode_picture(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnit *unit)
880 {
881     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
882
883     if (!is_valid_state(decoder, GST_MPEG_VIDEO_STATE_VALID_SEQ_HEADERS))
884         return GST_VAAPI_DECODER_STATUS_SUCCESS;
885
886     gst_vaapi_parser_info_mpeg2_replace(&priv->pic_ext, NULL);
887
888     priv->state |= GST_MPEG_VIDEO_STATE_GOT_PIC_HDR;
889     return GST_VAAPI_DECODER_STATUS_SUCCESS;
890 }
891
892 static GstVaapiDecoderStatus
893 parse_picture_ext(GstVaapiDecoderMpeg2 *decoder,
894     GstVaapiDecoderUnit *unit, const GstMpegVideoPacket *packet)
895 {
896     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
897     GstMpegVideoPictureExt *pic_ext;
898
899     priv->state &= (GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR|
900                     GST_MPEG_VIDEO_STATE_GOT_SEQ_EXT|
901                     GST_MPEG_VIDEO_STATE_GOT_PIC_HDR);
902
903     if (!gst_vaapi_parser_info_mpeg2_ensure(&priv->pic_ext)) {
904         GST_ERROR("failed to allocate parser info for picture extension");
905         return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
906     }
907
908     pic_ext = &priv->pic_ext->data.pic_ext;
909
910     if (!gst_mpeg_video_packet_parse_picture_extension(packet, pic_ext)) {
911         GST_ERROR("failed to parse picture-extension");
912         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
913     }
914
915     gst_vaapi_decoder_unit_set_parsed_info(unit, pic_ext, NULL);
916     return GST_VAAPI_DECODER_STATUS_SUCCESS;
917 }
918
919 static GstVaapiDecoderStatus
920 decode_picture_ext(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnit *unit)
921 {
922     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
923     GstMpegVideoPictureExt * const pic_ext = unit->parsed_info;
924
925     if (!is_valid_state(decoder, GST_MPEG_VIDEO_STATE_GOT_PIC_HDR))
926         return GST_VAAPI_DECODER_STATUS_SUCCESS;
927
928     if (priv->progressive_sequence && !pic_ext->progressive_frame) {
929         GST_WARNING("invalid interlaced frame in progressive sequence, fixing");
930         pic_ext->progressive_frame = 1;
931     }
932
933     if (pic_ext->picture_structure == 0 ||
934         (pic_ext->progressive_frame &&
935          pic_ext->picture_structure != GST_MPEG_VIDEO_PICTURE_STRUCTURE_FRAME)) {
936         GST_WARNING("invalid picture_structure %d, replacing with \"frame\"",
937                     pic_ext->picture_structure);
938         pic_ext->picture_structure = GST_MPEG_VIDEO_PICTURE_STRUCTURE_FRAME;
939     }
940
941     priv->state |= GST_MPEG_VIDEO_STATE_GOT_PIC_EXT;
942     return GST_VAAPI_DECODER_STATUS_SUCCESS;
943 }
944
945 static inline guint32
946 pack_f_code(guint8 f_code[2][2])
947 {
948     return (((guint32)f_code[0][0] << 12) |
949             ((guint32)f_code[0][1] <<  8) |
950             ((guint32)f_code[1][0] <<  4) |
951             (         f_code[1][1]      ));
952 }
953
954 static GstVaapiDecoderStatus
955 init_picture(GstVaapiDecoderMpeg2 *decoder, GstVaapiPicture *picture)
956 {
957     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
958     GstMpegVideoPictureHdr * const pic_hdr = &priv->pic_hdr->data.pic_hdr;
959     GstMpegVideoPictureExt * const pic_ext = &priv->pic_ext->data.pic_ext;
960
961     switch (pic_hdr->pic_type) {
962     case GST_MPEG_VIDEO_PICTURE_TYPE_I:
963         GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_REFERENCE);
964         picture->type = GST_VAAPI_PICTURE_TYPE_I;
965         break;
966     case GST_MPEG_VIDEO_PICTURE_TYPE_P:
967         GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_REFERENCE);
968         picture->type = GST_VAAPI_PICTURE_TYPE_P;
969         break;
970     case GST_MPEG_VIDEO_PICTURE_TYPE_B:
971         picture->type = GST_VAAPI_PICTURE_TYPE_B;
972         break;
973     default:
974         GST_ERROR("unsupported picture type %d", pic_hdr->pic_type);
975         return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
976     }
977
978     if (!priv->progressive_sequence && !pic_ext->progressive_frame) {
979         GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_INTERLACED);
980         if (pic_ext->top_field_first)
981             GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_TFF);
982     }
983
984     switch (pic_ext->picture_structure) {
985     case GST_MPEG_VIDEO_PICTURE_STRUCTURE_TOP_FIELD:
986         picture->structure = GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD;
987         break;
988     case GST_MPEG_VIDEO_PICTURE_STRUCTURE_BOTTOM_FIELD:
989         picture->structure = GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD;
990         break;
991     case GST_MPEG_VIDEO_PICTURE_STRUCTURE_FRAME:
992         picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
993         break;
994     }
995
996     /* Allocate dummy picture for first field based I-frame */
997     if (picture->type == GST_VAAPI_PICTURE_TYPE_I &&
998         !GST_VAAPI_PICTURE_IS_FRAME(picture) &&
999         gst_vaapi_dpb_size(priv->dpb) == 0) {
1000         GstVaapiPicture *dummy_picture;
1001         gboolean success;
1002
1003         dummy_picture = GST_VAAPI_PICTURE_NEW(MPEG2, decoder);
1004         if (!dummy_picture) {
1005             GST_ERROR("failed to allocate dummy picture");
1006             return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
1007         }
1008
1009         dummy_picture->type      = GST_VAAPI_PICTURE_TYPE_I;
1010         dummy_picture->pts       = GST_CLOCK_TIME_NONE;
1011         dummy_picture->poc       = -1;
1012         dummy_picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
1013
1014         GST_VAAPI_PICTURE_FLAG_SET(
1015             dummy_picture,
1016             (GST_VAAPI_PICTURE_FLAG_SKIPPED |
1017              GST_VAAPI_PICTURE_FLAG_OUTPUT  |
1018              GST_VAAPI_PICTURE_FLAG_REFERENCE)
1019         );
1020
1021         success = gst_vaapi_dpb_add(priv->dpb, dummy_picture);
1022         gst_vaapi_picture_unref(dummy_picture);
1023         if (!success) {
1024             GST_ERROR("failed to add dummy picture into DPB");
1025             return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
1026         }
1027         GST_INFO("allocated dummy picture for first field based I-frame");
1028     }
1029
1030     /* Update presentation time */
1031     picture->pts = pts_eval(&priv->tsg,
1032         GST_VAAPI_DECODER_CODEC_FRAME(decoder)->pts, pic_hdr->tsn);
1033     picture->poc = pts_get_poc(&priv->tsg);
1034     return GST_VAAPI_DECODER_STATUS_SUCCESS;
1035 }
1036
1037 static void
1038 fill_picture(GstVaapiDecoderMpeg2 *decoder, GstVaapiPicture *picture)
1039 {
1040     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
1041     VAPictureParameterBufferMPEG2 * const pic_param = picture->param;
1042     GstMpegVideoPictureHdr * const pic_hdr = &priv->pic_hdr->data.pic_hdr;
1043     GstMpegVideoPictureExt * const pic_ext = &priv->pic_ext->data.pic_ext;
1044     GstVaapiPicture *prev_picture, *next_picture;
1045
1046     /* Fill in VAPictureParameterBufferMPEG2 */
1047     pic_param->horizontal_size            = priv->width;
1048     pic_param->vertical_size              = priv->height;
1049     pic_param->forward_reference_picture  = VA_INVALID_ID;
1050     pic_param->backward_reference_picture = VA_INVALID_ID;
1051     pic_param->picture_coding_type        = pic_hdr->pic_type;
1052     pic_param->f_code                     = pack_f_code(pic_ext->f_code);
1053
1054 #define COPY_FIELD(a, b, f) \
1055     pic_param->a.b.f = pic_ext->f
1056     pic_param->picture_coding_extension.value = 0;
1057     pic_param->picture_coding_extension.bits.is_first_field =
1058         GST_VAAPI_PICTURE_IS_FIRST_FIELD(picture);
1059     COPY_FIELD(picture_coding_extension, bits, intra_dc_precision);
1060     COPY_FIELD(picture_coding_extension, bits, picture_structure);
1061     COPY_FIELD(picture_coding_extension, bits, top_field_first);
1062     COPY_FIELD(picture_coding_extension, bits, frame_pred_frame_dct);
1063     COPY_FIELD(picture_coding_extension, bits, concealment_motion_vectors);
1064     COPY_FIELD(picture_coding_extension, bits, q_scale_type);
1065     COPY_FIELD(picture_coding_extension, bits, intra_vlc_format);
1066     COPY_FIELD(picture_coding_extension, bits, alternate_scan);
1067     COPY_FIELD(picture_coding_extension, bits, repeat_first_field);
1068     COPY_FIELD(picture_coding_extension, bits, progressive_frame);
1069
1070     gst_vaapi_dpb_get_neighbours(priv->dpb, picture,
1071         &prev_picture, &next_picture);
1072
1073     switch (pic_hdr->pic_type) {
1074     case GST_MPEG_VIDEO_PICTURE_TYPE_B:
1075         if (next_picture)
1076             pic_param->backward_reference_picture = next_picture->surface_id;
1077         if (prev_picture)
1078             pic_param->forward_reference_picture = prev_picture->surface_id;
1079         else if (!priv->closed_gop)
1080             GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_SKIPPED);
1081         break;
1082     case GST_MPEG_VIDEO_PICTURE_TYPE_P:
1083         if (prev_picture)
1084             pic_param->forward_reference_picture = prev_picture->surface_id;
1085         break;
1086     }
1087 }
1088
1089 static GstVaapiDecoderStatus
1090 parse_slice(GstVaapiDecoderMpeg2 *decoder,
1091     GstVaapiDecoderUnit *unit, const GstMpegVideoPacket *packet)
1092 {
1093     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
1094     GstMpegVideoSliceHdr *slice_hdr;
1095     GstMpegVideoSequenceHdr *seq_hdr;
1096     GstMpegVideoSequenceScalableExt *seq_scalable_ext;
1097
1098     priv->state &= (GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR|
1099                     GST_MPEG_VIDEO_STATE_GOT_SEQ_EXT|
1100                     GST_MPEG_VIDEO_STATE_GOT_PIC_HDR|
1101                     GST_MPEG_VIDEO_STATE_GOT_PIC_EXT);
1102
1103     if (!gst_vaapi_parser_info_mpeg2_ensure(&priv->slice_hdr)) {
1104         GST_ERROR("failed to allocate parser info for slice header");
1105         return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
1106     }
1107
1108     slice_hdr = &priv->slice_hdr->data.slice_hdr;
1109     seq_hdr = &priv->seq_hdr->data.seq_hdr;
1110     seq_scalable_ext = priv->seq_scalable_ext ?
1111         &priv->seq_scalable_ext->data.seq_scalable_ext : NULL;
1112
1113     if (!gst_mpeg_video_packet_parse_slice_header(packet, slice_hdr,
1114             seq_hdr, seq_scalable_ext)) {
1115         GST_ERROR("failed to parse slice header");
1116         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
1117     }
1118
1119     gst_vaapi_decoder_unit_set_parsed_info(unit, slice_hdr, NULL);
1120     return GST_VAAPI_DECODER_STATUS_SUCCESS;
1121 }
1122
1123 static GstVaapiDecoderStatus
1124 decode_slice(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnit *unit)
1125 {
1126     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
1127     GstVaapiPicture * const picture = priv->current_picture;
1128     GstVaapiSlice *slice;
1129     VASliceParameterBufferMPEG2 *slice_param;
1130     GstMpegVideoSliceHdr * const slice_hdr = unit->parsed_info;
1131     GstBuffer * const buffer =
1132         GST_VAAPI_DECODER_CODEC_FRAME(decoder)->input_buffer;
1133     GstMapInfo map_info;
1134
1135     GST_DEBUG("slice %d (%u bytes)", slice_hdr->mb_row, unit->size);
1136
1137     if (!is_valid_state(decoder, GST_MPEG_VIDEO_STATE_VALID_PIC_HEADERS))
1138         return GST_VAAPI_DECODER_STATUS_SUCCESS;
1139
1140     if (!gst_buffer_map(buffer, &map_info, GST_MAP_READ)) {
1141         GST_ERROR("failed to map buffer");
1142         return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
1143     }
1144
1145     slice = GST_VAAPI_SLICE_NEW(MPEG2, decoder,
1146         (map_info.data + unit->offset), unit->size);
1147     gst_buffer_unmap(buffer, &map_info);
1148     if (!slice) {
1149         GST_ERROR("failed to allocate slice");
1150         return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
1151     }
1152     gst_vaapi_picture_add_slice(picture, slice);
1153
1154     /* Fill in VASliceParameterBufferMPEG2 */
1155     slice_param                            = slice->param;
1156     slice_param->macroblock_offset         = slice_hdr->header_size + 32;
1157     slice_param->slice_horizontal_position = slice_hdr->mb_column;
1158     slice_param->slice_vertical_position   = slice_hdr->mb_row;
1159     slice_param->quantiser_scale_code      = slice_hdr->quantiser_scale_code;
1160     slice_param->intra_slice_flag          = slice_hdr->intra_slice;
1161
1162     priv->state |= GST_MPEG_VIDEO_STATE_GOT_SLICE;
1163     return GST_VAAPI_DECODER_STATUS_SUCCESS;
1164 }
1165
1166 static inline gint
1167 scan_for_start_code(const guchar *buf, guint buf_size,
1168     GstMpegVideoPacketTypeCode *type_ptr)
1169 {
1170     guint i = 0;
1171
1172     while (i <= (buf_size - 4)) {
1173         if (buf[i + 2] > 1)
1174             i += 3;
1175         else if (buf[i + 1])
1176             i += 2;
1177         else if (buf[i] || buf[i + 2] != 1)
1178             i++;
1179         else
1180             break;
1181     }
1182
1183     if (i <= (buf_size - 4)) {
1184         if (type_ptr)
1185             *type_ptr = buf[i + 3];
1186         return i;
1187     }
1188     return -1;
1189 }
1190
1191 static GstVaapiDecoderStatus
1192 parse_unit(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnit *unit,
1193     GstMpegVideoPacket *packet)
1194 {
1195     GstMpegVideoPacketTypeCode type;
1196     GstMpegVideoPacketExtensionCode ext_type;
1197     GstVaapiDecoderStatus status;
1198
1199     type = packet->type;
1200     switch (type) {
1201     case GST_MPEG_VIDEO_PACKET_PICTURE:
1202         status = parse_picture(decoder, unit, packet);
1203         break;
1204     case GST_MPEG_VIDEO_PACKET_SEQUENCE:
1205         status = parse_sequence(decoder, unit, packet);
1206         break;
1207     case GST_MPEG_VIDEO_PACKET_EXTENSION:
1208         ext_type = packet->data[4] >> 4;
1209         switch (ext_type) {
1210         case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE:
1211             status = parse_sequence_ext(decoder, unit, packet);
1212             break;
1213         case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_DISPLAY:
1214             status = parse_sequence_display_ext(decoder, unit, packet);
1215             break;
1216         case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_SCALABLE:
1217             status = parse_sequence_scalable_ext(decoder, unit, packet);
1218             break;
1219         case GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX:
1220             status = parse_quant_matrix_ext(decoder, unit, packet);
1221             break;
1222         case GST_MPEG_VIDEO_PACKET_EXT_PICTURE:
1223             status = parse_picture_ext(decoder, unit, packet);
1224             break;
1225         default:
1226             status = GST_VAAPI_DECODER_STATUS_SUCCESS;
1227             break;
1228         }
1229         break;
1230     case GST_MPEG_VIDEO_PACKET_GOP:
1231         status = parse_gop(decoder, unit, packet);
1232         break;
1233     default:
1234         if (type >= GST_MPEG_VIDEO_PACKET_SLICE_MIN &&
1235             type <= GST_MPEG_VIDEO_PACKET_SLICE_MAX) {
1236             status = parse_slice(decoder, unit, packet);
1237             break;
1238         }
1239         status = GST_VAAPI_DECODER_STATUS_SUCCESS;
1240         break;
1241     }
1242     return status;
1243 }
1244
1245 static GstVaapiDecoderStatus
1246 decode_unit(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnit *unit,
1247     GstMpegVideoPacket *packet)
1248 {
1249     GstMpegVideoPacketTypeCode type;
1250     GstMpegVideoPacketExtensionCode ext_type;
1251     GstVaapiDecoderStatus status;
1252
1253     type = packet->type;
1254     switch (type) {
1255     case GST_MPEG_VIDEO_PACKET_PICTURE:
1256         status = decode_picture(decoder, unit);
1257         break;
1258     case GST_MPEG_VIDEO_PACKET_SEQUENCE:
1259         status = decode_sequence(decoder, unit);
1260         break;
1261     case GST_MPEG_VIDEO_PACKET_EXTENSION:
1262         ext_type = packet->data[4] >> 4;
1263         switch (ext_type) {
1264         case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE:
1265             status = decode_sequence_ext(decoder, unit);
1266             break;
1267         case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_DISPLAY:
1268             status = decode_sequence_display_ext(decoder, unit);
1269             break;
1270         case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_SCALABLE:
1271             status = decode_sequence_scalable_ext(decoder, unit);
1272             break;
1273         case GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX:
1274             status = decode_quant_matrix_ext(decoder, unit);
1275             break;
1276         case GST_MPEG_VIDEO_PACKET_EXT_PICTURE:
1277             status = decode_picture_ext(decoder, unit);
1278             break;
1279         default:
1280             // Ignore unknown start-code extensions
1281             GST_WARNING("unsupported packet extension type 0x%02x", ext_type);
1282             status = GST_VAAPI_DECODER_STATUS_SUCCESS;
1283             break;
1284         }
1285         break;
1286     case GST_MPEG_VIDEO_PACKET_SEQUENCE_END:
1287         status = decode_sequence_end(decoder);
1288         break;
1289     case GST_MPEG_VIDEO_PACKET_GOP:
1290         status = decode_gop(decoder, unit);
1291         break;
1292     default:
1293         if (type >= GST_MPEG_VIDEO_PACKET_SLICE_MIN &&
1294             type <= GST_MPEG_VIDEO_PACKET_SLICE_MAX) {
1295             status = decode_slice(decoder, unit);
1296             break;
1297         }
1298         GST_WARNING("unsupported packet type 0x%02x", type);
1299         status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
1300         break;
1301     }
1302     return status;
1303 }
1304
1305 static GstVaapiDecoderStatus
1306 ensure_decoder(GstVaapiDecoderMpeg2 *decoder)
1307 {
1308     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
1309
1310     if (!priv->is_opened) {
1311         priv->is_opened = gst_vaapi_decoder_mpeg2_open(decoder);
1312         if (!priv->is_opened)
1313             return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC;
1314     }
1315     return GST_VAAPI_DECODER_STATUS_SUCCESS;
1316 }
1317
1318 static GstVaapiDecoderStatus
1319 gst_vaapi_decoder_mpeg2_parse(GstVaapiDecoder *base_decoder,
1320     GstAdapter *adapter, gboolean at_eos, GstVaapiDecoderUnit *unit)
1321 {
1322     GstVaapiDecoderMpeg2 * const decoder =
1323         GST_VAAPI_DECODER_MPEG2_CAST(base_decoder);
1324     GstVaapiParserState * const ps = GST_VAAPI_PARSER_STATE(base_decoder);
1325     GstVaapiDecoderStatus status;
1326     GstMpegVideoPacketTypeCode type, type2 = GST_MPEG_VIDEO_PACKET_NONE;
1327     const guchar *buf;
1328     guint buf_size, flags;
1329     gint ofs, ofs1, ofs2;
1330
1331     status = ensure_decoder(decoder);
1332     if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
1333         return status;
1334
1335     buf_size = gst_adapter_available(adapter);
1336     if (buf_size < 4)
1337         return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
1338
1339     buf = gst_adapter_map(adapter, buf_size);
1340     if (!buf)
1341         return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
1342
1343     ofs = scan_for_start_code(buf, buf_size, &type);
1344     if (ofs < 0)
1345         return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
1346     ofs1 = ofs;
1347
1348     ofs2 = ps->input_offset2 - 4;
1349     if (ofs2 < ofs1 + 4)
1350         ofs2 = ofs1 + 4;
1351
1352     ofs = G_UNLIKELY(buf_size < ofs2 + 4) ? -1 :
1353         scan_for_start_code(&buf[ofs2], buf_size - ofs2, &type2);
1354     if (ofs < 0) {
1355         // Assume the whole packet is present if end-of-stream
1356         if (!at_eos) {
1357             ps->input_offset2 = buf_size;
1358             return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
1359         }
1360         ofs = buf_size - ofs2;
1361     }
1362     ofs2 += ofs;
1363
1364     unit->size = ofs2 - ofs1;
1365     gst_adapter_flush(adapter, ofs1);
1366     ps->input_offset2 = 4;
1367
1368     /* Check for start of new picture */
1369     flags = 0;
1370     switch (type) {
1371     case GST_MPEG_VIDEO_PACKET_SEQUENCE_END:
1372         flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END;
1373         flags |= GST_VAAPI_DECODER_UNIT_FLAG_STREAM_END;
1374         break;
1375     case GST_MPEG_VIDEO_PACKET_USER_DATA:
1376         flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP;
1377         /* fall-through */
1378     case GST_MPEG_VIDEO_PACKET_SEQUENCE:
1379     case GST_MPEG_VIDEO_PACKET_GOP:
1380     case GST_MPEG_VIDEO_PACKET_PICTURE:
1381         flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
1382         break;
1383     case GST_MPEG_VIDEO_PACKET_EXTENSION:
1384         if (G_UNLIKELY(unit->size < 5))
1385             return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
1386         break;
1387     default:
1388         if (type >= GST_MPEG_VIDEO_PACKET_SLICE_MIN &&
1389             type <= GST_MPEG_VIDEO_PACKET_SLICE_MAX) {
1390             flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE;
1391             switch (type2) {
1392             case GST_MPEG_VIDEO_PACKET_USER_DATA:
1393             case GST_MPEG_VIDEO_PACKET_SEQUENCE:
1394             case GST_MPEG_VIDEO_PACKET_GOP:
1395             case GST_MPEG_VIDEO_PACKET_PICTURE:
1396                 flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END;
1397                 break;
1398             default:
1399                 break;
1400             }
1401         }
1402
1403         // Ignore system start codes (PES headers)
1404         else if (type >= 0xb9 && type <= 0xff)
1405             flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP;
1406         break;
1407     }
1408     GST_VAAPI_DECODER_UNIT_FLAG_SET(unit, flags);
1409     return GST_VAAPI_DECODER_STATUS_SUCCESS;
1410 }
1411
1412 static GstVaapiDecoderStatus
1413 gst_vaapi_decoder_mpeg2_decode(GstVaapiDecoder *base_decoder,
1414     GstVaapiDecoderUnit *unit)
1415 {
1416     GstVaapiDecoderMpeg2 * const decoder =
1417         GST_VAAPI_DECODER_MPEG2_CAST(base_decoder);
1418     GstVaapiDecoderStatus status;
1419     GstMpegVideoPacket packet;
1420     GstBuffer * const buffer =
1421         GST_VAAPI_DECODER_CODEC_FRAME(decoder)->input_buffer;
1422     GstMapInfo map_info;
1423
1424     status = ensure_decoder(decoder);
1425     if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
1426         return status;
1427
1428     if (!gst_buffer_map(buffer, &map_info, GST_MAP_READ)) {
1429         GST_ERROR("failed to map buffer");
1430         return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
1431     }
1432
1433     packet.data = map_info.data + unit->offset;
1434     packet.size = unit->size;
1435     packet.type = packet.data[3];
1436     packet.offset = 4;
1437
1438     status = parse_unit(decoder, unit, &packet);
1439     gst_buffer_unmap(buffer, &map_info);
1440     if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
1441         return status;
1442     return decode_unit(decoder, unit, &packet);
1443 }
1444
1445 static GstVaapiDecoderStatus
1446 gst_vaapi_decoder_mpeg2_start_frame(GstVaapiDecoder *base_decoder,
1447     GstVaapiDecoderUnit *base_unit)
1448 {
1449     GstVaapiDecoderMpeg2 * const decoder =
1450         GST_VAAPI_DECODER_MPEG2_CAST(base_decoder);
1451     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
1452     GstMpegVideoSequenceHdr *seq_hdr;
1453     GstMpegVideoSequenceExt *seq_ext;
1454     GstMpegVideoSequenceDisplayExt *seq_display_ext;
1455     GstVaapiPicture *picture;
1456     GstVaapiDecoderStatus status;
1457
1458     if (!is_valid_state(decoder, GST_MPEG_VIDEO_STATE_VALID_PIC_HEADERS))
1459         return GST_VAAPI_DECODER_STATUS_SUCCESS;
1460     priv->state &= ~GST_MPEG_VIDEO_STATE_VALID_PIC_HEADERS;
1461
1462     seq_hdr = &priv->seq_hdr->data.seq_hdr;
1463     seq_ext = priv->seq_ext ? &priv->seq_ext->data.seq_ext : NULL;
1464     seq_display_ext = priv->seq_display_ext ?
1465         &priv->seq_display_ext->data.seq_display_ext : NULL;
1466     if (gst_mpeg_video_finalise_mpeg2_sequence_header(seq_hdr, seq_ext,
1467             seq_display_ext))
1468         gst_vaapi_decoder_set_pixel_aspect_ratio(base_decoder,
1469             seq_hdr->par_w, seq_hdr->par_h);
1470
1471     status = ensure_context(decoder);
1472     if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
1473         GST_ERROR("failed to reset context");
1474         return status;
1475     }
1476
1477     if (priv->current_picture) {
1478         /* Re-use current picture where the first field was decoded */
1479         picture = gst_vaapi_picture_new_field(priv->current_picture);
1480         if (!picture) {
1481             GST_ERROR("failed to allocate field picture");
1482             return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
1483         }
1484     }
1485     else {
1486         /* Create new picture */
1487         picture = GST_VAAPI_PICTURE_NEW(MPEG2, decoder);
1488         if (!picture) {
1489             GST_ERROR("failed to allocate picture");
1490             return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
1491         }
1492     }
1493     gst_vaapi_picture_replace(&priv->current_picture, picture);
1494     gst_vaapi_picture_unref(picture);
1495
1496     /* Update cropping rectangle */
1497     /* XXX: handle picture_display_extension() */
1498     if (seq_display_ext && priv->pic_display_ext) {
1499         GstVaapiRectangle * const crop_rect = &priv->crop_rect;
1500         if (crop_rect->x + crop_rect->width <= priv->width &&
1501             crop_rect->y + crop_rect->height <= priv->height)
1502             gst_vaapi_picture_set_crop_rect(picture, crop_rect);
1503     }
1504
1505     status = ensure_quant_matrix(decoder, picture);
1506     if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
1507         GST_ERROR("failed to reset quantizer matrix");
1508         return status;
1509     }
1510
1511     status = init_picture(decoder, picture);
1512     if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
1513         return status;
1514
1515     fill_picture(decoder, picture);
1516
1517     priv->state |= GST_MPEG_VIDEO_STATE_VALID_PIC_HEADERS;
1518     return GST_VAAPI_DECODER_STATUS_SUCCESS;
1519 }
1520
1521 static GstVaapiDecoderStatus
1522 gst_vaapi_decoder_mpeg2_end_frame(GstVaapiDecoder *base_decoder)
1523 {
1524     GstVaapiDecoderMpeg2 * const decoder =
1525         GST_VAAPI_DECODER_MPEG2_CAST(base_decoder);
1526
1527     return decode_current_picture(decoder);
1528 }
1529
1530 static GstVaapiDecoderStatus
1531 gst_vaapi_decoder_mpeg2_flush(GstVaapiDecoder *base_decoder)
1532 {
1533     GstVaapiDecoderMpeg2 * const decoder =
1534         GST_VAAPI_DECODER_MPEG2_CAST(base_decoder);
1535     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
1536
1537     gst_vaapi_dpb_flush(priv->dpb);
1538     return GST_VAAPI_DECODER_STATUS_SUCCESS;
1539 }
1540
1541 static void
1542 gst_vaapi_decoder_mpeg2_class_init(GstVaapiDecoderMpeg2Class *klass)
1543 {
1544     GstVaapiMiniObjectClass * const object_class =
1545         GST_VAAPI_MINI_OBJECT_CLASS(klass);
1546     GstVaapiDecoderClass * const decoder_class = GST_VAAPI_DECODER_CLASS(klass);
1547
1548     object_class->size          = sizeof(GstVaapiDecoderMpeg2);
1549     object_class->finalize      = (GDestroyNotify)gst_vaapi_decoder_finalize;
1550
1551     decoder_class->create       = gst_vaapi_decoder_mpeg2_create;
1552     decoder_class->destroy      = gst_vaapi_decoder_mpeg2_destroy;
1553     decoder_class->parse        = gst_vaapi_decoder_mpeg2_parse;
1554     decoder_class->decode       = gst_vaapi_decoder_mpeg2_decode;
1555     decoder_class->start_frame  = gst_vaapi_decoder_mpeg2_start_frame;
1556     decoder_class->end_frame    = gst_vaapi_decoder_mpeg2_end_frame;
1557     decoder_class->flush        = gst_vaapi_decoder_mpeg2_flush;
1558 }
1559
1560 static inline const GstVaapiDecoderClass *
1561 gst_vaapi_decoder_mpeg2_class(void)
1562 {
1563     static GstVaapiDecoderMpeg2Class g_class;
1564     static gsize g_class_init = FALSE;
1565
1566     if (g_once_init_enter(&g_class_init)) {
1567         gst_vaapi_decoder_mpeg2_class_init(&g_class);
1568         g_once_init_leave(&g_class_init, TRUE);
1569     }
1570     return GST_VAAPI_DECODER_CLASS(&g_class);
1571 }
1572
1573 /**
1574  * gst_vaapi_decoder_mpeg2_new:
1575  * @display: a #GstVaapiDisplay
1576  * @caps: a #GstCaps holding codec information
1577  *
1578  * Creates a new #GstVaapiDecoder for MPEG-2 decoding.  The @caps can
1579  * hold extra information like codec-data and pictured coded size.
1580  *
1581  * Return value: the newly allocated #GstVaapiDecoder object
1582  */
1583 GstVaapiDecoder *
1584 gst_vaapi_decoder_mpeg2_new(GstVaapiDisplay *display, GstCaps *caps)
1585 {
1586     return gst_vaapi_decoder_new(gst_vaapi_decoder_mpeg2_class(),
1587         display, caps);
1588 }