mpeg2: replace GstVaapiTSB API with GstAdapter (gst-plugins-base >= 0.10.24).
[platform/upstream/gstreamer-vaapi.git] / gst-libs / gst / vaapi / gstvaapidecoder_mpeg2.c
1 /*
2  *  gstvaapidecoder_mpeg2.c - MPEG-2 decoder
3  *
4  *  Copyright (C) 2011 Intel Corporation
5  *
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.
10  *
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.
15  *
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
20  */
21
22 /**
23  * SECTION:gstvaapidecoder_mpeg2
24  * @short_description: MPEG-2 decoder
25  */
26
27 #include "config.h"
28 #include <string.h>
29 #include <gst/base/gstbitreader.h>
30 #include <gst/codecparsers/gstmpegvideoparser.h>
31 #include "gstvaapidecoder_mpeg2.h"
32 #include "gstvaapidecoder_priv.h"
33 #include "gstvaapidisplay_priv.h"
34 #include "gstvaapiobject_priv.h"
35
36 #define DEBUG 1
37 #include "gstvaapidebug.h"
38
39 G_DEFINE_TYPE(GstVaapiDecoderMpeg2,
40               gst_vaapi_decoder_mpeg2,
41               GST_VAAPI_TYPE_DECODER);
42
43 #define GST_VAAPI_DECODER_MPEG2_GET_PRIVATE(obj)                \
44     (G_TYPE_INSTANCE_GET_PRIVATE((obj),                         \
45                                  GST_VAAPI_TYPE_DECODER_MPEG2,  \
46                                  GstVaapiDecoderMpeg2Private))
47
48 #define READ_UINT8(br, val, nbits) G_STMT_START {  \
49   if (!gst_bit_reader_get_bits_uint8 (br, &val, nbits)) { \
50     GST_WARNING ("failed to read uint8, nbits: %d", nbits); \
51     goto failed; \
52   } \
53 } G_STMT_END
54
55 struct _GstVaapiDecoderMpeg2Private {
56     GstVaapiProfile             profile;
57     guint                       width;
58     guint                       height;
59     guint                       fps_n;
60     guint                       fps_d;
61     GstMpegVideoSequenceHdr     seq_hdr;
62     GstMpegVideoSequenceExt     seq_ext;
63     GstMpegVideoPictureHdr      pic_hdr;
64     GstMpegVideoPictureExt      pic_ext;
65     GstMpegVideoQuantMatrixExt  quant_matrix_ext;
66     GstVaapiPicture            *current_picture;
67     GstVaapiPicture            *next_picture;
68     GstVaapiPicture            *prev_picture;
69     GstAdapter                 *adapter;
70     GstBuffer                  *sub_buffer;
71     guint                       mb_y;
72     guint                       mb_height;
73     GstClockTime                seq_pts;
74     GstClockTime                gop_pts;
75     GstClockTime                pts_diff;
76     guint                       is_constructed          : 1;
77     guint                       is_opened               : 1;
78     guint                       is_first_field          : 1;
79     guint                       has_seq_ext             : 1;
80     guint                       has_seq_scalable_ext    : 1;
81     guint                       has_pic_ext             : 1;
82     guint                       has_quant_matrix_ext    : 1;
83     guint                       size_changed            : 1;
84     guint                       profile_changed         : 1;
85     guint                       quant_matrix_changed    : 1;
86     guint                       progressive_sequence    : 1;
87     guint                       closed_gop              : 1;
88     guint                       broken_link             : 1;
89 };
90
91 static void
92 gst_vaapi_decoder_mpeg2_close(GstVaapiDecoderMpeg2 *decoder)
93 {
94     GstVaapiDecoder * const base_decoder = GST_VAAPI_DECODER(decoder);
95     GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
96
97     if (priv->current_picture) {
98         gst_vaapi_decoder_free_picture(base_decoder, priv->current_picture);
99         priv->current_picture = NULL;
100     }
101
102     if (priv->next_picture) {
103         gst_vaapi_decoder_free_picture(base_decoder, priv->next_picture);
104         priv->next_picture = NULL;
105     }
106
107     if (priv->prev_picture) {
108         gst_vaapi_decoder_free_picture(base_decoder, priv->prev_picture);
109         priv->prev_picture = NULL;
110     }
111
112     if (priv->sub_buffer) {
113         gst_buffer_unref(priv->sub_buffer);
114         priv->sub_buffer = NULL;
115     }
116
117     if (priv->adapter) {
118         gst_adapter_clear(priv->adapter);
119         g_object_unref(priv->adapter);
120         priv->adapter = NULL;
121     }
122 }
123
124 static gboolean
125 gst_vaapi_decoder_mpeg2_open(GstVaapiDecoderMpeg2 *decoder, GstBuffer *buffer)
126 {
127     GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
128
129     gst_vaapi_decoder_mpeg2_close(decoder);
130
131     priv->adapter = gst_adapter_new();
132     if (!priv->adapter)
133         return FALSE;
134     return TRUE;
135 }
136
137 static void
138 gst_vaapi_decoder_mpeg2_destroy(GstVaapiDecoderMpeg2 *decoder)
139 {
140     gst_vaapi_decoder_mpeg2_close(decoder);
141 }
142
143 static gboolean
144 gst_vaapi_decoder_mpeg2_create(GstVaapiDecoderMpeg2 *decoder)
145 {
146     if (!GST_VAAPI_DECODER_CODEC(decoder))
147         return FALSE;
148     return TRUE;
149 }
150
151 static inline void
152 copy_quant_matrix(guint8 dst[64], const guint8 src[64])
153 {
154     memcpy(dst, src, 64);
155 }
156
157 static GstVaapiDecoderStatus
158 ensure_context(GstVaapiDecoderMpeg2 *decoder)
159 {
160     GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
161     GstVaapiProfile profiles[2];
162     GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_VLD;
163     guint i, n_profiles = 0;
164     gboolean reset_context = FALSE;
165
166     if (priv->profile_changed) {
167         GST_DEBUG("profile changed");
168         priv->profile_changed = FALSE;
169         reset_context         = TRUE;
170
171         profiles[n_profiles++] = priv->profile;
172         if (priv->profile == GST_VAAPI_PROFILE_MPEG2_SIMPLE)
173             profiles[n_profiles++] = GST_VAAPI_PROFILE_MPEG2_MAIN;
174
175         for (i = 0; i < n_profiles; i++) {
176             if (gst_vaapi_display_has_decoder(GST_VAAPI_DECODER_DISPLAY(decoder),
177                                               profiles[i], entrypoint))
178                 break;
179         }
180         if (i == n_profiles)
181             return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
182         priv->profile = profiles[i];
183     }
184
185     if (priv->size_changed) {
186         GST_DEBUG("size changed");
187         priv->size_changed = FALSE;
188         reset_context      = TRUE;
189
190         if (priv->progressive_sequence)
191             priv->mb_height = (priv->height + 15) / 16;
192         else
193             priv->mb_height = (priv->height + 31) / 32 * 2;
194     }
195
196     if (reset_context) {
197         reset_context = gst_vaapi_decoder_ensure_context(
198             GST_VAAPI_DECODER(decoder),
199             priv->profile,
200             entrypoint,
201             priv->width, priv->height
202         );
203         if (!reset_context)
204             return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
205     }
206     return GST_VAAPI_DECODER_STATUS_SUCCESS;
207 }
208
209 static GstVaapiDecoderStatus
210 ensure_quant_matrix(GstVaapiDecoderMpeg2 *decoder, GstVaapiPicture *picture)
211 {
212     GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
213     VAIQMatrixBufferMPEG2 *iq_matrix;
214     guint8 *intra_quant_matrix = NULL;
215     guint8 *non_intra_quant_matrix = NULL;
216     guint8 *chroma_intra_quant_matrix = NULL;
217     guint8 *chroma_non_intra_quant_matrix = NULL;
218
219     if (!priv->quant_matrix_changed)
220         return GST_VAAPI_DECODER_STATUS_SUCCESS;
221
222     priv->quant_matrix_changed = FALSE;
223
224     picture->iq_matrix = gst_vaapi_decoder_new_iq_matrix(GST_VAAPI_DECODER(decoder));
225     if (!picture->iq_matrix) {
226         GST_DEBUG("failed to allocate IQ matrix");
227         return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
228     }
229     iq_matrix = picture->iq_matrix->param;
230
231     intra_quant_matrix     = priv->seq_hdr.intra_quantizer_matrix;
232     non_intra_quant_matrix = priv->seq_hdr.non_intra_quantizer_matrix;
233     if (priv->has_quant_matrix_ext) {
234         if (priv->quant_matrix_ext.load_intra_quantiser_matrix)
235             intra_quant_matrix = priv->quant_matrix_ext.intra_quantiser_matrix;
236         if (priv->quant_matrix_ext.load_non_intra_quantiser_matrix)
237             non_intra_quant_matrix = priv->quant_matrix_ext.non_intra_quantiser_matrix;
238         if (priv->quant_matrix_ext.load_chroma_intra_quantiser_matrix)
239             chroma_intra_quant_matrix = priv->quant_matrix_ext.chroma_intra_quantiser_matrix;
240         if (priv->quant_matrix_ext.load_chroma_non_intra_quantiser_matrix)
241             chroma_non_intra_quant_matrix = priv->quant_matrix_ext.chroma_non_intra_quantiser_matrix;
242     }
243
244     iq_matrix->load_intra_quantiser_matrix = intra_quant_matrix != NULL;
245     if (intra_quant_matrix) {
246         iq_matrix->load_intra_quantiser_matrix = 1;
247         copy_quant_matrix(iq_matrix->intra_quantiser_matrix,
248                           intra_quant_matrix);
249     }
250
251     iq_matrix->load_intra_quantiser_matrix = 1;
252     copy_quant_matrix(iq_matrix->intra_quantiser_matrix,
253                       priv->seq_hdr.intra_quantizer_matrix);
254
255     iq_matrix->load_non_intra_quantiser_matrix = 1;
256     copy_quant_matrix(iq_matrix->non_intra_quantiser_matrix,
257                       priv->seq_hdr.non_intra_quantizer_matrix);
258
259     iq_matrix->load_chroma_intra_quantiser_matrix     = 0;
260     iq_matrix->load_chroma_non_intra_quantiser_matrix = 0;
261     if (priv->has_quant_matrix_ext) {
262         if (priv->quant_matrix_ext.load_intra_quantiser_matrix)
263             copy_quant_matrix(iq_matrix->intra_quantiser_matrix,
264                               priv->quant_matrix_ext.intra_quantiser_matrix);
265
266         if (priv->quant_matrix_ext.load_non_intra_quantiser_matrix)
267             copy_quant_matrix(iq_matrix->non_intra_quantiser_matrix,
268                               priv->quant_matrix_ext.non_intra_quantiser_matrix);
269
270         if (priv->quant_matrix_ext.load_chroma_intra_quantiser_matrix) {
271             iq_matrix->load_chroma_intra_quantiser_matrix = 1;
272             copy_quant_matrix(iq_matrix->chroma_intra_quantiser_matrix,
273                               priv->quant_matrix_ext.chroma_intra_quantiser_matrix);
274         }
275
276         if (priv->quant_matrix_ext.load_chroma_non_intra_quantiser_matrix) {
277             iq_matrix->load_chroma_non_intra_quantiser_matrix = 1;
278             copy_quant_matrix(iq_matrix->chroma_non_intra_quantiser_matrix,
279                               priv->quant_matrix_ext.chroma_non_intra_quantiser_matrix);
280         }
281     }
282     return GST_VAAPI_DECODER_STATUS_SUCCESS;
283 }
284
285 static inline GstVaapiDecoderStatus
286 render_picture(GstVaapiDecoderMpeg2 *decoder, GstVaapiPicture *picture)
287 {
288     GstVaapiDecoder * const base_decoder = GST_VAAPI_DECODER(decoder);
289
290     if (!gst_vaapi_decoder_push_surface(base_decoder,
291                                         picture->surface,
292                                         picture->pts))
293         return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
294     return GST_VAAPI_DECODER_STATUS_SUCCESS;
295 }
296
297 static GstVaapiDecoderStatus
298 decode_current_picture(GstVaapiDecoderMpeg2 *decoder)
299 {
300     GstVaapiDecoder * const base_decoder = GST_VAAPI_DECODER(decoder);
301     GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
302     GstVaapiPicture * const picture = priv->current_picture;
303     GstVaapiDecoderStatus status = GST_VAAPI_DECODER_STATUS_SUCCESS;
304
305     if (picture) {
306         if (!gst_vaapi_decoder_decode_picture(base_decoder, picture))
307             status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
308         if (!GST_VAAPI_PICTURE_IS_REFERENCE(picture)) {
309             if ((priv->prev_picture && priv->next_picture) ||
310                 (priv->closed_gop && priv->next_picture))
311                 status = render_picture(decoder, picture);
312             gst_vaapi_decoder_free_picture(base_decoder, picture);
313         }
314         priv->current_picture = NULL;
315     }
316     return status;
317 }
318
319 static GstVaapiDecoderStatus
320 decode_sequence(GstVaapiDecoderMpeg2 *decoder, guchar *buf, guint buf_size)
321 {
322     GstVaapiDecoder * const base_decoder = GST_VAAPI_DECODER(decoder);
323     GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
324     GstMpegVideoSequenceHdr * const seq_hdr = &priv->seq_hdr;
325
326     if (!gst_mpeg_video_parse_sequence_header(seq_hdr, buf, buf_size, 0)) {
327         GST_DEBUG("failed to parse sequence header");
328         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
329     }
330
331     priv->fps_n = seq_hdr->fps_n;
332     priv->fps_d = seq_hdr->fps_d;
333     gst_vaapi_decoder_set_framerate(base_decoder, priv->fps_n, priv->fps_d);
334
335     priv->seq_pts = gst_adapter_prev_timestamp(priv->adapter, NULL);
336
337     priv->width                 = seq_hdr->width;
338     priv->height                = seq_hdr->height;
339     priv->has_seq_ext           = FALSE;
340     priv->size_changed          = TRUE;
341     priv->quant_matrix_changed  = TRUE;
342     priv->progressive_sequence  = TRUE;
343     return GST_VAAPI_DECODER_STATUS_SUCCESS;
344 }
345
346 static GstVaapiDecoderStatus
347 decode_sequence_ext(GstVaapiDecoderMpeg2 *decoder, guchar *buf, guint buf_size)
348 {
349     GstVaapiDecoder * const base_decoder = GST_VAAPI_DECODER(decoder);
350     GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
351     GstMpegVideoSequenceExt * const seq_ext = &priv->seq_ext;
352     GstVaapiProfile profile;
353     guint width, height;
354
355     if (!gst_mpeg_video_parse_sequence_extension(seq_ext, buf, buf_size, 0)) {
356         GST_DEBUG("failed to parse sequence-extension");
357         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
358     }
359     priv->has_seq_ext = TRUE;
360     priv->progressive_sequence = seq_ext->progressive;
361
362     width  = (priv->width  & 0xffff) | ((guint32)seq_ext->horiz_size_ext << 16);
363     height = (priv->height & 0xffff) | ((guint32)seq_ext->vert_size_ext  << 16);
364     GST_DEBUG("video resolution %ux%u", width, height);
365
366     if (seq_ext->fps_n_ext && seq_ext->fps_d_ext) {
367         priv->fps_n *= seq_ext->fps_n_ext + 1;
368         priv->fps_d *= seq_ext->fps_d_ext + 1;
369         gst_vaapi_decoder_set_framerate(base_decoder, priv->fps_n, priv->fps_d);
370     }
371
372     if (priv->width != width) {
373         priv->width = width;
374         priv->size_changed = TRUE;
375     }
376
377     if (priv->height != height) {
378         priv->height = height;
379         priv->size_changed = TRUE;
380     }
381
382     switch (seq_ext->profile) {
383     case GST_MPEG_VIDEO_PROFILE_SIMPLE:
384         profile = GST_VAAPI_PROFILE_MPEG2_SIMPLE;
385         break;
386     case GST_MPEG_VIDEO_PROFILE_MAIN:
387         profile = GST_VAAPI_PROFILE_MPEG2_MAIN;
388         break;
389     default:
390         GST_DEBUG("unsupported profile %d", seq_ext->profile);
391         return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
392     }
393     if (priv->profile != profile) {
394         priv->profile = profile;
395         priv->profile_changed = TRUE;
396     }
397     return GST_VAAPI_DECODER_STATUS_SUCCESS;
398 }
399
400 static GstVaapiDecoderStatus
401 decode_sequence_end(GstVaapiDecoderMpeg2 *decoder)
402 {
403     GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
404     GstVaapiDecoderStatus status;
405
406     if (priv->current_picture) {
407         status = decode_current_picture(decoder);
408         if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
409             return status;
410         status = render_picture(decoder, priv->current_picture);
411         if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
412             return status;
413     }
414
415     if (priv->next_picture) {
416         status = render_picture(decoder, priv->next_picture);
417         if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
418             return status;
419     }
420     return GST_VAAPI_DECODER_STATUS_END_OF_STREAM;
421 }
422
423 static GstVaapiDecoderStatus
424 decode_quant_matrix_ext(GstVaapiDecoderMpeg2 *decoder, guchar *buf, guint buf_size)
425 {
426     GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
427     GstMpegVideoQuantMatrixExt * const quant_matrix_ext = &priv->quant_matrix_ext;
428
429     if (!gst_mpeg_video_parse_quant_matrix_extension(quant_matrix_ext, buf, buf_size, 0)) {
430         GST_DEBUG("failed to parse quant-matrix-extension");
431         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
432     }
433     priv->has_quant_matrix_ext = TRUE;
434     priv->quant_matrix_changed = TRUE;
435     return GST_VAAPI_DECODER_STATUS_SUCCESS;
436 }
437
438 static GstVaapiDecoderStatus
439 decode_gop(GstVaapiDecoderMpeg2 *decoder, guchar *buf, guint buf_size)
440 {
441     GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
442     GstMpegVideoGop gop;
443     GstClockTime pts;
444
445     if (!gst_mpeg_video_parse_gop(&gop, buf, buf_size, 0)) {
446         GST_DEBUG("failed to parse GOP");
447         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
448     }
449
450     priv->closed_gop  = gop.closed_gop;
451     priv->broken_link = gop.broken_link;
452
453     GST_DEBUG("GOP %02u:%02u:%02u:%02u (closed_gop %d, broken_link %d)",
454               gop.hour, gop.minute, gop.second, gop.frame,
455               priv->closed_gop, priv->broken_link);
456
457     pts = GST_SECOND * (gop.hour * 3600 + gop.minute * 60 + gop.second);
458     pts += gst_util_uint64_scale(gop.frame, GST_SECOND * priv->fps_d, priv->fps_n);
459     priv->gop_pts = pts;
460     if (!priv->pts_diff)
461         priv->pts_diff = priv->seq_pts - priv->gop_pts;
462     return GST_VAAPI_DECODER_STATUS_SUCCESS;
463 }
464
465 static GstVaapiDecoderStatus
466 decode_picture(GstVaapiDecoderMpeg2 *decoder, guchar *buf, guint buf_size)
467 {
468     GstVaapiDecoder * const base_decoder = GST_VAAPI_DECODER(decoder);
469     GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
470     GstMpegVideoPictureHdr * const pic_hdr = &priv->pic_hdr;
471     GstVaapiPicture *picture;
472     GstVaapiDecoderStatus status;
473     GstClockTime pts;
474
475     status = ensure_context(decoder);
476     if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
477         GST_DEBUG("failed to reset context");
478         return status;
479     }
480
481     if (priv->current_picture) {
482         status = decode_current_picture(decoder);
483         if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
484             return status;
485     }
486
487     priv->current_picture = gst_vaapi_decoder_new_picture(base_decoder);
488     if (!priv->current_picture) {
489         GST_DEBUG("failed to allocate picture");
490         return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
491     }
492     picture = priv->current_picture;
493
494     status = ensure_quant_matrix(decoder, picture);
495     if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
496         GST_DEBUG("failed to reset quantizer matrix");
497         return status;
498     }
499
500     if (!gst_mpeg_video_parse_picture_header(pic_hdr, buf, buf_size, 0)) {
501         GST_DEBUG("failed to parse picture header");
502         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
503     }
504     priv->has_pic_ext = FALSE;
505
506     switch (pic_hdr->pic_type) {
507     case GST_MPEG_VIDEO_PICTURE_TYPE_I:
508         picture->type = GST_VAAPI_PICTURE_TYPE_I;
509         break;
510     case GST_MPEG_VIDEO_PICTURE_TYPE_P:
511         picture->type = GST_VAAPI_PICTURE_TYPE_P;
512         break;
513     case GST_MPEG_VIDEO_PICTURE_TYPE_B:
514         picture->type = GST_VAAPI_PICTURE_TYPE_B;
515         break;
516     default:
517         GST_DEBUG("unsupported picture type %d", pic_hdr->pic_type);
518         return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
519     }
520
521     priv->mb_y = 0;
522     if (pic_hdr->pic_type == GST_MPEG_VIDEO_PICTURE_TYPE_I)
523         priv->is_first_field = TRUE;
524     else
525         priv->is_first_field ^= 1;
526
527     /* Update presentation time */
528     pts = priv->gop_pts;
529     pts += gst_util_uint64_scale(pic_hdr->tsn, GST_SECOND * priv->fps_d, priv->fps_n);
530     picture->pts = pts + priv->pts_diff;
531
532     /* Update reference pictures */
533     if (pic_hdr->pic_type != GST_MPEG_VIDEO_PICTURE_TYPE_B) {
534         picture->flags |= GST_VAAPI_PICTURE_REFERENCE;
535         if (priv->prev_picture) {
536             gst_vaapi_decoder_free_picture(base_decoder, priv->prev_picture);
537             priv->prev_picture = NULL;
538         }
539         if (priv->next_picture) {
540             priv->prev_picture = priv->next_picture;
541             priv->next_picture = NULL;
542             status = render_picture(decoder, priv->prev_picture);
543         }
544         priv->next_picture = picture;
545     }
546     return status;
547 }
548
549 static GstVaapiDecoderStatus
550 decode_picture_ext(GstVaapiDecoderMpeg2 *decoder, guchar *buf, guint buf_size)
551 {
552     GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
553     GstMpegVideoPictureExt * const pic_ext = &priv->pic_ext;
554
555     if (!gst_mpeg_video_parse_picture_extension(pic_ext, buf, buf_size, 0)) {
556         GST_DEBUG("failed to parse picture-extension");
557         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
558     }
559     priv->has_pic_ext = TRUE;
560     return GST_VAAPI_DECODER_STATUS_SUCCESS;
561 }
562
563 static inline guint32
564 pack_f_code(guint8 f_code[2][2])
565 {
566     return (((guint32)f_code[0][0] << 12) |
567             ((guint32)f_code[0][1] <<  8) |
568             ((guint32)f_code[1][0] <<  4) |
569             (         f_code[1][1]      ));
570 }
571
572 static gboolean
573 fill_picture(GstVaapiDecoderMpeg2 *decoder, GstVaapiPicture *picture)
574 {
575     GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
576     VAPictureParameterBufferMPEG2 * const pic_param = picture->param;
577     GstMpegVideoPictureHdr * const pic_hdr = &priv->pic_hdr;
578     GstMpegVideoPictureExt * const pic_ext = &priv->pic_ext;
579
580     if (!priv->has_pic_ext)
581         return FALSE;
582
583     /* Fill in VAPictureParameterBufferMPEG2 */
584     pic_param->horizontal_size                                          = priv->width;
585     pic_param->vertical_size                                            = priv->height;
586     pic_param->forward_reference_picture                                = VA_INVALID_ID;
587     pic_param->backward_reference_picture                               = VA_INVALID_ID;
588     pic_param->picture_coding_type                                      = pic_hdr->pic_type;
589     pic_param->f_code                                                   = pack_f_code(pic_ext->f_code);
590
591 #define COPY_FIELD(a, b, f) \
592     pic_param->a.b.f = pic_ext->f
593     pic_param->picture_coding_extension.value                           = 0;
594     pic_param->picture_coding_extension.bits.is_first_field             = priv->is_first_field;
595     COPY_FIELD(picture_coding_extension, bits, intra_dc_precision);
596     COPY_FIELD(picture_coding_extension, bits, picture_structure);
597     COPY_FIELD(picture_coding_extension, bits, top_field_first);
598     COPY_FIELD(picture_coding_extension, bits, frame_pred_frame_dct);
599     COPY_FIELD(picture_coding_extension, bits, concealment_motion_vectors);
600     COPY_FIELD(picture_coding_extension, bits, q_scale_type);
601     COPY_FIELD(picture_coding_extension, bits, intra_vlc_format);
602     COPY_FIELD(picture_coding_extension, bits, alternate_scan);
603     COPY_FIELD(picture_coding_extension, bits, repeat_first_field);
604     COPY_FIELD(picture_coding_extension, bits, progressive_frame);
605
606     switch (pic_hdr->pic_type) {
607     case GST_MPEG_VIDEO_PICTURE_TYPE_B:
608         if (priv->next_picture)
609             pic_param->backward_reference_picture = priv->next_picture->surface_id;
610         // fall-through
611     case GST_MPEG_VIDEO_PICTURE_TYPE_P:
612         if (priv->prev_picture)
613             pic_param->forward_reference_picture = priv->prev_picture->surface_id;
614         break;
615     }
616     return TRUE;
617 }
618
619 static GstVaapiDecoderStatus
620 decode_slice(
621     GstVaapiDecoderMpeg2 *decoder,
622     int                   slice_no,
623     guchar               *buf,
624     guint                 buf_size
625 )
626 {
627     GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
628     GstVaapiPicture * const picture = priv->current_picture;
629     GstVaapiSlice *slice;
630     VASliceParameterBufferMPEG2 *slice_param;
631     GstVaapiDecoderStatus status;
632     GstBitReader br;
633     guint8 slice_vertical_position_extension;
634     guint8 quantiser_scale_code;
635     guint8 intra_slice_flag, intra_slice = 0;
636     guint8 extra_bit_slice, junk8;
637
638     GST_DEBUG("slice %d @ %p, %u bytes)", slice_no, buf, buf_size);
639
640     if (picture->slices->len == 0 && !fill_picture(decoder, picture))
641         return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
642
643     priv->mb_y = slice_no;
644
645     slice = gst_vaapi_decoder_new_slice(
646         GST_VAAPI_DECODER(decoder),
647         picture,
648         buf, buf_size
649     );
650     if (!slice) {
651         GST_DEBUG("failed to allocate slice");
652         return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
653     }
654
655     /* Parse slice */
656     gst_bit_reader_init(&br, buf, buf_size);
657     if (priv->height > 2800)
658         READ_UINT8(&br, slice_vertical_position_extension, 3);
659     if (priv->has_seq_scalable_ext) {
660         GST_DEBUG("failed to parse slice %d. Unsupported sequence_scalable_extension()", slice_no);
661         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
662     }
663     READ_UINT8(&br, quantiser_scale_code, 5);
664     READ_UINT8(&br, extra_bit_slice, 1);
665     if (extra_bit_slice == 1) {
666         READ_UINT8(&br, intra_slice_flag, 1);
667         if (intra_slice_flag) {
668             READ_UINT8(&br, intra_slice, 1);
669             READ_UINT8(&br, junk8, 7);
670         }
671         READ_UINT8(&br, extra_bit_slice, 1);
672         while (extra_bit_slice == 1) {
673             READ_UINT8(&br, junk8, 8);
674             READ_UINT8(&br, extra_bit_slice, 1);
675         }
676     }
677
678     /* Fill in VASliceParameterBufferMPEG2 */
679     slice_param                            = slice->param;
680     slice_param->macroblock_offset         = gst_bit_reader_get_pos(&br);
681     slice_param->slice_horizontal_position = 0;
682     slice_param->slice_vertical_position   = priv->mb_y;
683     slice_param->quantiser_scale_code      = quantiser_scale_code;
684     slice_param->intra_slice_flag          = intra_slice;
685
686     /* Commit picture for decoding if we reached the last slice */
687     if (++priv->mb_y >= priv->mb_height) {
688         status = decode_current_picture(decoder);
689         if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
690             return status;
691         GST_DEBUG("done");
692     }
693     return GST_VAAPI_DECODER_STATUS_SUCCESS;
694
695 failed:
696     return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
697 }
698
699 static GstVaapiDecoderStatus
700 decode_chunks(GstVaapiDecoderMpeg2 *decoder, GstBuffer *buffer, GList *chunks)
701 {
702     GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
703     GstMpegVideoTypeOffsetSize *tos;
704     GstVaapiDecoderStatus status;
705     guchar * const buf = GST_BUFFER_DATA(buffer);
706     const guint buf_size = GST_BUFFER_SIZE(buffer);
707     guchar *data;
708     guint data_size, ofs, pos = 0;
709     GList *l;
710
711     status = GST_VAAPI_DECODER_STATUS_SUCCESS;
712     for (l = chunks; l; l = g_list_next(l)) {
713         tos       = l->data;
714         data      = buf + tos->offset;
715         data_size = tos->size;
716         if (tos->size < 0)
717             break;
718
719         ofs = tos->offset - pos + tos->size;
720         if (gst_adapter_available(priv->adapter) >= ofs)
721             gst_adapter_flush(priv->adapter, ofs);
722         pos += ofs;
723
724         switch (tos->type) {
725         case GST_MPEG_VIDEO_PACKET_PICTURE:
726             status = decode_picture(decoder, data, data_size);
727             break;
728         case GST_MPEG_VIDEO_PACKET_SEQUENCE:
729             status = decode_sequence(decoder, data, data_size);
730             break;
731         case GST_MPEG_VIDEO_PACKET_EXTENSION: {
732             const guchar id = data[0] >> 4;
733             switch (id) {
734             case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE:
735                 status = decode_sequence_ext(decoder, data, data_size);
736                 break;
737             case GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX:
738                 status = decode_quant_matrix_ext(decoder, data, data_size);
739                 break;
740             case GST_MPEG_VIDEO_PACKET_EXT_PICTURE:
741                 status = decode_picture_ext(decoder, data, data_size);
742                 break;
743             default:
744                 // Ignore unknown extensions
745                 GST_DEBUG("unsupported start-code extension (0x%02x)", id);
746                 break;
747             }
748             break;
749         }
750         case GST_MPEG_VIDEO_PACKET_SEQUENCE_END:
751             status = decode_sequence_end(decoder);
752             break;
753         case GST_MPEG_VIDEO_PACKET_GOP:
754             status = decode_gop(decoder, data, data_size);
755             break;
756         case GST_MPEG_VIDEO_PACKET_USER_DATA:
757             // Ignore user-data packets
758             status = GST_VAAPI_DECODER_STATUS_SUCCESS;
759             break;
760         default:
761             if (tos->type >= GST_MPEG_VIDEO_PACKET_SLICE_MIN &&
762                 tos->type <= GST_MPEG_VIDEO_PACKET_SLICE_MAX) {
763                 status = decode_slice(
764                     decoder,
765                     tos->type - GST_MPEG_VIDEO_PACKET_SLICE_MIN,
766                     data, data_size
767                 );
768                 break;
769             }
770             else if (tos->type >= 0xb9 && tos->type <= 0xff) {
771                 // Ignore system start codes (PES headers)
772                 status = GST_VAAPI_DECODER_STATUS_SUCCESS;
773                 break;
774             }
775             GST_DEBUG("unsupported start code (0x%02x)", tos->type);
776             status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
777             break;
778         }
779         if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
780             break;
781     }
782
783     if (status == GST_VAAPI_DECODER_STATUS_SUCCESS && pos < buf_size)
784         priv->sub_buffer = gst_buffer_create_sub(buffer, pos, buf_size - pos);
785     return status;
786 }
787
788 static GstVaapiDecoderStatus
789 decode_buffer(GstVaapiDecoderMpeg2 *decoder, GstBuffer *buffer)
790 {
791     GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
792     GstVaapiDecoderStatus status;
793     guchar *buf;
794     guint buf_size;
795     GList *chunks;
796
797     buf      = GST_BUFFER_DATA(buffer);
798     buf_size = GST_BUFFER_SIZE(buffer);
799     if (!buf && buf_size == 0)
800         return decode_sequence_end(decoder);
801
802     gst_buffer_ref(buffer);
803     gst_adapter_push(priv->adapter, buffer);
804     if (priv->sub_buffer) {
805         buffer = gst_buffer_merge(priv->sub_buffer, buffer);
806         if (!buffer)
807             return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
808         gst_buffer_unref(priv->sub_buffer);
809         priv->sub_buffer = NULL;
810     }
811
812     buf      = GST_BUFFER_DATA(buffer);
813     buf_size = GST_BUFFER_SIZE(buffer);
814     chunks   = gst_mpeg_video_parse(buf, buf_size, 0);
815     if (!chunks)
816         return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
817
818     status = decode_chunks(decoder, buffer, chunks);
819     g_list_free_full(chunks, (GDestroyNotify)g_free);
820     return status;
821 }
822
823 GstVaapiDecoderStatus
824 gst_vaapi_decoder_mpeg2_decode(GstVaapiDecoder *base, GstBuffer *buffer)
825 {
826     GstVaapiDecoderMpeg2 * const decoder = GST_VAAPI_DECODER_MPEG2(base);
827     GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
828
829     g_return_val_if_fail(priv->is_constructed,
830                          GST_VAAPI_DECODER_STATUS_ERROR_INIT_FAILED);
831
832     if (!priv->is_opened) {
833         priv->is_opened = gst_vaapi_decoder_mpeg2_open(decoder, buffer);
834         if (!priv->is_opened)
835             return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC;
836     }
837     return decode_buffer(decoder, buffer);
838 }
839
840 static void
841 gst_vaapi_decoder_mpeg2_finalize(GObject *object)
842 {
843     GstVaapiDecoderMpeg2 * const decoder = GST_VAAPI_DECODER_MPEG2(object);
844
845     gst_vaapi_decoder_mpeg2_destroy(decoder);
846
847     G_OBJECT_CLASS(gst_vaapi_decoder_mpeg2_parent_class)->finalize(object);
848 }
849
850 static void
851 gst_vaapi_decoder_mpeg2_constructed(GObject *object)
852 {
853     GstVaapiDecoderMpeg2 * const decoder = GST_VAAPI_DECODER_MPEG2(object);
854     GstVaapiDecoderMpeg2Private * const priv = decoder->priv;
855     GObjectClass *parent_class;
856
857     parent_class = G_OBJECT_CLASS(gst_vaapi_decoder_mpeg2_parent_class);
858     if (parent_class->constructed)
859         parent_class->constructed(object);
860
861     priv->is_constructed = gst_vaapi_decoder_mpeg2_create(decoder);
862 }
863
864 static void
865 gst_vaapi_decoder_mpeg2_class_init(GstVaapiDecoderMpeg2Class *klass)
866 {
867     GObjectClass * const object_class = G_OBJECT_CLASS(klass);
868     GstVaapiDecoderClass * const decoder_class = GST_VAAPI_DECODER_CLASS(klass);
869
870     g_type_class_add_private(klass, sizeof(GstVaapiDecoderMpeg2Private));
871
872     object_class->finalize      = gst_vaapi_decoder_mpeg2_finalize;
873     object_class->constructed   = gst_vaapi_decoder_mpeg2_constructed;
874
875     decoder_class->decode       = gst_vaapi_decoder_mpeg2_decode;
876 }
877
878 static void
879 gst_vaapi_decoder_mpeg2_init(GstVaapiDecoderMpeg2 *decoder)
880 {
881     GstVaapiDecoderMpeg2Private *priv;
882
883     priv                        = GST_VAAPI_DECODER_MPEG2_GET_PRIVATE(decoder);
884     decoder->priv               = priv;
885     priv->width                 = 0;
886     priv->height                = 0;
887     priv->fps_n                 = 0;
888     priv->fps_d                 = 0;
889     priv->profile               = GST_VAAPI_PROFILE_MPEG2_SIMPLE;
890     priv->current_picture       = NULL;
891     priv->next_picture          = NULL;
892     priv->prev_picture          = NULL;
893     priv->adapter               = NULL;
894     priv->sub_buffer            = NULL;
895     priv->mb_y                  = 0;
896     priv->mb_height             = 0;
897     priv->seq_pts               = GST_CLOCK_TIME_NONE;
898     priv->gop_pts               = GST_CLOCK_TIME_NONE;
899     priv->pts_diff              = 0;
900     priv->is_constructed        = FALSE;
901     priv->is_opened             = FALSE;
902     priv->is_first_field        = FALSE;
903     priv->has_seq_ext           = FALSE;
904     priv->has_seq_scalable_ext  = FALSE;
905     priv->has_pic_ext           = FALSE;
906     priv->has_quant_matrix_ext  = FALSE;
907     priv->size_changed          = FALSE;
908     priv->profile_changed       = FALSE;
909     priv->quant_matrix_changed  = FALSE;
910     priv->progressive_sequence  = FALSE;
911     priv->closed_gop            = FALSE;
912     priv->broken_link           = FALSE;
913 }
914
915 /**
916  * gst_vaapi_decoder_mpeg2_new:
917  * @display: a #GstVaapiDisplay
918  * @caps: a #GstCaps holding codec information
919  *
920  * Creates a new #GstVaapiDecoder for MPEG-2 decoding.  The @caps can
921  * hold extra information like codec-data and pictured coded size.
922  *
923  * Return value: the newly allocated #GstVaapiDecoder object
924  */
925 GstVaapiDecoder *
926 gst_vaapi_decoder_mpeg2_new(GstVaapiDisplay *display, GstCaps *caps)
927 {
928     GstVaapiDecoderMpeg2 *decoder;
929
930     static const GstVaapiCodecInfo codec_info = {
931         .pic_size               = sizeof(GstVaapiPicture),
932         .slice_size             = sizeof(GstVaapiSlice),
933         .pic_param_size         = sizeof(VAPictureParameterBufferMPEG2),
934         .slice_param_size       = sizeof(VASliceParameterBufferMPEG2),
935         .iq_matrix_size         = sizeof(VAIQMatrixBufferMPEG2),
936     };
937
938     g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
939     g_return_val_if_fail(GST_IS_CAPS(caps), NULL);
940
941     decoder = g_object_new(
942         GST_VAAPI_TYPE_DECODER_MPEG2,
943         "display",      display,
944         "caps",         caps,
945         "codec-info",   &codec_info,
946         NULL
947     );
948     if (!decoder->priv->is_constructed) {
949         g_object_unref(decoder);
950         return NULL;
951     }
952     return GST_VAAPI_DECODER_CAST(decoder);
953 }