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