Userful gstreamer-vaapi
[vaapi:cpu-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.width      = priv->width;
439         info.height     = priv->height;
440         info.ref_frames = 2;
441         reset_context   = gst_vaapi_decoder_ensure_context(
442             GST_VAAPI_DECODER_CAST(decoder),
443             &info
444         );
445         if (!reset_context)
446             return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
447     }
448     return GST_VAAPI_DECODER_STATUS_SUCCESS;
449 }
450
451 static GstVaapiDecoderStatus
452 ensure_quant_matrix(GstVaapiDecoderMpeg2 *decoder, GstVaapiPicture *picture)
453 {
454     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
455     GstMpegVideoSequenceHdr * const seq_hdr = &priv->seq_hdr->data.seq_hdr;
456     VAIQMatrixBufferMPEG2 *iq_matrix;
457     guint8 *intra_quant_matrix = NULL;
458     guint8 *non_intra_quant_matrix = NULL;
459     guint8 *chroma_intra_quant_matrix = NULL;
460     guint8 *chroma_non_intra_quant_matrix = NULL;
461
462     if (!priv->quant_matrix_changed)
463         return GST_VAAPI_DECODER_STATUS_SUCCESS;
464
465     priv->quant_matrix_changed = FALSE;
466
467     picture->iq_matrix = GST_VAAPI_IQ_MATRIX_NEW(MPEG2, decoder);
468     if (!picture->iq_matrix) {
469         GST_ERROR("failed to allocate IQ matrix");
470         return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
471     }
472     iq_matrix = picture->iq_matrix->param;
473
474     intra_quant_matrix     = seq_hdr->intra_quantizer_matrix;
475     non_intra_quant_matrix = seq_hdr->non_intra_quantizer_matrix;
476
477     if (priv->quant_matrix) {
478         GstMpegVideoQuantMatrixExt * const quant_matrix =
479             &priv->quant_matrix->data.quant_matrix;
480         if (quant_matrix->load_intra_quantiser_matrix)
481             intra_quant_matrix = quant_matrix->intra_quantiser_matrix;
482         if (quant_matrix->load_non_intra_quantiser_matrix)
483             non_intra_quant_matrix = quant_matrix->non_intra_quantiser_matrix;
484         if (quant_matrix->load_chroma_intra_quantiser_matrix)
485             chroma_intra_quant_matrix = quant_matrix->chroma_intra_quantiser_matrix;
486         if (quant_matrix->load_chroma_non_intra_quantiser_matrix)
487             chroma_non_intra_quant_matrix = quant_matrix->chroma_non_intra_quantiser_matrix;
488     }
489
490     iq_matrix->load_intra_quantiser_matrix = intra_quant_matrix != NULL;
491     if (intra_quant_matrix)
492         copy_quant_matrix(iq_matrix->intra_quantiser_matrix,
493                           intra_quant_matrix);
494
495     iq_matrix->load_non_intra_quantiser_matrix = non_intra_quant_matrix != NULL;
496     if (non_intra_quant_matrix)
497         copy_quant_matrix(iq_matrix->non_intra_quantiser_matrix,
498                           non_intra_quant_matrix);
499
500     iq_matrix->load_chroma_intra_quantiser_matrix = chroma_intra_quant_matrix != NULL;
501     if (chroma_intra_quant_matrix)
502         copy_quant_matrix(iq_matrix->chroma_intra_quantiser_matrix,
503                           chroma_intra_quant_matrix);
504
505     iq_matrix->load_chroma_non_intra_quantiser_matrix = chroma_non_intra_quant_matrix != NULL;
506     if (chroma_non_intra_quant_matrix)
507         copy_quant_matrix(iq_matrix->chroma_non_intra_quantiser_matrix,
508                           chroma_non_intra_quant_matrix);
509     return GST_VAAPI_DECODER_STATUS_SUCCESS;
510 }
511
512 static inline gboolean
513 is_valid_state(GstVaapiDecoderMpeg2 *decoder, guint state)
514 {
515     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
516
517     return (priv->state & state) == state;
518 }
519
520 static GstVaapiDecoderStatus
521 decode_current_picture(GstVaapiDecoderMpeg2 *decoder)
522 {
523     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
524     GstVaapiPicture * const picture = priv->current_picture;
525
526     if (!is_valid_state(decoder, GST_MPEG_VIDEO_STATE_VALID_PICTURE))
527         goto drop_frame;
528     priv->state &= GST_MPEG_VIDEO_STATE_VALID_SEQ_HEADERS;
529
530     if (!picture)
531         return GST_VAAPI_DECODER_STATUS_SUCCESS;
532
533     if (!gst_vaapi_picture_decode(picture))
534         goto error;
535     if (GST_VAAPI_PICTURE_IS_COMPLETE(picture)) {
536         if (!gst_vaapi_dpb_add(priv->dpb, picture))
537             goto error;
538         gst_vaapi_picture_replace(&priv->current_picture, NULL);
539     }
540     return GST_VAAPI_DECODER_STATUS_SUCCESS;
541
542 error:
543     /* XXX: fix for cases where first field failed to be decoded */
544     gst_vaapi_picture_replace(&priv->current_picture, NULL);
545     return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
546
547 drop_frame:
548     priv->state &= GST_MPEG_VIDEO_STATE_VALID_SEQ_HEADERS;
549     return GST_VAAPI_DECODER_STATUS_DROP_FRAME;
550 }
551
552 static GstVaapiDecoderStatus
553 parse_sequence(GstVaapiDecoderMpeg2 *decoder,
554     GstVaapiDecoderUnit *unit, const GstMpegVideoPacket *packet)
555 {
556     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
557     GstMpegVideoSequenceHdr *seq_hdr;
558
559     priv->state = 0;
560
561     if (!gst_vaapi_parser_info_mpeg2_ensure(&priv->seq_hdr)) {
562         GST_ERROR("failed to allocate parser info for sequence header");
563         return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
564     }
565
566     seq_hdr = &priv->seq_hdr->data.seq_hdr;
567
568     if (!gst_mpeg_video_packet_parse_sequence_header(packet, seq_hdr)) {
569         GST_ERROR("failed to parse sequence header");
570         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
571     }
572
573     gst_vaapi_decoder_unit_set_parsed_info(unit, seq_hdr, NULL);
574     return GST_VAAPI_DECODER_STATUS_SUCCESS;
575 }
576
577 static GstVaapiDecoderStatus
578 decode_sequence(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnit *unit)
579 {
580     GstVaapiDecoder * const base_decoder = GST_VAAPI_DECODER_CAST(decoder);
581     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
582     GstMpegVideoSequenceHdr * const seq_hdr = unit->parsed_info;
583
584     gst_vaapi_parser_info_mpeg2_replace(&priv->seq_ext, NULL);
585     gst_vaapi_parser_info_mpeg2_replace(&priv->seq_display_ext, NULL);
586     gst_vaapi_parser_info_mpeg2_replace(&priv->seq_scalable_ext, NULL);
587     gst_vaapi_parser_info_mpeg2_replace(&priv->quant_matrix, NULL);
588     gst_vaapi_parser_info_mpeg2_replace(&priv->pic_display_ext, NULL);
589
590     priv->fps_n = seq_hdr->fps_n;
591     priv->fps_d = seq_hdr->fps_d;
592     pts_set_framerate(&priv->tsg, priv->fps_n, priv->fps_d);
593     gst_vaapi_decoder_set_framerate(base_decoder, priv->fps_n, priv->fps_d);
594
595     priv->width                 = seq_hdr->width;
596     priv->height                = seq_hdr->height;
597     priv->size_changed          = TRUE;
598     priv->quant_matrix_changed  = TRUE;
599     priv->progressive_sequence  = TRUE;
600
601     priv->state |= GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR;
602     return GST_VAAPI_DECODER_STATUS_SUCCESS;
603 }
604
605 static GstVaapiDecoderStatus
606 parse_sequence_ext(GstVaapiDecoderMpeg2 *decoder,
607     GstVaapiDecoderUnit *unit, const GstMpegVideoPacket *packet)
608 {
609     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
610     GstMpegVideoSequenceExt *seq_ext;
611
612     priv->state &= GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR;
613
614     if (!gst_vaapi_parser_info_mpeg2_ensure(&priv->seq_ext)) {
615         GST_ERROR("failed to allocate parser info for sequence extension");
616         return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
617     }
618
619     seq_ext = &priv->seq_ext->data.seq_ext;
620
621     if (!gst_mpeg_video_packet_parse_sequence_extension(packet, seq_ext)) {
622         GST_ERROR("failed to parse sequence-extension");
623         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
624     }
625
626     gst_vaapi_decoder_unit_set_parsed_info(unit, seq_ext, NULL);
627     return GST_VAAPI_DECODER_STATUS_SUCCESS;
628 }
629
630 static GstVaapiDecoderStatus
631 decode_sequence_ext(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnit *unit)
632 {
633     GstVaapiDecoder * const base_decoder = GST_VAAPI_DECODER_CAST(decoder);
634     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
635     GstMpegVideoSequenceExt * const seq_ext = unit->parsed_info;
636     GstVaapiProfile profile;
637     guint width, height;
638
639     if (!is_valid_state(decoder, GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR))
640         return GST_VAAPI_DECODER_STATUS_SUCCESS;
641
642     priv->progressive_sequence = seq_ext->progressive;
643     gst_vaapi_decoder_set_interlaced(base_decoder, !priv->progressive_sequence);
644
645     width  = (priv->width  & 0x0fff) | ((guint32)seq_ext->horiz_size_ext << 12);
646     height = (priv->height & 0x0fff) | ((guint32)seq_ext->vert_size_ext  << 12);
647     GST_DEBUG("video resolution %ux%u", width, height);
648
649     if (seq_ext->fps_n_ext && seq_ext->fps_d_ext) {
650         priv->fps_n *= seq_ext->fps_n_ext + 1;
651         priv->fps_d *= seq_ext->fps_d_ext + 1;
652         pts_set_framerate(&priv->tsg, priv->fps_n, priv->fps_d);
653         gst_vaapi_decoder_set_framerate(base_decoder, priv->fps_n, priv->fps_d);
654     }
655
656     if (priv->width != width) {
657         priv->width = width;
658         priv->size_changed = TRUE;
659     }
660
661     if (priv->height != height) {
662         priv->height = height;
663         priv->size_changed = TRUE;
664     }
665
666     switch (seq_ext->profile) {
667     case GST_MPEG_VIDEO_PROFILE_SIMPLE:
668         profile = GST_VAAPI_PROFILE_MPEG2_SIMPLE;
669         break;
670     case GST_MPEG_VIDEO_PROFILE_MAIN:
671         profile = GST_VAAPI_PROFILE_MPEG2_MAIN;
672         break;
673     case GST_MPEG_VIDEO_PROFILE_HIGH:
674         profile = GST_VAAPI_PROFILE_MPEG2_HIGH;
675         break;
676     default:
677         GST_ERROR("unsupported profile %d", seq_ext->profile);
678         return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
679     }
680     if (priv->profile != profile) {
681         priv->profile = profile;
682         priv->profile_changed = TRUE;
683     }
684
685     priv->state |= GST_MPEG_VIDEO_STATE_GOT_SEQ_EXT;
686     return GST_VAAPI_DECODER_STATUS_SUCCESS;
687 }
688
689 static GstVaapiDecoderStatus
690 parse_sequence_display_ext(GstVaapiDecoderMpeg2 *decoder,
691     GstVaapiDecoderUnit *unit, const GstMpegVideoPacket *packet)
692 {
693     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
694     GstMpegVideoSequenceDisplayExt *seq_display_ext;
695
696     if (!gst_vaapi_parser_info_mpeg2_ensure(&priv->seq_display_ext)) {
697         GST_ERROR("failed to allocate parser info for sequence display extension");
698         return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
699     }
700
701     seq_display_ext = &priv->seq_display_ext->data.seq_display_ext;
702
703     if (!gst_mpeg_video_packet_parse_sequence_display_extension(packet,
704             seq_display_ext)) {
705         GST_ERROR("failed to parse sequence-display-extension");
706         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
707     }
708
709     gst_vaapi_decoder_unit_set_parsed_info(unit, seq_display_ext, NULL);
710     return GST_VAAPI_DECODER_STATUS_SUCCESS;
711 }
712
713 static GstVaapiDecoderStatus
714 decode_sequence_display_ext(GstVaapiDecoderMpeg2 *decoder,
715     GstVaapiDecoderUnit *unit)
716 {
717     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
718     GstMpegVideoSequenceDisplayExt *seq_display_ext;
719
720     seq_display_ext = priv->seq_display_ext ?
721         &priv->seq_display_ext->data.seq_display_ext : NULL;
722
723     /* Update cropping rectangle */
724     if (seq_display_ext) {
725         GstVaapiRectangle * const crop_rect = &priv->crop_rect;
726         crop_rect->x = 0;
727         crop_rect->y = 0;
728         crop_rect->width = seq_display_ext->display_horizontal_size;
729         crop_rect->height = seq_display_ext->display_vertical_size;
730     }
731
732     /* XXX: handle color primaries */
733     return GST_VAAPI_DECODER_STATUS_SUCCESS;
734 }
735
736 static GstVaapiDecoderStatus
737 parse_sequence_scalable_ext(GstVaapiDecoderMpeg2 *decoder,
738     GstVaapiDecoderUnit *unit, const GstMpegVideoPacket *packet)
739 {
740     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
741     GstMpegVideoSequenceScalableExt *seq_scalable_ext;
742
743     if (!gst_vaapi_parser_info_mpeg2_ensure(&priv->seq_scalable_ext)) {
744         GST_ERROR("failed to allocate parser info for sequence scalable extension");
745         return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
746     }
747
748     seq_scalable_ext = &priv->seq_scalable_ext->data.seq_scalable_ext;
749
750     if (!gst_mpeg_video_packet_parse_sequence_scalable_extension(packet,
751             seq_scalable_ext)) {
752         GST_ERROR("failed to parse sequence-scalable-extension");
753         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
754     }
755
756     gst_vaapi_decoder_unit_set_parsed_info(unit, seq_scalable_ext, NULL);
757     return GST_VAAPI_DECODER_STATUS_SUCCESS;
758 }
759
760 static GstVaapiDecoderStatus
761 decode_sequence_scalable_ext(GstVaapiDecoderMpeg2 *decoder,
762     GstVaapiDecoderUnit *unit)
763 {
764     /* XXX: unsupported header -- ignore */
765     return GST_VAAPI_DECODER_STATUS_SUCCESS;
766 }
767
768 static GstVaapiDecoderStatus
769 decode_sequence_end(GstVaapiDecoderMpeg2 *decoder)
770 {
771     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
772
773     gst_vaapi_dpb_flush(priv->dpb);
774     return GST_VAAPI_DECODER_STATUS_SUCCESS;
775 }
776
777 static GstVaapiDecoderStatus
778 parse_quant_matrix_ext(GstVaapiDecoderMpeg2 *decoder,
779     GstVaapiDecoderUnit *unit, const GstMpegVideoPacket *packet)
780 {
781     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
782     GstMpegVideoQuantMatrixExt *quant_matrix;
783
784     if (!gst_vaapi_parser_info_mpeg2_ensure(&priv->quant_matrix)) {
785         GST_ERROR("failed to allocate parser info for quantization matrix");
786         return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
787     }
788
789     quant_matrix = &priv->quant_matrix->data.quant_matrix;
790
791     if (!gst_mpeg_video_packet_parse_quant_matrix_extension(packet,
792             quant_matrix)) {
793         GST_ERROR("failed to parse quant-matrix-extension");
794         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
795     }
796
797     gst_vaapi_decoder_unit_set_parsed_info(unit, quant_matrix, NULL);
798     return GST_VAAPI_DECODER_STATUS_SUCCESS;
799 }
800
801 static GstVaapiDecoderStatus
802 decode_quant_matrix_ext(GstVaapiDecoderMpeg2 *decoder,
803     GstVaapiDecoderUnit *unit)
804 {
805     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
806
807     priv->quant_matrix_changed = TRUE;
808     return GST_VAAPI_DECODER_STATUS_SUCCESS;
809 }
810
811 static GstVaapiDecoderStatus
812 parse_gop(GstVaapiDecoderMpeg2 *decoder,
813     GstVaapiDecoderUnit *unit, const GstMpegVideoPacket *packet)
814 {
815     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
816     GstMpegVideoGop *gop;
817
818     if (!gst_vaapi_parser_info_mpeg2_ensure(&priv->gop)) {
819         GST_ERROR("failed to allocate parser info for GOP");
820         return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
821     }
822
823     gop = &priv->gop->data.gop;
824
825     if (!gst_mpeg_video_packet_parse_gop(packet, gop)) {
826         GST_ERROR("failed to parse GOP");
827         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
828     }
829
830     gst_vaapi_decoder_unit_set_parsed_info(unit, gop, NULL);
831     return GST_VAAPI_DECODER_STATUS_SUCCESS;
832 }
833
834 static GstVaapiDecoderStatus
835 decode_gop(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnit *unit)
836 {
837     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
838     GstMpegVideoGop * const gop = unit->parsed_info;
839
840     priv->closed_gop  = gop->closed_gop;
841     priv->broken_link = gop->broken_link;
842
843     GST_DEBUG("GOP %02u:%02u:%02u:%02u (closed_gop %d, broken_link %d)",
844               gop->hour, gop->minute, gop->second, gop->frame,
845               priv->closed_gop, priv->broken_link);
846
847     pts_sync(&priv->tsg, GST_VAAPI_DECODER_CODEC_FRAME(decoder)->pts);
848     return GST_VAAPI_DECODER_STATUS_SUCCESS;
849 }
850
851 static GstVaapiDecoderStatus
852 parse_picture(GstVaapiDecoderMpeg2 *decoder,
853     GstVaapiDecoderUnit *unit, const GstMpegVideoPacket *packet)
854 {
855     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
856     GstMpegVideoPictureHdr *pic_hdr;
857
858     priv->state &= (GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR|
859                     GST_MPEG_VIDEO_STATE_GOT_SEQ_EXT);
860
861     if (!gst_vaapi_parser_info_mpeg2_ensure(&priv->pic_hdr)) {
862         GST_ERROR("failed to allocate parser info for picture header");
863         return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
864     }
865
866     pic_hdr = &priv->pic_hdr->data.pic_hdr;
867
868     if (!gst_mpeg_video_packet_parse_picture_header(packet, pic_hdr)) {
869         GST_ERROR("failed to parse picture header");
870         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
871     }
872
873     gst_vaapi_decoder_unit_set_parsed_info(unit, pic_hdr, NULL);
874     return GST_VAAPI_DECODER_STATUS_SUCCESS;
875 }
876
877 static GstVaapiDecoderStatus
878 decode_picture(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnit *unit)
879 {
880     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
881
882     if (!is_valid_state(decoder, GST_MPEG_VIDEO_STATE_VALID_SEQ_HEADERS))
883         return GST_VAAPI_DECODER_STATUS_SUCCESS;
884
885     gst_vaapi_parser_info_mpeg2_replace(&priv->pic_ext, NULL);
886
887     priv->state |= GST_MPEG_VIDEO_STATE_GOT_PIC_HDR;
888     return GST_VAAPI_DECODER_STATUS_SUCCESS;
889 }
890
891 static GstVaapiDecoderStatus
892 parse_picture_ext(GstVaapiDecoderMpeg2 *decoder,
893     GstVaapiDecoderUnit *unit, const GstMpegVideoPacket *packet)
894 {
895     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
896     GstMpegVideoPictureExt *pic_ext;
897
898     priv->state &= (GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR|
899                     GST_MPEG_VIDEO_STATE_GOT_SEQ_EXT|
900                     GST_MPEG_VIDEO_STATE_GOT_PIC_HDR);
901
902     if (!gst_vaapi_parser_info_mpeg2_ensure(&priv->pic_ext)) {
903         GST_ERROR("failed to allocate parser info for picture extension");
904         return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
905     }
906
907     pic_ext = &priv->pic_ext->data.pic_ext;
908
909     if (!gst_mpeg_video_packet_parse_picture_extension(packet, pic_ext)) {
910         GST_ERROR("failed to parse picture-extension");
911         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
912     }
913
914     gst_vaapi_decoder_unit_set_parsed_info(unit, pic_ext, NULL);
915     return GST_VAAPI_DECODER_STATUS_SUCCESS;
916 }
917
918 static GstVaapiDecoderStatus
919 decode_picture_ext(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnit *unit)
920 {
921     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
922     GstMpegVideoPictureExt * const pic_ext = unit->parsed_info;
923
924     if (!is_valid_state(decoder, GST_MPEG_VIDEO_STATE_GOT_PIC_HDR))
925         return GST_VAAPI_DECODER_STATUS_SUCCESS;
926
927     if (priv->progressive_sequence && !pic_ext->progressive_frame) {
928         GST_WARNING("invalid interlaced frame in progressive sequence, fixing");
929         pic_ext->progressive_frame = 1;
930     }
931
932     if (pic_ext->picture_structure == 0 ||
933         (pic_ext->progressive_frame &&
934          pic_ext->picture_structure != GST_MPEG_VIDEO_PICTURE_STRUCTURE_FRAME)) {
935         GST_WARNING("invalid picture_structure %d, replacing with \"frame\"",
936                     pic_ext->picture_structure);
937         pic_ext->picture_structure = GST_MPEG_VIDEO_PICTURE_STRUCTURE_FRAME;
938     }
939
940     priv->state |= GST_MPEG_VIDEO_STATE_GOT_PIC_EXT;
941     return GST_VAAPI_DECODER_STATUS_SUCCESS;
942 }
943
944 static inline guint32
945 pack_f_code(guint8 f_code[2][2])
946 {
947     return (((guint32)f_code[0][0] << 12) |
948             ((guint32)f_code[0][1] <<  8) |
949             ((guint32)f_code[1][0] <<  4) |
950             (         f_code[1][1]      ));
951 }
952
953 static GstVaapiDecoderStatus
954 init_picture(GstVaapiDecoderMpeg2 *decoder, GstVaapiPicture *picture)
955 {
956     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
957     GstMpegVideoPictureHdr * const pic_hdr = &priv->pic_hdr->data.pic_hdr;
958     GstMpegVideoPictureExt * const pic_ext = &priv->pic_ext->data.pic_ext;
959
960     switch (pic_hdr->pic_type) {
961     case GST_MPEG_VIDEO_PICTURE_TYPE_I:
962         GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_REFERENCE);
963         picture->type = GST_VAAPI_PICTURE_TYPE_I;
964         break;
965     case GST_MPEG_VIDEO_PICTURE_TYPE_P:
966         GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_REFERENCE);
967         picture->type = GST_VAAPI_PICTURE_TYPE_P;
968         break;
969     case GST_MPEG_VIDEO_PICTURE_TYPE_B:
970         picture->type = GST_VAAPI_PICTURE_TYPE_B;
971         break;
972     default:
973         GST_ERROR("unsupported picture type %d", pic_hdr->pic_type);
974         return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
975     }
976
977     if (!priv->progressive_sequence && !pic_ext->progressive_frame) {
978         GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_INTERLACED);
979         if (pic_ext->top_field_first)
980             GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_TFF);
981     }
982
983     switch (pic_ext->picture_structure) {
984     case GST_MPEG_VIDEO_PICTURE_STRUCTURE_TOP_FIELD:
985         picture->structure = GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD;
986         break;
987     case GST_MPEG_VIDEO_PICTURE_STRUCTURE_BOTTOM_FIELD:
988         picture->structure = GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD;
989         break;
990     case GST_MPEG_VIDEO_PICTURE_STRUCTURE_FRAME:
991         picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
992         break;
993     }
994
995     /* Allocate dummy picture for first field based I-frame */
996     if (picture->type == GST_VAAPI_PICTURE_TYPE_I &&
997         !GST_VAAPI_PICTURE_IS_FRAME(picture) &&
998         gst_vaapi_dpb_size(priv->dpb) == 0) {
999         GstVaapiPicture *dummy_picture;
1000         gboolean success;
1001
1002         dummy_picture = GST_VAAPI_PICTURE_NEW(MPEG2, decoder);
1003         if (!dummy_picture) {
1004             GST_ERROR("failed to allocate dummy picture");
1005             return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
1006         }
1007
1008         dummy_picture->type      = GST_VAAPI_PICTURE_TYPE_I;
1009         dummy_picture->pts       = GST_CLOCK_TIME_NONE;
1010         dummy_picture->poc       = -1;
1011         dummy_picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
1012
1013         GST_VAAPI_PICTURE_FLAG_SET(
1014             dummy_picture,
1015             (GST_VAAPI_PICTURE_FLAG_SKIPPED |
1016              GST_VAAPI_PICTURE_FLAG_OUTPUT  |
1017              GST_VAAPI_PICTURE_FLAG_REFERENCE)
1018         );
1019
1020         success = gst_vaapi_dpb_add(priv->dpb, dummy_picture);
1021         gst_vaapi_picture_unref(dummy_picture);
1022         if (!success) {
1023             GST_ERROR("failed to add dummy picture into DPB");
1024             return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
1025         }
1026         GST_INFO("allocated dummy picture for first field based I-frame");
1027     }
1028
1029     /* Update presentation time */
1030     picture->pts = pts_eval(&priv->tsg,
1031         GST_VAAPI_DECODER_CODEC_FRAME(decoder)->pts, pic_hdr->tsn);
1032     picture->poc = pts_get_poc(&priv->tsg);
1033     return GST_VAAPI_DECODER_STATUS_SUCCESS;
1034 }
1035
1036 static void
1037 fill_picture(GstVaapiDecoderMpeg2 *decoder, GstVaapiPicture *picture)
1038 {
1039     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
1040     VAPictureParameterBufferMPEG2 * const pic_param = picture->param;
1041     GstMpegVideoPictureHdr * const pic_hdr = &priv->pic_hdr->data.pic_hdr;
1042     GstMpegVideoPictureExt * const pic_ext = &priv->pic_ext->data.pic_ext;
1043     GstVaapiPicture *prev_picture, *next_picture;
1044
1045     /* Fill in VAPictureParameterBufferMPEG2 */
1046     pic_param->horizontal_size            = priv->width;
1047     pic_param->vertical_size              = priv->height;
1048     pic_param->forward_reference_picture  = VA_INVALID_ID;
1049     pic_param->backward_reference_picture = VA_INVALID_ID;
1050     pic_param->picture_coding_type        = pic_hdr->pic_type;
1051     pic_param->f_code                     = pack_f_code(pic_ext->f_code);
1052
1053 #define COPY_FIELD(a, b, f) \
1054     pic_param->a.b.f = pic_ext->f
1055     pic_param->picture_coding_extension.value = 0;
1056     pic_param->picture_coding_extension.bits.is_first_field =
1057         GST_VAAPI_PICTURE_IS_FIRST_FIELD(picture);
1058     COPY_FIELD(picture_coding_extension, bits, intra_dc_precision);
1059     COPY_FIELD(picture_coding_extension, bits, picture_structure);
1060     COPY_FIELD(picture_coding_extension, bits, top_field_first);
1061     COPY_FIELD(picture_coding_extension, bits, frame_pred_frame_dct);
1062     COPY_FIELD(picture_coding_extension, bits, concealment_motion_vectors);
1063     COPY_FIELD(picture_coding_extension, bits, q_scale_type);
1064     COPY_FIELD(picture_coding_extension, bits, intra_vlc_format);
1065     COPY_FIELD(picture_coding_extension, bits, alternate_scan);
1066     COPY_FIELD(picture_coding_extension, bits, repeat_first_field);
1067     COPY_FIELD(picture_coding_extension, bits, progressive_frame);
1068
1069     gst_vaapi_dpb_get_neighbours(priv->dpb, picture,
1070         &prev_picture, &next_picture);
1071
1072     switch (pic_hdr->pic_type) {
1073     case GST_MPEG_VIDEO_PICTURE_TYPE_B:
1074         if (next_picture)
1075             pic_param->backward_reference_picture = next_picture->surface_id;
1076         if (prev_picture)
1077             pic_param->forward_reference_picture = prev_picture->surface_id;
1078         else if (!priv->closed_gop)
1079             GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_SKIPPED);
1080         break;
1081     case GST_MPEG_VIDEO_PICTURE_TYPE_P:
1082         if (prev_picture)
1083             pic_param->forward_reference_picture = prev_picture->surface_id;
1084         break;
1085     }
1086 }
1087
1088 static GstVaapiDecoderStatus
1089 parse_slice(GstVaapiDecoderMpeg2 *decoder,
1090     GstVaapiDecoderUnit *unit, const GstMpegVideoPacket *packet)
1091 {
1092     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
1093     GstMpegVideoSliceHdr *slice_hdr;
1094     GstMpegVideoSequenceHdr *seq_hdr;
1095     GstMpegVideoSequenceScalableExt *seq_scalable_ext;
1096
1097     priv->state &= (GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR|
1098                     GST_MPEG_VIDEO_STATE_GOT_SEQ_EXT|
1099                     GST_MPEG_VIDEO_STATE_GOT_PIC_HDR|
1100                     GST_MPEG_VIDEO_STATE_GOT_PIC_EXT);
1101
1102     if (!gst_vaapi_parser_info_mpeg2_ensure(&priv->slice_hdr)) {
1103         GST_ERROR("failed to allocate parser info for slice header");
1104         return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
1105     }
1106
1107     slice_hdr = &priv->slice_hdr->data.slice_hdr;
1108     seq_hdr = &priv->seq_hdr->data.seq_hdr;
1109     seq_scalable_ext = priv->seq_scalable_ext ?
1110         &priv->seq_scalable_ext->data.seq_scalable_ext : NULL;
1111
1112     if (!gst_mpeg_video_packet_parse_slice_header(packet, slice_hdr,
1113             seq_hdr, seq_scalable_ext)) {
1114         GST_ERROR("failed to parse slice header");
1115         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
1116     }
1117
1118     gst_vaapi_decoder_unit_set_parsed_info(unit, slice_hdr, NULL);
1119     return GST_VAAPI_DECODER_STATUS_SUCCESS;
1120 }
1121
1122 static GstVaapiDecoderStatus
1123 decode_slice(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnit *unit)
1124 {
1125     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
1126     GstVaapiPicture * const picture = priv->current_picture;
1127     GstVaapiSlice *slice;
1128     VASliceParameterBufferMPEG2 *slice_param;
1129     GstMpegVideoSliceHdr * const slice_hdr = unit->parsed_info;
1130     GstBuffer * const buffer =
1131         GST_VAAPI_DECODER_CODEC_FRAME(decoder)->input_buffer;
1132     GstMapInfo map_info;
1133
1134     GST_DEBUG("slice %d (%u bytes)", slice_hdr->mb_row, unit->size);
1135
1136     if (!is_valid_state(decoder, GST_MPEG_VIDEO_STATE_VALID_PIC_HEADERS))
1137         return GST_VAAPI_DECODER_STATUS_SUCCESS;
1138
1139     if (!gst_buffer_map(buffer, &map_info, GST_MAP_READ)) {
1140         GST_ERROR("failed to map buffer");
1141         return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
1142     }
1143
1144     slice = GST_VAAPI_SLICE_NEW(MPEG2, decoder,
1145         (map_info.data + unit->offset), unit->size);
1146     gst_buffer_unmap(buffer, &map_info);
1147     if (!slice) {
1148         GST_ERROR("failed to allocate slice");
1149         return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
1150     }
1151     gst_vaapi_picture_add_slice(picture, slice);
1152
1153     /* Fill in VASliceParameterBufferMPEG2 */
1154     slice_param                            = slice->param;
1155     slice_param->macroblock_offset         = slice_hdr->header_size + 32;
1156     slice_param->slice_horizontal_position = slice_hdr->mb_column;
1157     slice_param->slice_vertical_position   = slice_hdr->mb_row;
1158     slice_param->quantiser_scale_code      = slice_hdr->quantiser_scale_code;
1159     slice_param->intra_slice_flag          = slice_hdr->intra_slice;
1160
1161     priv->state |= GST_MPEG_VIDEO_STATE_GOT_SLICE;
1162     return GST_VAAPI_DECODER_STATUS_SUCCESS;
1163 }
1164
1165 static inline gint
1166 scan_for_start_code(const guchar *buf, guint buf_size,
1167     GstMpegVideoPacketTypeCode *type_ptr)
1168 {
1169     guint i = 0;
1170
1171     while (i <= (buf_size - 4)) {
1172         if (buf[i + 2] > 1)
1173             i += 3;
1174         else if (buf[i + 1])
1175             i += 2;
1176         else if (buf[i] || buf[i + 2] != 1)
1177             i++;
1178         else
1179             break;
1180     }
1181
1182     if (i <= (buf_size - 4)) {
1183         if (type_ptr)
1184             *type_ptr = buf[i + 3];
1185         return i;
1186     }
1187     return -1;
1188 }
1189
1190 static GstVaapiDecoderStatus
1191 parse_unit(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnit *unit,
1192     GstMpegVideoPacket *packet)
1193 {
1194     GstMpegVideoPacketTypeCode type;
1195     GstMpegVideoPacketExtensionCode ext_type;
1196     GstVaapiDecoderStatus status;
1197
1198     type = packet->type;
1199     switch (type) {
1200     case GST_MPEG_VIDEO_PACKET_PICTURE:
1201         status = parse_picture(decoder, unit, packet);
1202         break;
1203     case GST_MPEG_VIDEO_PACKET_SEQUENCE:
1204         status = parse_sequence(decoder, unit, packet);
1205         break;
1206     case GST_MPEG_VIDEO_PACKET_EXTENSION:
1207         ext_type = packet->data[4] >> 4;
1208         switch (ext_type) {
1209         case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE:
1210             status = parse_sequence_ext(decoder, unit, packet);
1211             break;
1212         case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_DISPLAY:
1213             status = parse_sequence_display_ext(decoder, unit, packet);
1214             break;
1215         case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_SCALABLE:
1216             status = parse_sequence_scalable_ext(decoder, unit, packet);
1217             break;
1218         case GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX:
1219             status = parse_quant_matrix_ext(decoder, unit, packet);
1220             break;
1221         case GST_MPEG_VIDEO_PACKET_EXT_PICTURE:
1222             status = parse_picture_ext(decoder, unit, packet);
1223             break;
1224         default:
1225             status = GST_VAAPI_DECODER_STATUS_SUCCESS;
1226             break;
1227         }
1228         break;
1229     case GST_MPEG_VIDEO_PACKET_GOP:
1230         status = parse_gop(decoder, unit, packet);
1231         break;
1232     default:
1233         if (type >= GST_MPEG_VIDEO_PACKET_SLICE_MIN &&
1234             type <= GST_MPEG_VIDEO_PACKET_SLICE_MAX) {
1235             status = parse_slice(decoder, unit, packet);
1236             break;
1237         }
1238         status = GST_VAAPI_DECODER_STATUS_SUCCESS;
1239         break;
1240     }
1241     return status;
1242 }
1243
1244 static GstVaapiDecoderStatus
1245 decode_unit(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnit *unit,
1246     GstMpegVideoPacket *packet)
1247 {
1248     GstMpegVideoPacketTypeCode type;
1249     GstMpegVideoPacketExtensionCode ext_type;
1250     GstVaapiDecoderStatus status;
1251
1252     type = packet->type;
1253     switch (type) {
1254     case GST_MPEG_VIDEO_PACKET_PICTURE:
1255         status = decode_picture(decoder, unit);
1256         break;
1257     case GST_MPEG_VIDEO_PACKET_SEQUENCE:
1258         status = decode_sequence(decoder, unit);
1259         break;
1260     case GST_MPEG_VIDEO_PACKET_EXTENSION:
1261         ext_type = packet->data[4] >> 4;
1262         switch (ext_type) {
1263         case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE:
1264             status = decode_sequence_ext(decoder, unit);
1265             break;
1266         case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_DISPLAY:
1267             status = decode_sequence_display_ext(decoder, unit);
1268             break;
1269         case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_SCALABLE:
1270             status = decode_sequence_scalable_ext(decoder, unit);
1271             break;
1272         case GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX:
1273             status = decode_quant_matrix_ext(decoder, unit);
1274             break;
1275         case GST_MPEG_VIDEO_PACKET_EXT_PICTURE:
1276             status = decode_picture_ext(decoder, unit);
1277             break;
1278         default:
1279             // Ignore unknown start-code extensions
1280             GST_WARNING("unsupported packet extension type 0x%02x", ext_type);
1281             status = GST_VAAPI_DECODER_STATUS_SUCCESS;
1282             break;
1283         }
1284         break;
1285     case GST_MPEG_VIDEO_PACKET_SEQUENCE_END:
1286         status = decode_sequence_end(decoder);
1287         break;
1288     case GST_MPEG_VIDEO_PACKET_GOP:
1289         status = decode_gop(decoder, unit);
1290         break;
1291     default:
1292         if (type >= GST_MPEG_VIDEO_PACKET_SLICE_MIN &&
1293             type <= GST_MPEG_VIDEO_PACKET_SLICE_MAX) {
1294             status = decode_slice(decoder, unit);
1295             break;
1296         }
1297         GST_WARNING("unsupported packet type 0x%02x", type);
1298         status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
1299         break;
1300     }
1301     return status;
1302 }
1303
1304 static GstVaapiDecoderStatus
1305 ensure_decoder(GstVaapiDecoderMpeg2 *decoder)
1306 {
1307     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
1308
1309     if (!priv->is_opened) {
1310         priv->is_opened = gst_vaapi_decoder_mpeg2_open(decoder);
1311         if (!priv->is_opened)
1312             return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC;
1313     }
1314     return GST_VAAPI_DECODER_STATUS_SUCCESS;
1315 }
1316
1317 static GstVaapiDecoderStatus
1318 gst_vaapi_decoder_mpeg2_parse(GstVaapiDecoder *base_decoder,
1319     GstAdapter *adapter, gboolean at_eos, GstVaapiDecoderUnit *unit)
1320 {
1321     GstVaapiDecoderMpeg2 * const decoder =
1322         GST_VAAPI_DECODER_MPEG2_CAST(base_decoder);
1323     GstVaapiParserState * const ps = GST_VAAPI_PARSER_STATE(base_decoder);
1324     GstVaapiDecoderStatus status;
1325     GstMpegVideoPacketTypeCode type, type2 = GST_MPEG_VIDEO_PACKET_NONE;
1326     const guchar *buf;
1327     guint buf_size, flags;
1328     gint ofs, ofs1, ofs2;
1329
1330     status = ensure_decoder(decoder);
1331     if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
1332         return status;
1333
1334     buf_size = gst_adapter_available(adapter);
1335     if (buf_size < 4)
1336         return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
1337
1338     buf = gst_adapter_map(adapter, buf_size);
1339     if (!buf)
1340         return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
1341
1342     ofs = scan_for_start_code(buf, buf_size, &type);
1343     if (ofs < 0)
1344         return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
1345     ofs1 = ofs;
1346
1347     ofs2 = ps->input_offset2 - 4;
1348     if (ofs2 < ofs1 + 4)
1349         ofs2 = ofs1 + 4;
1350
1351     ofs = G_UNLIKELY(buf_size < ofs2 + 4) ? -1 :
1352         scan_for_start_code(&buf[ofs2], buf_size - ofs2, &type2);
1353     if (ofs < 0) {
1354         // Assume the whole packet is present if end-of-stream
1355         if (!at_eos) {
1356             ps->input_offset2 = buf_size;
1357             return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
1358         }
1359         ofs = buf_size - ofs2;
1360     }
1361     ofs2 += ofs;
1362
1363     unit->size = ofs2 - ofs1;
1364     gst_adapter_flush(adapter, ofs1);
1365     ps->input_offset2 = 4;
1366
1367     /* Check for start of new picture */
1368     flags = 0;
1369     switch (type) {
1370     case GST_MPEG_VIDEO_PACKET_SEQUENCE_END:
1371         flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END;
1372         flags |= GST_VAAPI_DECODER_UNIT_FLAG_STREAM_END;
1373         break;
1374     case GST_MPEG_VIDEO_PACKET_USER_DATA:
1375         flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP;
1376         /* fall-through */
1377     case GST_MPEG_VIDEO_PACKET_SEQUENCE:
1378     case GST_MPEG_VIDEO_PACKET_GOP:
1379     case GST_MPEG_VIDEO_PACKET_PICTURE:
1380         flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
1381         break;
1382     case GST_MPEG_VIDEO_PACKET_EXTENSION:
1383         if (G_UNLIKELY(unit->size < 5))
1384             return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
1385         break;
1386     default:
1387         if (type >= GST_MPEG_VIDEO_PACKET_SLICE_MIN &&
1388             type <= GST_MPEG_VIDEO_PACKET_SLICE_MAX) {
1389             flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE;
1390             switch (type2) {
1391             case GST_MPEG_VIDEO_PACKET_USER_DATA:
1392             case GST_MPEG_VIDEO_PACKET_SEQUENCE:
1393             case GST_MPEG_VIDEO_PACKET_GOP:
1394             case GST_MPEG_VIDEO_PACKET_PICTURE:
1395                 flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END;
1396                 break;
1397             default:
1398                 break;
1399             }
1400         }
1401
1402         // Ignore system start codes (PES headers)
1403         else if (type >= 0xb9 && type <= 0xff)
1404             flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP;
1405         break;
1406     }
1407     GST_VAAPI_DECODER_UNIT_FLAG_SET(unit, flags);
1408     return GST_VAAPI_DECODER_STATUS_SUCCESS;
1409 }
1410
1411 static GstVaapiDecoderStatus
1412 gst_vaapi_decoder_mpeg2_decode(GstVaapiDecoder *base_decoder,
1413     GstVaapiDecoderUnit *unit)
1414 {
1415     GstVaapiDecoderMpeg2 * const decoder =
1416         GST_VAAPI_DECODER_MPEG2_CAST(base_decoder);
1417     GstVaapiDecoderStatus status;
1418     GstMpegVideoPacket packet;
1419     GstBuffer * const buffer =
1420         GST_VAAPI_DECODER_CODEC_FRAME(decoder)->input_buffer;
1421     GstMapInfo map_info;
1422
1423     status = ensure_decoder(decoder);
1424     if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
1425         return status;
1426
1427     if (!gst_buffer_map(buffer, &map_info, GST_MAP_READ)) {
1428         GST_ERROR("failed to map buffer");
1429         return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
1430     }
1431
1432     packet.data = map_info.data + unit->offset;
1433     packet.size = unit->size;
1434     packet.type = packet.data[3];
1435     packet.offset = 4;
1436
1437     status = parse_unit(decoder, unit, &packet);
1438     gst_buffer_unmap(buffer, &map_info);
1439     if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
1440         return status;
1441     return decode_unit(decoder, unit, &packet);
1442 }
1443
1444 static GstVaapiDecoderStatus
1445 gst_vaapi_decoder_mpeg2_start_frame(GstVaapiDecoder *base_decoder,
1446     GstVaapiDecoderUnit *base_unit)
1447 {
1448     GstVaapiDecoderMpeg2 * const decoder =
1449         GST_VAAPI_DECODER_MPEG2_CAST(base_decoder);
1450     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
1451     GstMpegVideoSequenceHdr *seq_hdr;
1452     GstMpegVideoSequenceExt *seq_ext;
1453     GstMpegVideoSequenceDisplayExt *seq_display_ext;
1454     GstVaapiPicture *picture;
1455     GstVaapiDecoderStatus status;
1456
1457     if (!is_valid_state(decoder, GST_MPEG_VIDEO_STATE_VALID_PIC_HEADERS))
1458         return GST_VAAPI_DECODER_STATUS_SUCCESS;
1459     priv->state &= ~GST_MPEG_VIDEO_STATE_VALID_PIC_HEADERS;
1460
1461     seq_hdr = &priv->seq_hdr->data.seq_hdr;
1462     seq_ext = priv->seq_ext ? &priv->seq_ext->data.seq_ext : NULL;
1463     seq_display_ext = priv->seq_display_ext ?
1464         &priv->seq_display_ext->data.seq_display_ext : NULL;
1465     if (gst_mpeg_video_finalise_mpeg2_sequence_header(seq_hdr, seq_ext,
1466             seq_display_ext))
1467         gst_vaapi_decoder_set_pixel_aspect_ratio(base_decoder,
1468             seq_hdr->par_w, seq_hdr->par_h);
1469
1470     status = ensure_context(decoder);
1471     if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
1472         GST_ERROR("failed to reset context");
1473         return status;
1474     }
1475
1476     if (priv->current_picture) {
1477         /* Re-use current picture where the first field was decoded */
1478         picture = gst_vaapi_picture_new_field(priv->current_picture);
1479         if (!picture) {
1480             GST_ERROR("failed to allocate field picture");
1481             return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
1482         }
1483     }
1484     else {
1485         /* Create new picture */
1486         picture = GST_VAAPI_PICTURE_NEW(MPEG2, decoder);
1487         if (!picture) {
1488             GST_ERROR("failed to allocate picture");
1489             return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
1490         }
1491     }
1492     gst_vaapi_picture_replace(&priv->current_picture, picture);
1493     gst_vaapi_picture_unref(picture);
1494
1495     /* Update cropping rectangle */
1496     /* XXX: handle picture_display_extension() */
1497     if (seq_display_ext && priv->pic_display_ext) {
1498         GstVaapiRectangle * const crop_rect = &priv->crop_rect;
1499         if (crop_rect->x + crop_rect->width <= priv->width &&
1500             crop_rect->y + crop_rect->height <= priv->height)
1501             gst_vaapi_picture_set_crop_rect(picture, crop_rect);
1502     }
1503
1504     status = ensure_quant_matrix(decoder, picture);
1505     if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
1506         GST_ERROR("failed to reset quantizer matrix");
1507         return status;
1508     }
1509
1510     status = init_picture(decoder, picture);
1511     if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
1512         return status;
1513
1514     fill_picture(decoder, picture);
1515
1516     priv->state |= GST_MPEG_VIDEO_STATE_VALID_PIC_HEADERS;
1517     return GST_VAAPI_DECODER_STATUS_SUCCESS;
1518 }
1519
1520 static GstVaapiDecoderStatus
1521 gst_vaapi_decoder_mpeg2_end_frame(GstVaapiDecoder *base_decoder)
1522 {
1523     GstVaapiDecoderMpeg2 * const decoder =
1524         GST_VAAPI_DECODER_MPEG2_CAST(base_decoder);
1525
1526     return decode_current_picture(decoder);
1527 }
1528
1529 static GstVaapiDecoderStatus
1530 gst_vaapi_decoder_mpeg2_flush(GstVaapiDecoder *base_decoder)
1531 {
1532     GstVaapiDecoderMpeg2 * const decoder =
1533         GST_VAAPI_DECODER_MPEG2_CAST(base_decoder);
1534     GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
1535
1536     gst_vaapi_dpb_flush(priv->dpb);
1537     return GST_VAAPI_DECODER_STATUS_SUCCESS;
1538 }
1539
1540 static void
1541 gst_vaapi_decoder_mpeg2_class_init(GstVaapiDecoderMpeg2Class *klass)
1542 {
1543     GstVaapiMiniObjectClass * const object_class =
1544         GST_VAAPI_MINI_OBJECT_CLASS(klass);
1545     GstVaapiDecoderClass * const decoder_class = GST_VAAPI_DECODER_CLASS(klass);
1546
1547     object_class->size          = sizeof(GstVaapiDecoderMpeg2);
1548     object_class->finalize      = (GDestroyNotify)gst_vaapi_decoder_finalize;
1549
1550     decoder_class->create       = gst_vaapi_decoder_mpeg2_create;
1551     decoder_class->destroy      = gst_vaapi_decoder_mpeg2_destroy;
1552     decoder_class->parse        = gst_vaapi_decoder_mpeg2_parse;
1553     decoder_class->decode       = gst_vaapi_decoder_mpeg2_decode;
1554     decoder_class->start_frame  = gst_vaapi_decoder_mpeg2_start_frame;
1555     decoder_class->end_frame    = gst_vaapi_decoder_mpeg2_end_frame;
1556     decoder_class->flush        = gst_vaapi_decoder_mpeg2_flush;
1557 }
1558
1559 static inline const GstVaapiDecoderClass *
1560 gst_vaapi_decoder_mpeg2_class(void)
1561 {
1562     static GstVaapiDecoderMpeg2Class g_class;
1563     static gsize g_class_init = FALSE;
1564
1565     if (g_once_init_enter(&g_class_init)) {
1566         gst_vaapi_decoder_mpeg2_class_init(&g_class);
1567         g_once_init_leave(&g_class_init, TRUE);
1568     }
1569     return GST_VAAPI_DECODER_CLASS(&g_class);
1570 }
1571
1572 /**
1573  * gst_vaapi_decoder_mpeg2_new:
1574  * @display: a #GstVaapiDisplay
1575  * @caps: a #GstCaps holding codec information
1576  *
1577  * Creates a new #GstVaapiDecoder for MPEG-2 decoding.  The @caps can
1578  * hold extra information like codec-data and pictured coded size.
1579  *
1580  * Return value: the newly allocated #GstVaapiDecoder object
1581  */
1582 GstVaapiDecoder *
1583 gst_vaapi_decoder_mpeg2_new(GstVaapiDisplay *display, GstCaps *caps)
1584 {
1585     return gst_vaapi_decoder_new(gst_vaapi_decoder_mpeg2_class(),
1586         display, caps);
1587 }