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 G_DEFINE_TYPE(GstVaapiDecoderMpeg2,
42 gst_vaapi_decoder_mpeg2,
43 GST_VAAPI_TYPE_DECODER)
45 #define GST_VAAPI_DECODER_MPEG2_GET_PRIVATE(obj) \
46 (G_TYPE_INSTANCE_GET_PRIVATE((obj), \
47 GST_VAAPI_TYPE_DECODER_MPEG2, \
48 GstVaapiDecoderMpeg2Private))
50 #define READ_UINT8(br, val, nbits) G_STMT_START { \
51 if (!gst_bit_reader_get_bits_uint8 (br, &val, nbits)) { \
52 GST_WARNING ("failed to read uint8, nbits: %d", nbits); \
57 #define SKIP(reader, nbits) G_STMT_START { \
58 if (!gst_bit_reader_skip (reader, nbits)) { \
59 GST_WARNING ("failed to skip nbits: %d", nbits); \
65 typedef struct _PTSGenerator PTSGenerator;
66 struct _PTSGenerator {
67 GstClockTime gop_pts; // Current GOP PTS
68 GstClockTime max_pts; // Max picture PTS
69 guint gop_tsn; // Absolute GOP TSN
70 guint max_tsn; // Max picture TSN, relative to last GOP TSN
71 guint ovl_tsn; // How many times TSN overflowed since GOP
72 guint lst_tsn; // Last picture TSN
78 pts_init(PTSGenerator *tsg)
80 tsg->gop_pts = GST_CLOCK_TIME_NONE;
81 tsg->max_pts = GST_CLOCK_TIME_NONE;
90 static inline GstClockTime
91 pts_get_duration(PTSGenerator *tsg, guint num_frames)
93 return gst_util_uint64_scale(num_frames,
94 GST_SECOND * tsg->fps_d, tsg->fps_n);
98 pts_get_poc(PTSGenerator *tsg)
100 return tsg->gop_tsn + tsg->ovl_tsn * 1024 + tsg->lst_tsn;
104 pts_set_framerate(PTSGenerator *tsg, guint fps_n, guint fps_d)
111 pts_sync(PTSGenerator *tsg, GstClockTime gop_pts)
115 if (!GST_CLOCK_TIME_IS_VALID(gop_pts) ||
116 (GST_CLOCK_TIME_IS_VALID(tsg->max_pts) && tsg->max_pts >= gop_pts)) {
117 /* Invalid GOP PTS, interpolate from the last known picture PTS */
118 if (GST_CLOCK_TIME_IS_VALID(tsg->max_pts)) {
119 gop_pts = tsg->max_pts + pts_get_duration(tsg, 1);
120 gop_tsn = tsg->gop_tsn + tsg->ovl_tsn * 1024 + tsg->max_tsn + 1;
128 /* Interpolate GOP TSN from this valid PTS */
129 if (GST_CLOCK_TIME_IS_VALID(tsg->gop_pts))
130 gop_tsn = tsg->gop_tsn + gst_util_uint64_scale(
131 gop_pts - tsg->gop_pts + pts_get_duration(tsg, 1) - 1,
132 tsg->fps_n, GST_SECOND * tsg->fps_d);
137 tsg->gop_pts = gop_pts;
138 tsg->gop_tsn = gop_tsn;
145 pts_eval(PTSGenerator *tsg, GstClockTime pic_pts, guint pic_tsn)
149 if (!GST_CLOCK_TIME_IS_VALID(tsg->gop_pts))
152 pts = tsg->gop_pts + pts_get_duration(tsg, tsg->ovl_tsn * 1024 + pic_tsn);
154 if (!GST_CLOCK_TIME_IS_VALID(tsg->max_pts) || tsg->max_pts < pts)
157 if (tsg->max_tsn < pic_tsn)
158 tsg->max_tsn = pic_tsn;
159 else if (tsg->max_tsn == 1023 && pic_tsn < tsg->lst_tsn) { /* TSN wrapped */
160 tsg->max_tsn = pic_tsn;
163 tsg->lst_tsn = pic_tsn;
167 struct _GstVaapiDecoderMpeg2Private {
168 GstVaapiProfile profile;
169 GstVaapiProfile hw_profile;
174 GstMpegVideoSequenceHdr seq_hdr;
175 GstMpegVideoSequenceExt seq_ext;
176 GstMpegVideoPictureHdr pic_hdr;
177 GstMpegVideoPictureExt pic_ext;
178 GstMpegVideoQuantMatrixExt quant_matrix_ext;
179 GstVaapiPicture *current_picture;
183 guint is_constructed : 1;
185 guint has_seq_ext : 1;
186 guint has_seq_scalable_ext : 1;
187 guint has_pic_ext : 1;
188 guint has_quant_matrix_ext : 1;
189 guint size_changed : 1;
190 guint profile_changed : 1;
191 guint quant_matrix_changed : 1;
192 guint progressive_sequence : 1;
193 guint closed_gop : 1;
194 guint broken_link : 1;
197 /* VLC decoder from gst-plugins-bad */
198 typedef struct _VLCTable VLCTable;
206 decode_vlc(GstBitReader *br, gint *res, const VLCTable *table, guint length)
212 for (i = 0; i < length; i++) {
213 if (cbits != table[i].cbits) {
214 cbits = table[i].cbits;
215 if (!gst_bit_reader_peek_bits_uint32(br, &value, cbits)) {
220 if (value == table[i].cword) {
223 *res = table[i].value;
227 GST_DEBUG("failed to find VLC code");
230 GST_WARNING("failed to decode VLC, returning");
235 GST_MPEG_VIDEO_MACROBLOCK_ESCAPE = -1,
238 /* Table B-1: Variable length codes for macroblock_address_increment */
239 static const VLCTable mpeg2_mbaddr_vlc_table[] = {
273 { GST_MPEG_VIDEO_MACROBLOCK_ESCAPE, 0x08, 11 }
277 gst_vaapi_decoder_mpeg2_close(GstVaapiDecoderMpeg2 *decoder)
279 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
281 gst_vaapi_picture_replace(&priv->current_picture, NULL);
284 gst_vaapi_dpb_unref(priv->dpb);
289 gst_adapter_clear(priv->adapter);
290 g_object_unref(priv->adapter);
291 priv->adapter = NULL;
296 gst_vaapi_decoder_mpeg2_open(GstVaapiDecoderMpeg2 *decoder, GstBuffer *buffer)
298 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
300 gst_vaapi_decoder_mpeg2_close(decoder);
302 priv->adapter = gst_adapter_new();
306 priv->dpb = gst_vaapi_dpb_mpeg2_new();
310 pts_init(&priv->tsg);
315 gst_vaapi_decoder_mpeg2_destroy(GstVaapiDecoderMpeg2 *decoder)
317 gst_vaapi_decoder_mpeg2_close(decoder);
321 gst_vaapi_decoder_mpeg2_create(GstVaapiDecoderMpeg2 *decoder)
323 if (!GST_VAAPI_DECODER_CODEC(decoder))
329 copy_quant_matrix(guint8 dst[64], const guint8 src[64])
331 memcpy(dst, src, 64);
335 get_profile_str(GstVaapiProfile profile)
340 case GST_VAAPI_PROFILE_MPEG2_SIMPLE: str = "simple"; break;
341 case GST_VAAPI_PROFILE_MPEG2_MAIN: str = "main"; break;
342 case GST_VAAPI_PROFILE_MPEG2_HIGH: str = "high"; break;
343 default: str = "<unknown>"; break;
348 static GstVaapiProfile
349 get_profile(GstVaapiDecoderMpeg2 *decoder, GstVaapiEntrypoint entrypoint)
351 GstVaapiDisplay * const va_display = GST_VAAPI_DECODER_DISPLAY(decoder);
352 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
353 GstVaapiProfile profile = priv->profile;
356 /* Return immediately if the exact same profile was found */
357 if (gst_vaapi_display_has_decoder(va_display, profile, entrypoint))
360 /* Otherwise, try to map to a higher profile */
362 case GST_VAAPI_PROFILE_MPEG2_SIMPLE:
363 profile = GST_VAAPI_PROFILE_MPEG2_MAIN;
365 case GST_VAAPI_PROFILE_MPEG2_MAIN:
366 profile = GST_VAAPI_PROFILE_MPEG2_HIGH;
368 case GST_VAAPI_PROFILE_MPEG2_HIGH:
369 // Try to map to main profile if no high profile specific bits used
370 if (priv->profile == profile &&
371 !priv->has_seq_scalable_ext &&
372 (priv->has_seq_ext && priv->seq_ext.chroma_format == 1)) {
373 profile = GST_VAAPI_PROFILE_MPEG2_MAIN;
378 profile = GST_VAAPI_PROFILE_UNKNOWN;
381 } while (profile != GST_VAAPI_PROFILE_UNKNOWN);
383 if (profile != priv->profile)
384 GST_INFO("forced %s profile to %s profile",
385 get_profile_str(priv->profile), get_profile_str(profile));
389 static GstVaapiDecoderStatus
390 ensure_context(GstVaapiDecoderMpeg2 *decoder)
392 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
393 GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_VLD;
394 gboolean reset_context = FALSE;
396 if (priv->profile_changed) {
397 GST_DEBUG("profile changed");
398 priv->profile_changed = FALSE;
399 reset_context = TRUE;
401 priv->hw_profile = get_profile(decoder, entrypoint);
402 if (priv->hw_profile == GST_VAAPI_PROFILE_UNKNOWN)
403 return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
406 if (priv->size_changed) {
407 GST_DEBUG("size changed");
408 priv->size_changed = FALSE;
409 reset_context = TRUE;
413 GstVaapiContextInfo info;
415 info.profile = priv->hw_profile;
416 info.entrypoint = entrypoint;
417 info.width = priv->width;
418 info.height = priv->height;
420 reset_context = gst_vaapi_decoder_ensure_context(
421 GST_VAAPI_DECODER(decoder),
425 return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
427 return GST_VAAPI_DECODER_STATUS_SUCCESS;
430 static GstVaapiDecoderStatus
431 ensure_quant_matrix(GstVaapiDecoderMpeg2 *decoder, GstVaapiPicture *picture)
433 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
434 VAIQMatrixBufferMPEG2 *iq_matrix;
435 guint8 *intra_quant_matrix = NULL;
436 guint8 *non_intra_quant_matrix = NULL;
437 guint8 *chroma_intra_quant_matrix = NULL;
438 guint8 *chroma_non_intra_quant_matrix = NULL;
440 if (!priv->quant_matrix_changed)
441 return GST_VAAPI_DECODER_STATUS_SUCCESS;
443 priv->quant_matrix_changed = FALSE;
445 picture->iq_matrix = GST_VAAPI_IQ_MATRIX_NEW(MPEG2, decoder);
446 if (!picture->iq_matrix) {
447 GST_ERROR("failed to allocate IQ matrix");
448 return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
450 iq_matrix = picture->iq_matrix->param;
452 intra_quant_matrix = priv->seq_hdr.intra_quantizer_matrix;
453 non_intra_quant_matrix = priv->seq_hdr.non_intra_quantizer_matrix;
454 if (priv->has_quant_matrix_ext) {
455 if (priv->quant_matrix_ext.load_intra_quantiser_matrix)
456 intra_quant_matrix = priv->quant_matrix_ext.intra_quantiser_matrix;
457 if (priv->quant_matrix_ext.load_non_intra_quantiser_matrix)
458 non_intra_quant_matrix = priv->quant_matrix_ext.non_intra_quantiser_matrix;
459 if (priv->quant_matrix_ext.load_chroma_intra_quantiser_matrix)
460 chroma_intra_quant_matrix = priv->quant_matrix_ext.chroma_intra_quantiser_matrix;
461 if (priv->quant_matrix_ext.load_chroma_non_intra_quantiser_matrix)
462 chroma_non_intra_quant_matrix = priv->quant_matrix_ext.chroma_non_intra_quantiser_matrix;
465 iq_matrix->load_intra_quantiser_matrix = intra_quant_matrix != NULL;
466 if (intra_quant_matrix)
467 copy_quant_matrix(iq_matrix->intra_quantiser_matrix,
470 iq_matrix->load_non_intra_quantiser_matrix = non_intra_quant_matrix != NULL;
471 if (non_intra_quant_matrix)
472 copy_quant_matrix(iq_matrix->non_intra_quantiser_matrix,
473 non_intra_quant_matrix);
475 iq_matrix->load_chroma_intra_quantiser_matrix = chroma_intra_quant_matrix != NULL;
476 if (chroma_intra_quant_matrix)
477 copy_quant_matrix(iq_matrix->chroma_intra_quantiser_matrix,
478 chroma_intra_quant_matrix);
480 iq_matrix->load_chroma_non_intra_quantiser_matrix = chroma_non_intra_quant_matrix != NULL;
481 if (chroma_non_intra_quant_matrix)
482 copy_quant_matrix(iq_matrix->chroma_non_intra_quantiser_matrix,
483 chroma_non_intra_quant_matrix);
484 return GST_VAAPI_DECODER_STATUS_SUCCESS;
488 decode_current_picture(GstVaapiDecoderMpeg2 *decoder)
490 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
491 GstVaapiPicture * const picture = priv->current_picture;
494 if (!gst_vaapi_picture_decode(picture))
496 if (GST_VAAPI_PICTURE_IS_COMPLETE(picture)) {
497 if (!gst_vaapi_dpb_add(priv->dpb, picture))
499 gst_vaapi_picture_replace(&priv->current_picture, NULL);
505 static GstVaapiDecoderStatus
506 decode_sequence(GstVaapiDecoderMpeg2 *decoder, guchar *buf, guint buf_size)
508 GstVaapiDecoder * const base_decoder = GST_VAAPI_DECODER(decoder);
509 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
510 GstMpegVideoSequenceHdr * const seq_hdr = &priv->seq_hdr;
512 if (!gst_mpeg_video_parse_sequence_header(seq_hdr, buf, buf_size, 4)) {
513 GST_ERROR("failed to parse sequence header");
514 return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
517 priv->fps_n = seq_hdr->fps_n;
518 priv->fps_d = seq_hdr->fps_d;
519 pts_set_framerate(&priv->tsg, priv->fps_n, priv->fps_d);
520 gst_vaapi_decoder_set_framerate(base_decoder, priv->fps_n, priv->fps_d);
522 gst_vaapi_decoder_set_pixel_aspect_ratio(
528 priv->width = seq_hdr->width;
529 priv->height = seq_hdr->height;
530 priv->has_seq_ext = FALSE;
531 priv->size_changed = TRUE;
532 priv->quant_matrix_changed = TRUE;
533 priv->progressive_sequence = TRUE;
534 return GST_VAAPI_DECODER_STATUS_SUCCESS;
537 static GstVaapiDecoderStatus
538 decode_sequence_ext(GstVaapiDecoderMpeg2 *decoder, guchar *buf, guint buf_size)
540 GstVaapiDecoder * const base_decoder = GST_VAAPI_DECODER(decoder);
541 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
542 GstMpegVideoSequenceExt * const seq_ext = &priv->seq_ext;
543 GstVaapiProfile profile;
546 if (!gst_mpeg_video_parse_sequence_extension(seq_ext, buf, buf_size, 4)) {
547 GST_ERROR("failed to parse sequence-extension");
548 return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
550 priv->has_seq_ext = TRUE;
551 priv->progressive_sequence = seq_ext->progressive;
552 gst_vaapi_decoder_set_interlaced(base_decoder, !priv->progressive_sequence);
554 width = (priv->width & 0x0fff) | ((guint32)seq_ext->horiz_size_ext << 12);
555 height = (priv->height & 0x0fff) | ((guint32)seq_ext->vert_size_ext << 12);
556 GST_DEBUG("video resolution %ux%u", width, height);
558 if (seq_ext->fps_n_ext && seq_ext->fps_d_ext) {
559 priv->fps_n *= seq_ext->fps_n_ext + 1;
560 priv->fps_d *= seq_ext->fps_d_ext + 1;
561 pts_set_framerate(&priv->tsg, priv->fps_n, priv->fps_d);
562 gst_vaapi_decoder_set_framerate(base_decoder, priv->fps_n, priv->fps_d);
565 if (priv->width != width) {
567 priv->size_changed = TRUE;
570 if (priv->height != height) {
571 priv->height = height;
572 priv->size_changed = TRUE;
575 switch (seq_ext->profile) {
576 case GST_MPEG_VIDEO_PROFILE_SIMPLE:
577 profile = GST_VAAPI_PROFILE_MPEG2_SIMPLE;
579 case GST_MPEG_VIDEO_PROFILE_MAIN:
580 profile = GST_VAAPI_PROFILE_MPEG2_MAIN;
582 case GST_MPEG_VIDEO_PROFILE_HIGH:
583 profile = GST_VAAPI_PROFILE_MPEG2_HIGH;
586 GST_ERROR("unsupported profile %d", seq_ext->profile);
587 return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
589 if (priv->profile != profile) {
590 priv->profile = profile;
591 priv->profile_changed = TRUE;
593 return GST_VAAPI_DECODER_STATUS_SUCCESS;
596 static GstVaapiDecoderStatus
597 decode_sequence_end(GstVaapiDecoderMpeg2 *decoder)
599 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
601 if (priv->current_picture && !decode_current_picture(decoder))
602 return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
604 gst_vaapi_dpb_flush(priv->dpb);
605 return GST_VAAPI_DECODER_STATUS_END_OF_STREAM;
608 static GstVaapiDecoderStatus
609 decode_quant_matrix_ext(GstVaapiDecoderMpeg2 *decoder, guchar *buf, guint buf_size)
611 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
612 GstMpegVideoQuantMatrixExt * const quant_matrix_ext = &priv->quant_matrix_ext;
614 if (!gst_mpeg_video_parse_quant_matrix_extension(quant_matrix_ext, buf, buf_size, 4)) {
615 GST_ERROR("failed to parse quant-matrix-extension");
616 return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
618 priv->has_quant_matrix_ext = TRUE;
619 priv->quant_matrix_changed = TRUE;
620 return GST_VAAPI_DECODER_STATUS_SUCCESS;
623 static GstVaapiDecoderStatus
624 decode_gop(GstVaapiDecoderMpeg2 *decoder, guchar *buf, guint buf_size)
626 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
630 if (!gst_mpeg_video_parse_gop(&gop, buf, buf_size, 4)) {
631 GST_ERROR("failed to parse GOP");
632 return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
635 priv->closed_gop = gop.closed_gop;
636 priv->broken_link = gop.broken_link;
638 GST_DEBUG("GOP %02u:%02u:%02u:%02u (closed_gop %d, broken_link %d)",
639 gop.hour, gop.minute, gop.second, gop.frame,
640 priv->closed_gop, priv->broken_link);
642 pts = gst_adapter_prev_timestamp(priv->adapter, NULL);
643 pts_sync(&priv->tsg, pts);
644 return GST_VAAPI_DECODER_STATUS_SUCCESS;
647 static GstVaapiDecoderStatus
648 decode_picture(GstVaapiDecoderMpeg2 *decoder, guchar *buf, guint buf_size)
650 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
651 GstMpegVideoPictureHdr * const pic_hdr = &priv->pic_hdr;
652 GstVaapiPicture *picture;
653 GstVaapiDecoderStatus status;
656 status = ensure_context(decoder);
657 if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
658 GST_ERROR("failed to reset context");
662 if (priv->current_picture && !decode_current_picture(decoder))
663 return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
665 if (priv->current_picture) {
666 /* Re-use current picture where the first field was decoded */
667 picture = gst_vaapi_picture_new_field(priv->current_picture);
669 GST_ERROR("failed to allocate field picture");
670 return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
674 /* Create new picture */
675 picture = GST_VAAPI_PICTURE_NEW(MPEG2, decoder);
677 GST_ERROR("failed to allocate picture");
678 return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
681 gst_vaapi_picture_replace(&priv->current_picture, picture);
682 gst_vaapi_picture_unref(picture);
684 status = ensure_quant_matrix(decoder, picture);
685 if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
686 GST_ERROR("failed to reset quantizer matrix");
690 if (!gst_mpeg_video_parse_picture_header(pic_hdr, buf, buf_size, 4)) {
691 GST_ERROR("failed to parse picture header");
692 return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
694 priv->has_pic_ext = FALSE;
696 switch (pic_hdr->pic_type) {
697 case GST_MPEG_VIDEO_PICTURE_TYPE_I:
698 GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_REFERENCE);
699 picture->type = GST_VAAPI_PICTURE_TYPE_I;
701 case GST_MPEG_VIDEO_PICTURE_TYPE_P:
702 GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_REFERENCE);
703 picture->type = GST_VAAPI_PICTURE_TYPE_P;
705 case GST_MPEG_VIDEO_PICTURE_TYPE_B:
706 picture->type = GST_VAAPI_PICTURE_TYPE_B;
709 GST_ERROR("unsupported picture type %d", pic_hdr->pic_type);
710 return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
713 /* Update presentation time */
714 pts = gst_adapter_prev_timestamp(priv->adapter, NULL);
715 picture->pts = pts_eval(&priv->tsg, pts, pic_hdr->tsn);
716 picture->poc = pts_get_poc(&priv->tsg);
720 static GstVaapiDecoderStatus
721 decode_picture_ext(GstVaapiDecoderMpeg2 *decoder, guchar *buf, guint buf_size)
723 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
724 GstMpegVideoPictureExt * const pic_ext = &priv->pic_ext;
725 GstVaapiPicture * const picture = priv->current_picture;
727 if (!gst_mpeg_video_parse_picture_extension(pic_ext, buf, buf_size, 4)) {
728 GST_ERROR("failed to parse picture-extension");
729 return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
731 priv->has_pic_ext = TRUE;
733 if (priv->progressive_sequence && !pic_ext->progressive_frame) {
734 GST_WARNING("invalid interlaced frame in progressive sequence, fixing");
735 pic_ext->progressive_frame = 1;
738 if (pic_ext->picture_structure == 0 ||
739 (pic_ext->progressive_frame &&
740 pic_ext->picture_structure != GST_MPEG_VIDEO_PICTURE_STRUCTURE_FRAME)) {
741 GST_WARNING("invalid picture_structure %d, replacing with \"frame\"",
742 pic_ext->picture_structure);
743 pic_ext->picture_structure = GST_MPEG_VIDEO_PICTURE_STRUCTURE_FRAME;
746 if (!priv->progressive_sequence && !pic_ext->progressive_frame) {
747 GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_INTERLACED);
748 if (pic_ext->top_field_first)
749 GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_TFF);
752 switch (pic_ext->picture_structure) {
753 case GST_MPEG_VIDEO_PICTURE_STRUCTURE_TOP_FIELD:
754 picture->structure = GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD;
756 case GST_MPEG_VIDEO_PICTURE_STRUCTURE_BOTTOM_FIELD:
757 picture->structure = GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD;
759 case GST_MPEG_VIDEO_PICTURE_STRUCTURE_FRAME:
760 picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
764 /* Allocate dummy picture for first field based I-frame */
765 if (picture->type == GST_VAAPI_PICTURE_TYPE_I &&
766 !GST_VAAPI_PICTURE_IS_FRAME(picture) &&
767 gst_vaapi_dpb_size(priv->dpb) == 0) {
768 GstVaapiPicture *dummy_picture;
771 dummy_picture = GST_VAAPI_PICTURE_NEW(MPEG2, decoder);
772 if (!dummy_picture) {
773 GST_ERROR("failed to allocate dummy picture");
774 return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
777 dummy_picture->type = GST_VAAPI_PICTURE_TYPE_I;
778 dummy_picture->pts = GST_CLOCK_TIME_NONE;
779 dummy_picture->poc = -1;
780 dummy_picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
782 GST_VAAPI_PICTURE_FLAG_SET(
784 (GST_VAAPI_PICTURE_FLAG_SKIPPED |
785 GST_VAAPI_PICTURE_FLAG_REFERENCE)
788 success = gst_vaapi_dpb_add(priv->dpb, dummy_picture);
789 gst_vaapi_picture_unref(dummy_picture);
791 GST_ERROR("failed to add dummy picture into DPB");
792 return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
794 GST_INFO("allocated dummy picture for first field based I-frame");
796 return GST_VAAPI_DECODER_STATUS_SUCCESS;
799 static inline guint32
800 pack_f_code(guint8 f_code[2][2])
802 return (((guint32)f_code[0][0] << 12) |
803 ((guint32)f_code[0][1] << 8) |
804 ((guint32)f_code[1][0] << 4) |
809 fill_picture(GstVaapiDecoderMpeg2 *decoder, GstVaapiPicture *picture)
811 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
812 VAPictureParameterBufferMPEG2 * const pic_param = picture->param;
813 GstMpegVideoPictureHdr * const pic_hdr = &priv->pic_hdr;
814 GstMpegVideoPictureExt * const pic_ext = &priv->pic_ext;
815 GstVaapiPicture *prev_picture, *next_picture;
817 if (!priv->has_pic_ext)
820 /* Fill in VAPictureParameterBufferMPEG2 */
821 pic_param->horizontal_size = priv->width;
822 pic_param->vertical_size = priv->height;
823 pic_param->forward_reference_picture = VA_INVALID_ID;
824 pic_param->backward_reference_picture = VA_INVALID_ID;
825 pic_param->picture_coding_type = pic_hdr->pic_type;
826 pic_param->f_code = pack_f_code(pic_ext->f_code);
828 #define COPY_FIELD(a, b, f) \
829 pic_param->a.b.f = pic_ext->f
830 pic_param->picture_coding_extension.value = 0;
831 pic_param->picture_coding_extension.bits.is_first_field = GST_VAAPI_PICTURE_IS_FIRST_FIELD(picture);
832 COPY_FIELD(picture_coding_extension, bits, intra_dc_precision);
833 COPY_FIELD(picture_coding_extension, bits, picture_structure);
834 COPY_FIELD(picture_coding_extension, bits, top_field_first);
835 COPY_FIELD(picture_coding_extension, bits, frame_pred_frame_dct);
836 COPY_FIELD(picture_coding_extension, bits, concealment_motion_vectors);
837 COPY_FIELD(picture_coding_extension, bits, q_scale_type);
838 COPY_FIELD(picture_coding_extension, bits, intra_vlc_format);
839 COPY_FIELD(picture_coding_extension, bits, alternate_scan);
840 COPY_FIELD(picture_coding_extension, bits, repeat_first_field);
841 COPY_FIELD(picture_coding_extension, bits, progressive_frame);
843 gst_vaapi_dpb_mpeg2_get_references(
850 switch (pic_hdr->pic_type) {
851 case GST_MPEG_VIDEO_PICTURE_TYPE_B:
853 pic_param->backward_reference_picture = next_picture->surface_id;
855 pic_param->forward_reference_picture = prev_picture->surface_id;
856 else if (!priv->closed_gop)
857 GST_VAAPI_PICTURE_FLAG_SET(picture, GST_VAAPI_PICTURE_FLAG_SKIPPED);
859 case GST_MPEG_VIDEO_PICTURE_TYPE_P:
861 pic_param->forward_reference_picture = prev_picture->surface_id;
867 static GstVaapiDecoderStatus
869 GstVaapiDecoderMpeg2 *decoder,
875 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
876 GstVaapiPicture * const picture = priv->current_picture;
877 GstVaapiSlice *slice;
878 VASliceParameterBufferMPEG2 *slice_param;
880 gint mb_x, mb_y, mb_inc;
881 guint macroblock_offset;
882 guint8 slice_vertical_position_extension;
883 guint8 quantiser_scale_code;
884 guint8 intra_slice = 0;
885 guint8 extra_bit_slice, junk8;
887 GST_DEBUG("slice %d @ %p, %u bytes)", slice_no, buf, buf_size);
889 if (picture->slices->len == 0 && !fill_picture(decoder, picture))
890 return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
892 slice = GST_VAAPI_SLICE_NEW(MPEG2, decoder, buf, buf_size);
894 GST_ERROR("failed to allocate slice");
895 return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
897 gst_vaapi_picture_add_slice(picture, slice);
900 gst_bit_reader_init(&br, buf, buf_size);
901 SKIP(&br, 32); /* slice_start_code */
902 if (priv->height > 2800)
903 READ_UINT8(&br, slice_vertical_position_extension, 3);
904 if (priv->has_seq_scalable_ext) {
905 GST_ERROR("failed to parse slice %d. Unsupported sequence_scalable_extension()", slice_no);
906 return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
908 READ_UINT8(&br, quantiser_scale_code, 5);
909 READ_UINT8(&br, extra_bit_slice, 1);
910 if (extra_bit_slice == 1) {
911 READ_UINT8(&br, intra_slice, 1);
912 READ_UINT8(&br, junk8, 7);
913 READ_UINT8(&br, extra_bit_slice, 1);
914 while (extra_bit_slice == 1) {
915 READ_UINT8(&br, junk8, 8);
916 READ_UINT8(&br, extra_bit_slice, 1);
919 macroblock_offset = gst_bit_reader_get_pos(&br);
924 if (!decode_vlc(&br, &mb_inc, mpeg2_mbaddr_vlc_table,
925 G_N_ELEMENTS(mpeg2_mbaddr_vlc_table))) {
926 GST_WARNING("failed to decode first macroblock_address_increment");
929 mb_x += mb_inc == GST_MPEG_VIDEO_MACROBLOCK_ESCAPE ? 33 : mb_inc;
930 } while (mb_inc == GST_MPEG_VIDEO_MACROBLOCK_ESCAPE);
932 /* Fill in VASliceParameterBufferMPEG2 */
933 slice_param = slice->param;
934 slice_param->macroblock_offset = macroblock_offset;
935 slice_param->slice_horizontal_position = mb_x;
936 slice_param->slice_vertical_position = mb_y;
937 slice_param->quantiser_scale_code = quantiser_scale_code;
938 slice_param->intra_slice_flag = intra_slice;
939 return GST_VAAPI_DECODER_STATUS_SUCCESS;
942 return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
946 scan_for_start_code(GstAdapter *adapter, guint ofs, guint size, guint32 *scp)
948 return (gint)gst_adapter_masked_scan_uint32_peek(adapter,
949 0xffffff00, 0x00000100,
954 static GstVaapiDecoderStatus
955 decode_packet(GstVaapiDecoderMpeg2 *decoder, guchar *buf, guint buf_size)
957 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
958 GstVaapiDecoderStatus status;
961 /* The packet defined by buf and buf_size contains the start code */
964 case GST_MPEG_VIDEO_PACKET_PICTURE:
965 if (!priv->width || !priv->height)
966 goto unknown_picture_size;
967 status = decode_picture(decoder, buf, buf_size);
969 case GST_MPEG_VIDEO_PACKET_SEQUENCE:
970 status = decode_sequence(decoder, buf, buf_size);
972 case GST_MPEG_VIDEO_PACKET_EXTENSION: {
973 const guchar id = buf[4] >> 4;
975 case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE:
976 status = decode_sequence_ext(decoder, buf, buf_size);
978 case GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX:
979 status = decode_quant_matrix_ext(decoder, buf, buf_size);
981 case GST_MPEG_VIDEO_PACKET_EXT_PICTURE:
982 if (!priv->width || !priv->height)
983 goto unknown_picture_size;
984 status = decode_picture_ext(decoder, buf, buf_size);
987 // Ignore unknown start-code extensions
988 GST_WARNING("unsupported start code extension (0x%02x)", id);
989 status = GST_VAAPI_DECODER_STATUS_SUCCESS;
994 case GST_MPEG_VIDEO_PACKET_SEQUENCE_END:
995 status = decode_sequence_end(decoder);
997 case GST_MPEG_VIDEO_PACKET_GOP:
998 status = decode_gop(decoder, buf, buf_size);
1000 case GST_MPEG_VIDEO_PACKET_USER_DATA:
1001 // Ignore user-data packets
1002 status = GST_VAAPI_DECODER_STATUS_SUCCESS;
1005 if (type >= GST_MPEG_VIDEO_PACKET_SLICE_MIN &&
1006 type <= GST_MPEG_VIDEO_PACKET_SLICE_MAX) {
1007 if (!priv->current_picture)
1008 goto undefined_picture;
1009 status = decode_slice(
1011 type - GST_MPEG_VIDEO_PACKET_SLICE_MIN,
1016 else if (type >= 0xb9 && type <= 0xff) {
1017 // Ignore system start codes (PES headers)
1018 status = GST_VAAPI_DECODER_STATUS_SUCCESS;
1021 GST_WARNING("unsupported start code (0x%02x)", type);
1022 status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
1027 unknown_picture_size:
1028 // Ignore packet while picture size is undefined
1029 // i.e. missing sequence headers, or not parsed correctly
1030 GST_WARNING("failed to parse picture of unknown size");
1031 return GST_VAAPI_DECODER_STATUS_SUCCESS;
1034 // Ignore packet while picture is undefined
1035 // i.e. missing picture headers, or not parsed correctly
1036 GST_WARNING("failed to parse slice with undefined picture");
1037 return GST_VAAPI_DECODER_STATUS_SUCCESS;
1040 static GstVaapiDecoderStatus
1041 decode_buffer(GstVaapiDecoderMpeg2 *decoder, GstBuffer *buffer)
1043 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
1044 GstVaapiDecoderStatus status;
1047 guint buf_size, size;
1051 buf = GST_BUFFER_DATA(buffer);
1052 buf_size = GST_BUFFER_SIZE(buffer);
1053 is_eos = GST_BUFFER_IS_EOS(buffer);
1054 if (buf && buf_size > 0)
1055 gst_adapter_push(priv->adapter, gst_buffer_ref(buffer));
1057 size = gst_adapter_available(priv->adapter);
1060 status = GST_VAAPI_DECODER_STATUS_SUCCESS;
1064 status = GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
1067 ofs = scan_for_start_code(priv->adapter, 0, size, &start_code);
1070 gst_adapter_flush(priv->adapter, ofs);
1073 status = gst_vaapi_decoder_check_status(GST_VAAPI_DECODER(decoder));
1074 if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
1077 status = GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
1080 ofs = scan_for_start_code(priv->adapter, 4, size - 4, NULL);
1082 // Assume the whole packet is present if end-of-stream
1087 buffer = gst_adapter_take_buffer(priv->adapter, ofs);
1090 buf = GST_BUFFER_DATA(buffer);
1091 buf_size = GST_BUFFER_SIZE(buffer);
1092 status = decode_packet(decoder, buf, buf_size);
1094 gst_buffer_unref(buffer);
1095 } while (status == GST_VAAPI_DECODER_STATUS_SUCCESS);
1097 if (is_eos && (status == GST_VAAPI_DECODER_STATUS_SUCCESS ||
1098 status == GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA))
1099 status = decode_sequence_end(decoder);
1103 GstVaapiDecoderStatus
1104 gst_vaapi_decoder_mpeg2_decode(GstVaapiDecoder *base, GstBuffer *buffer)
1106 GstVaapiDecoderMpeg2 * const decoder = GST_VAAPI_DECODER_MPEG2(base);
1107 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
1109 g_return_val_if_fail(priv->is_constructed,
1110 GST_VAAPI_DECODER_STATUS_ERROR_INIT_FAILED);
1112 if (!priv->is_opened) {
1113 priv->is_opened = gst_vaapi_decoder_mpeg2_open(decoder, buffer);
1114 if (!priv->is_opened)
1115 return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC;
1117 return decode_buffer(decoder, buffer);
1121 gst_vaapi_decoder_mpeg2_finalize(GObject *object)
1123 GstVaapiDecoderMpeg2 * const decoder = GST_VAAPI_DECODER_MPEG2(object);
1125 gst_vaapi_decoder_mpeg2_destroy(decoder);
1127 G_OBJECT_CLASS(gst_vaapi_decoder_mpeg2_parent_class)->finalize(object);
1131 gst_vaapi_decoder_mpeg2_constructed(GObject *object)
1133 GstVaapiDecoderMpeg2 * const decoder = GST_VAAPI_DECODER_MPEG2(object);
1134 GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
1135 GObjectClass *parent_class;
1137 parent_class = G_OBJECT_CLASS(gst_vaapi_decoder_mpeg2_parent_class);
1138 if (parent_class->constructed)
1139 parent_class->constructed(object);
1141 priv->is_constructed = gst_vaapi_decoder_mpeg2_create(decoder);
1145 gst_vaapi_decoder_mpeg2_class_init(GstVaapiDecoderMpeg2Class *klass)
1147 GObjectClass * const object_class = G_OBJECT_CLASS(klass);
1148 GstVaapiDecoderClass * const decoder_class = GST_VAAPI_DECODER_CLASS(klass);
1150 g_type_class_add_private(klass, sizeof(GstVaapiDecoderMpeg2Private));
1152 object_class->finalize = gst_vaapi_decoder_mpeg2_finalize;
1153 object_class->constructed = gst_vaapi_decoder_mpeg2_constructed;
1155 decoder_class->decode = gst_vaapi_decoder_mpeg2_decode;
1159 gst_vaapi_decoder_mpeg2_init(GstVaapiDecoderMpeg2 *decoder)
1161 GstVaapiDecoderMpeg2Private *priv;
1163 priv = GST_VAAPI_DECODER_MPEG2_GET_PRIVATE(decoder);
1164 decoder->priv = priv;
1169 priv->hw_profile = GST_VAAPI_PROFILE_UNKNOWN;
1170 priv->profile = GST_VAAPI_PROFILE_MPEG2_SIMPLE;
1171 priv->current_picture = NULL;
1172 priv->adapter = NULL;
1173 priv->is_constructed = FALSE;
1174 priv->is_opened = FALSE;
1175 priv->has_seq_ext = FALSE;
1176 priv->has_seq_scalable_ext = FALSE;
1177 priv->has_pic_ext = FALSE;
1178 priv->has_quant_matrix_ext = FALSE;
1179 priv->size_changed = FALSE;
1180 priv->profile_changed = TRUE; /* Allow fallbacks to work */
1181 priv->quant_matrix_changed = FALSE;
1182 priv->progressive_sequence = FALSE;
1183 priv->closed_gop = FALSE;
1184 priv->broken_link = FALSE;
1188 * gst_vaapi_decoder_mpeg2_new:
1189 * @display: a #GstVaapiDisplay
1190 * @caps: a #GstCaps holding codec information
1192 * Creates a new #GstVaapiDecoder for MPEG-2 decoding. The @caps can
1193 * hold extra information like codec-data and pictured coded size.
1195 * Return value: the newly allocated #GstVaapiDecoder object
1198 gst_vaapi_decoder_mpeg2_new(GstVaapiDisplay *display, GstCaps *caps)
1200 GstVaapiDecoderMpeg2 *decoder;
1202 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
1203 g_return_val_if_fail(GST_IS_CAPS(caps), NULL);
1205 decoder = g_object_new(
1206 GST_VAAPI_TYPE_DECODER_MPEG2,
1211 if (!decoder->priv->is_constructed) {
1212 g_object_unref(decoder);
1215 return GST_VAAPI_DECODER_CAST(decoder);