From f8d863517ae6ab8a6a9c9ba229b49e0932d5eacd Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Tue, 25 Jan 2005 15:34:08 +0000 Subject: [PATCH] ext/a52dec/gsta52dec.c: Add some debug output. Check that a discont has a valid time associated. Original commit message from CVS: * ext/a52dec/gsta52dec.c: (gst_a52dec_push), (gst_a52dec_handle_event), (gst_a52dec_chain): Add some debug output. Check that a discont has a valid time associated. * ext/alsa/gstalsasink.c: (gst_alsa_sink_check_event), (gst_alsa_sink_loop): Ignore TAG events. A little extra debug for broken timestamps. * ext/dvdnav/dvdnavsrc.c: (dvdnavsrc_init), (dvdnavsrc_loop), (dvdnavsrc_change_state): Ensure we send a discont to engage the link before we send any other events. * ext/dvdread/dvdreadsrc.c: (dvdreadsrc_init), (dvdreadsrc_finalize), (_close), (_open), (_seek_title), (_seek_chapter), (seek_sector), (dvdreadsrc_get), (dvdreadsrc_uri_get_uri), (dvdreadsrc_uri_set_uri): Handle URI of the form dvd://title[,chapter[,angle]]. Currently only dvd://title works in totem because typefinding sends a seek that ends up going back to chapter 1 regardless. * ext/mpeg2dec/gstmpeg2dec.c: * ext/mpeg2dec/gstmpeg2dec.h: Output correct timestamps and handle disconts. * ext/ogg/gstoggdemux.c: (get_relative): Small guard against a null dereference. * ext/pango/gsttextoverlay.c: (gst_textoverlay_finalize), (gst_textoverlay_set_property): Free memory when done. Don't call gst_event_filler_get_duration on EOS events. Use GST_LOG and GST_WARNING instead of g_message and g_warning. * ext/smoothwave/gstsmoothwave.c: (gst_smoothwave_init), (draw_line), (gst_smoothwave_dispose), (gst_sw_sinklink), (gst_sw_srclink), (gst_smoothwave_chain): Draw solid lines, prettier colours. * gst/mpeg2sub/gstmpeg2subt.c: (gst_mpeg2subt_init): Add a default palette that'll work for some movies. * gst/mpegstream/gstdvddemux.c: (gst_dvd_demux_init), (gst_dvd_demux_handle_dvd_event), (gst_dvd_demux_send_discont), (gst_dvd_demux_send_subbuffer), (gst_dvd_demux_reset): * gst/mpegstream/gstdvddemux.h: * gst/mpegstream/gstmpegdemux.c: (gst_mpeg_demux_send_discont), (gst_mpeg_demux_parse_syshead), (gst_mpeg_demux_parse_pes): * gst/mpegstream/gstmpegparse.c: (gst_mpeg_parse_init), (gst_mpeg_parse_handle_discont), (gst_mpeg_parse_parse_packhead): * gst/mpegstream/gstmpegparse.h: Use PTM/NAV events when for timestamp adjustment when connected to dvdnavsrc. Don't use many discont events where one suffices. * gst/playback/gstplaybasebin.c: (group_destroy), (gen_preroll_element), (gst_play_base_bin_add_element): * gst/playback/gstplaybasebin.h: Make sure we remove subtitles from the same bin we put them in. * gst/subparse/gstsubparse.c: (convert_encoding), (parse_subrip), (gst_subparse_buffer_format_autodetect), (gst_subparse_change_state): Fix some memleaks and invalid accesses. * gst/typefind/gsttypefindfunctions.c: (ogganx_type_find), (oggskel_type_find), (cmml_type_find), (plugin_init): Some typefind functions for Annodex v3.0 files * gst/wavparse/gstwavparse.h: GstRiffReadClass is the correct parent class. --- ChangeLog | 60 ++++++++++++++++++ ext/a52dec/gsta52dec.c | 13 +++- ext/dvdnav/dvdnavsrc.c | 11 +++- ext/dvdread/dvdreadsrc.c | 140 ++++++++++++++++++++++++++++++++---------- ext/mpeg2dec/gstmpeg2dec.c | 67 +++++++++++++------- ext/mpeg2dec/gstmpeg2dec.h | 5 +- gst/mpegstream/gstdvddemux.c | 80 ++++++++++++++---------- gst/mpegstream/gstdvddemux.h | 2 +- gst/mpegstream/gstmpegdemux.c | 36 ++++++----- gst/mpegstream/gstmpegparse.c | 17 ++--- gst/mpegstream/gstmpegparse.h | 8 ++- 11 files changed, 322 insertions(+), 117 deletions(-) diff --git a/ChangeLog b/ChangeLog index b6e0567..d525a72 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,63 @@ +2005-01-26 Jan Schmidt + * ext/a52dec/gsta52dec.c: (gst_a52dec_push), + (gst_a52dec_handle_event), (gst_a52dec_chain): + Add some debug output. Check that a discont has a valid + time associated. + * ext/alsa/gstalsasink.c: (gst_alsa_sink_check_event), + (gst_alsa_sink_loop): + Ignore TAG events. A little extra debug for broken timestamps. + * ext/dvdnav/dvdnavsrc.c: (dvdnavsrc_init), (dvdnavsrc_loop), + (dvdnavsrc_change_state): + Ensure we send a discont to engage the link before we send any + other events. + * ext/dvdread/dvdreadsrc.c: (dvdreadsrc_init), + (dvdreadsrc_finalize), (_close), (_open), (_seek_title), + (_seek_chapter), (seek_sector), (dvdreadsrc_get), + (dvdreadsrc_uri_get_uri), (dvdreadsrc_uri_set_uri): + Handle URI of the form dvd://title[,chapter[,angle]]. Currently only + dvd://title works in totem because typefinding sends a seek that ends + up going back to chapter 1 regardless. + * ext/mpeg2dec/gstmpeg2dec.c: + * ext/mpeg2dec/gstmpeg2dec.h: + Output correct timestamps and handle disconts. + * ext/ogg/gstoggdemux.c: (get_relative): + Small guard against a null dereference. + * ext/pango/gsttextoverlay.c: (gst_textoverlay_finalize), + (gst_textoverlay_set_property): + Free memory when done. Don't call gst_event_filler_get_duration on + EOS events. Use GST_LOG and GST_WARNING instead of g_message and + g_warning. + * ext/smoothwave/gstsmoothwave.c: (gst_smoothwave_init), + (draw_line), (gst_smoothwave_dispose), (gst_sw_sinklink), + (gst_sw_srclink), (gst_smoothwave_chain): + Draw solid lines, prettier colours. + * gst/mpeg2sub/gstmpeg2subt.c: (gst_mpeg2subt_init): + Add a default palette that'll work for some movies. + * gst/mpegstream/gstdvddemux.c: (gst_dvd_demux_init), + (gst_dvd_demux_handle_dvd_event), (gst_dvd_demux_send_discont), + (gst_dvd_demux_send_subbuffer), (gst_dvd_demux_reset): + * gst/mpegstream/gstdvddemux.h: + * gst/mpegstream/gstmpegdemux.c: (gst_mpeg_demux_send_discont), + (gst_mpeg_demux_parse_syshead), (gst_mpeg_demux_parse_pes): + * gst/mpegstream/gstmpegparse.c: (gst_mpeg_parse_init), + (gst_mpeg_parse_handle_discont), (gst_mpeg_parse_parse_packhead): + * gst/mpegstream/gstmpegparse.h: + Use PTM/NAV events when for timestamp adjustment when connected to + dvdnavsrc. Don't use many discont events where one suffices. + * gst/playback/gstplaybasebin.c: (group_destroy), + (gen_preroll_element), (gst_play_base_bin_add_element): + * gst/playback/gstplaybasebin.h: + Make sure we remove subtitles from the same bin we put them in. + * gst/subparse/gstsubparse.c: (convert_encoding), (parse_subrip), + (gst_subparse_buffer_format_autodetect), + (gst_subparse_change_state): + Fix some memleaks and invalid accesses. + * gst/typefind/gsttypefindfunctions.c: (ogganx_type_find), + (oggskel_type_find), (cmml_type_find), (plugin_init): + Some typefind functions for Annodex v3.0 files + * gst/wavparse/gstwavparse.h: + GstRiffReadClass is the correct parent class. + 2005-01-25 Ronald S. Bultje * gst-libs/gst/riff/riff-media.c: diff --git a/ext/a52dec/gsta52dec.c b/ext/a52dec/gsta52dec.c index 4e25e9d..1c2ba80 100644 --- a/ext/a52dec/gsta52dec.c +++ b/ext/a52dec/gsta52dec.c @@ -283,6 +283,11 @@ gst_a52dec_push (GstA52Dec * a52dec, GST_BUFFER_TIMESTAMP (buf) = timestamp; GST_BUFFER_DURATION (buf) = 256 * GST_SECOND / a52dec->sample_rate; + GST_DEBUG_OBJECT (a52dec, + "Pushing buffer with ts %" GST_TIME_FORMAT " duration %" GST_TIME_FORMAT, + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), + GST_TIME_ARGS (GST_BUFFER_DURATION (buf))); + gst_pad_push (srcpad, GST_DATA (buf)); return 0; @@ -324,7 +329,8 @@ gst_a52dec_handle_event (GstA52Dec * a52dec, GstEvent * event) case GST_EVENT_DISCONTINUOUS:{ gint64 val; - if (!gst_event_discont_get_value (event, GST_FORMAT_TIME, &val)) { + if (!gst_event_discont_get_value (event, GST_FORMAT_TIME, &val) + || !GST_CLOCK_TIME_IS_VALID (val)) { GST_WARNING ("No time discont value in event %p", event); } else { a52dec->time = val; @@ -442,7 +448,12 @@ gst_a52dec_chain (GstPad * pad, GstData * _data) buf = GST_BUFFER (_data); if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { a52dec->time = GST_BUFFER_TIMESTAMP (buf); + GST_DEBUG_OBJECT (a52dec, + "Received buffer with ts %" GST_TIME_FORMAT " duration %" + GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), + GST_TIME_ARGS (GST_BUFFER_DURATION (buf))); } + if (a52dec->cache) { buf = gst_buffer_join (a52dec->cache, buf); a52dec->cache = NULL; diff --git a/ext/dvdnav/dvdnavsrc.c b/ext/dvdnav/dvdnavsrc.c index 4fc0338..38fedcc 100644 --- a/ext/dvdnav/dvdnavsrc.c +++ b/ext/dvdnav/dvdnavsrc.c @@ -124,7 +124,7 @@ struct _DVDNavSrc gboolean did_seek; gboolean need_flush; - gboolean need_discont; + gboolean need_newmedia; /* Timing */ GstClock *clock; /* The clock for this element. */ @@ -395,6 +395,7 @@ dvdnavsrc_init (DVDNavSrc * src) src->did_seek = FALSE; src->need_flush = FALSE; + src->need_newmedia = TRUE; /* Pause mode is initially inactive. */ src->pause_mode = DVDNAVSRC_PAUSE_OFF; @@ -1278,13 +1279,16 @@ dvdnavsrc_loop (GstElement * element) g_return_if_fail (dvdnavsrc_is_open (src)); - if (src->did_seek) { + if (src->did_seek || src->need_newmedia) { GstEvent *event; src->did_seek = FALSE; GST_INFO_OBJECT (src, "sending discont"); - event = gst_event_new_discontinuous (FALSE, 0); + + event = gst_event_new_discontinuous (src->need_newmedia, 0); + src->need_flush = FALSE; + src->need_newmedia = FALSE; gst_pad_push (src->srcpad, GST_DATA (event)); return; } @@ -1595,6 +1599,7 @@ dvdnavsrc_change_state (GstElement * element) } } src->streaminfo = NULL; + src->need_newmedia = TRUE; break; case GST_STATE_PAUSED_TO_PLAYING: break; diff --git a/ext/dvdread/dvdreadsrc.c b/ext/dvdread/dvdreadsrc.c index 060e82f..73c8cd5 100644 --- a/ext/dvdread/dvdreadsrc.c +++ b/ext/dvdread/dvdreadsrc.c @@ -53,6 +53,7 @@ struct _DVDReadSrcPrivate /* location */ gchar *location; + gchar *last_uri; gboolean new_seek; @@ -235,7 +236,13 @@ dvdreadsrc_init (DVDReadSrc * dvdreadsrc) dvdreadsrc_get_formats); gst_element_add_pad (GST_ELEMENT (dvdreadsrc), dvdreadsrc->priv->srcpad); + dvdreadsrc->priv->dvd = NULL; + dvdreadsrc->priv->vts_file = NULL; + dvdreadsrc->priv->vmg_file = NULL; + dvdreadsrc->priv->dvd_title = NULL; + dvdreadsrc->priv->location = g_strdup ("/dev/dvd"); + dvdreadsrc->priv->last_uri = NULL; dvdreadsrc->priv->new_seek = TRUE; dvdreadsrc->priv->new_cell = TRUE; dvdreadsrc->priv->title = 0; @@ -254,6 +261,7 @@ dvdreadsrc_finalize (GObject * object) if (dvdreadsrc->priv) { g_free (dvdreadsrc->priv->location); + g_free (dvdreadsrc->priv->last_uri); g_free (dvdreadsrc->priv); dvdreadsrc->priv = NULL; } @@ -550,6 +558,24 @@ is_nav_pack (unsigned char *buffer) } static int +_close (DVDReadSrcPrivate * priv) +{ + ifoClose (priv->vts_file); + priv->vts_file = NULL; + + ifoClose (priv->vmg_file); + priv->vmg_file = NULL; + + DVDCloseFile (priv->dvd_title); + priv->dvd_title = NULL; + + DVDClose (priv->dvd); + priv->dvd = NULL; + + return 0; +} + +static int _open (DVDReadSrcPrivate * priv, const gchar * location) { g_return_val_if_fail (priv != NULL, -1); @@ -572,7 +598,6 @@ _open (DVDReadSrcPrivate * priv, const gchar * location) priv->vmg_file = ifoOpen (priv->dvd, 0); if (!priv->vmg_file) { GST_ERROR ("Can't open VMG info"); - DVDClose (priv->dvd); return -1; } priv->tt_srpt = priv->vmg_file->tt_srpt; @@ -581,16 +606,6 @@ _open (DVDReadSrcPrivate * priv, const gchar * location) } static int -_close (DVDReadSrcPrivate * priv) -{ - ifoClose (priv->vts_file); - ifoClose (priv->vmg_file); - DVDCloseFile (priv->dvd_title); - DVDClose (priv->dvd); - return 0; -} - -static int _seek_title (DVDReadSrcPrivate * priv, int title, int angle) { GHashTable *languagelist = NULL; @@ -600,11 +615,13 @@ _seek_title (DVDReadSrcPrivate * priv, int title, int angle) */ GST_LOG ("There are %d titles on this DVD", priv->tt_srpt->nr_of_srpts); if (title < 0 || title >= priv->tt_srpt->nr_of_srpts) { - GST_ERROR ("Invalid title %d (only %d available)", + GST_WARNING ("Invalid title %d (only %d available)", title, priv->tt_srpt->nr_of_srpts); - ifoClose (priv->vmg_file); - DVDClose (priv->dvd); - return -1; + + if (title < 0) + title = 0; + else + title = priv->tt_srpt->nr_of_srpts - 1; } GST_LOG ("There are %d chapters in this title", @@ -617,14 +634,14 @@ _seek_title (DVDReadSrcPrivate * priv, int title, int angle) priv->tt_srpt->title[title].nr_of_angles); if (angle < 0 || angle >= priv->tt_srpt->title[title].nr_of_angles) { - GST_ERROR ("Invalid angle %d (only %d available)", + GST_WARNING ("Invalid angle %d (only %d available)", angle, priv->tt_srpt->title[title].nr_of_angles); - ifoClose (priv->vmg_file); - DVDClose (priv->dvd); - return -1; + if (angle < 0) + angle = 0; + else + angle = priv->tt_srpt->title[title].nr_of_angles - 1; } - /** * Load the VTS information for the title set our title is in. */ @@ -633,8 +650,7 @@ _seek_title (DVDReadSrcPrivate * priv, int title, int angle) if (!priv->vts_file) { GST_ERROR ("Can't open the info file of title %d", priv->tt_srpt->title[title].title_set_nr); - ifoClose (priv->vmg_file); - DVDClose (priv->dvd); + _close (priv); return -1; } @@ -650,9 +666,7 @@ _seek_title (DVDReadSrcPrivate * priv, int title, int angle) if (!priv->dvd_title) { GST_ERROR ("Can't open title VOBS (VTS_%02d_1.VOB)", priv->tt_srpt->title[title].title_set_nr); - ifoClose (priv->vts_file); - ifoClose (priv->vmg_file); - DVDClose (priv->dvd); + _close (priv); return -1; } @@ -665,6 +679,8 @@ _seek_title (DVDReadSrcPrivate * priv, int title, int angle) g_hash_table_destroy (languagelist); GST_LOG ("Opened title %d, angle %d", title, angle); + priv->title = title; + priv->angle = angle; return 0; } @@ -678,11 +694,11 @@ _seek_chapter (DVDReadSrcPrivate * priv, int chapter) * Make sure the chapter number is valid for this title. */ if (chapter < 0 || chapter >= priv->tt_srpt->title[priv->title].nr_of_ptts) { - GST_ERROR ("Invalid chapter %d (only %d available)", + GST_WARNING ("Invalid chapter %d (only %d available)", chapter, priv->tt_srpt->title[priv->title].nr_of_ptts); - ifoClose (priv->vmg_file); - DVDClose (priv->dvd); - return -1; + if (chapter < 0) + chapter = 0; + chapter = priv->tt_srpt->title[priv->title].nr_of_ptts - 1; } /** @@ -730,6 +746,7 @@ _seek_chapter (DVDReadSrcPrivate * priv, int chapter) priv->new_cell = TRUE; priv->next_cell = priv->start_cell; + priv->chapter = chapter; return 0; } @@ -907,7 +924,8 @@ again: static gboolean seek_sector (DVDReadSrcPrivate * priv, int angle) { - gint seek_to = priv->cur_pack, chapter, sectors, next, cur, i; + gint seek_to = priv->cur_pack; + gint chapter, sectors, next, cur, i; /* retrieve position */ priv->cur_pack = 0; @@ -992,6 +1010,7 @@ dvdreadsrc_get (GstPad * pad) priv->seek_pend_fmt = GST_FORMAT_UNDEFINED; } else { if (!seek_sector (priv, priv->angle)) { + gst_element_set_eos (GST_ELEMENT (dvdreadsrc)); return GST_DATA (gst_event_new (GST_EVENT_EOS)); } } @@ -1122,17 +1141,76 @@ dvdreadsrc_uri_get_protocols (void) static const gchar * dvdreadsrc_uri_get_uri (GstURIHandler * handler) { - return "dvd://"; + DVDReadSrc *dvdreadsrc = DVDREADSRC (handler); + + g_free (dvdreadsrc->priv->last_uri); + dvdreadsrc->priv->last_uri = + g_strdup_printf ("dvd://%d,%d,%d", dvdreadsrc->priv->title, + dvdreadsrc->priv->chapter, dvdreadsrc->priv->angle); + + return dvdreadsrc->priv->last_uri; } static gboolean dvdreadsrc_uri_set_uri (GstURIHandler * handler, const gchar * uri) { + DVDReadSrc *dvdreadsrc = DVDREADSRC (handler); gboolean ret; gchar *protocol = gst_uri_get_protocol (uri); ret = (protocol && !strcmp (protocol, "dvd")) ? TRUE : FALSE; g_free (protocol); + protocol = NULL; + + if (!ret) + return ret; + + /* + * Parse out the new t/c/a and seek to them + */ + { + gchar *location = NULL; + gchar **strs; + gchar **strcur; + gint pos = 0; + + location = gst_uri_get_location (uri); + + if (!location) + return ret; + + strcur = strs = g_strsplit (location, ",", 0); + while (strcur && *strcur) { + gint val; + + if (!sscanf (*strcur, "%d", &val)) + break; + + switch (pos) { + case 0: + if (val != dvdreadsrc->priv->title) { + dvdreadsrc->priv->title = val; + dvdreadsrc->priv->new_seek = TRUE; + } + break; + case 1: + if (val != dvdreadsrc->priv->chapter) { + dvdreadsrc->priv->chapter = val; + dvdreadsrc->priv->new_seek = TRUE; + } + break; + case 2: + dvdreadsrc->priv->angle = val; + break; + } + + strcur++; + pos++; + } + + g_strfreev (strs); + g_free (location); + } return ret; } diff --git a/ext/mpeg2dec/gstmpeg2dec.c b/ext/mpeg2dec/gstmpeg2dec.c index a70b8b6..84aae6c 100644 --- a/ext/mpeg2dec/gstmpeg2dec.c +++ b/ext/mpeg2dec/gstmpeg2dec.c @@ -585,7 +585,7 @@ gst_mpeg2dec_chain (GstPad * pad, GstData * _data) GstMpeg2dec *mpeg2dec = GST_MPEG2DEC (gst_pad_get_parent (pad)); guint32 size; guint8 *data, *end; - gint64 pts; + GstClockTime pts; const mpeg2_info_t *info; mpeg2_state_t state; gboolean done = FALSE; @@ -596,8 +596,20 @@ gst_mpeg2dec_chain (GstPad * pad, GstData * _data) switch (GST_EVENT_TYPE (event)) { case GST_EVENT_DISCONTINUOUS: { - GST_DEBUG_OBJECT (mpeg2dec, "discont, resetting next_time to 0"); - mpeg2dec->next_time = 0; + GstClockTime time; + + if (!gst_event_discont_get_value (event, GST_FORMAT_TIME, &time) + || !GST_CLOCK_TIME_IS_VALID (time)) { + GST_WARNING_OBJECT (mpeg2dec, + "No new time offset in discont event %p", event); + } else { + mpeg2dec->next_time = time; + GST_DEBUG_OBJECT (mpeg2dec, + "discont, reset next_time to %" G_GUINT64_FORMAT " (%" + GST_TIME_FORMAT ")", mpeg2dec->next_time, + GST_TIME_ARGS (mpeg2dec->next_time)); + } + mpeg2dec->discont_state = MPEG2DEC_DISC_NEW_PICTURE; gst_mpeg2dec_flush_decoder (mpeg2dec); gst_pad_event_default (pad, event); @@ -626,7 +638,7 @@ gst_mpeg2dec_chain (GstPad * pad, GstData * _data) info = mpeg2_info (mpeg2dec->decoder); end = data + size; - if (pts != -1) { + if (pts != GST_CLOCK_TIME_NONE) { gint64 mpeg_pts = GST_TIME_TO_MPEG_TIME (pts); GST_DEBUG_OBJECT (mpeg2dec, @@ -643,14 +655,14 @@ gst_mpeg2dec_chain (GstPad * pad, GstData * _data) GST_LOG ("no pts"); } - GST_LOG ("calling mpeg2_buffer"); + GST_LOG_OBJECT (mpeg2dec, "calling mpeg2_buffer"); mpeg2_buffer (mpeg2dec->decoder, data, end); - GST_LOG ("calling mpeg2_buffer done"); + GST_LOG_OBJECT (mpeg2dec, "calling mpeg2_buffer done"); while (!done) { gboolean slice = FALSE; - GST_LOG ("calling parse"); + GST_LOG_OBJECT (mpeg2dec, "calling parse"); state = mpeg2_parse (mpeg2dec->decoder); GST_DEBUG_OBJECT (mpeg2dec, "parse state %d", state); switch (state) { @@ -676,8 +688,9 @@ gst_mpeg2dec_chain (GstPad * pad, GstData * _data) info->sequence->frame_period * GST_USECOND / 27; GST_DEBUG_OBJECT (mpeg2dec, - "sequence flags: %d, frame period: %d, frame rate: %d", + "sequence flags: %d, frame period: %d (%g), frame rate: %g", info->sequence->flags, info->sequence->frame_period, + (double) (mpeg2dec->frame_period) / GST_SECOND, mpeg2dec->frame_rate); GST_DEBUG_OBJECT (mpeg2dec, "profile: %02x, colour_primaries: %d", info->sequence->profile_level_id, info->sequence->colour_primaries); @@ -741,10 +754,11 @@ gst_mpeg2dec_chain (GstPad * pad, GstData * _data) break; } case STATE_SLICE_1ST: - GST_DEBUG_OBJECT (mpeg2dec, "slice 1st"); + GST_LOG_OBJECT (mpeg2dec, "1st slice of frame encountered"); break; case STATE_PICTURE_2ND: - GST_DEBUG_OBJECT (mpeg2dec, "picture second"); + GST_LOG_OBJECT (mpeg2dec, + "Second picture header encountered. Decoding 2nd field"); break; case STATE_SLICE: slice = TRUE; @@ -788,22 +802,31 @@ gst_mpeg2dec_chain (GstPad * pad, GstData * _data) #else if (picture->flags & PIC_FLAG_TAGS) { GstClockTime time = - MPEG_TIME_TO_GST_TIME ((guint64) picture->tag2 << 32 | picture-> - tag); + MPEG_TIME_TO_GST_TIME ((GstClockTime) (picture-> + tag2) << 32 | picture->tag); #endif - - GST_DEBUG_OBJECT (mpeg2dec, "picture had pts %" GST_TIME_FORMAT, - GST_TIME_ARGS (time)); + GST_DEBUG_OBJECT (mpeg2dec, + "picture had pts %" GST_TIME_FORMAT ", we had %" + GST_TIME_FORMAT, GST_TIME_ARGS (time), + GST_TIME_ARGS (mpeg2dec->next_time)); GST_BUFFER_TIMESTAMP (outbuf) = mpeg2dec->next_time = time; } else { GST_DEBUG_OBJECT (mpeg2dec, - "picture didn't have pts using %" GST_TIME_FORMAT, + "picture didn't have pts. Using %" GST_TIME_FORMAT, GST_TIME_ARGS (mpeg2dec->next_time)); GST_BUFFER_TIMESTAMP (outbuf) = mpeg2dec->next_time; } - mpeg2dec->next_time += - (mpeg2dec->frame_period * picture->nb_fields) >> 1; + /* TODO set correct offset here based on frame number */ + if (info->display_picture_2nd) { + GST_BUFFER_DURATION (outbuf) = (picture->nb_fields + + info->display_picture_2nd->nb_fields) * mpeg2dec->frame_period / + 2; + } else { + GST_BUFFER_DURATION (outbuf) = + picture->nb_fields * mpeg2dec->frame_period / 2; + } + mpeg2dec->next_time += GST_BUFFER_DURATION (outbuf); GST_DEBUG_OBJECT (mpeg2dec, "picture: %s %s fields:%d off:%" G_GINT64_FORMAT " ts:%" @@ -840,8 +863,6 @@ gst_mpeg2dec_chain (GstPad * pad, GstData * _data) GST_DEBUG_OBJECT (mpeg2dec, "dropping buffer, asked to skip"); gst_buffer_unref (outbuf); } else { - /* TODO set correct offset here based on frame number */ - GST_BUFFER_DURATION (outbuf) = mpeg2dec->frame_period; GST_LOG_OBJECT (mpeg2dec, "pushing buffer, timestamp %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)), @@ -869,14 +890,13 @@ gst_mpeg2dec_chain (GstPad * pad, GstData * _data) break; /* error */ case STATE_INVALID: - g_warning ("mpeg2dec: decoding error"); + GST_WARNING_OBJECT (mpeg2dec, "Decoding error"); /* it looks like setting a new frame in libmpeg2 avoids a crash */ /* FIXME figure out how this screws up sync and buffer leakage */ gst_mpeg2dec_alloc_buffer (mpeg2dec, info, GST_BUFFER_OFFSET (buf)); break; default: - g_warning ("%s: unhandled state %d, FIXME", - gst_element_get_name (GST_ELEMENT (mpeg2dec)), state); + GST_ERROR_OBJECT (mpeg2dec, "Unknown libmpeg2 state %d, FIXME", state); break; } @@ -1306,6 +1326,7 @@ gst_mpeg2dec_change_state (GstElement * element) case GST_STATE_PLAYING_TO_PAUSED: break; case GST_STATE_PAUSED_TO_READY: + gst_mpeg2dec_flush_decoder (mpeg2dec); gst_mpeg2dec_close_decoder (mpeg2dec); break; case GST_STATE_READY_TO_NULL: diff --git a/ext/mpeg2dec/gstmpeg2dec.h b/ext/mpeg2dec/gstmpeg2dec.h index 4eb1368..72cd743 100644 --- a/ext/mpeg2dec/gstmpeg2dec.h +++ b/ext/mpeg2dec/gstmpeg2dec.h @@ -71,9 +71,10 @@ struct _GstMpeg2dec { gboolean closed; gboolean have_fbuf; - /* the timestamp of the next frame */ DiscontState discont_state; - gint64 next_time; + + /* the timestamp of the next frame */ + GstClockTime next_time; gint64 segment_start; gint64 segment_end; diff --git a/gst/mpegstream/gstdvddemux.c b/gst/mpegstream/gstdvddemux.c index b152886..45cb5c8 100644 --- a/gst/mpegstream/gstdvddemux.c +++ b/gst/mpegstream/gstdvddemux.c @@ -26,6 +26,11 @@ #include "gstdvddemux.h" +/* + * Start the timestamp sequence at 2 seconds to allow for strange audio + * timestamps when audio crosses a VOBU + */ +#define INITIAL_END_PTM (2 * GST_SECOND) GST_DEBUG_CATEGORY_STATIC (gstdvddemux_debug); #define GST_CAT_DEFAULT (gstdvddemux_debug) @@ -290,28 +295,7 @@ gst_dvd_demux_init (GstDVDDemux * dvd_demux) dvd_demux->cur_audio_nr = 0; dvd_demux->cur_subpicture_nr = 0; - /* Start the timestamp sequence in 0. */ - dvd_demux->last_end_ptm = 0; - - /* (Ronald) so, this was disabled. I'm enabling (default) it again. - * Timestamp adjustment is fairly evil, we would ideally use discont - * events instead. However, our current clocking has a pretty serious - * race condition: imagine that $pipeline is at time 30sec and $audio - * receives a discont to 0sec. Video processes its last buffer and - * calls _wait() on $timestamp, which is 30s - so we wait (hang) 30sec. - * This is unacceptable, obviously, and timestamp adjustment, no matter - * how evil, solves this. - * Before disabling this again, tripple check that al .vob files on our - * websites /media/ directory work fine, especially bullet.vob and - * barrage.vob. - */ -#if 0 - /* Try to prevent the mpegparse infrastructure from doing timestamp - adjustment. */ - mpeg_parse->do_adjust = FALSE; - mpeg_parse->adjust = 0; -#endif - + dvd_demux->last_end_ptm = INITIAL_END_PTM; dvd_demux->just_flushed = FALSE; dvd_demux->discont_time = GST_CLOCK_TIME_NONE; @@ -416,6 +400,26 @@ gst_dvd_demux_handle_dvd_event (GstDVDDemux * dvd_demux, GstEvent * event) (double) dvd_demux->last_end_ptm / GST_SECOND, (double) start_ptm / GST_SECOND, (double) mpeg_demux->adjust / GST_SECOND); + + /* Disable mpeg_parse's timestamp adjustment in favour of the info + * from DVD nav packets. + * Timestamp adjustment is fairly evil, we would ideally use discont + * events instead. However, our current clocking has a pretty serious + * race condition: imagine that $pipeline is at time 30sec and $audio + * receives a discont to 0sec. Video processes its last buffer and + * calls _wait() on $timestamp, which is 30s - so we wait (hang) 30sec. + * This is unacceptable, obviously, and timestamp adjustment, no matter + * how evil, solves this. + * Before disabling this again, tripple check that al .vob files on our + * websites /media/ directory work fine, especially bullet.vob and + * barrage.vob. + */ +#if 1 + /* Try to prevent the mpegparse infrastructure from doing timestamp + adjustment. */ + mpeg_parse->use_adjust = FALSE; + mpeg_parse->adjust = 0; +#endif } dvd_demux->last_end_ptm = end_ptm; @@ -425,6 +429,9 @@ gst_dvd_demux_handle_dvd_event (GstDVDDemux * dvd_demux, GstEvent * event) time gap between the discontinuity and the subsequent data blocks. */ dvd_demux->discont_time = start_ptm + mpeg_demux->adjust; + GST_DEBUG_OBJECT (dvd_demux, "Set discont time to %" G_GINT64_FORMAT, + start_ptm + mpeg_demux->adjust); + dvd_demux->just_flushed = FALSE; } @@ -454,34 +461,39 @@ gst_dvd_demux_send_discont (GstMPEGParse * mpeg_parse, GstClockTime time) GST_MPEG_PARSE_CLASS (parent_class)->send_discont (mpeg_parse, time); + discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, time, NULL); + if (!discont) { + GST_ELEMENT_ERROR (GST_ELEMENT (dvd_demux), + RESOURCE, FAILED, (NULL), ("Allocation failed")); + return; + } + for (i = 0; i < GST_DVD_DEMUX_NUM_SUBPICTURE_STREAMS; i++) { if (dvd_demux->subpicture_stream[i] && GST_PAD_IS_USABLE (dvd_demux->subpicture_stream[i]->pad)) { - discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, - time, NULL); + gst_event_ref (discont); gst_pad_push (dvd_demux->subpicture_stream[i]->pad, GST_DATA (discont)); } } /* Distribute the event to the "current" pads. */ if (GST_PAD_IS_USABLE (dvd_demux->cur_video)) { - discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, time, NULL); - + gst_event_ref (discont); gst_pad_push (dvd_demux->cur_video, GST_DATA (discont)); } if (GST_PAD_IS_USABLE (dvd_demux->cur_audio)) { - discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, time, NULL); - + gst_event_ref (discont); gst_pad_push (dvd_demux->cur_audio, GST_DATA (discont)); } if (GST_PAD_IS_USABLE (dvd_demux->cur_subpicture)) { - discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, time, NULL); - + gst_event_ref (discont); gst_pad_push (dvd_demux->cur_subpicture, GST_DATA (discont)); } + + gst_event_unref (discont); } static void @@ -857,8 +869,12 @@ gst_dvd_demux_send_subbuffer (GstMPEGDemux * mpeg_demux, minimize the time interval between the discontinuity and the data buffers following it. */ if (dvd_demux->discont_time != GST_CLOCK_TIME_NONE) { + if ((gint64) (dvd_demux->discont_time) < 0) { + GST_ERROR ("DVD Discont < 0! % " G_GINT64_FORMAT, + (gint64) dvd_demux->discont_time); + } PARSE_CLASS (mpeg_demux)->send_discont (mpeg_parse, - dvd_demux->discont_time - 200 * GST_MSECOND); + dvd_demux->discont_time); dvd_demux->discont_time = GST_CLOCK_TIME_NONE; } @@ -991,7 +1007,7 @@ gst_dvd_demux_reset (GstDVDDemux * dvd_demux) dvd_demux->cur_audio_nr = 0; dvd_demux->cur_subpicture_nr = 0; dvd_demux->mpeg_version = 0; - dvd_demux->last_end_ptm = 0; + dvd_demux->last_end_ptm = INITIAL_END_PTM; dvd_demux->just_flushed = FALSE; dvd_demux->discont_time = GST_CLOCK_TIME_NONE; diff --git a/gst/mpegstream/gstdvddemux.h b/gst/mpegstream/gstdvddemux.h index 3b7a6d6..002cfe5 100644 --- a/gst/mpegstream/gstdvddemux.h +++ b/gst/mpegstream/gstdvddemux.h @@ -107,7 +107,7 @@ struct _GstDVDDemux { gboolean just_flushed; /* The element just received a flush event. */ GstClockTime discont_time; /* If different from GST_CLOCK_TIME_NONE, a discontinuous event should be sent with the - given time, before sending the next dara + given time, before sending the next data block.. */ gint mpeg_version; /* Version of the MPEG video stream */ diff --git a/gst/mpegstream/gstmpegdemux.c b/gst/mpegstream/gstmpegdemux.c index ac48cb4..b49edbe 100644 --- a/gst/mpegstream/gstmpegdemux.c +++ b/gst/mpegstream/gstmpegdemux.c @@ -275,13 +275,18 @@ gst_mpeg_demux_send_discont (GstMPEGParse * mpeg_parse, GstClockTime time) gint i; GST_DEBUG_OBJECT (mpeg_demux, "discont %" G_GUINT64_FORMAT, time); + discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, time, NULL); + + if (!discont) { + GST_ELEMENT_ERROR (GST_ELEMENT (mpeg_demux), + RESOURCE, FAILED, (NULL), ("Allocation failed")); + return; + } for (i = 0; i < GST_MPEG_DEMUX_NUM_VIDEO_STREAMS; i++) { if (mpeg_demux->video_stream[i] && GST_PAD_IS_USABLE (mpeg_demux->video_stream[i]->pad)) { - discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, - time, NULL); - + gst_event_ref (discont); gst_pad_push (mpeg_demux->video_stream[i]->pad, GST_DATA (discont)); } } @@ -289,9 +294,7 @@ gst_mpeg_demux_send_discont (GstMPEGParse * mpeg_parse, GstClockTime time) for (i = 0; i < GST_MPEG_DEMUX_NUM_AUDIO_STREAMS; i++) { if (mpeg_demux->audio_stream[i] && GST_PAD_IS_USABLE (mpeg_demux->audio_stream[i]->pad)) { - discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, - time, NULL); - + gst_event_ref (discont); gst_pad_push (mpeg_demux->audio_stream[i]->pad, GST_DATA (discont)); } } @@ -299,12 +302,12 @@ gst_mpeg_demux_send_discont (GstMPEGParse * mpeg_parse, GstClockTime time) for (i = 0; i < GST_MPEG_DEMUX_NUM_PRIVATE_STREAMS; i++) { if (mpeg_demux->private_stream[i] && GST_PAD_IS_USABLE (mpeg_demux->private_stream[i]->pad)) { - discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, - time, NULL); - + gst_event_ref (discont); gst_pad_push (mpeg_demux->private_stream[i]->pad, GST_DATA (discont)); } } + + gst_event_unref (discont); } static void @@ -618,13 +621,13 @@ gst_mpeg_demux_parse_syshead (GstMPEGParse * mpeg_parse, GstBuffer * buffer) if (GST_PAD_IS_USABLE (outstream->pad)) { GstEvent *event; - gint64 time; + 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, - MPEGTIME_TO_GSTTIME (time), NULL); + time, NULL); gst_pad_push (outstream->pad, GST_DATA (event)); } @@ -839,11 +842,14 @@ gst_mpeg_demux_parse_pes (GstMPEGParse * mpeg_parse, GstBuffer * buffer) pts |= ((guint64) * buf++) << 7; pts |= ((guint64) (*buf++ & 0xFE)) >> 1; - GST_DEBUG_OBJECT (mpeg_demux, "0x%02x (%lld) PTS = %" G_GUINT64_FORMAT, - id, pts, MPEGTIME_TO_GSTTIME (pts)); + timestamp = + MPEGTIME_TO_GSTTIME (pts + mpeg_parse->adjust) + mpeg_demux->adjust; - pts += mpeg_parse->adjust; - timestamp = MPEGTIME_TO_GSTTIME (pts) + mpeg_demux->adjust; + GST_DEBUG_OBJECT (mpeg_demux, + "0x%02x (% " G_GINT64_FORMAT ") PTS = %" G_GUINT64_FORMAT + " (adjusted = %" G_GINT64_FORMAT ")", id, pts, + MPEGTIME_TO_GSTTIME (pts), + MPEGTIME_TO_GSTTIME (pts + mpeg_parse->adjust) + mpeg_demux->adjust); } else { timestamp = GST_CLOCK_TIME_NONE; } diff --git a/gst/mpegstream/gstmpegparse.c b/gst/mpegstream/gstmpegparse.c index 8e5fee8..a7deb6c 100644 --- a/gst/mpegstream/gstmpegparse.c +++ b/gst/mpegstream/gstmpegparse.c @@ -238,6 +238,7 @@ gst_mpeg_parse_init (GstMPEGParse * mpeg_parse) mpeg_parse->max_discont = DEFAULT_MAX_DISCONT; mpeg_parse->do_adjust = TRUE; + mpeg_parse->use_adjust = TRUE; GST_FLAG_SET (mpeg_parse, GST_ELEMENT_EVENT_AWARE); } @@ -283,9 +284,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_get_value (event, GST_FORMAT_TIME, &time)) { - GST_DEBUG_OBJECT (mpeg_parse, - "forwarding discontinuity, time: %0.3fs", (double) time / GST_SECOND); + 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", + (double) time / GST_SECOND); if (CLASS (mpeg_parse)->send_discont) CLASS (mpeg_parse)->send_discont (mpeg_parse, time); @@ -452,10 +454,11 @@ gst_mpeg_parse_parse_packhead (GstMPEGParse * mpeg_parse, GstBuffer * buffer) mpeg_parse->current_scr, mpeg_parse->adjust); if (mpeg_parse->do_adjust) { - mpeg_parse->adjust += - (gint64) mpeg_parse->next_scr - (gint64) mpeg_parse->current_scr; - - GST_DEBUG ("new adjust: %" G_GINT64_FORMAT, mpeg_parse->adjust); + if (mpeg_parse->use_adjust) { + mpeg_parse->adjust += + (gint64) mpeg_parse->next_scr - (gint64) mpeg_parse->current_scr; + GST_DEBUG ("new adjust: %" G_GINT64_FORMAT, mpeg_parse->adjust); + } } else { mpeg_parse->discont_pending = TRUE; } diff --git a/gst/mpegstream/gstmpegparse.h b/gst/mpegstream/gstmpegparse.h index 70db04b..e6d83d0 100644 --- a/gst/mpegstream/gstmpegparse.h +++ b/gst/mpegstream/gstmpegparse.h @@ -65,8 +65,12 @@ struct _GstMPEGParse { guint64 next_scr; /* Expected next SCR. */ guint64 bytes_since_scr; - gboolean do_adjust; /* Adjust timestamps to smooth - discontinuities. */ + 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. */ gboolean discont_pending; -- 2.7.4