Add initial MPEG-2 decoder.
authorGwenole Beauchesne <gwenole.beauchesne@intel.com>
Fri, 5 Aug 2011 09:55:11 +0000 (11:55 +0200)
committerGwenole Beauchesne <gwenole.beauchesne@intel.com>
Mon, 16 Jan 2012 10:40:50 +0000 (11:40 +0100)
gst-libs/gst/vaapi/Makefile.am
gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c [new file with mode: 0644]
gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.h [new file with mode: 0644]
gst/vaapi/gstvaapidecode.c
tests/test-decode.c

index 4333aa3..8023944 100644 (file)
@@ -144,8 +144,10 @@ endif
 
 if USE_CODEC_PARSERS
 libgstvaapi_source_c   += \
+       gstvaapidecoder_mpeg2.c                 \
        $(NULL)
 libgstvaapi_source_h   += \
+       gstvaapidecoder_mpeg2.h                 \
        $(NULL)
 libgstvaapi_cflags     += $(GST_CODEC_PARSERS_CFLAGS)
 libgstvaapi_libs       += $(GST_CODEC_PARSERS_LIBS)
diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c b/gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c
new file mode 100644 (file)
index 0000000..5a5d376
--- /dev/null
@@ -0,0 +1,942 @@
+/*
+ *  gstvaapidecoder_mpeg2.c - MPEG-2 decoder
+ *
+ *  Copyright (C) 2011 Intel Corporation
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapidecoder_mpeg2
+ * @short_description: MPEG-2 decoder
+ */
+
+#include "config.h"
+#include <string.h>
+#include <gst/base/gstbitreader.h>
+#include <gst/codecparsers/gstmpegvideoparser.h>
+#include "gstvaapidecoder_mpeg2.h"
+#include "gstvaapidecoder_priv.h"
+#include "gstvaapidisplay_priv.h"
+#include "gstvaapiobject_priv.h"
+#include "gstvaapiutils_tsb.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+G_DEFINE_TYPE(GstVaapiDecoderMpeg2,
+              gst_vaapi_decoder_mpeg2,
+              GST_VAAPI_TYPE_DECODER);
+
+#define GST_VAAPI_DECODER_MPEG2_GET_PRIVATE(obj)                \
+    (G_TYPE_INSTANCE_GET_PRIVATE((obj),                         \
+                                 GST_VAAPI_TYPE_DECODER_MPEG2,  \
+                                 GstVaapiDecoderMpeg2Private))
+
+#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
+
+struct _GstVaapiDecoderMpeg2Private {
+    GstVaapiProfile             profile;
+    guint                       width;
+    guint                       height;
+    guint                       fps_n;
+    guint                       fps_d;
+    GstMpegVideoSequenceHdr     seq_hdr;
+    GstMpegVideoSequenceExt     seq_ext;
+    GstMpegVideoPictureHdr      pic_hdr;
+    GstMpegVideoPictureExt      pic_ext;
+    GstMpegVideoQuantMatrixExt  quant_matrix_ext;
+    GstVaapiPicture            *current_picture;
+    GstVaapiPicture            *next_picture;
+    GstVaapiPicture            *prev_picture;
+    GstVaapiTSB                *tsb;
+    GstBuffer                  *sub_buffer;
+    guint                       mb_y;
+    guint                       mb_height;
+    GstClockTime                seq_pts;
+    GstClockTime                gop_pts;
+    GstClockTime                pts_diff;
+    guint                       is_constructed          : 1;
+    guint                       is_opened               : 1;
+    guint                       is_first_field          : 1;
+    guint                       has_seq_ext             : 1;
+    guint                       has_seq_scalable_ext    : 1;
+    guint                       has_pic_ext             : 1;
+    guint                       has_quant_matrix_ext    : 1;
+    guint                       size_changed            : 1;
+    guint                       profile_changed         : 1;
+    guint                       quant_matrix_changed    : 1;
+    guint                       progressive_sequence    : 1;
+};
+
+static void
+gst_vaapi_decoder_mpeg2_close(GstVaapiDecoderMpeg2 *decoder)
+{
+    GstVaapiDecoder * const base_decoder = GST_VAAPI_DECODER(decoder);
+    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+
+    if (priv->current_picture) {
+        gst_vaapi_decoder_free_picture(base_decoder, priv->current_picture);
+        priv->current_picture = NULL;
+    }
+
+    if (priv->next_picture) {
+        gst_vaapi_decoder_free_picture(base_decoder, priv->next_picture);
+        priv->next_picture = NULL;
+    }
+
+    if (priv->prev_picture) {
+        gst_vaapi_decoder_free_picture(base_decoder, priv->prev_picture);
+        priv->prev_picture = NULL;
+    }
+
+    if (priv->sub_buffer) {
+        gst_buffer_unref(priv->sub_buffer);
+        priv->sub_buffer = NULL;
+    }
+
+    if (priv->tsb) {
+        gst_vaapi_tsb_destroy(priv->tsb);
+        priv->tsb = NULL;
+    }
+}
+
+static gboolean
+gst_vaapi_decoder_mpeg2_open(GstVaapiDecoderMpeg2 *decoder, GstBuffer *buffer)
+{
+    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+
+    gst_vaapi_decoder_mpeg2_close(decoder);
+
+    priv->tsb = gst_vaapi_tsb_new();
+    if (!priv->tsb)
+        return FALSE;
+    return TRUE;
+}
+
+static void
+gst_vaapi_decoder_mpeg2_destroy(GstVaapiDecoderMpeg2 *decoder)
+{
+    gst_vaapi_decoder_mpeg2_close(decoder);
+}
+
+static gboolean
+gst_vaapi_decoder_mpeg2_create(GstVaapiDecoderMpeg2 *decoder)
+{
+    if (!GST_VAAPI_DECODER_CODEC(decoder))
+        return FALSE;
+    return TRUE;
+}
+
+static inline void
+copy_quant_matrix(guint8 dst[64], const guint8 src[64])
+{
+    memcpy(dst, src, 64);
+}
+
+static GstVaapiDecoderStatus
+ensure_context(GstVaapiDecoderMpeg2 *decoder)
+{
+    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstVaapiProfile profiles[2];
+    GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_VLD;
+    guint i, n_profiles = 0;
+    gboolean reset_context = FALSE;
+
+    if (priv->profile_changed) {
+        GST_DEBUG("profile changed");
+        priv->profile_changed = FALSE;
+        reset_context         = TRUE;
+
+        profiles[n_profiles++] = priv->profile;
+        if (priv->profile == GST_VAAPI_PROFILE_MPEG2_SIMPLE)
+            profiles[n_profiles++] = GST_VAAPI_PROFILE_MPEG2_MAIN;
+
+        for (i = 0; i < n_profiles; i++) {
+            if (gst_vaapi_display_has_decoder(GST_VAAPI_DECODER_DISPLAY(decoder),
+                                              profiles[i], entrypoint))
+                break;
+        }
+        if (i == n_profiles)
+            return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+        priv->profile = profiles[i];
+    }
+
+    if (priv->size_changed) {
+        GST_DEBUG("size changed");
+        priv->size_changed = FALSE;
+        reset_context      = TRUE;
+
+        if (priv->progressive_sequence)
+            priv->mb_height = (priv->height + 15) / 16;
+        else
+            priv->mb_height = (priv->height + 31) / 32 * 2;
+    }
+
+    if (reset_context) {
+        reset_context = gst_vaapi_decoder_ensure_context(
+            GST_VAAPI_DECODER(decoder),
+            priv->profile,
+            entrypoint,
+            priv->width, priv->height
+        );
+        if (!reset_context)
+            return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+    }
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+ensure_quant_matrix(GstVaapiDecoderMpeg2 *decoder, GstVaapiPicture *picture)
+{
+    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    VAIQMatrixBufferMPEG2 *iq_matrix;
+    guint8 *intra_quant_matrix = NULL;
+    guint8 *non_intra_quant_matrix = NULL;
+    guint8 *chroma_intra_quant_matrix = NULL;
+    guint8 *chroma_non_intra_quant_matrix = NULL;
+
+    if (!priv->quant_matrix_changed)
+        return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+    priv->quant_matrix_changed = FALSE;
+
+    picture->iq_matrix = gst_vaapi_decoder_new_iq_matrix(GST_VAAPI_DECODER(decoder));
+    if (!picture->iq_matrix) {
+        GST_DEBUG("failed to allocate IQ matrix");
+        return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+    }
+    iq_matrix = picture->iq_matrix->param;
+
+    intra_quant_matrix     = priv->seq_hdr.intra_quantizer_matrix;
+    non_intra_quant_matrix = priv->seq_hdr.non_intra_quantizer_matrix;
+    if (priv->has_quant_matrix_ext) {
+        if (priv->quant_matrix_ext.load_intra_quantiser_matrix)
+            intra_quant_matrix = priv->quant_matrix_ext.intra_quantiser_matrix;
+        if (priv->quant_matrix_ext.load_non_intra_quantiser_matrix)
+            non_intra_quant_matrix = priv->quant_matrix_ext.non_intra_quantiser_matrix;
+        if (priv->quant_matrix_ext.load_chroma_intra_quantiser_matrix)
+            chroma_intra_quant_matrix = priv->quant_matrix_ext.chroma_intra_quantiser_matrix;
+        if (priv->quant_matrix_ext.load_chroma_non_intra_quantiser_matrix)
+            chroma_non_intra_quant_matrix = priv->quant_matrix_ext.chroma_non_intra_quantiser_matrix;
+    }
+
+    iq_matrix->load_intra_quantiser_matrix = intra_quant_matrix != NULL;
+    if (intra_quant_matrix) {
+        iq_matrix->load_intra_quantiser_matrix = 1;
+        copy_quant_matrix(iq_matrix->intra_quantiser_matrix,
+                          intra_quant_matrix);
+    }
+
+    iq_matrix->load_intra_quantiser_matrix = 1;
+    copy_quant_matrix(iq_matrix->intra_quantiser_matrix,
+                      priv->seq_hdr.intra_quantizer_matrix);
+
+    iq_matrix->load_non_intra_quantiser_matrix = 1;
+    copy_quant_matrix(iq_matrix->non_intra_quantiser_matrix,
+                      priv->seq_hdr.non_intra_quantizer_matrix);
+
+    iq_matrix->load_chroma_intra_quantiser_matrix     = 0;
+    iq_matrix->load_chroma_non_intra_quantiser_matrix = 0;
+    if (priv->has_quant_matrix_ext) {
+        if (priv->quant_matrix_ext.load_intra_quantiser_matrix)
+            copy_quant_matrix(iq_matrix->intra_quantiser_matrix,
+                              priv->quant_matrix_ext.intra_quantiser_matrix);
+
+        if (priv->quant_matrix_ext.load_non_intra_quantiser_matrix)
+            copy_quant_matrix(iq_matrix->non_intra_quantiser_matrix,
+                              priv->quant_matrix_ext.non_intra_quantiser_matrix);
+
+        if (priv->quant_matrix_ext.load_chroma_intra_quantiser_matrix) {
+            iq_matrix->load_chroma_intra_quantiser_matrix = 1;
+            copy_quant_matrix(iq_matrix->chroma_intra_quantiser_matrix,
+                              priv->quant_matrix_ext.chroma_intra_quantiser_matrix);
+        }
+
+        if (priv->quant_matrix_ext.load_chroma_non_intra_quantiser_matrix) {
+            iq_matrix->load_chroma_non_intra_quantiser_matrix = 1;
+            copy_quant_matrix(iq_matrix->chroma_non_intra_quantiser_matrix,
+                              priv->quant_matrix_ext.chroma_non_intra_quantiser_matrix);
+        }
+    }
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static inline GstVaapiDecoderStatus
+render_picture(GstVaapiDecoderMpeg2 *decoder, GstVaapiPicture *picture)
+{
+    GstVaapiDecoder * const base_decoder = GST_VAAPI_DECODER(decoder);
+
+    if (!gst_vaapi_decoder_push_surface(base_decoder,
+                                        picture->surface,
+                                        picture->pts))
+        return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_current_picture(GstVaapiDecoderMpeg2 *decoder)
+{
+    GstVaapiDecoder * const base_decoder = GST_VAAPI_DECODER(decoder);
+    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstVaapiPicture * const picture = priv->current_picture;
+    GstVaapiDecoderStatus status = GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+    if (picture) {
+        if (!gst_vaapi_decoder_decode_picture(base_decoder, picture))
+            status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+        if (!GST_VAAPI_PICTURE_IS_REFERENCE(picture)) {
+            if (priv->prev_picture && priv->next_picture)
+                status = render_picture(decoder, picture);
+            gst_vaapi_decoder_free_picture(base_decoder, picture);
+        }
+        priv->current_picture = NULL;
+    }
+    return status;
+}
+
+static GstVaapiDecoderStatus
+decode_sequence(GstVaapiDecoderMpeg2 *decoder, guchar *buf, guint buf_size)
+{
+    GstVaapiDecoder * const base_decoder = GST_VAAPI_DECODER(decoder);
+    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstMpegVideoSequenceHdr * const seq_hdr = &priv->seq_hdr;
+
+    if (!gst_mpeg_video_parse_sequence_header(seq_hdr, buf, buf_size, 0)) {
+        GST_DEBUG("failed to parse sequence header");
+        return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+    }
+
+    priv->fps_n = seq_hdr->fps_n;
+    priv->fps_d = seq_hdr->fps_d;
+    gst_vaapi_decoder_set_framerate(base_decoder, priv->fps_n, priv->fps_d);
+
+    priv->seq_pts = gst_vaapi_tsb_get_timestamp(priv->tsb);
+
+    priv->width                 = seq_hdr->width;
+    priv->height                = seq_hdr->height;
+    priv->has_seq_ext           = FALSE;
+    priv->size_changed          = TRUE;
+    priv->quant_matrix_changed  = TRUE;
+    priv->progressive_sequence  = TRUE;
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_sequence_ext(GstVaapiDecoderMpeg2 *decoder, guchar *buf, guint buf_size)
+{
+    GstVaapiDecoder * const base_decoder = GST_VAAPI_DECODER(decoder);
+    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstMpegVideoSequenceExt * const seq_ext = &priv->seq_ext;
+    GstVaapiProfile profile;
+    guint width, height;
+
+    if (!gst_mpeg_video_parse_sequence_extension(seq_ext, buf, buf_size, 0)) {
+        GST_DEBUG("failed to parse sequence-extension");
+        return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+    }
+    priv->has_seq_ext = TRUE;
+    priv->progressive_sequence = seq_ext->progressive;
+
+    width  = (priv->width  & 0xffff) | ((guint32)seq_ext->horiz_size_ext << 16);
+    height = (priv->height & 0xffff) | ((guint32)seq_ext->vert_size_ext  << 16);
+    GST_DEBUG("video resolution %ux%u", width, height);
+
+    if (seq_ext->fps_n_ext && seq_ext->fps_d_ext) {
+        priv->fps_n *= seq_ext->fps_n_ext + 1;
+        priv->fps_d *= seq_ext->fps_d_ext + 1;
+        gst_vaapi_decoder_set_framerate(base_decoder, priv->fps_n, priv->fps_d);
+    }
+
+    if (priv->width != width) {
+        priv->width = width;
+        priv->size_changed = TRUE;
+    }
+
+    if (priv->height != height) {
+        priv->height = height;
+        priv->size_changed = TRUE;
+    }
+
+    switch (seq_ext->profile) {
+    case GST_MPEG_VIDEO_PROFILE_SIMPLE:
+        profile = GST_VAAPI_PROFILE_MPEG2_SIMPLE;
+        break;
+    case GST_MPEG_VIDEO_PROFILE_MAIN:
+        profile = GST_VAAPI_PROFILE_MPEG2_MAIN;
+        break;
+    default:
+        GST_DEBUG("unsupported profile %d", seq_ext->profile);
+        return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+    }
+    if (priv->profile != profile) {
+        priv->profile = profile;
+        priv->profile_changed = TRUE;
+    }
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_sequence_end(GstVaapiDecoderMpeg2 *decoder)
+{
+    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstVaapiDecoderStatus status;
+
+    if (priv->current_picture) {
+        status = decode_current_picture(decoder);
+        if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+            return status;
+        status = render_picture(decoder, priv->current_picture);
+        if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+            return status;
+    }
+
+    if (priv->next_picture) {
+        status = render_picture(decoder, priv->next_picture);
+        if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+            return status;
+    }
+    return GST_VAAPI_DECODER_STATUS_END_OF_STREAM;
+}
+
+static GstVaapiDecoderStatus
+decode_quant_matrix_ext(GstVaapiDecoderMpeg2 *decoder, guchar *buf, guint buf_size)
+{
+    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstMpegVideoQuantMatrixExt * const quant_matrix_ext = &priv->quant_matrix_ext;
+
+    if (!gst_mpeg_video_parse_quant_matrix_extension(quant_matrix_ext, buf, buf_size, 0)) {
+        GST_DEBUG("failed to parse quant-matrix-extension");
+        return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+    }
+    priv->has_quant_matrix_ext = TRUE;
+    priv->quant_matrix_changed = TRUE;
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_gop(GstVaapiDecoderMpeg2 *decoder, guchar *buf, guint buf_size)
+{
+    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstMpegVideoGop gop;
+    GstClockTime pts;
+
+    if (!gst_mpeg_video_parse_gop(&gop, buf, buf_size, 0)) {
+        GST_DEBUG("failed to parse GOP");
+        return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+    }
+
+    GST_DEBUG("GOP %02u:%02u:%02u:%02u",
+              gop.hour, gop.minute, gop.second, gop.frame);
+
+    pts = GST_SECOND * (gop.hour * 3600 + gop.minute * 60 + gop.second);
+    pts += gst_util_uint64_scale(gop.frame, GST_SECOND * priv->fps_d, priv->fps_n);
+    priv->gop_pts = pts;
+    if (!priv->pts_diff)
+        priv->pts_diff = priv->seq_pts - priv->gop_pts;
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_picture(GstVaapiDecoderMpeg2 *decoder, guchar *buf, guint buf_size)
+{
+    GstVaapiDecoder * const base_decoder = GST_VAAPI_DECODER(decoder);
+    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstMpegVideoPictureHdr * const pic_hdr = &priv->pic_hdr;
+    GstVaapiPicture *picture;
+    GstVaapiDecoderStatus status;
+    GstClockTime pts;
+
+    status = ensure_context(decoder);
+    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
+        GST_DEBUG("failed to reset context");
+        return status;
+    }
+
+    if (priv->current_picture) {
+        status = decode_current_picture(decoder);
+        if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+            return status;
+    }
+
+    priv->current_picture = gst_vaapi_decoder_new_picture(base_decoder);
+    if (!priv->current_picture) {
+        GST_DEBUG("failed to allocate picture");
+        return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+    }
+    picture = priv->current_picture;
+
+    status = ensure_quant_matrix(decoder, picture);
+    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
+        GST_DEBUG("failed to reset quantizer matrix");
+        return status;
+    }
+
+    if (!gst_mpeg_video_parse_picture_header(pic_hdr, buf, buf_size, 0)) {
+        GST_DEBUG("failed to parse picture header");
+        return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+    }
+    priv->has_pic_ext = FALSE;
+
+    switch (pic_hdr->pic_type) {
+    case GST_MPEG_VIDEO_PICTURE_TYPE_I:
+        picture->type = GST_VAAPI_PICTURE_TYPE_I;
+        break;
+    case GST_MPEG_VIDEO_PICTURE_TYPE_P:
+        picture->type = GST_VAAPI_PICTURE_TYPE_P;
+        break;
+    case GST_MPEG_VIDEO_PICTURE_TYPE_B:
+        picture->type = GST_VAAPI_PICTURE_TYPE_B;
+        break;
+    default:
+        GST_DEBUG("unsupported picture type %d", pic_hdr->pic_type);
+        return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+    }
+
+    priv->mb_y = 0;
+    if (pic_hdr->pic_type == GST_MPEG_VIDEO_PICTURE_TYPE_I)
+        priv->is_first_field = TRUE;
+    else
+        priv->is_first_field ^= 1;
+
+    /* Update presentation time */
+    pts = priv->gop_pts;
+    pts += gst_util_uint64_scale(pic_hdr->tsn, GST_SECOND * priv->fps_d, priv->fps_n);
+    picture->pts = pts + priv->pts_diff;
+
+    /* Update reference pictures */
+    if (pic_hdr->pic_type != GST_MPEG_VIDEO_PICTURE_TYPE_B) {
+        picture->flags |= GST_VAAPI_PICTURE_REFERENCE;
+        if (priv->prev_picture) {
+            gst_vaapi_decoder_free_picture(base_decoder, priv->prev_picture);
+            priv->prev_picture = NULL;
+        }
+        if (priv->next_picture) {
+            priv->prev_picture = priv->next_picture;
+            priv->next_picture = NULL;
+            status = render_picture(decoder, priv->prev_picture);
+        }
+        priv->next_picture = picture;
+    }
+    return status;
+}
+
+static GstVaapiDecoderStatus
+decode_picture_ext(GstVaapiDecoderMpeg2 *decoder, guchar *buf, guint buf_size)
+{
+    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstMpegVideoPictureExt * const pic_ext = &priv->pic_ext;
+
+    if (!gst_mpeg_video_parse_picture_extension(pic_ext, buf, buf_size, 0)) {
+        GST_DEBUG("failed to parse picture-extension");
+        return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+    }
+    priv->has_pic_ext = TRUE;
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static inline guint32
+pack_f_code(guint8 f_code[2][2])
+{
+    return (((guint32)f_code[0][0] << 12) |
+            ((guint32)f_code[0][1] <<  8) |
+            ((guint32)f_code[1][0] <<  4) |
+            (         f_code[1][1]      ));
+}
+
+static gboolean
+fill_picture(GstVaapiDecoderMpeg2 *decoder, GstVaapiPicture *picture)
+{
+    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    VAPictureParameterBufferMPEG2 * const pic_param = picture->param;
+    GstMpegVideoPictureHdr * const pic_hdr = &priv->pic_hdr;
+    GstMpegVideoPictureExt * const pic_ext = &priv->pic_ext;
+
+    if (!priv->has_pic_ext)
+        return FALSE;
+
+    /* Fill in VAPictureParameterBufferMPEG2 */
+    pic_param->horizontal_size                                          = priv->width;
+    pic_param->vertical_size                                            = priv->height;
+    pic_param->forward_reference_picture                                = VA_INVALID_ID;
+    pic_param->backward_reference_picture                               = VA_INVALID_ID;
+    pic_param->picture_coding_type                                      = pic_hdr->pic_type;
+    pic_param->f_code                                                   = pack_f_code(pic_ext->f_code);
+
+#define COPY_FIELD(a, b, f) \
+    pic_param->a.b.f = pic_ext->f
+    pic_param->picture_coding_extension.value                           = 0;
+    pic_param->picture_coding_extension.bits.is_first_field             = priv->is_first_field;
+    COPY_FIELD(picture_coding_extension, bits, intra_dc_precision);
+    COPY_FIELD(picture_coding_extension, bits, picture_structure);
+    COPY_FIELD(picture_coding_extension, bits, top_field_first);
+    COPY_FIELD(picture_coding_extension, bits, frame_pred_frame_dct);
+    COPY_FIELD(picture_coding_extension, bits, concealment_motion_vectors);
+    COPY_FIELD(picture_coding_extension, bits, q_scale_type);
+    COPY_FIELD(picture_coding_extension, bits, intra_vlc_format);
+    COPY_FIELD(picture_coding_extension, bits, alternate_scan);
+    COPY_FIELD(picture_coding_extension, bits, repeat_first_field);
+    COPY_FIELD(picture_coding_extension, bits, progressive_frame);
+
+    switch (pic_hdr->pic_type) {
+    case GST_MPEG_VIDEO_PICTURE_TYPE_B:
+        if (priv->next_picture)
+            pic_param->backward_reference_picture = priv->next_picture->surface_id;
+        // fall-through
+    case GST_MPEG_VIDEO_PICTURE_TYPE_P:
+        if (priv->prev_picture)
+            pic_param->forward_reference_picture = priv->prev_picture->surface_id;
+        break;
+    }
+    return TRUE;
+}
+
+static GstVaapiDecoderStatus
+decode_slice(
+    GstVaapiDecoderMpeg2 *decoder,
+    int                   slice_no,
+    guchar               *buf,
+    guint                 buf_size
+)
+{
+    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstVaapiPicture * const picture = priv->current_picture;
+    GstVaapiSlice *slice;
+    VASliceParameterBufferMPEG2 *slice_param;
+    GstVaapiDecoderStatus status;
+    GstBitReader br;
+    guint8 slice_vertical_position_extension;
+    guint8 quantiser_scale_code;
+    guint8 intra_slice_flag, intra_slice = 0;
+    guint8 extra_bit_slice, junk8;
+
+    GST_DEBUG("slice %d @ %p, %u bytes)", slice_no, buf, buf_size);
+
+    if (picture->slices->len == 0 && !fill_picture(decoder, picture))
+        return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+
+    priv->mb_y = slice_no;
+
+    slice = gst_vaapi_decoder_new_slice(
+        GST_VAAPI_DECODER(decoder),
+        picture,
+        buf, buf_size
+    );
+    if (!slice) {
+        GST_DEBUG("failed to allocate slice");
+        return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+    }
+
+    /* Parse slice */
+    gst_bit_reader_init(&br, buf, buf_size);
+    if (priv->height > 2800)
+        READ_UINT8(&br, slice_vertical_position_extension, 3);
+    if (priv->has_seq_scalable_ext) {
+        GST_DEBUG("failed to parse slice %d. Unsupported sequence_scalable_extension()", slice_no);
+        return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+    }
+    READ_UINT8(&br, quantiser_scale_code, 5);
+    READ_UINT8(&br, extra_bit_slice, 1);
+    if (extra_bit_slice == 1) {
+        READ_UINT8(&br, intra_slice_flag, 1);
+        if (intra_slice_flag) {
+            READ_UINT8(&br, intra_slice, 1);
+            READ_UINT8(&br, junk8, 7);
+        }
+        READ_UINT8(&br, extra_bit_slice, 1);
+        while (extra_bit_slice == 1) {
+            READ_UINT8(&br, junk8, 8);
+            READ_UINT8(&br, extra_bit_slice, 1);
+        }
+    }
+
+    /* Fill in VASliceParameterBufferMPEG2 */
+    slice_param                            = slice->param;
+    slice_param->macroblock_offset         = gst_bit_reader_get_pos(&br);
+    slice_param->slice_horizontal_position = 0;
+    slice_param->slice_vertical_position   = priv->mb_y;
+    slice_param->quantiser_scale_code      = quantiser_scale_code;
+    slice_param->intra_slice_flag          = intra_slice;
+
+    /* Commit picture for decoding if we reached the last slice */
+    if (++priv->mb_y >= priv->mb_height) {
+        status = decode_current_picture(decoder);
+        if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+            return status;
+        GST_DEBUG("done");
+    }
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+failed:
+    return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+}
+
+static GstVaapiDecoderStatus
+decode_chunks(GstVaapiDecoderMpeg2 *decoder, GstBuffer *buffer, GList *chunks)
+{
+    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstMpegVideoTypeOffsetSize *tos;
+    GstVaapiDecoderStatus status;
+    guchar * const buf = GST_BUFFER_DATA(buffer);
+    guchar *data;
+    guint data_size, ofs, pos = 0;
+    GList *l;
+
+    status = GST_VAAPI_DECODER_STATUS_SUCCESS;
+    for (l = chunks; l; l = g_list_next(l)) {
+        tos       = l->data;
+        data      = buf + tos->offset;
+        data_size = tos->size;
+        if (tos->size < 0) {
+            if (tos->offset < 4)
+                return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+            priv->sub_buffer = gst_buffer_create_sub(
+                buffer,
+                tos->offset - 4,
+                GST_BUFFER_SIZE(buffer) - (tos->offset - 4)
+            );
+            break;
+        }
+
+        ofs = tos->offset - pos + tos->size;
+        gst_vaapi_tsb_pop(priv->tsb, ofs);
+        pos += ofs;
+
+        switch (tos->type) {
+        case GST_MPEG_VIDEO_PACKET_PICTURE:
+            status = decode_picture(decoder, data, data_size);
+            break;
+        case GST_MPEG_VIDEO_PACKET_SEQUENCE:
+            status = decode_sequence(decoder, data, data_size);
+            break;
+        case GST_MPEG_VIDEO_PACKET_EXTENSION: {
+            const guchar id = data[0] >> 4;
+            switch (id) {
+            case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE:
+                status = decode_sequence_ext(decoder, data, data_size);
+                break;
+            case GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX:
+                status = decode_quant_matrix_ext(decoder, data, data_size);
+                break;
+            case GST_MPEG_VIDEO_PACKET_EXT_PICTURE:
+                status = decode_picture_ext(decoder, data, data_size);
+                break;
+            default:
+                // Ignore unknown extensions
+                GST_DEBUG("unsupported start-code extension (0x%02x)", id);
+                break;
+            }
+            break;
+        }
+        case GST_MPEG_VIDEO_PACKET_SEQUENCE_END:
+            status = decode_sequence_end(decoder);
+            break;
+        case GST_MPEG_VIDEO_PACKET_GOP:
+            status = decode_gop(decoder, data, data_size);
+            break;
+        case GST_MPEG_VIDEO_PACKET_USER_DATA:
+            // Ignore user-data packets
+            status = GST_VAAPI_DECODER_STATUS_SUCCESS;
+            break;
+        default:
+            if (tos->type >= GST_MPEG_VIDEO_PACKET_SLICE_MIN &&
+                tos->type <= GST_MPEG_VIDEO_PACKET_SLICE_MAX) {
+                status = decode_slice(
+                    decoder,
+                    tos->type - GST_MPEG_VIDEO_PACKET_SLICE_MIN,
+                    data, data_size
+                );
+                break;
+            }
+            GST_DEBUG("unsupported start code (0x%02x)", tos->type);
+            status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+            break;
+        }
+        if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+            break;
+    }
+    return status;
+}
+
+static GstVaapiDecoderStatus
+decode_buffer(GstVaapiDecoderMpeg2 *decoder, GstBuffer *buffer)
+{
+    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+    GstVaapiDecoderStatus status;
+    guchar *buf;
+    guint buf_size;
+    GList *chunks;
+
+    buf      = GST_BUFFER_DATA(buffer);
+    buf_size = GST_BUFFER_SIZE(buffer);
+    if (!buf && buf_size == 0)
+        return decode_sequence_end(decoder);
+
+    gst_vaapi_tsb_push(priv->tsb, buffer);
+
+    if (priv->sub_buffer) {
+        buffer = gst_buffer_merge(priv->sub_buffer, buffer);
+        if (!buffer)
+            return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+        gst_buffer_unref(priv->sub_buffer);
+        priv->sub_buffer = NULL;
+    }
+
+    buf      = GST_BUFFER_DATA(buffer);
+    buf_size = GST_BUFFER_SIZE(buffer);
+    chunks   = gst_mpeg_video_parse(buf, buf_size, 0);
+    if (!chunks)
+        return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+
+    status = decode_chunks(decoder, buffer, chunks);
+    g_list_free_full(chunks, (GDestroyNotify)g_free);
+    return status;
+}
+
+GstVaapiDecoderStatus
+gst_vaapi_decoder_mpeg2_decode(GstVaapiDecoder *base, GstBuffer *buffer)
+{
+    GstVaapiDecoderMpeg2 * const decoder = GST_VAAPI_DECODER_MPEG2(base);
+    GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
+
+    g_return_val_if_fail(priv->is_constructed,
+                         GST_VAAPI_DECODER_STATUS_ERROR_INIT_FAILED);
+
+    if (!priv->is_opened) {
+        priv->is_opened = gst_vaapi_decoder_mpeg2_open(decoder, buffer);
+        if (!priv->is_opened)
+            return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC;
+    }
+    return decode_buffer(decoder, buffer);
+}
+
+static void
+gst_vaapi_decoder_mpeg2_finalize(GObject *object)
+{
+    GstVaapiDecoderMpeg2 * const decoder = GST_VAAPI_DECODER_MPEG2(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)
+{
+    GstVaapiDecoderMpeg2 * const decoder = GST_VAAPI_DECODER_MPEG2(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);
+
+    priv->is_constructed = gst_vaapi_decoder_mpeg2_create(decoder);
+}
+
+static void
+gst_vaapi_decoder_mpeg2_class_init(GstVaapiDecoderMpeg2Class *klass)
+{
+    GObjectClass * const object_class = G_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;
+
+    decoder_class->decode       = gst_vaapi_decoder_mpeg2_decode;
+}
+
+static void
+gst_vaapi_decoder_mpeg2_init(GstVaapiDecoderMpeg2 *decoder)
+{
+    GstVaapiDecoderMpeg2Private *priv;
+
+    priv                        = GST_VAAPI_DECODER_MPEG2_GET_PRIVATE(decoder);
+    decoder->priv               = priv;
+    priv->width                 = 0;
+    priv->height                = 0;
+    priv->fps_n                 = 0;
+    priv->fps_d                 = 0;
+    priv->profile               = GST_VAAPI_PROFILE_MPEG2_SIMPLE;
+    priv->current_picture       = NULL;
+    priv->next_picture          = NULL;
+    priv->prev_picture          = NULL;
+    priv->tsb                   = NULL;
+    priv->sub_buffer            = NULL;
+    priv->mb_y                  = 0;
+    priv->mb_height             = 0;
+    priv->seq_pts               = GST_CLOCK_TIME_NONE;
+    priv->gop_pts               = GST_CLOCK_TIME_NONE;
+    priv->pts_diff              = 0;
+    priv->is_constructed        = FALSE;
+    priv->is_opened             = FALSE;
+    priv->is_first_field        = FALSE;
+    priv->has_seq_ext           = FALSE;
+    priv->has_seq_scalable_ext  = FALSE;
+    priv->has_pic_ext           = FALSE;
+    priv->has_quant_matrix_ext  = FALSE;
+    priv->size_changed          = FALSE;
+    priv->profile_changed       = FALSE;
+    priv->quant_matrix_changed  = FALSE;
+    priv->progressive_sequence  = FALSE;
+}
+
+/**
+ * gst_vaapi_decoder_mpeg2_new:
+ * @display: a #GstVaapiDisplay
+ * @caps: a #GstCaps holding codec information
+ *
+ * Creates a new #GstVaapiDecoder for MPEG-2 decoding.  The @caps can
+ * hold extra information like codec-data and pictured coded size.
+ *
+ * Return value: the newly allocated #GstVaapiDecoder object
+ */
+GstVaapiDecoder *
+gst_vaapi_decoder_mpeg2_new(GstVaapiDisplay *display, GstCaps *caps)
+{
+    GstVaapiDecoderMpeg2 *decoder;
+
+    static const GstVaapiCodecInfo codec_info = {
+        .pic_size               = sizeof(GstVaapiPicture),
+        .slice_size             = sizeof(GstVaapiSlice),
+        .pic_param_size         = sizeof(VAPictureParameterBufferMPEG2),
+        .slice_param_size       = sizeof(VASliceParameterBufferMPEG2),
+        .iq_matrix_size         = sizeof(VAIQMatrixBufferMPEG2),
+    };
+
+    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,
+        "codec-info",   &codec_info,
+        NULL
+    );
+    if (!decoder->priv->is_constructed) {
+        g_object_unref(decoder);
+        return NULL;
+    }
+    return GST_VAAPI_DECODER_CAST(decoder);
+}
diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.h b/gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.h
new file mode 100644 (file)
index 0000000..84a9a18
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ *  gstvaapidecoder_mpeg2.h - MPEG-2 decoder
+ *
+ *  Copyright (C) 2011 Intel Corporation
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_DECODER_MPEG2_H
+#define GST_VAAPI_DECODER_MPEG2_H
+
+#include <gst/vaapi/gstvaapidecoder.h>
+
+G_BEGIN_DECLS
+
+#define GST_VAAPI_TYPE_DECODER_MPEG2 \
+    (gst_vaapi_decoder_mpeg2_get_type())
+
+#define GST_VAAPI_DECODER_MPEG2(obj)                            \
+    (G_TYPE_CHECK_INSTANCE_CAST((obj),                          \
+                                GST_VAAPI_TYPE_DECODER_MPEG2,   \
+                                GstVaapiDecoderMpeg2))
+
+#define GST_VAAPI_DECODER_MPEG2_CLASS(klass)                    \
+    (G_TYPE_CHECK_CLASS_CAST((klass),                           \
+                             GST_VAAPI_TYPE_DECODER_MPEG2,      \
+                             GstVaapiDecoderMpeg2Class))
+
+#define GST_VAAPI_IS_DECODER_MPEG2(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_DECODER_MPEG2))
+
+#define GST_VAAPI_IS_DECODER_MPEG2_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_DECODER_MPEG2))
+
+#define GST_VAAPI_DECODER_MPEG2_GET_CLASS(obj)                  \
+    (G_TYPE_INSTANCE_GET_CLASS((obj),                           \
+                               GST_VAAPI_TYPE_DECODER_MPEG2,    \
+                               GstVaapiDecoderMpeg2Class))
+
+typedef struct _GstVaapiDecoderMpeg2            GstVaapiDecoderMpeg2;
+typedef struct _GstVaapiDecoderMpeg2Private     GstVaapiDecoderMpeg2Private;
+typedef struct _GstVaapiDecoderMpeg2Class       GstVaapiDecoderMpeg2Class;
+
+/**
+ * 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;
+};
+
+GType
+gst_vaapi_decoder_mpeg2_get_type(void);
+
+GstVaapiDecoder *
+gst_vaapi_decoder_mpeg2_new(GstVaapiDisplay *display, GstCaps *caps);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_DECODER_MPEG2_H */
index d4eb118..6077502 100644 (file)
@@ -31,6 +31,7 @@
 #include "config.h"
 
 #include <gst/vaapi/gstvaapidisplay.h>
+#include <gst/vaapi/gstvaapidecoder_mpeg2.h>
 #include <gst/vaapi/gstvaapivideosink.h>
 #include <gst/vaapi/gstvaapivideobuffer.h>
 #include <gst/vaapi/gstvaapidecoder_ffmpeg.h>
@@ -49,6 +50,7 @@
 # include <gst/vaapi/gstvaapidecoder_ffmpeg.h>
 #endif
 #if USE_CODEC_PARSERS
+# include <gst/vaapi/gstvaapidecoder_mpeg2.h>
 #endif
 
 /* Favor codecparsers-based decoders for 0.3.x series */
@@ -283,6 +285,7 @@ gst_vaapidecode_create(GstVaapiDecode *decode, GstCaps *caps)
 {
     VADisplay dpy;
     GstStructure *structure;
+    int version;
 
     if (!gst_vaapi_ensure_display(decode, &decode->display))
         return FALSE;
@@ -306,6 +309,12 @@ gst_vaapidecode_create(GstVaapiDecode *decode, GstCaps *caps)
         structure = gst_caps_get_structure(caps, 0);
         if (!structure)
             return FALSE;
+        if (gst_structure_has_name(structure, "video/mpeg")) {
+            if (!gst_structure_get_int(structure, "mpegversion", &version))
+                return FALSE;
+            if (version == 2)
+                decode->decoder = gst_vaapi_decoder_mpeg2_new(dpy, caps);
+        }
 #endif
     }
     if (!decode->decoder)
index 67b00db..0f37286 100644 (file)
@@ -33,6 +33,7 @@
 # include <gst/vaapi/gstvaapidecoder_ffmpeg.h>
 #endif
 #if USE_CODEC_PARSERS
+# include <gst/vaapi/gstvaapidecoder_mpeg2.h>
 #endif
 
 /* Set to 1 to check display cache works (shared VA display) */
@@ -160,6 +161,9 @@ main(int argc, char *argv[])
     else {
 #if USE_CODEC_PARSERS
         switch (gst_vaapi_profile_get_codec(info.profile)) {
+        case GST_VAAPI_CODEC_MPEG2:
+            decoder = gst_vaapi_decoder_mpeg2_new(display, decoder_caps);
+            break;
         default:
             decoder = NULL;
             break;