diff options
author | Dave Robillard <dave@drobilla.net> | 2009-05-31 19:26:30 -0400 |
---|---|---|
committer | Dave Robillard <dave@drobilla.net> | 2009-05-31 19:26:30 -0400 |
commit | af14cf34e69e46bfd6544a420b3fdd7e131aa69a (patch) | |
tree | 2bd39ab6ab67995d6e4c69a3e6c6eae2a17f350e /gst | |
parent | bd9a3cbd254714bf71cd87c31d4e5b77f6a96cba (diff) | |
parent | b19dd5920605c0036dacf19591a6feca7a736a50 (diff) | |
download | gst-plugins-bad-af14cf34e69e46bfd6544a420b3fdd7e131aa69a.tar.gz gst-plugins-bad-af14cf34e69e46bfd6544a420b3fdd7e131aa69a.tar.bz2 gst-plugins-bad-af14cf34e69e46bfd6544a420b3fdd7e131aa69a.zip |
Merge branch 'fdo' into lv2
Diffstat (limited to 'gst')
-rw-r--r-- | gst/aacparse/gstbaseparse.c | 2 | ||||
-rw-r--r-- | gst/amrparse/gstamrparse.c | 10 | ||||
-rw-r--r-- | gst/amrparse/gstamrparse.h | 1 | ||||
-rw-r--r-- | gst/amrparse/gstbaseparse.c | 2 | ||||
-rw-r--r-- | gst/dvdspu/gstspu-pgs.c | 22 | ||||
-rw-r--r-- | gst/dvdspu/gstspu-vobsub-render.c | 6 | ||||
-rw-r--r-- | gst/hdvparse/Makefile.am | 13 | ||||
-rw-r--r-- | gst/hdvparse/gsthdvparse.c | 362 | ||||
-rw-r--r-- | gst/hdvparse/gsthdvparse.h | 56 | ||||
-rw-r--r-- | gst/mpegdemux/gstmpegtsdemux.c | 44 | ||||
-rw-r--r-- | gst/qtmux/fourcc.h | 1 | ||||
-rw-r--r-- | gst/qtmux/gstqtmux.c | 5 | ||||
-rw-r--r-- | gst/rawparse/gstaudioparse.c | 73 | ||||
-rw-r--r-- | gst/rtpmanager/gstrtpbin.c | 4 | ||||
-rw-r--r-- | gst/rtpmanager/rtpsource.c | 4 | ||||
-rw-r--r-- | gst/sdp/gstsdpdemux.c | 3 | ||||
-rw-r--r-- | gst/selector/gstoutputselector.c | 45 | ||||
-rw-r--r-- | gst/shapewipe/Makefile.am | 11 | ||||
-rw-r--r-- | gst/shapewipe/gstshapewipe.c | 847 | ||||
-rw-r--r-- | gst/shapewipe/gstshapewipe.h | 74 |
20 files changed, 1536 insertions, 49 deletions
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__ */ |