diff --git a/ChangeLog b/ChangeLog index b6e0567b76..d525a72f96 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/alsa/gstalsasink.c b/ext/alsa/gstalsasink.c index 21b11efab9..5fea0ff0c6 100644 --- a/ext/alsa/gstalsasink.c +++ b/ext/alsa/gstalsasink.c @@ -252,6 +252,8 @@ gst_alsa_sink_check_event (GstAlsaSink * sink, gint pad_nr) break; } + case GST_EVENT_TAG: + break; default: GST_INFO_OBJECT (this, "got an unknown event (Type: %d)", GST_EVENT_TYPE (event)); @@ -449,8 +451,8 @@ sink_restart: if (size / (width / 8) != samples || samples > max_discont) { GST_WARNING_OBJECT (this, - "Integer overflow for size=%d/samples=%d - broken stream", - size, samples); + "Integer overflow for size=%d/samples=%d (sample_diff=%ld) - broken stream", + size, samples, sample_diff); goto no_difference; } GST_INFO_OBJECT (this, diff --git a/ext/ogg/gstoggdemux.c b/ext/ogg/gstoggdemux.c index fc22cbab46..83d04e710d 100644 --- a/ext/ogg/gstoggdemux.c +++ b/ext/ogg/gstoggdemux.c @@ -406,7 +406,7 @@ get_relative (GstOggDemux * ogg, GstOggPad * cur, gint64 granpos, GstFormat out) GstFormat fmt; /* we're gonna ask our peer */ - if (!GST_PAD_PEER (cur->pad)) + if (!cur->pad || !GST_PAD_PEER (cur->pad)) return -1; /* lineair unit (time) */ @@ -614,10 +614,12 @@ gst_ogg_demux_src_event (GstPad * pad, GstEvent * event) GST_OGG_SET_STATE (ogg, GST_OGG_STATE_SEEK); FOR_PAD_IN_CURRENT_CHAIN (ogg, pad, - pad->flags |= GST_OGG_PAD_NEEDS_DISCONT;); + pad->flags |= GST_OGG_PAD_NEEDS_DISCONT; + ); if (GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH) { FOR_PAD_IN_CURRENT_CHAIN (ogg, pad, - pad->flags |= GST_OGG_PAD_NEEDS_FLUSH;); + pad->flags |= GST_OGG_PAD_NEEDS_FLUSH; + ); } GST_DEBUG_OBJECT (ogg, "initiating seeking to format %d, offset %" G_GUINT64_FORMAT, format, @@ -692,7 +694,8 @@ gst_ogg_demux_handle_event (GstPad * pad, GstEvent * event) gst_event_unref (event); GST_FLAG_UNSET (ogg, GST_OGG_FLAG_WAIT_FOR_DISCONT); FOR_PAD_IN_CURRENT_CHAIN (ogg, pad, - pad->flags |= GST_OGG_PAD_NEEDS_DISCONT;); + pad->flags |= GST_OGG_PAD_NEEDS_DISCONT; + ); break; default: gst_pad_event_default (pad, event); @@ -978,7 +981,8 @@ _find_chain_get_unknown_part (GstOggDemux * ogg, gint64 * start, gint64 * end) *end = G_MAXINT64; g_assert (ogg->current_chain >= 0); - FOR_PAD_IN_CURRENT_CHAIN (ogg, pad, *start = MAX (*start, pad->end_offset);); + FOR_PAD_IN_CURRENT_CHAIN (ogg, pad, *start = MAX (*start, pad->end_offset); + ); if (ogg->setup_state == SETUP_FIND_LAST_CHAIN) { *end = gst_file_pad_get_length (ogg->sinkpad); @@ -1107,7 +1111,8 @@ _find_streams_check (GstOggDemux * ogg) } else { endpos = G_MAXINT64; FOR_PAD_IN_CHAIN (ogg, pad, ogg->chains->len - 1, - endpos = MIN (endpos, pad->start_offset);); + endpos = MIN (endpos, pad->start_offset); + ); } if (!ogg->seek_skipped || gst_ogg_demux_position (ogg) >= endpos) { /* have we found the endposition for all streams yet? */ diff --git a/ext/pango/gsttextoverlay.c b/ext/pango/gsttextoverlay.c index bbd92b02e2..8b427ffb5c 100644 --- a/ext/pango/gsttextoverlay.c +++ b/ext/pango/gsttextoverlay.c @@ -443,7 +443,8 @@ gst_textoverlay_video_chain (GstPad * pad, GstData * _data) GST_BUFFER_TIMESTAMP (GST_BUFFER (data))) #define GST_DATA_DURATION(data) \ (GST_IS_EVENT (data) ? \ - gst_event_filler_get_duration (GST_EVENT (data)) : \ + ((GST_EVENT_TYPE (data) == GST_EVENT_FILLER) ? gst_event_filler_get_duration (GST_EVENT (data)) : \ + GST_CLOCK_TIME_NONE) : \ GST_BUFFER_DURATION (GST_BUFFER (data))) #define PAST_END(data, time) \ @@ -631,6 +632,11 @@ gst_textoverlay_finalize (GObject * object) { GstTextOverlay *overlay = GST_TEXTOVERLAY (object); + if (overlay->default_text) { + g_free (overlay->default_text); + overlay->default_text = NULL; + } + if (overlay->layout) { g_object_unref (overlay->layout); overlay->layout = NULL; @@ -751,12 +757,12 @@ gst_textoverlay_set_property (GObject * object, guint prop_id, desc = pango_font_description_from_string (g_value_get_string (value)); if (desc) { - g_message ("font description set: %s", g_value_get_string (value)); + GST_LOG ("font description set: %s", g_value_get_string (value)); pango_layout_set_font_description (overlay->layout, desc); pango_font_description_free (desc); render_text (overlay); } else - g_warning ("font description parse failed: %s", + GST_WARNING ("font description parse failed: %s", g_value_get_string (value)); break; } diff --git a/gst/playback/gstplaybasebin.c b/gst/playback/gstplaybasebin.c index eff94ae5ec..39b036be9f 100644 --- a/gst/playback/gstplaybasebin.c +++ b/gst/playback/gstplaybasebin.c @@ -344,8 +344,8 @@ group_destroy (GstPlayBaseGroup * group) * from the thread */ if (get_active_group (play_base_bin) == group) { GST_LOG ("removing preroll element %s", gst_element_get_name (element)); - gst_bin_remove (GST_BIN (play_base_bin->thread), element); - gst_bin_remove (GST_BIN (play_base_bin->thread), group->type[n].selector); + gst_bin_remove (group->type[n].bin, element); + gst_bin_remove (group->type[n].bin, group->type[n].selector); } else { /* else we can just unref it */ gst_object_unref (GST_OBJECT (element)); @@ -354,6 +354,7 @@ group_destroy (GstPlayBaseGroup * group) group->type[n].preroll = NULL; group->type[n].selector = NULL; + group->type[n].bin = NULL; } /* free the streaminfo too */ @@ -505,10 +506,12 @@ gen_preroll_element (GstPlayBaseBin * play_base_bin, group->type[type - 1].selector = selector; group->type[type - 1].preroll = preroll; if (type == GST_STREAM_TYPE_TEXT && play_base_bin->subtitle) { + group->type[type - 1].bin = GST_BIN (play_base_bin->subtitle); gst_bin_add (GST_BIN (play_base_bin->subtitle), selector); gst_bin_add (GST_BIN (play_base_bin->subtitle), preroll); gst_element_set_state (selector, GST_STATE_PAUSED); } else { + group->type[type - 1].bin = GST_BIN (play_base_bin->thread); gst_bin_add (GST_BIN (play_base_bin->thread), selector); gst_bin_add (GST_BIN (play_base_bin->thread), preroll); gst_element_set_state (selector, GST_STATE_PLAYING); @@ -1740,7 +1743,6 @@ gst_play_base_bin_add_element (GstBin * bin, GstElement * element) sched = gst_element_get_scheduler (GST_ELEMENT (play_base_bin->thread)); clock = gst_scheduler_get_clock (sched); gst_scheduler_set_clock (sched, clock); - } else { g_warning ("adding elements is not allowed in NULL"); } diff --git a/gst/playback/gstplaybasebin.h b/gst/playback/gstplaybasebin.h index 37ca17beb6..e30db72108 100644 --- a/gst/playback/gstplaybasebin.h +++ b/gst/playback/gstplaybasebin.h @@ -54,6 +54,7 @@ typedef struct struct { gint npads; + GstBin *bin; GstElement *preroll; GstElement *selector; gboolean done; diff --git a/gst/subparse/gstsubparse.c b/gst/subparse/gstsubparse.c index dc1b95308f..faabb34ecb 100644 --- a/gst/subparse/gstsubparse.c +++ b/gst/subparse/gstsubparse.c @@ -232,11 +232,21 @@ convert_encoding (GstSubparse * self, const gchar * str, gsize len) converted = g_string_new (NULL); while (len) { - GST_DEBUG ("Trying to convert '%s'", g_strndup (str, len)); +#ifndef GST_DISABLE_GST_DEBUG + gchar *dbg = g_strndup (str, len); + + GST_DEBUG ("Trying to convert '%s'", dbg); + g_free (dbg); +#endif + rv = g_locale_to_utf8 (str, len, &bytes_read, &bytes_written, NULL); - g_string_append_len (converted, rv, bytes_written); - len -= bytes_read; - str += bytes_read; + if (rv) { + g_string_append_len (converted, rv, bytes_written); + g_free (rv); + + len -= bytes_read; + str += bytes_read; + } if (len) { /* conversion error ocurred => skip one char */ len--; @@ -438,7 +448,6 @@ parse_subrip (GstSubparse * self, guint64 * out_start_time, *out_end_time = self->state.subrip.time2; rv = g_markup_escape_text (self->state.subrip.buf->str, self->state.subrip.buf->len); - rv = g_strdup (self->state.subrip.buf->str); g_string_truncate (self->state.subrip.buf, 0); self->state.subrip.state = 0; return rv; @@ -546,7 +555,15 @@ gst_subparse_buffer_format_autodetect (GstBuffer * buf) static gboolean need_init_regexps = TRUE; static regex_t mdvd_rx; static regex_t subrip_rx; - const gchar *str = GST_BUFFER_DATA (buf); + + /* Copy out chars to guard against short non-null-terminated buffers */ + const gint match_chars = 35; + gchar *match_str = + g_strndup ((const gchar *) GST_BUFFER_DATA (buf), MIN (match_chars, + GST_BUFFER_SIZE (buf))); + + if (!match_str) + return GST_SUB_PARSE_FORMAT_UNKNOWN; /* initialize the regexps used the first time around */ if (need_init_regexps) { @@ -554,9 +571,9 @@ gst_subparse_buffer_format_autodetect (GstBuffer * buf) char errstr[128]; need_init_regexps = FALSE; - regcomp (&mdvd_rx, "^\\{[0-9]+\\}\\{[0-9]+\\}", - REG_EXTENDED | REG_NEWLINE | REG_NOSUB); - if ((err = regcomp (&subrip_rx, "^1\x0d\x0a" + if ((err = regcomp (&mdvd_rx, "^\\{[0-9]+\\}\\{[0-9]+\\}", + REG_EXTENDED | REG_NEWLINE | REG_NOSUB) != 0) || + (err = regcomp (&subrip_rx, "^1(\x0d)?\x0a" "[0-9][0-9]:[0-9][0-9]:[0-9][0-9],[0-9]{3}" " --> [0-9][0-9]:[0-9][0-9]:[0-9][0-9],[0-9]{3}", REG_EXTENDED | REG_NEWLINE | REG_NOSUB)) != 0) { @@ -565,19 +582,24 @@ gst_subparse_buffer_format_autodetect (GstBuffer * buf) } } - if (regexec (&mdvd_rx, str, 0, NULL, 0) == 0) { + if (regexec (&mdvd_rx, match_str, 0, NULL, 0) == 0) { GST_LOG ("subparse: MicroDVD (frame based) format detected"); + g_free (match_str); return GST_SUB_PARSE_FORMAT_MDVDSUB; } - if (regexec (&subrip_rx, str, 0, NULL, 0) == 0) { + if (regexec (&subrip_rx, match_str, 0, NULL, 0) == 0) { GST_LOG ("subparse: SubRip (time based) format detected"); + g_free (match_str); return GST_SUB_PARSE_FORMAT_SUBRIP; } - if (!strncmp (str, "FORMAT=TIME", 11)) { + if (!strncmp (match_str, "FORMAT=TIME", 11)) { GST_LOG ("subparse: MPSub (time based) format detected"); + g_free (match_str); return GST_SUB_PARSE_FORMAT_MPSUB; } + GST_WARNING ("subparse: subtitle format autodetection failed!"); + g_free (match_str); return GST_SUB_PARSE_FORMAT_UNKNOWN; } @@ -719,7 +741,8 @@ gst_subparse_change_state (GstElement * element) switch (GST_STATE_TRANSITION (element)) { case GST_STATE_PAUSED_TO_READY: - self->parser.deinit (self); + if (self->parser.deinit) + self->parser.deinit (self); self->parser.type = GST_SUB_PARSE_FORMAT_UNKNOWN; self->parser_detected = FALSE; self->seek_time = GST_CLOCK_TIME_NONE; diff --git a/gst/typefind/gsttypefindfunctions.c b/gst/typefind/gsttypefindfunctions.c index 755907a947..f72e4a721d 100644 --- a/gst/typefind/gsttypefindfunctions.c +++ b/gst/typefind/gsttypefindfunctions.c @@ -1322,8 +1322,36 @@ dv_type_find (GstTypeFind * tf, gpointer private) } } -/*** audio/x-vorbis ***********************************************************/ +/*** application/ogg and application/x-annodex *****************************/ +static GstStaticCaps ogg_caps = GST_STATIC_CAPS ("application/ogg"); +static GstStaticCaps annodex_caps = GST_STATIC_CAPS ("application/x-annodex"); +static GstStaticCaps ogganx_caps = + GST_STATIC_CAPS ("application/ogg; application/x-annodex"); +#define OGGANX_CAPS (gst_static_caps_get(&ogganx_caps)) + +static void +ogganx_type_find (GstTypeFind * tf, gpointer private) +{ + guint8 *data = gst_type_find_peek (tf, 28, 8); + gboolean is_annodex = FALSE; + + if ((data != NULL) && (memcmp (data, "fishead\0", 8) == 0)) { + is_annodex = TRUE; + } + + data = gst_type_find_peek (tf, 0, 4); + if ((data != NULL) && (memcmp (data, "OggS", 4) == 0)) { + if (is_annodex == TRUE) { + gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, + gst_static_caps_get (&annodex_caps)); + } + gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, + gst_static_caps_get (&ogg_caps)); + } +} + +/*** audio/x-vorbis ***********************************************************/ static GstStaticCaps vorbis_caps = GST_STATIC_CAPS ("audio/x-vorbis"); #define VORBIS_CAPS (gst_static_caps_get(&vorbis_caps)) @@ -1471,8 +1499,59 @@ speex_type_find (GstTypeFind * tf, gpointer private) } } -/*** generic typefind for streams that have some data at a specific position***/ +/*** application/x-ogg-skeleton ***********************************************************/ +static GstStaticCaps ogg_skeleton_caps = +GST_STATIC_CAPS ("application/x-ogg-skeleton"); +#define OGG_SKELETON_CAPS (gst_static_caps_get(&ogg_skeleton_caps)) +static void +oggskel_type_find (GstTypeFind * tf, gpointer private) +{ + guint8 *data = gst_type_find_peek (tf, 0, 12); + if (data) { + /* 8 byte string "fishead\0" for the ogg skeleton stream */ + if (memcmp (data, "fishead\0", 8) != 0) + return; + data += 8; + + /* Require that the header contains version 3.0 */ + if (GST_READ_UINT16_LE (data) != 3) + return; + data += 2; + if (GST_READ_UINT16_LE (data) != 0) + return; + + gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, OGG_SKELETON_CAPS); + } +} + +static GstStaticCaps cmml_caps = GST_STATIC_CAPS ("text/x-cmml"); + +#define CMML_CAPS (gst_static_caps_get(&cmml_caps)) +static void +cmml_type_find (GstTypeFind * tf, gpointer private) +{ + guint8 *data = gst_type_find_peek (tf, 0, 12); + + if (data) { + /* 8 byte string "CMML\0\0\0\0" for the magic number */ + if (memcmp (data, "CMML\0\0\0\0", 8) != 0) + return; + data += 8; + + /* Require that the header contains at least version 2.0 */ + if (GST_READ_UINT16_LE (data) < 2) + return; + data += 2; + + if (GST_READ_UINT16_LE (data) != 0) + return; + + gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, CMML_CAPS); + } +} + +/*** generic typefind for streams that have some data at a specific position***/ typedef struct { guint8 *data; @@ -1564,7 +1643,7 @@ plugin_init (GstPlugin * plugin) static gchar *musepack_exts[] = { "mpc", NULL }; static gchar *mpeg_sys_exts[] = { "mpe", "mpeg", "mpg", NULL }; static gchar *mpeg_video_exts[] = { "mpv", "mpeg", "mpg", NULL }; - static gchar *ogg_exts[] = { "ogg", "ogm", NULL }; + static gchar *ogg_exts[] = { "anx", "ogg", "ogm", NULL }; static gchar *qt_exts[] = { "mov", NULL }; static gchar *rm_exts[] = { "ra", "ram", "rm", "rmvb", NULL }; static gchar *swf_exts[] = { "swf", "swfl", NULL }; @@ -1644,8 +1723,8 @@ plugin_init (GstPlugin * plugin) mpeg1_sys_type_find, mpeg_sys_exts, MPEG_SYS_CAPS, NULL); TYPE_FIND_REGISTER (plugin, "video/mpeg2", GST_RANK_SECONDARY, mpeg2_sys_type_find, mpeg_sys_exts, MPEG_SYS_CAPS, NULL); - TYPE_FIND_REGISTER_START_WITH (plugin, "application/ogg", GST_RANK_PRIMARY, - ogg_exts, "OggS", 4, GST_TYPE_FIND_MAXIMUM); + TYPE_FIND_REGISTER (plugin, "application/ogg", GST_RANK_PRIMARY, + ogganx_type_find, ogg_exts, OGGANX_CAPS, NULL); 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-stream", GST_RANK_MARGINAL, @@ -1731,6 +1810,10 @@ plugin_init (GstPlugin * plugin) ogmtext_type_find, NULL, OGMTEXT_CAPS, NULL); TYPE_FIND_REGISTER (plugin, "audio/x-speex", GST_RANK_PRIMARY, speex_type_find, NULL, SPEEX_CAPS, NULL); + TYPE_FIND_REGISTER (plugin, "application/x-ogg-skeleton", GST_RANK_PRIMARY, + oggskel_type_find, NULL, OGG_SKELETON_CAPS, NULL); + TYPE_FIND_REGISTER (plugin, "text/x-cmml", GST_RANK_PRIMARY, + cmml_type_find, NULL, CMML_CAPS, NULL); TYPE_FIND_REGISTER (plugin, "audio/x-m4a", GST_RANK_PRIMARY, m4a_type_find, m4a_exts, M4A_CAPS, NULL); TYPE_FIND_REGISTER (plugin, "application/x-3gp", GST_RANK_PRIMARY,