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
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.
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.
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.
30 #include <gst/base/base.h>
31 #include <gst/pbutils/pbutils.h>
32 #include <gst/codecparsers/gstmpegvideometa.h>
34 #include "gstmpegvideoparse.h"
36 GST_DEBUG_CATEGORY (mpegv_parse_debug);
37 #define GST_CAT_DEFAULT mpegv_parse_debug
39 static GstStaticPadTemplate src_template =
40 GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC,
42 GST_STATIC_CAPS ("video/mpeg, "
43 "mpegversion = (int) [1, 2], "
44 "parsed = (boolean) true, " "systemstream = (boolean) false")
47 static GstStaticPadTemplate sink_template =
48 GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK,
50 GST_STATIC_CAPS ("video/mpeg, "
51 "mpegversion = (int) [1, 2], " "systemstream = (boolean) false")
55 #define DEFAULT_PROP_DROP TRUE
56 #define DEFAULT_PROP_GOP_SPLIT FALSE
65 #define parent_class gst_mpegv_parse_parent_class
66 G_DEFINE_TYPE (GstMpegvParse, gst_mpegv_parse, GST_TYPE_BASE_PARSE);
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,
77 static GstFlowReturn gst_mpegv_parse_pre_push_frame (GstBaseParse * parse,
78 GstBaseParseFrame * frame);
79 static gboolean gst_mpegv_parse_sink_query (GstBaseParse * parse,
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);
88 gst_mpegv_parse_set_property (GObject * object, guint property_id,
89 const GValue * value, GParamSpec * pspec)
91 GstMpegvParse *parse = GST_MPEGVIDEO_PARSE (object);
93 switch (property_id) {
95 parse->drop = g_value_get_boolean (value);
98 parse->gop_split = g_value_get_boolean (value);
101 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
106 gst_mpegv_parse_get_property (GObject * object, guint property_id,
107 GValue * value, GParamSpec * pspec)
109 GstMpegvParse *parse = GST_MPEGVIDEO_PARSE (object);
111 switch (property_id) {
113 g_value_set_boolean (value, parse->drop);
116 g_value_set_boolean (value, parse->gop_split);
119 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
124 gst_mpegv_parse_class_init (GstMpegvParseClass * klass)
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);
130 GST_DEBUG_CATEGORY_INIT (mpegv_parse_debug, "mpegvideoparse", 0,
131 "MPEG-1/2 video parser");
133 parent_class = g_type_class_peek_parent (klass);
135 gobject_class->set_property = gst_mpegv_parse_set_property;
136 gobject_class->get_property = gst_mpegv_parse_get_property;
138 g_object_class_install_property (gobject_class, PROP_DROP,
139 g_param_spec_boolean ("drop", "drop",
140 "Drop data until 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));
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));
149 gst_element_class_add_static_pad_template (element_class, &src_template);
150 gst_element_class_add_static_pad_template (element_class, &sink_template);
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>");
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);
172 gst_mpegv_parse_init (GstMpegvParse * parse)
174 parse->config_flags = FLAG_NONE;
176 gst_base_parse_set_pts_interpolation (GST_BASE_PARSE (parse), FALSE);
177 gst_base_parse_set_infer_ts (GST_BASE_PARSE (parse), FALSE);
178 GST_PAD_SET_ACCEPT_INTERSECT (GST_BASE_PARSE_SINK_PAD (parse));
179 GST_PAD_SET_ACCEPT_TEMPLATE (GST_BASE_PARSE_SINK_PAD (parse));
183 gst_mpegv_parse_reset_frame (GstMpegvParse * mpvparse)
185 /* done parsing; reset state */
186 mpvparse->last_sc = -1;
187 mpvparse->seq_size = 0;
188 mpvparse->seq_offset = -1;
189 mpvparse->pic_offset = -1;
190 mpvparse->frame_repeat_count = 0;
191 memset (mpvparse->ext_offsets, 0, sizeof (mpvparse->ext_offsets));
192 mpvparse->ext_count = 0;
193 mpvparse->slice_count = 0;
194 mpvparse->slice_offset = 0;
198 gst_mpegv_parse_reset (GstMpegvParse * mpvparse)
200 gst_mpegv_parse_reset_frame (mpvparse);
201 mpvparse->profile = 0;
202 mpvparse->update_caps = TRUE;
203 mpvparse->send_codec_tag = TRUE;
204 mpvparse->send_mpeg_meta = TRUE;
206 gst_buffer_replace (&mpvparse->config, NULL);
207 memset (&mpvparse->sequencehdr, 0, sizeof (mpvparse->sequencehdr));
208 memset (&mpvparse->sequenceext, 0, sizeof (mpvparse->sequenceext));
209 memset (&mpvparse->sequencedispext, 0, sizeof (mpvparse->sequencedispext));
210 memset (&mpvparse->pichdr, 0, sizeof (mpvparse->pichdr));
211 memset (&mpvparse->picext, 0, sizeof (mpvparse->picext));
213 mpvparse->seqhdr_updated = FALSE;
214 mpvparse->seqext_updated = FALSE;
215 mpvparse->seqdispext_updated = FALSE;
216 mpvparse->picext_updated = FALSE;
217 mpvparse->quantmatrext_updated = FALSE;
221 gst_mpegv_parse_sink_query (GstBaseParse * parse, GstQuery * query)
224 GstMpegvParse *mpvparse = GST_MPEGVIDEO_PARSE (parse);
226 res = GST_BASE_PARSE_CLASS (parent_class)->sink_query (parse, query);
228 if (res && GST_QUERY_TYPE (query) == GST_QUERY_ALLOCATION) {
229 mpvparse->send_mpeg_meta =
230 gst_query_find_allocation_meta (query, GST_MPEG_VIDEO_META_API_TYPE,
233 GST_DEBUG_OBJECT (parse, "Downstream can handle GstMpegVideo GstMeta : %d",
234 mpvparse->send_mpeg_meta);
241 gst_mpegv_parse_start (GstBaseParse * parse)
243 GstMpegvParse *mpvparse = GST_MPEGVIDEO_PARSE (parse);
245 GST_DEBUG_OBJECT (parse, "start");
247 gst_mpegv_parse_reset (mpvparse);
248 /* at least this much for a valid frame */
249 gst_base_parse_set_min_frame_size (parse, 6);
255 gst_mpegv_parse_stop (GstBaseParse * parse)
257 GstMpegvParse *mpvparse = GST_MPEGVIDEO_PARSE (parse);
259 GST_DEBUG_OBJECT (parse, "stop");
261 gst_mpegv_parse_reset (mpvparse);
267 gst_mpegv_parse_process_config (GstMpegvParse * mpvparse, GstMapInfo * info,
270 GstMpegVideoPacket packet;
271 guint8 *data_with_prefix;
274 if (mpvparse->seq_offset < 4) {
275 /* This shouldn't happen, but just in case... */
276 GST_WARNING_OBJECT (mpvparse, "Sequence header start code missing.");
280 packet.data = info->data;
281 packet.type = GST_MPEG_VIDEO_PACKET_SEQUENCE;
282 packet.offset = mpvparse->seq_offset;
283 packet.size = size - mpvparse->seq_offset;
284 /* pointer to sequence header data including the start code prefix -
285 used for codec private data */
286 data_with_prefix = (guint8 *) packet.data + packet.offset - 4;
288 /* only do stuff if something new; only compare first 8 bytes, changes in
289 quantiser matrix or bitrate don't matter here. Also changing the
290 matrices in codec_data seems to cause problem with decoders */
291 if (mpvparse->config &&
292 gst_buffer_memcmp (mpvparse->config, 0, data_with_prefix, MIN (size,
297 if (!gst_mpeg_video_packet_parse_sequence_header (&packet,
298 &mpvparse->sequencehdr)) {
299 GST_DEBUG_OBJECT (mpvparse,
300 "failed to parse config data (size %d) at offset %d",
301 size, mpvparse->seq_offset);
305 mpvparse->seqhdr_updated = TRUE;
307 GST_LOG_OBJECT (mpvparse, "accepting parsed config size %d", size);
309 /* Set mpeg version, and parse sequence extension */
310 mpvparse->config_flags = FLAG_NONE;
311 for (i = 0; i < mpvparse->ext_count; ++i) {
312 packet.type = GST_MPEG_VIDEO_PACKET_EXTENSION;
313 packet.offset = mpvparse->ext_offsets[i];
314 packet.size = (gint) size - mpvparse->ext_offsets[i];
315 mpvparse->config_flags |= FLAG_MPEG2;
316 if (packet.size > 1) {
317 switch (packet.data[packet.offset] >> 4) {
318 case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE:
319 if (gst_mpeg_video_packet_parse_sequence_extension (&packet,
320 &mpvparse->sequenceext)) {
321 GST_LOG_OBJECT (mpvparse, "Read Sequence Extension");
322 mpvparse->config_flags |= FLAG_SEQUENCE_EXT;
323 mpvparse->seqext_updated = TRUE;
326 case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_DISPLAY:
327 if (gst_mpeg_video_packet_parse_sequence_display_extension (&packet,
328 &mpvparse->sequencedispext)) {
329 GST_LOG_OBJECT (mpvparse, "Read Sequence Display Extension");
330 mpvparse->config_flags |= FLAG_SEQUENCE_DISPLAY_EXT;
331 mpvparse->seqdispext_updated = TRUE;
334 case GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX:
335 if (gst_mpeg_video_packet_parse_quant_matrix_extension (&packet,
336 &mpvparse->quantmatrext)) {
337 GST_LOG_OBJECT (mpvparse, "Read Quantization Matrix Extension");
338 mpvparse->quantmatrext_updated = TRUE;
344 if (mpvparse->config_flags & FLAG_MPEG2) {
345 /* Update the sequence header based on extensions */
346 GstMpegVideoSequenceExt *seqext = NULL;
347 GstMpegVideoSequenceDisplayExt *seqdispext = NULL;
349 if (mpvparse->config_flags & FLAG_SEQUENCE_EXT)
350 seqext = &mpvparse->sequenceext;
351 if (mpvparse->config_flags & FLAG_SEQUENCE_DISPLAY_EXT)
352 seqdispext = &mpvparse->sequencedispext;
354 gst_mpeg_video_finalise_mpeg2_sequence_header (&mpvparse->sequencehdr,
358 if (mpvparse->fps_num == 0 || mpvparse->fps_den == 0) {
359 mpvparse->fps_num = mpvparse->sequencehdr.fps_n;
360 mpvparse->fps_den = mpvparse->sequencehdr.fps_d;
363 /* parsing ok, so accept it as new config */
364 if (mpvparse->config != NULL)
365 gst_buffer_unref (mpvparse->config);
367 mpvparse->config = gst_buffer_new_and_alloc (size);
368 gst_buffer_fill (mpvparse->config, 0, data_with_prefix, size);
370 /* trigger src caps update */
371 mpvparse->update_caps = TRUE;
376 /* FIXME : Move these functions to libgstcodecparser for usage by
377 * more elements/code */
378 #ifndef GST_DISABLE_GST_DEBUG
380 picture_start_code_name (guint8 psc)
389 0x00, "Picture Start"}, {
392 0xb2, "User Data Start"}, {
393 0xb3, "Sequence Header Start"}, {
394 0xb4, "Sequence Error"}, {
395 0xb5, "Extension Start"}, {
397 0xb7, "Sequence End"}, {
398 0xb8, "Group Start"}, {
401 if (psc < 0xB0 && psc > 0)
402 return "Slice Start";
404 for (i = 0; i < G_N_ELEMENTS (psc_names); i++)
405 if (psc_names[i].psc == psc)
406 return psc_names[i].name;
412 picture_type_name (guint8 pct)
425 4, "DC Intra Coded (Shall Not Be Used!)"}
428 for (i = 0; i < G_N_ELEMENTS (pct_names); i++)
429 if (pct_names[i].pct == pct)
430 return pct_names[i].name;
432 return "Reserved/Unknown";
434 #endif /* GST_DISABLE_GST_DEBUG */
437 parse_packet_extension (GstMpegvParse * mpvparse, GstMapInfo * info, guint off)
439 GstMpegVideoPacket packet;
441 packet.data = info->data;
442 packet.type = GST_MPEG_VIDEO_PACKET_EXTENSION;
444 packet.size = info->size - off;
446 /* FIXME : WE ARE ASSUMING IT IS A *PICTURE* EXTENSION */
447 if (gst_mpeg_video_packet_parse_picture_extension (&packet,
448 &mpvparse->picext)) {
449 mpvparse->frame_repeat_count = 1;
451 if (mpvparse->picext.repeat_first_field) {
452 if (mpvparse->sequenceext.progressive) {
453 if (mpvparse->picext.top_field_first)
454 mpvparse->frame_repeat_count = 5;
456 mpvparse->frame_repeat_count = 3;
457 } else if (mpvparse->picext.progressive_frame) {
458 mpvparse->frame_repeat_count = 2;
461 mpvparse->picext_updated = TRUE;
466 parse_user_data_packet (GstMpegvParse * mpvparse, const guint8 * data,
470 GstVideoParseUtilsField field = GST_VIDEO_PARSE_UTILS_FIELD_1;
471 gst_byte_reader_init (&br, data, size);
473 if (mpvparse->picext.picture_structure ==
474 (guint8) GST_MPEG_VIDEO_PICTURE_STRUCTURE_BOTTOM_FIELD)
475 field = GST_VIDEO_PARSE_UTILS_FIELD_2;
476 gst_video_parse_user_data ((GstElement *) mpvparse, &mpvparse->user_data, &br,
477 field, ITU_T_T35_MANUFACTURER_US_ATSC);
481 /* caller guarantees at least start code in @buf at @off ( - 4)*/
482 /* for off == 4 initial code; returns TRUE if code starts a frame
483 * otherwise returns TRUE if code terminates preceding frame */
485 gst_mpegv_parse_process_sc (GstMpegvParse * mpvparse,
486 GstMapInfo * info, gint off, GstMpegVideoPacket * packet,
487 gboolean * need_more)
489 gboolean ret = FALSE, checkconfig = TRUE;
491 GST_LOG_OBJECT (mpvparse, "process startcode %x (%s) offset:%d", packet->type,
492 picture_start_code_name (packet->type), off);
496 switch (packet->type) {
497 case GST_MPEG_VIDEO_PACKET_PICTURE:
498 GST_LOG_OBJECT (mpvparse, "startcode is PICTURE");
499 /* picture is aggregated with preceding sequence/gop, if any.
500 * so, picture start code only ends if already a previous one */
501 if (mpvparse->pic_offset < 0)
502 mpvparse->pic_offset = off;
504 ret = (off != mpvparse->pic_offset);
505 /* but it's a valid starting one */
509 case GST_MPEG_VIDEO_PACKET_SEQUENCE:
510 GST_LOG_OBJECT (mpvparse, "startcode is SEQUENCE");
511 if (mpvparse->seq_offset < 0)
512 mpvparse->seq_offset = off;
515 case GST_MPEG_VIDEO_PACKET_GOP:
516 GST_LOG_OBJECT (mpvparse, "startcode is GOP");
517 if (mpvparse->seq_offset >= 0)
518 ret = mpvparse->gop_split;
522 case GST_MPEG_VIDEO_PACKET_EXTENSION:
523 mpvparse->config_flags |= FLAG_MPEG2;
524 GST_LOG_OBJECT (mpvparse, "startcode is VIDEO PACKET EXTENSION");
525 if (mpvparse->pic_offset >= 0) {
526 GST_LOG_OBJECT (mpvparse, "... considered PICTURE EXTENSION");
527 parse_packet_extension (mpvparse, info, off);
529 GST_LOG_OBJECT (mpvparse, "... considered SEQUENCE EXTENSION");
530 if (mpvparse->ext_count < G_N_ELEMENTS (mpvparse->ext_offsets))
531 mpvparse->ext_offsets[mpvparse->ext_count++] = off;
535 case GST_MPEG_VIDEO_PACKET_USER_DATA:
536 GST_LOG_OBJECT (mpvparse, "USER_DATA packet of %d bytes", packet->size);
538 if (packet->size < 0) {
539 GST_LOG_OBJECT (mpvparse, "no size yet, need more data");
544 parse_user_data_packet (mpvparse, info->data + off, packet->size);
548 if (GST_MPEG_VIDEO_PACKET_IS_SLICE (packet->type)) {
549 mpvparse->slice_count++;
550 if (mpvparse->slice_offset == 0)
551 mpvparse->slice_offset = off - 4;
557 /* set size to avoid processing config again */
558 if (checkconfig && mpvparse->seq_offset >= 0 && off != mpvparse->seq_offset &&
559 !mpvparse->seq_size) {
560 /* should always be at start */
561 g_assert (mpvparse->seq_offset <= 4);
562 gst_mpegv_parse_process_config (mpvparse, info, off - mpvparse->seq_offset);
563 mpvparse->seq_size = off - mpvparse->seq_offset;
566 /* extract some picture info if there is any in the frame being terminated */
567 if (ret && mpvparse->pic_offset >= 0 && mpvparse->pic_offset < off) {
568 GstMpegVideoPacket header;
570 header.data = info->data;
571 header.type = GST_MPEG_VIDEO_PACKET_PICTURE;
572 header.offset = mpvparse->pic_offset;
573 header.size = info->size - mpvparse->pic_offset;
574 if (gst_mpeg_video_packet_parse_picture_header (&header, &mpvparse->pichdr))
575 GST_LOG_OBJECT (mpvparse, "picture_coding_type %d (%s), ending"
576 "frame of size %d", mpvparse->pichdr.pic_type,
577 picture_type_name (mpvparse->pichdr.pic_type), off - 4);
579 GST_LOG_OBJECT (mpvparse, "Couldn't parse picture at offset %d",
580 mpvparse->pic_offset);
582 /* if terminating packet is a picture, we need to check if it has same TSN as the picture that is being
583 terminated. If it does, we need to keep those together, as these packets are two fields of the same
585 if (packet->type == GST_MPEG_VIDEO_PACKET_PICTURE
586 && (mpvparse->config_flags & FLAG_SEQUENCE_EXT)
587 && !mpvparse->sequenceext.progressive) {
588 if (info->size - off < 2) { /* we need at least two bytes to read the TSN */
592 /* TSN is stored in first 10 bits */
593 int tsn = info->data[off] << 2 | (info->data[off + 1] & 0xC0) >> 6;
595 if (tsn == mpvparse->pichdr.tsn) /* prevent termination if TSN is same */
604 /* FIXME move into baseparse, or anything equivalent;
605 * see https://bugzilla.gnome.org/show_bug.cgi?id=650093
606 * #define GST_BASE_PARSE_FRAME_FLAG_PARSING 0x100000 */
609 update_frame_parsing_status (GstMpegvParse * mpvparse,
610 GstBaseParseFrame * frame)
612 /* avoid stale cached parsing state */
613 if (frame->flags & GST_BASE_PARSE_FRAME_FLAG_NEW_FRAME) {
614 GST_LOG_OBJECT (mpvparse, "parsing new frame");
615 gst_mpegv_parse_reset_frame (mpvparse);
617 GST_LOG_OBJECT (mpvparse, "resuming frame parsing");
622 gst_mpegv_parse_handle_frame (GstBaseParse * parse,
623 GstBaseParseFrame * frame, gint * skipsize)
625 GstFlowReturn flowret = GST_FLOW_OK;
626 GstMpegvParse *mpvparse = GST_MPEGVIDEO_PARSE (parse);
627 GstBuffer *buf = frame->buffer;
628 gboolean ret = FALSE;
630 GstMpegVideoPacket packet;
633 gboolean need_more = FALSE;
636 update_frame_parsing_status (mpvparse, frame);
638 gst_buffer_map (buf, &map, GST_MAP_READ);
643 /* at least start code and subsequent byte */
644 if (G_UNLIKELY (size < 5 + off))
647 /* if already found a previous start code, e.g. start of frame, go for next */
648 if (mpvparse->last_sc >= 0) {
649 packet.offset = mpvparse->last_sc;
654 if (!gst_mpeg_video_parse (&packet, data, size, off)) {
655 /* didn't find anything that looks like a sync word, skip */
656 GST_LOG_OBJECT (mpvparse, "no start code found");
657 *skipsize = size - 3;
661 off = packet.offset - 4;
662 GST_LOG_OBJECT (mpvparse, "possible sync at buffer offset %d", off);
664 /* possible frame header, but not at offset 0? skip bytes before sync */
665 if (G_UNLIKELY (off > 0)) {
670 /* note: initial start code is assumed at offset 0 by subsequent code */
672 /* examine start code, see if it looks like an initial start code */
673 if (gst_mpegv_parse_process_sc (mpvparse, &map, 4, &packet, &need_more)) {
675 GST_LOG_OBJECT (mpvparse, "valid start code found");
676 mpvparse->last_sc = 0;
679 gst_mpegv_parse_reset_frame (mpvparse);
680 GST_LOG_OBJECT (mpvparse, "invalid start code");
685 /* start is fine as of now */
687 /* terminating start code may have been found in prev scan already */
688 if (((gint) packet.size) >= 0) {
689 off = packet.offset + packet.size;
690 /* so now we have start code at start of data; locate next start code */
691 if (!gst_mpeg_video_parse (&packet, data, size, off)) {
694 g_assert (packet.offset >= 4);
695 off = packet.offset - 4;
701 GST_LOG_OBJECT (mpvparse, "next start code at %d", off);
706 /* decide whether this startcode ends a frame */
707 ret = gst_mpegv_parse_process_sc (mpvparse, &map, off + 4, &packet,
709 /* in rare cases, might need to peek past start code */
711 GST_LOG_OBJECT (mpvparse, "need more data (past start code");
721 gst_buffer_unmap (buf, &map);
727 g_assert (off <= map.size);
728 res = gst_mpegv_parse_parse_frame (parse, frame);
729 if (res == GST_BASE_PARSE_FLOW_DROPPED)
730 frame->flags |= GST_BASE_PARSE_FRAME_FLAG_DROP;
731 flowret = gst_base_parse_finish_frame (parse, frame, off);
732 /* Reset local information */
733 mpvparse->seqhdr_updated = FALSE;
734 mpvparse->seqext_updated = FALSE;
735 mpvparse->seqdispext_updated = FALSE;
736 mpvparse->picext_updated = FALSE;
737 mpvparse->quantmatrext_updated = FALSE;
743 /* if draining, take all */
744 if (GST_BASE_PARSE_DRAINING (parse)) {
745 GST_LOG_OBJECT (mpvparse, "draining, accepting all data");
749 GST_LOG_OBJECT (mpvparse, "need more data");
750 /* resume scan where we left it */
751 mpvparse->last_sc = off;
752 /* request best next available */
759 gst_mpegv_parse_update_src_caps (GstMpegvParse * mpvparse)
761 GstCaps *caps = NULL;
762 GstStructure *s = NULL;
764 /* only update if no src caps yet or explicitly triggered */
765 if (G_LIKELY (gst_pad_has_current_caps (GST_BASE_PARSE_SRC_PAD (mpvparse)) &&
766 !mpvparse->update_caps))
769 /* carry over input caps as much as possible; override with our own stuff */
770 caps = gst_pad_get_current_caps (GST_BASE_PARSE_SINK_PAD (mpvparse));
772 caps = gst_caps_make_writable (caps);
773 s = gst_caps_get_structure (caps, 0);
775 caps = gst_caps_new_empty_simple ("video/mpeg");
778 /* typically we don't output buffers until we have properly parsed some
779 * config data, so we should at least know about version.
780 * If not, it means it has been requested not to drop data, and
781 * upstream and/or app must know what they are doing ... */
782 gst_caps_set_simple (caps,
783 "mpegversion", G_TYPE_INT, (mpvparse->config_flags & FLAG_MPEG2) ? 2 : 1,
786 gst_caps_set_simple (caps, "systemstream", G_TYPE_BOOLEAN, FALSE,
787 "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
789 if (mpvparse->sequencehdr.width > 0 && mpvparse->sequencehdr.height > 0) {
790 GstMpegVideoSequenceDisplayExt *seqdispext;
793 width = mpvparse->sequencehdr.width;
794 height = mpvparse->sequencehdr.height;
796 if (mpvparse->config_flags & FLAG_SEQUENCE_DISPLAY_EXT) {
797 seqdispext = &mpvparse->sequencedispext;
799 if (seqdispext->display_horizontal_size <= width
800 && seqdispext->display_vertical_size <= height) {
801 width = seqdispext->display_horizontal_size;
802 height = seqdispext->display_vertical_size;
803 GST_INFO_OBJECT (mpvparse,
804 "stream has display extension: display_width=%d display_height=%d",
808 gst_caps_set_simple (caps, "width", G_TYPE_INT, width,
809 "height", G_TYPE_INT, height, NULL);
812 /* perhaps we have a framerate */
814 gint fps_num = mpvparse->fps_num;
815 gint fps_den = mpvparse->fps_den;
816 GstClockTime latency;
818 /* upstream overrides */
819 if (s && gst_structure_has_field (s, "framerate"))
820 gst_structure_get_fraction (s, "framerate", &fps_num, &fps_den);
822 if (fps_den > 0 && fps_num > 0) {
823 gst_caps_set_simple (caps, "framerate",
824 GST_TYPE_FRACTION, fps_num, fps_den, NULL);
825 gst_base_parse_set_frame_rate (GST_BASE_PARSE (mpvparse),
826 fps_num, fps_den, 0, 0);
827 latency = gst_util_uint64_scale (GST_SECOND, fps_den, fps_num);
828 gst_base_parse_set_latency (GST_BASE_PARSE (mpvparse), latency, latency);
832 /* or pixel-aspect-ratio */
833 if (mpvparse->sequencehdr.par_w && mpvparse->sequencehdr.par_h > 0 &&
834 (!s || !gst_structure_has_field (s, "pixel-aspect-ratio"))) {
835 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
836 mpvparse->sequencehdr.par_w, mpvparse->sequencehdr.par_h, NULL);
839 if (mpvparse->config != NULL) {
840 gst_caps_set_simple (caps, "codec_data",
841 GST_TYPE_BUFFER, mpvparse->config, NULL);
844 if (mpvparse->config_flags & FLAG_SEQUENCE_EXT) {
845 guint8 escape = mpvparse->sequenceext.profile_level_escape_bit;
846 const guint profile_c = mpvparse->sequenceext.profile;
847 const guint level_c = mpvparse->sequenceext.level;
848 const gchar *profile = NULL, *level = NULL;
850 * Profile indication - 1 => High, 2 => Spatially Scalable,
851 * 3 => SNR Scalable, 4 => Main, 5 => Simple
852 * 4:2:2 and Multi-view have profile = 0, with the escape bit set to 1
854 const gchar *const profiles[] =
855 { "4:2:2", "high", "spatial", "snr", "main", "simple" };
857 * Level indication - 4 => High, 6 => High-1440, 8 => Main, 10 => Low,
858 * except in the case of profile = 0
860 const gchar *const levels[] = { "high", "high-1440", "main", "low" };
863 /* Non-hierarchical profile */
883 profile = "multiview";
891 profile = profiles[profile_c];
893 if ((level_c > 3) && (level_c < 11) && (level_c % 2 == 0))
894 level = levels[(level_c >> 1) - 2];
897 GST_DEBUG_OBJECT (mpvparse, "profile:'%s' level:'%s'", profile, level);
900 gst_caps_set_simple (caps, "profile", G_TYPE_STRING, profile, NULL);
902 GST_DEBUG_OBJECT (mpvparse, "Invalid profile - %u", profile_c);
905 gst_caps_set_simple (caps, "level", G_TYPE_STRING, level, NULL);
907 GST_DEBUG_OBJECT (mpvparse, "Invalid level - %u", level_c);
909 if (!s || !gst_structure_has_field (s, "interlace-mode"))
910 gst_caps_set_simple (caps, "interlace-mode",
912 (mpvparse->sequenceext.progressive ? "progressive" : "mixed"), NULL);
915 gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (mpvparse), caps);
916 gst_caps_unref (caps);
918 mpvparse->update_caps = FALSE;
922 gst_mpegv_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
924 GstMpegvParse *mpvparse = GST_MPEGVIDEO_PARSE (parse);
925 GstBuffer *buffer = frame->buffer;
927 if (G_UNLIKELY (mpvparse->pichdr.pic_type == GST_MPEG_VIDEO_PICTURE_TYPE_I))
928 GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
930 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
932 /* maybe only sequence in this buffer, though not recommended,
933 * so mark it as such and force 0 duration */
934 if (G_UNLIKELY (mpvparse->pic_offset < 0)) {
935 GST_DEBUG_OBJECT (mpvparse, "frame holds no picture data");
936 frame->flags |= GST_BASE_PARSE_FRAME_FLAG_NO_FRAME;
937 GST_BUFFER_DURATION (buffer) = 0;
940 if (mpvparse->pic_offset > 4) {
941 gst_base_parse_set_ts_at_offset (parse, mpvparse->pic_offset - 4);
944 if (mpvparse->frame_repeat_count
945 && GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer))) {
946 GST_BUFFER_DURATION (buffer) =
947 (1 + mpvparse->frame_repeat_count) * GST_BUFFER_DURATION (buffer) / 2;
950 if (G_UNLIKELY (mpvparse->drop && !mpvparse->config)) {
951 GST_DEBUG_OBJECT (mpvparse, "dropping frame as no config yet");
952 return GST_BASE_PARSE_FLOW_DROPPED;
955 gst_mpegv_parse_update_src_caps (mpvparse);
960 gst_mpegv_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
962 GstMpegvParse *mpvparse = GST_MPEGVIDEO_PARSE (parse);
964 GstMpegVideoMeta *meta;
965 GstMpegVideoSequenceHdr *seq_hdr = NULL;
966 GstMpegVideoSequenceExt *seq_ext = NULL;
967 GstMpegVideoSequenceDisplayExt *disp_ext = NULL;
968 GstMpegVideoPictureHdr *pic_hdr = NULL;
969 GstMpegVideoPictureExt *pic_ext = NULL;
970 GstMpegVideoQuantMatrixExt *quant_ext = NULL;
971 GstBuffer *parse_buffer = NULL;
973 /* tag sending done late enough in hook to ensure pending events
974 * have already been sent */
976 if (G_UNLIKELY (mpvparse->send_codec_tag)) {
980 caps = gst_pad_get_current_caps (GST_BASE_PARSE_SRC_PAD (parse));
981 if (G_UNLIKELY (caps == NULL)) {
982 if (GST_PAD_IS_FLUSHING (GST_BASE_PARSE_SRC_PAD (parse))) {
983 GST_INFO_OBJECT (parse, "Src pad is flushing");
984 return GST_FLOW_FLUSHING;
986 GST_INFO_OBJECT (parse, "Src pad is not negotiated!");
987 return GST_FLOW_NOT_NEGOTIATED;
991 taglist = gst_tag_list_new_empty ();
992 gst_pb_utils_add_codec_description_to_tag_list (taglist,
993 GST_TAG_VIDEO_CODEC, caps);
994 gst_caps_unref (caps);
996 gst_base_parse_merge_tags (parse, taglist, GST_TAG_MERGE_REPLACE);
997 gst_tag_list_unref (taglist);
999 mpvparse->send_codec_tag = FALSE;
1002 /* usual clipping applies */
1003 frame->flags |= GST_BASE_PARSE_FRAME_FLAG_CLIP;
1005 if (mpvparse->send_mpeg_meta) {
1008 if (mpvparse->seqhdr_updated)
1009 seq_hdr = &mpvparse->sequencehdr;
1010 if (mpvparse->seqext_updated)
1011 seq_ext = &mpvparse->sequenceext;
1012 if (mpvparse->seqdispext_updated)
1013 disp_ext = &mpvparse->sequencedispext;
1014 if (mpvparse->picext_updated)
1015 pic_ext = &mpvparse->picext;
1016 if (mpvparse->quantmatrext_updated)
1017 quant_ext = &mpvparse->quantmatrext;
1018 pic_hdr = &mpvparse->pichdr;
1020 GST_DEBUG_OBJECT (mpvparse,
1021 "Adding GstMpegVideoMeta (slice_count:%d, slice_offset:%d)",
1022 mpvparse->slice_count, mpvparse->slice_offset);
1024 if (frame->out_buffer) {
1025 buf = frame->out_buffer = gst_buffer_make_writable (frame->out_buffer);
1027 buf = frame->buffer = gst_buffer_make_writable (frame->buffer);
1031 gst_buffer_add_mpeg_video_meta (buf, seq_hdr, seq_ext, disp_ext,
1032 pic_hdr, pic_ext, quant_ext);
1033 meta->num_slices = mpvparse->slice_count;
1034 meta->slice_offset = mpvparse->slice_offset;
1037 if (frame->out_buffer) {
1038 parse_buffer = frame->out_buffer =
1039 gst_buffer_make_writable (frame->out_buffer);
1041 parse_buffer = frame->buffer = gst_buffer_make_writable (frame->buffer);
1044 if (pic_ext && !pic_ext->progressive_frame) {
1045 GST_BUFFER_FLAG_SET (parse_buffer, GST_VIDEO_BUFFER_FLAG_INTERLACED);
1046 if (pic_ext->top_field_first)
1047 GST_BUFFER_FLAG_SET (parse_buffer, GST_VIDEO_BUFFER_FLAG_TFF);
1049 gst_video_push_user_data ((GstElement *) mpvparse, &mpvparse->user_data,
1056 gst_mpegv_parse_set_caps (GstBaseParse * parse, GstCaps * caps)
1058 GstMpegvParse *mpvparse = GST_MPEGVIDEO_PARSE (parse);
1060 const GValue *value;
1063 GST_DEBUG_OBJECT (parse, "setcaps called with %" GST_PTR_FORMAT, caps);
1065 s = gst_caps_get_structure (caps, 0);
1067 if ((value = gst_structure_get_value (s, "codec_data")) != NULL
1068 && (buf = gst_value_get_buffer (value))) {
1070 gst_buffer_map (buf, &map, GST_MAP_READ);
1071 /* best possible parse attempt,
1072 * src caps are based on sink caps so it will end up in there
1073 * whether successful or not */
1074 mpvparse->seq_offset = 4;
1075 gst_mpegv_parse_process_config (mpvparse, &map, gst_buffer_get_size (buf));
1076 gst_buffer_unmap (buf, &map);
1077 gst_mpegv_parse_reset_frame (mpvparse);
1080 /* let's not interfere and accept regardless of config parsing success */
1085 remove_fields (GstCaps * caps)
1089 n = gst_caps_get_size (caps);
1090 for (i = 0; i < n; i++) {
1091 GstStructure *s = gst_caps_get_structure (caps, i);
1093 gst_structure_remove_field (s, "parsed");
1098 gst_mpegv_parse_get_caps (GstBaseParse * parse, GstCaps * filter)
1100 GstCaps *peercaps, *templ;
1103 templ = gst_pad_get_pad_template_caps (GST_BASE_PARSE_SINK_PAD (parse));
1105 GstCaps *fcopy = gst_caps_copy (filter);
1106 /* Remove the fields we convert */
1107 remove_fields (fcopy);
1108 peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), fcopy);
1109 gst_caps_unref (fcopy);
1111 peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), NULL);
1114 /* Remove the parsed field */
1115 peercaps = gst_caps_make_writable (peercaps);
1116 remove_fields (peercaps);
1118 res = gst_caps_intersect_full (peercaps, templ, GST_CAPS_INTERSECT_FIRST);
1119 gst_caps_unref (peercaps);
1120 gst_caps_unref (templ);
1126 GstCaps *intersection;
1129 gst_caps_intersect_full (filter, res, GST_CAPS_INTERSECT_FIRST);
1130 gst_caps_unref (res);