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.
This commit is contained in:
Jan Schmidt 2008-07-14 08:18:58 +00:00
parent 8b24a3a057
commit 024d0e56f5
6 changed files with 150 additions and 20 deletions

View file

@ -1,3 +1,13 @@
2008-07-14 Jan Schmidt <thaytan@noraisin.net>
* 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 <ensonic@users.sf.net> 2008-07-11 Stefan Kost <ensonic@users.sf.net>
* gst/audioconvert/gstaudioconvert.c: * gst/audioconvert/gstaudioconvert.c:

2
common

@ -1 +1 @@
Subproject commit 79ade7b9c9bf47eee491ceee4cf3ea116140ad35 Subproject commit a100efef186a5f8999fe3aa42c0720f5123c08eb

View file

@ -791,6 +791,8 @@ gen_preroll_element (GstPlayBaseBin * play_base_bin,
prename = "text"; prename = "text";
else if (type == GST_STREAM_TYPE_AUDIO) else if (type == GST_STREAM_TYPE_AUDIO)
prename = "audio"; prename = "audio";
else if (type == GST_STREAM_TYPE_SUBPICTURE)
prename = "subpicture";
else else
g_return_if_reached (); 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/") && if (g_str_has_prefix (mimetype, "audio/") &&
parent != GST_OBJECT_CAST (play_base_bin->subtitle)) { parent != GST_OBJECT_CAST (play_base_bin->subtitle)) {
type = GST_STREAM_TYPE_AUDIO; 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/") && } else if (g_str_has_prefix (mimetype, "video/") &&
parent != GST_OBJECT_CAST (play_base_bin->subtitle)) { parent != GST_OBJECT_CAST (play_base_bin->subtitle)) {
type = GST_STREAM_TYPE_VIDEO; type = GST_STREAM_TYPE_VIDEO;
@ -1569,7 +1574,7 @@ static const gchar *no_media_mimes[] = {
/* mime types we consider raw media */ /* mime types we consider raw media */
static const gchar *raw_mimes[] = { 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)) #define IS_STREAM_URI(uri) (array_has_value (stream_uris, uri))

View file

@ -63,8 +63,8 @@ typedef struct
GstElement *preroll; GstElement *preroll;
GstElement *selector; GstElement *selector;
gboolean done; gboolean done;
#define NUM_TYPES 3 #define NUM_TYPES 4
} type[NUM_TYPES]; /* AUDIO, VIDEO, TEXT */ } type[NUM_TYPES]; /* AUDIO, VIDEO, TEXT, SUBPIC */
} GstPlayBaseGroup; } GstPlayBaseGroup;
struct _GstPlayBaseBin { struct _GstPlayBaseBin {

View file

@ -262,6 +262,7 @@ struct _GstPlayBin
GstElement *pending_visualisation; GstElement *pending_visualisation;
GstElement *volume_element; GstElement *volume_element;
GstElement *textoverlay_element; GstElement *textoverlay_element;
GstElement *spu_element;
gfloat volume; gfloat volume;
/* these are the currently active sinks */ /* these are the currently active sinks */
@ -431,6 +432,7 @@ gst_play_bin_init (GstPlayBin * play_bin)
play_bin->pending_visualisation = NULL; play_bin->pending_visualisation = NULL;
play_bin->volume_element = NULL; play_bin->volume_element = NULL;
play_bin->textoverlay_element = NULL; play_bin->textoverlay_element = NULL;
play_bin->spu_element = NULL;
play_bin->volume = 1.0; play_bin->volume = 1.0;
play_bin->sinks = NULL; play_bin->sinks = NULL;
play_bin->frame = NULL; play_bin->frame = NULL;
@ -476,6 +478,10 @@ gst_play_bin_dispose (GObject * object)
gst_object_unref (play_bin->textoverlay_element); gst_object_unref (play_bin->textoverlay_element);
play_bin->textoverlay_element = NULL; 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); g_free (play_bin->font_desc);
play_bin->font_desc = NULL; play_bin->font_desc = NULL;
@ -911,7 +917,7 @@ link_failed:
* | tbin +-------------+ | * | tbin +-------------+ |
* | +-----+ | textoverlay | +------+ | * | +-----+ | textoverlay | +------+ |
* | | csp | +--video_sink | | vbin | | * | | csp | +--video_sink | | vbin | |
* video_sink-sink src+ +-text_sink src-sink | | * video_sink-sink src+ +-text_sink src---sink | |
* | +-----+ | +-------------+ +------+ | * | +-----+ | +-------------+ +------+ |
* text_sink-------------+ | * text_sink-------------+ |
* +--------------------------------------------------+ * +--------------------------------------------------+
@ -920,16 +926,11 @@ link_failed:
* videosink without the text_sink pad. * videosink without the text_sink pad.
*/ */
static GstElement * 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; 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 */ /* Text overlay */
overlay = gst_element_factory_make ("textoverlay", "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_element_add_pad (element, gst_ghost_pad_new ("sink", pad));
gst_object_unref (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 */ /* Set state to READY */
gst_element_set_state (element, GST_STATE_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 /* make the element (bin) that contains the elements needed to perform
* audio playback. * audio playback.
* *
@ -1479,8 +1555,10 @@ static gboolean
setup_sinks (GstPlayBaseBin * play_base_bin, GstPlayBaseGroup * group) setup_sinks (GstPlayBaseBin * play_base_bin, GstPlayBaseGroup * group)
{ {
GstPlayBin *play_bin = GST_PLAY_BIN (play_base_bin); GstPlayBin *play_bin = GST_PLAY_BIN (play_base_bin);
gboolean have_video = FALSE;
gboolean need_vis = FALSE; gboolean need_vis = FALSE;
gboolean need_text = FALSE; gboolean need_text = FALSE;
gboolean need_spu = FALSE;
GstPad *textsrcpad = NULL, *pad = NULL, *origtextsrcpad = NULL; GstPad *textsrcpad = NULL, *pad = NULL, *origtextsrcpad = NULL;
GstElement *sink; GstElement *sink;
gboolean res = TRUE; gboolean res = TRUE;
@ -1492,10 +1570,12 @@ setup_sinks (GstPlayBaseBin * play_base_bin, GstPlayBaseGroup * group)
GST_DEBUG_OBJECT (play_base_bin, "setupsinks"); GST_DEBUG_OBJECT (play_base_bin, "setupsinks");
/* find out what to do */ /* find out what to do */
if (group->type[GST_STREAM_TYPE_VIDEO - 1].npads > 0 && have_video = (group->type[GST_STREAM_TYPE_VIDEO - 1].npads > 0);
group->type[GST_STREAM_TYPE_TEXT - 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; 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 && group->type[GST_STREAM_TYPE_AUDIO - 1].npads > 0 &&
play_bin->visualisation != NULL) { play_bin->visualisation != NULL) {
need_vis = TRUE; need_vis = TRUE;
@ -1521,12 +1601,23 @@ setup_sinks (GstPlayBaseBin * play_base_bin, GstPlayBaseGroup * group)
} }
/* link video */ /* 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) { if (need_text) {
GstObject *parent = NULL, *grandparent = NULL; GstObject *parent = NULL, *grandparent = NULL;
GstPad *ghost = 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 = textsrcpad =
gst_element_get_static_pad (group->type[GST_STREAM_TYPE_TEXT - gst_element_get_static_pad (group->type[GST_STREAM_TYPE_TEXT -
1].preroll, "src"); 1].preroll, "src");
@ -1589,8 +1680,6 @@ setup_sinks (GstPlayBaseBin * play_base_bin, GstPlayBaseGroup * group)
gst_object_unref (parent); gst_object_unref (parent);
gst_object_unref (grandparent); gst_object_unref (grandparent);
} else {
sink = gen_video_element (play_bin);
} }
beach: beach:
if (!sink) 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_pad_set_blocked_async (origtextsrcpad, FALSE, dummy_blocked_cb, NULL);
gst_object_unref (origtextsrcpad); 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 /* remove the sinks now, pipeline get_state will now wait for the

View file

@ -254,12 +254,14 @@ gst_selector_pad_event (GstPad * pad, GstEvent * event)
gboolean forward = TRUE; gboolean forward = TRUE;
GstStreamSelector *sel; GstStreamSelector *sel;
GstSelectorPad *selpad; GstSelectorPad *selpad;
GstPad *active_sinkpad;
sel = GST_STREAM_SELECTOR (gst_pad_get_parent (pad)); sel = GST_STREAM_SELECTOR (gst_pad_get_parent (pad));
selpad = GST_SELECTOR_PAD_CAST (pad); selpad = GST_SELECTOR_PAD_CAST (pad);
/* only forward if we are dealing with the active sinkpad */ /* 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)) { switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_FLUSH_STOP: case GST_EVENT_FLUSH_STOP: