From: Ronald S. B. <rb...@pd...> - 2004-01-25 00:24:07
|
CVS Root: /home/cvs/gstreamer Module: gst-plugins Changes by: rbultje Date: Sat Jan 24 2004 16:25:28 PST Log message: 2004-01-25 Ronald Bultje <rb...@ro...> * gst-libs/gst/riff/riff-read.c: (gst_riff_read_info): Additional pad usability check. * gst/mpeg1videoparse/gstmp1videoparse.c: (gst_mp1videoparse_init), (mp1videoparse_find_next_gop), (gst_mp1videoparse_time_code), (gst_mp1videoparse_real_chain): Fix MPEG video stream parsing. The original plugin had several issues, including not timestamping streams where the source was not timestamped (this happens with PTS values in mpeg system streams, but MPEG video is also a valid stream on its own so that needs timestamps too). We use the display time code for that for now. Also, if one incoming buffer contains multiple valid frames, we push them all on correctly now, including proper EOS handling. Lastly, several potential segfaults were fixed, and we properly sync on new sequence/gop headers to include them in next, not previous frames (since they're header for the next frame, not the previous). Also see #119206. * gst/mpegaudioparse/gstmpegaudioparse.c: (gst_mp3parse_chain), (bpf_from_header): Move caps setting so we only do it after finding several valid MPEG-1 fraes sequentially, not right after the first one (which might be coincidental). * gst/typefind/gsttypefindfunctions.c: (mpeg1_sys_type_find), (mpeg_video_type_find), (mpeg_video_stream_type_find), (plugin_init): Add unsynced MPEG video stream typefinding, and change some probability values so we detect streams rightly. The idea is as follows: I can have an unsynced system stream which contains video. In the current code, I would randomly get a type for either system or video stream type found, because the probabilities are being calculated rather randomly. I now use fixed values, so we always prefer system stream if that was found (and that is how it should be). If no system stream was found, we can still identity the stream as video-only. Modified files: . : ChangeLog gst-libs/gst/riff: riff-read.c gst/mpeg1videoparse: gstmp1videoparse.c gst/mpegaudioparse: gstmpegaudioparse.c gst/typefind : gsttypefindfunctions.c Links: http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gst-plugins/ChangeLog.diff?r1=1.195&r2=1.196 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gst-plugins/gst-libs/gst/riff/riff-read.c.diff?r1=1.6&r2=1.7 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gst-plugins/gst/mpeg1videoparse/gstmp1videoparse.c.diff?r1=1.27&r2=1.28 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gst-plugins/gst/mpegaudioparse/gstmpegaudioparse.c.diff?r1=1.33&r2=1.34 http://freedesktop.org/cgi-bin/viewcvs.cgi/gstreamer/gst-plugins/gst/typefind/gsttypefindfunctions.c.diff?r1=1.26&r2=1.27 ====Begin Diffs==== Index: gsttypefindfunctions.c =================================================================== RCS file: /home/cvs/gstreamer/gst-plugins/gst/typefind/gsttypefindfunctions.c,v retrieving revision 1.26 retrieving revision 1.27 diff -u -d -r1.26 -r1.27 --- gsttypefindfunctions.c 23 Jan 2004 16:55:21 -0000 1.26 +++ gsttypefindfunctions.c 25 Jan 2004 00:25:15 -0000 1.27 @@ -569,17 +569,10 @@ g_assert (found <= GST_MPEG_TYPEFIND_TRY_HEADERS); if (found == GST_MPEG_TYPEFIND_TRY_HEADERS || packet_size == 1) { - guint probability = found * GST_TYPE_FIND_MAXIMUM * - (GST_MPEG_TYPEFIND_TRY_SYNC - skipped) / - GST_MPEG_TYPEFIND_TRY_HEADERS / GST_MPEG_TYPEFIND_TRY_SYNC; - - if (probability < GST_TYPE_FIND_MINIMUM) - probability = GST_TYPE_FIND_MINIMUM; - g_assert (probability <= GST_TYPE_FIND_MAXIMUM); caps = MPEG_SYS_CAPS; gst_structure_set (gst_caps_get_structure (caps, 0), "mpegversion", G_TYPE_INT, 1, 0); - gst_type_find_suggest (tf, probability, caps); + gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM - 1, caps); return; } } @@ -603,7 +596,96 @@ data = gst_type_find_peek (tf, 0, 8); if (data && memcmp(data, sequence_header, 4)==0){ - gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, MPEG_VIDEO_CAPS); + GstCaps *caps = MPEG_VIDEO_CAPS; + gst_structure_set (gst_caps_get_structure (caps, 0), "mpegversion", + G_TYPE_INT, 1, 0); + gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM - 1, caps); + } +} + +/* + * Idea is the same as MPEG system stream typefinding: We check each + * byte of the stream to see if - from that point on - the stream + * matches a predefined set of marker bits as defined in the MPEG + * video specs. + * + * I'm sure someone will do a chance calculation here too. + */ + +#define GST_MPEGVID_TYPEFIND_TRY_PICTURES 6 +#define GST_MPEGVID_TYPEFIND_TRY_SYNC (100 * 1024) /* 100 kB */ +#define GST_MPEGVID_TYPEFIND_SYNC_SIZE 2048 + +static void +mpeg_video_stream_type_find (GstTypeFind *tf, gpointer unused) +{ + gint size = 0, found = 0; + guint64 skipped = 0; + guint8 *data = NULL; + + while (1) { + if (found >= GST_MPEGVID_TYPEFIND_TRY_PICTURES) { + GstCaps *caps = MPEG_VIDEO_CAPS; + gst_structure_set (gst_caps_get_structure (caps, 0), "mpegversion", + G_TYPE_INT, 1, 0); + gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM - 2, caps); + return; + } + + if (skipped > GST_MPEGVID_TYPEFIND_TRY_SYNC) + break; + + if (size < 4) { + data = gst_type_find_peek (tf, skipped, GST_MPEGVID_TYPEFIND_SYNC_SIZE); + if (!data) + break; + size = GST_MPEGVID_TYPEFIND_SYNC_SIZE; + } + + /* are we a sequence (0xB3) or GOP (0xB8) header? */ + if (data[0] == 0x0 && data[1] == 0x0 && data[2] == 0x1 && + (data[3] == 0xB3 || data[3] == 0xB8)) { + size -= 8; + data += 8; + skipped += 8; + if (data[3] == 0xB3) + continue; + else if (size < 4) { + data = gst_type_find_peek (tf, skipped, GST_MPEGVID_TYPEFIND_SYNC_SIZE); + size = GST_MPEGVID_TYPEFIND_SYNC_SIZE; + if (!data) + break; + } + /* else, we should now see an image */ + } + + /* image header (and, when found, slice header) */ + if (data[0] == 0x0 && data[1] == 0x0 && + data[2] == 0x1 && data[4] == 0x0) { + size -= 8; + data += 8; + skipped += 8; + if (size < 5) { + data = gst_type_find_peek (tf, skipped, GST_MPEGVID_TYPEFIND_SYNC_SIZE); + size = GST_MPEGVID_TYPEFIND_SYNC_SIZE; + if (!data) + break; + } + if ((data[0] == 0x0 && data[1] == 0x0 && + data[2] == 0x1 && data[3] == 0x1) || + (data[1] == 0x0 && data[2] == 0x0 && + data[3] == 0x1 && data[4] == 0x1)) { + size -= 4; + data += 4; + skipped += 4; + found += 1; + continue; + } + } + + size--; + data++; + skipped++; } } @@ -1141,6 +1223,8 @@ ogg_exts, "OggS", 4, GST_TYPE_FIND_MAXIMUM); TYPE_FIND_REGISTER (plugin, "video/mpeg", GST_RANK_SECONDARY, mpeg_video_type_find, mpeg_video_exts, MPEG_VIDEO_CAPS, NULL); + TYPE_FIND_REGISTER (plugin, "video/mpeg", GST_RANK_MARGINAL, + mpeg_video_stream_type_find, mpeg_video_exts, MPEG_VIDEO_CAPS, NULL); TYPE_FIND_REGISTER (plugin, "video/quicktime", GST_RANK_SECONDARY, qt_type_find, qt_exts, QT_CAPS, NULL); TYPE_FIND_REGISTER_START_WITH (plugin, "application/vnd.rn-realmedia", GST_RANK_SECONDARY, Index: gstmpegaudioparse.c =================================================================== RCS file: /home/cvs/gstreamer/gst-plugins/gst/mpegaudioparse/gstmpegaudioparse.c,v retrieving revision 1.33 retrieving revision 1.34 diff -u -d -r1.33 -r1.34 --- gstmpegaudioparse.c 2 Jan 2004 07:09:23 -0000 1.33 +++ gstmpegaudioparse.c 25 Jan 2004 00:25:15 -0000 1.34 @@ -402,6 +402,26 @@ GST_DEBUG ("mp3parse: partial buffer needed %ld < %d ",(size-offset), bpf); break; } else { + guint bitrate, layer, rate, channels; + + if (!mp3_type_frame_length_from_header (header, &layer, + &channels, + &bitrate, &rate)) { + g_error("Header failed internal error"); + } + if (channels != mp3parse->channels || + rate != mp3parse->rate || + layer != mp3parse->layer || + bitrate != mp3parse->bit_rate) { + GstCaps *caps = mp3_caps_create (layer, channels, bitrate, rate); + + gst_pad_set_explicit_caps(mp3parse->srcpad, caps); + + mp3parse->channels = channels; + mp3parse->layer = layer; + mp3parse->rate = rate; + mp3parse->bit_rate = bitrate; + } outbuf = gst_buffer_create_sub(mp3parse->partialbuf,offset,bpf); @@ -460,20 +480,6 @@ return 0; } - if (channels != parse->channels || - rate != parse->rate || - layer != parse->layer || - bitrate != parse->bit_rate) { - GstCaps *caps = mp3_caps_create (layer, channels, bitrate, rate); - - gst_pad_set_explicit_caps(parse->srcpad, caps); - - parse->channels = channels; - parse->layer = layer; - parse->rate = rate; - parse->bit_rate = bitrate; - } - return length; } Index: gstmp1videoparse.c =================================================================== RCS file: /home/cvs/gstreamer/gst-plugins/gst/mpeg1videoparse/gstmp1videoparse.c,v retrieving revision 1.27 retrieving revision 1.28 diff -u -d -r1.27 -r1.28 --- gstmp1videoparse.c 2 Jan 2004 07:09:23 -0000 1.27 +++ gstmp1videoparse.c 25 Jan 2004 00:25:15 -0000 1.28 @@ -155,7 +155,7 @@ mp1videoparse->partialbuf = NULL; mp1videoparse->need_resync = FALSE; - mp1videoparse->last_pts = 0; + mp1videoparse->last_pts = GST_CLOCK_TIME_NONE; mp1videoparse->picture_in_buffer = 0; mp1videoparse->width = mp1videoparse->height = -1; mp1videoparse->fps = mp1videoparse->asr = 0.; @@ -259,8 +259,9 @@ have_sync = TRUE; } else if (have_sync) { - if (byte == (SEQ_START_CODE & 0xff) || byte == (GOP_START_CODE & 0xff)) return offset-4; - else { + if (byte == (SEQ_START_CODE & 0xff) || byte == (GOP_START_CODE & 0xff)) { + return offset - 4; + } else { sync_zeros = 0; have_sync = FALSE; } @@ -272,6 +273,19 @@ return -1; } + +static guint64 +gst_mp1videoparse_time_code (guchar *gop, + gfloat fps) +{ + guint32 data = GUINT32_FROM_BE (* (guint32 *) gop); + + return ((((data & 0xfc000000) >> 26) * 3600 * GST_SECOND) + /* hours */ + (((data & 0x03f00000) >> 20) * 60 * GST_SECOND) + /* minutes */ + (((data & 0x0007e000) >> 13) * GST_SECOND) + /* seconds */ + (((data & 0x00001f80) >> 7) * GST_SECOND / fps)); /* frames */ +} + static void gst_mp1videoparse_flush (Mp1VideoParse *mp1videoparse) { @@ -370,7 +384,7 @@ mp1videoparse->partialbuf) || mp1videoparse->need_resync) { sync_pos = mp1videoparse_find_next_gop(mp1videoparse, mp1videoparse->partialbuf); - if (sync_pos != -1) { + if (sync_pos >= 0) { mp1videoparse->need_resync = FALSE; GST_DEBUG ("mp1videoparse: found new gop at %d", sync_pos); @@ -383,6 +397,14 @@ size = GST_BUFFER_SIZE(mp1videoparse->partialbuf); offset = 0; } + + head = GUINT32_FROM_BE(*((guint32 *)data)); + /* re-call this function so that if we hadn't already, we can + * now read the sequence header and parse video properties, + * set caps, stream data, be happy, bla, bla, bla... */ + if (!mp1videoparse_valid_sync (mp1videoparse, head, + mp1videoparse->partialbuf)) + g_error ("Found sync but no valid sync point at pos 0x0"); } else { GST_DEBUG ("mp1videoparse: could not sync"); @@ -392,7 +414,8 @@ } } - if (mp1videoparse->picture_in_buffer == 1) { + if (mp1videoparse->picture_in_buffer == 1 && + time_stamp != GST_CLOCK_TIME_NONE) { mp1videoparse->last_pts = time_stamp; } @@ -403,7 +426,6 @@ while (offset < size-1) { sync_byte = *(data + offset); - /*printf(" %d %02x\n", offset, sync_byte); */ if (sync_byte == 0) { sync_state++; } @@ -412,7 +434,9 @@ if (data[offset+1] == (PICTURE_START_CODE & 0xff)) { mp1videoparse->picture_in_buffer++; if (mp1videoparse->picture_in_buffer == 1) { - mp1videoparse->last_pts = time_stamp; + if (time_stamp != GST_CLOCK_TIME_NONE) { + mp1videoparse->last_pts = time_stamp; + } sync_state = 0; } else if (mp1videoparse->picture_in_buffer == 2) { @@ -424,6 +448,33 @@ g_assert_not_reached(); } } + /* A new sequence (or GOP) is a valid sync too. Note that the + * sequence header should be put in the next buffer, not here. */ + else if (data[offset+1] == (SEQ_START_CODE & 0xFF) || + data[offset+1] == (GOP_START_CODE & 0xFF)) { + if (mp1videoparse->picture_in_buffer == 0 && + data[offset+1] == (GOP_START_CODE & 0xFF)) { + mp1videoparse->last_pts = gst_mp1videoparse_time_code (&data[2], + mp1videoparse->fps); + } + else if (mp1videoparse->picture_in_buffer == 1) { + have_sync = TRUE; + break; + } else { + g_assert (mp1videoparse->picture_in_buffer == 0); + } + } + /* end-of-sequence is a valid sync point and should be included + * in the current picture, not the next. */ + else if (data[offset+1] == (SEQ_END_CODE & 0xFF)) { + if (mp1videoparse->picture_in_buffer == 1) { + offset += 4; + have_sync = TRUE; + break; + } else { + g_assert (mp1videoparse->picture_in_buffer == 0); + } + } else sync_state = 0; } /* something else... */ @@ -434,12 +485,11 @@ if (have_sync) { offset -= 2; - GST_DEBUG ("mp1videoparse: synced at %ld code 0x000001%02x",offset,data[offset+3]); - - outbuf = gst_buffer_create_sub(mp1videoparse->partialbuf, 0, offset+4); + outbuf = gst_buffer_create_sub(mp1videoparse->partialbuf, 0, offset); g_assert(outbuf != NULL); GST_BUFFER_TIMESTAMP(outbuf) = mp1videoparse->last_pts; GST_BUFFER_DURATION(outbuf) = GST_SECOND / mp1videoparse->fps; + mp1videoparse->last_pts += GST_BUFFER_DURATION (outbuf); if (mp1videoparse->in_flush) { /* FIXME, send a flush event here */ @@ -456,12 +506,17 @@ } mp1videoparse->picture_in_buffer = 0; - temp = gst_buffer_create_sub(mp1videoparse->partialbuf, offset, size-offset); + if (size > offset) + temp = gst_buffer_create_sub(mp1videoparse->partialbuf, offset, size-offset); + else + temp = NULL; gst_buffer_unref(mp1videoparse->partialbuf); mp1videoparse->partialbuf = temp; } else { - mp1videoparse->last_pts = time_stamp; + if (time_stamp != GST_CLOCK_TIME_NONE) { + mp1videoparse->last_pts = time_stamp; + } } } Index: riff-read.c =================================================================== RCS file: /home/cvs/gstreamer/gst-plugins/gst-libs/gst/riff/riff-read.c,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- riff-read.c 23 Jan 2004 14:03:16 -0000 1.6 +++ riff-read.c 25 Jan 2004 00:25:16 -0000 1.7 @@ -815,7 +815,7 @@ /* let the world know about this wonderful thing */ for (padlist = gst_element_get_pad_list (element); padlist != NULL; padlist = padlist->next) { - if (GST_PAD_IS_SRC (padlist->data)) { + if (GST_PAD_IS_SRC (padlist->data) && GST_PAD_IS_USABLE(padlist->data)) { gst_event_ref (event); gst_pad_push (GST_PAD (padlist->data), GST_DATA (event)); } Index: ChangeLog =================================================================== RCS file: /home/cvs/gstreamer/gst-plugins/ChangeLog,v retrieving revision 1.195 retrieving revision 1.196 diff -u -d -r1.195 -r1.196 --- ChangeLog 23 Jan 2004 17:45:54 -0000 1.195 +++ ChangeLog 25 Jan 2004 00:25:16 -0000 1.196 @@ -1,3 +1,38 @@ +2004-01-25 Ronald Bultje <rb...@ro...> + + * gst-libs/gst/riff/riff-read.c: (gst_riff_read_info): + Additional pad usability check. + * gst/mpeg1videoparse/gstmp1videoparse.c: (gst_mp1videoparse_init), + (mp1videoparse_find_next_gop), (gst_mp1videoparse_time_code), + (gst_mp1videoparse_real_chain): + Fix MPEG video stream parsing. The original plugin had several + issues, including not timestamping streams where the source was + not timestamped (this happens with PTS values in mpeg system + streams, but MPEG video is also a valid stream on its own so + that needs timestamps too). We use the display time code for that + for now. Also, if one incoming buffer contains multiple valid + frames, we push them all on correctly now, including proper EOS + handling. Lastly, several potential segfaults were fixed, and we + properly sync on new sequence/gop headers to include them in next, + not previous frames (since they're header for the next frame, not + the previous). Also see #119206. + * gst/mpegaudioparse/gstmpegaudioparse.c: (gst_mp3parse_chain), + (bpf_from_header): + Move caps setting so we only do it after finding several valid + MPEG-1 fraes sequentially, not right after the first one (which + might be coincidental). + * gst/typefind/gsttypefindfunctions.c: (mpeg1_sys_type_find), + (mpeg_video_type_find), (mpeg_video_stream_type_find), + (plugin_init): + Add unsynced MPEG video stream typefinding, and change some + probability values so we detect streams rightly. The idea is as + follows: I can have an unsynced system stream which contains + video. In the current code, I would randomly get a type for either + system or video stream type found, because the probabilities are + being calculated rather randomly. I now use fixed values, so we + always prefer system stream if that was found (and that is how it + should be). If no system stream was found, we can still identity the stream as video-only. + 2004-01-23 Benjamin Otte <in...@pu...> * gst/avi/gstavidemux.c: (gst_avi_demux_stream_avih), |