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