mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-18 06:16:36 +00:00
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:
parent
8b24a3a057
commit
024d0e56f5
6 changed files with 150 additions and 20 deletions
10
ChangeLog
10
ChangeLog
|
@ -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
2
common
|
@ -1 +1 @@
|
||||||
Subproject commit 79ade7b9c9bf47eee491ceee4cf3ea116140ad35
|
Subproject commit a100efef186a5f8999fe3aa42c0720f5123c08eb
|
|
@ -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))
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
Loading…
Reference in a new issue