3 * jpegparse: a parser for JPEG streams
5 * Copyright (C) <2009> Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be>
6 * Víctor Manuel Jáquez Leal <vjaquez@igalia.com>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
25 * SECTION:element-jpegparse
27 * @short_description: JPEG parser
29 * Parses a JPEG stream into JPEG images. It looks for EOI boundaries to
30 * split a continuous stream into single-frame buffers. Also reads the
31 * image header searching for image properties such as width and height
32 * among others. Jpegparse can also extract metadata (e.g. xmp).
34 * ## Example launch line
36 * gst-launch-1.0 -v souphttpsrc location=... ! jpegparse ! matroskamux ! filesink location=...
38 * The above pipeline fetches a motion JPEG stream from an IP camera over
39 * HTTP and stores it in a matroska file.
42 /* FIXME: output plain JFIF APP marker only. This provides best code reuse.
43 * JPEG decoders would not need to handle this part anymore. Also when remuxing
44 * (... ! jpegparse ! ... ! jifmux ! ...) metadata consolidation would be
52 #include <gst/base/gstbytereader.h>
53 #include <gst/tag/tag.h>
55 #include "gstjpegparse.h"
57 static GstStaticPadTemplate gst_jpeg_parse_src_pad_template =
58 GST_STATIC_PAD_TEMPLATE ("src",
61 GST_STATIC_CAPS ("image/jpeg, "
62 "format = (string) { I420, Y41B, UYVY, YV12 }, "
63 "width = (int) [ 0, MAX ],"
64 "height = (int) [ 0, MAX ], "
65 "framerate = (fraction) [ 0/1, MAX ], " "parsed = (boolean) true")
68 static GstStaticPadTemplate gst_jpeg_parse_sink_pad_template =
69 GST_STATIC_PAD_TEMPLATE ("sink",
72 GST_STATIC_CAPS ("image/jpeg")
75 GST_DEBUG_CATEGORY_STATIC (jpeg_parse_debug);
76 #define GST_CAT_DEFAULT jpeg_parse_debug
79 gst_jpeg_parse_handle_frame (GstBaseParse * bparse, GstBaseParseFrame * frame,
81 static gboolean gst_jpeg_parse_set_sink_caps (GstBaseParse * parse,
83 static gboolean gst_jpeg_parse_sink_event (GstBaseParse * parse,
85 static gboolean gst_jpeg_parse_start (GstBaseParse * parse);
86 static gboolean gst_jpeg_parse_stop (GstBaseParse * parse);
87 static GstFlowReturn gst_jpeg_parse_pre_push_frame (GstBaseParse * bparse,
88 GstBaseParseFrame * frame);
90 #define gst_jpeg_parse_parent_class parent_class
91 G_DEFINE_TYPE (GstJpegParse, gst_jpeg_parse, GST_TYPE_BASE_PARSE);
94 gst_jpeg_parse_class_init (GstJpegParseClass * klass)
96 GstBaseParseClass *gstbaseparse_class;
97 GstElementClass *gstelement_class;
99 gstbaseparse_class = (GstBaseParseClass *) klass;
100 gstelement_class = (GstElementClass *) klass;
102 gstbaseparse_class->start = gst_jpeg_parse_start;
103 gstbaseparse_class->stop = gst_jpeg_parse_stop;
104 gstbaseparse_class->set_sink_caps = gst_jpeg_parse_set_sink_caps;
105 gstbaseparse_class->sink_event = gst_jpeg_parse_sink_event;
106 gstbaseparse_class->handle_frame = gst_jpeg_parse_handle_frame;
107 gstbaseparse_class->pre_push_frame = gst_jpeg_parse_pre_push_frame;
109 gst_element_class_add_static_pad_template (gstelement_class,
110 &gst_jpeg_parse_src_pad_template);
111 gst_element_class_add_static_pad_template (gstelement_class,
112 &gst_jpeg_parse_sink_pad_template);
114 gst_element_class_set_static_metadata (gstelement_class,
115 "JPEG stream parser",
117 "Parse JPEG images into single-frame buffers",
118 "Arnout Vandecappelle (Essensium/Mind) <arnout@mind.be>");
120 GST_DEBUG_CATEGORY_INIT (jpeg_parse_debug, "jpegparse", 0, "JPEG parser");
124 gst_jpeg_parse_init (GstJpegParse * parse)
126 parse->next_ts = GST_CLOCK_TIME_NONE;
130 gst_jpeg_parse_set_sink_caps (GstBaseParse * bparse, GstCaps * caps)
132 GstJpegParse *parse = GST_JPEG_PARSE_CAST (bparse);
133 GstStructure *s = gst_caps_get_structure (caps, 0);
134 const GValue *framerate;
136 if ((framerate = gst_structure_get_value (s, "framerate")) != NULL) {
137 if (GST_VALUE_HOLDS_FRACTION (framerate)) {
138 parse->framerate_numerator = gst_value_get_fraction_numerator (framerate);
139 parse->framerate_denominator =
140 gst_value_get_fraction_denominator (framerate);
141 parse->has_fps = TRUE;
142 GST_DEBUG_OBJECT (parse, "got framerate of %d/%d",
143 parse->framerate_numerator, parse->framerate_denominator);
152 * gst_jpeg_parse_skip_to_jpeg_header:
155 * Flush everything until the next JPEG header. The header is considered
156 * to be the a start marker SOI (0xff 0xd8) followed by any other marker
159 * Returns: TRUE if the header was found, FALSE if more data is needed.
162 gst_jpeg_parse_skip_to_jpeg_header (GstJpegParse * parse, GstMapInfo * mapinfo,
166 GstByteReader reader;
168 if (mapinfo->size < 4)
171 gst_byte_reader_init (&reader, mapinfo->data, mapinfo->size);
173 *skipsize = gst_byte_reader_masked_scan_uint32 (&reader, 0xffffff00,
174 0xffd8ff00, 0, mapinfo->size);
175 if (*skipsize == -1) {
176 *skipsize = mapinfo->size - 3; /* Last 3 bytes + 1 more may match header. */
182 static inline gboolean
183 gst_jpeg_parse_parse_tag_has_entropy_segment (guint8 tag)
185 if (tag == SOS || (tag >= RST0 && tag <= RST7))
190 /* returns image length in bytes if parsed successfully,
191 * otherwise 0 if more data needed,
192 * if < 0 the absolute value needs to be flushed */
194 gst_jpeg_parse_get_image_length (GstJpegParse * parse, GstMapInfo * mapinfo)
198 gint offset, noffset;
199 GstByteReader reader;
201 size = mapinfo->size;
202 gst_byte_reader_init (&reader, mapinfo->data, mapinfo->size);
204 /* TODO could be removed as previous functions already guarantee this to be
206 /* we expect at least 4 bytes, first of which start marker */
207 if (gst_byte_reader_masked_scan_uint32 (&reader, 0xffff0000, 0xffd80000, 0,
211 GST_DEBUG ("Parsing jpeg image data (%u bytes)", size);
213 GST_DEBUG ("Parse state: offset=%d, resync=%d, entropy len=%d",
214 parse->last_offset, parse->last_resync, parse->last_entropy_len);
216 /* offset is 2 less than actual offset;
217 * - adapter needs at least 4 bytes for scanning,
218 * - start and end marker ensure at least that much
220 /* resume from state offset */
221 offset = parse->last_offset;
228 gst_byte_reader_masked_scan_uint32_peek (&reader, 0x0000ff00,
229 0x0000ff00, offset, size - offset, &value);
230 /* lost sync if 0xff marker not where expected */
231 if ((resync = (noffset != offset))) {
232 GST_DEBUG ("Lost sync at 0x%08x, resyncing", offset + 2);
234 /* may have marker, but could have been resyncng */
235 resync = resync || parse->last_resync;
236 /* Skip over extra 0xff */
237 while ((noffset >= 0) && ((value & 0xff) == 0xff)) {
240 gst_byte_reader_masked_scan_uint32_peek (&reader, 0x0000ff00,
241 0x0000ff00, noffset, size - noffset, &value);
243 /* enough bytes left for marker? (we need 0xNN after the 0xff) */
245 GST_DEBUG ("at end of input and no EOI marker found, need more data");
249 /* now lock on the marker we found */
251 value = value & 0xff;
253 GST_DEBUG ("0x%08x: EOI marker", offset + 2);
254 /* clear parse state */
255 parse->last_resync = FALSE;
256 parse->last_offset = 0;
258 } else if (value == 0xd8) {
259 /* Skip this frame if we found another SOI marker */
260 GST_DEBUG ("0x%08x: SOI marker before EOI, skipping", offset + 2);
261 /* clear parse state */
262 parse->last_resync = FALSE;
263 parse->last_offset = 0;
264 return -(offset + 2);
267 if (value >= 0xd0 && value <= 0xd7)
270 /* peek tag and subsequent length */
271 if (offset + 2 + 4 > size)
274 gst_byte_reader_masked_scan_uint32_peek (&reader, 0x0, 0x0, offset + 2,
276 frame_len = frame_len & 0xffff;
278 GST_DEBUG ("0x%08x: tag %02x, frame_len=%u", offset + 2, value, frame_len);
279 /* the frame length includes the 2 bytes for the length; here we want at
280 * least 2 more bytes at the end for an end marker */
281 if (offset + 2 + 2 + frame_len + 2 > size) {
285 if (gst_jpeg_parse_parse_tag_has_entropy_segment (value)) {
286 guint eseglen = parse->last_entropy_len;
288 GST_DEBUG ("0x%08x: finding entropy segment length", offset + 2);
289 noffset = offset + 2 + frame_len + eseglen;
291 noffset = gst_byte_reader_masked_scan_uint32_peek (&reader, 0x0000ff00,
292 0x0000ff00, noffset, size - noffset, &value);
295 parse->last_entropy_len = size - offset - 4 - frame_len - 2;
298 if ((value & 0xff) != 0x00) {
299 eseglen = noffset - offset - frame_len - 2;
304 parse->last_entropy_len = 0;
305 frame_len += eseglen;
306 GST_DEBUG ("entropy segment length=%u => frame_len=%u", eseglen,
310 /* check if we will still be in sync if we interpret
311 * this as a sync point and skip this frame */
312 noffset = offset + frame_len + 2;
314 gst_byte_reader_masked_scan_uint32 (&reader, 0x0000ff00, 0x0000ff00,
317 /* ignore and continue resyncing until we hit the end
318 * of our data or find a sync point that looks okay */
322 GST_DEBUG ("found sync at 0x%x", offset + 2);
325 offset += frame_len + 2;
331 parse->last_offset = offset;
332 parse->last_resync = resync;
337 static inline gboolean
338 gst_jpeg_parse_sof (GstJpegParse * parse, GstByteReader * reader)
340 guint8 numcomps = 0; /* Number of components in image
341 (1 for gray, 3 for YUV, etc.) */
342 guint8 precision; /* precision (in bits) for the samples */
343 guint8 compId[3] G_GNUC_UNUSED; /* unique value identifying each component */
344 guint8 qtId[3] G_GNUC_UNUSED; /* quantization table ID to use for this comp */
345 guint8 blockWidth[3]; /* Array[numComponents] giving the number of
346 blocks (horiz) in this component */
347 guint8 blockHeight[3]; /* Same for the vertical part of this component */
351 /* flush length field */
352 if (!gst_byte_reader_skip (reader, 2))
355 /* Get sample precision */
356 if (!gst_byte_reader_get_uint8 (reader, &precision))
360 if (!gst_byte_reader_get_uint16_be (reader, &parse->height))
362 if (!gst_byte_reader_get_uint16_be (reader, &parse->width))
365 /* Get number of components */
366 if (!gst_byte_reader_get_uint8 (reader, &numcomps))
369 if (numcomps > 3) /* FIXME */
372 /* Get decimation and quantization table id for each component */
373 for (i = 0; i < numcomps; i++) {
374 /* Get component ID number */
375 if (!gst_byte_reader_get_uint8 (reader, &value))
380 if (!gst_byte_reader_get_uint8 (reader, &value))
382 blockWidth[i] = (value & 0xf0) >> 4;
383 blockHeight[i] = (value & 0x0f);
385 /* Get quantization table id */
386 if (!gst_byte_reader_get_uint8 (reader, &value))
392 /* gray image - no format */
394 } else if (numcomps == 3) {
395 temp = (blockWidth[0] * blockHeight[0]) / (blockWidth[1] * blockHeight[1]);
397 if (temp == 4 && blockHeight[0] == 2)
398 parse->format = "I420";
399 else if (temp == 4 && blockHeight[0] == 4)
400 parse->format = "Y41B";
402 parse->format = "UYVY";
404 parse->format = "YV12";
411 GST_DEBUG_OBJECT (parse, "Header parsed");
416 static inline gboolean
417 gst_jpeg_parse_skip_marker (GstJpegParse * parse,
418 GstByteReader * reader, guint8 marker)
422 if (!gst_byte_reader_get_uint16_be (reader, &size))
425 #ifndef GST_DISABLE_GST_DEBUG
426 /* We'd pry the id of the skipped application segment */
427 if (marker >= APP0 && marker <= APP15) {
428 const gchar *id_str = NULL;
430 if (gst_byte_reader_peek_string_utf8 (reader, &id_str)) {
431 GST_DEBUG_OBJECT (parse, "unhandled marker %x: '%s' skiping %u bytes",
432 marker, id_str ? id_str : "(NULL)", size);
434 GST_DEBUG_OBJECT (parse, "unhandled marker %x skiping %u bytes", marker,
439 GST_DEBUG_OBJECT (parse, "unhandled marker %x skiping %u bytes", marker,
441 #endif // GST_DISABLE_GST_DEBUG
443 if (!gst_byte_reader_skip (reader, size - 2))
449 static inline GstTagList *
450 get_tag_list (GstJpegParse * parse)
453 parse->tags = gst_tag_list_new_empty ();
458 extract_and_queue_tags (GstJpegParse * parse, guint size, guint8 * data,
459 GstTagList * (*tag_func) (GstBuffer * buff))
464 buf = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, data, size, 0,
467 tags = tag_func (buf);
468 gst_buffer_unref (buf);
471 GstTagList *taglist = parse->tags;
473 gst_tag_list_insert (taglist, tags, GST_TAG_MERGE_REPLACE);
474 gst_tag_list_unref (tags);
478 GST_DEBUG_OBJECT (parse, "collected tags: %" GST_PTR_FORMAT, parse->tags);
482 static inline gboolean
483 gst_jpeg_parse_app1 (GstJpegParse * parse, GstByteReader * reader)
487 const guint8 *data = NULL;
489 if (!gst_byte_reader_get_uint16_be (reader, &size))
492 size -= 2; /* 2 bytes for the mark */
493 if (!gst_byte_reader_peek_string_utf8 (reader, &id_str))
496 if (!strncmp (id_str, "Exif", 4)) {
498 /* skip id + NUL + padding */
499 if (!gst_byte_reader_skip (reader, 6))
503 /* handle exif metadata */
504 if (!gst_byte_reader_get_data (reader, size, &data))
507 extract_and_queue_tags (parse, size, (guint8 *) data,
508 gst_tag_list_from_exif_buffer_with_tiff_header);
510 GST_LOG_OBJECT (parse, "parsed marker %x: '%s' %u bytes",
513 } else if (!strncmp (id_str, "http://ns.adobe.com/xap/1.0/", 28)) {
515 /* skip the id + NUL */
516 if (!gst_byte_reader_skip (reader, 29))
520 /* handle xmp metadata */
521 if (!gst_byte_reader_get_data (reader, size, &data))
524 extract_and_queue_tags (parse, size, (guint8 *) data,
525 gst_tag_list_from_xmp_buffer);
527 GST_LOG_OBJECT (parse, "parsed marker %x: '%s' %u bytes",
531 /* restore the byte position and size */
534 if (!gst_jpeg_parse_skip_marker (parse, reader, APP1))
541 static inline gchar *
542 get_utf8_from_data (const guint8 * data, guint16 size)
544 const gchar *env_vars[] = { "GST_JPEG_TAG_ENCODING",
545 "GST_TAG_ENCODING", NULL
547 const char *str = (gchar *) data;
549 return gst_tag_freeform_string_to_utf8 (str, size, env_vars);
552 /* read comment and post as tag */
553 static inline gboolean
554 gst_jpeg_parse_com (GstJpegParse * parse, GstByteReader * reader)
556 const guint8 *data = NULL;
560 if (!gst_byte_reader_get_uint16_be (reader, &size))
564 if (!gst_byte_reader_get_data (reader, size, &data))
567 comment = get_utf8_from_data (data, size);
570 GstTagList *taglist = get_tag_list (parse);
571 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
572 GST_TAG_COMMENT, comment, NULL);
573 GST_DEBUG_OBJECT (parse, "collected tags: %" GST_PTR_FORMAT, taglist);
581 gst_jpeg_parse_read_header (GstJpegParse * parse, GstMapInfo * map, gint len)
583 GstByteReader reader;
585 gboolean foundSOF = FALSE;
587 gst_byte_reader_init (&reader, map->data, len);
589 if (!gst_byte_reader_peek_uint8 (&reader, &marker))
592 while (marker == 0xff) {
593 if (!gst_byte_reader_skip (&reader, 1))
596 if (!gst_byte_reader_get_uint8 (&reader, &marker))
599 GST_DEBUG_OBJECT (parse, "marker = %x", marker);
602 case SOS: /* start of scan (begins compressed data) */
609 if (!gst_byte_reader_skip (&reader, 4)) /* fixed size */
614 if (!gst_jpeg_parse_com (parse, &reader))
619 if (!gst_jpeg_parse_app1 (parse, &reader))
625 /* Ignore these codes */
626 if (!gst_jpeg_parse_skip_marker (parse, &reader, marker))
631 /* parse Start Of Frame */
632 if (!gst_jpeg_parse_sof (parse, &reader))
639 if (marker == JPG || (marker >= JPG0 && marker <= JPG13) ||
640 (marker >= APP0 && marker <= APP15)) {
641 if (!gst_jpeg_parse_skip_marker (parse, &reader, marker))
647 if (!gst_byte_reader_peek_uint8 (&reader, &marker))
657 GST_WARNING_OBJECT (parse,
658 "Error parsing image header (need more than %u bytes available)",
659 gst_byte_reader_get_remaining (&reader));
664 GST_WARNING_OBJECT (parse, "unhandled marker %x, leaving", marker);
665 /* Not SOF or SOI. Must not be a JPEG file (or file pointer
666 * is placed wrong). In either case, it's an error. */
672 gst_jpeg_parse_set_new_caps (GstJpegParse * parse, gboolean header_ok)
677 GST_DEBUG_OBJECT (parse, "setting caps on srcpad (hdr_ok=%d, have_fps=%d)",
678 header_ok, parse->has_fps);
680 caps = gst_caps_new_simple ("image/jpeg",
681 "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
683 if (header_ok == TRUE) {
684 gst_caps_set_simple (caps,
685 "format", G_TYPE_STRING, parse->format,
686 "width", G_TYPE_INT, parse->width,
687 "height", G_TYPE_INT, parse->height, NULL);
690 if (parse->has_fps == TRUE) {
691 /* we have a framerate */
692 gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION,
693 parse->framerate_numerator, parse->framerate_denominator, NULL);
695 if (!GST_CLOCK_TIME_IS_VALID (parse->duration)
696 && parse->framerate_numerator != 0) {
697 parse->duration = gst_util_uint64_scale_int (GST_SECOND,
698 parse->framerate_denominator, parse->framerate_numerator);
701 /* unknown duration */
702 parse->duration = GST_CLOCK_TIME_NONE;
703 gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, 1, 1, NULL);
706 GST_DEBUG_OBJECT (parse,
707 "setting downstream caps on %s:%s to %" GST_PTR_FORMAT,
708 GST_DEBUG_PAD_NAME (GST_BASE_PARSE_SRC_PAD (parse)), caps);
709 res = gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps);
710 gst_caps_unref (caps);
717 gst_jpeg_parse_pre_push_frame (GstBaseParse * bparse, GstBaseParseFrame * frame)
719 GstJpegParse *parse = GST_JPEG_PARSE_CAST (bparse);
720 GstBuffer *outbuf = frame->buffer;
722 if (parse->has_fps && !GST_CLOCK_TIME_IS_VALID (parse->next_ts))
723 parse->next_ts = bparse->segment.start;
725 GST_BUFFER_TIMESTAMP (outbuf) = parse->next_ts;
727 if (parse->has_fps && GST_CLOCK_TIME_IS_VALID (parse->next_ts)
728 && GST_CLOCK_TIME_IS_VALID (parse->duration)) {
729 parse->next_ts += parse->duration;
731 parse->duration = GST_CLOCK_TIME_NONE;
732 parse->next_ts = GST_CLOCK_TIME_NONE;
735 GST_BUFFER_DURATION (outbuf) = parse->duration;
741 gst_jpeg_parse_handle_frame (GstBaseParse * bparse, GstBaseParseFrame * frame,
744 GstJpegParse *parse = GST_JPEG_PARSE_CAST (bparse);
746 GstClockTime timestamp, duration;
750 timestamp = GST_BUFFER_PTS (frame->buffer);
751 duration = GST_BUFFER_DURATION (frame->buffer);
753 if (!gst_buffer_map (frame->buffer, &mapinfo, GST_MAP_READ)) {
754 return GST_FLOW_ERROR;
757 if (!gst_jpeg_parse_skip_to_jpeg_header (parse, &mapinfo, skipsize)) {
758 gst_buffer_unmap (frame->buffer, &mapinfo);
762 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (parse->next_ts)))
763 parse->next_ts = timestamp;
765 if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (duration)))
766 parse->duration = duration;
768 len = gst_jpeg_parse_get_image_length (parse, &mapinfo);
770 gst_buffer_unmap (frame->buffer, &mapinfo);
772 } else if (len < 0) {
774 gst_buffer_unmap (frame->buffer, &mapinfo);
778 /* check if we already have a EOI */
779 GST_LOG_OBJECT (parse, "parsed image of size %d", len);
781 /* reset the offset (only when we flushed) */
782 parse->last_offset = 0;
783 parse->last_entropy_len = 0;
785 header_ok = gst_jpeg_parse_read_header (parse, &mapinfo, len);
787 gst_buffer_unmap (frame->buffer, &mapinfo);
789 if (parse->width != parse->caps_width
790 || parse->height != parse->caps_height
791 || parse->framerate_numerator !=
792 parse->caps_framerate_numerator
793 || parse->framerate_denominator != parse->caps_framerate_denominator) {
794 if (!gst_jpeg_parse_set_new_caps (parse, header_ok)) {
795 GST_ELEMENT_ERROR (parse, CORE, NEGOTIATION,
796 ("Can't set caps to the src pad"), ("Can't set caps to the src pad"));
797 return GST_FLOW_ERROR;
801 GST_DEBUG_OBJECT (parse, "Pushing tags: %" GST_PTR_FORMAT, parse->tags);
802 gst_pad_push_event (GST_BASE_PARSE_SRC_PAD (parse),
803 gst_event_new_tag (parse->tags));
807 parse->caps_width = parse->width;
808 parse->caps_height = parse->height;
809 parse->caps_framerate_numerator = parse->framerate_numerator;
810 parse->caps_framerate_denominator = parse->framerate_denominator;
814 return gst_base_parse_finish_frame (bparse, frame, len);
818 gst_jpeg_parse_sink_event (GstBaseParse * bparse, GstEvent * event)
820 GstJpegParse *parse = GST_JPEG_PARSE_CAST (bparse);
823 GST_DEBUG_OBJECT (parse, "event : %s", GST_EVENT_TYPE_NAME (event));
825 switch (GST_EVENT_TYPE (event)) {
826 case GST_EVENT_FLUSH_STOP:
827 parse->next_ts = GST_CLOCK_TIME_NONE;
828 parse->duration = GST_CLOCK_TIME_NONE;
829 parse->last_offset = 0;
830 parse->last_entropy_len = 0;
831 parse->last_resync = FALSE;
832 res = GST_BASE_PARSE_CLASS (parent_class)->sink_event (bparse, event);
835 if (gst_pad_has_current_caps (GST_BASE_PARSE_SRC_PAD (parse)))
836 res = GST_BASE_PARSE_CLASS (parent_class)->sink_event (bparse, event);
838 GstTagList *taglist = NULL;
840 gst_event_parse_tag (event, &taglist);
841 /* Hold on to the tags till the srcpad caps are definitely set */
842 gst_tag_list_insert (get_tag_list (parse), taglist,
843 GST_TAG_MERGE_REPLACE);
844 GST_DEBUG ("collected tags: %" GST_PTR_FORMAT, parse->tags);
845 gst_event_unref (event);
850 res = GST_BASE_PARSE_CLASS (parent_class)->sink_event (bparse, event);
858 gst_jpeg_parse_start (GstBaseParse * bparse)
862 parse = GST_JPEG_PARSE_CAST (bparse);
864 parse->has_fps = FALSE;
866 parse->width = parse->height = 0;
867 parse->framerate_numerator = 0;
868 parse->framerate_denominator = 1;
870 parse->caps_framerate_numerator = parse->caps_framerate_denominator = 0;
871 parse->caps_width = parse->caps_height = -1;
873 parse->next_ts = GST_CLOCK_TIME_NONE;
874 parse->duration = GST_CLOCK_TIME_NONE;
876 parse->last_offset = 0;
877 parse->last_entropy_len = 0;
878 parse->last_resync = FALSE;
886 gst_jpeg_parse_stop (GstBaseParse * bparse)
890 parse = GST_JPEG_PARSE_CAST (bparse);
893 gst_tag_list_unref (parse->tags);