ext/resindvd/: Add in Title/Chapter seeking, and simple but buggy audio and subtitle stream selection.

Original commit message from CVS:
* ext/resindvd/gstmpegdemux.c:
* ext/resindvd/gstmpegdemux.h:
* ext/resindvd/resindvdbin.c:
* ext/resindvd/resindvdsrc.c:
* ext/resindvd/rsnstreamselector.c:
Add in Title/Chapter seeking, and simple but buggy audio
and subtitle stream selection.
This commit is contained in:
Jan Schmidt 2008-09-27 01:12:30 +00:00
parent a51c4c16b2
commit a8736df9b5
5 changed files with 291 additions and 54 deletions

View file

@ -1,3 +1,13 @@
2008-09-27 Jan Schmidt <jan.schmidt@sun.com>
* ext/resindvd/gstmpegdemux.c:
* ext/resindvd/gstmpegdemux.h:
* ext/resindvd/resindvdbin.c:
* ext/resindvd/resindvdsrc.c:
* ext/resindvd/rsnstreamselector.c:
Add in Title/Chapter seeking, and simple but buggy audio
and subtitle stream selection.
2008-09-24 Michael Smith <msmith@songbirdnest.com>
* sys/dshowdecwrapper/gstdshowaudiodec.cpp:

View file

@ -28,9 +28,6 @@
#include "gstmpegdefs.h"
#include "gstmpegdemux.h"
#define MAX_DVD_AUDIO_STREAMS 8
#define MAX_DVD_SUBPICTURE_STREAMS 32
#define SEGMENT_THRESHOLD (GST_SECOND/2)
/* The SCR_MUNGE value is used to offset the scr_adjust value, to avoid
@ -581,6 +578,7 @@ gst_flups_demux_handle_dvd_event (GstFluPSDemux * demux, GstEvent * event)
gint i;
gchar cur_stream_name[32];
GstFluPSStream *temp;
gboolean ret = TRUE;
if (strcmp (type, "dvd-lang-codes") == 0) {
GstEvent **p_ev;
@ -624,6 +622,8 @@ gst_flups_demux_handle_dvd_event (GstFluPSDemux * demux, GstEvent * event)
if (!gst_structure_get_int (structure, cur_stream_name, &stream_format))
continue;
demux->audio_stream_types[i] = stream_format;
switch (stream_format) {
case 0x0:
/* AC3 */
@ -678,10 +678,89 @@ gst_flups_demux_handle_dvd_event (GstFluPSDemux * demux, GstEvent * event)
gst_element_no_more_pads (GST_ELEMENT (demux));
demux->need_no_more_pads = FALSE;
gst_event_unref (event);
} else if (strcmp (type, "dvd-set-subpicture-track") == 0) {
gint stream_id;
gboolean forced_only;
gst_structure_get_boolean (structure, "forced-only", &forced_only);
if (gst_structure_get_int (structure, "physical-id", &stream_id)) {
temp = demux->streams[0x20 + stream_id];
if (temp != NULL && temp->pad != NULL) {
/* Send event to the selector to activate the desired pad */
GstStructure *s = gst_structure_new ("application/x-gst-dvd",
"event", G_TYPE_STRING, "select-pad", NULL);
GstEvent *sel_event =
gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
gst_pad_push_event (temp->pad, sel_event);
gst_event_ref (event);
ret = gst_pad_push_event (temp->pad, event);
g_print ("Subpicture physical ID change to %d, forced %d\n", stream_id,
forced_only);
}
}
gst_event_unref (event);
} else if (strcmp (type, "dvd-set-audio-track") == 0) {
gint stream_id;
if (gst_structure_get_int (structure, "physical-id", &stream_id)) {
gint aud_type;
stream_id %= MAX_DVD_AUDIO_STREAMS;
aud_type = demux->audio_stream_types[stream_id % MAX_DVD_AUDIO_STREAMS];
switch (aud_type) {
case 0x0:
/* AC3 */
stream_id += 0x80;
temp = demux->streams[stream_id];
break;
#if 0 /* FIXME: Ignore non AC-3 requests until the decoder bin can handle them */
case 0x2:
case 0x3:
/* MPEG audio without and with extension stream are
* treated the same */
stream_id = 0xC0 + i;
temp = demux->streams[stream_id];
break;
case 0x4:
/* LPCM */
stream_id = 0xA0 + i;
temp = demux->streams[stream_id];
break;
case 0x6:
/* DTS */
stream_id = 0x88 + i;
temp = demux->streams[stream_id];
break;
case 0x7:
/* FIXME: What range is SDDS? */
break;
#endif
default:
temp = NULL;
break;
}
if (temp != NULL && temp->pad != NULL) {
/* Send event to the selector to activate the desired pad */
GstStructure *s = gst_structure_new ("application/x-gst-dvd",
"event", G_TYPE_STRING, "select-pad", NULL);
GstEvent *sel_event =
gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
gst_pad_push_event (temp->pad, sel_event);
g_print ("Audio physical ID change to %d\n", stream_id);
gst_event_ref (event);
ret = gst_pad_push_event (temp->pad, event);
}
}
ret = gst_flups_demux_send_event (demux, event);
} else {
gst_flups_demux_send_event (demux, event);
ret = gst_flups_demux_send_event (demux, event);
}
return TRUE;
return ret;
}
static gboolean

View file

@ -42,6 +42,8 @@ typedef struct _GstFluPSDemuxClass GstFluPSDemuxClass;
#define GST_FLUPS_DEMUX_MAX_STREAMS 256
#define GST_FLUPS_DEMUX_MAX_PSM 256
#define MAX_DVD_AUDIO_STREAMS 8
#define MAX_DVD_SUBPICTURE_STREAMS 32
typedef enum {
STATE_FLUPS_DEMUX_NEED_SYNC,
@ -106,6 +108,7 @@ struct _GstFluPSDemux {
/* Language codes event is stored when a dvd-lang-codes
* custom event arrives from upstream */
GstEvent * lang_codes;
gint audio_stream_types[MAX_DVD_AUDIO_STREAMS];
};
struct _GstFluPSDemuxClass {

View file

@ -84,6 +84,9 @@ static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
/* Private seek format for private flushing */
static GstFormat rsndvd_format;
/* Title/chapter formats */
static GstFormat title_format;
static GstFormat chapter_format;
static void rsn_dvdsrc_register_extra (GType rsn_dvdsrc_type);
@ -104,6 +107,7 @@ static gboolean rsn_dvdsrc_stop (RsnBaseSrc * bsrc);
static gboolean rsn_dvdsrc_unlock (RsnBaseSrc * bsrc);
static gboolean rsn_dvdsrc_unlock_stop (RsnBaseSrc * bsrc);
static gboolean rsn_dvdsrc_is_seekable (RsnBaseSrc * bsrc);
static gboolean rsn_dvdsrc_prepare_seek (RsnBaseSrc * bsrc, GstEvent * event,
GstSegment * segment);
static gboolean rsn_dvdsrc_do_seek (RsnBaseSrc * bsrc, GstSegment * segment);
@ -163,6 +167,9 @@ rsn_dvdsrc_register_extra (GType rsn_dvdsrc_type)
rsndvd_format = gst_format_register ("rsndvdsrc-internal",
"private Resin DVD src format");
title_format = gst_format_register ("title", "DVD title format");
chapter_format = gst_format_register ("chapter", "DVD chapter format");
}
static void
@ -206,6 +213,7 @@ rsn_dvdsrc_class_init (resinDvdSrcClass * klass)
gstbasesrc_class->unlock_stop = GST_DEBUG_FUNCPTR (rsn_dvdsrc_unlock_stop);
gstbasesrc_class->event = GST_DEBUG_FUNCPTR (rsn_dvdsrc_src_event);
gstbasesrc_class->query = GST_DEBUG_FUNCPTR (rsn_dvdsrc_src_query);
gstbasesrc_class->is_seekable = GST_DEBUG_FUNCPTR (rsn_dvdsrc_is_seekable);
gstbasesrc_class->prepare_seek_segment =
GST_DEBUG_FUNCPTR (rsn_dvdsrc_prepare_seek);
gstbasesrc_class->do_seek = GST_DEBUG_FUNCPTR (rsn_dvdsrc_do_seek);
@ -284,7 +292,6 @@ rsn_dvdsrc_set_property (GObject * object, guint prop_id,
else
src->device = g_value_dup_string (value);
GST_OBJECT_UNLOCK (src);
g_print ("Device is now %s\n", src->device);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -756,7 +763,6 @@ rsn_dvdsrc_step (resinDvdSrc * src, gboolean have_dvd_lock)
case DVDNAV_VTS_CHANGE:{
dvdnav_vts_change_event_t *event = (dvdnav_vts_change_event_t *) data;
g_print ("VTS change\n");
if (dvdnav_is_domain_vmgm (src->dvdnav))
src->vts_n = 0;
else
@ -772,7 +778,7 @@ rsn_dvdsrc_step (resinDvdSrc * src, gboolean have_dvd_lock)
case DVDNAV_AUDIO_STREAM_CHANGE:{
dvdnav_audio_stream_change_event_t *event =
(dvdnav_audio_stream_change_event_t *) data;
g_print ("cur audio stream change\n");
GST_DEBUG_OBJECT (src, " physical: %d", event->physical);
GST_DEBUG_OBJECT (src, " logical: %d", event->logical);
@ -782,9 +788,10 @@ rsn_dvdsrc_step (resinDvdSrc * src, gboolean have_dvd_lock)
case DVDNAV_SPU_STREAM_CHANGE:{
dvdnav_spu_stream_change_event_t *event =
(dvdnav_spu_stream_change_event_t *) data;
gint phys_track = event->physical_wide & 0x1f;
gboolean forced_only = (event->physical_wide & 0x80) ? TRUE : FALSE;
rsn_dvdsrc_prepare_spu_stream_event (src, event->physical_wide & 0x1f,
(event->physical_wide & 0x80) ? TRUE : FALSE);
rsn_dvdsrc_prepare_spu_stream_event (src, phys_track, forced_only);
GST_DEBUG_OBJECT (src, " physical_wide: %d", event->physical_wide);
GST_DEBUG_OBJECT (src, " physical_letterbox: %d",
@ -1200,6 +1207,8 @@ rsn_dvdsrc_prepare_audio_stream_event (resinDvdSrc * src, guint8 phys_stream)
return;
src->cur_audio_phys_stream = phys_stream;
g_print ("Preparing audio change, phys %d\n", phys_stream);
s = gst_structure_new ("application/x-gst-dvd",
"event", G_TYPE_STRING, "dvd-set-audio-track",
"physical-id", G_TYPE_INT, (gint) phys_stream, NULL);
@ -1220,12 +1229,14 @@ rsn_dvdsrc_prepare_spu_stream_event (resinDvdSrc * src, guint8 phys_stream,
if (phys_stream == src->cur_spu_phys_stream &&
forced_only == src->cur_spu_forced_only) {
g_print ("Not preparing SPU change\n");
return;
}
src->cur_spu_phys_stream = phys_stream;
src->cur_spu_forced_only = forced_only;
g_print ("Preparing SPU change, phys %d forced %d\n",
phys_stream, forced_only);
s = gst_structure_new ("application/x-gst-dvd",
"event", G_TYPE_STRING, "dvd-set-subpicture-track",
"physical-id", G_TYPE_INT, (gint) phys_stream,
@ -1252,6 +1263,7 @@ rsn_dvdsrc_prepare_streamsinfo_event (resinDvdSrc * src)
gchar lang_code[3] = { '\0', '\0', '\0' };
gchar *t;
gboolean is_widescreen;
gboolean have_audio;
if (src->vts_attrs == NULL || src->vts_n >= src->vts_attrs->len) {
if (src->vts_attrs)
@ -1301,13 +1313,21 @@ rsn_dvdsrc_prepare_streamsinfo_event (resinDvdSrc * src)
NULL);
/* audio */
if (n_audio == 0) {
/* Always create at least one audio stream */
gst_structure_set (s, "audio-0-format", G_TYPE_INT, (int) 0, NULL);
}
have_audio = FALSE;
for (i = 0; i < n_audio; i++) {
const audio_attr_t *a = a_attrs + i;
#if 1
/* FIXME: Only output A52 streams for now, until the decoder switching
* is ready */
if (a->audio_format != 0) {
GST_DEBUG_OBJECT (src, "Ignoring non-A52 stream %d, format %d", i,
(int) a->audio_format);
continue;
}
#endif
have_audio = TRUE;
t = g_strdup_printf ("audio-%d-format", i);
gst_structure_set (s, t, G_TYPE_INT, (int) a->audio_format, NULL);
g_free (t);
@ -1327,6 +1347,11 @@ rsn_dvdsrc_prepare_streamsinfo_event (resinDvdSrc * src)
GST_DEBUG_OBJECT (src, "Audio stream %d - no language", i, lang_code);
}
if (have_audio == FALSE) {
/* Always create at least one audio stream */
gst_structure_set (s, "audio-0-format", G_TYPE_INT, (int) 0, NULL);
}
/* subpictures */
if (n_subp == 0) {
/* Always create at least one subpicture stream */
@ -1447,7 +1472,15 @@ rsn_dvdsrc_update_highlight (resinDvdSrc * src)
/* Check if we have a new button number, or a new highlight region. */
if (button != src->active_button ||
memcmp (&area, &(src->area), sizeof (dvdnav_highlight_area_t)) != 0) {
area.sx != src->area.sx || area.sy != src->area.sy ||
area.ex != src->area.ex || area.ey != src->area.ey ||
area.palette != src->area.palette) {
g_print ("Setting highlight. Button %d @ %d,%d active %d palette 0x%x "
"(from button %d @ %d,%d palette 0x%x)\n",
button, src->area.sx, src->area.sy, mode, src->area.palette,
src->active_button, area.sx, area.sy, area.palette);
memcpy (&(src->area), &area, sizeof (dvdnav_highlight_area_t));
s = gst_structure_new ("application/x-gst-dvd", "event",
@ -1469,9 +1502,6 @@ rsn_dvdsrc_update_highlight (resinDvdSrc * src)
src->active_button = button;
g_print ("Setting highlight. Button %d @ %d,%d active %d"
" palette 0x%x\n", button, area.sx, area.sy, mode, area.palette);
if (src->highlight_event)
gst_event_unref (src->highlight_event);
src->highlight_event = event;
@ -1708,11 +1738,70 @@ rsn_dvdsrc_src_query (RsnBaseSrc * basesrc, GstQuery * query)
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_DURATION:
gst_query_parse_duration (query, &format, NULL);
if (format == GST_FORMAT_TIME && src->pgc_duration != GST_CLOCK_TIME_NONE) {
val = src->pgc_duration;
gst_query_set_duration (query, format, val);
res = TRUE;
g_mutex_lock (src->dvd_lock);
if (!src->running) {
g_mutex_unlock (src->dvd_lock);
break;
}
if (format == GST_FORMAT_TIME) {
if (src->pgc_duration != GST_CLOCK_TIME_NONE) {
val = src->pgc_duration;
gst_query_set_duration (query, format, val);
res = TRUE;
}
} else if (format == title_format) {
gint32 titles;
if (dvdnav_get_number_of_titles (src->dvdnav,
&titles) == DVDNAV_STATUS_OK) {
val = titles;
gst_query_set_duration (query, format, val);
res = TRUE;
}
} else if (format == chapter_format) {
gint32 title, chapters, x;
if (dvdnav_current_title_info (src->dvdnav, &title,
&x) == DVDNAV_STATUS_OK) {
if (dvdnav_get_number_of_parts (src->dvdnav, title,
&chapters) == DVDNAV_STATUS_OK) {
val = chapters;
gst_query_set_duration (query, format, val);
res = TRUE;
}
}
}
g_mutex_unlock (src->dvd_lock);
break;
case GST_QUERY_POSITION:
gst_query_parse_position (query, &format, NULL);
g_mutex_lock (src->dvd_lock);
if (!src->running) {
g_mutex_unlock (src->dvd_lock);
break;
}
if (format == title_format) {
gint32 title, chapter;
if (dvdnav_current_title_info (src->dvdnav, &title,
&chapter) == DVDNAV_STATUS_OK) {
val = title;
gst_query_set_position (query, format, val);
res = TRUE;
}
} else if (format == chapter_format) {
gint32 title, chapter = -1;
if (dvdnav_current_title_info (src->dvdnav, &title,
&chapter) == DVDNAV_STATUS_OK) {
val = chapter;
gst_query_set_position (query, format, val);
res = TRUE;
}
}
g_mutex_unlock (src->dvd_lock);
break;
default:
res = GST_BASE_SRC_CLASS (parent_class)->query (basesrc, query);
@ -1722,6 +1811,12 @@ rsn_dvdsrc_src_query (RsnBaseSrc * basesrc, GstQuery * query)
return res;
}
static gboolean
rsn_dvdsrc_is_seekable (RsnBaseSrc * bsrc)
{
return TRUE;
}
static gboolean
rsn_dvdsrc_prepare_seek (RsnBaseSrc * bsrc, GstEvent * event,
GstSegment * segment)
@ -1737,8 +1832,9 @@ rsn_dvdsrc_prepare_seek (RsnBaseSrc * bsrc, GstEvent * event,
gst_event_parse_seek (event, &rate, &seek_format, &flags,
&cur_type, &cur, &stop_type, &stop);
if (seek_format == rsndvd_format) {
/* Seeks in our internal format are passed directly through to the do_seek
if (seek_format == rsndvd_format || seek_format == title_format ||
seek_format == chapter_format) {
/* Seeks in our internal formats are passed directly through to the do_seek
* method. */
gst_segment_init (segment, seek_format);
gst_segment_set_seek (segment, rate, seek_format, flags, cur_type, cur,
@ -1753,8 +1849,7 @@ rsn_dvdsrc_prepare_seek (RsnBaseSrc * bsrc, GstEvent * event,
if (seek_format == GST_FORMAT_BYTES)
return FALSE;
/* Let basesrc handle other formats for now. FIXME: Implement angle,
* chapter etc */
/* Let basesrc handle other formats for now. FIXME: Implement angle */
return GST_BASE_SRC_CLASS (parent_class)->prepare_seek_segment (bsrc,
event, segment);
}
@ -1766,6 +1861,9 @@ rsn_dvdsrc_do_seek (RsnBaseSrc * bsrc, GstSegment * segment)
gboolean ret = FALSE;
if (segment->format == rsndvd_format) {
/* The internal format has alread served its purpose of waking
* everything up and flushing, we just need to step to the next
* data block (below) so we know our new position */
ret = TRUE;
} else {
/* FIXME: Handle other formats: Time, title, chapter, angle */
@ -1773,13 +1871,41 @@ rsn_dvdsrc_do_seek (RsnBaseSrc * bsrc, GstSegment * segment)
if (segment->format == GST_FORMAT_TIME) {
ret = TRUE;
src->discont = TRUE;
} else if (segment->format == title_format) {
gint titles;
g_mutex_lock (src->dvd_lock);
if (src->running &&
dvdnav_get_number_of_titles (src->dvdnav,
&titles) == DVDNAV_STATUS_OK) {
if (segment->start > 0 && segment->start <= titles) {
dvdnav_title_play (src->dvdnav, segment->start);
ret = TRUE;
src->discont = TRUE;
}
}
g_mutex_unlock (src->dvd_lock);
} else if (segment->format == chapter_format) {
g_mutex_lock (src->dvd_lock);
if (src->running) {
gint32 title, chapters, x;
if (dvdnav_current_title_info (src->dvdnav, &title, &x) ==
DVDNAV_STATUS_OK) {
if (dvdnav_get_number_of_parts (src->dvdnav, title, &chapters) ==
DVDNAV_STATUS_OK) {
if (segment->start > 0 && segment->start <= chapters) {
dvdnav_part_play (src->dvdnav, title, segment->start);
ret = TRUE;
src->discont = TRUE;
}
}
}
}
g_mutex_unlock (src->dvd_lock);
}
}
if (ret) {
/* The internal format has served its purpose of waking everything
* up and flushing, now step to the next data block so we know our
* position */
/* Force a highlight update */
src->active_button = -1;

View file

@ -63,7 +63,9 @@ enum
static gboolean rsn_stream_selector_is_active_sinkpad (RsnStreamSelector * sel,
GstPad * pad);
static GstPad *rsn_stream_selector_activate_sinkpad (RsnStreamSelector * sel,
static GstPad *rsn_stream_selector_get_active (RsnStreamSelector * sel,
GstPad * pad);
static void rsn_stream_selector_set_active (RsnStreamSelector * sel,
GstPad * pad);
static GstPad *rsn_stream_selector_get_linked_pad (GstPad * pad,
gboolean strict);
@ -261,7 +263,7 @@ gst_selector_pad_event (GstPad * pad, GstEvent * event)
selpad = GST_SELECTOR_PAD_CAST (pad);
/* only forward if we are dealing with the active sinkpad */
active_sinkpad = rsn_stream_selector_activate_sinkpad (sel, pad);
active_sinkpad = rsn_stream_selector_get_active (sel, pad);
forward = (active_sinkpad == pad);
switch (GST_EVENT_TYPE (event)) {
@ -307,6 +309,18 @@ gst_selector_pad_event (GstPad * pad, GstEvent * event)
GST_OBJECT_UNLOCK (selpad);
break;
}
case GST_EVENT_CUSTOM_DOWNSTREAM:
{
const GstStructure *structure = gst_event_get_structure (event);
if (structure != NULL &&
gst_structure_has_name (structure, "application/x-gst-dvd")) {
const char *type = gst_structure_get_string (structure, "event");
if (strcmp (type, "select-pad") == 0) {
rsn_stream_selector_set_active (sel, pad);
forward = FALSE;
}
}
}
case GST_EVENT_EOS:
selpad->eos = TRUE;
break;
@ -351,7 +365,7 @@ gst_selector_pad_bufferalloc (GstPad * pad, guint64 offset,
sel = RSN_STREAM_SELECTOR (gst_pad_get_parent (pad));
active_sinkpad = rsn_stream_selector_activate_sinkpad (sel, pad);
active_sinkpad = rsn_stream_selector_get_active (sel, pad);
/* Fallback allocation for buffers from pads except the selected one */
if (pad != active_sinkpad) {
@ -397,7 +411,7 @@ gst_selector_pad_chain (GstPad * pad, GstBuffer * buf)
selpad = GST_SELECTOR_PAD_CAST (pad);
seg = &selpad->segment;
active_sinkpad = rsn_stream_selector_activate_sinkpad (sel, pad);
active_sinkpad = rsn_stream_selector_get_active (sel, pad);
timestamp = GST_BUFFER_TIMESTAMP (buf);
if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
@ -574,28 +588,10 @@ rsn_stream_selector_set_property (GObject * object, guint prop_id,
case PROP_ACTIVE_PAD:
{
GstPad *pad = NULL;
GstPad **active_pad_p;
pad = g_value_get_object (value);
rsn_stream_selector_set_active (sel, pad);
GST_OBJECT_LOCK (object);
if (pad != sel->active_sinkpad) {
RsnSelectorPad *selpad;
selpad = GST_SELECTOR_PAD_CAST (pad);
/* we can only activate pads that have data received */
if (selpad && !selpad->active) {
GST_DEBUG_OBJECT (sel, "No data received on pad %" GST_PTR_FORMAT,
pad);
} else {
active_pad_p = &sel->active_sinkpad;
gst_object_replace ((GstObject **) active_pad_p,
GST_OBJECT_CAST (pad));
GST_DEBUG_OBJECT (sel, "New active pad is %" GST_PTR_FORMAT,
sel->active_sinkpad);
}
}
GST_OBJECT_UNLOCK (object);
break;
}
default:
@ -694,7 +690,7 @@ rsn_stream_selector_is_active_sinkpad (RsnStreamSelector * sel, GstPad * pad)
/* Get or create the active sinkpad */
static GstPad *
rsn_stream_selector_activate_sinkpad (RsnStreamSelector * sel, GstPad * pad)
rsn_stream_selector_get_active (RsnStreamSelector * sel, GstPad * pad)
{
GstPad *active_sinkpad;
RsnSelectorPad *selpad;
@ -714,6 +710,29 @@ rsn_stream_selector_activate_sinkpad (RsnStreamSelector * sel, GstPad * pad)
return active_sinkpad;
}
static void
rsn_stream_selector_set_active (RsnStreamSelector * sel, GstPad * pad)
{
GstPad **active_pad_p;
GST_OBJECT_LOCK (GST_OBJECT_CAST (sel));
if (pad != sel->active_sinkpad) {
RsnSelectorPad *selpad;
selpad = GST_SELECTOR_PAD_CAST (pad);
/* we can only activate pads that have data received */
if (selpad && !selpad->active) {
GST_DEBUG_OBJECT (sel, "No data received on pad %" GST_PTR_FORMAT, pad);
} else {
active_pad_p = &sel->active_sinkpad;
gst_object_replace ((GstObject **) active_pad_p, GST_OBJECT_CAST (pad));
GST_DEBUG_OBJECT (sel, "New active pad is %" GST_PTR_FORMAT,
sel->active_sinkpad);
}
}
GST_OBJECT_UNLOCK (GST_OBJECT_CAST (sel));
}
static GList *
rsn_stream_selector_get_linked_pads (GstPad * pad)
{