2 * gstvaapidecoder_mpeg2.c - MPEG-2 decoder
4 * Copyright (C) 2011 Intel Corporation
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public License
8 * as published by the Free Software Foundation; either version 2.1
9 * of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free
18 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
23 * SECTION:gstvaapidecoder_mpeg2
24 * @short_description: MPEG-2 decoder
29 #include <gst/base/gstbitreader.h>
30 #include <gst/codecparsers/gstmpegvideoparser.h>
31 #include "gstvaapidecoder_mpeg2.h"
32 #include "gstvaapidecoder_objects.h"
33 #include "gstvaapidecoder_dpb.h"
34 #include "gstvaapidecoder_priv.h"
35 #include "gstvaapidisplay_priv.h"
36 #include "gstvaapiobject_priv.h"
39 #include "gstvaapidebug.h"
41 /* ------------------------------------------------------------------------- */
42 /* --- VLC Reader --- */
43 /* ------------------------------------------------------------------------- */
45 #define READ_UINT8(br, val, nbits) G_STMT_START { \
46 if (!gst_bit_reader_get_bits_uint8 (br, &val, nbits)) { \
47 GST_WARNING ("failed to read uint8, nbits: %d", nbits); \
52 #define SKIP(reader, nbits) G_STMT_START { \
53 if (!gst_bit_reader_skip (reader, nbits)) { \
54 GST_WARNING ("failed to skip nbits: %d", nbits); \
59 /* VLC decoder from gst-plugins-bad */
60 typedef struct _VLCTable VLCTable;
68 decode_vlc(GstBitReader *br, gint *res, const VLCTable *table, guint length)
74 for (i = 0; i < length; i++) {
75 if (cbits != table[i].cbits) {
76 cbits = table[i].cbits;
77 if (!gst_bit_reader_peek_bits_uint32(br, &value, cbits)) {
82 if (value == table[i].cword) {
85 *res = table[i].value;
89 GST_DEBUG("failed to find VLC code");
92 GST_WARNING("failed to decode VLC, returning");
97 GST_MPEG_VIDEO_MACROBLOCK_ESCAPE = -1,
100 /* Table B-1: Variable length codes for macroblock_address_increment */
101 static const VLCTable mpeg2_mbaddr_vlc_table[] = {
135 { GST_MPEG_VIDEO_MACROBLOCK_ESCAPE, 0x08, 11 }
138 /* ------------------------------------------------------------------------- */
139 /* --- PTS Generator --- */
140 /* ------------------------------------------------------------------------- */
142 typedef struct _PTSGenerator PTSGenerator;
143 struct _PTSGenerator {
144 GstClockTime gop_pts; // Current GOP PTS
145 GstClockTime max_pts; // Max picture PTS
146 guint gop_tsn; // Absolute GOP TSN
147 guint max_tsn; // Max picture TSN, relative to last GOP TSN
148 guint ovl_tsn; // How many times TSN overflowed since GOP
149 guint lst_tsn; // Last picture TSN
155 pts_init(PTSGenerator *tsg)
157 tsg->gop_pts = GST_CLOCK_TIME_NONE;
158 tsg->max_pts = GST_CLOCK_TIME_NONE;
167 static inline GstClockTime
168 pts_get_duration(PTSGenerator *tsg, guint num_frames)
170 return gst_util_uint64_scale(num_frames,
171 GST_SECOND * tsg->fps_d, tsg->fps_n);
175 pts_get_poc(PTSGenerator *tsg)
177 return tsg->gop_tsn + tsg->ovl_tsn * 1024 + tsg->lst_tsn;
181 pts_set_framerate(PTSGenerator *tsg, guint fps_n, guint fps_d)
188 pts_sync(PTSGenerator *tsg, GstClockTime gop_pts)
192 if (!GST_CLOCK_TIME_IS_VALID(gop_pts) ||
193 (GST_CLOCK_TIME_IS_VALID(tsg->max_pts) && tsg->max_pts >= gop_pts)) {
194 /* Invalid GOP PTS, interpolate from the last known picture PTS */
195 if (GST_CLOCK_TIME_IS_VALID(tsg->max_pts)) {
196 gop_pts = tsg->max_pts + pts_get_duration(tsg, 1);
197 gop_tsn = tsg->gop_tsn + tsg->ovl_tsn * 1024 + tsg->max_tsn + 1;
205 /* Interpolate GOP TSN from this valid PTS */
206 if (GST_CLOCK_TIME_IS_VALID(tsg->gop_pts))
207 gop_tsn = tsg->gop_tsn + gst_util_uint64_scale(
208 gop_pts - tsg->gop_pts + pts_get_duration(tsg, 1) - 1,
209 tsg->fps_n, GST_SECOND * tsg->fps_d);
214 tsg->gop_pts = gop_pts;
215 tsg->gop_tsn = gop_tsn;
222 pts_eval(PTSGenerator *tsg, GstClockTime pic_pts, guint pic_tsn)
226 if (!GST_CLOCK_TIME_IS_VALID(tsg->gop_pts))
229 pts = tsg->gop_pts + pts_get_duration(tsg, tsg->ovl_tsn * 1024 + pic_tsn);
231 if (!GST_CLOCK_TIME_IS_VALID(tsg->max_pts) || tsg->max_pts < pts)
234 if (tsg->max_tsn < pic_tsn)
235 tsg->max_tsn = pic_tsn;
236 else if (tsg->max_tsn == 1023 && pic_tsn < tsg->lst_tsn) { /* TSN wrapped */
237 tsg->max_tsn = pic_tsn;
240 tsg->lst_tsn = pic_tsn;
244 /* ------------------------------------------------------------------------- */
245 /* --- MPEG-2 Decoder Units --- */
246 /* ------------------------------------------------------------------------- */
248 typedef struct _GstMpegVideoSliceHdr GstMpegVideoSliceHdr;
249 struct _GstMpegVideoSliceHdr {
250 guint16 slice_horizontal_position;
251 guint16 slice_vertical_position;
252 guint8 quantiser_scale_code;
255 /* Size of the slice() header in bits */
259 typedef struct _GstVaapiDecoderUnitMpeg2 GstVaapiDecoderUnitMpeg2;
260 struct _GstVaapiDecoderUnitMpeg2 {
261 GstVaapiDecoderUnit base;
262 GstMpegVideoPacket packet;
263 guint8 extension_type; /* for Extension packets */
265 GstMpegVideoSequenceHdr seq_hdr;
266 GstMpegVideoSequenceExt seq_ext;
267 GstMpegVideoSequenceDisplayExt seq_display_ext;
269 GstMpegVideoQuantMatrixExt quant_matrix;
270 GstMpegVideoPictureHdr pic_hdr;
271 GstMpegVideoPictureExt pic_ext;
272 GstMpegVideoSliceHdr slice_hdr;
276 static GstVaapiDecoderUnitMpeg2 *
277 gst_vaapi_decoder_unit_mpeg2_new(guint size)
279 GstVaapiDecoderUnitMpeg2 *unit;
281 static const GstVaapiMiniObjectClass GstVaapiDecoderUnitMpeg2Class = {
282 sizeof(GstVaapiDecoderUnitMpeg2),
283 (GDestroyNotify)gst_vaapi_decoder_unit_finalize
286 unit = (GstVaapiDecoderUnitMpeg2 *)
287 gst_vaapi_mini_object_new(&GstVaapiDecoderUnitMpeg2Class);
291 gst_vaapi_decoder_unit_init(&unit->base, size);
295 /* ------------------------------------------------------------------------- */
296 /* --- MPEG-2 Decoder --- */
297 /* ------------------------------------------------------------------------- */
299 G_DEFINE_TYPE(GstVaapiDecoderMpeg2,
300 gst_vaapi_decoder_mpeg2,
301 GST_VAAPI_TYPE_DECODER)
303 #define GST_VAAPI_DECODER_MPEG2_CAST(decoder) \
304 ((GstVaapiDecoderMpeg2 *)(decoder))
306 #define GST_VAAPI_DECODER_MPEG2_GET_PRIVATE(obj) \
307 (G_TYPE_INSTANCE_GET_PRIVATE((obj), \
308 GST_VAAPI_TYPE_DECODER_MPEG2, \
309 GstVaapiDecoderMpeg2Private))
311 struct _GstVaapiDecoderMpeg2Private {
312 GstVaapiProfile profile;
313 GstVaapiProfile hw_profile;
318 GstVaapiDecoderUnitMpeg2 *seq_hdr_unit;
319 GstVaapiDecoderUnitMpeg2 *seq_ext_unit;
320 GstVaapiDecoderUnitMpeg2 *seq_display_ext_unit;
321 GstVaapiDecoderUnitMpeg2 *seq_scalable_ext_unit;
322 GstVaapiDecoderUnitMpeg2 *pic_hdr_unit;
323 GstVaapiDecoderUnitMpeg2 *pic_ext_unit;
324 GstVaapiDecoderUnitMpeg2 *quant_matrix_unit;
325 GstVaapiPicture *current_picture;
328 guint is_constructed : 1;
330 guint size_changed : 1;
331 guint profile_changed : 1;
332 guint quant_matrix_changed : 1;
333 guint progressive_sequence : 1;
334 guint closed_gop : 1;
335 guint broken_link : 1;
339 gst_vaapi_decoder_mpeg2_close(GstVaapiDecoderMpeg2 *decoder)
341 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
343 gst_vaapi_picture_replace(&priv->current_picture, NULL);
345 gst_vaapi_decoder_unit_replace(&priv->seq_hdr_unit, NULL);
346 gst_vaapi_decoder_unit_replace(&priv->seq_ext_unit, NULL);
347 gst_vaapi_decoder_unit_replace(&priv->seq_display_ext_unit, NULL);
348 gst_vaapi_decoder_unit_replace(&priv->seq_scalable_ext_unit, NULL);
349 gst_vaapi_decoder_unit_replace(&priv->pic_hdr_unit, NULL);
350 gst_vaapi_decoder_unit_replace(&priv->pic_ext_unit, NULL);
351 gst_vaapi_decoder_unit_replace(&priv->quant_matrix_unit, NULL);
354 gst_vaapi_dpb_unref(priv->dpb);
360 gst_vaapi_decoder_mpeg2_open(GstVaapiDecoderMpeg2 *decoder)
362 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
364 gst_vaapi_decoder_mpeg2_close(decoder);
366 priv->dpb = gst_vaapi_dpb_mpeg2_new();
370 pts_init(&priv->tsg);
375 gst_vaapi_decoder_mpeg2_destroy(GstVaapiDecoderMpeg2 *decoder)
377 gst_vaapi_decoder_mpeg2_close(decoder);
381 gst_vaapi_decoder_mpeg2_create(GstVaapiDecoderMpeg2 *decoder)
383 if (!GST_VAAPI_DECODER_CODEC(decoder))
389 copy_quant_matrix(guint8 dst[64], const guint8 src[64])
391 memcpy(dst, src, 64);
395 get_profile_str(GstVaapiProfile profile)
400 case GST_VAAPI_PROFILE_MPEG2_SIMPLE: str = "simple"; break;
401 case GST_VAAPI_PROFILE_MPEG2_MAIN: str = "main"; break;
402 case GST_VAAPI_PROFILE_MPEG2_HIGH: str = "high"; break;
403 default: str = "<unknown>"; break;
408 static GstVaapiProfile
409 get_profile(GstVaapiDecoderMpeg2 *decoder, GstVaapiEntrypoint entrypoint)
411 GstVaapiDisplay * const va_display = GST_VAAPI_DECODER_DISPLAY(decoder);
412 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
413 GstVaapiProfile profile = priv->profile;
416 /* Return immediately if the exact same profile was found */
417 if (gst_vaapi_display_has_decoder(va_display, profile, entrypoint))
420 /* Otherwise, try to map to a higher profile */
422 case GST_VAAPI_PROFILE_MPEG2_SIMPLE:
423 profile = GST_VAAPI_PROFILE_MPEG2_MAIN;
425 case GST_VAAPI_PROFILE_MPEG2_MAIN:
426 profile = GST_VAAPI_PROFILE_MPEG2_HIGH;
428 case GST_VAAPI_PROFILE_MPEG2_HIGH:
429 // Try to map to main profile if no high profile specific bits used
430 if (priv->profile == profile &&
431 !priv->seq_scalable_ext_unit &&
432 (priv->seq_ext_unit &&
433 priv->seq_ext_unit->data.seq_ext.chroma_format == 1)) {
434 profile = GST_VAAPI_PROFILE_MPEG2_MAIN;
439 profile = GST_VAAPI_PROFILE_UNKNOWN;
442 } while (profile != GST_VAAPI_PROFILE_UNKNOWN);
444 if (profile != priv->profile)
445 GST_INFO("forced %s profile to %s profile",
446 get_profile_str(priv->profile), get_profile_str(profile));
450 static GstVaapiDecoderStatus
451 ensure_context(GstVaapiDecoderMpeg2 *decoder)
453 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
454 GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_VLD;
455 gboolean reset_context = FALSE;
457 if (priv->profile_changed) {
458 GST_DEBUG("profile changed");
459 priv->profile_changed = FALSE;
460 reset_context = TRUE;
462 priv->hw_profile = get_profile(decoder, entrypoint);
463 if (priv->hw_profile == GST_VAAPI_PROFILE_UNKNOWN)
464 return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
467 if (priv->size_changed) {
468 GST_DEBUG("size changed");
469 priv->size_changed = FALSE;
470 reset_context = TRUE;
474 GstVaapiContextInfo info;
476 info.profile = priv->hw_profile;
477 info.entrypoint = entrypoint;
478 info.width = priv->width;
479 info.height = priv->height;
481 reset_context = gst_vaapi_decoder_ensure_context(
482 GST_VAAPI_DECODER_CAST(decoder),
486 return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
488 return GST_VAAPI_DECODER_STATUS_SUCCESS;
491 static GstVaapiDecoderStatus
492 ensure_quant_matrix(GstVaapiDecoderMpeg2 *decoder, GstVaapiPicture *picture)
494 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
495 GstMpegVideoSequenceHdr * const seq_hdr = &priv->seq_hdr_unit->data.seq_hdr;
496 VAIQMatrixBufferMPEG2 *iq_matrix;
497 guint8 *intra_quant_matrix = NULL;
498 guint8 *non_intra_quant_matrix = NULL;
499 guint8 *chroma_intra_quant_matrix = NULL;
500 guint8 *chroma_non_intra_quant_matrix = NULL;
502 if (!priv->quant_matrix_changed)
503 return GST_VAAPI_DECODER_STATUS_SUCCESS;
505 priv->quant_matrix_changed = FALSE;
507 picture->iq_matrix = GST_VAAPI_IQ_MATRIX_NEW(MPEG2, decoder);
508 if (!picture->iq_matrix) {
509 GST_ERROR("failed to allocate IQ matrix");
510 return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
512 iq_matrix = picture->iq_matrix->param;
514 intra_quant_matrix = seq_hdr->intra_quantizer_matrix;
515 non_intra_quant_matrix = seq_hdr->non_intra_quantizer_matrix;
517 if (priv->quant_matrix_unit) {
518 GstMpegVideoQuantMatrixExt * const quant_matrix =
519 &priv->quant_matrix_unit->data.quant_matrix;
520 if (quant_matrix->load_intra_quantiser_matrix)
521 intra_quant_matrix = quant_matrix->intra_quantiser_matrix;
522 if (quant_matrix->load_non_intra_quantiser_matrix)
523 non_intra_quant_matrix = quant_matrix->non_intra_quantiser_matrix;
524 if (quant_matrix->load_chroma_intra_quantiser_matrix)
525 chroma_intra_quant_matrix = quant_matrix->chroma_intra_quantiser_matrix;
526 if (quant_matrix->load_chroma_non_intra_quantiser_matrix)
527 chroma_non_intra_quant_matrix = quant_matrix->chroma_non_intra_quantiser_matrix;
530 iq_matrix->load_intra_quantiser_matrix = intra_quant_matrix != NULL;
531 if (intra_quant_matrix)
532 copy_quant_matrix(iq_matrix->intra_quantiser_matrix,
535 iq_matrix->load_non_intra_quantiser_matrix = non_intra_quant_matrix != NULL;
536 if (non_intra_quant_matrix)
537 copy_quant_matrix(iq_matrix->non_intra_quantiser_matrix,
538 non_intra_quant_matrix);
540 iq_matrix->load_chroma_intra_quantiser_matrix = chroma_intra_quant_matrix != NULL;
541 if (chroma_intra_quant_matrix)
542 copy_quant_matrix(iq_matrix->chroma_intra_quantiser_matrix,
543 chroma_intra_quant_matrix);
545 iq_matrix->load_chroma_non_intra_quantiser_matrix = chroma_non_intra_quant_matrix != NULL;
546 if (chroma_non_intra_quant_matrix)
547 copy_quant_matrix(iq_matrix->chroma_non_intra_quantiser_matrix,
548 chroma_non_intra_quant_matrix);
549 return GST_VAAPI_DECODER_STATUS_SUCCESS;
552 static GstVaapiDecoderStatus
553 decode_current_picture(GstVaapiDecoderMpeg2 *decoder)
555 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
556 GstVaapiPicture * const picture = priv->current_picture;
559 return GST_VAAPI_DECODER_STATUS_SUCCESS;
561 if (!gst_vaapi_picture_decode(picture))
563 if (GST_VAAPI_PICTURE_IS_COMPLETE(picture)) {
564 if (!gst_vaapi_dpb_add(priv->dpb, picture))
566 gst_vaapi_picture_replace(&priv->current_picture, NULL);
568 return GST_VAAPI_DECODER_STATUS_SUCCESS;
571 /* XXX: fix for cases where first field failed to be decoded */
572 gst_vaapi_picture_replace(&priv->current_picture, NULL);
573 return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
576 static GstVaapiDecoderStatus
577 parse_sequence(GstVaapiDecoderUnitMpeg2 *unit)
579 GstMpegVideoPacket * const packet = &unit->packet;
581 if (!gst_mpeg_video_parse_sequence_header(&unit->data.seq_hdr,
582 packet->data, packet->size, packet->offset)) {
583 GST_ERROR("failed to parse sequence header");
584 return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
586 return GST_VAAPI_DECODER_STATUS_SUCCESS;
589 static GstVaapiDecoderStatus
590 decode_sequence(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnitMpeg2 *unit)
592 GstVaapiDecoder * const base_decoder = GST_VAAPI_DECODER_CAST(decoder);
593 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
594 GstMpegVideoSequenceHdr *seq_hdr;
596 gst_vaapi_decoder_unit_replace(&priv->seq_hdr_unit, unit);
597 seq_hdr = &priv->seq_hdr_unit->data.seq_hdr;
598 gst_vaapi_decoder_unit_replace(&priv->seq_ext_unit, NULL);
599 gst_vaapi_decoder_unit_replace(&priv->seq_display_ext_unit, NULL);
601 priv->fps_n = seq_hdr->fps_n;
602 priv->fps_d = seq_hdr->fps_d;
603 pts_set_framerate(&priv->tsg, priv->fps_n, priv->fps_d);
604 gst_vaapi_decoder_set_framerate(base_decoder, priv->fps_n, priv->fps_d);
606 priv->width = seq_hdr->width;
607 priv->height = seq_hdr->height;
608 priv->size_changed = TRUE;
609 priv->quant_matrix_changed = TRUE;
610 priv->progressive_sequence = TRUE;
611 return GST_VAAPI_DECODER_STATUS_SUCCESS;
614 static GstVaapiDecoderStatus
615 parse_sequence_ext(GstVaapiDecoderUnitMpeg2 *unit)
617 GstMpegVideoPacket * const packet = &unit->packet;
619 if (!gst_mpeg_video_parse_sequence_extension(&unit->data.seq_ext,
620 packet->data, packet->size, packet->offset)) {
621 GST_ERROR("failed to parse sequence-extension");
622 return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
624 return GST_VAAPI_DECODER_STATUS_SUCCESS;
627 static GstVaapiDecoderStatus
628 decode_sequence_ext(GstVaapiDecoderMpeg2 *decoder,
629 GstVaapiDecoderUnitMpeg2 *unit)
631 GstVaapiDecoder * const base_decoder = GST_VAAPI_DECODER_CAST(decoder);
632 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
633 GstMpegVideoSequenceExt *seq_ext;
634 GstVaapiProfile profile;
637 gst_vaapi_decoder_unit_replace(&priv->seq_ext_unit, unit);
638 seq_ext = &priv->seq_ext_unit->data.seq_ext;
640 priv->progressive_sequence = seq_ext->progressive;
641 gst_vaapi_decoder_set_interlaced(base_decoder, !priv->progressive_sequence);
643 width = (priv->width & 0x0fff) | ((guint32)seq_ext->horiz_size_ext << 12);
644 height = (priv->height & 0x0fff) | ((guint32)seq_ext->vert_size_ext << 12);
645 GST_DEBUG("video resolution %ux%u", width, height);
647 if (seq_ext->fps_n_ext && seq_ext->fps_d_ext) {
648 priv->fps_n *= seq_ext->fps_n_ext + 1;
649 priv->fps_d *= seq_ext->fps_d_ext + 1;
650 pts_set_framerate(&priv->tsg, priv->fps_n, priv->fps_d);
651 gst_vaapi_decoder_set_framerate(base_decoder, priv->fps_n, priv->fps_d);
654 if (priv->width != width) {
656 priv->size_changed = TRUE;
659 if (priv->height != height) {
660 priv->height = height;
661 priv->size_changed = TRUE;
664 switch (seq_ext->profile) {
665 case GST_MPEG_VIDEO_PROFILE_SIMPLE:
666 profile = GST_VAAPI_PROFILE_MPEG2_SIMPLE;
668 case GST_MPEG_VIDEO_PROFILE_MAIN:
669 profile = GST_VAAPI_PROFILE_MPEG2_MAIN;
671 case GST_MPEG_VIDEO_PROFILE_HIGH:
672 profile = GST_VAAPI_PROFILE_MPEG2_HIGH;
675 GST_ERROR("unsupported profile %d", seq_ext->profile);
676 return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
678 if (priv->profile != profile) {
679 priv->profile = profile;
680 priv->profile_changed = TRUE;
682 return GST_VAAPI_DECODER_STATUS_SUCCESS;
685 static GstVaapiDecoderStatus
686 parse_sequence_display_ext(GstVaapiDecoderUnitMpeg2 *unit)
688 GstMpegVideoPacket * const packet = &unit->packet;
690 if (!gst_mpeg_video_parse_sequence_display_extension(
691 &unit->data.seq_display_ext,
692 packet->data, packet->size, packet->offset)) {
693 GST_ERROR("failed to parse sequence-display-extension");
694 return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
696 return GST_VAAPI_DECODER_STATUS_SUCCESS;
699 static GstVaapiDecoderStatus
700 decode_sequence_display_ext(GstVaapiDecoderMpeg2 *decoder,
701 GstVaapiDecoderUnitMpeg2 *unit)
703 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
705 gst_vaapi_decoder_unit_replace(&priv->seq_display_ext_unit, unit);
707 /* XXX: handle color primaries and cropping */
708 return GST_VAAPI_DECODER_STATUS_SUCCESS;
711 static GstVaapiDecoderStatus
712 decode_sequence_end(GstVaapiDecoderMpeg2 *decoder)
714 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
715 GstVaapiDecoderStatus status;
717 status = decode_current_picture(decoder);
718 if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
721 gst_vaapi_dpb_flush(priv->dpb);
722 return GST_VAAPI_DECODER_STATUS_SUCCESS;
725 static GstVaapiDecoderStatus
726 parse_quant_matrix_ext(GstVaapiDecoderUnitMpeg2 *unit)
728 GstMpegVideoPacket * const packet = &unit->packet;
730 if (!gst_mpeg_video_parse_quant_matrix_extension(&unit->data.quant_matrix,
731 packet->data, packet->size, packet->offset)) {
732 GST_ERROR("failed to parse quant-matrix-extension");
733 return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
735 return GST_VAAPI_DECODER_STATUS_SUCCESS;
738 static GstVaapiDecoderStatus
739 decode_quant_matrix_ext(GstVaapiDecoderMpeg2 *decoder,
740 GstVaapiDecoderUnitMpeg2 *unit)
742 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
744 gst_vaapi_decoder_unit_replace(&priv->quant_matrix_unit, unit);
745 priv->quant_matrix_changed = TRUE;
746 return GST_VAAPI_DECODER_STATUS_SUCCESS;
749 static GstVaapiDecoderStatus
750 parse_gop(GstVaapiDecoderUnitMpeg2 *unit)
752 GstMpegVideoPacket * const packet = &unit->packet;
754 if (!gst_mpeg_video_parse_gop(&unit->data.gop,
755 packet->data, packet->size, packet->offset)) {
756 GST_ERROR("failed to parse GOP");
757 return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
759 return GST_VAAPI_DECODER_STATUS_SUCCESS;
762 static GstVaapiDecoderStatus
763 decode_gop(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnitMpeg2 *unit)
765 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
766 GstMpegVideoGop * const gop = &unit->data.gop;
768 priv->closed_gop = gop->closed_gop;
769 priv->broken_link = gop->broken_link;
771 GST_DEBUG("GOP %02u:%02u:%02u:%02u (closed_gop %d, broken_link %d)",
772 gop->hour, gop->minute, gop->second, gop->frame,
773 priv->closed_gop, priv->broken_link);
775 pts_sync(&priv->tsg, GST_VAAPI_DECODER_CODEC_FRAME(decoder)->pts);
776 return GST_VAAPI_DECODER_STATUS_SUCCESS;
779 static GstVaapiDecoderStatus
780 parse_picture(GstVaapiDecoderUnitMpeg2 *unit)
782 GstMpegVideoPacket * const packet = &unit->packet;
784 if (!gst_mpeg_video_parse_picture_header(&unit->data.pic_hdr,
785 packet->data, packet->size, packet->offset)) {
786 GST_ERROR("failed to parse picture header");
787 return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
789 return GST_VAAPI_DECODER_STATUS_SUCCESS;
792 static GstVaapiDecoderStatus
793 parse_slice(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnitMpeg2 *unit)
795 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
796 GstMpegVideoSliceHdr * const slice_hdr = &unit->data.slice_hdr;
797 GstMpegVideoPacket * const packet = &unit->packet;
799 gint mb_x, mb_y, mb_inc;
800 guint8 slice_vertical_position_extension;
801 guint8 extra_bit_slice, junk8;
803 gst_bit_reader_init(&br, packet->data + packet->offset, packet->size);
804 if (priv->height > 2800)
805 READ_UINT8(&br, slice_vertical_position_extension, 3);
806 if (priv->seq_scalable_ext_unit) {
807 GST_ERROR("failed to parse slice with sequence_scalable_extension()");
808 return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
810 READ_UINT8(&br, slice_hdr->quantiser_scale_code, 5);
811 READ_UINT8(&br, extra_bit_slice, 1);
812 if (!extra_bit_slice)
813 slice_hdr->intra_slice = 0;
815 READ_UINT8(&br, slice_hdr->intra_slice, 1);
816 READ_UINT8(&br, junk8, 7);
817 READ_UINT8(&br, extra_bit_slice, 1);
818 while (extra_bit_slice) {
819 READ_UINT8(&br, junk8, 8);
820 READ_UINT8(&br, extra_bit_slice, 1);
823 slice_hdr->header_size = 32 + gst_bit_reader_get_pos(&br);
825 mb_y = packet->type - GST_MPEG_VIDEO_PACKET_SLICE_MIN;
828 if (!decode_vlc(&br, &mb_inc, mpeg2_mbaddr_vlc_table,
829 G_N_ELEMENTS(mpeg2_mbaddr_vlc_table))) {
830 GST_WARNING("failed to decode first macroblock_address_increment");
833 mb_x += mb_inc == GST_MPEG_VIDEO_MACROBLOCK_ESCAPE ? 33 : mb_inc;
834 } while (mb_inc == GST_MPEG_VIDEO_MACROBLOCK_ESCAPE);
836 slice_hdr->slice_horizontal_position = mb_x;
837 slice_hdr->slice_vertical_position = mb_y;
838 return GST_VAAPI_DECODER_STATUS_SUCCESS;
841 return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
844 static GstVaapiDecoderStatus
845 decode_picture(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnitMpeg2 *unit)
847 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
849 gst_vaapi_decoder_unit_replace(&priv->pic_hdr_unit, unit);
850 gst_vaapi_decoder_unit_replace(&priv->pic_ext_unit, NULL);
851 return GST_VAAPI_DECODER_STATUS_SUCCESS;
854 static GstVaapiDecoderStatus
855 parse_picture_ext(GstVaapiDecoderUnitMpeg2 *unit)
857 GstMpegVideoPacket * const packet = &unit->packet;
859 if (!gst_mpeg_video_parse_picture_extension(&unit->data.pic_ext,
860 packet->data, packet->size, packet->offset)) {
861 GST_ERROR("failed to parse picture-extension");
862 return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
864 return GST_VAAPI_DECODER_STATUS_SUCCESS;
867 static GstVaapiDecoderStatus
868 decode_picture_ext(GstVaapiDecoderMpeg2 *decoder,
869 GstVaapiDecoderUnitMpeg2 *unit)
871 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
872 GstMpegVideoPictureExt *pic_ext;
874 gst_vaapi_decoder_unit_replace(&priv->pic_ext_unit, unit);
875 pic_ext = &priv->pic_ext_unit->data.pic_ext;
877 if (priv->progressive_sequence && !pic_ext->progressive_frame) {
878 GST_WARNING("invalid interlaced frame in progressive sequence, fixing");
879 pic_ext->progressive_frame = 1;
882 if (pic_ext->picture_structure == 0 ||
883 (pic_ext->progressive_frame &&
884 pic_ext->picture_structure != GST_MPEG_VIDEO_PICTURE_STRUCTURE_FRAME)) {
885 GST_WARNING("invalid picture_structure %d, replacing with \"frame\"",
886 pic_ext->picture_structure);
887 pic_ext->picture_structure = GST_MPEG_VIDEO_PICTURE_STRUCTURE_FRAME;
889 return GST_VAAPI_DECODER_STATUS_SUCCESS;
892 static inline guint32
893 pack_f_code(guint8 f_code[2][2])
895 return (((guint32)f_code[0][0] << 12) |
896 ((guint32)f_code[0][1] << 8) |
897 ((guint32)f_code[1][0] << 4) |
901 static GstVaapiDecoderStatus
902 init_picture(GstVaapiDecoderMpeg2 *decoder, GstVaapiPicture *picture)
904 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
905 GstMpegVideoPictureHdr * const pic_hdr = &priv->pic_hdr_unit->data.pic_hdr;
906 GstMpegVideoPictureExt * const pic_ext = &priv->pic_ext_unit->data.pic_ext;
908 switch (pic_hdr->pic_type) {
909 case GST_MPEG_VIDEO_PICTURE_TYPE_I:
910 GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_REFERENCE);
911 picture->type = GST_VAAPI_PICTURE_TYPE_I;
913 case GST_MPEG_VIDEO_PICTURE_TYPE_P:
914 GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_REFERENCE);
915 picture->type = GST_VAAPI_PICTURE_TYPE_P;
917 case GST_MPEG_VIDEO_PICTURE_TYPE_B:
918 picture->type = GST_VAAPI_PICTURE_TYPE_B;
921 GST_ERROR("unsupported picture type %d", pic_hdr->pic_type);
922 return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
925 if (!priv->progressive_sequence && !pic_ext->progressive_frame) {
926 GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_INTERLACED);
927 if (pic_ext->top_field_first)
928 GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_TFF);
931 switch (pic_ext->picture_structure) {
932 case GST_MPEG_VIDEO_PICTURE_STRUCTURE_TOP_FIELD:
933 picture->structure = GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD;
935 case GST_MPEG_VIDEO_PICTURE_STRUCTURE_BOTTOM_FIELD:
936 picture->structure = GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD;
938 case GST_MPEG_VIDEO_PICTURE_STRUCTURE_FRAME:
939 picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
943 /* Allocate dummy picture for first field based I-frame */
944 if (picture->type == GST_VAAPI_PICTURE_TYPE_I &&
945 !GST_VAAPI_PICTURE_IS_FRAME(picture) &&
946 gst_vaapi_dpb_size(priv->dpb) == 0) {
947 GstVaapiPicture *dummy_picture;
950 dummy_picture = GST_VAAPI_PICTURE_NEW(MPEG2, decoder);
951 if (!dummy_picture) {
952 GST_ERROR("failed to allocate dummy picture");
953 return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
956 dummy_picture->type = GST_VAAPI_PICTURE_TYPE_I;
957 dummy_picture->pts = GST_CLOCK_TIME_NONE;
958 dummy_picture->poc = -1;
959 dummy_picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
961 GST_VAAPI_PICTURE_FLAG_SET(
963 (GST_VAAPI_PICTURE_FLAG_SKIPPED |
964 GST_VAAPI_PICTURE_FLAG_REFERENCE)
967 success = gst_vaapi_dpb_add(priv->dpb, dummy_picture);
968 gst_vaapi_picture_unref(dummy_picture);
970 GST_ERROR("failed to add dummy picture into DPB");
971 return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
973 GST_INFO("allocated dummy picture for first field based I-frame");
976 /* Update presentation time */
977 picture->pts = pts_eval(&priv->tsg,
978 GST_VAAPI_DECODER_CODEC_FRAME(decoder)->pts, pic_hdr->tsn);
979 picture->poc = pts_get_poc(&priv->tsg);
980 return GST_VAAPI_DECODER_STATUS_SUCCESS;
984 fill_picture(GstVaapiDecoderMpeg2 *decoder, GstVaapiPicture *picture)
986 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
987 VAPictureParameterBufferMPEG2 * const pic_param = picture->param;
988 GstMpegVideoPictureHdr * const pic_hdr = &priv->pic_hdr_unit->data.pic_hdr;
989 GstMpegVideoPictureExt * const pic_ext = &priv->pic_ext_unit->data.pic_ext;
990 GstVaapiPicture *prev_picture, *next_picture;
992 /* Fill in VAPictureParameterBufferMPEG2 */
993 pic_param->horizontal_size = priv->width;
994 pic_param->vertical_size = priv->height;
995 pic_param->forward_reference_picture = VA_INVALID_ID;
996 pic_param->backward_reference_picture = VA_INVALID_ID;
997 pic_param->picture_coding_type = pic_hdr->pic_type;
998 pic_param->f_code = pack_f_code(pic_ext->f_code);
1000 #define COPY_FIELD(a, b, f) \
1001 pic_param->a.b.f = pic_ext->f
1002 pic_param->picture_coding_extension.value = 0;
1003 pic_param->picture_coding_extension.bits.is_first_field =
1004 GST_VAAPI_PICTURE_IS_FIRST_FIELD(picture);
1005 COPY_FIELD(picture_coding_extension, bits, intra_dc_precision);
1006 COPY_FIELD(picture_coding_extension, bits, picture_structure);
1007 COPY_FIELD(picture_coding_extension, bits, top_field_first);
1008 COPY_FIELD(picture_coding_extension, bits, frame_pred_frame_dct);
1009 COPY_FIELD(picture_coding_extension, bits, concealment_motion_vectors);
1010 COPY_FIELD(picture_coding_extension, bits, q_scale_type);
1011 COPY_FIELD(picture_coding_extension, bits, intra_vlc_format);
1012 COPY_FIELD(picture_coding_extension, bits, alternate_scan);
1013 COPY_FIELD(picture_coding_extension, bits, repeat_first_field);
1014 COPY_FIELD(picture_coding_extension, bits, progressive_frame);
1016 gst_vaapi_dpb_mpeg2_get_references(priv->dpb, picture,
1017 &prev_picture, &next_picture);
1019 switch (pic_hdr->pic_type) {
1020 case GST_MPEG_VIDEO_PICTURE_TYPE_B:
1022 pic_param->backward_reference_picture = next_picture->surface_id;
1024 pic_param->forward_reference_picture = prev_picture->surface_id;
1025 else if (!priv->closed_gop)
1026 GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_SKIPPED);
1028 case GST_MPEG_VIDEO_PICTURE_TYPE_P:
1030 pic_param->forward_reference_picture = prev_picture->surface_id;
1035 static GstVaapiDecoderStatus
1036 decode_slice(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnitMpeg2 *unit)
1038 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
1039 GstVaapiPicture * const picture = priv->current_picture;
1040 GstVaapiSlice *slice;
1041 VASliceParameterBufferMPEG2 *slice_param;
1042 GstMpegVideoPacket * const packet = &unit->packet;
1043 GstMpegVideoSliceHdr * const slice_hdr = &unit->data.slice_hdr;
1045 GST_DEBUG("slice %d (%u bytes)", slice_hdr->slice_vertical_position,
1048 unit->base.buffer = gst_buffer_create_sub(
1049 GST_VAAPI_DECODER_CODEC_FRAME(decoder)->input_buffer,
1050 unit->base.offset, unit->base.size);
1051 if (!unit->base.buffer) {
1052 GST_ERROR("failed to allocate slice data");
1053 return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
1056 slice = GST_VAAPI_SLICE_NEW(MPEG2, decoder,
1057 GST_BUFFER_DATA(unit->base.buffer), packet->size);
1059 GST_ERROR("failed to allocate slice");
1060 return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
1062 gst_vaapi_picture_add_slice(picture, slice);
1064 /* Fill in VASliceParameterBufferMPEG2 */
1065 slice_param = slice->param;
1066 slice_param->macroblock_offset = slice_hdr->header_size;
1067 slice_param->slice_horizontal_position = slice_hdr->slice_horizontal_position;
1068 slice_param->slice_vertical_position = slice_hdr->slice_vertical_position;
1069 slice_param->quantiser_scale_code = slice_hdr->quantiser_scale_code;
1070 slice_param->intra_slice_flag = slice_hdr->intra_slice;
1071 return GST_VAAPI_DECODER_STATUS_SUCCESS;
1075 scan_for_start_code(GstAdapter *adapter, guint ofs, guint size, guint32 *scp)
1077 return (gint)gst_adapter_masked_scan_uint32_peek(adapter,
1078 0xffffff00, 0x00000100,
1083 static GstVaapiDecoderStatus
1084 decode_unit(GstVaapiDecoderMpeg2 *decoder, GstVaapiDecoderUnitMpeg2 *unit)
1086 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
1087 const GstMpegVideoPacketTypeCode type = unit->packet.type;
1088 GstVaapiDecoderStatus status;
1091 case GST_MPEG_VIDEO_PACKET_PICTURE:
1092 if (!priv->width || !priv->height)
1093 goto unknown_picture_size;
1094 status = decode_picture(decoder, unit);
1096 case GST_MPEG_VIDEO_PACKET_SEQUENCE:
1097 status = decode_sequence(decoder, unit);
1099 case GST_MPEG_VIDEO_PACKET_EXTENSION:
1100 switch (unit->extension_type) {
1101 case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE:
1102 status = decode_sequence_ext(decoder, unit);
1104 case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_DISPLAY:
1105 status = decode_sequence_display_ext(decoder, unit);
1107 case GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX:
1108 status = decode_quant_matrix_ext(decoder, unit);
1110 case GST_MPEG_VIDEO_PACKET_EXT_PICTURE:
1111 if (!priv->width || !priv->height)
1112 goto unknown_picture_size;
1113 status = decode_picture_ext(decoder, unit);
1116 // Ignore unknown start-code extensions
1117 GST_WARNING("unsupported packet extension type 0x%02x",
1118 unit->extension_type);
1119 status = GST_VAAPI_DECODER_STATUS_SUCCESS;
1123 case GST_MPEG_VIDEO_PACKET_SEQUENCE_END:
1124 status = decode_sequence_end(decoder);
1126 case GST_MPEG_VIDEO_PACKET_GOP:
1127 status = decode_gop(decoder, unit);
1130 if (type >= GST_MPEG_VIDEO_PACKET_SLICE_MIN &&
1131 type <= GST_MPEG_VIDEO_PACKET_SLICE_MAX) {
1132 status = decode_slice(decoder, unit);
1135 GST_WARNING("unsupported packet type 0x%02x", type);
1136 status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
1141 unknown_picture_size:
1142 // Ignore packet while picture size is undefined
1143 // i.e. missing sequence headers, or not parsed correctly
1144 GST_WARNING("failed to parse picture of unknown size");
1145 return GST_VAAPI_DECODER_STATUS_SUCCESS;
1148 static GstVaapiDecoderStatus
1149 ensure_decoder(GstVaapiDecoderMpeg2 *decoder)
1151 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
1153 g_return_val_if_fail(priv->is_constructed,
1154 GST_VAAPI_DECODER_STATUS_ERROR_INIT_FAILED);
1156 if (!priv->is_opened) {
1157 priv->is_opened = gst_vaapi_decoder_mpeg2_open(decoder);
1158 if (!priv->is_opened)
1159 return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC;
1161 return GST_VAAPI_DECODER_STATUS_SUCCESS;
1164 static GstVaapiDecoderStatus
1165 gst_vaapi_decoder_mpeg2_parse(GstVaapiDecoder *base_decoder,
1166 GstAdapter *adapter, gboolean at_eos, GstVaapiDecoderUnit **unit_ptr)
1168 GstVaapiDecoderMpeg2 * const decoder =
1169 GST_VAAPI_DECODER_MPEG2_CAST(base_decoder);
1170 GstVaapiParserState * const ps = GST_VAAPI_PARSER_STATE(base_decoder);
1171 GstVaapiDecoderUnitMpeg2 *unit;
1172 GstVaapiDecoderStatus status;
1173 GstMpegVideoPacket *packet;
1176 guint size, buf_size, flags;
1179 status = ensure_decoder(decoder);
1180 if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
1183 size = gst_adapter_available(adapter);
1185 return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
1187 ofs = scan_for_start_code(adapter, 0, size, &start_code);
1189 return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
1192 gst_adapter_flush(adapter, ofs);
1196 ofs2 = ps->input_offset2 - ofs - 4;
1200 ofs = G_UNLIKELY(size < ofs2 + 4) ? -1 :
1201 scan_for_start_code(adapter, ofs2, size - ofs2, NULL);
1203 // Assume the whole packet is present if end-of-stream
1205 ps->input_offset2 = size;
1206 return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
1211 ps->input_offset2 = 0;
1213 buf = gst_adapter_peek(adapter, buf_size);
1215 return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
1217 unit = gst_vaapi_decoder_unit_mpeg2_new(buf_size);
1219 return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
1221 packet = &unit->packet;
1223 packet->size = buf_size;
1225 packet->type = start_code & 0xff;
1228 switch (packet->type) {
1229 case GST_MPEG_VIDEO_PACKET_SEQUENCE:
1230 status = parse_sequence(unit);
1232 case GST_MPEG_VIDEO_PACKET_GOP:
1233 status = parse_gop(unit);
1235 case GST_MPEG_VIDEO_PACKET_PICTURE:
1236 status = parse_picture(unit);
1238 case GST_MPEG_VIDEO_PACKET_EXTENSION:
1239 if (G_UNLIKELY(buf_size < 5)) {
1240 status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
1243 unit->extension_type = buf[4] >> 4;
1244 switch (unit->extension_type) {
1245 case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE:
1246 status = parse_sequence_ext(unit);
1248 case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_DISPLAY:
1249 status = parse_sequence_display_ext(unit);
1251 case GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX:
1252 status = parse_quant_matrix_ext(unit);
1254 case GST_MPEG_VIDEO_PACKET_EXT_PICTURE:
1255 status = parse_picture_ext(unit);
1258 status = GST_VAAPI_DECODER_STATUS_SUCCESS;
1263 if (packet->type >= GST_MPEG_VIDEO_PACKET_SLICE_MIN &&
1264 packet->type <= GST_MPEG_VIDEO_PACKET_SLICE_MAX) {
1265 status = parse_slice(decoder, unit);
1269 status = GST_VAAPI_DECODER_STATUS_SUCCESS;
1272 if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
1275 /* Check for start of new picture */
1277 switch (packet->type) {
1278 case GST_MPEG_VIDEO_PACKET_SEQUENCE_END:
1279 flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END;
1280 flags |= GST_VAAPI_DECODER_UNIT_FLAG_STREAM_END;
1282 case GST_MPEG_VIDEO_PACKET_USER_DATA:
1283 flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP;
1285 case GST_MPEG_VIDEO_PACKET_SEQUENCE:
1286 case GST_MPEG_VIDEO_PACKET_GOP:
1287 case GST_MPEG_VIDEO_PACKET_PICTURE:
1288 flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
1291 if (packet->type >= GST_MPEG_VIDEO_PACKET_SLICE_MIN &&
1292 packet->type <= GST_MPEG_VIDEO_PACKET_SLICE_MAX)
1293 flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE;
1295 // Ignore system start codes (PES headers)
1296 else if (packet->type >= 0xb9 && packet->type <= 0xff)
1297 flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP;
1300 GST_VAAPI_DECODER_UNIT_FLAG_SET(unit, flags);
1302 unit->packet.data = NULL;
1303 *unit_ptr = &unit->base;
1304 return GST_VAAPI_DECODER_STATUS_SUCCESS;
1307 static GstVaapiDecoderStatus
1308 gst_vaapi_decoder_mpeg2_decode(GstVaapiDecoder *base_decoder,
1309 GstVaapiDecoderUnit *unit)
1311 GstVaapiDecoderMpeg2 * const decoder =
1312 GST_VAAPI_DECODER_MPEG2_CAST(base_decoder);
1313 GstVaapiDecoderStatus status;
1315 status = ensure_decoder(decoder);
1316 if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
1318 return decode_unit(decoder, (GstVaapiDecoderUnitMpeg2 *)unit);
1321 static GstVaapiDecoderStatus
1322 gst_vaapi_decoder_mpeg2_start_frame(GstVaapiDecoder *base_decoder,
1323 GstVaapiDecoderUnit *base_unit)
1325 GstVaapiDecoderMpeg2 * const decoder =
1326 GST_VAAPI_DECODER_MPEG2_CAST(base_decoder);
1327 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
1328 GstMpegVideoSequenceHdr *seq_hdr;
1329 GstMpegVideoSequenceExt *seq_ext;
1330 GstMpegVideoSequenceDisplayExt *seq_display_ext;
1331 GstVaapiPicture *picture;
1332 GstVaapiDecoderStatus status;
1334 if (!priv->width || !priv->height) {
1335 // Ignore packet while picture size is undefined
1336 // i.e. missing sequence headers, or not parsed correctly
1337 GST_WARNING("failed to decode picture of unknown size");
1338 return GST_VAAPI_DECODER_STATUS_SUCCESS;
1341 seq_hdr = &priv->seq_hdr_unit->data.seq_hdr;
1342 seq_ext = priv->seq_ext_unit ? &priv->seq_ext_unit->data.seq_ext : NULL;
1343 seq_display_ext = priv->seq_display_ext_unit ?
1344 &priv->seq_display_ext_unit->data.seq_display_ext : NULL;
1345 if (gst_mpeg_video_finalise_mpeg2_sequence_header(seq_hdr, seq_ext,
1347 gst_vaapi_decoder_set_pixel_aspect_ratio(base_decoder,
1348 seq_hdr->par_w, seq_hdr->par_h);
1350 status = ensure_context(decoder);
1351 if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
1352 GST_ERROR("failed to reset context");
1356 if (priv->current_picture) {
1357 /* Re-use current picture where the first field was decoded */
1358 picture = gst_vaapi_picture_new_field(priv->current_picture);
1360 GST_ERROR("failed to allocate field picture");
1361 return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
1365 /* Create new picture */
1366 picture = GST_VAAPI_PICTURE_NEW(MPEG2, decoder);
1368 GST_ERROR("failed to allocate picture");
1369 return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
1372 gst_vaapi_picture_replace(&priv->current_picture, picture);
1373 gst_vaapi_picture_unref(picture);
1375 status = ensure_quant_matrix(decoder, picture);
1376 if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
1377 GST_ERROR("failed to reset quantizer matrix");
1381 status = init_picture(decoder, picture);
1382 if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
1385 fill_picture(decoder, picture);
1386 return GST_VAAPI_DECODER_STATUS_SUCCESS;
1389 static GstVaapiDecoderStatus
1390 gst_vaapi_decoder_mpeg2_end_frame(GstVaapiDecoder *base_decoder)
1392 GstVaapiDecoderMpeg2 * const decoder =
1393 GST_VAAPI_DECODER_MPEG2_CAST(base_decoder);
1395 return decode_current_picture(decoder);
1399 gst_vaapi_decoder_mpeg2_finalize(GObject *object)
1401 GstVaapiDecoderMpeg2 * const decoder = GST_VAAPI_DECODER_MPEG2_CAST(object);
1403 gst_vaapi_decoder_mpeg2_destroy(decoder);
1405 G_OBJECT_CLASS(gst_vaapi_decoder_mpeg2_parent_class)->finalize(object);
1409 gst_vaapi_decoder_mpeg2_constructed(GObject *object)
1411 GstVaapiDecoderMpeg2 * const decoder = GST_VAAPI_DECODER_MPEG2_CAST(object);
1412 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
1413 GObjectClass *parent_class;
1415 parent_class = G_OBJECT_CLASS(gst_vaapi_decoder_mpeg2_parent_class);
1416 if (parent_class->constructed)
1417 parent_class->constructed(object);
1419 priv->is_constructed = gst_vaapi_decoder_mpeg2_create(decoder);
1423 gst_vaapi_decoder_mpeg2_class_init(GstVaapiDecoderMpeg2Class *klass)
1425 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
1426 GstVaapiDecoderClass * const decoder_class = GST_VAAPI_DECODER_CLASS(klass);
1428 g_type_class_add_private(klass, sizeof(GstVaapiDecoderMpeg2Private));
1430 object_class->finalize = gst_vaapi_decoder_mpeg2_finalize;
1431 object_class->constructed = gst_vaapi_decoder_mpeg2_constructed;
1433 decoder_class->parse = gst_vaapi_decoder_mpeg2_parse;
1434 decoder_class->decode = gst_vaapi_decoder_mpeg2_decode;
1435 decoder_class->start_frame = gst_vaapi_decoder_mpeg2_start_frame;
1436 decoder_class->end_frame = gst_vaapi_decoder_mpeg2_end_frame;
1440 gst_vaapi_decoder_mpeg2_init(GstVaapiDecoderMpeg2 *decoder)
1442 GstVaapiDecoderMpeg2Private *priv;
1444 priv = GST_VAAPI_DECODER_MPEG2_GET_PRIVATE(decoder);
1445 decoder->priv = priv;
1446 priv->hw_profile = GST_VAAPI_PROFILE_UNKNOWN;
1447 priv->profile = GST_VAAPI_PROFILE_MPEG2_SIMPLE;
1448 priv->profile_changed = TRUE; /* Allow fallbacks to work */
1452 * gst_vaapi_decoder_mpeg2_new:
1453 * @display: a #GstVaapiDisplay
1454 * @caps: a #GstCaps holding codec information
1456 * Creates a new #GstVaapiDecoder for MPEG-2 decoding. The @caps can
1457 * hold extra information like codec-data and pictured coded size.
1459 * Return value: the newly allocated #GstVaapiDecoder object
1462 gst_vaapi_decoder_mpeg2_new(GstVaapiDisplay *display, GstCaps *caps)
1464 GstVaapiDecoderMpeg2 *decoder;
1466 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
1467 g_return_val_if_fail(GST_IS_CAPS(caps), NULL);
1469 decoder = g_object_new(
1470 GST_VAAPI_TYPE_DECODER_MPEG2,
1475 if (!decoder->priv->is_constructed) {
1476 g_object_unref(decoder);
1479 return GST_VAAPI_DECODER_CAST(decoder);