mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 04:01:08 +00:00
playbin2: first support for subpictures
Add beginnings of subpicture support.
This commit is contained in:
parent
c081c6b747
commit
e7b382c6a9
3 changed files with 85 additions and 52 deletions
|
@ -274,6 +274,7 @@ struct _GstSourceGroup
|
|||
GPtrArray *video_channels; /* links to selector pads */
|
||||
GPtrArray *audio_channels; /* links to selector pads */
|
||||
GPtrArray *text_channels; /* links to selector pads */
|
||||
GPtrArray *subp_channels; /* links to selector pads */
|
||||
|
||||
/* uridecodebins for uri and subtitle uri */
|
||||
GstElement *uridecodebin;
|
||||
|
@ -934,8 +935,10 @@ init_group (GstPlayBin * playbin, GstSourceGroup * group)
|
|||
group->video_channels = g_ptr_array_new ();
|
||||
group->audio_channels = g_ptr_array_new ();
|
||||
group->text_channels = g_ptr_array_new ();
|
||||
group->subp_channels = g_ptr_array_new ();
|
||||
group->lock = g_mutex_new ();
|
||||
/* init selectors */
|
||||
/* init selectors. The selector is found by finding the first prefix that
|
||||
* matches the media. */
|
||||
group->playbin = playbin;
|
||||
group->selector[0].media = "audio/x-raw-";
|
||||
group->selector[0].type = GST_PLAY_SINK_TYPE_AUDIO_RAW;
|
||||
|
@ -946,12 +949,15 @@ init_group (GstPlayBin * playbin, GstSourceGroup * group)
|
|||
group->selector[2].media = "video/x-raw-";
|
||||
group->selector[2].type = GST_PLAY_SINK_TYPE_VIDEO_RAW;
|
||||
group->selector[2].channels = group->video_channels;
|
||||
group->selector[3].media = "video/";
|
||||
group->selector[3].type = GST_PLAY_SINK_TYPE_VIDEO;
|
||||
group->selector[3].channels = group->video_channels;
|
||||
group->selector[4].media = "text/";
|
||||
group->selector[4].type = GST_PLAY_SINK_TYPE_TEXT;
|
||||
group->selector[4].channels = group->text_channels;
|
||||
group->selector[3].media = "video/x-dvd-subpicture";
|
||||
group->selector[3].type = GST_PLAY_SINK_TYPE_SUBPIC;
|
||||
group->selector[3].channels = group->subp_channels;
|
||||
group->selector[4].media = "video/";
|
||||
group->selector[4].type = GST_PLAY_SINK_TYPE_VIDEO;
|
||||
group->selector[4].channels = group->video_channels;
|
||||
group->selector[5].media = "text/";
|
||||
group->selector[5].type = GST_PLAY_SINK_TYPE_TEXT;
|
||||
group->selector[5].channels = group->text_channels;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -961,6 +967,7 @@ free_group (GstPlayBin * playbin, GstSourceGroup * group)
|
|||
g_ptr_array_free (group->video_channels, TRUE);
|
||||
g_ptr_array_free (group->audio_channels, TRUE);
|
||||
g_ptr_array_free (group->text_channels, TRUE);
|
||||
g_ptr_array_free (group->subp_channels, TRUE);
|
||||
g_mutex_free (group->lock);
|
||||
}
|
||||
|
||||
|
@ -1708,11 +1715,6 @@ pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
|
|||
"pad %s:%s with caps %" GST_PTR_FORMAT " added in group %p",
|
||||
GST_DEBUG_PAD_NAME (pad), caps, group);
|
||||
|
||||
for (i = 0; blacklisted_mimes[i]; i++) {
|
||||
if (!strcmp (name, blacklisted_mimes[i]))
|
||||
goto blacklisted_type;
|
||||
}
|
||||
|
||||
/* major type of the pad, this determines the selector to use */
|
||||
for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
|
||||
if (g_str_has_prefix (name, group->selector[i].media)) {
|
||||
|
@ -1792,6 +1794,7 @@ pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
|
|||
case GST_PLAY_SINK_TYPE_TEXT:
|
||||
signal = SIGNAL_TEXT_CHANGED;
|
||||
break;
|
||||
case GST_PLAY_SINK_TYPE_SUBPIC:
|
||||
default:
|
||||
signal = -1;
|
||||
}
|
||||
|
@ -1805,12 +1808,6 @@ done:
|
|||
return;
|
||||
|
||||
/* ERRORS */
|
||||
blacklisted_type:
|
||||
{
|
||||
GST_WARNING_OBJECT (playbin, "blacklisted type %s for pad %s:%s",
|
||||
name, GST_DEBUG_PAD_NAME (pad));
|
||||
goto done;
|
||||
}
|
||||
unknown_type:
|
||||
{
|
||||
GST_ERROR_OBJECT (playbin, "unknown type %s for pad %s:%s",
|
||||
|
|
|
@ -110,23 +110,31 @@ struct _GstPlaySink
|
|||
|
||||
GstPlayFlags flags;
|
||||
|
||||
/* chains */
|
||||
GstPlayAudioChain *audiochain;
|
||||
GstPlayVideoChain *videochain;
|
||||
GstPlayVisChain *vischain;
|
||||
GstPlayTextChain *textchain;
|
||||
|
||||
/* audio */
|
||||
GstPad *audio_pad;
|
||||
gboolean audio_pad_raw;
|
||||
/* audio tee */
|
||||
GstElement *audio_tee;
|
||||
GstPad *audio_tee_sink;
|
||||
GstPad *audio_tee_asrc;
|
||||
GstPad *audio_tee_vissrc;
|
||||
|
||||
/* video */
|
||||
GstPad *video_pad;
|
||||
gboolean video_pad_raw;
|
||||
|
||||
/* text */
|
||||
GstPad *text_pad;
|
||||
|
||||
/* subpictures */
|
||||
GstPad *subp_pad;
|
||||
|
||||
/* properties */
|
||||
GstElement *audio_sink;
|
||||
GstElement *video_sink;
|
||||
|
@ -769,12 +777,13 @@ try_element (GstPlaySink * playsink, GstElement * element)
|
|||
*
|
||||
*/
|
||||
static GstPlayVideoChain *
|
||||
gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async)
|
||||
gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async,
|
||||
gboolean queue)
|
||||
{
|
||||
GstPlayVideoChain *chain;
|
||||
GstBin *bin;
|
||||
GstPad *pad;
|
||||
GstElement *prev, *elem;
|
||||
GstElement *head, *prev, *elem;
|
||||
|
||||
chain = g_new0 (GstPlayVideoChain, 1);
|
||||
chain->chain.playsink = playsink;
|
||||
|
@ -821,15 +830,20 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async)
|
|||
gst_object_sink (bin);
|
||||
gst_bin_add (bin, chain->sink);
|
||||
|
||||
/* decouple decoder from sink, this improves playback quite a lot since the
|
||||
* decoder can continue while the sink blocks for synchronisation. We don't
|
||||
* need a lot of buffers as this consumes a lot of memory and we don't want
|
||||
* too little because else we would be context switching too quickly. */
|
||||
chain->queue = gst_element_factory_make ("queue", "vqueue");
|
||||
g_object_set (G_OBJECT (chain->queue), "max-size-buffers", 3,
|
||||
"max-size-bytes", 0, "max-size-time", (gint64) 0, NULL);
|
||||
gst_bin_add (bin, chain->queue);
|
||||
prev = chain->queue;
|
||||
if (queue) {
|
||||
/* decouple decoder from sink, this improves playback quite a lot since the
|
||||
* decoder can continue while the sink blocks for synchronisation. We don't
|
||||
* need a lot of buffers as this consumes a lot of memory and we don't want
|
||||
* too little because else we would be context switching too quickly. */
|
||||
chain->queue = gst_element_factory_make ("queue", "vqueue");
|
||||
g_object_set (G_OBJECT (chain->queue), "max-size-buffers", 3,
|
||||
"max-size-bytes", 0, "max-size-time", (gint64) 0, NULL);
|
||||
gst_bin_add (bin, chain->queue);
|
||||
head = prev = chain->queue;
|
||||
} else {
|
||||
head = chain->sink;
|
||||
prev = NULL;
|
||||
}
|
||||
|
||||
if (raw && !(playsink->flags & GST_PLAY_FLAG_NATIVE_VIDEO)) {
|
||||
GST_DEBUG_OBJECT (playsink, "creating ffmpegcolorspace");
|
||||
|
@ -841,9 +855,12 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async)
|
|||
"ffmpegcolorspace"), ("video rendering might fail"));
|
||||
} else {
|
||||
gst_bin_add (bin, chain->conv);
|
||||
if (!gst_element_link_pads (prev, "src", chain->conv, "sink"))
|
||||
goto link_failed;
|
||||
|
||||
if (prev) {
|
||||
if (!gst_element_link_pads (prev, "src", chain->conv, "sink"))
|
||||
goto link_failed;
|
||||
} else {
|
||||
head = chain->conv;
|
||||
}
|
||||
prev = chain->conv;
|
||||
}
|
||||
|
||||
|
@ -856,19 +873,23 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async)
|
|||
"videoscale"), ("possibly a liboil version mismatch?"));
|
||||
} else {
|
||||
gst_bin_add (bin, chain->scale);
|
||||
if (!gst_element_link_pads (prev, "src", chain->scale, "sink"))
|
||||
goto link_failed;
|
||||
|
||||
if (prev) {
|
||||
if (!gst_element_link_pads (prev, "src", chain->scale, "sink"))
|
||||
goto link_failed;
|
||||
} else {
|
||||
head = chain->scale;
|
||||
}
|
||||
prev = chain->scale;
|
||||
}
|
||||
}
|
||||
|
||||
/* be more careful with the pad from the custom sink element, it might not
|
||||
* be named 'sink' */
|
||||
if (!gst_element_link_pads (prev, "src", chain->sink, NULL))
|
||||
goto link_failed;
|
||||
if (prev) {
|
||||
GST_DEBUG_OBJECT (playsink, "linking to sink");
|
||||
if (!gst_element_link_pads (prev, "src", chain->sink, NULL))
|
||||
goto link_failed;
|
||||
}
|
||||
|
||||
pad = gst_element_get_static_pad (chain->queue, "sink");
|
||||
pad = gst_element_get_static_pad (head, "sink");
|
||||
chain->sinkpad = gst_ghost_pad_new ("sink", pad);
|
||||
gst_object_unref (pad);
|
||||
|
||||
|
@ -896,7 +917,8 @@ link_failed:
|
|||
}
|
||||
|
||||
static gboolean
|
||||
setup_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async)
|
||||
setup_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async,
|
||||
gboolean queue)
|
||||
{
|
||||
GstElement *elem;
|
||||
GstPlayVideoChain *chain;
|
||||
|
@ -1456,12 +1478,12 @@ gboolean
|
|||
gst_play_sink_reconfigure (GstPlaySink * playsink)
|
||||
{
|
||||
GstPlayFlags flags;
|
||||
gboolean need_audio, need_video, need_vis, need_text;
|
||||
gboolean need_audio, need_video, need_vis, need_text, need_subp;
|
||||
|
||||
GST_DEBUG_OBJECT (playsink, "reconfiguring");
|
||||
|
||||
/* assume we need nothing */
|
||||
need_audio = need_video = need_vis = need_text = FALSE;
|
||||
need_audio = need_video = need_vis = need_text = need_subp = FALSE;
|
||||
|
||||
GST_PLAY_SINK_LOCK (playsink);
|
||||
GST_OBJECT_LOCK (playsink);
|
||||
|
@ -1500,20 +1522,22 @@ gst_play_sink_reconfigure (GstPlaySink * playsink)
|
|||
|
||||
/* set up video pipeline */
|
||||
if (need_video) {
|
||||
gboolean raw, async;
|
||||
gboolean raw, async, queue;
|
||||
|
||||
/* we need a raw sink when we do vis or when we have a raw pad */
|
||||
raw = need_vis ? TRUE : playsink->video_pad_raw;
|
||||
/* we try to set the sink async=FALSE when we need vis, this way we can
|
||||
* avoid a queue in the audio chain. */
|
||||
async = !need_vis;
|
||||
/* put a little queue in front of the video */
|
||||
queue = TRUE;
|
||||
|
||||
GST_DEBUG_OBJECT (playsink, "adding video, raw %d",
|
||||
playsink->video_pad_raw);
|
||||
|
||||
if (playsink->videochain) {
|
||||
/* try to reactivate the chain */
|
||||
if (!setup_video_chain (playsink, raw, async)) {
|
||||
if (!setup_video_chain (playsink, raw, async, queue)) {
|
||||
add_chain (GST_PLAY_CHAIN (playsink->videochain), FALSE);
|
||||
activate_chain (GST_PLAY_CHAIN (playsink->videochain), FALSE);
|
||||
free_chain ((GstPlayChain *) playsink->videochain);
|
||||
|
@ -1522,7 +1546,7 @@ gst_play_sink_reconfigure (GstPlaySink * playsink)
|
|||
}
|
||||
|
||||
if (!playsink->videochain) {
|
||||
playsink->videochain = gen_video_chain (playsink, raw, async);
|
||||
playsink->videochain = gen_video_chain (playsink, raw, async, queue);
|
||||
}
|
||||
if (playsink->videochain) {
|
||||
GST_DEBUG_OBJECT (playsink, "adding video chain");
|
||||
|
@ -1553,8 +1577,8 @@ gst_play_sink_reconfigure (GstPlaySink * playsink)
|
|||
playsink->audio_tee_vissrc = NULL;
|
||||
}
|
||||
srcpad =
|
||||
gst_element_get_static_pad (GST_ELEMENT_CAST (playsink->vischain->
|
||||
chain.bin), "src");
|
||||
gst_element_get_static_pad (GST_ELEMENT_CAST (playsink->
|
||||
vischain->chain.bin), "src");
|
||||
gst_pad_unlink (srcpad, playsink->videochain->sinkpad);
|
||||
}
|
||||
add_chain (GST_PLAY_CHAIN (playsink->videochain), FALSE);
|
||||
|
@ -1683,8 +1707,8 @@ gst_play_sink_reconfigure (GstPlaySink * playsink)
|
|||
if (playsink->vischain) {
|
||||
GST_DEBUG_OBJECT (playsink, "setting up vis chain");
|
||||
srcpad =
|
||||
gst_element_get_static_pad (GST_ELEMENT_CAST (playsink->vischain->
|
||||
chain.bin), "src");
|
||||
gst_element_get_static_pad (GST_ELEMENT_CAST (playsink->
|
||||
vischain->chain.bin), "src");
|
||||
add_chain (GST_PLAY_CHAIN (playsink->vischain), TRUE);
|
||||
activate_chain (GST_PLAY_CHAIN (playsink->vischain), TRUE);
|
||||
if (playsink->audio_tee_vissrc == NULL) {
|
||||
|
@ -1925,6 +1949,15 @@ gst_play_sink_request_pad (GstPlaySink * playsink, GstPlaySinkType type)
|
|||
created = TRUE;
|
||||
break;
|
||||
}
|
||||
case GST_PLAY_SINK_TYPE_SUBPIC:
|
||||
GST_LOG_OBJECT (playsink, "ghosting subpicture pad");
|
||||
if (!playsink->subp_pad) {
|
||||
playsink->subp_pad =
|
||||
gst_ghost_pad_new_no_target ("subp_sink", GST_PAD_SINK);
|
||||
created = TRUE;
|
||||
}
|
||||
res = playsink->subp_pad;
|
||||
break;
|
||||
default:
|
||||
res = NULL;
|
||||
break;
|
||||
|
|
|
@ -55,8 +55,11 @@ typedef enum {
|
|||
GST_PLAY_SINK_TYPE_VIDEO = 2,
|
||||
GST_PLAY_SINK_TYPE_VIDEO_RAW = 3,
|
||||
GST_PLAY_SINK_TYPE_TEXT = 4,
|
||||
GST_PLAY_SINK_TYPE_LAST = 5,
|
||||
GST_PLAY_SINK_TYPE_FLUSHING = 6
|
||||
GST_PLAY_SINK_TYPE_SUBPIC = 5,
|
||||
GST_PLAY_SINK_TYPE_LAST = 6,
|
||||
|
||||
/* this is a dummy pad */
|
||||
GST_PLAY_SINK_TYPE_FLUSHING = 7
|
||||
} GstPlaySinkType;
|
||||
|
||||
typedef struct _GstPlaySink GstPlaySink;
|
||||
|
|
Loading…
Reference in a new issue