decoder: mpeg2: respect any input PTS provided for a frame.
[platform/upstream/gstreamer-vaapi.git] / gst-libs / gst / vaapi / gstvaapidecoder_mpeg2.c
index 784618c..c3ab7a6 100644 (file)
@@ -1,7 +1,8 @@
 /*
  *  gstvaapidecoder_mpeg2.c - MPEG-2 decoder
  *
- *  Copyright (C) 2011 Intel Corporation
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public License
 #include "gstvaapidebug.h"
 
 /* ------------------------------------------------------------------------- */
-/* --- VLC Reader                                                        --- */
-/* ------------------------------------------------------------------------- */
-
-#define READ_UINT8(br, val, nbits) G_STMT_START {  \
-  if (!gst_bit_reader_get_bits_uint8 (br, &val, nbits)) { \
-    GST_WARNING ("failed to read uint8, nbits: %d", nbits); \
-    goto failed; \
-  } \
-} G_STMT_END
-
-#define SKIP(reader, nbits) G_STMT_START { \
-  if (!gst_bit_reader_skip (reader, nbits)) { \
-    GST_WARNING ("failed to skip nbits: %d", nbits); \
-    goto failed; \
-  } \
-} G_STMT_END
-
-/* VLC decoder from gst-plugins-bad */
-typedef struct _VLCTable VLCTable;
-struct _VLCTable {
-    gint  value;
-    guint cword;
-    guint cbits;
-};
-
-static gboolean
-decode_vlc(GstBitReader *br, gint *res, const VLCTable *table, guint length)
-{
-    guint8 i;
-    guint cbits = 0;
-    guint32 value = 0;
-
-    for (i = 0; i < length; i++) {
-        if (cbits != table[i].cbits) {
-            cbits = table[i].cbits;
-            if (!gst_bit_reader_peek_bits_uint32(br, &value, cbits)) {
-                goto failed;
-            }
-        }
-
-        if (value == table[i].cword) {
-            SKIP(br, cbits);
-            if (res)
-                *res = table[i].value;
-            return TRUE;
-        }
-    }
-    GST_DEBUG("failed to find VLC code");
-
-failed:
-    GST_WARNING("failed to decode VLC, returning");
-    return FALSE;
-}
-
-enum {
-    GST_MPEG_VIDEO_MACROBLOCK_ESCAPE = -1,
-};
-
-/* Table B-1: Variable length codes for macroblock_address_increment */
-static const VLCTable mpeg2_mbaddr_vlc_table[] = {
-    {  1, 0x01,  1 },
-    {  2, 0x03,  3 },
-    {  3, 0x02,  3 },
-    {  4, 0x03,  4 },
-    {  5, 0x02,  4 },
-    {  6, 0x03,  5 },
-    {  7, 0x02,  5 },
-    {  8, 0x07,  7 },
-    {  9, 0x06,  7 },
-    { 10, 0x0b,  8 },
-    { 11, 0x0a,  8 },
-    { 12, 0x09,  8 },
-    { 13, 0x08,  8 },
-    { 14, 0x07,  8 },
-    { 15, 0x06,  8 },
-    { 16, 0x17, 10 },
-    { 17, 0x16, 10 },
-    { 18, 0x15, 10 },
-    { 19, 0x14, 10 },
-    { 20, 0x13, 10 },
-    { 21, 0x12, 10 },
-    { 22, 0x23, 11 },
-    { 23, 0x22, 11 },
-    { 24, 0x21, 11 },
-    { 25, 0x20, 11 },
-    { 26, 0x1f, 11 },
-    { 27, 0x1e, 11 },
-    { 28, 0x1d, 11 },
-    { 29, 0x1c, 11 },
-    { 30, 0x1b, 11 },
-    { 31, 0x1a, 11 },
-    { 32, 0x19, 11 },
-    { 33, 0x18, 11 },
-    { GST_MPEG_VIDEO_MACROBLOCK_ESCAPE, 0x08, 11 }
-};
-
-/* ------------------------------------------------------------------------- */
 /* --- PTS Generator                                                     --- */
 /* ------------------------------------------------------------------------- */
 
@@ -226,7 +130,9 @@ pts_eval(PTSGenerator *tsg, GstClockTime pic_pts, guint pic_tsn)
     if (!GST_CLOCK_TIME_IS_VALID(tsg->gop_pts))
         tsg->gop_pts = 0;
 
-    pts = tsg->gop_pts + pts_get_duration(tsg, tsg->ovl_tsn * 1024 + pic_tsn);
+    pts = pic_pts;
+    if (!GST_CLOCK_TIME_IS_VALID (pts))
+       pts = tsg->gop_pts + pts_get_duration(tsg, tsg->ovl_tsn * 1024 + pic_tsn);
 
     if (!GST_CLOCK_TIME_IS_VALID(tsg->max_pts) || tsg->max_pts < pts)
         tsg->max_pts = pts;
@@ -238,6 +144,7 @@ pts_eval(PTSGenerator *tsg, GstClockTime pic_pts, guint pic_tsn)
         tsg->ovl_tsn++;
     }
     tsg->lst_tsn = pic_tsn;
+
     return pts;
 }
 
@@ -245,25 +152,16 @@ pts_eval(PTSGenerator *tsg, GstClockTime pic_pts, guint pic_tsn)
 /* --- MPEG-2 Parser Info                                                --- */
 /* ------------------------------------------------------------------------- */
 
-typedef struct _GstMpegVideoSliceHdr GstMpegVideoSliceHdr;
-struct _GstMpegVideoSliceHdr {
-    guint16 slice_horizontal_position;
-    guint16 slice_vertical_position;
-    guint8 quantiser_scale_code;
-    guint8 intra_slice;
-
-    /* Size of the slice() header in bits */
-    guint header_size;
-};
-
 typedef struct _GstVaapiParserInfoMpeg2 GstVaapiParserInfoMpeg2;
 struct _GstVaapiParserInfoMpeg2 {
+    GstVaapiMiniObject  parent_instance;
     GstMpegVideoPacket  packet;
     guint8              extension_type; /* for Extension packets */
     union {
         GstMpegVideoSequenceHdr         seq_hdr;
         GstMpegVideoSequenceExt         seq_ext;
         GstMpegVideoSequenceDisplayExt  seq_display_ext;
+        GstMpegVideoSequenceScalableExt seq_scalable_ext;
         GstMpegVideoGop                 gop;
         GstMpegVideoQuantMatrixExt      quant_matrix;
         GstMpegVideoPictureHdr          pic_hdr;
@@ -315,17 +213,30 @@ gst_vaapi_parser_info_mpeg2_ensure(GstVaapiParserInfoMpeg2 **pi_ptr)
 /* --- MPEG-2 Decoder                                                    --- */
 /* ------------------------------------------------------------------------- */
 
-G_DEFINE_TYPE(GstVaapiDecoderMpeg2,
-              gst_vaapi_decoder_mpeg2,
-              GST_VAAPI_TYPE_DECODER)
-
 #define GST_VAAPI_DECODER_MPEG2_CAST(decoder) \
     ((GstVaapiDecoderMpeg2 *)(decoder))
 
-#define GST_VAAPI_DECODER_MPEG2_GET_PRIVATE(obj)                \
-    (G_TYPE_INSTANCE_GET_PRIVATE((obj),                         \
-                                 GST_VAAPI_TYPE_DECODER_MPEG2,  \
-                                 GstVaapiDecoderMpeg2Private))
+typedef struct _GstVaapiDecoderMpeg2Private     GstVaapiDecoderMpeg2Private;
+typedef struct _GstVaapiDecoderMpeg2Class       GstVaapiDecoderMpeg2Class;
+
+typedef enum {
+    GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR    = 1 << 0,
+    GST_MPEG_VIDEO_STATE_GOT_SEQ_EXT    = 1 << 1,
+    GST_MPEG_VIDEO_STATE_GOT_PIC_HDR    = 1 << 2,
+    GST_MPEG_VIDEO_STATE_GOT_PIC_EXT    = 1 << 3,
+    GST_MPEG_VIDEO_STATE_GOT_SLICE      = 1 << 4,
+
+    GST_MPEG_VIDEO_STATE_VALID_SEQ_HEADERS = (
+        GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR|
+        GST_MPEG_VIDEO_STATE_GOT_SEQ_EXT),
+    GST_MPEG_VIDEO_STATE_VALID_PIC_HEADERS = (
+        GST_MPEG_VIDEO_STATE_GOT_PIC_HDR|
+        GST_MPEG_VIDEO_STATE_GOT_PIC_EXT),
+    GST_MPEG_VIDEO_STATE_VALID_PICTURE = (
+        GST_MPEG_VIDEO_STATE_VALID_SEQ_HEADERS|
+        GST_MPEG_VIDEO_STATE_VALID_PIC_HEADERS|
+        GST_MPEG_VIDEO_STATE_GOT_SLICE)
+} GstMpegVideoState;
 
 struct _GstVaapiDecoderMpeg2Private {
     GstVaapiProfile             profile;
@@ -334,6 +245,8 @@ struct _GstVaapiDecoderMpeg2Private {
     guint                       height;
     guint                       fps_n;
     guint                       fps_d;
+    guint                       state;
+    GstVaapiRectangle           crop_rect;
     GstVaapiParserInfoMpeg2    *seq_hdr;
     GstVaapiParserInfoMpeg2    *seq_ext;
     GstVaapiParserInfoMpeg2    *seq_display_ext;
@@ -341,12 +254,12 @@ struct _GstVaapiDecoderMpeg2Private {
     GstVaapiParserInfoMpeg2    *gop;
     GstVaapiParserInfoMpeg2    *pic_hdr;
     GstVaapiParserInfoMpeg2    *pic_ext;
+    GstVaapiParserInfoMpeg2    *pic_display_ext;
     GstVaapiParserInfoMpeg2    *quant_matrix;
     GstVaapiParserInfoMpeg2    *slice_hdr;
     GstVaapiPicture            *current_picture;
     GstVaapiDpb                *dpb;
     PTSGenerator                tsg;
-    guint                       is_constructed          : 1;
     guint                       is_opened               : 1;
     guint                       size_changed            : 1;
     guint                       profile_changed         : 1;
@@ -356,10 +269,31 @@ struct _GstVaapiDecoderMpeg2Private {
     guint                       broken_link             : 1;
 };
 
+/**
+ * GstVaapiDecoderMpeg2:
+ *
+ * A decoder based on Mpeg2.
+ */
+struct _GstVaapiDecoderMpeg2 {
+    /*< private >*/
+    GstVaapiDecoder             parent_instance;
+    GstVaapiDecoderMpeg2Private priv;
+};
+
+/**
+ * GstVaapiDecoderMpeg2Class:
+ *
+ * A decoder class based on Mpeg2.
+ */
+struct _GstVaapiDecoderMpeg2Class {
+    /*< private >*/
+    GstVaapiDecoderClass parent_class;
+};
+
 static void
 gst_vaapi_decoder_mpeg2_close(GstVaapiDecoderMpeg2 *decoder)
 {
-    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
 
     gst_vaapi_picture_replace(&priv->current_picture, NULL);
 
@@ -370,23 +304,21 @@ gst_vaapi_decoder_mpeg2_close(GstVaapiDecoderMpeg2 *decoder)
     gst_vaapi_parser_info_mpeg2_replace(&priv->gop, NULL);
     gst_vaapi_parser_info_mpeg2_replace(&priv->pic_hdr, NULL);
     gst_vaapi_parser_info_mpeg2_replace(&priv->pic_ext, NULL);
+    gst_vaapi_parser_info_mpeg2_replace(&priv->pic_display_ext, NULL);
     gst_vaapi_parser_info_mpeg2_replace(&priv->quant_matrix, NULL);
     gst_vaapi_parser_info_mpeg2_replace(&priv->slice_hdr, NULL);
 
-    if (priv->dpb) {
-        gst_vaapi_dpb_unref(priv->dpb);
-        priv->dpb = NULL;
-    }
+    gst_vaapi_dpb_replace(&priv->dpb, NULL);
 }
 
 static gboolean
 gst_vaapi_decoder_mpeg2_open(GstVaapiDecoderMpeg2 *decoder)
 {
-    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
 
     gst_vaapi_decoder_mpeg2_close(decoder);
 
-    priv->dpb = gst_vaapi_dpb_mpeg2_new();
+    priv->dpb = gst_vaapi_dpb_new(2);
     if (!priv->dpb)
         return FALSE;
 
@@ -395,16 +327,24 @@ gst_vaapi_decoder_mpeg2_open(GstVaapiDecoderMpeg2 *decoder)
 }
 
 static void
-gst_vaapi_decoder_mpeg2_destroy(GstVaapiDecoderMpeg2 *decoder)
+gst_vaapi_decoder_mpeg2_destroy(GstVaapiDecoder *base_decoder)
 {
+    GstVaapiDecoderMpeg2 * const decoder =
+        GST_VAAPI_DECODER_MPEG2_CAST(base_decoder);
+
     gst_vaapi_decoder_mpeg2_close(decoder);
 }
 
 static gboolean
-gst_vaapi_decoder_mpeg2_create(GstVaapiDecoderMpeg2 *decoder)
+gst_vaapi_decoder_mpeg2_create(GstVaapiDecoder *base_decoder)
 {
-    if (!GST_VAAPI_DECODER_CODEC(decoder))
-        return FALSE;
+    GstVaapiDecoderMpeg2 * const decoder =
+        GST_VAAPI_DECODER_MPEG2_CAST(base_decoder);
+    GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
+
+    priv->hw_profile            = GST_VAAPI_PROFILE_UNKNOWN;
+    priv->profile               = GST_VAAPI_PROFILE_MPEG2_SIMPLE;
+    priv->profile_changed       = TRUE; /* Allow fallbacks to work */
     return TRUE;
 }
 
@@ -432,7 +372,7 @@ static GstVaapiProfile
 get_profile(GstVaapiDecoderMpeg2 *decoder, GstVaapiEntrypoint entrypoint)
 {
     GstVaapiDisplay * const va_display = GST_VAAPI_DECODER_DISPLAY(decoder);
-    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
     GstVaapiProfile profile = priv->profile;
 
     do {
@@ -473,7 +413,7 @@ get_profile(GstVaapiDecoderMpeg2 *decoder, GstVaapiEntrypoint entrypoint)
 static GstVaapiDecoderStatus
 ensure_context(GstVaapiDecoderMpeg2 *decoder)
 {
-    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
     GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_VLD;
     gboolean reset_context = FALSE;
 
@@ -498,6 +438,7 @@ ensure_context(GstVaapiDecoderMpeg2 *decoder)
 
         info.profile    = priv->hw_profile;
         info.entrypoint = entrypoint;
+        info.chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420;
         info.width      = priv->width;
         info.height     = priv->height;
         info.ref_frames = 2;
@@ -514,7 +455,7 @@ ensure_context(GstVaapiDecoderMpeg2 *decoder)
 static GstVaapiDecoderStatus
 ensure_quant_matrix(GstVaapiDecoderMpeg2 *decoder, GstVaapiPicture *picture)
 {
-    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
     GstMpegVideoSequenceHdr * const seq_hdr = &priv->seq_hdr->data.seq_hdr;
     VAIQMatrixBufferMPEG2 *iq_matrix;
     guint8 *intra_quant_matrix = NULL;
@@ -572,12 +513,24 @@ ensure_quant_matrix(GstVaapiDecoderMpeg2 *decoder, GstVaapiPicture *picture)
     return GST_VAAPI_DECODER_STATUS_SUCCESS;
 }
 
+static inline gboolean
+is_valid_state(GstVaapiDecoderMpeg2 *decoder, guint state)
+{
+    GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
+
+    return (priv->state & state) == state;
+}
+
 static GstVaapiDecoderStatus
 decode_current_picture(GstVaapiDecoderMpeg2 *decoder)
 {
-    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
     GstVaapiPicture * const picture = priv->current_picture;
 
+    if (!is_valid_state(decoder, GST_MPEG_VIDEO_STATE_VALID_PICTURE))
+        goto drop_frame;
+    priv->state &= GST_MPEG_VIDEO_STATE_VALID_SEQ_HEADERS;
+
     if (!picture)
         return GST_VAAPI_DECODER_STATUS_SUCCESS;
 
@@ -594,15 +547,21 @@ error:
     /* XXX: fix for cases where first field failed to be decoded */
     gst_vaapi_picture_replace(&priv->current_picture, NULL);
     return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+
+drop_frame:
+    priv->state &= GST_MPEG_VIDEO_STATE_VALID_SEQ_HEADERS;
+    return GST_VAAPI_DECODER_STATUS_DROP_FRAME;
 }
 
 static GstVaapiDecoderStatus
 parse_sequence(GstVaapiDecoderMpeg2 *decoder,
-    GstVaapiDecoderUnit *unit, GstMpegVideoPacket *packet)
+    GstVaapiDecoderUnit *unit, const GstMpegVideoPacket *packet)
 {
-    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
     GstMpegVideoSequenceHdr *seq_hdr;
 
+    priv->state = 0;
+
     if (!gst_vaapi_parser_info_mpeg2_ensure(&priv->seq_hdr)) {
         GST_ERROR("failed to allocate parser info for sequence header");
         return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
@@ -610,8 +569,7 @@ parse_sequence(GstVaapiDecoderMpeg2 *decoder,
 
     seq_hdr = &priv->seq_hdr->data.seq_hdr;
 
-    if (!gst_mpeg_video_parse_sequence_header(seq_hdr,
-            packet->data, packet->size, packet->offset)) {
+    if (!gst_mpeg_video_packet_parse_sequence_header(packet, seq_hdr)) {
         GST_ERROR("failed to parse sequence header");
         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
     }
@@ -624,11 +582,14 @@ static GstVaapiDecoderStatus
 decode_sequence(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnit *unit)
 {
     GstVaapiDecoder * const base_decoder = GST_VAAPI_DECODER_CAST(decoder);
-    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
     GstMpegVideoSequenceHdr * const seq_hdr = unit->parsed_info;
 
     gst_vaapi_parser_info_mpeg2_replace(&priv->seq_ext, NULL);
     gst_vaapi_parser_info_mpeg2_replace(&priv->seq_display_ext, NULL);
+    gst_vaapi_parser_info_mpeg2_replace(&priv->seq_scalable_ext, NULL);
+    gst_vaapi_parser_info_mpeg2_replace(&priv->quant_matrix, NULL);
+    gst_vaapi_parser_info_mpeg2_replace(&priv->pic_display_ext, NULL);
 
     priv->fps_n = seq_hdr->fps_n;
     priv->fps_d = seq_hdr->fps_d;
@@ -640,16 +601,20 @@ decode_sequence(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnit *unit)
     priv->size_changed          = TRUE;
     priv->quant_matrix_changed  = TRUE;
     priv->progressive_sequence  = TRUE;
+
+    priv->state |= GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR;
     return GST_VAAPI_DECODER_STATUS_SUCCESS;
 }
 
 static GstVaapiDecoderStatus
 parse_sequence_ext(GstVaapiDecoderMpeg2 *decoder,
-    GstVaapiDecoderUnit *unit, GstMpegVideoPacket *packet)
+    GstVaapiDecoderUnit *unit, const GstMpegVideoPacket *packet)
 {
-    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
     GstMpegVideoSequenceExt *seq_ext;
 
+    priv->state &= GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR;
+
     if (!gst_vaapi_parser_info_mpeg2_ensure(&priv->seq_ext)) {
         GST_ERROR("failed to allocate parser info for sequence extension");
         return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
@@ -657,8 +622,7 @@ parse_sequence_ext(GstVaapiDecoderMpeg2 *decoder,
 
     seq_ext = &priv->seq_ext->data.seq_ext;
 
-    if (!gst_mpeg_video_parse_sequence_extension(seq_ext,
-            packet->data, packet->size, packet->offset)) {
+    if (!gst_mpeg_video_packet_parse_sequence_extension(packet, seq_ext)) {
         GST_ERROR("failed to parse sequence-extension");
         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
     }
@@ -671,11 +635,14 @@ static GstVaapiDecoderStatus
 decode_sequence_ext(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnit *unit)
 {
     GstVaapiDecoder * const base_decoder = GST_VAAPI_DECODER_CAST(decoder);
-    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
     GstMpegVideoSequenceExt * const seq_ext = unit->parsed_info;
     GstVaapiProfile profile;
     guint width, height;
 
+    if (!is_valid_state(decoder, GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR))
+        return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
     priv->progressive_sequence = seq_ext->progressive;
     gst_vaapi_decoder_set_interlaced(base_decoder, !priv->progressive_sequence);
 
@@ -718,14 +685,16 @@ decode_sequence_ext(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnit *unit)
         priv->profile = profile;
         priv->profile_changed = TRUE;
     }
+
+    priv->state |= GST_MPEG_VIDEO_STATE_GOT_SEQ_EXT;
     return GST_VAAPI_DECODER_STATUS_SUCCESS;
 }
 
 static GstVaapiDecoderStatus
 parse_sequence_display_ext(GstVaapiDecoderMpeg2 *decoder,
-    GstVaapiDecoderUnit *unit, GstMpegVideoPacket *packet)
+    GstVaapiDecoderUnit *unit, const GstMpegVideoPacket *packet)
 {
-    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
     GstMpegVideoSequenceDisplayExt *seq_display_ext;
 
     if (!gst_vaapi_parser_info_mpeg2_ensure(&priv->seq_display_ext)) {
@@ -735,8 +704,8 @@ parse_sequence_display_ext(GstVaapiDecoderMpeg2 *decoder,
 
     seq_display_ext = &priv->seq_display_ext->data.seq_display_ext;
 
-    if (!gst_mpeg_video_parse_sequence_display_extension(seq_display_ext,
-            packet->data, packet->size, packet->offset)) {
+    if (!gst_mpeg_video_packet_parse_sequence_display_extension(packet,
+            seq_display_ext)) {
         GST_ERROR("failed to parse sequence-display-extension");
         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
     }
@@ -749,19 +718,61 @@ static GstVaapiDecoderStatus
 decode_sequence_display_ext(GstVaapiDecoderMpeg2 *decoder,
     GstVaapiDecoderUnit *unit)
 {
-    /* XXX: handle color primaries and cropping */
+    GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
+    GstMpegVideoSequenceDisplayExt *seq_display_ext;
+
+    seq_display_ext = priv->seq_display_ext ?
+        &priv->seq_display_ext->data.seq_display_ext : NULL;
+
+    /* Update cropping rectangle */
+    if (seq_display_ext) {
+        GstVaapiRectangle * const crop_rect = &priv->crop_rect;
+        crop_rect->x = 0;
+        crop_rect->y = 0;
+        crop_rect->width = seq_display_ext->display_horizontal_size;
+        crop_rect->height = seq_display_ext->display_vertical_size;
+    }
+
+    /* XXX: handle color primaries */
     return GST_VAAPI_DECODER_STATUS_SUCCESS;
 }
 
 static GstVaapiDecoderStatus
-decode_sequence_end(GstVaapiDecoderMpeg2 *decoder)
+parse_sequence_scalable_ext(GstVaapiDecoderMpeg2 *decoder,
+    GstVaapiDecoderUnit *unit, const GstMpegVideoPacket *packet)
 {
-    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
-    GstVaapiDecoderStatus status;
+    GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
+    GstMpegVideoSequenceScalableExt *seq_scalable_ext;
 
-    status = decode_current_picture(decoder);
-    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
-        return status;
+    if (!gst_vaapi_parser_info_mpeg2_ensure(&priv->seq_scalable_ext)) {
+        GST_ERROR("failed to allocate parser info for sequence scalable extension");
+        return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+    }
+
+    seq_scalable_ext = &priv->seq_scalable_ext->data.seq_scalable_ext;
+
+    if (!gst_mpeg_video_packet_parse_sequence_scalable_extension(packet,
+            seq_scalable_ext)) {
+        GST_ERROR("failed to parse sequence-scalable-extension");
+        return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+    }
+
+    gst_vaapi_decoder_unit_set_parsed_info(unit, seq_scalable_ext, NULL);
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_sequence_scalable_ext(GstVaapiDecoderMpeg2 *decoder,
+    GstVaapiDecoderUnit *unit)
+{
+    /* XXX: unsupported header -- ignore */
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_sequence_end(GstVaapiDecoderMpeg2 *decoder)
+{
+    GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
 
     gst_vaapi_dpb_flush(priv->dpb);
     return GST_VAAPI_DECODER_STATUS_SUCCESS;
@@ -769,9 +780,9 @@ decode_sequence_end(GstVaapiDecoderMpeg2 *decoder)
 
 static GstVaapiDecoderStatus
 parse_quant_matrix_ext(GstVaapiDecoderMpeg2 *decoder,
-    GstVaapiDecoderUnit *unit, GstMpegVideoPacket *packet)
+    GstVaapiDecoderUnit *unit, const GstMpegVideoPacket *packet)
 {
-    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
     GstMpegVideoQuantMatrixExt *quant_matrix;
 
     if (!gst_vaapi_parser_info_mpeg2_ensure(&priv->quant_matrix)) {
@@ -781,8 +792,8 @@ parse_quant_matrix_ext(GstVaapiDecoderMpeg2 *decoder,
 
     quant_matrix = &priv->quant_matrix->data.quant_matrix;
 
-    if (!gst_mpeg_video_parse_quant_matrix_extension(quant_matrix,
-            packet->data, packet->size, packet->offset)) {
+    if (!gst_mpeg_video_packet_parse_quant_matrix_extension(packet,
+            quant_matrix)) {
         GST_ERROR("failed to parse quant-matrix-extension");
         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
     }
@@ -795,7 +806,7 @@ static GstVaapiDecoderStatus
 decode_quant_matrix_ext(GstVaapiDecoderMpeg2 *decoder,
     GstVaapiDecoderUnit *unit)
 {
-    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
 
     priv->quant_matrix_changed = TRUE;
     return GST_VAAPI_DECODER_STATUS_SUCCESS;
@@ -803,9 +814,9 @@ decode_quant_matrix_ext(GstVaapiDecoderMpeg2 *decoder,
 
 static GstVaapiDecoderStatus
 parse_gop(GstVaapiDecoderMpeg2 *decoder,
-    GstVaapiDecoderUnit *unit, GstMpegVideoPacket *packet)
+    GstVaapiDecoderUnit *unit, const GstMpegVideoPacket *packet)
 {
-    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
     GstMpegVideoGop *gop;
 
     if (!gst_vaapi_parser_info_mpeg2_ensure(&priv->gop)) {
@@ -815,8 +826,7 @@ parse_gop(GstVaapiDecoderMpeg2 *decoder,
 
     gop = &priv->gop->data.gop;
 
-    if (!gst_mpeg_video_parse_gop(gop,
-            packet->data, packet->size, packet->offset)) {
+    if (!gst_mpeg_video_packet_parse_gop(packet, gop)) {
         GST_ERROR("failed to parse GOP");
         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
     }
@@ -828,7 +838,7 @@ parse_gop(GstVaapiDecoderMpeg2 *decoder,
 static GstVaapiDecoderStatus
 decode_gop(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnit *unit)
 {
-    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
     GstMpegVideoGop * const gop = unit->parsed_info;
 
     priv->closed_gop  = gop->closed_gop;
@@ -844,11 +854,14 @@ decode_gop(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnit *unit)
 
 static GstVaapiDecoderStatus
 parse_picture(GstVaapiDecoderMpeg2 *decoder,
-    GstVaapiDecoderUnit *unit, GstMpegVideoPacket *packet)
+    GstVaapiDecoderUnit *unit, const GstMpegVideoPacket *packet)
 {
-    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
     GstMpegVideoPictureHdr *pic_hdr;
 
+    priv->state &= (GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR|
+                    GST_MPEG_VIDEO_STATE_GOT_SEQ_EXT);
+
     if (!gst_vaapi_parser_info_mpeg2_ensure(&priv->pic_hdr)) {
         GST_ERROR("failed to allocate parser info for picture header");
         return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
@@ -856,8 +869,7 @@ parse_picture(GstVaapiDecoderMpeg2 *decoder,
 
     pic_hdr = &priv->pic_hdr->data.pic_hdr;
 
-    if (!gst_mpeg_video_parse_picture_header(pic_hdr,
-            packet->data, packet->size, packet->offset)) {
+    if (!gst_mpeg_video_packet_parse_picture_header(packet, pic_hdr)) {
         GST_ERROR("failed to parse picture header");
         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
     }
@@ -869,19 +881,28 @@ parse_picture(GstVaapiDecoderMpeg2 *decoder,
 static GstVaapiDecoderStatus
 decode_picture(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnit *unit)
 {
-    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
+
+    if (!is_valid_state(decoder, GST_MPEG_VIDEO_STATE_VALID_SEQ_HEADERS))
+        return GST_VAAPI_DECODER_STATUS_SUCCESS;
 
     gst_vaapi_parser_info_mpeg2_replace(&priv->pic_ext, NULL);
+
+    priv->state |= GST_MPEG_VIDEO_STATE_GOT_PIC_HDR;
     return GST_VAAPI_DECODER_STATUS_SUCCESS;
 }
 
 static GstVaapiDecoderStatus
 parse_picture_ext(GstVaapiDecoderMpeg2 *decoder,
-    GstVaapiDecoderUnit *unit, GstMpegVideoPacket *packet)
+    GstVaapiDecoderUnit *unit, const GstMpegVideoPacket *packet)
 {
-    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
     GstMpegVideoPictureExt *pic_ext;
 
+    priv->state &= (GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR|
+                    GST_MPEG_VIDEO_STATE_GOT_SEQ_EXT|
+                    GST_MPEG_VIDEO_STATE_GOT_PIC_HDR);
+
     if (!gst_vaapi_parser_info_mpeg2_ensure(&priv->pic_ext)) {
         GST_ERROR("failed to allocate parser info for picture extension");
         return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
@@ -889,8 +910,7 @@ parse_picture_ext(GstVaapiDecoderMpeg2 *decoder,
 
     pic_ext = &priv->pic_ext->data.pic_ext;
 
-    if (!gst_mpeg_video_parse_picture_extension(pic_ext,
-            packet->data, packet->size, packet->offset)) {
+    if (!gst_mpeg_video_packet_parse_picture_extension(packet, pic_ext)) {
         GST_ERROR("failed to parse picture-extension");
         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
     }
@@ -902,9 +922,12 @@ parse_picture_ext(GstVaapiDecoderMpeg2 *decoder,
 static GstVaapiDecoderStatus
 decode_picture_ext(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnit *unit)
 {
-    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
     GstMpegVideoPictureExt * const pic_ext = unit->parsed_info;
 
+    if (!is_valid_state(decoder, GST_MPEG_VIDEO_STATE_GOT_PIC_HDR))
+        return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
     if (priv->progressive_sequence && !pic_ext->progressive_frame) {
         GST_WARNING("invalid interlaced frame in progressive sequence, fixing");
         pic_ext->progressive_frame = 1;
@@ -917,6 +940,8 @@ decode_picture_ext(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnit *unit)
                     pic_ext->picture_structure);
         pic_ext->picture_structure = GST_MPEG_VIDEO_PICTURE_STRUCTURE_FRAME;
     }
+
+    priv->state |= GST_MPEG_VIDEO_STATE_GOT_PIC_EXT;
     return GST_VAAPI_DECODER_STATUS_SUCCESS;
 }
 
@@ -932,7 +957,7 @@ pack_f_code(guint8 f_code[2][2])
 static GstVaapiDecoderStatus
 init_picture(GstVaapiDecoderMpeg2 *decoder, GstVaapiPicture *picture)
 {
-    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
     GstMpegVideoPictureHdr * const pic_hdr = &priv->pic_hdr->data.pic_hdr;
     GstMpegVideoPictureExt * const pic_ext = &priv->pic_ext->data.pic_ext;
 
@@ -992,6 +1017,7 @@ init_picture(GstVaapiDecoderMpeg2 *decoder, GstVaapiPicture *picture)
         GST_VAAPI_PICTURE_FLAG_SET(
             dummy_picture,
             (GST_VAAPI_PICTURE_FLAG_SKIPPED |
+             GST_VAAPI_PICTURE_FLAG_OUTPUT  |
              GST_VAAPI_PICTURE_FLAG_REFERENCE)
         );
 
@@ -1014,7 +1040,7 @@ init_picture(GstVaapiDecoderMpeg2 *decoder, GstVaapiPicture *picture)
 static void
 fill_picture(GstVaapiDecoderMpeg2 *decoder, GstVaapiPicture *picture)
 {
-    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
     VAPictureParameterBufferMPEG2 * const pic_param = picture->param;
     GstMpegVideoPictureHdr * const pic_hdr = &priv->pic_hdr->data.pic_hdr;
     GstMpegVideoPictureExt * const pic_ext = &priv->pic_ext->data.pic_ext;
@@ -1044,7 +1070,7 @@ fill_picture(GstVaapiDecoderMpeg2 *decoder, GstVaapiPicture *picture)
     COPY_FIELD(picture_coding_extension, bits, repeat_first_field);
     COPY_FIELD(picture_coding_extension, bits, progressive_frame);
 
-    gst_vaapi_dpb_mpeg2_get_references(priv->dpb, picture,
+    gst_vaapi_dpb_get_neighbours(priv->dpb, picture,
         &prev_picture, &next_picture);
 
     switch (pic_hdr->pic_type) {
@@ -1065,14 +1091,17 @@ fill_picture(GstVaapiDecoderMpeg2 *decoder, GstVaapiPicture *picture)
 
 static GstVaapiDecoderStatus
 parse_slice(GstVaapiDecoderMpeg2 *decoder,
-    GstVaapiDecoderUnit *unit, GstMpegVideoPacket *packet)
+    GstVaapiDecoderUnit *unit, const GstMpegVideoPacket *packet)
 {
-    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
     GstMpegVideoSliceHdr *slice_hdr;
-    GstBitReader br;
-    gint mb_x, mb_y, mb_inc;
-    guint8 slice_vertical_position_extension;
-    guint8 extra_bit_slice, junk8;
+    GstMpegVideoSequenceHdr *seq_hdr;
+    GstMpegVideoSequenceScalableExt *seq_scalable_ext;
+
+    priv->state &= (GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR|
+                    GST_MPEG_VIDEO_STATE_GOT_SEQ_EXT|
+                    GST_MPEG_VIDEO_STATE_GOT_PIC_HDR|
+                    GST_MPEG_VIDEO_STATE_GOT_PIC_EXT);
 
     if (!gst_vaapi_parser_info_mpeg2_ensure(&priv->slice_hdr)) {
         GST_ERROR("failed to allocate parser info for slice header");
@@ -1080,65 +1109,45 @@ parse_slice(GstVaapiDecoderMpeg2 *decoder,
     }
 
     slice_hdr = &priv->slice_hdr->data.slice_hdr;
+    seq_hdr = &priv->seq_hdr->data.seq_hdr;
+    seq_scalable_ext = priv->seq_scalable_ext ?
+        &priv->seq_scalable_ext->data.seq_scalable_ext : NULL;
 
-    gst_bit_reader_init(&br, packet->data + packet->offset, packet->size);
-    if (priv->height > 2800)
-        READ_UINT8(&br, slice_vertical_position_extension, 3);
-    if (priv->seq_scalable_ext) {
-        GST_ERROR("failed to parse slice with sequence_scalable_extension()");
+    if (!gst_mpeg_video_packet_parse_slice_header(packet, slice_hdr,
+            seq_hdr, seq_scalable_ext)) {
+        GST_ERROR("failed to parse slice header");
         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
     }
-    READ_UINT8(&br, slice_hdr->quantiser_scale_code, 5);
-    READ_UINT8(&br, extra_bit_slice, 1);
-    if (!extra_bit_slice)
-        slice_hdr->intra_slice = 0;
-    else {
-        READ_UINT8(&br, slice_hdr->intra_slice, 1);
-        READ_UINT8(&br, junk8, 7);
-        READ_UINT8(&br, extra_bit_slice, 1);
-        while (extra_bit_slice) {
-            READ_UINT8(&br, junk8, 8);
-            READ_UINT8(&br, extra_bit_slice, 1);
-        }
-    }
-    slice_hdr->header_size = 32 + gst_bit_reader_get_pos(&br);
-
-    mb_y = packet->type - GST_MPEG_VIDEO_PACKET_SLICE_MIN;
-    mb_x = -1;
-    do {
-        if (!decode_vlc(&br, &mb_inc, mpeg2_mbaddr_vlc_table,
-                G_N_ELEMENTS(mpeg2_mbaddr_vlc_table))) {
-            GST_WARNING("failed to decode first macroblock_address_increment");
-            goto failed;
-        }
-        mb_x += mb_inc == GST_MPEG_VIDEO_MACROBLOCK_ESCAPE ? 33 : mb_inc;
-    } while (mb_inc == GST_MPEG_VIDEO_MACROBLOCK_ESCAPE);
-
-    slice_hdr->slice_horizontal_position = mb_x;
-    slice_hdr->slice_vertical_position   = mb_y;
 
     gst_vaapi_decoder_unit_set_parsed_info(unit, slice_hdr, NULL);
     return GST_VAAPI_DECODER_STATUS_SUCCESS;
-
-failed:
-    return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
 }
 
 static GstVaapiDecoderStatus
 decode_slice(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnit *unit)
 {
-    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
     GstVaapiPicture * const picture = priv->current_picture;
     GstVaapiSlice *slice;
     VASliceParameterBufferMPEG2 *slice_param;
     GstMpegVideoSliceHdr * const slice_hdr = unit->parsed_info;
+    GstBuffer * const buffer =
+        GST_VAAPI_DECODER_CODEC_FRAME(decoder)->input_buffer;
+    GstMapInfo map_info;
+
+    GST_DEBUG("slice %d (%u bytes)", slice_hdr->mb_row, unit->size);
 
-    GST_DEBUG("slice %d (%u bytes)", slice_hdr->slice_vertical_position,
-              unit->size);
+    if (!is_valid_state(decoder, GST_MPEG_VIDEO_STATE_VALID_PIC_HEADERS))
+        return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+    if (!gst_buffer_map(buffer, &map_info, GST_MAP_READ)) {
+        GST_ERROR("failed to map buffer");
+        return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+    }
 
     slice = GST_VAAPI_SLICE_NEW(MPEG2, decoder,
-        (GST_BUFFER_DATA(GST_VAAPI_DECODER_CODEC_FRAME(decoder)->input_buffer) +
-         unit->offset), unit->size);
+        (map_info.data + unit->offset), unit->size);
+    gst_buffer_unmap(buffer, &map_info);
     if (!slice) {
         GST_ERROR("failed to allocate slice");
         return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
@@ -1147,21 +1156,39 @@ decode_slice(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnit *unit)
 
     /* Fill in VASliceParameterBufferMPEG2 */
     slice_param                            = slice->param;
-    slice_param->macroblock_offset         = slice_hdr->header_size;
-    slice_param->slice_horizontal_position = slice_hdr->slice_horizontal_position;
-    slice_param->slice_vertical_position   = slice_hdr->slice_vertical_position;
+    slice_param->macroblock_offset         = slice_hdr->header_size + 32;
+    slice_param->slice_horizontal_position = slice_hdr->mb_column;
+    slice_param->slice_vertical_position   = slice_hdr->mb_row;
     slice_param->quantiser_scale_code      = slice_hdr->quantiser_scale_code;
     slice_param->intra_slice_flag          = slice_hdr->intra_slice;
+
+    priv->state |= GST_MPEG_VIDEO_STATE_GOT_SLICE;
     return GST_VAAPI_DECODER_STATUS_SUCCESS;
 }
 
 static inline gint
-scan_for_start_code(GstAdapter *adapter, guint ofs, guint size, guint32 *scp)
+scan_for_start_code(const guchar *buf, guint buf_size,
+    GstMpegVideoPacketTypeCode *type_ptr)
 {
-    return (gint)gst_adapter_masked_scan_uint32_peek(adapter,
-                                                     0xffffff00, 0x00000100,
-                                                     ofs, size,
-                                                     scp);
+    guint i = 0;
+
+    while (i <= (buf_size - 4)) {
+        if (buf[i + 2] > 1)
+            i += 3;
+        else if (buf[i + 1])
+            i += 2;
+        else if (buf[i] || buf[i + 2] != 1)
+            i++;
+        else
+            break;
+    }
+
+    if (i <= (buf_size - 4)) {
+        if (type_ptr)
+            *type_ptr = buf[i + 3];
+        return i;
+    }
+    return -1;
 }
 
 static GstVaapiDecoderStatus
@@ -1189,6 +1216,9 @@ parse_unit(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnit *unit,
         case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_DISPLAY:
             status = parse_sequence_display_ext(decoder, unit, packet);
             break;
+        case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_SCALABLE:
+            status = parse_sequence_scalable_ext(decoder, unit, packet);
+            break;
         case GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX:
             status = parse_quant_matrix_ext(decoder, unit, packet);
             break;
@@ -1219,7 +1249,6 @@ static GstVaapiDecoderStatus
 decode_unit(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnit *unit,
     GstMpegVideoPacket *packet)
 {
-    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
     GstMpegVideoPacketTypeCode type;
     GstMpegVideoPacketExtensionCode ext_type;
     GstVaapiDecoderStatus status;
@@ -1227,8 +1256,6 @@ decode_unit(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnit *unit,
     type = packet->type;
     switch (type) {
     case GST_MPEG_VIDEO_PACKET_PICTURE:
-        if (!priv->width || !priv->height)
-            goto unknown_picture_size;
         status = decode_picture(decoder, unit);
         break;
     case GST_MPEG_VIDEO_PACKET_SEQUENCE:
@@ -1243,12 +1270,13 @@ decode_unit(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnit *unit,
         case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_DISPLAY:
             status = decode_sequence_display_ext(decoder, unit);
             break;
+        case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_SCALABLE:
+            status = decode_sequence_scalable_ext(decoder, unit);
+            break;
         case GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX:
             status = decode_quant_matrix_ext(decoder, unit);
             break;
         case GST_MPEG_VIDEO_PACKET_EXT_PICTURE:
-            if (!priv->width || !priv->height)
-                goto unknown_picture_size;
             status = decode_picture_ext(decoder, unit);
             break;
         default:
@@ -1275,21 +1303,12 @@ decode_unit(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnit *unit,
         break;
     }
     return status;
-
-unknown_picture_size:
-    // Ignore packet while picture size is undefined
-    // i.e. missing sequence headers, or not parsed correctly
-    GST_WARNING("failed to parse picture of unknown size");
-    return GST_VAAPI_DECODER_STATUS_SUCCESS;
 }
 
 static GstVaapiDecoderStatus
 ensure_decoder(GstVaapiDecoderMpeg2 *decoder)
 {
-    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
-
-    g_return_val_if_fail(priv->is_constructed,
-                         GST_VAAPI_DECODER_STATUS_ERROR_INIT_FAILED);
+    GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
 
     if (!priv->is_opened) {
         priv->is_opened = gst_vaapi_decoder_mpeg2_open(decoder);
@@ -1307,48 +1326,47 @@ gst_vaapi_decoder_mpeg2_parse(GstVaapiDecoder *base_decoder,
         GST_VAAPI_DECODER_MPEG2_CAST(base_decoder);
     GstVaapiParserState * const ps = GST_VAAPI_PARSER_STATE(base_decoder);
     GstVaapiDecoderStatus status;
-    GstMpegVideoPacketTypeCode type;
-    guint32 start_code;
-    guint size, buf_size, flags;
-    gint ofs, ofs2;
+    GstMpegVideoPacketTypeCode type, type2 = GST_MPEG_VIDEO_PACKET_NONE;
+    const guchar *buf;
+    guint buf_size, flags;
+    gint ofs, ofs1, ofs2;
 
     status = ensure_decoder(decoder);
     if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
         return status;
 
-    size = gst_adapter_available(adapter);
-    if (size < 4)
+    buf_size = gst_adapter_available(adapter);
+    if (buf_size < 4)
         return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
 
-    ofs = scan_for_start_code(adapter, 0, size, &start_code);
-    if (ofs < 0)
+    buf = gst_adapter_map(adapter, buf_size);
+    if (!buf)
         return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
 
-    if (ofs > 0) {
-        gst_adapter_flush(adapter, ofs);
-        size -= ofs;
-    }
+    ofs = scan_for_start_code(buf, buf_size, &type);
+    if (ofs < 0)
+        return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+    ofs1 = ofs;
 
-    ofs2 = ps->input_offset2 - ofs - 4;
-    if (ofs2 < 4)
-        ofs2 = 4;
+    ofs2 = ps->input_offset2 - 4;
+    if (ofs2 < ofs1 + 4)
+        ofs2 = ofs1 + 4;
 
-    ofs = G_UNLIKELY(size < ofs2 + 4) ? -1 :
-        scan_for_start_code(adapter, ofs2, size - ofs2, NULL);
+    ofs = G_UNLIKELY(buf_size < ofs2 + 4) ? -1 :
+        scan_for_start_code(&buf[ofs2], buf_size - ofs2, &type2);
     if (ofs < 0) {
         // Assume the whole packet is present if end-of-stream
         if (!at_eos) {
-            ps->input_offset2 = size;
+            ps->input_offset2 = buf_size;
             return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
         }
-        ofs = size;
+        ofs = buf_size - ofs2;
     }
-    buf_size = ofs;
-    ps->input_offset2 = 0;
-
-    unit->size = buf_size;
+    ofs2 += ofs;
 
-    type = start_code & 0xff;
+    unit->size = ofs2 - ofs1;
+    gst_adapter_flush(adapter, ofs1);
+    ps->input_offset2 = 4;
 
     /* Check for start of new picture */
     flags = 0;
@@ -1366,13 +1384,24 @@ gst_vaapi_decoder_mpeg2_parse(GstVaapiDecoder *base_decoder,
         flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
         break;
     case GST_MPEG_VIDEO_PACKET_EXTENSION:
-        if (G_UNLIKELY(buf_size < 5))
+        if (G_UNLIKELY(unit->size < 5))
             return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
         break;
     default:
         if (type >= GST_MPEG_VIDEO_PACKET_SLICE_MIN &&
-            type <= GST_MPEG_VIDEO_PACKET_SLICE_MAX)
+            type <= GST_MPEG_VIDEO_PACKET_SLICE_MAX) {
             flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE;
+            switch (type2) {
+            case GST_MPEG_VIDEO_PACKET_USER_DATA:
+            case GST_MPEG_VIDEO_PACKET_SEQUENCE:
+            case GST_MPEG_VIDEO_PACKET_GOP:
+            case GST_MPEG_VIDEO_PACKET_PICTURE:
+                flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END;
+                break;
+            default:
+                break;
+            }
+        }
 
         // Ignore system start codes (PES headers)
         else if (type >= 0xb9 && type <= 0xff)
@@ -1391,19 +1420,26 @@ gst_vaapi_decoder_mpeg2_decode(GstVaapiDecoder *base_decoder,
         GST_VAAPI_DECODER_MPEG2_CAST(base_decoder);
     GstVaapiDecoderStatus status;
     GstMpegVideoPacket packet;
+    GstBuffer * const buffer =
+        GST_VAAPI_DECODER_CODEC_FRAME(decoder)->input_buffer;
+    GstMapInfo map_info;
 
     status = ensure_decoder(decoder);
     if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
         return status;
 
-    packet.data =
-        (GST_BUFFER_DATA(GST_VAAPI_DECODER_CODEC_FRAME(decoder)->input_buffer) +
-         unit->offset);
+    if (!gst_buffer_map(buffer, &map_info, GST_MAP_READ)) {
+        GST_ERROR("failed to map buffer");
+        return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+    }
+
+    packet.data = map_info.data + unit->offset;
     packet.size = unit->size;
     packet.type = packet.data[3];
     packet.offset = 4;
 
     status = parse_unit(decoder, unit, &packet);
+    gst_buffer_unmap(buffer, &map_info);
     if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
         return status;
     return decode_unit(decoder, unit, &packet);
@@ -1415,19 +1451,16 @@ gst_vaapi_decoder_mpeg2_start_frame(GstVaapiDecoder *base_decoder,
 {
     GstVaapiDecoderMpeg2 * const decoder =
         GST_VAAPI_DECODER_MPEG2_CAST(base_decoder);
-    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
     GstMpegVideoSequenceHdr *seq_hdr;
     GstMpegVideoSequenceExt *seq_ext;
     GstMpegVideoSequenceDisplayExt *seq_display_ext;
     GstVaapiPicture *picture;
     GstVaapiDecoderStatus status;
 
-    if (!priv->width || !priv->height) {
-        // Ignore packet while picture size is undefined
-        // i.e. missing sequence headers, or not parsed correctly
-        GST_WARNING("failed to decode picture of unknown size");
+    if (!is_valid_state(decoder, GST_MPEG_VIDEO_STATE_VALID_PIC_HEADERS))
         return GST_VAAPI_DECODER_STATUS_SUCCESS;
-    }
+    priv->state &= ~GST_MPEG_VIDEO_STATE_VALID_PIC_HEADERS;
 
     seq_hdr = &priv->seq_hdr->data.seq_hdr;
     seq_ext = priv->seq_ext ? &priv->seq_ext->data.seq_ext : NULL;
@@ -1463,6 +1496,15 @@ gst_vaapi_decoder_mpeg2_start_frame(GstVaapiDecoder *base_decoder,
     gst_vaapi_picture_replace(&priv->current_picture, picture);
     gst_vaapi_picture_unref(picture);
 
+    /* Update cropping rectangle */
+    /* XXX: handle picture_display_extension() */
+    if (seq_display_ext && priv->pic_display_ext) {
+        GstVaapiRectangle * const crop_rect = &priv->crop_rect;
+        if (crop_rect->x + crop_rect->width <= priv->width &&
+            crop_rect->y + crop_rect->height <= priv->height)
+            gst_vaapi_picture_set_crop_rect(picture, crop_rect);
+    }
+
     status = ensure_quant_matrix(decoder, picture);
     if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
         GST_ERROR("failed to reset quantizer matrix");
@@ -1474,6 +1516,8 @@ gst_vaapi_decoder_mpeg2_start_frame(GstVaapiDecoder *base_decoder,
         return status;
 
     fill_picture(decoder, picture);
+
+    priv->state |= GST_MPEG_VIDEO_STATE_VALID_PIC_HEADERS;
     return GST_VAAPI_DECODER_STATUS_SUCCESS;
 }
 
@@ -1486,57 +1530,47 @@ gst_vaapi_decoder_mpeg2_end_frame(GstVaapiDecoder *base_decoder)
     return decode_current_picture(decoder);
 }
 
-static void
-gst_vaapi_decoder_mpeg2_finalize(GObject *object)
-{
-    GstVaapiDecoderMpeg2 * const decoder = GST_VAAPI_DECODER_MPEG2_CAST(object);
-
-    gst_vaapi_decoder_mpeg2_destroy(decoder);
-
-    G_OBJECT_CLASS(gst_vaapi_decoder_mpeg2_parent_class)->finalize(object);
-}
-
-static void
-gst_vaapi_decoder_mpeg2_constructed(GObject *object)
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_mpeg2_flush(GstVaapiDecoder *base_decoder)
 {
-    GstVaapiDecoderMpeg2 * const decoder = GST_VAAPI_DECODER_MPEG2_CAST(object);
-    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
-    GObjectClass *parent_class;
-
-    parent_class = G_OBJECT_CLASS(gst_vaapi_decoder_mpeg2_parent_class);
-    if (parent_class->constructed)
-        parent_class->constructed(object);
+    GstVaapiDecoderMpeg2 * const decoder =
+        GST_VAAPI_DECODER_MPEG2_CAST(base_decoder);
+    GstVaapiDecoderMpeg2Private * const priv = &decoder->priv;
 
-    priv->is_constructed = gst_vaapi_decoder_mpeg2_create(decoder);
+    gst_vaapi_dpb_flush(priv->dpb);
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
 }
 
 static void
 gst_vaapi_decoder_mpeg2_class_init(GstVaapiDecoderMpeg2Class *klass)
 {
-    GObjectClass * const object_class = G_OBJECT_CLASS(klass);
+    GstVaapiMiniObjectClass * const object_class =
+        GST_VAAPI_MINI_OBJECT_CLASS(klass);
     GstVaapiDecoderClass * const decoder_class = GST_VAAPI_DECODER_CLASS(klass);
 
-    g_type_class_add_private(klass, sizeof(GstVaapiDecoderMpeg2Private));
-
-    object_class->finalize      = gst_vaapi_decoder_mpeg2_finalize;
-    object_class->constructed   = gst_vaapi_decoder_mpeg2_constructed;
+    object_class->size          = sizeof(GstVaapiDecoderMpeg2);
+    object_class->finalize      = (GDestroyNotify)gst_vaapi_decoder_finalize;
 
+    decoder_class->create       = gst_vaapi_decoder_mpeg2_create;
+    decoder_class->destroy      = gst_vaapi_decoder_mpeg2_destroy;
     decoder_class->parse        = gst_vaapi_decoder_mpeg2_parse;
     decoder_class->decode       = gst_vaapi_decoder_mpeg2_decode;
     decoder_class->start_frame  = gst_vaapi_decoder_mpeg2_start_frame;
     decoder_class->end_frame    = gst_vaapi_decoder_mpeg2_end_frame;
+    decoder_class->flush        = gst_vaapi_decoder_mpeg2_flush;
 }
 
-static void
-gst_vaapi_decoder_mpeg2_init(GstVaapiDecoderMpeg2 *decoder)
+static inline const GstVaapiDecoderClass *
+gst_vaapi_decoder_mpeg2_class(void)
 {
-    GstVaapiDecoderMpeg2Private *priv;
+    static GstVaapiDecoderMpeg2Class g_class;
+    static gsize g_class_init = FALSE;
 
-    priv                        = GST_VAAPI_DECODER_MPEG2_GET_PRIVATE(decoder);
-    decoder->priv               = priv;
-    priv->hw_profile            = GST_VAAPI_PROFILE_UNKNOWN;
-    priv->profile               = GST_VAAPI_PROFILE_MPEG2_SIMPLE;
-    priv->profile_changed       = TRUE; /* Allow fallbacks to work */
+    if (g_once_init_enter(&g_class_init)) {
+        gst_vaapi_decoder_mpeg2_class_init(&g_class);
+        g_once_init_leave(&g_class_init, TRUE);
+    }
+    return GST_VAAPI_DECODER_CLASS(&g_class);
 }
 
 /**
@@ -1552,20 +1586,6 @@ gst_vaapi_decoder_mpeg2_init(GstVaapiDecoderMpeg2 *decoder)
 GstVaapiDecoder *
 gst_vaapi_decoder_mpeg2_new(GstVaapiDisplay *display, GstCaps *caps)
 {
-    GstVaapiDecoderMpeg2 *decoder;
-
-    g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
-    g_return_val_if_fail(GST_IS_CAPS(caps), NULL);
-
-    decoder = g_object_new(
-        GST_VAAPI_TYPE_DECODER_MPEG2,
-        "display",      display,
-        "caps",         caps,
-        NULL
-    );
-    if (!decoder->priv->is_constructed) {
-        g_object_unref(decoder);
-        return NULL;
-    }
-    return GST_VAAPI_DECODER_CAST(decoder);
+    return gst_vaapi_decoder_new(gst_vaapi_decoder_mpeg2_class(),
+        display, caps);
 }