summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--configure.ac16
-rw-r--r--ext/jack/gstjackaudioclient.c32
-rw-r--r--ext/jack/gstjackaudiosink.c7
-rw-r--r--ext/resindvd/gstmpegdemux.c17
-rw-r--r--ext/resindvd/gstmpegdemux.h1
-rw-r--r--ext/resindvd/resindvdsrc.c7
-rw-r--r--ext/resindvd/rsnaudiomunge.c5
-rw-r--r--gst/aacparse/gstbaseparse.c2
-rw-r--r--gst/amrparse/gstamrparse.c10
-rw-r--r--gst/amrparse/gstamrparse.h1
-rw-r--r--gst/amrparse/gstbaseparse.c2
-rw-r--r--gst/dvdspu/gstspu-pgs.c22
-rw-r--r--gst/dvdspu/gstspu-vobsub-render.c6
-rw-r--r--gst/hdvparse/Makefile.am13
-rw-r--r--gst/hdvparse/gsthdvparse.c362
-rw-r--r--gst/hdvparse/gsthdvparse.h56
-rw-r--r--gst/mpegdemux/gstmpegtsdemux.c44
-rw-r--r--gst/qtmux/fourcc.h1
-rw-r--r--gst/qtmux/gstqtmux.c5
-rw-r--r--gst/rawparse/gstaudioparse.c73
-rw-r--r--gst/rtpmanager/gstrtpbin.c4
-rw-r--r--gst/rtpmanager/rtpsource.c4
-rw-r--r--gst/sdp/gstsdpdemux.c3
-rw-r--r--gst/selector/gstoutputselector.c45
-rw-r--r--gst/shapewipe/Makefile.am11
-rw-r--r--gst/shapewipe/gstshapewipe.c847
-rw-r--r--gst/shapewipe/gstshapewipe.h74
-rw-r--r--tests/examples/Makefile.am4
-rw-r--r--tests/examples/shapewipe/Makefile.am8
-rw-r--r--tests/examples/shapewipe/shapewipe-example.c128
31 files changed, 1740 insertions, 71 deletions
diff --git a/.gitignore b/.gitignore
index 90d737e0..ddb619a4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,6 +28,7 @@ autoregen.sh
ABOUT-NLS
_stdint.h
gst-plugins-bad-*.tar.*
+tests/examples/shapewipe/shapewipe-example
.deps
.libs
diff --git a/configure.ac b/configure.ac
index a9b89f0f..294348d7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -266,6 +266,7 @@ AG_GST_CHECK_PLUGIN(dvdspu)
AG_GST_CHECK_PLUGIN(festival)
AG_GST_CHECK_PLUGIN(freeze)
AG_GST_CHECK_PLUGIN(h264parse)
+AG_GST_CHECK_PLUGIN(hdvparse)
AG_GST_CHECK_PLUGIN(id3tag)
AG_GST_CHECK_PLUGIN(librfb)
AG_GST_CHECK_PLUGIN(liveadder)
@@ -286,6 +287,7 @@ AG_GST_CHECK_PLUGIN(rtpmux)
AG_GST_CHECK_PLUGIN(scaletempo)
AG_GST_CHECK_PLUGIN(sdp)
AG_GST_CHECK_PLUGIN(selector)
+AG_GST_CHECK_PLUGIN(shapewipe)
AG_GST_CHECK_PLUGIN(siren)
AG_GST_CHECK_PLUGIN(speed)
AG_GST_CHECK_PLUGIN(subenc)
@@ -1308,10 +1310,13 @@ AG_GST_CHECK_FEATURE(SOUNDTOUCH, [soundtouch plug-in], soundtouch, [
[HAVE_SOUNDTOUCH=yes
HAVE_SOUNDTOUCH_1_4=no
SOUNDTOUCH_LIBS="$SOUNDTOUCH_LIBS -lBPM"],
- [PKG_CHECK_MODULES(SOUNDTOUCH, libSoundTouch,
- HAVE_SOUNDTOUCH=yes
- SOUNDTOUCH_LIBS="$SOUNDTOUCH_LIBS -lBPM",
- HAVE_SOUNDTOUCH=no)])])
+ [PKG_CHECK_MODULES(SOUNDTOUCH, libSoundTouch >= 1.4,
+ [HAVE_SOUNDTOUCH=yes],
+ [PKG_CHECK_MODULES(SOUNDTOUCH, libSoundTouch,
+ [HAVE_SOUNDTOUCH=yes
+ HAVE_SOUNDTOUCH_1_4=no
+ SOUNDTOUCH_LIBS="$SOUNDTOUCH_LIBS -lBPM"],
+ HAVE_SOUNDTOUCH=no)])])])
AC_SUBST(SOUNDTOUCH_CFLAGS)
AC_SUBST(SOUNDTOUCH_LIBS)
if test "x$HAVE_CXX" != "xyes"; then
@@ -1585,6 +1590,7 @@ gst/dvdspu/Makefile
gst/festival/Makefile
gst/freeze/Makefile
gst/h264parse/Makefile
+gst/hdvparse/Makefile
gst/id3tag/Makefile
gst/librfb/Makefile
gst/mpegdemux/Makefile
@@ -1604,6 +1610,7 @@ gst/rtpmux/Makefile
gst/scaletempo/Makefile
gst/sdp/Makefile
gst/selector/Makefile
+gst/shapewipe/Makefile
gst/siren/Makefile
gst/speed/Makefile
gst/subenc/Makefile
@@ -1639,6 +1646,7 @@ sys/winscreencap/Makefile
tests/examples/Makefile
tests/examples/directfb/Makefile
tests/examples/mxf/Makefile
+tests/examples/shapewipe/Makefile
tests/examples/scaletempo/Makefile
tests/examples/switch/Makefile
ext/amrwb/Makefile
diff --git a/ext/jack/gstjackaudioclient.c b/ext/jack/gstjackaudioclient.c
index 1aa1baf8..60e41381 100644
--- a/ext/jack/gstjackaudioclient.c
+++ b/ext/jack/gstjackaudioclient.c
@@ -42,6 +42,7 @@ typedef struct
{
gint refcount;
GMutex *lock;
+ GCond *flush_cond;
/* id/server pair and the connection */
gchar *id;
@@ -61,6 +62,7 @@ struct _GstJackAudioClient
GstJackClientType type;
gboolean active;
+ gboolean deactivate;
void (*shutdown) (void *arg);
JackProcessCallback process;
@@ -92,15 +94,25 @@ jack_process_cb (jack_nframes_t nframes, void *arg)
GstJackAudioClient *client = (GstJackAudioClient *) walk->data;
/* only call active clients */
- if (client->active && client->process)
+ if ((client->active || client->deactivate) && client->process) {
res = client->process (nframes, client->user_data);
+ if (client->deactivate) {
+ client->deactivate = FALSE;
+ g_cond_signal (conn->flush_cond);
+ }
+ }
}
for (walk = conn->sink_clients; walk; walk = g_list_next (walk)) {
GstJackAudioClient *client = (GstJackAudioClient *) walk->data;
/* only call active clients */
- if (client->active && client->process)
+ if ((client->active || client->deactivate) && client->process) {
res = client->process (nframes, client->user_data);
+ if (client->deactivate) {
+ client->deactivate = FALSE;
+ g_cond_signal (conn->flush_cond);
+ }
+ }
}
g_mutex_unlock (conn->lock);
@@ -203,6 +215,7 @@ gst_jack_audio_make_connection (const gchar * id, const gchar * server,
conn = g_new (GstJackAudioConnection, 1);
conn->refcount = 1;
conn->lock = g_mutex_new ();
+ conn->flush_cond = g_cond_new ();
conn->id = g_strdup (id);
conn->server = g_strdup (server);
conn->client = jclient;
@@ -325,6 +338,7 @@ gst_jack_audio_unref_connection (GstJackAudioConnection * conn)
/* free resources */
g_mutex_free (conn->lock);
+ g_cond_free (conn->flush_cond);
g_free (conn->id);
g_free (conn->server);
g_free (conn);
@@ -409,9 +423,11 @@ gst_jack_audio_client_new (const gchar * id, const gchar * server,
if (conn == NULL)
goto no_connection;
+ GST_INFO ("new client %s", id);
+
/* make new client using the connection */
client = g_new (GstJackAudioClient, 1);
- client->active = FALSE;
+ client->active = client->deactivate = FALSE;
client->conn = conn;
client->type = type;
client->shutdown = shutdown;
@@ -446,6 +462,8 @@ gst_jack_audio_client_free (GstJackAudioClient * client)
g_return_if_fail (client != NULL);
+ GST_INFO ("free client");
+
conn = client->conn;
/* remove from connection first so that it's not scheduled anymore after this
@@ -492,6 +510,14 @@ gst_jack_audio_client_set_active (GstJackAudioClient * client, gboolean active)
/* make sure that we are not dispatching the client */
g_mutex_lock (client->conn->lock);
+ if (client->active && !active) {
+ /* we need to process once more to flush the port */
+ client->deactivate = TRUE;
+
+ /* need to wait for process_cb run once more */
+ while (client->deactivate)
+ g_cond_wait (client->conn->flush_cond, client->conn->lock);
+ }
client->active = active;
g_mutex_unlock (client->conn->lock);
diff --git a/ext/jack/gstjackaudiosink.c b/ext/jack/gstjackaudiosink.c
index 01383cbb..58a699d0 100644
--- a/ext/jack/gstjackaudiosink.c
+++ b/ext/jack/gstjackaudiosink.c
@@ -213,8 +213,8 @@ jack_process_cb (jack_nframes_t nframes, void *arg)
if (nframes * sizeof (sample_t) != flen)
goto wrong_size;
- GST_DEBUG ("copy %d frames: %p, %d bytes, %d channels", nframes, readptr,
- flen, channels);
+ GST_DEBUG_OBJECT (sink, "copy %d frames: %p, %d bytes, %d channels",
+ nframes, readptr, flen, channels);
data = (sample_t *) readptr;
/* the samples in the ringbuffer have the channels interleaved, we need to
@@ -231,6 +231,7 @@ jack_process_cb (jack_nframes_t nframes, void *arg)
/* we wrote one segment */
gst_ring_buffer_advance (buf, 1);
} else {
+ GST_DEBUG_OBJECT (sink, "write %d frames silence", nframes);
/* We are not allowed to read from the ringbuffer, write silence to all
* jack output buffers */
for (i = 0; i < channels; i++) {
@@ -607,7 +608,7 @@ gst_jack_ring_buffer_delay (GstRingBuffer * buf)
res = latency;
}
- GST_DEBUG_OBJECT (sink, "delay %u", res);
+ GST_LOG_OBJECT (sink, "delay %u", res);
return res;
}
diff --git a/ext/resindvd/gstmpegdemux.c b/ext/resindvd/gstmpegdemux.c
index 5ab26107..d9aefe53 100644
--- a/ext/resindvd/gstmpegdemux.c
+++ b/ext/resindvd/gstmpegdemux.c
@@ -356,7 +356,7 @@ gst_flups_demux_get_stream (GstFluPSDemux * demux, gint id, gint type)
{
GstFluPSStream *stream = demux->streams[id];
- if (stream == NULL) {
+ if (stream == NULL && !demux->disable_stream_creation) {
if (!(stream = gst_flups_demux_create_stream (demux, id, type)))
goto unknown_stream;
@@ -612,6 +612,8 @@ gst_flups_demux_handle_dvd_event (GstFluPSDemux * demux, GstEvent * event)
GST_DEBUG_OBJECT (demux, "Handling language codes event");
+ demux->disable_stream_creation = FALSE;
+
/* Create a video pad to ensure it exists before emitting no more pads */
temp = gst_flups_demux_get_stream (demux, 0xe0, ST_VIDEO_MPEG2);
/* Send a video format event downstream */
@@ -719,6 +721,8 @@ gst_flups_demux_handle_dvd_event (GstFluPSDemux * demux, GstEvent * event)
ST_PS_DVD_SUBPICTURE);
}
+ demux->disable_stream_creation = TRUE;
+
GST_DEBUG_OBJECT (demux, "Created all pads from Language Codes event, "
"signalling no-more-pads");
@@ -767,32 +771,33 @@ gst_flups_demux_handle_dvd_event (GstFluPSDemux * demux, GstEvent * event)
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;
+ stream_id += 0xC0;
temp = demux->streams[stream_id];
break;
case 0x4:
/* LPCM */
- stream_id = 0xA0 + i;
+ stream_id += 0xA0;
temp = demux->streams[stream_id];
break;
case 0x6:
/* DTS */
- stream_id = 0x88 + i;
+ stream_id += 0x88;
temp = demux->streams[stream_id];
break;
case 0x7:
/* FIXME: What range is SDDS? */
+ temp = NULL;
break;
-#endif
default:
temp = NULL;
break;
}
+ GST_INFO_OBJECT (demux, "Have DVD audio stream select event: "
+ "stream 0x%02x", 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",
diff --git a/ext/resindvd/gstmpegdemux.h b/ext/resindvd/gstmpegdemux.h
index 683b7cde..f6291500 100644
--- a/ext/resindvd/gstmpegdemux.h
+++ b/ext/resindvd/gstmpegdemux.h
@@ -106,6 +106,7 @@ struct _GstFluPSDemux {
/* Indicates an MPEG-2 stream */
gboolean is_mpeg2_pack;
+ gboolean disable_stream_creation;
/* Language codes event is stored when a dvd-lang-codes
* custom event arrives from upstream */
diff --git a/ext/resindvd/resindvdsrc.c b/ext/resindvd/resindvdsrc.c
index f24e45aa..122f2b67 100644
--- a/ext/resindvd/resindvdsrc.c
+++ b/ext/resindvd/resindvdsrc.c
@@ -1882,7 +1882,7 @@ rsn_dvdsrc_prepare_streamsinfo_event (resinDvdSrc * src)
GST_DEBUG_OBJECT (src, "mapped logical audio %d to MPEG substream %d",
i, phys_id);
-#if 1
+#if 0
/* FIXME: Only output A52 streams for now, until the decoder switching
* is ready */
if (a->audio_format != 0) {
@@ -1891,7 +1891,8 @@ rsn_dvdsrc_prepare_streamsinfo_event (resinDvdSrc * src)
continue;
}
#endif
- have_audio = TRUE;
+ if (a->audio_format == 0)
+ have_audio = TRUE;
GST_DEBUG_OBJECT (src, "Audio stream %d is format %d, substream %d", i,
(int) a->audio_format, phys_id);
@@ -1917,7 +1918,7 @@ rsn_dvdsrc_prepare_streamsinfo_event (resinDvdSrc * src)
}
if (have_audio == FALSE) {
- /* Always create at least one audio stream */
+ /* Always create at least one audio stream of the required type */
gst_structure_set (s, "audio-0-format", G_TYPE_INT, (int) 0,
"audio-0-stream", G_TYPE_INT, (int) 0, NULL);
}
diff --git a/ext/resindvd/rsnaudiomunge.c b/ext/resindvd/rsnaudiomunge.c
index 50d33be7..fda2a96b 100644
--- a/ext/resindvd/rsnaudiomunge.c
+++ b/ext/resindvd/rsnaudiomunge.c
@@ -200,10 +200,13 @@ rsn_audiomunge_make_audio (RsnAudioMunge * munge,
guint buf_size;
/* Just generate a 48khz stereo buffer for now */
+ /* FIXME: Adapt to the allowed formats, according to the currently
+ * plugged decoder, or at least add a source pad that accepts the
+ * caps we're outputting if the upstream decoder does not */
#if 0
caps =
gst_caps_from_string
- ("audio/x-raw-int,rate=48000,channels=2,width=16,depth=16,signed=(boolean)true,endianness=1234");
+ ("audio/x-raw-int,rate=48000,channels=2,width=16,depth=16,signed=(boolean)true,endianness=4321");
buf_size = 4 * (48000 * fill_time / GST_SECOND);
#else
caps = gst_caps_from_string ("audio/x-raw-float, endianness=(int)1234,"
diff --git a/gst/aacparse/gstbaseparse.c b/gst/aacparse/gstbaseparse.c
index 3224f445..34d28ec2 100644
--- a/gst/aacparse/gstbaseparse.c
+++ b/gst/aacparse/gstbaseparse.c
@@ -290,7 +290,7 @@ gst_base_parse_base_init (gpointer g_class)
GstBaseParseClass *klass = GST_BASE_PARSE_CLASS (g_class);
GstBaseParseClassPrivate *priv;
- GST_DEBUG_CATEGORY_INIT (gst_base_parse_debug, "flacbaseparse", 0,
+ GST_DEBUG_CATEGORY_INIT (gst_base_parse_debug, "aacbaseparse", 0,
"baseparse element");
/* TODO: Remove this once GObject supports class private data */
diff --git a/gst/amrparse/gstamrparse.c b/gst/amrparse/gstamrparse.c
index aeb928e1..5ec0c6c2 100644
--- a/gst/amrparse/gstamrparse.c
+++ b/gst/amrparse/gstamrparse.c
@@ -309,12 +309,12 @@ gst_amrparse_parse_header (GstAmrParse * amrparse,
GST_DEBUG_OBJECT (amrparse, "AMR-WB detected");
amrparse->block_size = block_size_wb;
amrparse->wide = TRUE;
- *skipsize = 9;
+ *skipsize = amrparse->header = 9;
} else if (!memcmp (data, "#!AMR\n", 6)) {
GST_DEBUG_OBJECT (amrparse, "AMR-NB detected");
amrparse->block_size = block_size_nb;
amrparse->wide = FALSE;
- *skipsize = 6;
+ *skipsize = amrparse->header = 6;
} else
return FALSE;
@@ -453,6 +453,7 @@ gst_amrparse_start (GstBaseParse * parse)
amrparse = GST_AMRPARSE (parse);
GST_DEBUG ("start");
amrparse->need_header = TRUE;
+ amrparse->header = 0;
amrparse->sync = TRUE;
amrparse->eos = FALSE;
amrparse->framecount = 0;
@@ -478,6 +479,7 @@ gst_amrparse_stop (GstBaseParse * parse)
amrparse = GST_AMRPARSE (parse);
GST_DEBUG ("stop");
amrparse->need_header = TRUE;
+ amrparse->header = 0;
amrparse->ts = -1;
return TRUE;
}
@@ -548,7 +550,7 @@ gst_amrparse_convert (GstBaseParse * parse,
GST_DEBUG ("converting bytes -> time");
if (amrparse->framecount) {
- *dest_value = AMR_FRAME_DURATION * src_value / bpf;
+ *dest_value = AMR_FRAME_DURATION * (src_value - amrparse->header) / bpf;
GST_DEBUG ("conversion result: %lld ms", *dest_value / GST_MSECOND);
ret = TRUE;
}
@@ -557,7 +559,7 @@ gst_amrparse_convert (GstBaseParse * parse,
GST_DEBUG ("converting time -> bytes");
if (dest_format == GST_FORMAT_BYTES) {
if (amrparse->framecount) {
- *dest_value = bpf * src_value / AMR_FRAME_DURATION;
+ *dest_value = bpf * src_value / AMR_FRAME_DURATION + amrparse->header;
GST_DEBUG ("time %lld ms in bytes = %lld",
src_value / GST_MSECOND, *dest_value);
ret = TRUE;
diff --git a/gst/amrparse/gstamrparse.h b/gst/amrparse/gstamrparse.h
index e776f295..4cd432e2 100644
--- a/gst/amrparse/gstamrparse.h
+++ b/gst/amrparse/gstamrparse.h
@@ -61,6 +61,7 @@ struct _GstAmrParse {
GstBaseParse element;
const gint *block_size;
gboolean need_header;
+ gint header;
gboolean wide;
gboolean eos;
gboolean sync;
diff --git a/gst/amrparse/gstbaseparse.c b/gst/amrparse/gstbaseparse.c
index 7483c2b9..e0f1f4d7 100644
--- a/gst/amrparse/gstbaseparse.c
+++ b/gst/amrparse/gstbaseparse.c
@@ -290,7 +290,7 @@ gst_base_parse_base_init (gpointer g_class)
GstBaseParseClass *klass = GST_BASE_PARSE_CLASS (g_class);
GstBaseParseClassPrivate *priv;
- GST_DEBUG_CATEGORY_INIT (gst_base_parse_debug, "flacbaseparse", 0,
+ GST_DEBUG_CATEGORY_INIT (gst_base_parse_debug, "amrbaseparse", 0,
"baseparse element");
/* TODO: Remove this once GObject supports class private data */
diff --git a/gst/dvdspu/gstspu-pgs.c b/gst/dvdspu/gstspu-pgs.c
index d1d4de18..37d80236 100644
--- a/gst/dvdspu/gstspu-pgs.c
+++ b/gst/dvdspu/gstspu-pgs.c
@@ -134,6 +134,9 @@ dump_rle_data (GstDVDSpu * dvdspu, guint8 * data, guint32 len)
pal_id = data[2];
data += 3;
break;
+ default:
+ run_len = 0;
+ break;
}
}
@@ -252,6 +255,9 @@ pgs_composition_object_render (PgsCompositionObject * obj, SpuState * state,
pal_id = data[2];
data += 3;
break;
+ default:
+ run_len = 0;
+ break;
}
}
@@ -430,12 +436,13 @@ parse_presentation_segment (GstDVDSpu * dvdspu, guint8 type, guint8 * payload,
if (obj->flags & ~(PGS_COMPOSITION_OBJECT_FLAG_CROPPED |
PGS_COMPOSITION_OBJECT_FLAG_FORCED))
- g_warning ("PGS Composition Object has unknown flags: 0x%02x",
+ GST_ERROR ("PGS Composition Object has unknown flags: 0x%02x",
obj->flags);
}
if (payload != end) {
- g_warning ("PGS Composition Object: %ld bytes not consumed", end - payload);
+ GST_ERROR ("PGS Composition Object: %" G_GSSIZE_FORMAT
+ " bytes not consumed", (gssize) (end - payload));
dump_bytes (payload, end - payload);
}
@@ -495,7 +502,8 @@ parse_set_palette (GstDVDSpu * dvdspu, guint8 type, guint8 * payload,
#endif
if (payload != end) {
- g_warning ("PGS Set Palette: %ld bytes not consumed", end - payload);
+ GST_ERROR ("PGS Set Palette: %" G_GSSIZE_FORMAT " bytes not consumed",
+ (gssize) (end - payload));
dump_bytes (payload, end - payload);
}
@@ -529,7 +537,8 @@ parse_set_window (GstDVDSpu * dvdspu, guint8 type, guint8 * payload,
state->pgs.win_h);
if (payload != end) {
- g_warning ("PGS Set Window: %ld bytes not consumed", end - payload);
+ GST_ERROR ("PGS Set Window: %" G_GSSIZE_FORMAT " bytes not consumed",
+ (gssize) (end - payload));
dump_bytes (payload, end - payload);
}
@@ -590,7 +599,8 @@ parse_set_object_data (GstDVDSpu * dvdspu, guint8 type, guint8 * payload,
dump_rle_data (dvdspu, obj->rle_data, obj->rle_data_size);
if (payload != end) {
- g_warning ("PGS Set Object Data: %ld bytes not consumed", end - payload);
+ GST_ERROR ("PGS Set Object Data: %" G_GSSIZE_FORMAT " bytes not consumed",
+ (gssize) (end - payload));
dump_bytes (payload, end - payload);
}
@@ -642,7 +652,7 @@ parse_pgs_packet (GstDVDSpu * dvdspu, guint8 type, guint8 * payload,
pgs_state->in_presentation_segment = FALSE;
break;
default:
- g_warning ("Unknown PGS command: type 0x%02x len %u", type, len);
+ GST_ERROR ("Unknown PGS command: type 0x%02x len %u", type, len);
dump_bytes (payload, len);
break;
}
diff --git a/gst/dvdspu/gstspu-vobsub-render.c b/gst/dvdspu/gstspu-vobsub-render.c
index 07abff22..3709d82a 100644
--- a/gst/dvdspu/gstspu-vobsub-render.c
+++ b/gst/dvdspu/gstspu-vobsub-render.c
@@ -343,7 +343,7 @@ gstspu_vobsub_blend_comp_buffers (SpuState * state, guint8 * planes[3])
gstspu_blend_comp_buffers (state, planes);
}
-void
+static void
gstspu_vobsub_clear_comp_buffers (SpuState * state)
{
state->comp_left = state->vobsub.disp_rect.left;
@@ -452,7 +452,7 @@ gstspu_vobsub_render (GstDVDSpu * dvdspu, GstBuffer * buf)
|| state->vobsub.cur_Y > state->vobsub.clip_rect.bottom);
/* Reset the compositing buffer */
- gstspu_clear_comp_buffers (state);
+ gstspu_vobsub_clear_comp_buffers (state);
/* Render even line */
state->vobsub.comp_last_x_ptr = state->vobsub.comp_last_x;
gstspu_vobsub_render_line (state, planes, &state->vobsub.cur_offsets[0]);
@@ -480,7 +480,7 @@ gstspu_vobsub_render (GstDVDSpu * dvdspu, GstBuffer * buf)
/* Render a remaining lone last even line. y already has the correct value
* after the above loop exited. */
- gstspu_clear_comp_buffers (state);
+ gstspu_vobsub_clear_comp_buffers (state);
state->vobsub.comp_last_x_ptr = state->vobsub.comp_last_x;
gstspu_vobsub_render_line (state, planes, &state->vobsub.cur_offsets[0]);
gstspu_vobsub_blend_comp_buffers (state, planes);
diff --git a/gst/hdvparse/Makefile.am b/gst/hdvparse/Makefile.am
new file mode 100644
index 00000000..d7eb4d28
--- /dev/null
+++ b/gst/hdvparse/Makefile.am
@@ -0,0 +1,13 @@
+plugin_LTLIBRARIES = libgsthdvparse.la
+
+libgsthdvparse_la_SOURCES = \
+ gsthdvparse.c
+
+noinst_HEADERS = \
+ gsthdvparse.h
+
+libgsthdvparse_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS)
+libgsthdvparse_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS)
+libgsthdvparse_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgsthdvparse_la_LIBTOOLFLAGS = --tag=disable-static
+
diff --git a/gst/hdvparse/gsthdvparse.c b/gst/hdvparse/gsthdvparse.c
new file mode 100644
index 00000000..9914cfa2
--- /dev/null
+++ b/gst/hdvparse/gsthdvparse.c
@@ -0,0 +1,362 @@
+/*
+ * GStreamer
+ * Copyright (C) 2009 Edward Hervey <bilboed@bilboed.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * SECTION:element-HDVParse
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * <para>
+ * <programlisting>
+ * gst-launch -v -m filesrc ! mpegtsdemux ! hdvparse ! fakesink silent=TRUE
+ * </programlisting>
+ * </para>
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+
+#include "gsthdvparse.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_hdvparse_debug);
+#define GST_CAT_DEFAULT gst_hdvparse_debug
+
+/* Filter signals and args */
+enum
+{
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum
+{
+ PROP_0,
+};
+
+static gchar *aperture_table[] = {
+ "???",
+ "cls",
+ "1.0",
+ "1.2",
+ "1.4",
+ "1.6",
+ "1.7",
+ "1.8",
+ "2.0",
+ "2.2",
+ "2.4",
+ "2.6",
+ "2.8",
+ "3.1",
+ "3.4",
+ "3.7",
+ "4.0",
+ "4.4",
+ "4.8",
+ "5.2",
+ "5.6",
+ "6.2",
+ "6.8",
+ "7.3",
+ "8.0",
+ "8.7",
+ "9.6",
+ "10",
+ "11",
+ "12",
+ "14",
+ "14",
+ "16",
+ "17",
+ "18",
+ "6.7"
+};
+
+/* Observations from my HDV Camera (Canon HV20 Pal)
+ * FIXME : replace with with code once we've figured out the algorithm.
+ * Shutter speed 0x4f 0x50
+ * ------------------------------------
+ * 1/6 F3 95
+ * 1/8 90 91
+ * 1/12 FA 8A
+ * 1/15 C8 88
+ * 1/24 7D 85
+ * 1/30 64 84
+ * 1/48 BE 82
+ * 1/60 32 82
+ * 1/100 51 81
+ * 1/250 87 80
+ * 1/500 43 80
+ * 1/1000 22 80
+ * 1/2000 11 80
+ */
+typedef struct
+{
+ guint vala, valb, shutter;
+} Shutter_t;
+
+static Shutter_t shutter_table[] = {
+ {0xf3, 0x95, 6},
+ {0x90, 0x91, 8},
+ {0xfa, 0x8a, 12},
+ {0xc8, 0x88, 15},
+ {0x7d, 0x85, 24},
+ {0x64, 0x84, 30},
+ {0xbe, 0x82, 48},
+ {0x32, 0x82, 60},
+ {0x51, 0x81, 100},
+ {0x87, 0x80, 250},
+ {0x43, 0x80, 500},
+ {0x22, 0x80, 1000},
+ {0x11, 0x80, 2000}
+};
+
+/* Binary-coded decimal reading macro */
+#define BCD(c) ( ((((c) >> 4) & 0x0f) * 10) + ((c) & 0x0f) )
+/* Same as before, but with a mask */
+#define BCD_M(c, mask) (BCD ((c) & (mask)))
+
+
+/* the capabilities of the inputs and outputs.
+ *
+ * describe the real formats here.
+ */
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("private/hdv-a1")
+ );
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("private/hdv-a1,parsed=(boolean)True")
+ );
+
+/* debug category for fltering log messages
+ *
+ * exchange the string 'Template HDVParse' with your description
+ */
+#define DEBUG_INIT(bla) \
+ GST_DEBUG_CATEGORY_INIT (gst_hdvparse_debug, "hdvparse", 0, "HDV private stream parser");
+
+GST_BOILERPLATE_FULL (GstHDVParse, gst_hdvparse, GstBaseTransform,
+ GST_TYPE_BASE_TRANSFORM, DEBUG_INIT);
+
+static GstFlowReturn gst_hdvparse_transform_ip (GstBaseTransform * base,
+ GstBuffer * outbuf);
+
+/* GObject vmethod implementations */
+
+static void
+gst_hdvparse_base_init (gpointer klass)
+{
+ static GstElementDetails element_details = {
+ "HDVParser",
+ "Data/Parser",
+ "HDV private stream Parser",
+ "Edward Hervey <bilboed@bilboed.com>"
+ };
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&src_template));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&sink_template));
+ gst_element_class_set_details (element_class, &element_details);
+}
+
+/* initialize the HDVParse's class */
+static void
+gst_hdvparse_class_init (GstHDVParseClass * klass)
+{
+ GST_BASE_TRANSFORM_CLASS (klass)->transform_ip =
+ GST_DEBUG_FUNCPTR (gst_hdvparse_transform_ip);
+}
+
+/* initialize the new element
+ * initialize instance structure
+ */
+static void
+gst_hdvparse_init (GstHDVParse * filter, GstHDVParseClass * klass)
+{
+ GstBaseTransform *transform = GST_BASE_TRANSFORM (filter);
+
+ gst_base_transform_set_in_place (transform, TRUE);
+ gst_base_transform_set_passthrough (transform, TRUE);
+}
+
+static guint
+get_shutter_speed (guint8 vala, guint8 valb)
+{
+ guint i;
+
+ for (i = 0; i < G_N_ELEMENTS (shutter_table); i++)
+ if (shutter_table[i].vala == vala && shutter_table[i].valb == valb)
+ return shutter_table[i].shutter;
+ GST_WARNING ("Unknown shutter speed ! vala:0x%02x, valb:0x%02x", vala, valb);
+ return 0;
+}
+
+static void
+gst_hdvparse_parse (GstHDVParse * filter, GstBuffer * buf)
+{
+ guint8 *data = GST_BUFFER_DATA (buf);
+ guint apertured, shutter;
+ gfloat gain;
+ gboolean dst = FALSE;
+ GstStructure *str;
+ GstMessage *msg;
+
+ GST_MEMDUMP_OBJECT (filter, "BUFFER", data, GST_BUFFER_SIZE (buf));
+
+ str = gst_structure_empty_new ("HDV");
+
+ /* 0x1f - 0x23 : TimeCode */
+
+ if (data[0x1f] != 0xff) {
+ guint8 tframe, tsec, tmin, thour;
+ gchar *timecode = NULL;
+ tframe = BCD (data[0x1f] & 0x3f);
+ tsec = BCD (data[0x20] & 0x7f);
+ tmin = BCD (data[0x21] & 0x7f);
+ thour = BCD (data[0x22] & 0x3f);
+
+ timecode =
+ g_strdup_printf ("%01d:%02d:%02d.%02d", thour, tmin, tsec, tframe);
+ gst_structure_set (str, "timecode", G_TYPE_STRING, timecode, NULL);
+ g_free (timecode);
+ GST_LOG_OBJECT (filter, timecode);
+ }
+
+ /* 0x23 : Timezone / Dailight Saving Time */
+ /* 0x24 - 0x2a : Original time */
+ if (data[0x23] != 0xff) {
+ GDate *date = NULL;
+ guint tzone = 0;
+ guint day, month, year, hour, min, sec;
+ gchar *datetime;
+
+ tzone = data[0x23];
+ dst = !(tzone & 0x80);
+ tzone =
+ BCD (tzone & 0x1f) > 12 ? BCD (tzone & 0x1f) - 12 : BCD (tzone & 0x1f);
+ GST_LOG_OBJECT (filter, "TimeZone : %d, DST : %d", tzone, dst);
+
+ day = BCD_M (data[0x24], 0x3f);
+ month = BCD_M (data[0x25], 0x1f);
+ year = BCD (data[0x26]);
+ if (year > 90)
+ year += 1900;
+ else
+ year += 2000;
+ /* 0x27: ??? */
+ sec = BCD_M (data[0x28], 0x7f);
+ min = BCD_M (data[0x29], 0x7f);
+ hour = BCD_M (data[0x2a], 0x3f);
+
+ /* FIXME : we need a date/time object ! */
+ date = g_date_new_dmy (day, month, year);
+ datetime =
+ g_strdup_printf ("%02d/%02d/%02d %02d:%02d:%02d", day, month, year,
+ hour, min, sec);
+ gst_structure_set (str, "date", GST_TYPE_DATE, date, "recording-time",
+ G_TYPE_STRING, datetime, NULL);
+ g_free (datetime);
+ GST_LOG_OBJECT (filter, datetime);
+ }
+
+ /* 0x2b : Various flags, including scene-change */
+ if (!((data[0x2b] & 0x20) >> 5)) {
+ GST_LOG_OBJECT (filter, "Scene change !");
+ gst_structure_set (str, "scene-change", G_TYPE_BOOLEAN, TRUE, NULL);
+ }
+
+ /* Check for partials */
+ if (GST_BUFFER_SIZE (buf) < 0x50) {
+ goto beach;
+ }
+
+ /* 0x43 : Aperture */
+ apertured = data[0x43] & 0x3f;
+ if (apertured < 35) {
+ GST_LOG_OBJECT (filter, "Aperture : F%s", aperture_table[apertured]);
+ gst_structure_set (str, "aperture", G_TYPE_STRING,
+ aperture_table[apertured], NULL);
+ } else {
+ GST_LOG_OBJECT (filter, "Aperture : %d", apertured);
+ }
+
+ /* 0x44 : Gain */
+ gain = ((data[0x44] & 0xf) - 1) * 1.5;
+ GST_LOG_OBJECT (filter, "Gain : %03f db", gain);
+ gst_structure_set (str, "gain", G_TYPE_FLOAT, gain, NULL);
+
+ /* 0x4f - 0x50 : Shutter */
+ shutter = get_shutter_speed (data[0x4f], data[0x50]);
+ GST_LOG_OBJECT (filter, "Shutter speed : 1/%d", shutter);
+ if (shutter)
+ gst_structure_set (str, "shutter-speed", GST_TYPE_FRACTION, 1, shutter,
+ NULL);
+
+beach:
+ msg = gst_message_new_element (GST_OBJECT (filter), str);
+ gst_element_post_message (GST_ELEMENT (filter), msg);
+ return;
+}
+
+/* GstBaseTransform vmethod implementations */
+
+static GstFlowReturn
+gst_hdvparse_transform_ip (GstBaseTransform * base, GstBuffer * outbuf)
+{
+ GstHDVParse *filter = GST_HDVPARSE (base);
+
+ gst_hdvparse_parse (filter, outbuf);
+
+ return GST_FLOW_OK;
+}
+
+
+/* entry point to initialize the plug-in
+ * initialize the plug-in itself
+ * register the element factories and other features
+ */
+static gboolean
+HDVParse_init (GstPlugin * HDVParse)
+{
+ return gst_element_register (HDVParse, "hdvparse", GST_RANK_NONE,
+ GST_TYPE_HDVPARSE);
+}
+
+/* gstreamer looks for this structure to register HDVParses
+ *
+ * exchange the string 'Template HDVParse' with you HDVParse description
+ */
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "hdvparse",
+ "HDV private stream parser",
+ HDVParse_init, VERSION, "LGPL", "GStreamer", "http://gstreamer.net/")
diff --git a/gst/hdvparse/gsthdvparse.h b/gst/hdvparse/gsthdvparse.h
new file mode 100644
index 00000000..824634f6
--- /dev/null
+++ b/gst/hdvparse/gsthdvparse.h
@@ -0,0 +1,56 @@
+/*
+ * GStreamer
+ * Copyright (C) 2009 Edward Hervey <bilboed@bilboed.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_HDVPARSE_H__
+#define __GST_HDVPARSE_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_HDVPARSE \
+ (gst_hdvparse_get_type())
+#define GST_HDVPARSE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_HDVPARSE,GstHDVParse))
+#define GST_HDVPARSE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_HDVPARSE,GstHDVParseClass))
+#define GST_IS_HDVPARSE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_HDVPARSE))
+#define GST_IS_HDVPARSE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_HDVPARSE))
+
+typedef struct _GstHDVParse GstHDVParse;
+typedef struct _GstHDVParseClass GstHDVParseClass;
+
+struct _GstHDVParse {
+ GstBaseTransform element;
+
+};
+
+struct _GstHDVParseClass {
+ GstBaseTransformClass parent_class;
+};
+
+GType gst_hdvparse_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_HDVPARSE_H__ */
diff --git a/gst/mpegdemux/gstmpegtsdemux.c b/gst/mpegdemux/gstmpegtsdemux.c
index ef0de2c8..b75bfc6d 100644
--- a/gst/mpegdemux/gstmpegtsdemux.c
+++ b/gst/mpegdemux/gstmpegtsdemux.c
@@ -822,6 +822,39 @@ no_pcr_stream:
}
}
+static void
+gst_mpegts_demux_send_tags_for_stream (GstMpegTSDemux * demux,
+ GstMpegTSStream * stream)
+{
+ GstTagList *list = NULL;
+
+ if (stream->ES_info) {
+ guint8 *iso639_languages =
+ gst_mpeg_descriptor_find (stream->ES_info, DESC_ISO_639_LANGUAGE);
+ if (iso639_languages) {
+ if (DESC_ISO_639_LANGUAGE_codes_n (iso639_languages)) {
+ gchar lang_code[4];
+ gchar *language_n = (gchar *)
+ DESC_ISO_639_LANGUAGE_language_code_nth (iso639_languages, 0);
+ lang_code[0] = language_n[0];
+ lang_code[1] = language_n[1];
+ lang_code[2] = language_n[2];
+ lang_code[3] = 0;
+ if (!list)
+ list = gst_tag_list_new ();
+ gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
+ GST_TAG_LANGUAGE_CODE, lang_code, NULL);
+ }
+ }
+ }
+
+ if (list) {
+ GST_DEBUG_OBJECT (demux, "Sending tags %p for pad %s:%s",
+ list, GST_DEBUG_PAD_NAME (stream->pad));
+ gst_element_found_tags_for_pad (GST_ELEMENT (demux), stream->pad, list);
+ }
+}
+
#ifndef GST_FLOW_IS_SUCCESS
#define GST_FLOW_IS_SUCCESS(ret) ((ret) >= GST_FLOW_OK)
#endif
@@ -890,8 +923,8 @@ gst_mpegts_demux_data_cb (GstPESFilter * filter, gboolean first,
* to drop. */
if (stream->PMT_pid <= MPEGTS_MAX_PID && demux->streams[stream->PMT_pid]
&& demux->streams[demux->streams[stream->PMT_pid]->PMT.PCR_PID]
- && demux->streams[demux->streams[stream->PMT_pid]->PMT.PCR_PID]->
- discont_PCR) {
+ && demux->streams[demux->streams[stream->PMT_pid]->PMT.
+ PCR_PID]->discont_PCR) {
GST_WARNING_OBJECT (demux, "middle of discont, dropping");
goto bad_timestamp;
}
@@ -913,8 +946,8 @@ gst_mpegts_demux_data_cb (GstPESFilter * filter, gboolean first,
*/
if (stream->PMT_pid <= MPEGTS_MAX_PID && demux->streams[stream->PMT_pid]
&& demux->streams[demux->streams[stream->PMT_pid]->PMT.PCR_PID]
- && demux->streams[demux->streams[stream->PMT_pid]->PMT.PCR_PID]->
- last_PCR > 0) {
+ && demux->streams[demux->streams[stream->PMT_pid]->PMT.
+ PCR_PID]->last_PCR > 0) {
GST_DEBUG_OBJECT (demux, "timestamps wrapped before noticed in PCR");
time = MPEGTIME_TO_GSTTIME (pts) + stream->base_time +
MPEGTIME_TO_GSTTIME ((guint64) (1) << 33);
@@ -1026,6 +1059,9 @@ gst_mpegts_demux_data_cb (GstPESFilter * filter, gboolean first,
/* send new_segment */
gst_mpegts_demux_send_new_segment (demux, stream, pts);
+
+ /* send tags */
+ gst_mpegts_demux_send_tags_for_stream (demux, stream);
}
GST_DEBUG_OBJECT (srcpad, "pushing buffer");
diff --git a/gst/qtmux/fourcc.h b/gst/qtmux/fourcc.h
index 0fa7aa9b..3db60036 100644
--- a/gst/qtmux/fourcc.h
+++ b/gst/qtmux/fourcc.h
@@ -140,6 +140,7 @@ G_BEGIN_DECLS
#define FOURCC_drms GST_MAKE_FOURCC('d','r','m','s')
#define FOURCC_avc1 GST_MAKE_FOURCC('a','v','c','1')
#define FOURCC_h263 GST_MAKE_FOURCC('h','2','6','3')
+#define FOURCC_s263 GST_MAKE_FOURCC('s','2','6','3')
#define FOURCC_avcC GST_MAKE_FOURCC('a','v','c','C')
#define FOURCC_VP31 GST_MAKE_FOURCC('V','P','3','1')
#define FOURCC_rle_ GST_MAKE_FOURCC('r','l','e',' ')
diff --git a/gst/qtmux/gstqtmux.c b/gst/qtmux/gstqtmux.c
index b0df9d71..03b0a1a6 100644
--- a/gst/qtmux/gstqtmux.c
+++ b/gst/qtmux/gstqtmux.c
@@ -1507,7 +1507,10 @@ gst_qt_mux_video_sink_set_caps (GstPad * pad, GstCaps * caps)
break;
}
} else if (strcmp (mimetype, "video/x-h263") == 0) {
- entry.fourcc = FOURCC_h263;
+ if (format == GST_QT_MUX_FORMAT_QT)
+ entry.fourcc = FOURCC_h263;
+ else
+ entry.fourcc = FOURCC_s263;
ext_atom = build_h263_extension ();
} else if (strcmp (mimetype, "video/x-divx") == 0 ||
strcmp (mimetype, "video/mpeg") == 0) {
diff --git a/gst/rawparse/gstaudioparse.c b/gst/rawparse/gstaudioparse.c
index def9803e..f7eb6651 100644
--- a/gst/rawparse/gstaudioparse.c
+++ b/gst/rawparse/gstaudioparse.c
@@ -33,7 +33,9 @@
typedef enum
{
GST_AUDIO_PARSE_FORMAT_INT,
- GST_AUDIO_PARSE_FORMAT_FLOAT
+ GST_AUDIO_PARSE_FORMAT_FLOAT,
+ GST_AUDIO_PARSE_FORMAT_MULAW,
+ GST_AUDIO_PARSE_FORMAT_ALAW
} GstAudioParseFormat;
typedef enum
@@ -69,7 +71,7 @@ enum
ARG_ENDIANNESS,
ARG_WIDTH,
ARG_DEPTH,
- ARG_SIGNED,
+ ARG_SIGNED
};
@@ -81,6 +83,8 @@ gst_audio_parse_format_get_type (void)
static const GEnumValue format_types[] = {
{GST_AUDIO_PARSE_FORMAT_INT, "Integer", "int"},
{GST_AUDIO_PARSE_FORMAT_FLOAT, "Floating Point", "float"},
+ {GST_AUDIO_PARSE_FORMAT_ALAW, "A-Law", "alaw"},
+ {GST_AUDIO_PARSE_FORMAT_MULAW, "\302\265-Law", "mulaw"},
{0, NULL, NULL}
};
@@ -137,7 +141,9 @@ gst_audio_parse_base_init (gpointer g_class)
"audio/x-raw-float,"
" width=(int) { 32, 64 },"
" endianness=(int) { LITTLE_ENDIAN, BIG_ENDIAN }, "
- " rate=(int)[1,MAX]," " channels=(int)[1,MAX]");
+ " rate=(int)[1,MAX], channels=(int)[1,MAX]; "
+ "audio/x-alaw, rate=(int)[1,MAX], channels=(int)[1,MAX]; "
+ "audio/x-mulaw, rate=(int)[1,MAX], channels=(int)[1,MAX]");
gst_raw_parse_class_set_src_pad_template (rp_class, caps);
gst_raw_parse_class_set_multiple_frames_per_buffer (rp_class, TRUE);
@@ -282,9 +288,21 @@ gst_audio_parse_get_property (GObject * object, guint prop_id, GValue * value,
void
gst_audio_parse_update_frame_size (GstAudioParse * ap)
{
- gint framesize;
+ gint framesize, width;
- framesize = (ap->width / 8) * ap->channels;
+ switch (ap->format) {
+ case GST_AUDIO_PARSE_FORMAT_ALAW:
+ case GST_AUDIO_PARSE_FORMAT_MULAW:
+ width = 8;
+ break;
+ case GST_AUDIO_PARSE_FORMAT_INT:
+ case GST_AUDIO_PARSE_FORMAT_FLOAT:
+ default:
+ width = ap->width;
+ break;
+ }
+
+ framesize = (width / 8) * ap->channels;
gst_raw_parse_set_framesize (GST_RAW_PARSE (ap), framesize);
}
@@ -299,20 +317,37 @@ gst_audio_parse_get_caps (GstRawParse * rp)
gst_raw_parse_get_fps (rp, &fps_n, &fps_d);
- if (ap->format == GST_AUDIO_PARSE_FORMAT_INT) {
- caps = gst_caps_new_simple ("audio/x-raw-int",
- "rate", G_TYPE_INT, fps_n,
- "channels", G_TYPE_INT, ap->channels,
- "width", G_TYPE_INT, ap->width,
- "depth", G_TYPE_INT, ap->depth,
- "signed", G_TYPE_BOOLEAN, ap->signedness,
- "endianness", G_TYPE_INT, ap->endianness, NULL);
- } else {
- caps = gst_caps_new_simple ("audio/x-raw-float",
- "rate", G_TYPE_INT, fps_n,
- "channels", G_TYPE_INT, ap->channels,
- "width", G_TYPE_INT, ap->width,
- "endianness", G_TYPE_INT, ap->endianness, NULL);
+ switch (ap->format) {
+ case GST_AUDIO_PARSE_FORMAT_INT:
+ caps = gst_caps_new_simple ("audio/x-raw-int",
+ "rate", G_TYPE_INT, fps_n,
+ "channels", G_TYPE_INT, ap->channels,
+ "width", G_TYPE_INT, ap->width,
+ "depth", G_TYPE_INT, ap->depth,
+ "signed", G_TYPE_BOOLEAN, ap->signedness,
+ "endianness", G_TYPE_INT, ap->endianness, NULL);
+ break;
+ case GST_AUDIO_PARSE_FORMAT_FLOAT:
+ caps = gst_caps_new_simple ("audio/x-raw-float",
+ "rate", G_TYPE_INT, fps_n,
+ "channels", G_TYPE_INT, ap->channels,
+ "width", G_TYPE_INT, ap->width,
+ "endianness", G_TYPE_INT, ap->endianness, NULL);
+ break;
+ case GST_AUDIO_PARSE_FORMAT_ALAW:
+ caps = gst_caps_new_simple ("audio/x-alaw",
+ "rate", G_TYPE_INT, fps_n,
+ "channels", G_TYPE_INT, ap->channels, NULL);
+ break;
+ case GST_AUDIO_PARSE_FORMAT_MULAW:
+ caps = gst_caps_new_simple ("audio/x-mulaw",
+ "rate", G_TYPE_INT, fps_n,
+ "channels", G_TYPE_INT, ap->channels, NULL);
+ break;
+ default:
+ caps = gst_caps_new_empty ();
+ GST_ERROR_OBJECT (rp, "unexpected format %d", ap->format);
+ break;
}
return caps;
}
diff --git a/gst/rtpmanager/gstrtpbin.c b/gst/rtpmanager/gstrtpbin.c
index 19de4f1b..482cf017 100644
--- a/gst/rtpmanager/gstrtpbin.c
+++ b/gst/rtpmanager/gstrtpbin.c
@@ -1758,7 +1758,7 @@ gst_rtp_bin_handle_message (GstBin * bin, GstMessage * message)
const GstStructure *s = gst_message_get_structure (message);
/* we change the structure name and add the session ID to it */
- if (gst_structure_has_name (s, "GstRTPSessionSDES")) {
+ if (gst_structure_has_name (s, "application/x-rtp-source-sdes")) {
GSList *walk;
/* find the session, the message source has it */
@@ -1771,8 +1771,6 @@ gst_rtp_bin_handle_message (GstBin * bin, GstMessage * message)
message = gst_message_make_writable (message);
s = gst_message_get_structure (message);
- gst_structure_set_name ((GstStructure *) s, "GstRTPBinSDES");
-
gst_structure_set ((GstStructure *) s, "session", G_TYPE_UINT,
sess->id, NULL);
break;
diff --git a/gst/rtpmanager/rtpsource.c b/gst/rtpmanager/rtpsource.c
index 355526ee..ed080717 100644
--- a/gst/rtpmanager/rtpsource.c
+++ b/gst/rtpmanager/rtpsource.c
@@ -199,6 +199,7 @@ make_address_string (GstNetAddress * addr, gchar * dest, gulong n)
guint16 port;
gst_netaddress_get_ip4_address (addr, &address, &port);
+ address = g_ntohl (address);
g_snprintf (dest, n, "%d.%d.%d.%d:%d", (address >> 24) & 0xff,
(address >> 16) & 0xff, (address >> 8) & 0xff, address & 0xff,
@@ -321,7 +322,8 @@ rtp_source_create_sdes (RTPSource * src)
GstStructure *s;
gchar *str;
- s = gst_structure_new ("application/x-rtp-source-sdes", NULL);
+ s = gst_structure_new ("application/x-rtp-source-sdes",
+ "ssrc", G_TYPE_UINT, (guint) src->ssrc, NULL);
if ((str = rtp_source_get_sdes_string (src, GST_RTCP_SDES_CNAME))) {
gst_structure_set (s, "cname", G_TYPE_STRING, str, NULL);
diff --git a/gst/sdp/gstsdpdemux.c b/gst/sdp/gstsdpdemux.c
index 4deac870..3c543d0a 100644
--- a/gst/sdp/gstsdpdemux.c
+++ b/gst/sdp/gstsdpdemux.c
@@ -51,6 +51,9 @@
#include <unistd.h>
#endif
+/* include GLIB for G_OS_WIN32 */
+#include <glib.h>
+
#ifdef G_OS_WIN32
#ifdef _MSC_VER
#include <Winsock2.h>
diff --git a/gst/selector/gstoutputselector.c b/gst/selector/gstoutputselector.c
index 32988af4..bf354a74 100644
--- a/gst/selector/gstoutputselector.c
+++ b/gst/selector/gstoutputselector.c
@@ -19,7 +19,7 @@
/**
* SECTION:element-output-selector
- * @see_also: #GstTee, #GstInputSelector
+ * @see_also: #GstOutputSelector, #GstInputSelector
*
* Direct input stream to one out of N output pads.
*/
@@ -74,6 +74,8 @@ static GstPad *gst_output_selector_request_new_pad (GstElement * element,
static void gst_output_selector_release_pad (GstElement * element,
GstPad * pad);
static GstFlowReturn gst_output_selector_chain (GstPad * pad, GstBuffer * buf);
+static GstFlowReturn gst_output_selector_buffer_alloc (GstPad * pad,
+ guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
static GstStateChangeReturn gst_output_selector_change_state (GstElement *
element, GstStateChange transition);
static gboolean gst_output_selector_handle_sink_event (GstPad * pad,
@@ -136,17 +138,17 @@ gst_output_selector_init (GstOutputSelector * sel,
GST_DEBUG_FUNCPTR (gst_output_selector_chain));
gst_pad_set_event_function (sel->sinkpad,
GST_DEBUG_FUNCPTR (gst_output_selector_handle_sink_event));
-
- gst_element_add_pad (GST_ELEMENT (sel), sel->sinkpad);
-
+ gst_pad_set_bufferalloc_function (sel->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_output_selector_buffer_alloc));
/*
- gst_pad_set_bufferalloc_function (sel->sinkpad,
- GST_DEBUG_FUNCPTR (gst_output_selector_bufferalloc));
gst_pad_set_setcaps_function (sel->sinkpad,
GST_DEBUG_FUNCPTR (gst_pad_proxy_setcaps));
gst_pad_set_getcaps_function (sel->sinkpad,
GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
*/
+
+ gst_element_add_pad (GST_ELEMENT (sel), sel->sinkpad);
+
/* srcpad management */
sel->active_srcpad = NULL;
sel->nb_srcpads = 0;
@@ -251,6 +253,37 @@ gst_output_selector_get_property (GObject * object, guint prop_id,
}
}
+static GstFlowReturn
+gst_output_selector_buffer_alloc (GstPad * pad, guint64 offset, guint size,
+ GstCaps * caps, GstBuffer ** buf)
+{
+ GstOutputSelector *sel;
+ GstFlowReturn res;
+ GstPad *allocpad;
+
+ sel = GST_OUTPUT_SELECTOR (GST_PAD_PARENT (pad));
+
+ res = GST_FLOW_NOT_LINKED;
+
+ GST_OBJECT_LOCK (sel);
+ if ((allocpad = sel->active_srcpad)) {
+ /* if we had a previous pad we used for allocating a buffer, continue using
+ * it. */
+ GST_DEBUG_OBJECT (sel, "using pad %s:%s for alloc",
+ GST_DEBUG_PAD_NAME (allocpad));
+ gst_object_ref (allocpad);
+ GST_OBJECT_UNLOCK (sel);
+
+ res = gst_pad_alloc_buffer (allocpad, offset, size, caps, buf);
+ gst_object_unref (allocpad);
+
+ GST_OBJECT_LOCK (sel);
+ }
+ GST_OBJECT_UNLOCK (sel);
+
+ return res;
+}
+
static GstPad *
gst_output_selector_request_new_pad (GstElement * element,
GstPadTemplate * templ, const gchar * name)
diff --git a/gst/shapewipe/Makefile.am b/gst/shapewipe/Makefile.am
new file mode 100644
index 00000000..7f6df372
--- /dev/null
+++ b/gst/shapewipe/Makefile.am
@@ -0,0 +1,11 @@
+plugin_LTLIBRARIES = libgstshapewipe.la
+
+libgstshapewipe_la_SOURCES = gstshapewipe.c
+
+libgstshapewipe_la_CFLAGS = $(GIO_CFLAGS) $(GST_CFLAGS) $(GST_CONTROLLER_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS)
+libgstshapewipe_la_LIBADD = $(GIO_LIBS) $(GST_LIBS) $(GST_CONTROLLER_LIBS) $(GST_PLUGINS_BASE_LIBS) -lgstvideo-@GST_MAJORMINOR@
+libgstshapewipe_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstshapewipe_la_LIBTOOLFLAGS = --tag=disable-static
+
+noinst_HEADERS = gstshapewipe.h
+
diff --git a/gst/shapewipe/gstshapewipe.c b/gst/shapewipe/gstshapewipe.c
new file mode 100644
index 00000000..ec33f0a7
--- /dev/null
+++ b/gst/shapewipe/gstshapewipe.c
@@ -0,0 +1,847 @@
+/* GStreamer
+ * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+
+#include <gst/gst.h>
+#include <gst/controller/gstcontroller.h>
+
+#include "gstshapewipe.h"
+
+static void gst_shape_wipe_finalize (GObject * object);
+static void gst_shape_wipe_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+static void gst_shape_wipe_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+
+static void gst_shape_wipe_reset (GstShapeWipe * self);
+
+static GstStateChangeReturn gst_shape_wipe_change_state (GstElement * element,
+ GstStateChange transition);
+
+static GstFlowReturn gst_shape_wipe_video_sink_chain (GstPad * pad,
+ GstBuffer * buffer);
+static gboolean gst_shape_wipe_video_sink_event (GstPad * pad,
+ GstEvent * event);
+static gboolean gst_shape_wipe_video_sink_setcaps (GstPad * pad,
+ GstCaps * caps);
+static GstCaps *gst_shape_wipe_video_sink_getcaps (GstPad * pad);
+static GstFlowReturn gst_shape_wipe_mask_sink_chain (GstPad * pad,
+ GstBuffer * buffer);
+static gboolean gst_shape_wipe_mask_sink_event (GstPad * pad, GstEvent * event);
+static gboolean gst_shape_wipe_mask_sink_setcaps (GstPad * pad, GstCaps * caps);
+static GstCaps *gst_shape_wipe_mask_sink_getcaps (GstPad * pad);
+static gboolean gst_shape_wipe_src_event (GstPad * pad, GstEvent * event);
+static GstCaps *gst_shape_wipe_src_getcaps (GstPad * pad);
+
+enum
+{
+ PROP_0,
+ PROP_POSITION,
+ PROP_BORDER
+};
+
+static GstStaticPadTemplate video_sink_pad_template =
+GST_STATIC_PAD_TEMPLATE ("video_sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV")));
+
+static GstStaticPadTemplate mask_sink_pad_template =
+ GST_STATIC_PAD_TEMPLATE ("mask_sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-raw-gray, "
+ "bpp = 8, "
+ "depth = 8, "
+ "width = " GST_VIDEO_SIZE_RANGE ", "
+ "height = " GST_VIDEO_SIZE_RANGE ", " "framerate = 0/1 ; "
+ "video/x-raw-gray, " "bpp = 16, " "depth = 16, "
+ "endianness = BYTE_ORDER, " "width = " GST_VIDEO_SIZE_RANGE ", "
+ "height = " GST_VIDEO_SIZE_RANGE ", " "framerate = 0/1"));
+
+static GstStaticPadTemplate src_pad_template =
+GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV")));
+
+GST_DEBUG_CATEGORY_STATIC (gst_shape_wipe_debug);
+#define GST_CAT_DEFAULT gst_shape_wipe_debug
+
+GST_BOILERPLATE (GstShapeWipe, gst_shape_wipe, GstElement, GST_TYPE_ELEMENT);
+
+static void
+gst_shape_wipe_base_init (gpointer g_class)
+{
+ GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_set_details_simple (gstelement_class,
+ "Shape Wipe transition filter",
+ "Filter/Editor/Video",
+ "Adds a shape wipe transition to a video stream",
+ "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&video_sink_pad_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&mask_sink_pad_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&src_pad_template));
+}
+
+static void
+gst_shape_wipe_class_init (GstShapeWipeClass * klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+
+ gobject_class->finalize = gst_shape_wipe_finalize;
+ gobject_class->set_property = gst_shape_wipe_set_property;
+ gobject_class->get_property = gst_shape_wipe_get_property;
+
+ g_object_class_install_property (gobject_class, PROP_POSITION,
+ g_param_spec_float ("position", "Position", "Position of the mask",
+ 0.0, 1.0, 0.0,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
+ g_object_class_install_property (gobject_class, PROP_BORDER,
+ g_param_spec_float ("border", "Border", "Border of the mask",
+ 0.0, 1.0, 0.0,
+ G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
+
+ gstelement_class->change_state =
+ GST_DEBUG_FUNCPTR (gst_shape_wipe_change_state);
+}
+
+static void
+gst_shape_wipe_init (GstShapeWipe * self, GstShapeWipeClass * g_class)
+{
+ self->video_sinkpad =
+ gst_pad_new_from_static_template (&video_sink_pad_template, "video_sink");
+ gst_pad_set_chain_function (self->video_sinkpad,
+ GST_DEBUG_FUNCPTR (gst_shape_wipe_video_sink_chain));
+ gst_pad_set_event_function (self->video_sinkpad,
+ GST_DEBUG_FUNCPTR (gst_shape_wipe_video_sink_event));
+ gst_pad_set_setcaps_function (self->video_sinkpad,
+ GST_DEBUG_FUNCPTR (gst_shape_wipe_video_sink_setcaps));
+ gst_pad_set_getcaps_function (self->video_sinkpad,
+ GST_DEBUG_FUNCPTR (gst_shape_wipe_video_sink_getcaps));
+ gst_element_add_pad (GST_ELEMENT (self), self->video_sinkpad);
+
+ self->mask_sinkpad =
+ gst_pad_new_from_static_template (&mask_sink_pad_template, "mask_sink");
+ gst_pad_set_chain_function (self->mask_sinkpad,
+ GST_DEBUG_FUNCPTR (gst_shape_wipe_mask_sink_chain));
+ gst_pad_set_event_function (self->mask_sinkpad,
+ GST_DEBUG_FUNCPTR (gst_shape_wipe_mask_sink_event));
+ gst_pad_set_setcaps_function (self->mask_sinkpad,
+ GST_DEBUG_FUNCPTR (gst_shape_wipe_mask_sink_setcaps));
+ gst_pad_set_getcaps_function (self->mask_sinkpad,
+ GST_DEBUG_FUNCPTR (gst_shape_wipe_mask_sink_getcaps));
+ gst_element_add_pad (GST_ELEMENT (self), self->mask_sinkpad);
+
+ self->srcpad = gst_pad_new_from_static_template (&src_pad_template, "src");
+ gst_pad_set_event_function (self->srcpad,
+ GST_DEBUG_FUNCPTR (gst_shape_wipe_src_event));
+ gst_pad_set_getcaps_function (self->srcpad,
+ GST_DEBUG_FUNCPTR (gst_shape_wipe_src_getcaps));
+ gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
+
+ self->mask_mutex = g_mutex_new ();
+ self->mask_cond = g_cond_new ();
+
+ gst_shape_wipe_reset (self);
+}
+
+static void
+gst_shape_wipe_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstShapeWipe *self = GST_SHAPE_WIPE (object);
+
+ switch (prop_id) {
+ case PROP_POSITION:
+ g_value_set_float (value, self->mask_position);
+ break;
+ case PROP_BORDER:
+ g_value_set_float (value, self->mask_border);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_shape_wipe_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstShapeWipe *self = GST_SHAPE_WIPE (object);
+
+ switch (prop_id) {
+ case PROP_POSITION:
+ self->mask_position = g_value_get_float (value);
+ break;
+ case PROP_BORDER:
+ self->mask_border = g_value_get_float (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_shape_wipe_finalize (GObject * object)
+{
+ GstShapeWipe *self = GST_SHAPE_WIPE (object);
+
+ gst_shape_wipe_reset (self);
+
+ if (self->mask_cond)
+ g_cond_free (self->mask_cond);
+ self->mask_cond = NULL;
+
+ if (self->mask_mutex)
+ g_mutex_free (self->mask_mutex);
+ self->mask_mutex = NULL;
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_shape_wipe_reset (GstShapeWipe * self)
+{
+ if (self->mask)
+ gst_buffer_unref (self->mask);
+ self->mask = NULL;
+
+ g_cond_signal (self->mask_cond);
+
+ self->width = self->height = 0;
+ self->mask_position = 0.0;
+ self->mask_border = 0.0;
+ self->mask_bpp = 0;
+
+ gst_segment_init (&self->segment, GST_FORMAT_TIME);
+}
+
+static gboolean
+gst_shape_wipe_video_sink_setcaps (GstPad * pad, GstCaps * caps)
+{
+ GstShapeWipe *self = GST_SHAPE_WIPE (gst_pad_get_parent (pad));
+ gboolean ret = TRUE;
+ GstStructure *s;
+ gint width, height;
+
+ GST_DEBUG_OBJECT (pad, "Setting caps: %" GST_PTR_FORMAT, caps);
+
+ s = gst_caps_get_structure (caps, 0);
+
+ if (!gst_structure_get_int (s, "width", &width) ||
+ !gst_structure_get_int (s, "height", &height)) {
+ ret = FALSE;
+ goto done;
+ }
+
+ if (self->width != width || self->height != height) {
+ g_mutex_lock (self->mask_mutex);
+ self->width = width;
+ self->height = height;
+
+ if (self->mask)
+ gst_buffer_unref (self->mask);
+ self->mask = NULL;
+ g_mutex_unlock (self->mask_mutex);
+ }
+
+ ret = gst_pad_set_caps (self->srcpad, caps);
+
+done:
+ gst_object_unref (self);
+
+ return ret;
+}
+
+static GstCaps *
+gst_shape_wipe_video_sink_getcaps (GstPad * pad)
+{
+ GstShapeWipe *self = GST_SHAPE_WIPE (gst_pad_get_parent (pad));
+ GstCaps *ret, *tmp;
+
+ if (GST_PAD_CAPS (pad))
+ return gst_caps_copy (GST_PAD_CAPS (pad));
+
+ tmp = gst_pad_peer_get_caps (self->srcpad);
+ if (tmp) {
+ ret = gst_caps_intersect (tmp, gst_pad_get_pad_template_caps (pad));
+ gst_caps_unref (tmp);
+ } else {
+ ret = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
+ }
+
+ tmp = gst_pad_peer_get_caps (pad);
+ if (tmp) {
+ GstCaps *intersection;
+
+ intersection = gst_caps_intersect (tmp, ret);
+ gst_caps_unref (tmp);
+ gst_caps_unref (ret);
+ ret = intersection;
+ }
+
+ if (self->height && self->width) {
+ guint i, n;
+
+ n = gst_caps_get_size (ret);
+ for (i = 0; i < n; i++) {
+ GstStructure *s = gst_caps_get_structure (ret, i);
+
+ gst_structure_set (s, "width", G_TYPE_INT, self->width, "height",
+ G_TYPE_INT, self->height, NULL);
+ }
+ }
+
+ tmp = gst_pad_peer_get_caps (self->mask_sinkpad);
+ if (tmp) {
+ GstCaps *intersection, *tmp2;
+ guint i, n;
+
+ tmp = gst_caps_make_writable (tmp);
+
+ tmp2 = gst_caps_copy (gst_pad_get_pad_template_caps (self->mask_sinkpad));
+
+ intersection = gst_caps_intersect (tmp, tmp2);
+ gst_caps_unref (tmp);
+ gst_caps_unref (tmp2);
+ tmp = intersection;
+
+ n = gst_caps_get_size (tmp);
+
+ for (i = 0; i < n; i++) {
+ GstStructure *s = gst_caps_get_structure (tmp, i);
+
+ gst_structure_remove_fields (s, "bpp", "depth", "endianness", "framerate",
+ NULL);
+ gst_structure_set_name (s, "video/x-raw-yuv");
+ }
+
+ intersection = gst_caps_intersect (tmp, ret);
+ gst_caps_unref (tmp);
+ gst_caps_unref (ret);
+ ret = intersection;
+ }
+
+ gst_object_unref (self);
+
+ GST_DEBUG_OBJECT (pad, "Returning caps: %" GST_PTR_FORMAT, ret);
+
+ return ret;
+}
+
+static gboolean
+gst_shape_wipe_mask_sink_setcaps (GstPad * pad, GstCaps * caps)
+{
+ GstShapeWipe *self = GST_SHAPE_WIPE (gst_pad_get_parent (pad));
+ gboolean ret = TRUE;
+ GstStructure *s;
+ gint width, height, bpp;
+
+ GST_DEBUG_OBJECT (pad, "Setting caps: %" GST_PTR_FORMAT, caps);
+
+ s = gst_caps_get_structure (caps, 0);
+
+ if (!gst_structure_get_int (s, "width", &width) ||
+ !gst_structure_get_int (s, "height", &height) ||
+ !gst_structure_get_int (s, "bpp", &bpp)) {
+ ret = FALSE;
+ goto done;
+ }
+
+ if ((self->width != width || self->height != height) &&
+ self->width > 0 && self->height > 0) {
+ GST_ERROR_OBJECT (pad, "Mask caps must have the same width/height "
+ "as the video caps");
+ ret = FALSE;
+ goto done;
+ } else {
+ self->width = width;
+ self->height = height;
+ }
+
+ self->mask_bpp = bpp;
+
+done:
+ gst_object_unref (self);
+
+ return ret;
+}
+
+static GstCaps *
+gst_shape_wipe_mask_sink_getcaps (GstPad * pad)
+{
+ GstShapeWipe *self = GST_SHAPE_WIPE (gst_pad_get_parent (pad));
+ GstCaps *ret, *tmp;
+ guint i, n;
+
+ if (GST_PAD_CAPS (pad))
+ return gst_caps_copy (GST_PAD_CAPS (pad));
+
+ tmp = gst_pad_peer_get_caps (self->video_sinkpad);
+ if (tmp) {
+ ret =
+ gst_caps_intersect (tmp,
+ gst_pad_get_pad_template_caps (self->video_sinkpad));
+ gst_caps_unref (tmp);
+ } else {
+ ret = gst_caps_copy (gst_pad_get_pad_template_caps (self->video_sinkpad));
+ }
+
+ tmp = gst_pad_peer_get_caps (self->srcpad);
+ if (tmp) {
+ GstCaps *intersection;
+
+ intersection = gst_caps_intersect (ret, tmp);
+ gst_caps_unref (ret);
+ gst_caps_unref (tmp);
+ ret = intersection;
+ }
+
+ n = gst_caps_get_size (ret);
+ tmp = gst_caps_new_empty ();
+ for (i = 0; i < n; i++) {
+ GstStructure *s = gst_caps_get_structure (ret, i);
+ GstStructure *t;
+
+ gst_structure_set_name (s, "video/x-raw-gray");
+ gst_structure_remove_fields (s, "format", "framerate", NULL);
+
+ if (self->width && self->height)
+ gst_structure_set (s, "width", G_TYPE_INT, self->width, "height",
+ G_TYPE_INT, self->height, NULL);
+
+ gst_structure_set (s, "framerate", GST_TYPE_FRACTION, 0, 1, NULL);
+
+ t = gst_structure_copy (s);
+
+ gst_structure_set (s, "bpp", G_TYPE_INT, 16, "depth", G_TYPE_INT, 16,
+ "endianness", G_TYPE_INT, G_BYTE_ORDER, NULL);
+ gst_structure_set (t, "bpp", G_TYPE_INT, 8, "depth", G_TYPE_INT, 8, NULL);
+
+ gst_caps_append_structure (tmp, t);
+ }
+ gst_caps_merge (ret, tmp);
+
+ tmp = gst_pad_peer_get_caps (pad);
+ if (tmp) {
+ GstCaps *intersection;
+
+ intersection = gst_caps_intersect (tmp, ret);
+ gst_caps_unref (tmp);
+ gst_caps_unref (ret);
+ ret = intersection;
+ }
+
+ gst_object_unref (self);
+
+ GST_DEBUG_OBJECT (pad, "Returning caps: %" GST_PTR_FORMAT, ret);
+
+ return ret;
+}
+
+static GstCaps *
+gst_shape_wipe_src_getcaps (GstPad * pad)
+{
+ GstShapeWipe *self = GST_SHAPE_WIPE (gst_pad_get_parent (pad));
+ GstCaps *ret, *tmp;
+
+ if (GST_PAD_CAPS (pad))
+ return gst_caps_copy (GST_PAD_CAPS (pad));
+ else if (GST_PAD_CAPS (self->video_sinkpad))
+ return gst_caps_copy (GST_PAD_CAPS (self->video_sinkpad));
+
+ tmp = gst_pad_peer_get_caps (self->video_sinkpad);
+ if (tmp) {
+ ret =
+ gst_caps_intersect (tmp,
+ gst_pad_get_pad_template_caps (self->video_sinkpad));
+ gst_caps_unref (tmp);
+ } else {
+ ret = gst_caps_copy (gst_pad_get_pad_template_caps (self->video_sinkpad));
+ }
+
+ tmp = gst_pad_peer_get_caps (pad);
+ if (tmp) {
+ GstCaps *intersection;
+
+ intersection = gst_caps_intersect (tmp, ret);
+ gst_caps_unref (tmp);
+ gst_caps_unref (ret);
+ ret = intersection;
+ }
+
+ if (self->height && self->width) {
+ guint i, n;
+
+ n = gst_caps_get_size (ret);
+ for (i = 0; i < n; i++) {
+ GstStructure *s = gst_caps_get_structure (ret, i);
+
+ gst_structure_set (s, "width", G_TYPE_INT, self->width, "height",
+ G_TYPE_INT, self->height, NULL);
+ }
+ }
+
+ tmp = gst_pad_peer_get_caps (self->mask_sinkpad);
+ if (tmp) {
+ GstCaps *intersection, *tmp2;
+ guint i, n;
+
+ tmp = gst_caps_make_writable (tmp);
+ tmp2 = gst_caps_copy (gst_pad_get_pad_template_caps (self->mask_sinkpad));
+
+ intersection = gst_caps_intersect (tmp, tmp2);
+ gst_caps_unref (tmp);
+ gst_caps_unref (tmp2);
+
+ tmp = intersection;
+ n = gst_caps_get_size (tmp);
+
+ for (i = 0; i < n; i++) {
+ GstStructure *s = gst_caps_get_structure (tmp, i);
+
+ gst_structure_remove_fields (s, "bpp", "depth", "endianness", "framerate",
+ NULL);
+ gst_structure_set_name (s, "video/x-raw-yuv");
+ }
+
+ intersection = gst_caps_intersect (tmp, ret);
+ gst_caps_unref (tmp);
+ gst_caps_unref (ret);
+ ret = intersection;
+ }
+
+ gst_object_unref (self);
+
+ GST_DEBUG_OBJECT (pad, "Returning caps: %" GST_PTR_FORMAT, ret);
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_shape_wipe_blend_16 (GstShapeWipe * self, GstBuffer * inbuf,
+ GstBuffer * maskbuf, GstBuffer * outbuf)
+{
+ const guint16 *mask = (const guint16 *) GST_BUFFER_DATA (maskbuf);
+ const guint8 *input = (const guint8 *) GST_BUFFER_DATA (inbuf);
+ guint8 *output = (guint8 *) GST_BUFFER_DATA (outbuf);
+ guint i, j;
+ guint mask_increment = GST_ROUND_UP_2 (self->width) - self->width;
+ gfloat position = self->mask_position;
+ gfloat low = position - (self->mask_border / 2.0f);
+ gfloat high = position + (self->mask_border / 2.0f);
+
+ if (low < 0.0f) {
+ high = 0.0f;
+ low = 0.0f;
+ }
+
+ if (high > 1.0f) {
+ low = 1.0f;
+ high = 1.0f;
+ }
+
+ for (i = 0; i < self->height; i++) {
+ for (j = 0; j < self->width; j++) {
+ gfloat in = *mask / 65535.0f;
+
+ if (in < low) {
+ output[0] = 0x00; /* A */
+ output[1] = 0x00; /* Y */
+ output[2] = 0x80; /* U */
+ output[3] = 0x80; /* V */
+ } else if (in >= high) {
+ output[0] = 0xff; /* A */
+ output[1] = input[1]; /* Y */
+ output[2] = input[2]; /* U */
+ output[3] = input[3]; /* V */
+ } else {
+ gfloat val = 255.0f * ((in - low) / (high - low));
+
+ output[0] = CLAMP (val, 0, 255); /* A */
+ output[1] = input[1]; /* Y */
+ output[2] = input[2]; /* U */
+ output[3] = input[3]; /* V */
+ }
+
+ mask++;
+ input += 4;
+ output += 4;
+ }
+ mask += mask_increment;
+ }
+
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_shape_wipe_blend_8 (GstShapeWipe * self, GstBuffer * inbuf,
+ GstBuffer * maskbuf, GstBuffer * outbuf)
+{
+ const guint8 *mask = (const guint8 *) GST_BUFFER_DATA (maskbuf);
+ const guint8 *input = (const guint8 *) GST_BUFFER_DATA (inbuf);
+ guint8 *output = (guint8 *) GST_BUFFER_DATA (outbuf);
+ guint i, j;
+ guint mask_increment = GST_ROUND_UP_4 (self->width) - self->width;
+ gfloat position = self->mask_position;
+ gfloat low = position - (self->mask_border / 2.0f);
+ gfloat high = position + (self->mask_border / 2.0f);
+
+ if (low < 0.0f) {
+ high = 0.0f;
+ low = 0.0f;
+ }
+
+ if (high > 1.0f) {
+ low = 1.0f;
+ high = 1.0f;
+ }
+
+ for (i = 0; i < self->height; i++) {
+ for (j = 0; j < self->width; j++) {
+ gfloat in = *mask / 255.0f;
+
+ if (in < low) {
+ output[0] = 0x00; /* A */
+ output[1] = 0x00; /* Y */
+ output[2] = 0x80; /* U */
+ output[3] = 0x80; /* V */
+ } else if (in >= high) {
+ output[0] = 0xff; /* A */
+ output[1] = input[1]; /* Y */
+ output[2] = input[2]; /* U */
+ output[3] = input[3]; /* V */
+ } else {
+ gfloat val = 255.0f * ((in - low) / (high - low));
+
+ output[0] = CLAMP (val, 0, 255); /* A */
+ output[1] = input[1]; /* Y */
+ output[2] = input[2]; /* U */
+ output[3] = input[3]; /* V */
+ }
+
+ mask++;
+ input += 4;
+ output += 4;
+ }
+ mask += mask_increment;
+ }
+
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_shape_wipe_video_sink_chain (GstPad * pad, GstBuffer * buffer)
+{
+ GstShapeWipe *self = GST_SHAPE_WIPE (GST_PAD_PARENT (pad));
+ GstFlowReturn ret = GST_FLOW_OK;
+ GstBuffer *mask = NULL, *outbuf = NULL;
+ GstClockTime timestamp;
+
+ timestamp = GST_BUFFER_TIMESTAMP (buffer);
+ timestamp =
+ gst_segment_to_stream_time (&self->segment, GST_FORMAT_TIME, timestamp);
+
+ if (GST_CLOCK_TIME_IS_VALID (timestamp))
+ gst_object_sync_values (G_OBJECT (self), timestamp);
+
+ GST_DEBUG_OBJECT (self,
+ "Blending buffer with timestamp %" GST_TIME_FORMAT " at position %lf",
+ GST_TIME_ARGS (timestamp), self->mask_position);
+
+ g_mutex_lock (self->mask_mutex);
+ mask = self->mask;
+ if (self->mask)
+ gst_buffer_ref (self->mask);
+ else
+ g_cond_wait (self->mask_cond, self->mask_mutex);
+
+ if (self->mask == NULL) {
+ g_mutex_unlock (self->mask_mutex);
+ return GST_FLOW_UNEXPECTED;
+ }
+
+ mask = gst_buffer_ref (self->mask);
+
+ g_mutex_unlock (self->mask_mutex);
+
+ ret =
+ gst_pad_alloc_buffer_and_set_caps (self->srcpad, GST_BUFFER_OFFSET_NONE,
+ GST_BUFFER_SIZE (buffer), GST_PAD_CAPS (self->srcpad), &outbuf);
+ if (G_UNLIKELY (ret != GST_FLOW_OK))
+ return ret;
+
+ if (self->mask_bpp == 16)
+ ret = gst_shape_wipe_blend_16 (self, buffer, mask, outbuf);
+ else
+ ret = gst_shape_wipe_blend_8 (self, buffer, mask, outbuf);
+
+ gst_buffer_unref (mask);
+ gst_buffer_unref (buffer);
+ if (ret != GST_FLOW_OK) {
+ gst_buffer_unref (outbuf);
+ return ret;
+ }
+
+ ret = gst_pad_push (self->srcpad, outbuf);
+ return ret;
+}
+
+static GstFlowReturn
+gst_shape_wipe_mask_sink_chain (GstPad * pad, GstBuffer * buffer)
+{
+ GstShapeWipe *self = GST_SHAPE_WIPE (GST_PAD_PARENT (pad));
+ GstFlowReturn ret = GST_FLOW_OK;
+
+ g_mutex_lock (self->mask_mutex);
+ GST_DEBUG_OBJECT (self, "Setting new mask buffer: %" GST_PTR_FORMAT, buffer);
+
+ gst_buffer_replace (&self->mask, buffer);
+ g_cond_signal (self->mask_cond);
+ g_mutex_unlock (self->mask_mutex);
+
+ return ret;
+}
+
+static GstStateChangeReturn
+gst_shape_wipe_change_state (GstElement * element, GstStateChange transition)
+{
+ GstShapeWipe *self = GST_SHAPE_WIPE (element);
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ default:
+ break;
+ }
+
+ /* Unblock video sink chain function */
+ if (transition == GST_STATE_CHANGE_PAUSED_TO_READY)
+ g_cond_signal (self->mask_cond);
+
+ if (GST_ELEMENT_CLASS (parent_class)->change_state)
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_shape_wipe_reset (self);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static gboolean
+gst_shape_wipe_video_sink_event (GstPad * pad, GstEvent * event)
+{
+ GstShapeWipe *self = GST_SHAPE_WIPE (gst_pad_get_parent (pad));
+ gboolean ret;
+
+ GST_DEBUG_OBJECT (pad, "Got %s event", GST_EVENT_TYPE_NAME (event));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_NEWSEGMENT:{
+ GstFormat fmt;
+ gboolean is_update;
+ gint64 start, end, base;
+ gdouble rate;
+
+ gst_event_parse_new_segment (event, &is_update, &rate, &fmt, &start,
+ &end, &base);
+ if (fmt == GST_FORMAT_TIME) {
+ GST_DEBUG_OBJECT (pad,
+ "Got NEWSEGMENT event in GST_FORMAT_TIME, passing on (%"
+ GST_TIME_FORMAT " - %" GST_TIME_FORMAT ")", GST_TIME_ARGS (start),
+ GST_TIME_ARGS (end));
+ gst_segment_set_newsegment (&self->segment, is_update, rate, fmt, start,
+ end, base);
+ } else {
+ gst_segment_init (&self->segment, GST_FORMAT_TIME);
+ }
+ }
+ /* fall through */
+ default:
+ ret = gst_pad_push_event (self->srcpad, event);
+ break;
+ }
+
+ gst_object_unref (self);
+ return ret;
+}
+
+static gboolean
+gst_shape_wipe_mask_sink_event (GstPad * pad, GstEvent * event)
+{
+ GST_DEBUG_OBJECT (pad, "Got %s event", GST_EVENT_TYPE_NAME (event));
+
+ /* Dropping all events here */
+ gst_event_unref (event);
+ return TRUE;
+}
+
+static gboolean
+gst_shape_wipe_src_event (GstPad * pad, GstEvent * event)
+{
+ GstShapeWipe *self = GST_SHAPE_WIPE (gst_pad_get_parent (pad));
+ gboolean ret;
+
+ switch (GST_EVENT_TYPE (event)) {
+ default:
+ ret = gst_pad_push_event (self->video_sinkpad, event);
+ break;
+ }
+
+ gst_object_unref (self);
+ return ret;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ GST_DEBUG_CATEGORY_INIT (gst_shape_wipe_debug, "shapewipe", 0,
+ "shapewipe element");
+
+ gst_controller_init (NULL, NULL);
+
+ if (!gst_element_register (plugin, "shapewipe", GST_RANK_NONE,
+ GST_TYPE_SHAPE_WIPE))
+ return FALSE;
+
+ return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "shapewipe",
+ "Shape Wipe transition filter",
+ plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/gst/shapewipe/gstshapewipe.h b/gst/shapewipe/gstshapewipe.h
new file mode 100644
index 00000000..00ed776e
--- /dev/null
+++ b/gst/shapewipe/gstshapewipe.h
@@ -0,0 +1,74 @@
+/* GStreamer
+ * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_SHAPE_WIPE_H__
+#define __GST_SHAPE_WIPE_H__
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_SHAPE_WIPE \
+ (gst_shape_wipe_get_type())
+#define GST_SHAPE_WIPE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SHAPE_WIPE,GstShapeWipe))
+#define GST_SHAPE_WIPE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SHAPE_WIPE,GstShapeWipeClass))
+#define GST_SHAPE_WIPE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_SHAPE_WIPE,GstShapeWipeClass))
+#define GST_IS_SHAPE_WIPE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SHAPE_WIPE))
+#define GST_IS_SHAPE_WIPE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SHAPE_WIPE))
+
+typedef struct _GstShapeWipe GstShapeWipe;
+typedef struct _GstShapeWipeClass GstShapeWipeClass;
+
+struct _GstShapeWipe
+{
+ GstElement parent;
+
+ /* private */
+ GstPad *video_sinkpad;
+ GstPad *mask_sinkpad;
+
+ GstPad *srcpad;
+
+ GstSegment segment;
+
+ GstBuffer *mask;
+ gfloat mask_position;
+ gfloat mask_border;
+ GMutex *mask_mutex;
+ GCond *mask_cond;
+ gint mask_bpp;
+
+ gint width, height;
+};
+
+struct _GstShapeWipeClass
+{
+ GstElementClass parent_class;
+};
+
+GType gst_shape_wipe_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_SHAPE_WIPE_H__ */
diff --git a/tests/examples/Makefile.am b/tests/examples/Makefile.am
index e20db8df..b36232de 100644
--- a/tests/examples/Makefile.am
+++ b/tests/examples/Makefile.am
@@ -10,5 +10,5 @@ else
DIRECTFB_DIR=
endif
-SUBDIRS= $(DIRECTFB_DIR) $(GTK_EXAMPLES) switch
-DIST_SUBDIRS= directfb switch scaletempo mxf
+SUBDIRS= $(DIRECTFB_DIR) $(GTK_EXAMPLES) switch shapewipe mxf
+DIST_SUBDIRS= directfb switch scaletempo shapewipe mxf
diff --git a/tests/examples/shapewipe/Makefile.am b/tests/examples/shapewipe/Makefile.am
new file mode 100644
index 00000000..0a5eecf1
--- /dev/null
+++ b/tests/examples/shapewipe/Makefile.am
@@ -0,0 +1,8 @@
+noinst_PROGRAMS = shapewipe-example
+
+shapewipe_example_SOURCES = shapewipe-example.c
+shapewipe_example_CFLAGS = $(GST_CFLAGS) $(GST_CONTROLLER_CFLAGS)
+shapewipe_example_LDFLAGS = $(GST_LIBS) $(GST_CONTROLLER_LIBS)
+
+noinst_HEADERS =
+
diff --git a/tests/examples/shapewipe/shapewipe-example.c b/tests/examples/shapewipe/shapewipe-example.c
new file mode 100644
index 00000000..1179aab3
--- /dev/null
+++ b/tests/examples/shapewipe/shapewipe-example.c
@@ -0,0 +1,128 @@
+/* GStreamer
+ * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gst/gst.h>
+#include <gst/controller/gstcontroller.h>
+#include <gst/controller/gstlfocontrolsource.h>
+
+static gboolean
+on_message (GstBus * bus, GstMessage * message, gpointer user_data)
+{
+ GMainLoop *loop = (GMainLoop *) user_data;
+
+ switch (GST_MESSAGE_TYPE (message)) {
+ case GST_MESSAGE_ERROR:
+ g_warning ("Got ERROR");
+ g_main_loop_quit (loop);
+ break;
+ case GST_MESSAGE_WARNING:
+ g_warning ("Got WARNING");
+ g_main_loop_quit (loop);
+ break;
+ case GST_MESSAGE_EOS:
+ g_main_loop_quit (loop);
+ break;
+ default:
+ break;
+ }
+
+ return TRUE;
+}
+
+gint
+main (gint argc, gchar ** argv)
+{
+ GstElement *pipeline;
+ GstElement *shapewipe;
+ GstController *ctrl;
+ GstLFOControlSource *csource;
+ GValue val = { 0, };
+ GMainLoop *loop;
+ GstBus *bus;
+ gchar *pipeline_string;
+
+ if (argc != 2) {
+ g_print ("Usage: shapewipe mask.png\n");
+ return -1;
+ }
+
+ gst_init (&argc, &argv);
+ gst_controller_init (&argc, &argv);
+
+ pipeline_string =
+ g_strdup_printf
+ ("videotestsrc ! video/x-raw-yuv,width=640,height=480 ! shapewipe name=shape border=0.05 ! videomixer name=mixer ! ffmpegcolorspace ! autovideosink filesrc location=%s ! typefind ! decodebin2 ! ffmpegcolorspace ! videoscale ! queue ! shape.mask_sink videotestsrc pattern=snow ! video/x-raw-yuv,width=640,height=480 ! queue ! mixer.",
+ argv[1]);
+
+ pipeline = gst_parse_launch (pipeline_string, NULL);
+ g_free (pipeline_string);
+
+ if (pipeline == NULL) {
+ g_print ("Failed to create pipeline\n");
+ return -2;
+ }
+
+ shapewipe = gst_bin_get_by_name (GST_BIN (pipeline), "shape");
+
+ if (!(ctrl = gst_controller_new (G_OBJECT (shapewipe), "position", NULL))) {
+ g_print ("can't control shapewipe element\n");
+ return -3;
+ }
+
+ csource = gst_lfo_control_source_new ();
+
+ gst_controller_set_control_source (ctrl, "position",
+ GST_CONTROL_SOURCE (csource));
+
+ g_value_init (&val, G_TYPE_FLOAT);
+ g_value_set_float (&val, 0.5);
+ g_object_set (G_OBJECT (csource), "amplitude", &val, NULL);
+ g_value_set_float (&val, 0.5);
+ g_object_set (G_OBJECT (csource), "offset", &val, NULL);
+ g_value_unset (&val);
+
+ g_object_set (G_OBJECT (csource), "frequency", 0.5, NULL);
+ g_object_set (G_OBJECT (csource), "timeshift", 500 * GST_MSECOND, NULL);
+
+ g_object_unref (csource);
+
+ loop = g_main_loop_new (NULL, FALSE);
+
+ bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
+ gst_bus_add_signal_watch (bus);
+ g_signal_connect (G_OBJECT (bus), "message", G_CALLBACK (on_message), loop);
+ gst_object_unref (GST_OBJECT (bus));
+
+ if (gst_element_set_state (pipeline,
+ GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
+ g_error ("Failed to go into PLAYING state");
+ return -4;
+ }
+
+ g_main_loop_run (loop);
+
+ gst_element_set_state (pipeline, GST_STATE_NULL);
+
+ g_main_loop_unref (loop);
+
+ g_object_unref (G_OBJECT (ctrl));
+ gst_object_unref (G_OBJECT (pipeline));
+
+ return 0;
+}