From 024d0e56f5e12a96d2ab0c92c27c44db2fdabe01 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Mon, 14 Jul 2008 08:18:58 +0000 Subject: [PATCH] gst/playback/: First stab at integrating DVD subpicture overlay into playbin. Successfully plugs and plays, but the q... Original commit message from CVS: * gst/playback/gstplaybasebin.c: * gst/playback/gstplaybasebin.h: * gst/playback/gstplaybin.c: * gst/playback/gststreamselector.c: First stab at integrating DVD subpicture overlay into playbin. Successfully plugs and plays, but the queues need shrinking - 3 seconds of video is too much buffering. --- ChangeLog | 10 +++ common | 2 +- gst/playback/gstplaybasebin.c | 7 +- gst/playback/gstplaybasebin.h | 4 +- gst/playback/gstplaybin.c | 143 +++++++++++++++++++++++++++---- gst/playback/gststreamselector.c | 4 +- 6 files changed, 150 insertions(+), 20 deletions(-) diff --git a/ChangeLog b/ChangeLog index b2ddd9c0d0..774f725ef7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2008-07-14 Jan Schmidt + + * gst/playback/gstplaybasebin.c: + * gst/playback/gstplaybasebin.h: + * gst/playback/gstplaybin.c: + * gst/playback/gststreamselector.c: + First stab at integrating DVD subpicture overlay into + playbin. Successfully plugs and plays, but the queues need + shrinking - 3 seconds of video is too much buffering. + 2008-07-11 Stefan Kost * gst/audioconvert/gstaudioconvert.c: diff --git a/common b/common index 79ade7b9c9..a100efef18 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 79ade7b9c9bf47eee491ceee4cf3ea116140ad35 +Subproject commit a100efef186a5f8999fe3aa42c0720f5123c08eb diff --git a/gst/playback/gstplaybasebin.c b/gst/playback/gstplaybasebin.c index 8bd9cdbf26..aa47d771e4 100644 --- a/gst/playback/gstplaybasebin.c +++ b/gst/playback/gstplaybasebin.c @@ -791,6 +791,8 @@ gen_preroll_element (GstPlayBaseBin * play_base_bin, prename = "text"; else if (type == GST_STREAM_TYPE_AUDIO) prename = "audio"; + else if (type == GST_STREAM_TYPE_SUBPICTURE) + prename = "subpicture"; else g_return_if_reached (); @@ -1337,6 +1339,9 @@ new_decoded_pad_full (GstElement * element, GstPad * pad, gboolean last, if (g_str_has_prefix (mimetype, "audio/") && parent != GST_OBJECT_CAST (play_base_bin->subtitle)) { type = GST_STREAM_TYPE_AUDIO; + } else if (g_str_has_prefix (mimetype, "video/x-dvd-subpicture") && + parent != GST_OBJECT_CAST (play_base_bin->subtitle)) { + type = GST_STREAM_TYPE_SUBPICTURE; } else if (g_str_has_prefix (mimetype, "video/") && parent != GST_OBJECT_CAST (play_base_bin->subtitle)) { type = GST_STREAM_TYPE_VIDEO; @@ -1569,7 +1574,7 @@ static const gchar *no_media_mimes[] = { /* mime types we consider raw media */ static const gchar *raw_mimes[] = { - "audio/x-raw", "video/x-raw", NULL + "audio/x-raw", "video/x-raw", "video/x-dvd-subpicture", NULL }; #define IS_STREAM_URI(uri) (array_has_value (stream_uris, uri)) diff --git a/gst/playback/gstplaybasebin.h b/gst/playback/gstplaybasebin.h index 256ba66a17..b567794a90 100644 --- a/gst/playback/gstplaybasebin.h +++ b/gst/playback/gstplaybasebin.h @@ -63,8 +63,8 @@ typedef struct GstElement *preroll; GstElement *selector; gboolean done; -#define NUM_TYPES 3 - } type[NUM_TYPES]; /* AUDIO, VIDEO, TEXT */ +#define NUM_TYPES 4 + } type[NUM_TYPES]; /* AUDIO, VIDEO, TEXT, SUBPIC */ } GstPlayBaseGroup; struct _GstPlayBaseBin { diff --git a/gst/playback/gstplaybin.c b/gst/playback/gstplaybin.c index 3e8d0a7325..fe1e20eff4 100644 --- a/gst/playback/gstplaybin.c +++ b/gst/playback/gstplaybin.c @@ -262,6 +262,7 @@ struct _GstPlayBin GstElement *pending_visualisation; GstElement *volume_element; GstElement *textoverlay_element; + GstElement *spu_element; gfloat volume; /* these are the currently active sinks */ @@ -431,6 +432,7 @@ gst_play_bin_init (GstPlayBin * play_bin) play_bin->pending_visualisation = NULL; play_bin->volume_element = NULL; play_bin->textoverlay_element = NULL; + play_bin->spu_element = NULL; play_bin->volume = 1.0; play_bin->sinks = NULL; play_bin->frame = NULL; @@ -476,6 +478,10 @@ gst_play_bin_dispose (GObject * object) gst_object_unref (play_bin->textoverlay_element); play_bin->textoverlay_element = NULL; } + if (play_bin->spu_element != NULL) { + gst_object_unref (play_bin->spu_element); + play_bin->spu_element = NULL; + } g_free (play_bin->font_desc); play_bin->font_desc = NULL; @@ -911,7 +917,7 @@ link_failed: * | tbin +-------------+ | * | +-----+ | textoverlay | +------+ | * | | csp | +--video_sink | | vbin | | - * video_sink-sink src+ +-text_sink src-sink | | + * video_sink-sink src+ +-text_sink src---sink | | * | +-----+ | +-------------+ +------+ | * text_sink-------------+ | * +--------------------------------------------------+ @@ -920,16 +926,11 @@ link_failed: * videosink without the text_sink pad. */ static GstElement * -gen_text_element (GstPlayBin * play_bin) +add_text_element (GstPlayBin * play_bin, GstElement * vbin) { - GstElement *element, *csp, *overlay, *vbin; + GstElement *element, *csp, *overlay; GstPad *pad; - /* Create the video rendering bin, error is posted when this fails. */ - vbin = gen_video_element (play_bin); - if (!vbin) - return NULL; - /* Text overlay */ overlay = gst_element_factory_make ("textoverlay", "overlay"); @@ -969,6 +970,13 @@ gen_text_element (GstPlayBin * play_bin) gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad)); gst_object_unref (pad); + /* If the vbin provides a subpicture sink pad, ghost it too */ + pad = gst_element_get_static_pad (vbin, "subpicture_sink"); + if (pad) { + gst_element_add_pad (element, gst_ghost_pad_new ("subpicture_sink", pad)); + gst_object_unref (pad); + } + /* Set state to READY */ gst_element_set_state (element, GST_STATE_READY); @@ -984,6 +992,74 @@ no_overlay: } } +/* make an element for rendering DVD subpictures onto output video + * + * +---------------------------------------------+ + * | tbin +--------+ | + * | +-----+ | | +------+ | + * | | csp | src-videosink | | vbin | | + * video_sink-sink src+ | src-sink | | + * | +-----+ +subpicture | +------+ | + * subpicture_pad--------+ +--------+ | + * +---------- ----------------------------------+ + * + */ +static GstElement * +add_spu_element (GstPlayBin * play_bin, GstElement * vbin) +{ + GstElement *element, *csp, *overlay; + GstPad *pad; + + /* DVD spu overlay */ + GST_DEBUG_OBJECT (play_bin, "Attempting to insert DVD SPU element"); + + overlay = gst_element_factory_make ("dvdspu", "overlay"); + + /* If no overlay return the video bin without subpicture support. */ + if (!overlay) + goto no_overlay; + + /* Create our bin */ + element = gst_bin_new ("spubin"); + + /* Take a ref */ + play_bin->spu_element = GST_ELEMENT_CAST (gst_object_ref (overlay)); + + /* we know this will succeed, as the video bin already created one before */ + csp = gst_element_factory_make ("ffmpegcolorspace", "spucsp"); + + /* Add our elements */ + gst_bin_add_many (GST_BIN_CAST (element), csp, overlay, vbin, NULL); + + /* Link */ + gst_element_link_pads (csp, "src", overlay, "video"); + gst_element_link_pads (overlay, "src", vbin, "sink"); + + /* Add ghost pad on the subpicture bin so it looks like vbin */ + pad = gst_element_get_static_pad (csp, "sink"); + gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad)); + gst_object_unref (pad); + + pad = gst_element_get_static_pad (overlay, "subpicture"); + gst_element_add_pad (element, gst_ghost_pad_new ("subpicture_sink", pad)); + gst_object_unref (pad); + + /* Set state to READY */ + gst_element_set_state (element, GST_STATE_READY); + + return element; + + /* ERRORS */ +no_overlay: + { + post_missing_element_message (play_bin, "dvdspu"); + GST_WARNING_OBJECT (play_bin, + "No DVD overlay (dvdspu) element. " + "menu highlight/subtitles unavailable"); + return vbin; + } +} + /* make the element (bin) that contains the elements needed to perform * audio playback. * @@ -1479,8 +1555,10 @@ static gboolean setup_sinks (GstPlayBaseBin * play_base_bin, GstPlayBaseGroup * group) { GstPlayBin *play_bin = GST_PLAY_BIN (play_base_bin); + gboolean have_video = FALSE; gboolean need_vis = FALSE; gboolean need_text = FALSE; + gboolean need_spu = FALSE; GstPad *textsrcpad = NULL, *pad = NULL, *origtextsrcpad = NULL; GstElement *sink; gboolean res = TRUE; @@ -1492,10 +1570,12 @@ setup_sinks (GstPlayBaseBin * play_base_bin, GstPlayBaseGroup * group) GST_DEBUG_OBJECT (play_base_bin, "setupsinks"); /* find out what to do */ - if (group->type[GST_STREAM_TYPE_VIDEO - 1].npads > 0 && - group->type[GST_STREAM_TYPE_TEXT - 1].npads > 0) { + have_video = (group->type[GST_STREAM_TYPE_VIDEO - 1].npads > 0); + need_spu = (group->type[GST_STREAM_TYPE_SUBPICTURE - 1].npads != 0); + + if (have_video && group->type[GST_STREAM_TYPE_TEXT - 1].npads > 0) { need_text = TRUE; - } else if (group->type[GST_STREAM_TYPE_VIDEO - 1].npads == 0 && + } else if (!have_video && group->type[GST_STREAM_TYPE_AUDIO - 1].npads > 0 && play_bin->visualisation != NULL) { need_vis = TRUE; @@ -1521,12 +1601,23 @@ setup_sinks (GstPlayBaseBin * play_base_bin, GstPlayBaseGroup * group) } /* link video */ - if (group->type[GST_STREAM_TYPE_VIDEO - 1].npads > 0) { + if (have_video) { + /* Create the video rendering bin, error is posted when this fails. */ + sink = gen_video_element (play_bin); + if (!sink) + return FALSE; + if (need_spu) { + sink = add_spu_element (play_bin, sink); + } + if (need_text) { GstObject *parent = NULL, *grandparent = NULL; GstPad *ghost = NULL; - sink = gen_text_element (play_bin); + /* Add the subtitle overlay element into the video sink */ + sink = add_text_element (play_bin, sink); + + /* Link the incoming subtitle stream into the output bin */ textsrcpad = gst_element_get_static_pad (group->type[GST_STREAM_TYPE_TEXT - 1].preroll, "src"); @@ -1589,8 +1680,6 @@ setup_sinks (GstPlayBaseBin * play_base_bin, GstPlayBaseGroup * group) gst_object_unref (parent); gst_object_unref (grandparent); - } else { - sink = gen_video_element (play_bin); } beach: if (!sink) @@ -1606,6 +1695,30 @@ setup_sinks (GstPlayBaseBin * play_base_bin, GstPlayBaseGroup * group) gst_pad_set_blocked_async (origtextsrcpad, FALSE, dummy_blocked_cb, NULL); gst_object_unref (origtextsrcpad); } + + /* If we have a DVD subpicture stream, link it to the SPU now */ + if (need_spu) { + GstPad *subpic_pad; + GstPad *spu_sink_pad; + + subpic_pad = + gst_element_get_static_pad (group->type[GST_STREAM_TYPE_SUBPICTURE + - 1].preroll, "src"); + spu_sink_pad = gst_element_get_static_pad (sink, "subpicture_sink"); + if (subpic_pad && spu_sink_pad) { + GST_LOG_OBJECT (play_bin, "Linking DVD subpicture stream onto SPU"); + gst_pad_set_blocked_async (subpic_pad, TRUE, dummy_blocked_cb, NULL); + if (gst_pad_link (subpic_pad, spu_sink_pad) != GST_PAD_LINK_OK) { + GST_WARNING_OBJECT (play_bin, + "Failed to link DVD subpicture stream onto SPU"); + } + gst_pad_set_blocked_async (subpic_pad, FALSE, dummy_blocked_cb, NULL); + } + if (subpic_pad) + gst_object_unref (subpic_pad); + if (spu_sink_pad) + gst_object_unref (spu_sink_pad); + } } /* remove the sinks now, pipeline get_state will now wait for the diff --git a/gst/playback/gststreamselector.c b/gst/playback/gststreamselector.c index 1a72b5018a..a99ecee845 100644 --- a/gst/playback/gststreamselector.c +++ b/gst/playback/gststreamselector.c @@ -254,12 +254,14 @@ gst_selector_pad_event (GstPad * pad, GstEvent * event) gboolean forward = TRUE; GstStreamSelector *sel; GstSelectorPad *selpad; + GstPad *active_sinkpad; sel = GST_STREAM_SELECTOR (gst_pad_get_parent (pad)); selpad = GST_SELECTOR_PAD_CAST (pad); /* only forward if we are dealing with the active sinkpad */ - forward = gst_stream_selector_is_active_sinkpad (sel, pad); + active_sinkpad = gst_stream_selector_activate_sinkpad (sel, pad); + forward = (active_sinkpad == pad); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_FLUSH_STOP: