mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-06-07 07:58:51 +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 *video_channels; /* links to selector pads */
|
||||||
GPtrArray *audio_channels; /* links to selector pads */
|
GPtrArray *audio_channels; /* links to selector pads */
|
||||||
GPtrArray *text_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 */
|
/* uridecodebins for uri and subtitle uri */
|
||||||
GstElement *uridecodebin;
|
GstElement *uridecodebin;
|
||||||
|
@ -934,8 +935,10 @@ init_group (GstPlayBin * playbin, GstSourceGroup * group)
|
||||||
group->video_channels = g_ptr_array_new ();
|
group->video_channels = g_ptr_array_new ();
|
||||||
group->audio_channels = g_ptr_array_new ();
|
group->audio_channels = g_ptr_array_new ();
|
||||||
group->text_channels = g_ptr_array_new ();
|
group->text_channels = g_ptr_array_new ();
|
||||||
|
group->subp_channels = g_ptr_array_new ();
|
||||||
group->lock = g_mutex_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->playbin = playbin;
|
||||||
group->selector[0].media = "audio/x-raw-";
|
group->selector[0].media = "audio/x-raw-";
|
||||||
group->selector[0].type = GST_PLAY_SINK_TYPE_AUDIO_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].media = "video/x-raw-";
|
||||||
group->selector[2].type = GST_PLAY_SINK_TYPE_VIDEO_RAW;
|
group->selector[2].type = GST_PLAY_SINK_TYPE_VIDEO_RAW;
|
||||||
group->selector[2].channels = group->video_channels;
|
group->selector[2].channels = group->video_channels;
|
||||||
group->selector[3].media = "video/";
|
group->selector[3].media = "video/x-dvd-subpicture";
|
||||||
group->selector[3].type = GST_PLAY_SINK_TYPE_VIDEO;
|
group->selector[3].type = GST_PLAY_SINK_TYPE_SUBPIC;
|
||||||
group->selector[3].channels = group->video_channels;
|
group->selector[3].channels = group->subp_channels;
|
||||||
group->selector[4].media = "text/";
|
group->selector[4].media = "video/";
|
||||||
group->selector[4].type = GST_PLAY_SINK_TYPE_TEXT;
|
group->selector[4].type = GST_PLAY_SINK_TYPE_VIDEO;
|
||||||
group->selector[4].channels = group->text_channels;
|
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
|
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->video_channels, TRUE);
|
||||||
g_ptr_array_free (group->audio_channels, TRUE);
|
g_ptr_array_free (group->audio_channels, TRUE);
|
||||||
g_ptr_array_free (group->text_channels, TRUE);
|
g_ptr_array_free (group->text_channels, TRUE);
|
||||||
|
g_ptr_array_free (group->subp_channels, TRUE);
|
||||||
g_mutex_free (group->lock);
|
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",
|
"pad %s:%s with caps %" GST_PTR_FORMAT " added in group %p",
|
||||||
GST_DEBUG_PAD_NAME (pad), caps, group);
|
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 */
|
/* major type of the pad, this determines the selector to use */
|
||||||
for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
|
for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
|
||||||
if (g_str_has_prefix (name, group->selector[i].media)) {
|
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:
|
case GST_PLAY_SINK_TYPE_TEXT:
|
||||||
signal = SIGNAL_TEXT_CHANGED;
|
signal = SIGNAL_TEXT_CHANGED;
|
||||||
break;
|
break;
|
||||||
|
case GST_PLAY_SINK_TYPE_SUBPIC:
|
||||||
default:
|
default:
|
||||||
signal = -1;
|
signal = -1;
|
||||||
}
|
}
|
||||||
|
@ -1805,12 +1808,6 @@ done:
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
blacklisted_type:
|
|
||||||
{
|
|
||||||
GST_WARNING_OBJECT (playbin, "blacklisted type %s for pad %s:%s",
|
|
||||||
name, GST_DEBUG_PAD_NAME (pad));
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
unknown_type:
|
unknown_type:
|
||||||
{
|
{
|
||||||
GST_ERROR_OBJECT (playbin, "unknown type %s for pad %s:%s",
|
GST_ERROR_OBJECT (playbin, "unknown type %s for pad %s:%s",
|
||||||
|
|
|
@ -110,23 +110,31 @@ struct _GstPlaySink
|
||||||
|
|
||||||
GstPlayFlags flags;
|
GstPlayFlags flags;
|
||||||
|
|
||||||
|
/* chains */
|
||||||
GstPlayAudioChain *audiochain;
|
GstPlayAudioChain *audiochain;
|
||||||
GstPlayVideoChain *videochain;
|
GstPlayVideoChain *videochain;
|
||||||
GstPlayVisChain *vischain;
|
GstPlayVisChain *vischain;
|
||||||
GstPlayTextChain *textchain;
|
GstPlayTextChain *textchain;
|
||||||
|
|
||||||
|
/* audio */
|
||||||
GstPad *audio_pad;
|
GstPad *audio_pad;
|
||||||
gboolean audio_pad_raw;
|
gboolean audio_pad_raw;
|
||||||
|
/* audio tee */
|
||||||
GstElement *audio_tee;
|
GstElement *audio_tee;
|
||||||
GstPad *audio_tee_sink;
|
GstPad *audio_tee_sink;
|
||||||
GstPad *audio_tee_asrc;
|
GstPad *audio_tee_asrc;
|
||||||
GstPad *audio_tee_vissrc;
|
GstPad *audio_tee_vissrc;
|
||||||
|
|
||||||
|
/* video */
|
||||||
GstPad *video_pad;
|
GstPad *video_pad;
|
||||||
gboolean video_pad_raw;
|
gboolean video_pad_raw;
|
||||||
|
|
||||||
|
/* text */
|
||||||
GstPad *text_pad;
|
GstPad *text_pad;
|
||||||
|
|
||||||
|
/* subpictures */
|
||||||
|
GstPad *subp_pad;
|
||||||
|
|
||||||
/* properties */
|
/* properties */
|
||||||
GstElement *audio_sink;
|
GstElement *audio_sink;
|
||||||
GstElement *video_sink;
|
GstElement *video_sink;
|
||||||
|
@ -769,12 +777,13 @@ try_element (GstPlaySink * playsink, GstElement * element)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static GstPlayVideoChain *
|
static GstPlayVideoChain *
|
||||||
gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async)
|
gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async,
|
||||||
|
gboolean queue)
|
||||||
{
|
{
|
||||||
GstPlayVideoChain *chain;
|
GstPlayVideoChain *chain;
|
||||||
GstBin *bin;
|
GstBin *bin;
|
||||||
GstPad *pad;
|
GstPad *pad;
|
||||||
GstElement *prev, *elem;
|
GstElement *head, *prev, *elem;
|
||||||
|
|
||||||
chain = g_new0 (GstPlayVideoChain, 1);
|
chain = g_new0 (GstPlayVideoChain, 1);
|
||||||
chain->chain.playsink = playsink;
|
chain->chain.playsink = playsink;
|
||||||
|
@ -821,6 +830,7 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async)
|
||||||
gst_object_sink (bin);
|
gst_object_sink (bin);
|
||||||
gst_bin_add (bin, chain->sink);
|
gst_bin_add (bin, chain->sink);
|
||||||
|
|
||||||
|
if (queue) {
|
||||||
/* decouple decoder from sink, this improves playback quite a lot since the
|
/* decouple decoder from sink, this improves playback quite a lot since the
|
||||||
* decoder can continue while the sink blocks for synchronisation. We don't
|
* 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
|
* need a lot of buffers as this consumes a lot of memory and we don't want
|
||||||
|
@ -829,7 +839,11 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async)
|
||||||
g_object_set (G_OBJECT (chain->queue), "max-size-buffers", 3,
|
g_object_set (G_OBJECT (chain->queue), "max-size-buffers", 3,
|
||||||
"max-size-bytes", 0, "max-size-time", (gint64) 0, NULL);
|
"max-size-bytes", 0, "max-size-time", (gint64) 0, NULL);
|
||||||
gst_bin_add (bin, chain->queue);
|
gst_bin_add (bin, chain->queue);
|
||||||
prev = chain->queue;
|
head = prev = chain->queue;
|
||||||
|
} else {
|
||||||
|
head = chain->sink;
|
||||||
|
prev = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (raw && !(playsink->flags & GST_PLAY_FLAG_NATIVE_VIDEO)) {
|
if (raw && !(playsink->flags & GST_PLAY_FLAG_NATIVE_VIDEO)) {
|
||||||
GST_DEBUG_OBJECT (playsink, "creating ffmpegcolorspace");
|
GST_DEBUG_OBJECT (playsink, "creating ffmpegcolorspace");
|
||||||
|
@ -841,9 +855,12 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async)
|
||||||
"ffmpegcolorspace"), ("video rendering might fail"));
|
"ffmpegcolorspace"), ("video rendering might fail"));
|
||||||
} else {
|
} else {
|
||||||
gst_bin_add (bin, chain->conv);
|
gst_bin_add (bin, chain->conv);
|
||||||
|
if (prev) {
|
||||||
if (!gst_element_link_pads (prev, "src", chain->conv, "sink"))
|
if (!gst_element_link_pads (prev, "src", chain->conv, "sink"))
|
||||||
goto link_failed;
|
goto link_failed;
|
||||||
|
} else {
|
||||||
|
head = chain->conv;
|
||||||
|
}
|
||||||
prev = chain->conv;
|
prev = chain->conv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -856,19 +873,23 @@ gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async)
|
||||||
"videoscale"), ("possibly a liboil version mismatch?"));
|
"videoscale"), ("possibly a liboil version mismatch?"));
|
||||||
} else {
|
} else {
|
||||||
gst_bin_add (bin, chain->scale);
|
gst_bin_add (bin, chain->scale);
|
||||||
|
if (prev) {
|
||||||
if (!gst_element_link_pads (prev, "src", chain->scale, "sink"))
|
if (!gst_element_link_pads (prev, "src", chain->scale, "sink"))
|
||||||
goto link_failed;
|
goto link_failed;
|
||||||
|
} else {
|
||||||
|
head = chain->scale;
|
||||||
|
}
|
||||||
prev = chain->scale;
|
prev = chain->scale;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* be more careful with the pad from the custom sink element, it might not
|
if (prev) {
|
||||||
* be named 'sink' */
|
GST_DEBUG_OBJECT (playsink, "linking to sink");
|
||||||
if (!gst_element_link_pads (prev, "src", chain->sink, NULL))
|
if (!gst_element_link_pads (prev, "src", chain->sink, NULL))
|
||||||
goto link_failed;
|
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);
|
chain->sinkpad = gst_ghost_pad_new ("sink", pad);
|
||||||
gst_object_unref (pad);
|
gst_object_unref (pad);
|
||||||
|
|
||||||
|
@ -896,7 +917,8 @@ link_failed:
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
setup_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async)
|
setup_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async,
|
||||||
|
gboolean queue)
|
||||||
{
|
{
|
||||||
GstElement *elem;
|
GstElement *elem;
|
||||||
GstPlayVideoChain *chain;
|
GstPlayVideoChain *chain;
|
||||||
|
@ -1456,12 +1478,12 @@ gboolean
|
||||||
gst_play_sink_reconfigure (GstPlaySink * playsink)
|
gst_play_sink_reconfigure (GstPlaySink * playsink)
|
||||||
{
|
{
|
||||||
GstPlayFlags flags;
|
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");
|
GST_DEBUG_OBJECT (playsink, "reconfiguring");
|
||||||
|
|
||||||
/* assume we need nothing */
|
/* 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_PLAY_SINK_LOCK (playsink);
|
||||||
GST_OBJECT_LOCK (playsink);
|
GST_OBJECT_LOCK (playsink);
|
||||||
|
@ -1500,20 +1522,22 @@ gst_play_sink_reconfigure (GstPlaySink * playsink)
|
||||||
|
|
||||||
/* set up video pipeline */
|
/* set up video pipeline */
|
||||||
if (need_video) {
|
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 */
|
/* we need a raw sink when we do vis or when we have a raw pad */
|
||||||
raw = need_vis ? TRUE : playsink->video_pad_raw;
|
raw = need_vis ? TRUE : playsink->video_pad_raw;
|
||||||
/* we try to set the sink async=FALSE when we need vis, this way we can
|
/* we try to set the sink async=FALSE when we need vis, this way we can
|
||||||
* avoid a queue in the audio chain. */
|
* avoid a queue in the audio chain. */
|
||||||
async = !need_vis;
|
async = !need_vis;
|
||||||
|
/* put a little queue in front of the video */
|
||||||
|
queue = TRUE;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (playsink, "adding video, raw %d",
|
GST_DEBUG_OBJECT (playsink, "adding video, raw %d",
|
||||||
playsink->video_pad_raw);
|
playsink->video_pad_raw);
|
||||||
|
|
||||||
if (playsink->videochain) {
|
if (playsink->videochain) {
|
||||||
/* try to reactivate the chain */
|
/* 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);
|
add_chain (GST_PLAY_CHAIN (playsink->videochain), FALSE);
|
||||||
activate_chain (GST_PLAY_CHAIN (playsink->videochain), FALSE);
|
activate_chain (GST_PLAY_CHAIN (playsink->videochain), FALSE);
|
||||||
free_chain ((GstPlayChain *) playsink->videochain);
|
free_chain ((GstPlayChain *) playsink->videochain);
|
||||||
|
@ -1522,7 +1546,7 @@ gst_play_sink_reconfigure (GstPlaySink * playsink)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!playsink->videochain) {
|
if (!playsink->videochain) {
|
||||||
playsink->videochain = gen_video_chain (playsink, raw, async);
|
playsink->videochain = gen_video_chain (playsink, raw, async, queue);
|
||||||
}
|
}
|
||||||
if (playsink->videochain) {
|
if (playsink->videochain) {
|
||||||
GST_DEBUG_OBJECT (playsink, "adding video chain");
|
GST_DEBUG_OBJECT (playsink, "adding video chain");
|
||||||
|
@ -1553,8 +1577,8 @@ gst_play_sink_reconfigure (GstPlaySink * playsink)
|
||||||
playsink->audio_tee_vissrc = NULL;
|
playsink->audio_tee_vissrc = NULL;
|
||||||
}
|
}
|
||||||
srcpad =
|
srcpad =
|
||||||
gst_element_get_static_pad (GST_ELEMENT_CAST (playsink->vischain->
|
gst_element_get_static_pad (GST_ELEMENT_CAST (playsink->
|
||||||
chain.bin), "src");
|
vischain->chain.bin), "src");
|
||||||
gst_pad_unlink (srcpad, playsink->videochain->sinkpad);
|
gst_pad_unlink (srcpad, playsink->videochain->sinkpad);
|
||||||
}
|
}
|
||||||
add_chain (GST_PLAY_CHAIN (playsink->videochain), FALSE);
|
add_chain (GST_PLAY_CHAIN (playsink->videochain), FALSE);
|
||||||
|
@ -1683,8 +1707,8 @@ gst_play_sink_reconfigure (GstPlaySink * playsink)
|
||||||
if (playsink->vischain) {
|
if (playsink->vischain) {
|
||||||
GST_DEBUG_OBJECT (playsink, "setting up vis chain");
|
GST_DEBUG_OBJECT (playsink, "setting up vis chain");
|
||||||
srcpad =
|
srcpad =
|
||||||
gst_element_get_static_pad (GST_ELEMENT_CAST (playsink->vischain->
|
gst_element_get_static_pad (GST_ELEMENT_CAST (playsink->
|
||||||
chain.bin), "src");
|
vischain->chain.bin), "src");
|
||||||
add_chain (GST_PLAY_CHAIN (playsink->vischain), TRUE);
|
add_chain (GST_PLAY_CHAIN (playsink->vischain), TRUE);
|
||||||
activate_chain (GST_PLAY_CHAIN (playsink->vischain), TRUE);
|
activate_chain (GST_PLAY_CHAIN (playsink->vischain), TRUE);
|
||||||
if (playsink->audio_tee_vissrc == NULL) {
|
if (playsink->audio_tee_vissrc == NULL) {
|
||||||
|
@ -1925,6 +1949,15 @@ gst_play_sink_request_pad (GstPlaySink * playsink, GstPlaySinkType type)
|
||||||
created = TRUE;
|
created = TRUE;
|
||||||
break;
|
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:
|
default:
|
||||||
res = NULL;
|
res = NULL;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -55,8 +55,11 @@ typedef enum {
|
||||||
GST_PLAY_SINK_TYPE_VIDEO = 2,
|
GST_PLAY_SINK_TYPE_VIDEO = 2,
|
||||||
GST_PLAY_SINK_TYPE_VIDEO_RAW = 3,
|
GST_PLAY_SINK_TYPE_VIDEO_RAW = 3,
|
||||||
GST_PLAY_SINK_TYPE_TEXT = 4,
|
GST_PLAY_SINK_TYPE_TEXT = 4,
|
||||||
GST_PLAY_SINK_TYPE_LAST = 5,
|
GST_PLAY_SINK_TYPE_SUBPIC = 5,
|
||||||
GST_PLAY_SINK_TYPE_FLUSHING = 6
|
GST_PLAY_SINK_TYPE_LAST = 6,
|
||||||
|
|
||||||
|
/* this is a dummy pad */
|
||||||
|
GST_PLAY_SINK_TYPE_FLUSHING = 7
|
||||||
} GstPlaySinkType;
|
} GstPlaySinkType;
|
||||||
|
|
||||||
typedef struct _GstPlaySink GstPlaySink;
|
typedef struct _GstPlaySink GstPlaySink;
|
||||||
|
|
Loading…
Reference in a new issue