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 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));
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_PAD_SET_ACCEPT_INTERSECT (GST_BASE_PARSE_SINK_PAD (parse));
178 GST_PAD_SET_ACCEPT_TEMPLATE (GST_BASE_PARSE_SINK_PAD (parse));
182 gst_mpegv_parse_reset_frame (GstMpegvParse * mpvparse)
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;
197 gst_mpegv_parse_reset (GstMpegvParse * mpvparse)
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;
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));
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;
220 gst_mpegv_parse_sink_query (GstBaseParse * parse, GstQuery * query)
223 GstMpegvParse *mpvparse = GST_MPEGVIDEO_PARSE (parse);
225 res = GST_BASE_PARSE_CLASS (parent_class)->sink_query (parse, query);
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,
232 GST_DEBUG_OBJECT (parse, "Downstream can handle GstMpegVideo GstMeta : %d",
233 mpvparse->send_mpeg_meta);
240 gst_mpegv_parse_start (GstBaseParse * parse)
242 GstMpegvParse *mpvparse = GST_MPEGVIDEO_PARSE (parse);
244 GST_DEBUG_OBJECT (parse, "start");
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);
254 gst_mpegv_parse_stop (GstBaseParse * parse)
256 GstMpegvParse *mpvparse = GST_MPEGVIDEO_PARSE (parse);
258 GST_DEBUG_OBJECT (parse, "stop");
260 gst_mpegv_parse_reset (mpvparse);
266 gst_mpegv_parse_process_config (GstMpegvParse * mpvparse, GstMapInfo * info,
269 GstMpegVideoPacket packet;
270 guint8 *data_with_prefix;
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.");
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;
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,
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);
304 mpvparse->seqhdr_updated = TRUE;
306 GST_LOG_OBJECT (mpvparse, "accepting parsed config size %d", size);
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;
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;
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;
343 if (mpvparse->config_flags & FLAG_MPEG2) {
344 /* Update the sequence header based on extensions */
345 GstMpegVideoSequenceExt *seqext = NULL;
346 GstMpegVideoSequenceDisplayExt *seqdispext = NULL;
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;
353 gst_mpeg_video_finalise_mpeg2_sequence_header (&mpvparse->sequencehdr,
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;
362 /* parsing ok, so accept it as new config */
363 if (mpvparse->config != NULL)
364 gst_buffer_unref (mpvparse->config);
366 mpvparse->config = gst_buffer_new_and_alloc (size);
367 gst_buffer_fill (mpvparse->config, 0, data_with_prefix, size);
369 /* trigger src caps update */
370 mpvparse->update_caps = TRUE;
375 /* FIXME : Move these functions to libgstcodecparser for usage by
376 * more elements/code */
377 #ifndef GST_DISABLE_GST_DEBUG
379 picture_start_code_name (guint8 psc)
388 0x00, "Picture Start"}, {
391 0xb2, "User Data Start"}, {
392 0xb3, "Sequence Header Start"}, {
393 0xb4, "Sequence Error"}, {
394 0xb5, "Extension Start"}, {
396 0xb7, "Sequence End"}, {
397 0xb8, "Group Start"}, {
400 if (psc < 0xB0 && psc > 0)
401 return "Slice Start";
403 for (i = 0; i < G_N_ELEMENTS (psc_names); i++)
404 if (psc_names[i].psc == psc)
405 return psc_names[i].name;
411 picture_type_name (guint8 pct)
424 4, "DC Intra Coded (Shall Not Be Used!)"}
427 for (i = 0; i < G_N_ELEMENTS (pct_names); i++)
428 if (pct_names[i].pct == pct)
429 return pct_names[i].name;
431 return "Reserved/Unknown";
433 #endif /* GST_DISABLE_GST_DEBUG */
436 parse_packet_extension (GstMpegvParse * mpvparse, GstMapInfo * info, guint off)
438 GstMpegVideoPacket packet;
440 packet.data = info->data;
441 packet.type = GST_MPEG_VIDEO_PACKET_EXTENSION;
443 packet.size = info->size - off;
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;
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;
455 mpvparse->frame_repeat_count = 3;
456 } else if (mpvparse->picext.progressive_frame) {
457 mpvparse->frame_repeat_count = 2;
460 mpvparse->picext_updated = TRUE;
465 parse_user_data_packet (GstMpegvParse * mpvparse, const guint8 * data,
469 GstVideoParseUtilsField field = GST_VIDEO_PARSE_UTILS_FIELD_1;
470 gst_byte_reader_init (&br, data, size);
472 if (mpvparse->picext.picture_structure ==
473 (guint8) GST_MPEG_VIDEO_PICTURE_STRUCTURE_BOTTOM_FIELD)
474 field = GST_VIDEO_PARSE_UTILS_FIELD_2;
475 gst_video_parse_user_data ((GstElement *) mpvparse, &mpvparse->user_data, &br,
476 field, ITU_T_T35_MANUFACTURER_US_ATSC);
480 /* caller guarantees at least start code in @buf at @off ( - 4)*/
481 /* for off == 4 initial code; returns TRUE if code starts a frame
482 * otherwise returns TRUE if code terminates preceding frame */
484 gst_mpegv_parse_process_sc (GstMpegvParse * mpvparse,
485 GstMapInfo * info, gint off, GstMpegVideoPacket * packet,
486 gboolean * need_more)
488 gboolean ret = FALSE, checkconfig = TRUE;
490 GST_LOG_OBJECT (mpvparse, "process startcode %x (%s) offset:%d", packet->type,
491 picture_start_code_name (packet->type), off);
495 switch (packet->type) {
496 case GST_MPEG_VIDEO_PACKET_PICTURE:
497 GST_LOG_OBJECT (mpvparse, "startcode is PICTURE");
498 /* picture is aggregated with preceding sequence/gop, if any.
499 * so, picture start code only ends if already a previous one */
500 if (mpvparse->pic_offset < 0)
501 mpvparse->pic_offset = off;
503 ret = (off != mpvparse->pic_offset);
504 /* but it's a valid starting one */
508 case GST_MPEG_VIDEO_PACKET_SEQUENCE:
509 GST_LOG_OBJECT (mpvparse, "startcode is SEQUENCE");
510 if (mpvparse->seq_offset < 0)
511 mpvparse->seq_offset = off;
514 case GST_MPEG_VIDEO_PACKET_GOP:
515 GST_LOG_OBJECT (mpvparse, "startcode is GOP");
516 if (mpvparse->seq_offset >= 0)
517 ret = mpvparse->gop_split;
521 case GST_MPEG_VIDEO_PACKET_EXTENSION:
522 mpvparse->config_flags |= FLAG_MPEG2;
523 GST_LOG_OBJECT (mpvparse, "startcode is VIDEO PACKET EXTENSION");
524 if (mpvparse->pic_offset >= 0) {
525 GST_LOG_OBJECT (mpvparse, "... considered PICTURE EXTENSION");
526 parse_packet_extension (mpvparse, info, off);
528 GST_LOG_OBJECT (mpvparse, "... considered SEQUENCE EXTENSION");
529 if (mpvparse->ext_count < G_N_ELEMENTS (mpvparse->ext_offsets))
530 mpvparse->ext_offsets[mpvparse->ext_count++] = off;
534 case GST_MPEG_VIDEO_PACKET_USER_DATA:
535 GST_LOG_OBJECT (mpvparse, "USER_DATA packet of %d bytes", packet->size);
537 if (packet->size < 0) {
538 GST_LOG_OBJECT (mpvparse, "no size yet, need more data");
543 parse_user_data_packet (mpvparse, info->data + off, packet->size);
547 if (GST_MPEG_VIDEO_PACKET_IS_SLICE (packet->type)) {
548 mpvparse->slice_count++;
549 if (mpvparse->slice_offset == 0)
550 mpvparse->slice_offset = off - 4;
556 /* set size to avoid processing config again */
557 if (checkconfig && mpvparse->seq_offset >= 0 && off != mpvparse->seq_offset &&
558 !mpvparse->seq_size) {
559 /* should always be at start */
560 g_assert (mpvparse->seq_offset <= 4);
561 gst_mpegv_parse_process_config (mpvparse, info, off - mpvparse->seq_offset);
562 mpvparse->seq_size = off - mpvparse->seq_offset;
565 /* extract some picture info if there is any in the frame being terminated */
566 if (ret && mpvparse->pic_offset >= 0 && mpvparse->pic_offset < off) {
567 GstMpegVideoPacket header;
569 header.data = info->data;
570 header.type = GST_MPEG_VIDEO_PACKET_PICTURE;
571 header.offset = mpvparse->pic_offset;
572 header.size = info->size - mpvparse->pic_offset;
573 if (gst_mpeg_video_packet_parse_picture_header (&header, &mpvparse->pichdr))
574 GST_LOG_OBJECT (mpvparse, "picture_coding_type %d (%s), ending"
575 "frame of size %d", mpvparse->pichdr.pic_type,
576 picture_type_name (mpvparse->pichdr.pic_type), off - 4);
578 GST_LOG_OBJECT (mpvparse, "Couldn't parse picture at offset %d",
579 mpvparse->pic_offset);
581 /* if terminating packet is a picture, we need to check if it has same TSN as the picture that is being
582 terminated. If it does, we need to keep those together, as these packets are two fields of the same
584 if (packet->type == GST_MPEG_VIDEO_PACKET_PICTURE
585 && (mpvparse->config_flags & FLAG_SEQUENCE_EXT)
586 && !mpvparse->sequenceext.progressive) {
587 if (info->size - off < 2) { /* we need at least two bytes to read the TSN */
591 /* TSN is stored in first 10 bits */
592 int tsn = info->data[off] << 2 | (info->data[off + 1] & 0xC0) >> 6;
594 if (tsn == mpvparse->pichdr.tsn) /* prevent termination if TSN is same */
603 /* FIXME move into baseparse, or anything equivalent;
604 * see https://bugzilla.gnome.org/show_bug.cgi?id=650093
605 * #define GST_BASE_PARSE_FRAME_FLAG_PARSING 0x100000 */
608 update_frame_parsing_status (GstMpegvParse * mpvparse,
609 GstBaseParseFrame * frame)
611 /* avoid stale cached parsing state */
612 if (frame->flags & GST_BASE_PARSE_FRAME_FLAG_NEW_FRAME) {
613 GST_LOG_OBJECT (mpvparse, "parsing new frame");
614 gst_mpegv_parse_reset_frame (mpvparse);
616 GST_LOG_OBJECT (mpvparse, "resuming frame parsing");
621 gst_mpegv_parse_handle_frame (GstBaseParse * parse,
622 GstBaseParseFrame * frame, gint * skipsize)
624 GstFlowReturn flowret = GST_FLOW_OK;
625 GstMpegvParse *mpvparse = GST_MPEGVIDEO_PARSE (parse);
626 GstBuffer *buf = frame->buffer;
627 gboolean ret = FALSE;
629 GstMpegVideoPacket packet;
632 gboolean need_more = FALSE;
635 update_frame_parsing_status (mpvparse, frame);
637 gst_buffer_map (buf, &map, GST_MAP_READ);
642 /* at least start code and subsequent byte */
643 if (G_UNLIKELY (size < 5 + off))
646 /* if already found a previous start code, e.g. start of frame, go for next */
647 if (mpvparse->last_sc >= 0) {
648 packet.offset = mpvparse->last_sc;
653 if (!gst_mpeg_video_parse (&packet, data, size, off)) {
654 /* didn't find anything that looks like a sync word, skip */
655 GST_LOG_OBJECT (mpvparse, "no start code found");
656 *skipsize = size - 3;
660 off = packet.offset - 4;
661 GST_LOG_OBJECT (mpvparse, "possible sync at buffer offset %d", off);
663 /* possible frame header, but not at offset 0? skip bytes before sync */
664 if (G_UNLIKELY (off > 0)) {
669 /* note: initial start code is assumed at offset 0 by subsequent code */
671 /* examine start code, see if it looks like an initial start code */
672 if (gst_mpegv_parse_process_sc (mpvparse, &map, 4, &packet, &need_more)) {
674 GST_LOG_OBJECT (mpvparse, "valid start code found");
675 mpvparse->last_sc = 0;
678 gst_mpegv_parse_reset_frame (mpvparse);
679 GST_LOG_OBJECT (mpvparse, "invalid start code");
684 /* start is fine as of now */
686 /* terminating start code may have been found in prev scan already */
687 if (((gint) packet.size) >= 0) {
688 off = packet.offset + packet.size;
689 /* so now we have start code at start of data; locate next start code */
690 if (!gst_mpeg_video_parse (&packet, data, size, off)) {
693 g_assert (packet.offset >= 4);
694 off = packet.offset - 4;
700 GST_LOG_OBJECT (mpvparse, "next start code at %d", off);
705 /* decide whether this startcode ends a frame */
706 ret = gst_mpegv_parse_process_sc (mpvparse, &map, off + 4, &packet,
708 /* in rare cases, might need to peek past start code */
710 GST_LOG_OBJECT (mpvparse, "need more data (past start code");
720 gst_buffer_unmap (buf, &map);
726 g_assert (off <= map.size);
727 res = gst_mpegv_parse_parse_frame (parse, frame);
728 if (res == GST_BASE_PARSE_FLOW_DROPPED)
729 frame->flags |= GST_BASE_PARSE_FRAME_FLAG_DROP;
730 flowret = gst_base_parse_finish_frame (parse, frame, off);
731 /* Reset local information */
732 mpvparse->seqhdr_updated = FALSE;
733 mpvparse->seqext_updated = FALSE;
734 mpvparse->seqdispext_updated = FALSE;
735 mpvparse->picext_updated = FALSE;
736 mpvparse->quantmatrext_updated = FALSE;
742 /* if draining, take all */
743 if (GST_BASE_PARSE_DRAINING (parse)) {
744 GST_LOG_OBJECT (mpvparse, "draining, accepting all data");
748 GST_LOG_OBJECT (mpvparse, "need more data");
749 /* resume scan where we left it */
750 mpvparse->last_sc = off;
751 /* request best next available */
758 gst_mpegv_parse_update_src_caps (GstMpegvParse * mpvparse)
760 GstCaps *caps = NULL;
761 GstStructure *s = NULL;
763 /* only update if no src caps yet or explicitly triggered */
764 if (G_LIKELY (gst_pad_has_current_caps (GST_BASE_PARSE_SRC_PAD (mpvparse)) &&
765 !mpvparse->update_caps))
768 /* carry over input caps as much as possible; override with our own stuff */
769 caps = gst_pad_get_current_caps (GST_BASE_PARSE_SINK_PAD (mpvparse));
771 caps = gst_caps_make_writable (caps);
772 s = gst_caps_get_structure (caps, 0);
774 caps = gst_caps_new_empty_simple ("video/mpeg");
777 /* typically we don't output buffers until we have properly parsed some
778 * config data, so we should at least know about version.
779 * If not, it means it has been requested not to drop data, and
780 * upstream and/or app must know what they are doing ... */
781 gst_caps_set_simple (caps,
782 "mpegversion", G_TYPE_INT, (mpvparse->config_flags & FLAG_MPEG2) ? 2 : 1,
785 gst_caps_set_simple (caps, "systemstream", G_TYPE_BOOLEAN, FALSE,
786 "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
788 if (mpvparse->sequencehdr.width > 0 && mpvparse->sequencehdr.height > 0) {
789 GstMpegVideoSequenceDisplayExt *seqdispext;
792 width = mpvparse->sequencehdr.width;
793 height = mpvparse->sequencehdr.height;
795 if (mpvparse->config_flags & FLAG_SEQUENCE_DISPLAY_EXT) {
796 seqdispext = &mpvparse->sequencedispext;
798 if (seqdispext->display_horizontal_size <= width
799 && seqdispext->display_vertical_size <= height) {
800 width = seqdispext->display_horizontal_size;
801 height = seqdispext->display_vertical_size;
802 GST_INFO_OBJECT (mpvparse,
803 "stream has display extension: display_width=%d display_height=%d",
807 gst_caps_set_simple (caps, "width", G_TYPE_INT, width,
808 "height", G_TYPE_INT, height, NULL);
811 /* perhaps we have a framerate */
813 gint fps_num = mpvparse->fps_num;
814 gint fps_den = mpvparse->fps_den;
815 GstClockTime latency;
817 /* upstream overrides */
818 if (s && gst_structure_has_field (s, "framerate"))
819 gst_structure_get_fraction (s, "framerate", &fps_num, &fps_den);
821 if (fps_den > 0 && fps_num > 0) {
822 gst_caps_set_simple (caps, "framerate",
823 GST_TYPE_FRACTION, fps_num, fps_den, NULL);
824 gst_base_parse_set_frame_rate (GST_BASE_PARSE (mpvparse),
825 fps_num, fps_den, 0, 0);
826 latency = gst_util_uint64_scale (GST_SECOND, fps_den, fps_num);
827 gst_base_parse_set_latency (GST_BASE_PARSE (mpvparse), latency, latency);
831 /* or pixel-aspect-ratio */
832 if (mpvparse->sequencehdr.par_w && mpvparse->sequencehdr.par_h > 0 &&
833 (!s || !gst_structure_has_field (s, "pixel-aspect-ratio"))) {
834 gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
835 mpvparse->sequencehdr.par_w, mpvparse->sequencehdr.par_h, NULL);
838 if (mpvparse->config != NULL) {
839 gst_caps_set_simple (caps, "codec_data",
840 GST_TYPE_BUFFER, mpvparse->config, NULL);
843 if (mpvparse->config_flags & FLAG_SEQUENCE_EXT) {
844 guint8 escape = mpvparse->sequenceext.profile_level_escape_bit;
845 const guint profile_c = mpvparse->sequenceext.profile;
846 const guint level_c = mpvparse->sequenceext.level;
847 const gchar *profile = NULL, *level = NULL;
849 * Profile indication - 1 => High, 2 => Spatially Scalable,
850 * 3 => SNR Scalable, 4 => Main, 5 => Simple
851 * 4:2:2 and Multi-view have profile = 0, with the escape bit set to 1
853 const gchar *const profiles[] =
854 { "4:2:2", "high", "spatial", "snr", "main", "simple" };
856 * Level indication - 4 => High, 6 => High-1440, 8 => Main, 10 => Low,
857 * except in the case of profile = 0
859 const gchar *const levels[] = { "high", "high-1440", "main", "low" };
862 /* Non-hierarchical profile */
882 profile = "multiview";
890 profile = profiles[profile_c];
892 if ((level_c > 3) && (level_c < 11) && (level_c % 2 == 0))
893 level = levels[(level_c >> 1) - 2];
896 GST_DEBUG_OBJECT (mpvparse, "profile:'%s' level:'%s'", profile, level);
899 gst_caps_set_simple (caps, "profile", G_TYPE_STRING, profile, NULL);
901 GST_DEBUG_OBJECT (mpvparse, "Invalid profile - %u", profile_c);
904 gst_caps_set_simple (caps, "level", G_TYPE_STRING, level, NULL);
906 GST_DEBUG_OBJECT (mpvparse, "Invalid level - %u", level_c);
908 if (!s || !gst_structure_has_field (s, "interlace-mode"))
909 gst_caps_set_simple (caps, "interlace-mode",
911 (mpvparse->sequenceext.progressive ? "progressive" : "mixed"), NULL);
914 gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (mpvparse), caps);
915 gst_caps_unref (caps);
917 mpvparse->update_caps = FALSE;
921 gst_mpegv_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
923 GstMpegvParse *mpvparse = GST_MPEGVIDEO_PARSE (parse);
924 GstBuffer *buffer = frame->buffer;
926 if (G_UNLIKELY (mpvparse->pichdr.pic_type == GST_MPEG_VIDEO_PICTURE_TYPE_I))
927 GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
929 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
931 /* maybe only sequence in this buffer, though not recommended,
932 * so mark it as such and force 0 duration */
933 if (G_UNLIKELY (mpvparse->pic_offset < 0)) {
934 GST_DEBUG_OBJECT (mpvparse, "frame holds no picture data");
935 frame->flags |= GST_BASE_PARSE_FRAME_FLAG_NO_FRAME;
936 GST_BUFFER_DURATION (buffer) = 0;
939 if (mpvparse->pic_offset > 4) {
940 gst_base_parse_set_ts_at_offset (parse, mpvparse->pic_offset - 4);
943 if (mpvparse->frame_repeat_count
944 && GST_CLOCK_TIME_IS_VALID (GST_BUFFER_DURATION (buffer))) {
945 GST_BUFFER_DURATION (buffer) =
946 (1 + mpvparse->frame_repeat_count) * GST_BUFFER_DURATION (buffer) / 2;
949 if (G_UNLIKELY (mpvparse->drop && !mpvparse->config)) {
950 GST_DEBUG_OBJECT (mpvparse, "dropping frame as no config yet");
951 return GST_BASE_PARSE_FLOW_DROPPED;
954 gst_mpegv_parse_update_src_caps (mpvparse);
959 gst_mpegv_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
961 GstMpegvParse *mpvparse = GST_MPEGVIDEO_PARSE (parse);
963 GstMpegVideoMeta *meta;
964 GstMpegVideoSequenceHdr *seq_hdr = NULL;
965 GstMpegVideoSequenceExt *seq_ext = NULL;
966 GstMpegVideoSequenceDisplayExt *disp_ext = NULL;
967 GstMpegVideoPictureHdr *pic_hdr = NULL;
968 GstMpegVideoPictureExt *pic_ext = NULL;
969 GstMpegVideoQuantMatrixExt *quant_ext = NULL;
970 GstBuffer *parse_buffer = NULL;
972 /* tag sending done late enough in hook to ensure pending events
973 * have already been sent */
975 if (G_UNLIKELY (mpvparse->send_codec_tag)) {
979 caps = gst_pad_get_current_caps (GST_BASE_PARSE_SRC_PAD (parse));
980 if (G_UNLIKELY (caps == NULL)) {
981 if (GST_PAD_IS_FLUSHING (GST_BASE_PARSE_SRC_PAD (parse))) {
982 GST_INFO_OBJECT (parse, "Src pad is flushing");
983 return GST_FLOW_FLUSHING;
985 GST_INFO_OBJECT (parse, "Src pad is not negotiated!");
986 return GST_FLOW_NOT_NEGOTIATED;
990 taglist = gst_tag_list_new_empty ();
991 gst_pb_utils_add_codec_description_to_tag_list (taglist,
992 GST_TAG_VIDEO_CODEC, caps);
993 gst_caps_unref (caps);
995 gst_base_parse_merge_tags (parse, taglist, GST_TAG_MERGE_REPLACE);
996 gst_tag_list_unref (taglist);
998 mpvparse->send_codec_tag = FALSE;
1001 /* usual clipping applies */
1002 frame->flags |= GST_BASE_PARSE_FRAME_FLAG_CLIP;
1004 if (mpvparse->send_mpeg_meta) {
1007 if (mpvparse->seqhdr_updated)
1008 seq_hdr = &mpvparse->sequencehdr;
1009 if (mpvparse->seqext_updated)
1010 seq_ext = &mpvparse->sequenceext;
1011 if (mpvparse->seqdispext_updated)
1012 disp_ext = &mpvparse->sequencedispext;
1013 if (mpvparse->picext_updated)
1014 pic_ext = &mpvparse->picext;
1015 if (mpvparse->quantmatrext_updated)
1016 quant_ext = &mpvparse->quantmatrext;
1017 pic_hdr = &mpvparse->pichdr;
1019 GST_DEBUG_OBJECT (mpvparse,
1020 "Adding GstMpegVideoMeta (slice_count:%d, slice_offset:%d)",
1021 mpvparse->slice_count, mpvparse->slice_offset);
1023 if (frame->out_buffer) {
1024 buf = frame->out_buffer = gst_buffer_make_writable (frame->out_buffer);
1026 buf = frame->buffer = gst_buffer_make_writable (frame->buffer);
1030 gst_buffer_add_mpeg_video_meta (buf, seq_hdr, seq_ext, disp_ext,
1031 pic_hdr, pic_ext, quant_ext);
1032 meta->num_slices = mpvparse->slice_count;
1033 meta->slice_offset = mpvparse->slice_offset;
1036 if (frame->out_buffer) {
1037 parse_buffer = frame->out_buffer =
1038 gst_buffer_make_writable (frame->out_buffer);
1040 parse_buffer = frame->buffer = gst_buffer_make_writable (frame->buffer);
1043 if (pic_ext && !pic_ext->progressive_frame) {
1044 GST_BUFFER_FLAG_SET (parse_buffer, GST_VIDEO_BUFFER_FLAG_INTERLACED);
1045 if (pic_ext->top_field_first)
1046 GST_BUFFER_FLAG_SET (parse_buffer, GST_VIDEO_BUFFER_FLAG_TFF);
1048 gst_video_push_user_data ((GstElement *) mpvparse, &mpvparse->user_data,
1055 gst_mpegv_parse_set_caps (GstBaseParse * parse, GstCaps * caps)
1057 GstMpegvParse *mpvparse = GST_MPEGVIDEO_PARSE (parse);
1059 const GValue *value;
1062 GST_DEBUG_OBJECT (parse, "setcaps called with %" GST_PTR_FORMAT, caps);
1064 s = gst_caps_get_structure (caps, 0);
1066 if ((value = gst_structure_get_value (s, "codec_data")) != NULL
1067 && (buf = gst_value_get_buffer (value))) {
1069 gst_buffer_map (buf, &map, GST_MAP_READ);
1070 /* best possible parse attempt,
1071 * src caps are based on sink caps so it will end up in there
1072 * whether sucessful or not */
1073 mpvparse->seq_offset = 4;
1074 gst_mpegv_parse_process_config (mpvparse, &map, gst_buffer_get_size (buf));
1075 gst_buffer_unmap (buf, &map);
1076 gst_mpegv_parse_reset_frame (mpvparse);
1079 /* let's not interfere and accept regardless of config parsing success */
1084 remove_fields (GstCaps * caps)
1088 n = gst_caps_get_size (caps);
1089 for (i = 0; i < n; i++) {
1090 GstStructure *s = gst_caps_get_structure (caps, i);
1092 gst_structure_remove_field (s, "parsed");
1097 gst_mpegv_parse_get_caps (GstBaseParse * parse, GstCaps * filter)
1099 GstCaps *peercaps, *templ;
1102 templ = gst_pad_get_pad_template_caps (GST_BASE_PARSE_SINK_PAD (parse));
1104 GstCaps *fcopy = gst_caps_copy (filter);
1105 /* Remove the fields we convert */
1106 remove_fields (fcopy);
1107 peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), fcopy);
1108 gst_caps_unref (fcopy);
1110 peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), NULL);
1113 /* Remove the parsed field */
1114 peercaps = gst_caps_make_writable (peercaps);
1115 remove_fields (peercaps);
1117 res = gst_caps_intersect_full (peercaps, templ, GST_CAPS_INTERSECT_FIRST);
1118 gst_caps_unref (peercaps);
1119 gst_caps_unref (templ);
1125 GstCaps *intersection;
1128 gst_caps_intersect_full (filter, res, GST_CAPS_INTERSECT_FIRST);
1129 gst_caps_unref (res);