diff --git a/ChangeLog b/ChangeLog index 10d1943244..f9b01e18b5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,32 @@ +2005-02-02 Jan Schmidt + + * ext/mpeg2dec/gstmpeg2dec.c: + Don't send things to NULL PAD_PEERs + + * gst/deinterlace/gstdeinterlace.c: (gst_deinterlace_chain): + Copy-on-write the incoming buffer. + + * gst/mpegstream/gstdvddemux.h: + * gst/mpegstream/gstmpegclock.h: + * gst/mpegstream/gstmpegdemux.c: (gst_mpeg_demux_parse_syshead), + (normal_seek), (gst_mpeg_demux_handle_src_event): + * gst/mpegstream/gstmpegdemux.h: + * gst/mpegstream/gstmpegpacketize.h: + * gst/mpegstream/gstmpegparse.c: + (gst_mpeg_parse_update_streaminfo), (gst_mpeg_parse_reset), + (gst_mpeg_parse_handle_discont), (gst_mpeg_parse_parse_packhead), + (gst_mpeg_parse_loop), (gst_mpeg_parse_get_rate), + (gst_mpeg_parse_convert_src), (gst_mpeg_parse_handle_src_query), + (gst_mpeg_parse_handle_src_event), (gst_mpeg_parse_change_state): + * gst/mpegstream/gstmpegparse.h: + * gst/mpegstream/gstrfc2250enc.h: + Various changes to the way time is computed that make seeking and + total time estimation much better here. + Use G_BEGIN/END_DECLS instead of __cplusplus + + * gst/videocrop/gstvideocrop.c: (gst_video_crop_chain): + Use gst_buffer_stamp instead of only copying the TIMESTAMP + 2005-02-01 Ronald S. Bultje * gst/subparse/gstsubparse.c: diff --git a/ext/mpeg2dec/gstmpeg2dec.c b/ext/mpeg2dec/gstmpeg2dec.c index 84aae6c685..d007d916ce 100644 --- a/ext/mpeg2dec/gstmpeg2dec.c +++ b/ext/mpeg2dec/gstmpeg2dec.c @@ -1062,7 +1062,7 @@ gst_mpeg2dec_src_query (GstPad * pad, GstQueryType type, { gboolean res = TRUE; GstMpeg2dec *mpeg2dec; - static const GstFormat *formats; + static const GstFormat *formats = NULL; mpeg2dec = GST_MPEG2DEC (gst_pad_get_parent (pad)); @@ -1077,10 +1077,11 @@ gst_mpeg2dec_src_query (GstPad * pad, GstQueryType type, res = FALSE; /* get our peer formats */ - formats = gst_pad_get_formats (GST_PAD_PEER (mpeg2dec->sinkpad)); + if (GST_PAD_PEER (mpeg2dec->sinkpad)) + formats = gst_pad_get_formats (GST_PAD_PEER (mpeg2dec->sinkpad)); /* while we did not exhaust our seek formats without result */ - while (formats && *formats) { + while (formats && *formats && !res) { GstFormat peer_format; gint64 peer_value; @@ -1152,7 +1153,7 @@ index_seek (GstPad * pad, GstEvent * event) GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_KEY_UNIT, GST_EVENT_SEEK_FORMAT (event), GST_EVENT_SEEK_OFFSET (event)); - if (entry) { + if ((entry) && GST_PAD_PEER (mpeg2dec->sinkpad)) { const GstFormat *peer_formats, *try_formats; /* since we know the exact byteoffset of the frame, make sure to seek on bytes first */ @@ -1202,7 +1203,7 @@ normal_seek (GstPad * pad, GstEvent * event) gint64 src_offset; gboolean flush; GstFormat format; - const GstFormat *peer_formats; + const GstFormat *peer_formats = NULL; gboolean res = FALSE; GstMpeg2dec *mpeg2dec; @@ -1222,7 +1223,8 @@ normal_seek (GstPad * pad, GstEvent * event) flush = GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH; /* get our peer formats */ - peer_formats = gst_pad_get_formats (GST_PAD_PEER (mpeg2dec->sinkpad)); + if (GST_PAD_PEER (mpeg2dec->sinkpad)) + peer_formats = gst_pad_get_formats (GST_PAD_PEER (mpeg2dec->sinkpad)); /* while we did not exhaust our seek formats without result */ while (peer_formats && *peer_formats) { @@ -1288,7 +1290,11 @@ gst_mpeg2dec_src_event (GstPad * pad, GstEvent * event) break; case GST_EVENT_NAVIGATION: /* Forward a navigation event unchanged */ - return gst_pad_send_event (GST_PAD_PEER (mpeg2dec->sinkpad), event); + if (GST_PAD_PEER (mpeg2dec->sinkpad)) + return gst_pad_send_event (GST_PAD_PEER (mpeg2dec->sinkpad), event); + + res = FALSE; + break; default: res = FALSE; break; diff --git a/gst/mpegstream/gstdvddemux.h b/gst/mpegstream/gstdvddemux.h index 002cfe5c71..dd9a876870 100644 --- a/gst/mpegstream/gstdvddemux.h +++ b/gst/mpegstream/gstdvddemux.h @@ -25,11 +25,7 @@ #include #include "gstmpegdemux.h" - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - +G_BEGIN_DECLS #define GST_TYPE_DVD_DEMUX \ (gst_dvd_demux_get_type()) @@ -139,10 +135,6 @@ GType gst_dvd_demux_get_type (void); gboolean gst_dvd_demux_plugin_init (GstPlugin *plugin); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - +G_END_DECLS #endif /* __DVD_DEMUX_H__ */ diff --git a/gst/mpegstream/gstmpegclock.h b/gst/mpegstream/gstmpegclock.h index b7a4ae6fa3..718b95ebf1 100644 --- a/gst/mpegstream/gstmpegclock.h +++ b/gst/mpegstream/gstmpegclock.h @@ -26,10 +26,7 @@ #include -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - +G_BEGIN_DECLS #define GST_TYPE_MPEG_CLOCK \ (gst_mpeg_clock_get_type()) @@ -63,9 +60,6 @@ GType gst_mpeg_clock_get_type (void); GstClock* gst_mpeg_clock_new (gchar *name, GstMPEGClockGetTimeFunc func, gpointer user_data); -#ifdef __cplusplus -} -#endif /* __cplusplus */ - +G_END_DECLS #endif /* __GST_MPEG_CLOCK_H__ */ diff --git a/gst/mpegstream/gstmpegdemux.c b/gst/mpegstream/gstmpegdemux.c index b49edbe533..4be7d457dd 100644 --- a/gst/mpegstream/gstmpegdemux.c +++ b/gst/mpegstream/gstmpegdemux.c @@ -551,6 +551,9 @@ gst_mpeg_demux_parse_syshead (GstMPEGParse * mpeg_parse, GstBuffer * buffer) gint stream_count = (header_length - 6) / 3; gint i, j = 0; + /* Reset the total_size_bound before counting it up */ + mpeg_demux->total_size_bound = 0; + GST_DEBUG_OBJECT (mpeg_demux, "number of streams: %d ", stream_count); for (i = 0; i < stream_count; i++) { @@ -618,19 +621,6 @@ gst_mpeg_demux_parse_syshead (GstMPEGParse * mpeg_parse, GstBuffer * buffer) outstream->index_id = _demux_get_writer_id (mpeg_demux->index, outstream->pad); } - - if (GST_PAD_IS_USABLE (outstream->pad)) { - GstEvent *event; - GstClockTime time; - - time = MPEGTIME_TO_GSTTIME (mpeg_parse->current_scr - + mpeg_parse->adjust) + mpeg_demux->adjust; - - event = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, - time, NULL); - - gst_pad_push (outstream->pad, GST_DATA (event)); - } } j++; @@ -1024,7 +1014,7 @@ normal_seek (GstPad * pad, GstEvent * event, gint64 * offset) if (res) { *offset = MAX (GST_EVENT_SEEK_OFFSET (event) - adjust, 0); - GST_CAT_DEBUG (GST_CAT_SEEK, "%s:%s guestimate %" G_GINT64_FORMAT + GST_CAT_DEBUG (GST_CAT_SEEK, "%s:%s guesstimate %" G_GINT64_FORMAT " %s -> %" G_GINT64_FORMAT " (total_size_bound = %" G_GINT64_FORMAT ")", GST_DEBUG_PAD_NAME (pad), @@ -1063,9 +1053,12 @@ gst_mpeg_demux_handle_src_event (GstPad * pad, GstEvent * event) break; } case GST_EVENT_NAVIGATION: - return gst_pad_send_event (GST_PAD_PEER (GST_MPEG_PARSE (mpeg_demux)-> - sinkpad), event); - break; + { + GstPad *out = GST_PAD_PEER (GST_MPEG_PARSE (mpeg_demux)->sinkpad); + + if (out && GST_PAD_IS_USABLE (out)) + return gst_pad_send_event (out, event); + } default: gst_event_unref (event); break; diff --git a/gst/mpegstream/gstmpegdemux.h b/gst/mpegstream/gstmpegdemux.h index a130b4a98f..48c80934a4 100644 --- a/gst/mpegstream/gstmpegdemux.h +++ b/gst/mpegstream/gstmpegdemux.h @@ -25,11 +25,7 @@ #include #include "gstmpegparse.h" - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - +G_BEGIN_DECLS #define GST_TYPE_MPEG_DEMUX \ (gst_mpeg_demux_get_type()) @@ -188,9 +184,6 @@ GType gst_mpeg_demux_get_type (void); gboolean gst_mpeg_demux_plugin_init (GstPlugin *plugin); -#ifdef __cplusplus -} -#endif /* __cplusplus */ - +G_END_DECLS #endif /* __MPEG_DEMUX_H__ */ diff --git a/gst/mpegstream/gstmpegpacketize.h b/gst/mpegstream/gstmpegpacketize.h index c632cc70ce..1e844d9b52 100644 --- a/gst/mpegstream/gstmpegpacketize.h +++ b/gst/mpegstream/gstmpegpacketize.h @@ -25,10 +25,7 @@ #include #include - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ +G_BEGIN_DECLS #define PICTURE_START_CODE 0x00 #define SLICE_MIN_START_CODE 0x01 @@ -71,9 +68,6 @@ void gst_mpeg_packetize_destroy (GstMPEGPacketize *packetize); GstData* gst_mpeg_packetize_read (GstMPEGPacketize *packetize); -#ifdef __cplusplus -} -#endif /* __cplusplus */ - +G_END_DECLS #endif /* __MPEGPACKETIZE_H__ */ diff --git a/gst/mpegstream/gstmpegparse.c b/gst/mpegstream/gstmpegparse.c index e4a1aac934..4b07d0e5da 100644 --- a/gst/mpegstream/gstmpegparse.c +++ b/gst/mpegstream/gstmpegparse.c @@ -27,12 +27,20 @@ static GstFormat scr_format; - GST_DEBUG_CATEGORY_STATIC (gstmpegparse_debug); #define GST_CAT_DEFAULT (gstmpegparse_debug) GST_DEBUG_CATEGORY_EXTERN (GST_CAT_SEEK); +#define MP_INVALID_SCR ((guint64)(-1)) +#define MP_MUX_RATE_MULT 50 +#define MP_MIN_VALID_BSS 8192 +#define MP_MAX_VALID_BSS 16384 +/* + * Hysteresis value to limit the + * total predicted time skipping about + */ +#define MP_SCR_RATE_HYST 0.08 /* elementfactory information */ static GstElementDetails mpeg_parse_details = { @@ -266,7 +274,7 @@ gst_mpeg_parse_update_streaminfo (GstMPEGParse * mpeg_parse) gst_props_add_entry (props, (GstPropsEntry *) entry); entry = - gst_props_entry_new ("bitrate", G_TYPE_INT (mpeg_parse->mux_rate * 400)); + gst_props_entry_new ("bitrate", G_TYPE_INT (mpeg_parse->mux_rate * 8)); gst_props_add_entry (props, (GstPropsEntry *) entry); caps = gst_caps_new ("mpeg_streaminfo", @@ -277,6 +285,27 @@ gst_mpeg_parse_update_streaminfo (GstMPEGParse * mpeg_parse) } #endif +static void +gst_mpeg_parse_reset (GstMPEGParse * mpeg_parse) +{ + mpeg_parse->current_scr = 0; + mpeg_parse->bytes_since_scr = 0; + mpeg_parse->avg_bitrate_time = 0; + mpeg_parse->avg_bitrate_bytes = 0; + mpeg_parse->first_scr = MP_INVALID_SCR; + mpeg_parse->first_scr_pos = 0; + mpeg_parse->last_scr = MP_INVALID_SCR; + mpeg_parse->last_scr_pos = 0; + mpeg_parse->scr_rate = 0; + + mpeg_parse->adjust = 0; + mpeg_parse->next_scr = 0; + mpeg_parse->mux_rate = 0; + + mpeg_parse->discont_pending = FALSE; + mpeg_parse->scr_pending = FALSE; +} + static void gst_mpeg_parse_handle_discont (GstMPEGParse * mpeg_parse, GstEvent * event) { @@ -284,6 +313,10 @@ gst_mpeg_parse_handle_discont (GstMPEGParse * mpeg_parse, GstEvent * event) g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_DISCONTINUOUS); + if (GST_EVENT_DISCONT_NEW_MEDIA (event)) { + gst_mpeg_parse_reset (mpeg_parse); + } + if (gst_event_discont_get_value (event, GST_FORMAT_TIME, &time) && (GST_CLOCK_TIME_IS_VALID (time))) { GST_DEBUG_OBJECT (mpeg_parse, "forwarding discontinuity, time: %0.3fs", @@ -423,15 +456,28 @@ gst_mpeg_parse_parse_packhead (GstMPEGParse * mpeg_parse, GstBuffer * buffer) new_rate |= ((gint32) buf[1]) << 7; new_rate |= buf[2] >> 1; } + new_rate *= MP_MUX_RATE_MULT; prev_scr = mpeg_parse->current_scr; mpeg_parse->current_scr = scr; mpeg_parse->scr_pending = FALSE; - if (mpeg_parse->next_scr == -1) { + if (mpeg_parse->next_scr == MP_INVALID_SCR) { mpeg_parse->next_scr = mpeg_parse->current_scr; } + if ((mpeg_parse->first_scr == MP_INVALID_SCR) || + (mpeg_parse->current_scr < mpeg_parse->first_scr)) { + mpeg_parse->first_scr = mpeg_parse->current_scr; + mpeg_parse->first_scr_pos = gst_bytestream_tell (mpeg_parse->packetize->bs); + } + + if ((mpeg_parse->last_scr == MP_INVALID_SCR) || + (mpeg_parse->current_scr > mpeg_parse->last_scr)) { + mpeg_parse->last_scr = mpeg_parse->current_scr; + mpeg_parse->last_scr_pos = gst_bytestream_tell (mpeg_parse->packetize->bs); + } + GST_LOG_OBJECT (mpeg_parse, "SCR is %" G_GUINT64_FORMAT " (%" G_GUINT64_FORMAT ") next: %" @@ -449,9 +495,9 @@ gst_mpeg_parse_parse_packhead (GstMPEGParse * mpeg_parse, GstBuffer * buffer) if (ABS ((gint64) mpeg_parse->next_scr - (gint64) (scr)) > mpeg_parse->max_discont) { GST_DEBUG ("discontinuity detected; expected: %" G_GUINT64_FORMAT " got: %" - G_GUINT64_FORMAT " real:%" G_GINT64_FORMAT " adjust:%" G_GINT64_FORMAT, - mpeg_parse->next_scr, mpeg_parse->current_scr + mpeg_parse->adjust, - mpeg_parse->current_scr, mpeg_parse->adjust); + G_GUINT64_FORMAT " adjusted:%" G_GINT64_FORMAT " adjust:%" + G_GINT64_FORMAT, mpeg_parse->next_scr, mpeg_parse->current_scr, + mpeg_parse->current_scr + mpeg_parse->adjust, mpeg_parse->adjust); if (mpeg_parse->do_adjust) { if (mpeg_parse->use_adjust) { @@ -472,23 +518,39 @@ gst_mpeg_parse_parse_packhead (GstMPEGParse * mpeg_parse, GstBuffer * buffer) GST_FORMAT_TIME, MPEGTIME_TO_GSTTIME (mpeg_parse->current_scr), 0); } + if (mpeg_parse->current_scr > prev_scr) { + mpeg_parse->avg_bitrate_time += + MPEGTIME_TO_GSTTIME (mpeg_parse->current_scr - prev_scr); + mpeg_parse->avg_bitrate_bytes += mpeg_parse->bytes_since_scr; + } + if (mpeg_parse->mux_rate != new_rate) { if (GST_MPEG_PACKETIZE_IS_MPEG2 (mpeg_parse->packetize)) { mpeg_parse->mux_rate = new_rate; - } else { + } else if (mpeg_parse->avg_bitrate_bytes > MP_MIN_VALID_BSS) { mpeg_parse->mux_rate = - (double) mpeg_parse->bytes_since_scr / - MPEGTIME_TO_GSTTIME (mpeg_parse->current_scr - - prev_scr) / 50 * 1000000000; + GST_SECOND * mpeg_parse->avg_bitrate_bytes / + mpeg_parse->avg_bitrate_time; } - //gst_mpeg_parse_update_streaminfo (mpeg_parse); - GST_DEBUG ("stream is %1.3fMbs, calculated over %1.3fkB", - (mpeg_parse->mux_rate * 400) / 1000000.0, - mpeg_parse->bytes_since_scr / 1000.0); + GST_DEBUG ("stream current is %1.3fMbs, calculated over %1.3fkB", + (mpeg_parse->mux_rate * 8) / 1048576.0, + mpeg_parse->bytes_since_scr / 1024.0); + } + + if (mpeg_parse->avg_bitrate_bytes > MP_MAX_VALID_BSS) { + mpeg_parse->avg_bitrate_bytes = 0; + mpeg_parse->avg_bitrate_time = 0; } mpeg_parse->bytes_since_scr = 0; + if (mpeg_parse->avg_bitrate_bytes) { + GST_DEBUG ("stream avg is %1.3fMbs, calculated over %1.3fkB", + (float) (mpeg_parse->avg_bitrate_bytes) * 8 * GST_SECOND + / mpeg_parse->avg_bitrate_time / 1048576.0, + mpeg_parse->avg_bitrate_bytes / 1024.0); + } + return TRUE; } @@ -607,12 +669,12 @@ gst_mpeg_parse_loop (GstElement * element) gst_element_wait (GST_ELEMENT (mpeg_parse), time); } - if (mpeg_parse->current_scr != -1) { + if (mpeg_parse->current_scr != MP_INVALID_SCR) { guint64 scr, bss, br; scr = mpeg_parse->current_scr; bss = mpeg_parse->bytes_since_scr; - br = mpeg_parse->mux_rate * 50; + br = mpeg_parse->mux_rate; if (br) { if (GST_MPEG_PACKETIZE_IS_MPEG2 (mpeg_parse->packetize)) { @@ -621,6 +683,7 @@ gst_mpeg_parse_loop (GstElement * element) * * mpeg_parse->next_scr = (scr * br + bss * CLOCK_FREQ) / (CLOCK_FREQ + br); */ + mpeg_parse->next_scr = scr + (bss * CLOCK_FREQ) / br; } else { /* we are interpolating the scr here */ @@ -632,8 +695,8 @@ gst_mpeg_parse_loop (GstElement * element) } GST_LOG_OBJECT (mpeg_parse, "size: %" G_GINT64_FORMAT - ", total since SCR: %" G_GINT64_FORMAT - ", next SCR: %" G_GINT64_FORMAT, size, bss, mpeg_parse->next_scr); + ", total since SCR: %" G_GINT64_FORMAT ", br: %" G_GINT64_FORMAT + ", next SCR: %" G_GINT64_FORMAT, size, bss, br, mpeg_parse->next_scr); } } } @@ -650,12 +713,81 @@ gst_mpeg_parse_get_src_formats (GstPad * pad) return formats; } +/* + * Return the bitrate to the nearest byte/sec + */ +static gboolean +gst_mpeg_parse_get_rate (GstMPEGParse * mpeg_parse, gint64 * rate) +{ + GstFormat time_format = GST_FORMAT_TIME; + GstFormat bytes_format = GST_FORMAT_BYTES; + gint64 total_time = 0; + gint64 total_bytes = 0; + + /* If upstream knows the total time and the total bytes, + * use those to compute an average byterate + */ + if (gst_pad_query (GST_PAD_PEER (mpeg_parse->sinkpad), + GST_QUERY_TOTAL, &time_format, &total_time) + && + gst_pad_query (GST_PAD_PEER (mpeg_parse->sinkpad), + GST_QUERY_TOTAL, &bytes_format, &total_bytes) + && total_time != 0) { + *rate = GST_SECOND * total_bytes / total_time; + return TRUE; + } + + if ((mpeg_parse->first_scr != MP_INVALID_SCR) && + (mpeg_parse->last_scr != MP_INVALID_SCR) && + (mpeg_parse->last_scr_pos - mpeg_parse->first_scr_pos > MP_MIN_VALID_BSS) + && (mpeg_parse->last_scr != mpeg_parse->first_scr)) { + *rate = + GST_SECOND * (mpeg_parse->last_scr_pos - + mpeg_parse->first_scr_pos) / MPEGTIME_TO_GSTTIME (mpeg_parse->last_scr - + mpeg_parse->first_scr); + if (*rate != 0) { + /* + * check if we need to update scr_rate + */ + if ((mpeg_parse->scr_rate == 0) || + (((double) (ABS (mpeg_parse->scr_rate - + *rate)) / mpeg_parse->scr_rate) + >= MP_SCR_RATE_HYST)) { + mpeg_parse->scr_rate = *rate; + return TRUE; + } + } + if (mpeg_parse->scr_rate != 0) { + *rate = mpeg_parse->scr_rate; + return TRUE; + } + } + + if (mpeg_parse->avg_bitrate_time != 0 && mpeg_parse->avg_bitrate_bytes != 0) { + *rate = + GST_SECOND * mpeg_parse->avg_bitrate_bytes / + mpeg_parse->avg_bitrate_time; + if (*rate != 0) { + return TRUE; + } + } + + if (mpeg_parse->mux_rate != 0) { + *rate = mpeg_parse->mux_rate; + return TRUE; + } + + return FALSE; +} + gboolean gst_mpeg_parse_convert_src (GstPad * pad, GstFormat src_format, gint64 src_value, GstFormat * dest_format, gint64 * dest_value) { gboolean res = TRUE; GstMPEGParse *mpeg_parse = GST_MPEG_PARSE (gst_pad_get_parent (pad)); + gint64 rate; + switch (src_format) { case GST_FORMAT_BYTES: @@ -663,10 +795,11 @@ gst_mpeg_parse_convert_src (GstPad * pad, GstFormat src_format, case GST_FORMAT_DEFAULT: *dest_format = GST_FORMAT_TIME; case GST_FORMAT_TIME: - if (mpeg_parse->mux_rate == 0) + if (!gst_mpeg_parse_get_rate (mpeg_parse, &rate)) res = FALSE; - else - *dest_value = src_value * GST_SECOND / (mpeg_parse->mux_rate * 50); + else { + *dest_value = GST_SECOND * src_value / rate; + } break; default: res = FALSE; @@ -677,7 +810,11 @@ gst_mpeg_parse_convert_src (GstPad * pad, GstFormat src_format, case GST_FORMAT_DEFAULT: *dest_format = GST_FORMAT_BYTES; case GST_FORMAT_BYTES: - *dest_value = mpeg_parse->mux_rate * 50 * src_value / GST_SECOND; + if (!gst_mpeg_parse_get_rate (mpeg_parse, &rate)) + res = FALSE; + else { + *dest_value = src_value * rate / GST_SECOND; + } break; default: res = FALSE; @@ -687,6 +824,7 @@ gst_mpeg_parse_convert_src (GstPad * pad, GstFormat src_format, res = FALSE; break; } + return res; } @@ -708,8 +846,8 @@ gst_mpeg_parse_handle_src_query (GstPad * pad, GstQueryType type, { gboolean res = TRUE; GstMPEGParse *mpeg_parse = GST_MPEG_PARSE (gst_pad_get_parent (pad)); - GstFormat src_format; - gint64 src_value; + GstFormat src_format = GST_FORMAT_UNDEFINED; + gint64 src_value = 0; switch (type) { case GST_QUERY_TOTAL: @@ -718,6 +856,18 @@ gst_mpeg_parse_handle_src_query (GstPad * pad, GstQueryType type, case GST_FORMAT_DEFAULT: *format = GST_FORMAT_TIME; /* fallthrough */ + case GST_FORMAT_TIME: + /* + * Try asking upstream if it knows the time - a DVD might know + */ + src_format = GST_FORMAT_TIME; + if (gst_pad_query (GST_PAD_PEER (mpeg_parse->sinkpad), + GST_QUERY_TOTAL, &src_format, &src_value)) { + res = TRUE; + break; + } + + /* Otherwise fallthrough */ default: src_format = GST_FORMAT_BYTES; if (!gst_pad_query (GST_PAD_PEER (mpeg_parse->sinkpad), @@ -736,7 +886,14 @@ gst_mpeg_parse_handle_src_query (GstPad * pad, GstQueryType type, /* fallthrough */ default: src_format = GST_FORMAT_TIME; - src_value = MPEGTIME_TO_GSTTIME (mpeg_parse->current_scr); + if ((mpeg_parse->current_scr == MP_INVALID_SCR) || + (mpeg_parse->first_scr == MP_INVALID_SCR)) + res = FALSE; + else { + gint64 cur = + (gint64) (mpeg_parse->current_scr) - mpeg_parse->first_scr; + src_value = MPEGTIME_TO_GSTTIME (MAX (0, cur)); + } break; } break; @@ -838,13 +995,16 @@ gst_mpeg_parse_handle_src_event (GstPad * pad, GstEvent * event) if (!res) break; - GST_DEBUG ("sending seek to %" G_GINT64_FORMAT, desired_offset); + GST_DEBUG ("sending seek to %" G_GINT64_FORMAT " expected SCR: %" + G_GUINT64_FORMAT " (%" G_GUINT64_FORMAT ")", desired_offset, + expected_scr, MPEGTIME_TO_GSTTIME (expected_scr)); + if (gst_bytestream_seek (mpeg_parse->packetize->bs, desired_offset, GST_SEEK_METHOD_SET)) { mpeg_parse->discont_pending = TRUE; mpeg_parse->scr_pending = TRUE; mpeg_parse->next_scr = expected_scr; - mpeg_parse->current_scr = -1; + mpeg_parse->current_scr = MP_INVALID_SCR; mpeg_parse->adjust = 0; res = TRUE; } @@ -870,15 +1030,7 @@ gst_mpeg_parse_change_state (GstElement * element) GST_MPEG_PACKETIZE_SYSTEM); } /* initialize parser state */ - mpeg_parse->current_scr = 0; - mpeg_parse->bytes_since_scr = 0; - mpeg_parse->adjust = 0; - mpeg_parse->next_scr = 0; - - /* zero counters (should be done at RUNNING?) */ - mpeg_parse->mux_rate = 0; - mpeg_parse->discont_pending = FALSE; - mpeg_parse->scr_pending = FALSE; + gst_mpeg_parse_reset (mpeg_parse); break; case GST_STATE_PAUSED_TO_READY: if (mpeg_parse->packetize) { diff --git a/gst/mpegstream/gstmpegparse.h b/gst/mpegstream/gstmpegparse.h index e6d83d04f4..c249d9d36a 100644 --- a/gst/mpegstream/gstmpegparse.h +++ b/gst/mpegstream/gstmpegparse.h @@ -25,10 +25,7 @@ #include #include "gstmpegpacketize.h" -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - +G_BEGIN_DECLS #define GST_TYPE_MPEG_PARSE \ (gst_mpeg_parse_get_type()) @@ -49,80 +46,93 @@ extern "C" { #define MPEGTIME_TO_GSTTIME(time) (((time) * (GST_MSECOND/10)) / CLOCK_BASE) #define GSTTIME_TO_MPEGTIME(time) (((time) * CLOCK_BASE) / (GST_MSECOND/10)) -typedef struct _GstMPEGParse GstMPEGParse; -typedef struct _GstMPEGParseClass GstMPEGParseClass; + typedef struct _GstMPEGParse GstMPEGParse; + typedef struct _GstMPEGParseClass GstMPEGParseClass; -struct _GstMPEGParse { - GstElement element; + struct _GstMPEGParse + { + GstElement element; - GstPad *sinkpad, *srcpad; + GstPad *sinkpad, *srcpad; - GstMPEGPacketize *packetize; + GstMPEGPacketize *packetize; - /* pack header values */ - guint32 mux_rate; - guint64 current_scr; /* Current SCR from the stream. */ - guint64 next_scr; /* Expected next SCR. */ - guint64 bytes_since_scr; + /* + * Keep track of total rate using SCR + * and use hysteresis. + */ + guint64 first_scr; /* Earliest SCR value for reference */ + guint64 first_scr_pos; /* Byte position of reference SCR */ + guint64 last_scr; /* Latest SCR value for reference */ + guint64 last_scr_pos; /* Byte position of reference SCR */ + guint64 scr_rate; /* Remember the last rate for hysteresis */ - gboolean do_adjust; /* If false, send discont events on SCR - * jumps - */ - gboolean use_adjust; /* Collect SCR jumps into 'adjust' in - * order to adjust timestamps to smooth - * discontinuities. */ - gint64 adjust; /* Current timestamp adjust value. */ + /* + * Compute a rolling average for SCR interpolation (for MPEG1) + */ + guint64 avg_bitrate_time; /* Time total for local average bitrate */ + guint64 avg_bitrate_bytes; /* bytes total for local average bitrate */ - gboolean discont_pending; - gboolean scr_pending; - gint max_discont; + /* pack header values */ + guint32 mux_rate; /* mux rate in bytes/sec derived from Pack + * header */ + guint64 current_scr; /* Current SCR from the stream. */ + guint64 next_scr; /* Expected next SCR. */ + guint64 bytes_since_scr; /* Bytes since current_scr */ - GstClock *clock; - gboolean sync; - GstClockID id; + gboolean do_adjust; /* If false, send discont events on SCR + * jumps + */ + gboolean use_adjust; /* Collect SCR jumps into 'adjust' in + * order to adjust timestamps to smooth + * discontinuities. */ + gint64 adjust; /* Current timestamp adjust value. */ - GstIndex *index; - gint index_id; -}; + gboolean discont_pending; + gboolean scr_pending; + gint max_discont; -struct _GstMPEGParseClass { - GstElementClass parent_class; + GstClock *clock; + gboolean sync; + GstClockID id; - /* process packet types */ - gboolean (*parse_packhead) (GstMPEGParse *parse, GstBuffer *buffer); - gboolean (*parse_syshead) (GstMPEGParse *parse, GstBuffer *buffer); - gboolean (*parse_packet) (GstMPEGParse *parse, GstBuffer *buffer); - gboolean (*parse_pes) (GstMPEGParse *parse, GstBuffer *buffer); + GstIndex *index; + gint index_id; + }; - /* process events */ - void (*handle_discont) (GstMPEGParse *parse, GstEvent *event); + struct _GstMPEGParseClass + { + GstElementClass parent_class; - /* optional method to send out the data */ - void (*send_data) (GstMPEGParse *parse, GstData *data, GstClockTime time); - void (*send_discont) (GstMPEGParse *parse, GstClockTime time); -}; + /* process packet types */ + gboolean (*parse_packhead) (GstMPEGParse * parse, GstBuffer * buffer); + gboolean (*parse_syshead) (GstMPEGParse * parse, GstBuffer * buffer); + gboolean (*parse_packet) (GstMPEGParse * parse, GstBuffer * buffer); + gboolean (*parse_pes) (GstMPEGParse * parse, GstBuffer * buffer); -GType gst_mpeg_parse_get_type(void); + /* process events */ + void (*handle_discont) (GstMPEGParse * parse, GstEvent * event); -gboolean gst_mpeg_parse_plugin_init (GstPlugin *plugin); + /* optional method to send out the data */ + void (*send_data) (GstMPEGParse * parse, GstData * data, GstClockTime time); + void (*send_discont) (GstMPEGParse * parse, GstClockTime time); + }; -const GstFormat* - gst_mpeg_parse_get_src_formats (GstPad *pad); - -gboolean gst_mpeg_parse_convert_src (GstPad *pad, GstFormat src_format, gint64 src_value, - GstFormat *dest_format, gint64 *dest_value); -const GstEventMask* - gst_mpeg_parse_get_src_event_masks (GstPad *pad); -gboolean gst_mpeg_parse_handle_src_event (GstPad *pad, GstEvent *event); + GType gst_mpeg_parse_get_type (void); -const GstQueryType* - gst_mpeg_parse_get_src_query_types (GstPad *pad); -gboolean gst_mpeg_parse_handle_src_query (GstPad *pad, GstQueryType type, - GstFormat *format, gint64 *value); + gboolean gst_mpeg_parse_plugin_init (GstPlugin * plugin); -#ifdef __cplusplus -} -#endif /* __cplusplus */ + const GstFormat *gst_mpeg_parse_get_src_formats (GstPad * pad); + gboolean gst_mpeg_parse_convert_src (GstPad * pad, GstFormat src_format, + gint64 src_value, GstFormat * dest_format, gint64 * dest_value); + const GstEventMask *gst_mpeg_parse_get_src_event_masks (GstPad * pad); + gboolean gst_mpeg_parse_handle_src_event (GstPad * pad, GstEvent * event); -#endif /* __MPEG_PARSE_H__ */ + const GstQueryType *gst_mpeg_parse_get_src_query_types (GstPad * pad); + gboolean gst_mpeg_parse_handle_src_query (GstPad * pad, GstQueryType type, + GstFormat * format, gint64 * value); + +G_END_DECLS + +#endif /* __MPEG_PARSE_H__ */ diff --git a/gst/mpegstream/gstrfc2250enc.h b/gst/mpegstream/gstrfc2250enc.h index 1846baf7b4..f89098231e 100644 --- a/gst/mpegstream/gstrfc2250enc.h +++ b/gst/mpegstream/gstrfc2250enc.h @@ -26,11 +26,7 @@ #include #include "gstmpegpacketize.h" - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - +G_BEGIN_DECLS #define GST_TYPE_RFC2250_ENC \ (gst_rfc2250_enc_get_type()) @@ -79,10 +75,6 @@ GType gst_rfc2250_enc_get_type(void); gboolean gst_rfc2250_enc_plugin_init (GstPlugin *plugin); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - +G_END_DECLS #endif /* __RFC2250_ENC_H__ */