* gstvaapidecoder_mpeg2.c - MPEG-2 decoder
*
* 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 --- */
/* ------------------------------------------------------------------------- */
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;
tsg->ovl_tsn++;
}
tsg->lst_tsn = pic_tsn;
+
return pts;
}
/* --- 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;
/* --- 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;
guint height;
guint fps_n;
guint fps_d;
+ guint state;
+ GstVaapiRectangle crop_rect;
GstVaapiParserInfoMpeg2 *seq_hdr;
GstVaapiParserInfoMpeg2 *seq_ext;
GstVaapiParserInfoMpeg2 *seq_display_ext;
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;
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);
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);
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);
}
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;
}
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 {
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;
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;
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;
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;
/* 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;
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;
}
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;
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;
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;
}
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);
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)) {
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;
}
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;
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)) {
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;
}
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;
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)) {
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;
}
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;
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;
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;
}
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;
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;
}
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;
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;
}
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;
GST_VAAPI_PICTURE_FLAG_SET(
dummy_picture,
(GST_VAAPI_PICTURE_FLAG_SKIPPED |
+ GST_VAAPI_PICTURE_FLAG_OUTPUT |
GST_VAAPI_PICTURE_FLAG_REFERENCE)
);
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;
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");
}
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->slice_vertical_position,
- unit->size);
+ GST_DEBUG("slice %d (%u bytes)", slice_hdr->mb_row, 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;
/* 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;
}
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;
decode_unit(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnit *unit,
GstMpegVideoPacket *packet)
{
- GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
GstMpegVideoPacketTypeCode type;
GstMpegVideoPacketExtensionCode ext_type;
GstVaapiDecoderStatus status;
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:
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:
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);
if (buf_size < 4)
return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
- buf = gst_adapter_peek(adapter, buf_size);
+ buf = gst_adapter_map(adapter, buf_size);
if (!buf)
return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
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);
{
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;
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");
return status;
fill_picture(decoder, picture);
+
+ priv->state |= GST_MPEG_VIDEO_STATE_VALID_PIC_HEADERS;
return GST_VAAPI_DECODER_STATUS_SUCCESS;
}
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);
}
/**
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);
}