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