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