1 /* GStreamer
2  * Copyright (C) <2007> Jan Schmidt <thaytan@mad.scientist.com>
3  * Copyright (C) <2011> Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
4  * Copyright (C) <2011> Thibault Saunier <thibault.saunier@collabora.com>
5  * Copyright (C) <2011> Collabora ltd
6  * Copyright (C) <2011> Nokia Corporation
7  * Copyright (C) <2011> Intel Corporation
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  */
24 
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28 
29 #include <string.h>
30 #include <gst/base/base.h>
31 #include <gst/pbutils/pbutils.h>
32 #include <gst/codecparsers/gstmpegvideometa.h>
33 
34 #include "gstmpegvideoparse.h"
35 
36 GST_DEBUG_CATEGORY (mpegv_parse_debug);
37 #define GST_CAT_DEFAULT mpegv_parse_debug
38 
39 static GstStaticPadTemplate src_template =
40 GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC,
41     GST_PAD_ALWAYS,
42     GST_STATIC_CAPS ("video/mpeg, "
43         "mpegversion = (int) [1, 2], "
44         "parsed = (boolean) true, " "systemstream = (boolean) false")
45     );
46 
47 static GstStaticPadTemplate sink_template =
48 GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK,
49     GST_PAD_ALWAYS,
50     GST_STATIC_CAPS ("video/mpeg, "
51         "mpegversion = (int) [1, 2], " "systemstream = (boolean) false")
52     );
53 
54 /* Properties */
55 #define DEFAULT_PROP_DROP       TRUE
56 #define DEFAULT_PROP_GOP_SPLIT  FALSE
57 
58 enum
59 {
60   PROP_0,
61   PROP_DROP,
62   PROP_GOP_SPLIT
63 };
64 
65 #define parent_class gst_mpegv_parse_parent_class
66 G_DEFINE_TYPE (GstMpegvParse, gst_mpegv_parse, GST_TYPE_BASE_PARSE);
67 
68 static gboolean gst_mpegv_parse_start (GstBaseParse * parse);
69 static gboolean gst_mpegv_parse_stop (GstBaseParse * parse);
70 static GstFlowReturn gst_mpegv_parse_handle_frame (GstBaseParse * parse,
71     GstBaseParseFrame * frame, gint * skipsize);
72 static GstFlowReturn gst_mpegv_parse_parse_frame (GstBaseParse * parse,
73     GstBaseParseFrame * frame);
74 static gboolean gst_mpegv_parse_set_caps (GstBaseParse * parse, GstCaps * caps);
75 static GstCaps *gst_mpegv_parse_get_caps (GstBaseParse * parse,
76     GstCaps * filter);
77 static GstFlowReturn gst_mpegv_parse_pre_push_frame (GstBaseParse * parse,
78     GstBaseParseFrame * frame);
79 static gboolean gst_mpegv_parse_sink_query (GstBaseParse * parse,
80     GstQuery * query);
81 
82 static void gst_mpegv_parse_set_property (GObject * object, guint prop_id,
83     const GValue * value, GParamSpec * pspec);
84 static void gst_mpegv_parse_get_property (GObject * object, guint prop_id,
85     GValue * value, GParamSpec * pspec);
86 
87 static void
gst_mpegv_parse_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)88 gst_mpegv_parse_set_property (GObject * object, guint property_id,
89     const GValue * value, GParamSpec * pspec)
90 {
91   GstMpegvParse *parse = GST_MPEGVIDEO_PARSE (object);
92 
93   switch (property_id) {
94     case PROP_DROP:
95       parse->drop = g_value_get_boolean (value);
96       break;
97     case PROP_GOP_SPLIT:
98       parse->gop_split = g_value_get_boolean (value);
99       break;
100     default:
101       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
102   }
103 }
104 
105 static void
gst_mpegv_parse_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)106 gst_mpegv_parse_get_property (GObject * object, guint property_id,
107     GValue * value, GParamSpec * pspec)
108 {
109   GstMpegvParse *parse = GST_MPEGVIDEO_PARSE (object);
110 
111   switch (property_id) {
112     case PROP_DROP:
113       g_value_set_boolean (value, parse->drop);
114       break;
115     case PROP_GOP_SPLIT:
116       g_value_set_boolean (value, parse->gop_split);
117       break;
118     default:
119       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
120   }
121 }
122 
123 static void
gst_mpegv_parse_class_init(GstMpegvParseClass * klass)124 gst_mpegv_parse_class_init (GstMpegvParseClass * klass)
125 {
126   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
127   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
128   GstBaseParseClass *parse_class = GST_BASE_PARSE_CLASS (klass);
129 
130   GST_DEBUG_CATEGORY_INIT (mpegv_parse_debug, "mpegvideoparse", 0,
131       "MPEG-1/2 video parser");
132 
133   parent_class = g_type_class_peek_parent (klass);
134 
135   gobject_class->set_property = gst_mpegv_parse_set_property;
136   gobject_class->get_property = gst_mpegv_parse_get_property;
137 
138   g_object_class_install_property (gobject_class, PROP_DROP,
139       g_param_spec_boolean ("drop", "drop",
140           "Drop data untill valid configuration data is received either "
141           "in the stream or through caps", DEFAULT_PROP_DROP,
142           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
143 
144   g_object_class_install_property (gobject_class, PROP_GOP_SPLIT,
145       g_param_spec_boolean ("gop-split", "gop-split",
146           "Split frame when encountering GOP", DEFAULT_PROP_GOP_SPLIT,
147           G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
148 
149   gst_element_class_add_static_pad_template (element_class, &src_template);
150   gst_element_class_add_static_pad_template (element_class, &sink_template);
151 
152   gst_element_class_set_static_metadata (element_class,
153       "MPEG video elementary stream parser",
154       "Codec/Parser/Video",
155       "Parses and frames MPEG-1 and MPEG-2 elementary video streams",
156       "Wim Taymans <wim.taymans@ccollabora.co.uk>, "
157       "Jan Schmidt <thaytan@mad.scientist.com>, "
158       "Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>");
159 
160   /* Override BaseParse vfuncs */
161   parse_class->start = GST_DEBUG_FUNCPTR (gst_mpegv_parse_start);
162   parse_class->stop = GST_DEBUG_FUNCPTR (gst_mpegv_parse_stop);
163   parse_class->handle_frame = GST_DEBUG_FUNCPTR (gst_mpegv_parse_handle_frame);
164   parse_class->set_sink_caps = GST_DEBUG_FUNCPTR (gst_mpegv_parse_set_caps);
165   parse_class->get_sink_caps = GST_DEBUG_FUNCPTR (gst_mpegv_parse_get_caps);
166   parse_class->pre_push_frame =
167       GST_DEBUG_FUNCPTR (gst_mpegv_parse_pre_push_frame);
168   parse_class->sink_query = GST_DEBUG_FUNCPTR (gst_mpegv_parse_sink_query);
169 }
170 
171 static void
gst_mpegv_parse_init(GstMpegvParse * parse)172 gst_mpegv_parse_init (GstMpegvParse * parse)
173 {
174   parse->config_flags = FLAG_NONE;
175 
176   gst_base_parse_set_pts_interpolation (GST_BASE_PARSE (parse), FALSE);
177   GST_PAD_SET_ACCEPT_INTERSECT (GST_BASE_PARSE_SINK_PAD (parse));
178   GST_PAD_SET_ACCEPT_TEMPLATE (GST_BASE_PARSE_SINK_PAD (parse));
179 }
180 
181 static void
gst_mpegv_parse_reset_frame(GstMpegvParse * mpvparse)182 gst_mpegv_parse_reset_frame (GstMpegvParse * mpvparse)
183 {
184   /* done parsing; reset state */
185   mpvparse->last_sc = -1;
186   mpvparse->seq_size = 0;
187   mpvparse->seq_offset = -1;
188   mpvparse->pic_offset = -1;
189   mpvparse->frame_repeat_count = 0;
190   memset (mpvparse->ext_offsets, 0, sizeof (mpvparse->ext_offsets));
191   mpvparse->ext_count = 0;
192   mpvparse->slice_count = 0;
193   mpvparse->slice_offset = 0;
194 }
195 
196 static void
gst_mpegv_parse_reset(GstMpegvParse * mpvparse)197 gst_mpegv_parse_reset (GstMpegvParse * mpvparse)
198 {
199   gst_mpegv_parse_reset_frame (mpvparse);
200   mpvparse->profile = 0;
201   mpvparse->update_caps = TRUE;
202   mpvparse->send_codec_tag = TRUE;
203   mpvparse->send_mpeg_meta = TRUE;
204 
205   gst_buffer_replace (&mpvparse->config, NULL);
206   memset (&mpvparse->sequencehdr, 0, sizeof (mpvparse->sequencehdr));
207   memset (&mpvparse->sequenceext, 0, sizeof (mpvparse->sequenceext));
208   memset (&mpvparse->sequencedispext, 0, sizeof (mpvparse->sequencedispext));
209   memset (&mpvparse->pichdr, 0, sizeof (mpvparse->pichdr));
210   memset (&mpvparse->picext, 0, sizeof (mpvparse->picext));
211 
212   mpvparse->seqhdr_updated = FALSE;
213   mpvparse->seqext_updated = FALSE;
214   mpvparse->seqdispext_updated = FALSE;
215   mpvparse->picext_updated = FALSE;
216   mpvparse->quantmatrext_updated = FALSE;
217 }
218 
219 static gboolean
gst_mpegv_parse_sink_query(GstBaseParse * parse,GstQuery * query)220 gst_mpegv_parse_sink_query (GstBaseParse * parse, GstQuery * query)
221 {
222   gboolean res;
223   GstMpegvParse *mpvparse = GST_MPEGVIDEO_PARSE (parse);
224 
225   res = GST_BASE_PARSE_CLASS (parent_class)->sink_query (parse, query);
226 
227   if (res && GST_QUERY_TYPE (query) == GST_QUERY_ALLOCATION) {
228     mpvparse->send_mpeg_meta =
229         gst_query_find_allocation_meta (query, GST_MPEG_VIDEO_META_API_TYPE,
230         NULL);
231 
232     GST_DEBUG_OBJECT (parse, "Downstream can handle GstMpegVideo GstMeta : %d",
233         mpvparse->send_mpeg_meta);
234   }
235 
236   return res;
237 }
238 
239 static gboolean
gst_mpegv_parse_start(GstBaseParse * parse)240 gst_mpegv_parse_start (GstBaseParse * parse)
241 {
242   GstMpegvParse *mpvparse = GST_MPEGVIDEO_PARSE (parse);
243 
244   GST_DEBUG_OBJECT (parse, "start");
245 
246   gst_mpegv_parse_reset (mpvparse);
247   /* at least this much for a valid frame */
248   gst_base_parse_set_min_frame_size (parse, 6);
249 
250   return TRUE;
251 }
252 
253 static gboolean
gst_mpegv_parse_stop(GstBaseParse * parse)254 gst_mpegv_parse_stop (GstBaseParse * parse)
255 {
256   GstMpegvParse *mpvparse = GST_MPEGVIDEO_PARSE (parse);
257 
258   GST_DEBUG_OBJECT (parse, "stop");
259 
260   gst_mpegv_parse_reset (mpvparse);
261 
262   return TRUE;
263 }
264 
265 static gboolean
gst_mpegv_parse_process_config(GstMpegvParse * mpvparse,GstMapInfo * info,guint size)266 gst_mpegv_parse_process_config (GstMpegvParse * mpvparse, GstMapInfo * info,
267     guint size)
268 {
269   GstMpegVideoPacket packet;
270   guint8 *data_with_prefix;
271   gint i;
272 
273   if (mpvparse->seq_offset < 4) {
274     /* This shouldn't happen, but just in case... */
275     GST_WARNING_OBJECT (mpvparse, "Sequence header start code missing.");
276     return FALSE;
277   }
278 
279   packet.data = info->data;
280   packet.type = GST_MPEG_VIDEO_PACKET_SEQUENCE;
281   packet.offset = mpvparse->seq_offset;
282   packet.size = size - mpvparse->seq_offset;
283   /* pointer to sequence header data including the start code prefix -
284      used for codec private data */
285   data_with_prefix = (guint8 *) packet.data + packet.offset - 4;
286 
287   /* only do stuff if something new; only compare first 8 bytes, changes in
288      quantiser matrix or bitrate don't matter here. Also changing the
289      matrices in codec_data seems to cause problem with decoders */
290   if (mpvparse->config &&
291       gst_buffer_memcmp (mpvparse->config, 0, data_with_prefix, MIN (size,
292               8)) == 0) {
293     return TRUE;
294   }
295 
296   if (!gst_mpeg_video_packet_parse_sequence_header (&packet,
297           &mpvparse->sequencehdr)) {
298     GST_DEBUG_OBJECT (mpvparse,
299         "failed to parse config data (size %d) at offset %d",
300         size, mpvparse->seq_offset);
301     return FALSE;
302   }
303 
304   mpvparse->seqhdr_updated = TRUE;
305 
306   GST_LOG_OBJECT (mpvparse, "accepting parsed config size %d", size);
307 
308   /* Set mpeg version, and parse sequence extension */
309   mpvparse->config_flags = FLAG_NONE;
310   for (i = 0; i < mpvparse->ext_count; ++i) {
311     packet.type = GST_MPEG_VIDEO_PACKET_EXTENSION;
312     packet.offset = mpvparse->ext_offsets[i];
313     packet.size = (gint) size - mpvparse->ext_offsets[i];
314     mpvparse->config_flags |= FLAG_MPEG2;
315     if (packet.size > 1) {
316       switch (packet.data[packet.offset] >> 4) {
317         case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE:
318           if (gst_mpeg_video_packet_parse_sequence_extension (&packet,
319                   &mpvparse->sequenceext)) {
320             GST_LOG_OBJECT (mpvparse, "Read Sequence Extension");
321             mpvparse->config_flags |= FLAG_SEQUENCE_EXT;
322             mpvparse->seqext_updated = TRUE;
323           }
324           break;
325         case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_DISPLAY:
326           if (gst_mpeg_video_packet_parse_sequence_display_extension (&packet,
327                   &mpvparse->sequencedispext)) {
328             GST_LOG_OBJECT (mpvparse, "Read Sequence Display Extension");
329             mpvparse->config_flags |= FLAG_SEQUENCE_DISPLAY_EXT;
330             mpvparse->seqdispext_updated = TRUE;
331           }
332           break;
333         case GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX:
334           if (gst_mpeg_video_packet_parse_quant_matrix_extension (&packet,
335                   &mpvparse->quantmatrext)) {
336             GST_LOG_OBJECT (mpvparse, "Read Quantization Matrix Extension");
337             mpvparse->quantmatrext_updated = TRUE;
338           }
339           break;
340       }
341     }
342   }
343   if (mpvparse->config_flags & FLAG_MPEG2) {
344     /* Update the sequence header based on extensions */
345     GstMpegVideoSequenceExt *seqext = NULL;
346     GstMpegVideoSequenceDisplayExt *seqdispext = NULL;
347 
348     if (mpvparse->config_flags & FLAG_SEQUENCE_EXT)
349       seqext = &mpvparse->sequenceext;
350     if (mpvparse->config_flags & FLAG_SEQUENCE_DISPLAY_EXT)
351       seqdispext = &mpvparse->sequencedispext;
352 
353     gst_mpeg_video_finalise_mpeg2_sequence_header (&mpvparse->sequencehdr,
354         seqext, seqdispext);
355   }
356 
357   if (mpvparse->fps_num == 0 || mpvparse->fps_den == 0) {
358     mpvparse->fps_num = mpvparse->sequencehdr.fps_n;
359     mpvparse->fps_den = mpvparse->sequencehdr.fps_d;
360   }
361 
362   /* parsing ok, so accept it as new config */
363   if (mpvparse->config != NULL)
364     gst_buffer_unref (mpvparse->config);
365 
366   mpvparse->config = gst_buffer_new_and_alloc (size);
367   gst_buffer_fill (mpvparse->config, 0, data_with_prefix, size);
368 
369   /* trigger src caps update */
370   mpvparse->update_caps = TRUE;
371 
372   return TRUE;
373 }
374 
375 /* FIXME : Move these functions to libgstcodecparser for usage by
376  * more elements/code */
377 #ifndef GST_DISABLE_GST_DEBUG
378 static const gchar *
picture_start_code_name(guint8 psc)379 picture_start_code_name (guint8 psc)
380 {
381   guint i;
382   const struct
383   {
384     guint8 psc;
385     const gchar *name;
386   } psc_names[] = {
387     {
388     0x00, "Picture Start"}, {
389     0xb0, "Reserved"}, {
390     0xb1, "Reserved"}, {
391     0xb2, "User Data Start"}, {
392     0xb3, "Sequence Header Start"}, {
393     0xb4, "Sequence Error"}, {
394     0xb5, "Extension Start"}, {
395     0xb6, "Reserved"}, {
396     0xb7, "Sequence End"}, {
397     0xb8, "Group Start"}, {
398     0xb9, "Program End"}
399   };
400   if (psc < 0xB0 && psc > 0)
401     return "Slice Start";
402 
403   for (i = 0; i < G_N_ELEMENTS (psc_names); i++)
404     if (psc_names[i].psc == psc)
405       return psc_names[i].name;
406 
407   return "UNKNOWN";
408 };
409 
410 static const gchar *
picture_type_name(guint8 pct)411 picture_type_name (guint8 pct)
412 {
413   guint i;
414   const struct
415   {
416     guint8 pct;
417     const gchar *name;
418   } pct_names[] = {
419     {
420     0, "Forbidden"}, {
421     1, "I Frame"}, {
422     2, "P Frame"}, {
423     3, "B Frame"}, {
424     4, "DC Intra Coded (Shall Not Be Used!)"}
425   };
426 
427   for (i = 0; i < G_N_ELEMENTS (pct_names); i++)
428     if (pct_names[i].pct == pct)
429       return pct_names[i].name;
430 
431   return "Reserved/Unknown";
432 }
433 #endif /* GST_DISABLE_GST_DEBUG */
434 
435 static void
parse_packet_extension(GstMpegvParse * mpvparse,GstMapInfo * info,guint off)436 parse_packet_extension (GstMpegvParse * mpvparse, GstMapInfo * info, guint off)
437 {
438   GstMpegVideoPacket packet;
439 
440   packet.data = info->data;
441   packet.type = GST_MPEG_VIDEO_PACKET_EXTENSION;
442   packet.offset = off;
443   packet.size = info->size - off;
444 
445   /* FIXME : WE ARE ASSUMING IT IS A *PICTURE* EXTENSION */
446   if (gst_mpeg_video_packet_parse_picture_extension (&packet,
447           &mpvparse->picext)) {
448     mpvparse->frame_repeat_count = 1;
449 
450     if (mpvparse->picext.repeat_first_field) {
451       if (mpvparse->sequenceext.progressive) {
452         if (mpvparse->picext.top_field_first)
453           mpvparse->frame_repeat_count = 5;
454         else
455           mpvparse->frame_repeat_count = 3;
456       } else if (mpvparse->picext.progressive_frame) {
457         mpvparse->frame_repeat_count = 2;
458       }
459     }
460     mpvparse->picext_updated = TRUE;
461   }
462 }
463 
464 /* A53-4 Table 6.7 */
465 #define A53_USER_DATA_ID_GA94 0x47413934
466 #define A53_USER_DATA_ID_DTG1 0x44544731
467 
468 /* A53-4 Table 6.9 */
469 #define A53_USER_DATA_TYPE_CODE_MPEG_CC_DATA 0x03
470 #define A53_USER_DATA_TYPE_CODE_BAR_DATA 0x06
471 
472 /* CEA-708 Table 2 */
473 #define CEA_708_PROCESS_CC_DATA_FLAG 0x40
474 #define CEA_708_PROCESS_EM_DATA_FLAG 0x80
475 
476 static void
parse_user_data_packet(GstMpegvParse * mpvparse,const guint8 * data,guint size)477 parse_user_data_packet (GstMpegvParse * mpvparse, const guint8 * data,
478     guint size)
479 {
480   gboolean a53_user_data_ga94 = FALSE;
481   gboolean a53_user_data_dtg1 = FALSE;
482   gboolean a53_user_data_mpeg_cc = FALSE;
483   gboolean a53_process_708_cc_data = FALSE;
484   gboolean process_708_em_data = FALSE;
485 
486   if (size < 2) {
487     GST_DEBUG_OBJECT (mpvparse, "user data packet too short, ignoring");
488     return;
489   }
490 
491   /* A53 part 4 closed captions */
492   if (size > 6) {
493     guint32 user_data_id = GST_READ_UINT32_BE (data);
494     a53_user_data_ga94 = user_data_id == A53_USER_DATA_ID_GA94;
495     a53_user_data_dtg1 = user_data_id == A53_USER_DATA_ID_DTG1;
496     a53_user_data_mpeg_cc = data[4] == A53_USER_DATA_TYPE_CODE_MPEG_CC_DATA;
497     a53_process_708_cc_data = (data[5] & CEA_708_PROCESS_CC_DATA_FLAG) != 0;
498     process_708_em_data = (data[5] & CEA_708_PROCESS_EM_DATA_FLAG) != 0;
499 
500     if (a53_user_data_dtg1) {
501       GST_DEBUG_OBJECT (mpvparse,
502           "ignoring closed captions as DTG1 is not supported");
503     } else if (a53_user_data_ga94) {
504       GST_DEBUG_OBJECT (mpvparse, "GA94 closed captions");
505       if (!a53_user_data_mpeg_cc) {
506         GST_DEBUG_OBJECT (mpvparse,
507             "ignoring closed captions as A53_USER_DATA_TYPE_CODE_MPEG_CC_DATA is not set");
508       }
509       if (!a53_process_708_cc_data) {
510         GST_DEBUG_OBJECT (mpvparse,
511             "ignoring closed captions as CEA_708_PROCESS_CC_DATA_FLAG is not set");
512       }
513       if (!process_708_em_data) {
514         GST_DEBUG_OBJECT (mpvparse,
515             "CEA_708_PROCESS_EM_DATA_FLAG flag is not set");
516       }
517       /* ignore em data flag for now as it breaks one of the tests */
518       process_708_em_data = /*process_708_em_data && */ (data[6] == 0xff);
519       if (!process_708_em_data) {
520         GST_DEBUG_OBJECT (mpvparse,
521             "ignoring closed captions as em data does not equal 0xFF");
522       }
523     }
524   }
525   if (size > 6 && a53_user_data_ga94 && a53_user_data_mpeg_cc
526       && a53_process_708_cc_data && process_708_em_data) {
527     guint8 cc_count = data[5] & 0x1f;
528     guint cc_size = cc_count * 3;
529 
530     data += 7;
531     size -= 7;
532 
533     if (cc_size == 0 || cc_size > size) {
534       GST_DEBUG_OBJECT (mpvparse, "ignoring closed captions, not enough data");
535       return;
536     }
537 
538     /* Shouldn't really happen so let's not go out of our way to handle it */
539     if (mpvparse->closedcaptions_size > 0)
540       GST_WARNING_OBJECT (mpvparse, "unused pending closed captions!");
541 
542     g_assert (cc_size <= sizeof (mpvparse->closedcaptions));
543     memcpy (mpvparse->closedcaptions, data, cc_size);
544     mpvparse->closedcaptions_size = cc_size;
545     mpvparse->closedcaptions_type = GST_VIDEO_CAPTION_TYPE_CEA708_RAW;
546     GST_DEBUG_OBJECT (mpvparse, "CEA-708 closed captions, %u bytes", cc_size);
547     return;
548   }
549 
550   GST_MEMDUMP_OBJECT (mpvparse, "unhandled user data packet", data, size);
551 }
552 
553 /* caller guarantees at least start code in @buf at @off ( - 4)*/
554 /* for off == 4 initial code; returns TRUE if code starts a frame
555  * otherwise returns TRUE if code terminates preceding frame */
556 static gboolean
gst_mpegv_parse_process_sc(GstMpegvParse * mpvparse,GstMapInfo * info,gint off,GstMpegVideoPacket * packet,gboolean * need_more)557 gst_mpegv_parse_process_sc (GstMpegvParse * mpvparse,
558     GstMapInfo * info, gint off, GstMpegVideoPacket * packet,
559     gboolean * need_more)
560 {
561   gboolean ret = FALSE, checkconfig = TRUE;
562 
563   GST_LOG_OBJECT (mpvparse, "process startcode %x (%s) offset:%d", packet->type,
564       picture_start_code_name (packet->type), off);
565 
566   *need_more = FALSE;
567 
568   switch (packet->type) {
569     case GST_MPEG_VIDEO_PACKET_PICTURE:
570       GST_LOG_OBJECT (mpvparse, "startcode is PICTURE");
571       /* picture is aggregated with preceding sequence/gop, if any.
572        * so, picture start code only ends if already a previous one */
573       if (mpvparse->pic_offset < 0)
574         mpvparse->pic_offset = off;
575       else
576         ret = (off != mpvparse->pic_offset);
577       /* but it's a valid starting one */
578       if (off == 4)
579         ret = TRUE;
580       break;
581     case GST_MPEG_VIDEO_PACKET_SEQUENCE:
582       GST_LOG_OBJECT (mpvparse, "startcode is SEQUENCE");
583       if (mpvparse->seq_offset < 0)
584         mpvparse->seq_offset = off;
585       ret = TRUE;
586       break;
587     case GST_MPEG_VIDEO_PACKET_GOP:
588       GST_LOG_OBJECT (mpvparse, "startcode is GOP");
589       if (mpvparse->seq_offset >= 0)
590         ret = mpvparse->gop_split;
591       else
592         ret = TRUE;
593       break;
594     case GST_MPEG_VIDEO_PACKET_EXTENSION:
595       mpvparse->config_flags |= FLAG_MPEG2;
596       GST_LOG_OBJECT (mpvparse, "startcode is VIDEO PACKET EXTENSION");
597       if (mpvparse->pic_offset >= 0) {
598         GST_LOG_OBJECT (mpvparse, "... considered PICTURE EXTENSION");
599         parse_packet_extension (mpvparse, info, off);
600       } else {
601         GST_LOG_OBJECT (mpvparse, "... considered SEQUENCE EXTENSION");
602         if (mpvparse->ext_count < G_N_ELEMENTS (mpvparse->ext_offsets))
603           mpvparse->ext_offsets[mpvparse->ext_count++] = off;
604       }
605       checkconfig = FALSE;
606       break;
607     case GST_MPEG_VIDEO_PACKET_USER_DATA:
608       GST_LOG_OBJECT (mpvparse, "USER_DATA packet of %d bytes", packet->size);
609 
610       if (packet->size < 0) {
611         GST_LOG_OBJECT (mpvparse, "no size yet, need more data");
612         *need_more = TRUE;
613         return FALSE;
614       }
615 
616       parse_user_data_packet (mpvparse, info->data + off, packet->size);
617       checkconfig = FALSE;
618       break;
619     default:
620       if (GST_MPEG_VIDEO_PACKET_IS_SLICE (packet->type)) {
621         mpvparse->slice_count++;
622         if (mpvparse->slice_offset == 0)
623           mpvparse->slice_offset = off - 4;
624       }
625       checkconfig = FALSE;
626       break;
627   }
628 
629   /* set size to avoid processing config again */
630   if (checkconfig && mpvparse->seq_offset >= 0 && off != mpvparse->seq_offset &&
631       !mpvparse->seq_size) {
632     /* should always be at start */
633     g_assert (mpvparse->seq_offset <= 4);
634     gst_mpegv_parse_process_config (mpvparse, info, off - mpvparse->seq_offset);
635     mpvparse->seq_size = off - mpvparse->seq_offset;
636   }
637 
638   /* extract some picture info if there is any in the frame being terminated */
639   if (ret && mpvparse->pic_offset >= 0 && mpvparse->pic_offset < off) {
640     GstMpegVideoPacket header;
641 
642     header.data = info->data;
643     header.type = GST_MPEG_VIDEO_PACKET_PICTURE;
644     header.offset = mpvparse->pic_offset;
645     header.size = info->size - mpvparse->pic_offset;
646     if (gst_mpeg_video_packet_parse_picture_header (&header, &mpvparse->pichdr))
647       GST_LOG_OBJECT (mpvparse, "picture_coding_type %d (%s), ending"
648           "frame of size %d", mpvparse->pichdr.pic_type,
649           picture_type_name (mpvparse->pichdr.pic_type), off - 4);
650     else
651       GST_LOG_OBJECT (mpvparse, "Couldn't parse picture at offset %d",
652           mpvparse->pic_offset);
653 
654     /* if terminating packet is a picture, we need to check if it has same TSN as the picture that is being
655        terminated. If it does, we need to keep those together, as these packets are two fields of the same
656        frame */
657     if (packet->type == GST_MPEG_VIDEO_PACKET_PICTURE
658         && (mpvparse->config_flags & FLAG_SEQUENCE_EXT)
659         && !mpvparse->sequenceext.progressive) {
660       if (info->size - off < 2) {       /* we need at least two bytes to read the TSN */
661         *need_more = TRUE;
662         ret = FALSE;
663       } else {
664         /* TSN is stored in first 10 bits */
665         int tsn = info->data[off] << 2 | (info->data[off + 1] & 0xC0) >> 6;
666 
667         if (tsn == mpvparse->pichdr.tsn)        /* prevent termination if TSN is same */
668           ret = FALSE;
669       }
670     }
671   }
672 
673   return ret;
674 }
675 
676 /* FIXME move into baseparse, or anything equivalent;
677  * see https://bugzilla.gnome.org/show_bug.cgi?id=650093
678  * #define GST_BASE_PARSE_FRAME_FLAG_PARSING   0x100000 */
679 
680 static inline void
update_frame_parsing_status(GstMpegvParse * mpvparse,GstBaseParseFrame * frame)681 update_frame_parsing_status (GstMpegvParse * mpvparse,
682     GstBaseParseFrame * frame)
683 {
684   /* avoid stale cached parsing state */
685   if (frame->flags & GST_BASE_PARSE_FRAME_FLAG_NEW_FRAME) {
686     GST_LOG_OBJECT (mpvparse, "parsing new frame");
687     gst_mpegv_parse_reset_frame (mpvparse);
688   } else {
689     GST_LOG_OBJECT (mpvparse, "resuming frame parsing");
690   }
691 }
692 
693 static GstFlowReturn
gst_mpegv_parse_handle_frame(GstBaseParse * parse,GstBaseParseFrame * frame,gint * skipsize)694 gst_mpegv_parse_handle_frame (GstBaseParse * parse,
695     GstBaseParseFrame * frame, gint * skipsize)
696 {
697   GstFlowReturn flowret = GST_FLOW_OK;
698   GstMpegvParse *mpvparse = GST_MPEGVIDEO_PARSE (parse);
699   GstBuffer *buf = frame->buffer;
700   gboolean ret = FALSE;
701   gint off = 0;
702   GstMpegVideoPacket packet;
703   guint8 *data;
704   gint size;
705   gboolean need_more = FALSE;
706   GstMapInfo map;
707 
708   update_frame_parsing_status (mpvparse, frame);
709 
710   gst_buffer_map (buf, &map, GST_MAP_READ);
711   data = map.data;
712   size = map.size;
713 
714 retry:
715   /* at least start code and subsequent byte */
716   if (G_UNLIKELY (size < 5 + off))
717     goto exit;
718 
719   /* if already found a previous start code, e.g. start of frame, go for next */
720   if (mpvparse->last_sc >= 0) {
721     packet.offset = mpvparse->last_sc;
722     packet.size = 0;
723     goto next;
724   }
725 
726   if (!gst_mpeg_video_parse (&packet, data, size, off)) {
727     /* didn't find anything that looks like a sync word, skip */
728     GST_LOG_OBJECT (mpvparse, "no start code found");
729     *skipsize = size - 3;
730     goto exit;
731   }
732 
733   off = packet.offset - 4;
734   GST_LOG_OBJECT (mpvparse, "possible sync at buffer offset %d", off);
735 
736   /* possible frame header, but not at offset 0? skip bytes before sync */
737   if (G_UNLIKELY (off > 0)) {
738     *skipsize = off;
739     goto exit;
740   }
741 
742   /* note: initial start code is assumed at offset 0 by subsequent code */
743 
744   /* examine start code, see if it looks like an initial start code */
745   if (gst_mpegv_parse_process_sc (mpvparse, &map, 4, &packet, &need_more)) {
746     /* found sc */
747     GST_LOG_OBJECT (mpvparse, "valid start code found");
748     mpvparse->last_sc = 0;
749   } else {
750     off++;
751     gst_mpegv_parse_reset_frame (mpvparse);
752     GST_LOG_OBJECT (mpvparse, "invalid start code");
753     goto retry;
754   }
755 
756 next:
757   /* start is fine as of now */
758   *skipsize = 0;
759   /* terminating start code may have been found in prev scan already */
760   if (((gint) packet.size) >= 0) {
761     off = packet.offset + packet.size;
762     /* so now we have start code at start of data; locate next start code */
763     if (!gst_mpeg_video_parse (&packet, data, size, off)) {
764       off = -1;
765     } else {
766       g_assert (packet.offset >= 4);
767       off = packet.offset - 4;
768     }
769   } else {
770     off = -1;
771   }
772 
773   GST_LOG_OBJECT (mpvparse, "next start code at %d", off);
774   if (off < 0) {
775     off = size - 3;
776     goto need_more;
777   } else {
778     /* decide whether this startcode ends a frame */
779     ret = gst_mpegv_parse_process_sc (mpvparse, &map, off + 4, &packet,
780         &need_more);
781     /* in rare cases, might need to peek past start code */
782     if (need_more) {
783       GST_LOG_OBJECT (mpvparse, "need more data (past start code");
784       ret = FALSE;
785       goto need_more;
786     }
787   }
788 
789   if (!ret)
790     goto next;
791 
792 exit:
793   gst_buffer_unmap (buf, &map);
794 
795   if (ret) {
796     GstFlowReturn res;
797 
798     *skipsize = 0;
799     g_assert (off <= map.size);
800     res = gst_mpegv_parse_parse_frame (parse, frame);
801     if (res == GST_BASE_PARSE_FLOW_DROPPED)
802       frame->flags |= GST_BASE_PARSE_FRAME_FLAG_DROP;
803     flowret = gst_base_parse_finish_frame (parse, frame, off);
804     /* Reset local information */
805     mpvparse->seqhdr_updated = FALSE;
806     mpvparse->seqext_updated = FALSE;
807     mpvparse->seqdispext_updated = FALSE;
808     mpvparse->picext_updated = FALSE;
809     mpvparse->quantmatrext_updated = FALSE;
810   }
811 
812   return flowret;
813 
814 need_more:
815   /* if draining, take all */
816   if (GST_BASE_PARSE_DRAINING (parse)) {
817     GST_LOG_OBJECT (mpvparse, "draining, accepting all data");
818     off = size;
819     ret = TRUE;
820   } else {
821     GST_LOG_OBJECT (mpvparse, "need more data");
822     /* resume scan where we left it */
823     mpvparse->last_sc = off;
824     /* request best next available */
825     off = G_MAXUINT;
826   }
827   goto exit;
828 }
829 
830 static void
gst_mpegv_parse_update_src_caps(GstMpegvParse * mpvparse)831 gst_mpegv_parse_update_src_caps (GstMpegvParse * mpvparse)
832 {
833   GstCaps *caps = NULL;
834   GstStructure *s = NULL;
835 
836   /* only update if no src caps yet or explicitly triggered */
837   if (G_LIKELY (gst_pad_has_current_caps (GST_BASE_PARSE_SRC_PAD (mpvparse)) &&
838           !mpvparse->update_caps))
839     return;
840 
841   /* carry over input caps as much as possible; override with our own stuff */
842   caps = gst_pad_get_current_caps (GST_BASE_PARSE_SINK_PAD (mpvparse));
843   if (caps) {
844     caps = gst_caps_make_writable (caps);
845     s = gst_caps_get_structure (caps, 0);
846   } else {
847     caps = gst_caps_new_empty_simple ("video/mpeg");
848   }
849 
850   /* typically we don't output buffers until we have properly parsed some
851    * config data, so we should at least know about version.
852    * If not, it means it has been requested not to drop data, and
853    * upstream and/or app must know what they are doing ... */
854   gst_caps_set_simple (caps,
855       "mpegversion", G_TYPE_INT, (mpvparse->config_flags & FLAG_MPEG2) ? 2 : 1,
856       NULL);
857 
858   gst_caps_set_simple (caps, "systemstream", G_TYPE_BOOLEAN, FALSE,
859       "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
860 
861   if (mpvparse->sequencehdr.width > 0 && mpvparse->sequencehdr.height > 0) {
862     GstMpegVideoSequenceDisplayExt *seqdispext;
863     gint width, height;
864 
865     width = mpvparse->sequencehdr.width;
866     height = mpvparse->sequencehdr.height;
867 
868     if (mpvparse->config_flags & FLAG_SEQUENCE_DISPLAY_EXT) {
869       seqdispext = &mpvparse->sequencedispext;
870 
871       if (seqdispext->display_horizontal_size <= width
872           && seqdispext->display_vertical_size <= height) {
873         width = seqdispext->display_horizontal_size;
874         height = seqdispext->display_vertical_size;
875         GST_INFO_OBJECT (mpvparse,
876             "stream has display extension: display_width=%d display_height=%d",
877             width, height);
878       }
879     }
880     gst_caps_set_simple (caps, "width", G_TYPE_INT, width,
881         "height", G_TYPE_INT, height, NULL);
882   }
883 
884   /* perhaps we have a framerate */
885   {
886     gint fps_num = mpvparse->fps_num;
887     gint fps_den = mpvparse->fps_den;
888     GstClockTime latency;
889 
890     /* upstream overrides */
891     if (s && gst_structure_has_field (s, "framerate"))
892       gst_structure_get_fraction (s, "framerate", &fps_num, &fps_den);
893 
894     if (fps_den > 0 && fps_num > 0) {
895       gst_caps_set_simple (caps, "framerate",
896           GST_TYPE_FRACTION, fps_num, fps_den, NULL);
897       gst_base_parse_set_frame_rate (GST_BASE_PARSE (mpvparse),
898           fps_num, fps_den, 0, 0);
899       latency = gst_util_uint64_scale (GST_SECOND, fps_den, fps_num);
900       gst_base_parse_set_latency (GST_BASE_PARSE (mpvparse), latency, latency);
901     }
902   }
903 
904   /* or pixel-aspect-ratio */
905   if (mpvparse->sequencehdr.par_w && mpvparse->sequencehdr.par_h > 0 &&
906       (!s || !gst_structure_has_field (s, "pixel-aspect-ratio"))) {
907     gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
908         mpvparse->sequencehdr.par_w, mpvparse->sequencehdr.par_h, NULL);
909   }
910 
911   if (mpvparse->config != NULL) {
912     gst_caps_set_simple (caps, "codec_data",
913         GST_TYPE_BUFFER, mpvparse->config, NULL);
914   }
915 
916   if (mpvparse->config_flags & FLAG_SEQUENCE_EXT) {
917     guint8 escape = mpvparse->sequenceext.profile_level_escape_bit;
918     const guint profile_c = mpvparse->sequenceext.profile;
919     const guint level_c = mpvparse->sequenceext.level;
920     const gchar *profile = NULL, *level = NULL;
921     /*
922      * Profile indication - 1 => High, 2 => Spatially Scalable,
923      *                      3 => SNR Scalable, 4 => Main, 5 => Simple
924      * 4:2:2 and Multi-view have profile = 0, with the escape bit set to 1
925      */
926     const gchar *const profiles[] =
927         { "4:2:2", "high", "spatial", "snr", "main", "simple" };
928     /*
929      * Level indication - 4 => High, 6 => High-1440, 8 => Main, 10 => Low,
930      *                    except in the case of profile = 0
931      */
932     const gchar *const levels[] = { "high", "high-1440", "main", "low" };
933 
934     if (escape) {
935       /* Non-hierarchical profile */
936       switch (level_c) {
937         case 2:
938           level = levels[0];
939         case 5:
940           if (!level)
941             level = levels[2];
942           profile = "4:2:2";
943           break;
944         case 10:
945           level = levels[0];
946         case 11:
947           if (!level)
948             level = levels[1];
949         case 13:
950           if (!level)
951             level = levels[2];
952         case 14:
953           if (!level)
954             level = levels[3];
955           profile = "multiview";
956           break;
957         default:
958           break;
959       }
960 
961     } else {
962       if (profile_c < 6)
963         profile = profiles[profile_c];
964 
965       if ((level_c > 3) && (level_c < 11) && (level_c % 2 == 0))
966         level = levels[(level_c >> 1) - 2];
967     }
968 
969     GST_DEBUG_OBJECT (mpvparse, "profile:'%s' level:'%s'", profile, level);
970 
971     if (profile)
972       gst_caps_set_simple (caps, "profile", G_TYPE_STRING, profile, NULL);
973     else
974       GST_DEBUG_OBJECT (mpvparse, "Invalid profile - %u", profile_c);
975 
976     if (level)
977       gst_caps_set_simple (caps, "level", G_TYPE_STRING, level, NULL);
978     else
979       GST_DEBUG_OBJECT (mpvparse, "Invalid level - %u", level_c);
980 
981     gst_caps_set_simple (caps, "interlace-mode",
982         G_TYPE_STRING,
983         (mpvparse->sequenceext.progressive ? "progressive" : "mixed"), NULL);
984   }
985 
986   gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (mpvparse), caps);
987   gst_caps_unref (caps);
988 
989   mpvparse->update_caps = FALSE;
990 }
991 
992 static GstFlowReturn
gst_mpegv_parse_parse_frame(GstBaseParse * parse,GstBaseParseFrame * frame)993 gst_mpegv_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
994 {
995   GstMpegvParse *mpvparse = GST_MPEGVIDEO_PARSE (parse);
996   GstBuffer *buffer = frame->buffer;
997 
998   if (G_UNLIKELY (mpvparse->pichdr.pic_type == GST_MPEG_VIDEO_PICTURE_TYPE_I))
999     GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
1000   else
1001     GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
1002 
1003   /* maybe only sequence in this buffer, though not recommended,
1004    * so mark it as such and force 0 duration */
1005   if (G_UNLIKELY (mpvparse->pic_offset < 0)) {
1006     GST_DEBUG_OBJECT (mpvparse, "frame holds no picture data");
1007     frame->flags |= GST_BASE_PARSE_FRAME_FLAG_NO_FRAME;
1008     GST_BUFFER_DURATION (buffer) = 0;
1009   }
1010 
1011   if (mpvparse->pic_offset > 4) {
1012     gst_base_parse_set_ts_at_offset (parse, mpvparse->pic_offset - 4);
1013   }
1014 
1015   if (mpvparse->frame_repeat_count
1016       && GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer))) {
1017     GST_BUFFER_DURATION (buffer) =
1018         (1 + mpvparse->frame_repeat_count) * GST_BUFFER_DURATION (buffer) / 2;
1019   }
1020 
1021   if (G_UNLIKELY (mpvparse->drop && !mpvparse->config)) {
1022     GST_DEBUG_OBJECT (mpvparse, "dropping frame as no config yet");
1023     return GST_BASE_PARSE_FLOW_DROPPED;
1024   }
1025 
1026   gst_mpegv_parse_update_src_caps (mpvparse);
1027   return GST_FLOW_OK;
1028 }
1029 
1030 static GstFlowReturn
gst_mpegv_parse_pre_push_frame(GstBaseParse * parse,GstBaseParseFrame * frame)1031 gst_mpegv_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
1032 {
1033   GstMpegvParse *mpvparse = GST_MPEGVIDEO_PARSE (parse);
1034   GstTagList *taglist;
1035   GstMpegVideoMeta *meta;
1036   GstMpegVideoSequenceHdr *seq_hdr = NULL;
1037   GstMpegVideoSequenceExt *seq_ext = NULL;
1038   GstMpegVideoSequenceDisplayExt *disp_ext = NULL;
1039   GstMpegVideoPictureHdr *pic_hdr = NULL;
1040   GstMpegVideoPictureExt *pic_ext = NULL;
1041   GstMpegVideoQuantMatrixExt *quant_ext = NULL;
1042 
1043   /* tag sending done late enough in hook to ensure pending events
1044    * have already been sent */
1045 
1046   if (G_UNLIKELY (mpvparse->send_codec_tag)) {
1047     GstCaps *caps;
1048 
1049     /* codec tag */
1050     caps = gst_pad_get_current_caps (GST_BASE_PARSE_SRC_PAD (parse));
1051     if (G_UNLIKELY (caps == NULL)) {
1052       if (GST_PAD_IS_FLUSHING (GST_BASE_PARSE_SRC_PAD (parse))) {
1053         GST_INFO_OBJECT (parse, "Src pad is flushing");
1054         return GST_FLOW_FLUSHING;
1055       } else {
1056         GST_INFO_OBJECT (parse, "Src pad is not negotiated!");
1057         return GST_FLOW_NOT_NEGOTIATED;
1058       }
1059     }
1060 
1061     taglist = gst_tag_list_new_empty ();
1062     gst_pb_utils_add_codec_description_to_tag_list (taglist,
1063         GST_TAG_VIDEO_CODEC, caps);
1064     gst_caps_unref (caps);
1065 
1066     gst_base_parse_merge_tags (parse, taglist, GST_TAG_MERGE_REPLACE);
1067     gst_tag_list_unref (taglist);
1068 
1069     mpvparse->send_codec_tag = FALSE;
1070   }
1071 
1072   /* usual clipping applies */
1073   frame->flags |= GST_BASE_PARSE_FRAME_FLAG_CLIP;
1074 
1075   if (mpvparse->send_mpeg_meta) {
1076     GstBuffer *buf;
1077 
1078     if (mpvparse->seqhdr_updated)
1079       seq_hdr = &mpvparse->sequencehdr;
1080     if (mpvparse->seqext_updated)
1081       seq_ext = &mpvparse->sequenceext;
1082     if (mpvparse->seqdispext_updated)
1083       disp_ext = &mpvparse->sequencedispext;
1084     if (mpvparse->picext_updated)
1085       pic_ext = &mpvparse->picext;
1086     if (mpvparse->quantmatrext_updated)
1087       quant_ext = &mpvparse->quantmatrext;
1088     pic_hdr = &mpvparse->pichdr;
1089 
1090     GST_DEBUG_OBJECT (mpvparse,
1091         "Adding GstMpegVideoMeta (slice_count:%d, slice_offset:%d)",
1092         mpvparse->slice_count, mpvparse->slice_offset);
1093 
1094     if (frame->out_buffer) {
1095       buf = frame->out_buffer = gst_buffer_make_writable (frame->out_buffer);
1096     } else {
1097       buf = frame->buffer = gst_buffer_make_writable (frame->buffer);
1098     }
1099 
1100     meta =
1101         gst_buffer_add_mpeg_video_meta (buf, seq_hdr, seq_ext, disp_ext,
1102         pic_hdr, pic_ext, quant_ext);
1103     meta->num_slices = mpvparse->slice_count;
1104     meta->slice_offset = mpvparse->slice_offset;
1105   }
1106 
1107   if (mpvparse->closedcaptions_size > 0) {
1108     GstBuffer *buf;
1109 
1110     if (frame->out_buffer) {
1111       buf = frame->out_buffer = gst_buffer_make_writable (frame->out_buffer);
1112     } else {
1113       buf = frame->buffer = gst_buffer_make_writable (frame->buffer);
1114     }
1115 
1116     gst_buffer_add_video_caption_meta (buf,
1117         mpvparse->closedcaptions_type, mpvparse->closedcaptions,
1118         mpvparse->closedcaptions_size);
1119 
1120     mpvparse->closedcaptions_type = GST_VIDEO_CAPTION_TYPE_UNKNOWN;
1121     mpvparse->closedcaptions_size = 0;
1122   }
1123 
1124   return GST_FLOW_OK;
1125 }
1126 
1127 static gboolean
gst_mpegv_parse_set_caps(GstBaseParse * parse,GstCaps * caps)1128 gst_mpegv_parse_set_caps (GstBaseParse * parse, GstCaps * caps)
1129 {
1130   GstMpegvParse *mpvparse = GST_MPEGVIDEO_PARSE (parse);
1131   GstStructure *s;
1132   const GValue *value;
1133   GstBuffer *buf;
1134 
1135   GST_DEBUG_OBJECT (parse, "setcaps called with %" GST_PTR_FORMAT, caps);
1136 
1137   s = gst_caps_get_structure (caps, 0);
1138 
1139   if ((value = gst_structure_get_value (s, "codec_data")) != NULL
1140       && (buf = gst_value_get_buffer (value))) {
1141     GstMapInfo map;
1142     gst_buffer_map (buf, &map, GST_MAP_READ);
1143     /* best possible parse attempt,
1144      * src caps are based on sink caps so it will end up in there
1145      * whether sucessful or not */
1146     mpvparse->seq_offset = 4;
1147     gst_mpegv_parse_process_config (mpvparse, &map, gst_buffer_get_size (buf));
1148     gst_buffer_unmap (buf, &map);
1149     gst_mpegv_parse_reset_frame (mpvparse);
1150   }
1151 
1152   /* let's not interfere and accept regardless of config parsing success */
1153   return TRUE;
1154 }
1155 
1156 static void
remove_fields(GstCaps * caps)1157 remove_fields (GstCaps * caps)
1158 {
1159   guint i, n;
1160 
1161   n = gst_caps_get_size (caps);
1162   for (i = 0; i < n; i++) {
1163     GstStructure *s = gst_caps_get_structure (caps, i);
1164 
1165     gst_structure_remove_field (s, "parsed");
1166   }
1167 }
1168 
1169 static GstCaps *
gst_mpegv_parse_get_caps(GstBaseParse * parse,GstCaps * filter)1170 gst_mpegv_parse_get_caps (GstBaseParse * parse, GstCaps * filter)
1171 {
1172   GstCaps *peercaps, *templ;
1173   GstCaps *res;
1174 
1175   templ = gst_pad_get_pad_template_caps (GST_BASE_PARSE_SINK_PAD (parse));
1176   if (filter) {
1177     GstCaps *fcopy = gst_caps_copy (filter);
1178     /* Remove the fields we convert */
1179     remove_fields (fcopy);
1180     peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), fcopy);
1181     gst_caps_unref (fcopy);
1182   } else
1183     peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), NULL);
1184 
1185   if (peercaps) {
1186     /* Remove the parsed field */
1187     peercaps = gst_caps_make_writable (peercaps);
1188     remove_fields (peercaps);
1189 
1190     res = gst_caps_intersect_full (peercaps, templ, GST_CAPS_INTERSECT_FIRST);
1191     gst_caps_unref (peercaps);
1192     gst_caps_unref (templ);
1193   } else {
1194     res = templ;
1195   }
1196 
1197   if (filter) {
1198     GstCaps *intersection;
1199 
1200     intersection =
1201         gst_caps_intersect_full (filter, res, GST_CAPS_INTERSECT_FIRST);
1202     gst_caps_unref (res);
1203     res = intersection;
1204   }
1205 
1206   return res;
1207 }
1208