Commit 18881b68 authored by Ronald S. Bultje's avatar Ronald S. Bultje
Browse files

OGM text support, Matroska UTF-8 text support, deadlock fixes all over the...

OGM text support, Matroska UTF-8 text support, deadlock fixes all over the place, subtitle awareness in decodebin/pla...

Original commit message from CVS:
* configure.ac:
* ext/ogg/gstoggdemux.c: (gst_ogg_pad_new):
* ext/ogg/gstogmparse.c: (gst_ogm_text_parse_get_type),
(gst_ogm_text_parse_base_init), (gst_ogm_text_parse_init),
(gst_ogm_parse_get_sink_querytypes), (gst_ogm_parse_sink_convert),
(gst_ogm_parse_sink_query), (gst_ogm_parse_chain),
(gst_ogm_parse_plugin_init):
* ext/pango/gsttextoverlay.c: (gst_textoverlay_linkedpads),
(gst_textoverlay_link), (gst_textoverlay_getcaps),
(gst_textoverlay_event), (gst_textoverlay_video_chain),
(gst_textoverlay_loop), (gst_textoverlay_init), (plugin_init):
* ext/pango/gsttextoverlay.h:
* gst/matroska/matroska-demux.c: (gst_matroska_demux_add_stream),
(gst_matroska_demux_handle_seek_event),
(gst_matroska_demux_sync_streams),
(gst_matroska_demux_parse_blockgroup),
(gst_matroska_demux_subtitle_caps),
(gst_matroska_demux_plugin_init):
* gst/matroska/matroska-ids.h:
* gst/playback/gstdecodebin.c: (close_pad_link):
* gst/playback/gstplaybasebin.c: (gst_play_base_bin_init),
(gen_preroll_element), (remove_groups), (add_stream),
(new_decoded_pad), (setup_subtitles), (gen_source_element),
(setup_source):
* gst/playback/gstplaybasebin.h:
* gst/playback/gstplaybin.c: (gen_text_element), (setup_sinks):
* gst/subparse/Makefile.am:
* gst/subparse/gstsubparse.c: (gst_subparse_get_type),
(gst_subparse_base_init), (gst_subparse_class_init),
(gst_subparse_init), (gst_subparse_formats),
(gst_subparse_eventmask), (gst_subparse_event),
(gst_subparse_handle_event), (convert_encoding), (get_next_line),
(parse_mdvdsub), (parse_mdvdsub_init), (parse_subrip),
(parse_subrip_deinit), (parse_subrip_init), (parse_mpsub),
(parse_mpsub_deinit), (parse_mpsub_init),
(gst_subparse_buffer_format_autodetect),
(gst_subparse_format_autodetect), (gst_subparse_loop),
(gst_subparse_change_state), (gst_subparse_type_find),
(plugin_init):
* gst/subparse/gstsubparse.h:
* gst/typefind/gsttypefindfunctions.c: (ogmtext_type_find),
(plugin_init):
Add subtitle support, .sub parser (supports SRT and MPsub),
OGM text support, Matroska UTF-8 text support, deadlock fixes
all over the place, subtitle awareness in decodebin/playbin
and some fixes to textoverlay to handle subtitles in a stream
correctly. Fixes #100931.
parent e59bf40b
2005-01-08 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
* configure.ac:
* ext/ogg/gstoggdemux.c: (gst_ogg_pad_new):
* ext/ogg/gstogmparse.c: (gst_ogm_text_parse_get_type),
(gst_ogm_text_parse_base_init), (gst_ogm_text_parse_init),
(gst_ogm_parse_get_sink_querytypes), (gst_ogm_parse_sink_convert),
(gst_ogm_parse_sink_query), (gst_ogm_parse_chain),
(gst_ogm_parse_plugin_init):
* ext/pango/gsttextoverlay.c: (gst_textoverlay_linkedpads),
(gst_textoverlay_link), (gst_textoverlay_getcaps),
(gst_textoverlay_event), (gst_textoverlay_video_chain),
(gst_textoverlay_loop), (gst_textoverlay_init), (plugin_init):
* ext/pango/gsttextoverlay.h:
* gst/matroska/matroska-demux.c: (gst_matroska_demux_add_stream),
(gst_matroska_demux_handle_seek_event),
(gst_matroska_demux_sync_streams),
(gst_matroska_demux_parse_blockgroup),
(gst_matroska_demux_subtitle_caps),
(gst_matroska_demux_plugin_init):
* gst/matroska/matroska-ids.h:
* gst/playback/gstdecodebin.c: (close_pad_link):
* gst/playback/gstplaybasebin.c: (gst_play_base_bin_init),
(gen_preroll_element), (remove_groups), (add_stream),
(new_decoded_pad), (setup_subtitles), (gen_source_element),
(setup_source):
* gst/playback/gstplaybasebin.h:
* gst/playback/gstplaybin.c: (gen_text_element), (setup_sinks):
* gst/subparse/Makefile.am:
* gst/subparse/gstsubparse.c: (gst_subparse_get_type),
(gst_subparse_base_init), (gst_subparse_class_init),
(gst_subparse_init), (gst_subparse_formats),
(gst_subparse_eventmask), (gst_subparse_event),
(gst_subparse_handle_event), (convert_encoding), (get_next_line),
(parse_mdvdsub), (parse_mdvdsub_init), (parse_subrip),
(parse_subrip_deinit), (parse_subrip_init), (parse_mpsub),
(parse_mpsub_deinit), (parse_mpsub_init),
(gst_subparse_buffer_format_autodetect),
(gst_subparse_format_autodetect), (gst_subparse_loop),
(gst_subparse_change_state), (gst_subparse_type_find),
(plugin_init):
* gst/subparse/gstsubparse.h:
* gst/typefind/gsttypefindfunctions.c: (ogmtext_type_find),
(plugin_init):
Add subtitle support, .sub parser (supports SRT and MPsub),
OGM text support, Matroska UTF-8 text support, deadlock fixes
all over the place, subtitle awareness in decodebin/playbin
and some fixes to textoverlay to handle subtitles in a stream
correctly. Fixes #100931.
2005-01-08 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
 
* ext/vorbis/vorbisdec.c: (vorbis_dec_src_query):
......
......@@ -408,6 +408,7 @@ GST_PLUGINS_ALL="\
spectrum \
speed \
stereo \
subparse \
switch \
synaesthesia \
tags \
......@@ -1972,6 +1973,7 @@ gst/smpte/Makefile
gst/spectrum/Makefile
gst/speed/Makefile
gst/stereo/Makefile
gst/subparse/Makefile
gst/switch/Makefile
gst/synaesthesia/Makefile
gst/tags/Makefile
......
......@@ -614,12 +614,10 @@ 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,
......@@ -694,8 +692,7 @@ 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);
......@@ -981,8 +978,7 @@ _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);
......@@ -1111,8 +1107,7 @@ _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? */
......@@ -1308,6 +1303,7 @@ gst_ogg_pad_new (GstOggDemux * ogg, int serial)
ret->start_offset = ret->end_offset = -1;
ret->start = -1;
ret->start_found = ret->end_found = FALSE;
ret->offset = GST_BUFFER_OFFSET_NONE;
return ret;
}
......@@ -1461,6 +1457,37 @@ gst_ogg_demux_push (GstOggDemux * ogg, ogg_page * page)
cur->pad = NULL;
}
}
static void
gst_ogg_sync (GstOggDemux * ogg, GstOggPad * cur)
{
gint64 bias, time;
GstFormat fmt = GST_FORMAT_TIME;
time = get_relative (ogg, cur, cur->offset, GST_FORMAT_TIME);
FOR_PAD_IN_CURRENT_CHAIN (ogg, pad,
if (pad->pad && GST_PAD_PEER (pad->pad) &&
pad->offset != GST_BUFFER_OFFSET_NONE) {
if (gst_pad_query (GST_PAD_PEER (pad->pad),
GST_QUERY_POSITION, &fmt, &bias) && bias + GST_SECOND < time) {
GstEvent * event;
gint64 val = 0;
GstFormat fmt = GST_FORMAT_DEFAULT;
event = gst_event_new_filler_stamped (bias,
time - bias - GST_SECOND / 2);
GST_DEBUG ("Syncing stream %d at time %" GST_TIME_FORMAT
" and duration %" GST_TIME_FORMAT,
pad->serial, GST_TIME_ARGS (bias),
GST_TIME_ARGS (time - bias - GST_SECOND / 2));
gst_pad_push (pad->pad, GST_DATA (event));
gst_pad_convert (GST_PAD_PEER (pad->pad),
GST_FORMAT_TIME, bias, &fmt, &val);
/* hmm... */
pad->offset = pad->start + val;}
}
);
}
static void
gst_ogg_pad_push (GstOggDemux * ogg, GstOggPad * pad)
{
......@@ -1554,6 +1581,7 @@ gst_ogg_pad_push (GstOggDemux * ogg, GstOggPad * pad)
} else {
event = gst_event_new_discontinuous (FALSE,
GST_FORMAT_DEFAULT, discont, GST_FORMAT_UNDEFINED);
pad->offset = discont;
}
} else {
event = gst_event_new_discontinuous (FALSE,
......@@ -1577,6 +1605,7 @@ gst_ogg_pad_push (GstOggDemux * ogg, GstOggPad * pad)
if (packet.granulepos != -1 && pos != -1)
GST_BUFFER_OFFSET_END (buf) = pos;
pad->offset = packet.granulepos;
gst_ogg_sync (ogg, pad);
if (GST_PAD_IS_USABLE (pad->pad))
gst_pad_push (pad->pad, GST_DATA (buf));
break;
......
......@@ -39,6 +39,10 @@ GST_DEBUG_CATEGORY_STATIC (gst_ogm_parse_debug);
#define GST_IS_OGM_AUDIO_PARSE(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_OGM_AUDIO_PARSE))
#define GST_TYPE_OGM_TEXT_PARSE (gst_ogm_text_parse_get_type())
#define GST_IS_OGM_TEXT_PARSE(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_OGM_TEXT_PARSE))
#define GST_TYPE_OGM_PARSE (gst_ogm_parse_get_type())
#define GST_OGM_PARSE(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_OGM_PARSE, GstOgmParse))
......@@ -87,6 +91,7 @@ typedef struct _stream_header
{
stream_header_video video;
stream_header_audio audio;
/* text has no additional data */
} s;
} stream_header;
......@@ -116,22 +121,31 @@ GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
static GstStaticPadTemplate ogm_audio_parse_sink_template_factory =
GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
GST_STATIC_CAPS ("application/x-ogm-audio"));
static GstPadTemplate *video_src_templ, *audio_src_templ;
static GstStaticPadTemplate ogm_text_parse_sink_template_factory =
GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
GST_STATIC_CAPS ("application/x-ogm-text"));
static GstPadTemplate *video_src_templ, *audio_src_templ, *text_src_templ;
static GType gst_ogm_audio_parse_get_type (void);
static GType gst_ogm_video_parse_get_type (void);
static GType gst_ogm_text_parse_get_type (void);
static GType gst_ogm_parse_get_type (void);
static void gst_ogm_audio_parse_base_init (GstOgmParseClass * klass);
static void gst_ogm_video_parse_base_init (GstOgmParseClass * klass);
static void gst_ogm_text_parse_base_init (GstOgmParseClass * klass);
static void gst_ogm_parse_class_init (GstOgmParseClass * klass);
static void gst_ogm_parse_init (GstOgmParse * ogm);
static void gst_ogm_video_parse_init (GstOgmParse * ogm);
static void gst_ogm_audio_parse_init (GstOgmParse * ogm);
static void gst_ogm_text_parse_init (GstOgmParse * ogm);
static const GstFormat *gst_ogm_parse_get_sink_formats (GstPad * pad);
static const GstQueryType *gst_ogm_parse_get_sink_querytypes (GstPad * pad);
static gboolean gst_ogm_parse_sink_convert (GstPad * pad, GstFormat src_format,
gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
static gboolean gst_ogm_parse_sink_query (GstPad * pad, GstQueryType type,
GstFormat * fmt, gint64 * val);
static void gst_ogm_parse_chain (GstPad * pad, GstData * data);
......@@ -217,6 +231,32 @@ gst_ogm_video_parse_get_type (void)
return ogm_video_parse_type;
}
GType
gst_ogm_text_parse_get_type (void)
{
static GType ogm_text_parse_type = 0;
if (!ogm_text_parse_type) {
static const GTypeInfo ogm_text_parse_info = {
sizeof (GstOgmParseClass),
(GBaseInitFunc) gst_ogm_text_parse_base_init,
NULL,
NULL,
NULL,
NULL,
sizeof (GstOgmParse),
0,
(GInstanceInitFunc) gst_ogm_text_parse_init,
};
ogm_text_parse_type =
g_type_register_static (GST_TYPE_OGM_PARSE,
"GstOgmTextParse", &ogm_text_parse_info, 0);
}
return ogm_text_parse_type;
}
static void
gst_ogm_audio_parse_base_init (GstOgmParseClass * klass)
{
......@@ -257,6 +297,26 @@ gst_ogm_video_parse_base_init (GstOgmParseClass * klass)
gst_element_class_add_pad_template (element_class, video_src_templ);
}
static void
gst_ogm_text_parse_base_init (GstOgmParseClass * klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
static GstElementDetails gst_ogm_text_parse_details =
GST_ELEMENT_DETAILS ("OGM text stream parser",
"Codec/Decoder/Subtitle",
"parse an OGM text header and stream",
"Ronald Bultje <rbultje@ronald.bitfreak.net>");
GstCaps *caps = gst_caps_new_simple ("text/plain", NULL);
gst_element_class_set_details (element_class, &gst_ogm_text_parse_details);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&ogm_text_parse_sink_template_factory));
text_src_templ = gst_pad_template_new ("src",
GST_PAD_SRC, GST_PAD_SOMETIMES, caps);
gst_element_class_add_pad_template (element_class, text_src_templ);
}
static void
gst_ogm_parse_class_init (GstOgmParseClass * klass)
{
......@@ -317,6 +377,30 @@ gst_ogm_video_parse_init (GstOgmParse * ogm)
ogm->srcpadtempl = video_src_templ;
}
static void
gst_ogm_text_parse_init (GstOgmParse * ogm)
{
GstPadTemplate *templ;
/* create the pads */
templ = gst_static_pad_template_get (&ogm_text_parse_sink_template_factory);
ogm->sinkpad = gst_pad_new_from_template (templ, "sink");
gst_pad_set_convert_function (ogm->sinkpad, gst_ogm_parse_sink_convert);
gst_pad_set_formats_function (ogm->sinkpad, gst_ogm_parse_get_sink_formats);
gst_pad_set_query_type_function (ogm->sinkpad,
gst_ogm_parse_get_sink_querytypes);
gst_pad_set_query_function (ogm->sinkpad, gst_ogm_parse_sink_query);
gst_pad_set_chain_function (ogm->sinkpad, gst_ogm_parse_chain);
gst_element_add_pad (GST_ELEMENT (ogm), ogm->sinkpad);
#if 0
ogm->srcpad = gst_pad_new_from_template (text_src_templ, "src");
gst_pad_use_explicit_caps (ogm->srcpad);
gst_element_add_pad (GST_ELEMENT (ogm), ogm->srcpad);
#endif
ogm->srcpadtempl = text_src_templ;
}
static const GstFormat *
gst_ogm_parse_get_sink_formats (GstPad * pad)
{
......@@ -329,6 +413,17 @@ gst_ogm_parse_get_sink_formats (GstPad * pad)
return formats;
}
static const GstQueryType *
gst_ogm_parse_get_sink_querytypes (GstPad * pad)
{
static const GstQueryType types[] = {
GST_QUERY_POSITION,
0
};
return types;
}
static gboolean
gst_ogm_parse_sink_convert (GstPad * pad,
GstFormat src_format, gint64 src_value,
......@@ -347,6 +442,7 @@ gst_ogm_parse_sink_convert (GstPad * pad,
res = TRUE;
break;
case 'v':
case 't':
*dest_value = (GST_SECOND / 10000000) *
ogm->hdr.time_unit * src_value;
res = TRUE;
......@@ -359,6 +455,28 @@ gst_ogm_parse_sink_convert (GstPad * pad,
break;
}
break;
case GST_FORMAT_TIME:
switch (*dest_format) {
case GST_FORMAT_DEFAULT:
switch (ogm->hdr.streamtype[0]) {
case 'a':
*dest_value = ogm->hdr.samples_per_unit * src_value / GST_SECOND;
res = TRUE;
break;
case 'v':
case 't':
*dest_value = src_value /
((GST_SECOND / 10000000) * ogm->hdr.time_unit);
res = TRUE;
break;
default:
break;
}
break;
default:
break;
}
break;
default:
break;
}
......@@ -366,6 +484,21 @@ gst_ogm_parse_sink_convert (GstPad * pad,
return res;
}
static gboolean
gst_ogm_parse_sink_query (GstPad * pad,
GstQueryType type, GstFormat * fmt, gint64 * val)
{
GstOgmParse *ogm = GST_OGM_PARSE (gst_pad_get_parent (pad));
if (type != GST_QUERY_POSITION)
return FALSE;
if (*fmt != GST_FORMAT_DEFAULT && *fmt != GST_FORMAT_TIME)
return FALSE;
return gst_pad_convert (pad,
GST_FORMAT_DEFAULT, ogm->next_granulepos, fmt, val);
}
static void
gst_ogm_parse_chain (GstPad * pad, GstData * dat)
{
......@@ -394,6 +527,8 @@ gst_ogm_parse_chain (GstPad * pad, GstData * dat)
ogm->hdr.s.audio.channels = GST_READ_UINT32_LE (&data[45]);
ogm->hdr.s.audio.blockalign = GST_READ_UINT32_LE (&data[47]);
ogm->hdr.s.audio.avgbytespersec = GST_READ_UINT32_LE (&data[49]);
} else if (!memcmp (&data[1], "text\000\000\000\000", 8)) {
/* nothing here */
} else {
GST_ELEMENT_ERROR (ogm, STREAM, WRONG_TYPE,
("Unknown stream type"), (NULL));
......@@ -448,6 +583,13 @@ gst_ogm_parse_chain (GstPad * pad, GstData * dat)
"framerate", G_TYPE_DOUBLE, 10000000. / ogm->hdr.time_unit, NULL);
break;
}
case 't':
GST_LOG_OBJECT (ogm, "Type: %s, s/u: %" G_GINT64_FORMAT
", timeunit=%" G_GINT64_FORMAT,
ogm->hdr.streamtype, ogm->hdr.samples_per_unit,
ogm->hdr.time_unit);
caps = gst_caps_new_simple ("text/plain", NULL);
break;
default:
g_assert_not_reached ();
}
......@@ -491,15 +633,19 @@ gst_ogm_parse_chain (GstPad * pad, GstData * dat)
ogm->next_granulepos = GST_BUFFER_OFFSET_END (buf);
}
switch (ogm->hdr.streamtype[0]) {
case 'v':
case 't':
case 'v':{
gint samples = (ogm->hdr.streamtype[0] == 'v') ? 1 : xsize;
if (keyframe)
GST_BUFFER_FLAG_SET (sbuf, GST_BUFFER_KEY_UNIT);
GST_BUFFER_TIMESTAMP (sbuf) = (GST_SECOND / 10000000) *
ogm->next_granulepos * ogm->hdr.time_unit;
GST_BUFFER_DURATION (sbuf) = (GST_SECOND / 10000000) *
ogm->hdr.time_unit;
ogm->next_granulepos++;
ogm->hdr.time_unit * samples;
ogm->next_granulepos += samples;
break;
}
case 'a':
GST_BUFFER_TIMESTAMP (sbuf) = GST_SECOND *
ogm->next_granulepos / ogm->hdr.samples_per_unit;
......@@ -508,9 +654,13 @@ gst_ogm_parse_chain (GstPad * pad, GstData * dat)
ogm->next_granulepos += xsize;
break;
default:
g_assert_not_reached ();
gst_buffer_unref (sbuf);
sbuf = NULL;
GST_ELEMENT_ERROR (ogm, RESOURCE, SYNC, (NULL), (NULL));
break;
}
gst_pad_push (ogm->srcpad, GST_DATA (sbuf));
if (sbuf)
gst_pad_push (ogm->srcpad, GST_DATA (sbuf));
} else {
GST_ELEMENT_ERROR (ogm, STREAM, WRONG_TYPE,
("Wrong packet startcode 0x%02x", data[0]), (NULL));
......@@ -548,7 +698,9 @@ gst_ogm_parse_plugin_init (GstPlugin * plugin)
GST_DEBUG_CATEGORY_INIT (gst_ogm_parse_debug, "ogmparse", 0, "ogm parser");
return gst_element_register (plugin, "ogmaudioparse", GST_RANK_PRIMARY,
GST_TYPE_OGM_AUDIO_PARSE)
&& gst_element_register (plugin, "ogmvideoparse", GST_RANK_PRIMARY,
GST_TYPE_OGM_VIDEO_PARSE);
GST_TYPE_OGM_AUDIO_PARSE) &&
gst_element_register (plugin, "ogmvideoparse", GST_RANK_PRIMARY,
GST_TYPE_OGM_VIDEO_PARSE) &&
gst_element_register (plugin, "ogmtextparse", GST_RANK_PRIMARY,
GST_TYPE_OGM_TEXT_PARSE);
}
......@@ -24,6 +24,9 @@
#include <gst/gst.h>
#include "gsttextoverlay.h"
GST_DEBUG_CATEGORY_STATIC (pango_debug);
#define GST_CAT_DEFAULT pango_debug
static GstElementDetails textoverlay_details = {
"Text Overlay",
"Filter/Editor/Video",
......@@ -224,23 +227,78 @@ render_text (GstTextOverlay * overlay)
/* return GST_PAD_LINK_DONE; */
/* } */
static GList *
gst_textoverlay_linkedpads (GstPad * pad)
{
GstPad *otherpad;
GstTextOverlay *overlay;
overlay = GST_TEXTOVERLAY (gst_pad_get_parent (pad));
if (pad == overlay->text_sinkpad)
return NULL;
otherpad = (pad == overlay->video_sinkpad) ?
overlay->srcpad : overlay->video_sinkpad;
return g_list_append (NULL, otherpad);
}
static GstPadLinkReturn
gst_textoverlay_video_sinkconnect (GstPad * pad, const GstCaps * caps)
gst_textoverlay_link (GstPad * pad, const GstCaps * caps)
{
GstPad *otherpad;
GstTextOverlay *overlay;
GstStructure *structure;
GstPadLinkReturn ret;
overlay = GST_TEXTOVERLAY (gst_pad_get_parent (pad));
otherpad = (pad == overlay->video_sinkpad) ?
overlay->srcpad : overlay->video_sinkpad;
ret = gst_pad_try_set_caps (otherpad, caps);
if (GST_PAD_LINK_FAILED (ret))
return ret;
structure = gst_caps_get_structure (caps, 0);
overlay->width = overlay->height = 0;
gst_structure_get_int (structure, "width", &overlay->width);
gst_structure_get_int (structure, "height", &overlay->height);
return gst_pad_try_set_caps (overlay->srcpad, caps);
return ret;
}
static GstCaps *
gst_textoverlay_getcaps (GstPad * pad)
{
GstPad *otherpad;
GstTextOverlay *overlay;
GstCaps *caps, *rcaps;
const GstCaps *tcaps;
overlay = GST_TEXTOVERLAY (gst_pad_get_parent (pad));
otherpad = (pad == overlay->video_sinkpad) ?
overlay->srcpad : overlay->video_sinkpad;
caps = gst_pad_get_allowed_caps (otherpad);
tcaps = gst_pad_get_pad_template_caps (pad);
rcaps = gst_caps_intersect (caps, tcaps);
gst_caps_free (caps);
return rcaps;
}
static gboolean
gst_textoverlay_event (GstPad * pad, GstEvent * event)
{
GstTextOverlay *overlay = GST_TEXTOVERLAY (gst_pad_get_parent (pad));
if (GST_EVENT_TYPE (event) == GST_EVENT_SEEK &&
GST_PAD_IS_LINKED (overlay->text_sinkpad)) {
gst_event_ref (event);
gst_pad_send_event (GST_PAD_PEER (overlay->text_sinkpad), event);
}
return gst_pad_send_event (GST_PAD_PEER (overlay->video_sinkpad), event);
}
static void
gst_text_overlay_blit_yuv420 (GstTextOverlay * overlay, FT_Bitmap * bitmap,
......@@ -353,9 +411,9 @@ gst_textoverlay_video_chain (GstPad * pad, GstData * _data)
y0 = overlay->y0;
switch (overlay->valign) {
case GST_TEXT_OVERLAY_VALIGN_BOTTOM:
y0 += overlay->bitmap.rows;
y0 = overlay->height - overlay->bitmap.rows - y0;
break;
case GST_TEXT_OVERLAY_VALIGN_BASELINE:
case GST_TEXT_OVERLAY_VALIGN_BASELINE: /* ? */
y0 -= (overlay->bitmap.rows - overlay->baseline_y);
break;
case GST_TEXT_OVERLAY_VALIGN_TOP:
......@@ -366,10 +424,10 @@ gst_textoverlay_video_chain (GstPad * pad, GstData * _data)
case GST_TEXT_OVERLAY_HALIGN_LEFT:
break;
case GST_TEXT_OVERLAY_HALIGN_RIGHT:
x0 -= overlay->bitmap.width;
x0 = overlay->width - overlay->bitmap.width - x0;
break;
case GST_TEXT_OVERLAY_HALIGN_CENTER:
x0 -= overlay->bitmap.width / 2;
x0 = (overlay->width - overlay->bitmap.width) / 2;
break;
}
......@@ -379,10 +437,19 @@ gst_textoverlay_video_chain (GstPad * pad, GstData * _data)
gst_pad_push (overlay->srcpad, GST_DATA (buf));
}
#define PAST_END(buffer, time) \
(GST_BUFFER_TIMESTAMP (buffer) != GST_CLOCK_TIME_NONE && \
GST_BUFFER_DURATION (buffer) != GST_CLOCK_TIME_NONE && \
GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer) \
#define GST_DATA_TIMESTAMP(data) \
(GST_IS_EVENT (data) ? \
GST_EVENT_TIMESTAMP (GST_EVENT (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_BUFFER_DURATION (GST_BUFFER (data)))
#define PAST_END(data, time) \
(GST_DATA_TIMESTAMP (data) != GST_CLOCK_TIME_NONE && \
GST_DATA_DURATION (data) != GST_CLOCK_TIME_NONE && \
GST_DATA_TIMESTAMP (data) + GST_DATA_DURATION (data) \
< (time))
static void
......@@ -396,8 +463,36 @@ gst_textoverlay_loop (GstElement * element)
g_return_if_fail (GST_IS_TEXTOVERLAY (element));
overlay = GST_TEXTOVERLAY (element);
video_frame = GST_BUFFER (gst_pad_pull (overlay->video_sinkpad));
do {
GST_DEBUG ("Attempting to pull next video frame");
video_frame = GST_BUFFER (gst_pad_pull (overlay->video_sinkpad));
if (GST_IS_EVENT (video_frame)) {
GstEvent *event = GST_EVENT (video_frame);
GstEventType type = GST_EVENT_TYPE (event);
gst_pad_event_default (overlay->video_sinkpad, event);
GST_DEBUG ("Received event of type %d", type);
if (type == GST_EVENT_INTERRUPT)
return;
else if (type == GST_EVENT_EOS) {
/* EOS text stream */
GstData *data = NULL;
do {
if (data)
gst_data_unref (data);
data = gst_pad_pull (overlay->text_sinkpad);
} while (!GST_IS_EVENT (data) ||
GST_EVENT_TYPE (data) == GST_EVENT_EOS);
gst_data_unref (data);
return;
}