diff --git a/configure.ac b/configure.ac index 0d31edfa93..943b2a9fe3 100644 --- a/configure.ac +++ b/configure.ac @@ -314,7 +314,7 @@ dnl Make sure you have a space before and after all plugins GST_PLUGINS_NONPORTED="deinterlace interleave flx \ smpte \ videobox \ - cairo cairo_gobject dv1394 \ + cairo cairo_gobject dv1394 gdk_pixbuf \ oss oss4 \ osx_video osx_audio " AC_SUBST(GST_PLUGINS_NONPORTED) @@ -386,18 +386,14 @@ AG_GST_CHECK_FEATURE(DIRECTSOUND, [DirectSound plug-in], directsoundsink, [ LDFLAGS="$LDFLAGS $DIRECTSOUND_LDFLAGS" LIBS="$LIBS -ldsound -ldxerr9 -luser32" AC_MSG_CHECKING(for DirectSound LDFLAGS) - AC_LINK_IFELSE([ + AC_LINK_IFELSE([AC_LANG_PROGRAM([[ #include #include #include - -int main () -{ +]], [[ DXGetErrorString9 (0); DirectSoundCreate(NULL, NULL, NULL); - - return 0; -} +]]) ], [HAVE_DIRECTSOUND="yes"], [HAVE_DIRECTSOUND="no"]) diff --git a/docs/plugins/gst-plugins-good-plugins.args b/docs/plugins/gst-plugins-good-plugins.args index b9afcdf967..b4ce2676ce 100644 --- a/docs/plugins/gst-plugins-good-plugins.args +++ b/docs/plugins/gst-plugins-good-plugins.args @@ -868,6 +868,16 @@ FALSE + +GstRTSPSrc::do-rtsp-keep-alive +gboolean + +rw +Do RTSP Keep Alive +Send RTSP keep alive packets, disable for old incompatible server. +TRUE + + GstRTPDec::skip gint @@ -1925,7 +1935,7 @@ rwx Seekpoints Add SEEKTABLE metadata (if > 0, number of entries, if < 0, interval in sec). -0 +-10 @@ -21525,7 +21535,7 @@ rw Transport mode Jack transport behaviour of the client. -No transport support + @@ -21575,7 +21585,7 @@ rw Transport mode Jack transport behaviour of the client. -No transport support + @@ -22578,3 +22588,73 @@ FALSE + +GstGdkPixbufOverlay::location +gchar* + +rw +location +Location of image file to overlay. +NULL + + + +GstGdkPixbufOverlay::offset-x +gint + +rw +X Offset +Horizontal offset of overlay image in pixels from top-left corner of video image. +0 + + + +GstGdkPixbufOverlay::offset-y +gint + +rw +Y Offset +Vertical offset of overlay image in pixels from top-left corner of video image. +0 + + + +GstGdkPixbufOverlay::overlay-height +gint +>= 0 +rw +Overlay Height +Height of overlay image in pixels (0 = same as overlay image). +0 + + + +GstGdkPixbufOverlay::overlay-width +gint +>= 0 +rw +Overlay Width +Width of overlay image in pixels (0 = same as overlay image). +0 + + + +GstGdkPixbufOverlay::relative-x +gdouble +[0,1] +rw +Relative X Offset +Horizontal offset of overlay image in fractions of video image width, from top-left corner of video image. +0 + + + +GstGdkPixbufOverlay::relative-y +gdouble +[0,1] +rw +Relative Y Offset +Vertical offset of overlay image in fractions of video image height, from top-left corner of video image. +0 + + diff --git a/docs/plugins/inspect/plugin-audioparsers.xml b/docs/plugins/inspect/plugin-audioparsers.xml index c58dc604f8..c26f2eb006 100644 --- a/docs/plugins/inspect/plugin-audioparsers.xml +++ b/docs/plugins/inspect/plugin-audioparsers.xml @@ -135,5 +135,26 @@ + + wavpackparse2 + Wavpack audio stream parser + Codec/Parser/Audio + Wavpack parser + Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk> + + + sink + sink + always +
audio/x-wavpack
+
+ + src + source + always +
audio/x-wavpack, width=(int)[ 1, 32 ], channels=(int)[ 1, 8 ], rate=(int)[ 6000, 192000 ], framed=(boolean)true; audio/x-wavpack-correction, framed=(boolean)true
+
+
+
\ No newline at end of file diff --git a/docs/plugins/inspect/plugin-avi.xml b/docs/plugins/inspect/plugin-avi.xml index 5b6cbe5ca5..fdae4f6abb 100644 --- a/docs/plugins/inspect/plugin-avi.xml +++ b/docs/plugins/inspect/plugin-avi.xml @@ -91,4 +91,4 @@ - \ No newline at end of file + diff --git a/docs/plugins/inspect/plugin-gdkpixbuf.xml b/docs/plugins/inspect/plugin-gdkpixbuf.xml index 8b27462bf3..72211c3320 100644 --- a/docs/plugins/inspect/plugin-gdkpixbuf.xml +++ b/docs/plugins/inspect/plugin-gdkpixbuf.xml @@ -30,6 +30,27 @@ + + gdkpixbufoverlay + GdkPixbuf Overlay + Filter/Effect/Video + Overlay an image onto a video stream + Tim-Philipp Müller <tim centricular net> + + + sink + sink + always +
video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-yuv, format=(fourcc){ I420, YV12, AYUV, YUY2, UYVY, v308, v210, v216, Y41B, Y42B, Y444, Y800, Y16 , NV12, NV21, UYVP, A420, YUV9, IYU1 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]
+
+ + src + source + always +
video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)24, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)24, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)-16777216, green_mask=(int)16711680, blue_mask=(int)65280, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, alpha_mask=(int)255, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)16711680, green_mask=(int)65280, blue_mask=(int)255, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-rgb, bpp=(int)32, depth=(int)32, endianness=(int)4321, red_mask=(int)255, green_mask=(int)65280, blue_mask=(int)16711680, alpha_mask=(int)-16777216, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw-yuv, format=(fourcc){ I420, YV12, AYUV, YUY2, UYVY, v308, v210, v216, Y41B, Y42B, Y444, Y800, Y16 , NV12, NV21, UYVP, A420, YUV9, IYU1 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]
+
+
+
gdkpixbufscale GdkPixbuf image scaler diff --git a/docs/plugins/inspect/plugin-png.xml b/docs/plugins/inspect/plugin-png.xml index 7cc2823d92..9561c4fed8 100644 --- a/docs/plugins/inspect/plugin-png.xml +++ b/docs/plugins/inspect/plugin-png.xml @@ -52,4 +52,4 @@ - \ No newline at end of file + diff --git a/docs/plugins/inspect/plugin-wavpack.xml b/docs/plugins/inspect/plugin-wavpack.xml index d5b7cbddb6..88ba0687c1 100644 --- a/docs/plugins/inspect/plugin-wavpack.xml +++ b/docs/plugins/inspect/plugin-wavpack.xml @@ -26,7 +26,7 @@ src source always -
audio/x-raw-int, width=(int)32, depth=(int)[ 1, 32 ], channels=(int)[ 1, 8 ], rate=(int)[ 6000, 192000 ], endianness=(int)1234, signed=(boolean)true
+
audio/x-raw-int, width=(int)8, depth=(int)8, channels=(int)[ 1, 8 ], rate=(int)[ 6000, 192000 ], endianness=(int)1234, signed=(boolean)true; audio/x-raw-int, width=(int)16, depth=(int)16, channels=(int)[ 1, 8 ], rate=(int)[ 6000, 192000 ], endianness=(int)1234, signed=(boolean)true; audio/x-raw-int, width=(int)32, depth=(int)32, channels=(int)[ 1, 8 ], rate=(int)[ 6000, 192000 ], endianness=(int)1234, signed=(boolean)true
@@ -41,13 +41,13 @@ sink sink always -
audio/x-raw-int, width=(int)32, depth=(int)[ 1, 32 ], endianness=(int)1234, channels=(int)[ 1, 8 ], rate=(int)[ 6000, 192000 ], signed=(boolean)true
+
audio/x-raw-int, width=(int)32, depth=(int){ 24, 32 }, endianness=(int)1234, channels=(int)[ 1, 8 ], rate=(int)[ 6000, 192000 ], signed=(boolean)true
src source always -
audio/x-wavpack, width=(int)[ 1, 32 ], channels=(int)[ 1, 2 ], rate=(int)[ 6000, 192000 ], framed=(boolean)true
+
audio/x-wavpack, width=(int)[ 1, 32 ], channels=(int)[ 1, 8 ], rate=(int)[ 6000, 192000 ], framed=(boolean)true
wvcsrc diff --git a/ext/flac/gstflacdec.c b/ext/flac/gstflacdec.c index f553f64e1a..37f697dd49 100644 --- a/ext/flac/gstflacdec.c +++ b/ext/flac/gstflacdec.c @@ -415,6 +415,26 @@ gst_flac_dec_scan_got_frame (GstFlacDec * flacdec, guint8 * data, guint size, return TRUE; } +static gboolean +gst_flac_dec_handle_decoder_error (GstFlacDec * dec, gboolean msg) +{ + gboolean ret; + + dec->error_count++; + if (dec->error_count > 10) { + if (msg) + GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), (NULL)); + dec->last_flow = GST_FLOW_ERROR; + ret = TRUE; + } else { + GST_DEBUG_OBJECT (dec, "ignoring error for now at count %d", + dec->error_count); + ret = FALSE; + } + + return ret; +} + static void gst_flac_dec_metadata_cb (const FLAC__StreamDecoder * decoder, const FLAC__StreamMetadata * metadata, void *client_data) @@ -495,8 +515,8 @@ gst_flac_dec_error_cb (const FLAC__StreamDecoder * d, break; } - GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("%s (%d)", error, status)); - dec->last_flow = GST_FLOW_ERROR; + if (gst_flac_dec_handle_decoder_error (dec, FALSE)) + GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("%s (%d)", error, status)); } static FLAC__StreamDecoderReadStatus @@ -674,6 +694,8 @@ gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame, gst_buffer_unmap (outbuf, &map); GST_DEBUG_OBJECT (flacdec, "pushing %d samples", samples); + if (flacdec->error_count) + flacdec->error_count--; ret = gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (flacdec), outbuf, 1); diff --git a/ext/flac/gstflacdec.h b/ext/flac/gstflacdec.h index 2386a122fc..12447f8e67 100644 --- a/ext/flac/gstflacdec.h +++ b/ext/flac/gstflacdec.h @@ -58,6 +58,8 @@ struct _GstFlacDec { /* from the stream info, needed for scanning */ guint16 min_blocksize; guint16 max_blocksize; + + gint error_count; }; struct _GstFlacDecClass { diff --git a/ext/flac/gstflacenc.c b/ext/flac/gstflacenc.c index 9c7a3eec9d..f39b98fc94 100644 --- a/ext/flac/gstflacenc.c +++ b/ext/flac/gstflacenc.c @@ -203,7 +203,7 @@ static const GstFlacEncParams flacenc_params[] = { #define DEFAULT_QUALITY 5 #define DEFAULT_PADDING 0 -#define DEFAULT_SEEKPOINTS 0 +#define DEFAULT_SEEKPOINTS -10 #define GST_TYPE_FLAC_ENC_QUALITY (gst_flac_enc_quality_get_type ()) static GType diff --git a/ext/gdk_pixbuf/Makefile.am b/ext/gdk_pixbuf/Makefile.am index cf5265c2e8..32a82effe1 100644 --- a/ext/gdk_pixbuf/Makefile.am +++ b/ext/gdk_pixbuf/Makefile.am @@ -1,12 +1,15 @@ plugin_LTLIBRARIES = libgstgdkpixbuf.la -libgstgdkpixbuf_la_SOURCES = gstgdkpixbuf.c gstgdkpixbufsink.c pixbufscale.c +libgstgdkpixbuf_la_SOURCES = gstgdkpixbuf.c gstgdkpixbufsink.c pixbufscale.c \ + gstgdkpixbufoverlay.c libgstgdkpixbuf_la_CFLAGS = \ $(GST_PLUGINS_BASE_CFLAGS) \ + $(GST_CONTROLLER_CFLAGS) \ $(GST_BASE_CFLAGS) \ $(GST_CFLAGS) $(GDK_PIXBUF_CFLAGS) libgstgdkpixbuf_la_LIBADD = \ $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_MAJORMINOR) \ + $(GST_CONTROLLER_LIBS) \ $(GST_BASE_LIBS) \ $(GST_LIBS) $(GDK_PIXBUF_LIBS) libgstgdkpixbuf_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) @@ -14,6 +17,7 @@ libgstgdkpixbuf_la_LIBTOOLFLAGS = --tag=disable-static noinst_HEADERS = \ gstgdkpixbuf.h \ + gstgdkpixbufoverlay.h \ gstgdkpixbufsink.h \ pixbufscale.h \ gstgdkanimation.h diff --git a/ext/gdk_pixbuf/gstgdkpixbuf.c b/ext/gdk_pixbuf/gstgdkpixbuf.c index 588e1656c9..1f51a24dc4 100644 --- a/ext/gdk_pixbuf/gstgdkpixbuf.c +++ b/ext/gdk_pixbuf/gstgdkpixbuf.c @@ -27,6 +27,7 @@ #include #include "gstgdkpixbuf.h" +#include "gstgdkpixbufoverlay.h" #include "gstgdkpixbufsink.h" #include "pixbufscale.h" @@ -589,6 +590,10 @@ plugin_init (GstPlugin * plugin) gst_gdk_pixbuf_type_find, NULL, GST_CAPS_ANY, NULL); #endif + if (!gst_element_register (plugin, "gdkpixbufoverlay", GST_RANK_NONE, + GST_TYPE_GDK_PIXBUF_OVERLAY)) + return FALSE; + if (!gst_element_register (plugin, "gdkpixbufsink", GST_RANK_NONE, GST_TYPE_GDK_PIXBUF_SINK)) return FALSE; diff --git a/ext/gdk_pixbuf/gstgdkpixbufoverlay.c b/ext/gdk_pixbuf/gstgdkpixbufoverlay.c new file mode 100644 index 0000000000..6ea95c7b6a --- /dev/null +++ b/ext/gdk_pixbuf/gstgdkpixbufoverlay.c @@ -0,0 +1,508 @@ +/* GStreamer GdkPixbuf overlay + * Copyright (C) 2012 Tim-Philipp Müller + * + * 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., 51 Franklin Street, Suite 500, + * Boston, MA 02110-1335, USA. + */ + +/** + * SECTION:element-gdkpixbufoverlay + * @see_also: + * + * The gdkpixbufoverlay element overlays an image loaded from file onto + * a video stream. + * + * Changing the positioning or overlay width and height properties at runtime + * is supported, but it might be prudent to to protect the property setting + * code with GST_BASE_TRANSFORM_LOCK and GST_BASE_TRANSFORM_UNLOCK, as + * g_object_set() is not atomic for multiple properties passed in one go. + * + * Changing the image at runtime is currently not supported. + * + * Negative offsets are also not yet supported. + * + * + * Example launch line + * |[ + * gst-launch -v videotestsrc ! gdkpixbufoverlay location=image.png ! autovideosink + * ]| + * Overlays the image in image.png onto the test video picture produced by + * videotestsrc. + * + * + * Since: 0.10.33 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "gstgdkpixbufoverlay.h" + +GST_DEBUG_CATEGORY_STATIC (gdkpixbufoverlay_debug); +#define GST_CAT_DEFAULT gdkpixbufoverlay_debug + +static void gst_gdk_pixbuf_overlay_set_property (GObject * object, + guint property_id, const GValue * value, GParamSpec * pspec); +static void gst_gdk_pixbuf_overlay_get_property (GObject * object, + guint property_id, GValue * value, GParamSpec * pspec); +static void gst_gdk_pixbuf_overlay_finalize (GObject * object); + +static gboolean gst_gdk_pixbuf_overlay_start (GstBaseTransform * trans); +static gboolean gst_gdk_pixbuf_overlay_stop (GstBaseTransform * trans); +static GstFlowReturn +gst_gdk_pixbuf_overlay_transform_ip (GstBaseTransform * trans, GstBuffer * buf); +static void gst_gdk_pixbuf_overlay_before_transform (GstBaseTransform * trans, + GstBuffer * outbuf); +static gboolean +gst_gdk_pixbuf_overlay_set_caps (GstBaseTransform * trans, GstCaps * incaps, + GstCaps * outcaps); + +enum +{ + PROP_0, + PROP_LOCATION, + PROP_OFFSET_X, + PROP_OFFSET_Y, + PROP_RELATIVE_X, + PROP_RELATIVE_Y, + PROP_OVERLAY_WIDTH, + PROP_OVERLAY_HEIGHT +}; + +#define VIDEO_CAPS \ + GST_VIDEO_CAPS_BGRx ";" \ + GST_VIDEO_CAPS_RGB ";" \ + GST_VIDEO_CAPS_BGR ";" \ + GST_VIDEO_CAPS_RGBx ";" \ + GST_VIDEO_CAPS_xRGB ";" \ + GST_VIDEO_CAPS_xBGR ";" \ + GST_VIDEO_CAPS_RGBA ";" \ + GST_VIDEO_CAPS_BGRA ";" \ + GST_VIDEO_CAPS_ARGB ";" \ + GST_VIDEO_CAPS_ABGR ";" \ + GST_VIDEO_CAPS_YUV ("{I420, YV12, AYUV, YUY2, UYVY, v308, v210," \ + " v216, Y41B, Y42B, Y444, Y800, Y16, NV12, NV21, UYVP, A420," \ + " YUV9, IYU1}") + +static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (VIDEO_CAPS) + ); + +static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (VIDEO_CAPS) + ); + +GST_BOILERPLATE (GstGdkPixbufOverlay, gst_gdk_pixbuf_overlay, + GstVideoFilter, GST_TYPE_VIDEO_FILTER); + +static void +gst_gdk_pixbuf_overlay_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_add_static_pad_template (element_class, &sink_template); + gst_element_class_add_static_pad_template (element_class, &src_template); + + gst_element_class_set_details_simple (element_class, + "GdkPixbuf Overlay", "Filter/Effect/Video", + "Overlay an image onto a video stream", + "Tim-Philipp Müller "); +} + +static void +gst_gdk_pixbuf_overlay_class_init (GstGdkPixbufOverlayClass * klass) +{ + GstBaseTransformClass *basetrans_class = GST_BASE_TRANSFORM_CLASS (klass); + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->set_property = gst_gdk_pixbuf_overlay_set_property; + gobject_class->get_property = gst_gdk_pixbuf_overlay_get_property; + gobject_class->finalize = gst_gdk_pixbuf_overlay_finalize; + + basetrans_class->start = GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_overlay_start); + basetrans_class->stop = GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_overlay_stop); + basetrans_class->set_caps = + GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_overlay_set_caps); + basetrans_class->transform_ip = + GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_overlay_transform_ip); + basetrans_class->before_transform = + GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_overlay_before_transform); + + g_object_class_install_property (gobject_class, PROP_LOCATION, + g_param_spec_string ("location", "location", + "Location of image file to overlay", NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_OFFSET_X, + g_param_spec_int ("offset-x", "X Offset", + "Horizontal offset of overlay image in pixels from top-left corner " + "of video image", G_MININT, G_MAXINT, 0, + GST_PARAM_CONTROLLABLE | GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE + | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_OFFSET_Y, + g_param_spec_int ("offset-y", "Y Offset", + "Vertical offset of overlay image in pixels from top-left corner " + "of video image", G_MININT, G_MAXINT, 0, + GST_PARAM_CONTROLLABLE | GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE + | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_RELATIVE_X, + g_param_spec_double ("relative-x", "Relative X Offset", + "Horizontal offset of overlay image in fractions of video image " + "width, from top-left corner of video image", 0.0, 1.0, 0.0, + GST_PARAM_CONTROLLABLE | GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE + | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_RELATIVE_Y, + g_param_spec_double ("relative-y", "Relative Y Offset", + "Vertical offset of overlay image in fractions of video image " + "height, from top-left corner of video image", 0.0, 1.0, 0.0, + GST_PARAM_CONTROLLABLE | GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE + | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_OVERLAY_WIDTH, + g_param_spec_int ("overlay-width", "Overlay Width", + "Width of overlay image in pixels (0 = same as overlay image)", 0, + G_MAXINT, 0, + GST_PARAM_CONTROLLABLE | GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE + | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_OVERLAY_HEIGHT, + g_param_spec_int ("overlay-height", "Overlay Height", + "Height of overlay image in pixels (0 = same as overlay image)", 0, + G_MAXINT, 0, + GST_PARAM_CONTROLLABLE | GST_PARAM_MUTABLE_PLAYING | G_PARAM_READWRITE + | G_PARAM_STATIC_STRINGS)); + + GST_DEBUG_CATEGORY_INIT (gdkpixbufoverlay_debug, "gdkpixbufoverlay", 0, + "debug category for gdkpixbufoverlay element"); +} + +static void +gst_gdk_pixbuf_overlay_init (GstGdkPixbufOverlay * overlay, + GstGdkPixbufOverlayClass * overlay_class) +{ + overlay->offset_x = 0; + overlay->offset_y = 0; + + overlay->relative_x = 0.0; + overlay->relative_y = 0.0; + + overlay->overlay_width = 0; + overlay->overlay_height = 0; +} + +void +gst_gdk_pixbuf_overlay_set_property (GObject * object, guint property_id, + const GValue * value, GParamSpec * pspec) +{ + GstGdkPixbufOverlay *overlay = GST_GDK_PIXBUF_OVERLAY (object); + + GST_OBJECT_LOCK (overlay); + + switch (property_id) { + case PROP_LOCATION: + g_free (overlay->location); + overlay->location = g_value_dup_string (value); + break; + case PROP_OFFSET_X: + overlay->offset_x = g_value_get_int (value); + overlay->update_composition = TRUE; + break; + case PROP_OFFSET_Y: + overlay->offset_y = g_value_get_int (value); + overlay->update_composition = TRUE; + break; + case PROP_RELATIVE_X: + overlay->relative_x = g_value_get_double (value); + overlay->update_composition = TRUE; + break; + case PROP_RELATIVE_Y: + overlay->relative_y = g_value_get_double (value); + overlay->update_composition = TRUE; + break; + case PROP_OVERLAY_WIDTH: + overlay->overlay_width = g_value_get_int (value); + overlay->update_composition = TRUE; + break; + case PROP_OVERLAY_HEIGHT: + overlay->overlay_height = g_value_get_int (value); + overlay->update_composition = TRUE; + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } + + GST_OBJECT_UNLOCK (overlay); +} + +void +gst_gdk_pixbuf_overlay_get_property (GObject * object, guint property_id, + GValue * value, GParamSpec * pspec) +{ + GstGdkPixbufOverlay *overlay = GST_GDK_PIXBUF_OVERLAY (object); + + GST_OBJECT_LOCK (overlay); + + switch (property_id) { + case PROP_LOCATION: + g_value_set_string (value, overlay->location); + break; + case PROP_OFFSET_X: + g_value_set_int (value, overlay->offset_x); + break; + case PROP_OFFSET_Y: + g_value_set_int (value, overlay->offset_y); + break; + case PROP_RELATIVE_X: + g_value_set_double (value, overlay->relative_x); + break; + case PROP_RELATIVE_Y: + g_value_set_double (value, overlay->relative_y); + break; + case PROP_OVERLAY_WIDTH: + g_value_set_int (value, overlay->overlay_width); + break; + case PROP_OVERLAY_HEIGHT: + g_value_set_int (value, overlay->overlay_height); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } + + GST_OBJECT_UNLOCK (overlay); +} + +void +gst_gdk_pixbuf_overlay_finalize (GObject * object) +{ + GstGdkPixbufOverlay *overlay = GST_GDK_PIXBUF_OVERLAY (object); + + g_free (overlay->location); + overlay->location = NULL; + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static gboolean +gst_gdk_pixbuf_overlay_load_image (GstGdkPixbufOverlay * overlay, GError ** err) +{ + GdkPixbuf *pixbuf; + guint8 *pixels, *p; + gint width, height, stride, w, h; + + pixbuf = gdk_pixbuf_new_from_file (overlay->location, err); + + if (pixbuf == NULL) + return FALSE; + + if (!gdk_pixbuf_get_has_alpha (pixbuf)) { + GdkPixbuf *alpha_pixbuf; + + /* FIXME: we could do this much more efficiently ourselves below, but + * we're lazy for now */ + /* FIXME: perhaps expose substitute_color via properties */ + alpha_pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0); + g_object_unref (pixbuf); + pixbuf = alpha_pixbuf; + } + + width = gdk_pixbuf_get_width (pixbuf); + height = gdk_pixbuf_get_height (pixbuf); + stride = gdk_pixbuf_get_rowstride (pixbuf); + pixels = gdk_pixbuf_get_pixels (pixbuf); + + /* the memory layout in GdkPixbuf is R-G-B-A, we want: + * - B-G-R-A on little-endian platforms + * - A-R-G-B on big-endian platforms + */ + for (h = 0; h < height; ++h) { + p = pixels + (h * stride); + for (w = 0; w < width; ++w) { + guint8 tmp; + + /* R-G-B-A ==> B-G-R-A */ + tmp = p[0]; + p[0] = p[2]; + p[2] = tmp; + + if (G_BYTE_ORDER == G_BIG_ENDIAN) { + /* B-G-R-A ==> A-R-G-B */ + /* we can probably assume sane alignment */ + *((guint32 *) p) = GUINT32_SWAP_LE_BE (*((guint32 *) p)); + } + + p += 4; + } + } + + overlay->pixels = gst_buffer_new (); + GST_BUFFER_DATA (overlay->pixels) = pixels; + /* assume we have row padding even for the last row */ + GST_BUFFER_SIZE (overlay->pixels) = height * stride; + /* transfer ownership of pixbuf to buffer */ + GST_BUFFER_MALLOCDATA (overlay->pixels) = (guint8 *) pixbuf; + GST_BUFFER_FREE_FUNC (overlay->pixels) = (GFreeFunc) g_object_unref; + + overlay->pixels_width = width; + overlay->pixels_height = height; + overlay->pixels_stride = stride; + + overlay->update_composition = TRUE; + + GST_INFO_OBJECT (overlay, "Loaded image, %d x %d", width, height); + return TRUE; +} + +static gboolean +gst_gdk_pixbuf_overlay_start (GstBaseTransform * trans) +{ + GstGdkPixbufOverlay *overlay = GST_GDK_PIXBUF_OVERLAY (trans); + GError *err = NULL; + + if (overlay->location != NULL) { + if (!gst_gdk_pixbuf_overlay_load_image (overlay, &err)) + goto error_loading_image; + + gst_base_transform_set_passthrough (trans, FALSE); + } else { + GST_WARNING_OBJECT (overlay, "no image location set, doing nothing"); + gst_base_transform_set_passthrough (trans, TRUE); + } + + return TRUE; + +/* ERRORS */ +error_loading_image: + { + GST_ELEMENT_ERROR (overlay, RESOURCE, OPEN_READ, + ("Could not load overlay image."), ("%s", err->message)); + g_error_free (err); + return FALSE; + } +} + +static gboolean +gst_gdk_pixbuf_overlay_stop (GstBaseTransform * trans) +{ + GstGdkPixbufOverlay *overlay = GST_GDK_PIXBUF_OVERLAY (trans); + + if (overlay->comp) { + gst_video_overlay_composition_unref (overlay->comp); + overlay->comp = NULL; + } + + gst_buffer_replace (&overlay->pixels, NULL); + + return TRUE; +} + +static gboolean +gst_gdk_pixbuf_overlay_set_caps (GstBaseTransform * trans, GstCaps * incaps, + GstCaps * outcaps) +{ + GstGdkPixbufOverlay *overlay = GST_GDK_PIXBUF_OVERLAY (trans); + GstVideoFormat video_format; + int w, h; + + if (!gst_video_format_parse_caps (incaps, &video_format, &w, &h)) + return FALSE; + + overlay->format = video_format; + overlay->width = w; + overlay->height = h; + return TRUE; +} + +static void +gst_gdk_pixbuf_overlay_update_composition (GstGdkPixbufOverlay * overlay) +{ + GstVideoOverlayComposition *comp; + GstVideoOverlayRectangle *rect; + gint x, y, width, height; + + x = overlay->offset_x + (overlay->relative_x * overlay->pixels_width); + y = overlay->offset_y + (overlay->relative_y * overlay->pixels_height); + + /* FIXME: this should work, but seems to crash */ + if (x < 0) + x = 0; + if (y < 0) + y = 0; + + width = overlay->overlay_width; + if (width == 0) + width = overlay->pixels_width; + + height = overlay->overlay_height; + if (height == 0) + height = overlay->pixels_height; + + GST_DEBUG_OBJECT (overlay, "overlay image dimensions: %d x %d", + overlay->pixels_width, overlay->pixels_height); + GST_DEBUG_OBJECT (overlay, "properties: x,y: %d,%d (%g%%,%g%%) - WxH: %dx%d", + overlay->offset_x, overlay->offset_y, + overlay->relative_x * 100.0, overlay->relative_y * 100.0, + overlay->overlay_height, overlay->overlay_width); + GST_DEBUG_OBJECT (overlay, "overlay rendered: %d x %d @ %d,%d (onto %d x %d)", + width, height, x, y, overlay->width, overlay->height); + + rect = gst_video_overlay_rectangle_new_argb (overlay->pixels, + overlay->pixels_width, overlay->pixels_height, overlay->pixels_stride, + x, y, width, height, GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE); + + comp = gst_video_overlay_composition_new (rect); + gst_video_overlay_rectangle_unref (rect); + + if (overlay->comp) + gst_video_overlay_composition_unref (overlay->comp); + overlay->comp = comp; +} + +static void +gst_gdk_pixbuf_overlay_before_transform (GstBaseTransform * trans, + GstBuffer * outbuf) +{ + GstClockTime stream_time; + + stream_time = gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME, + GST_BUFFER_TIMESTAMP (outbuf)); + + if (GST_CLOCK_TIME_IS_VALID (stream_time)) + gst_object_sync_values (G_OBJECT (trans), stream_time); +} + +static GstFlowReturn +gst_gdk_pixbuf_overlay_transform_ip (GstBaseTransform * trans, GstBuffer * buf) +{ + GstGdkPixbufOverlay *overlay = GST_GDK_PIXBUF_OVERLAY (trans); + + GST_OBJECT_LOCK (overlay); + + if (G_UNLIKELY (overlay->update_composition)) { + gst_gdk_pixbuf_overlay_update_composition (overlay); + overlay->update_composition = FALSE; + } + + GST_OBJECT_UNLOCK (overlay); + + gst_video_overlay_composition_blend (overlay->comp, buf); + + return GST_FLOW_OK; +} diff --git a/ext/gdk_pixbuf/gstgdkpixbufoverlay.h b/ext/gdk_pixbuf/gstgdkpixbufoverlay.h new file mode 100644 index 0000000000..9c940909f4 --- /dev/null +++ b/ext/gdk_pixbuf/gstgdkpixbufoverlay.h @@ -0,0 +1,87 @@ +/* GStreamer GdkPixbuf overlay + * Copyright (C) 2012 Tim-Philipp Müller + * + * 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_GDK_PIXBUF_OVERLAY_H_ +#define _GST_GDK_PIXBUF_OVERLAY_H_ + +#include +#include +#include + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_GDK_PIXBUF_OVERLAY (gst_gdk_pixbuf_overlay_get_type()) +#define GST_GDK_PIXBUF_OVERLAY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GDK_PIXBUF_OVERLAY,GstGdkPixbufOverlay)) +#define GST_GDK_PIXBUF_OVERLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GDK_PIXBUF_OVERLAY,GstGdkPixbufOverlayClass)) +#define GST_IS_GDK_PIXBUF_OVERLAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GDK_PIXBUF_OVERLAY)) +#define GST_IS_GDK_PIXBUF_OVERLAY_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GDK_PIXBUF_OVERLAY)) + +typedef struct _GstGdkPixbufOverlay GstGdkPixbufOverlay; +typedef struct _GstGdkPixbufOverlayClass GstGdkPixbufOverlayClass; + +/** + * GstGdkPixbufOverlay: + * + * The opaque element instance structure. + */ +struct _GstGdkPixbufOverlay +{ + GstVideoFilter videofilter; + + /* negotiated format */ + GstVideoFormat format; + gint width; + gint height; + + /* properties */ + gchar * location; + + gint offset_x; + gint offset_y; + + gdouble relative_x; + gdouble relative_y; + + gint overlay_width; + gint overlay_height; + + /* the loaded image */ + GstBuffer * pixels; + guint pixels_width; + guint pixels_height; + guint pixels_stride; + + GstVideoOverlayComposition * comp; + + /* render position or dimension has changed */ + gboolean update_composition; +}; + +struct _GstGdkPixbufOverlayClass +{ + GstVideoFilterClass videofilter_class; +}; + +GType gst_gdk_pixbuf_overlay_get_type (void); + +G_END_DECLS + +#endif diff --git a/ext/libpng/gstpngdec.c b/ext/libpng/gstpngdec.c index 0c10b4cd5e..9e0cbe7099 100644 --- a/ext/libpng/gstpngdec.c +++ b/ext/libpng/gstpngdec.c @@ -61,7 +61,8 @@ static GstStaticPadTemplate gst_pngdec_src_pad_template = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ RGBA, RGB }")) + GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE + ("{ RGBA, RGB, ARGB64, GRAY8, GRAY16_BE }")) ); static GstStaticPadTemplate gst_pngdec_sink_pad_template = @@ -406,15 +407,15 @@ gst_pngdec_caps_create_and_set (GstPngDec * pngdec) /* Get bits per channel */ bpc = png_get_bit_depth (pngdec->png, pngdec->info); - if (bpc > 8) { - /* Add alpha channel if 16-bit depth */ - png_set_add_alpha (pngdec->png, 0xffff, PNG_FILLER_BEFORE); - png_set_swap (pngdec->png); - } /* Get Color type */ color_type = png_get_color_type (pngdec->png, pngdec->info); + /* Add alpha channel if 16-bit depth, but not for GRAY images */ + if ((bpc > 8) && (color_type != PNG_COLOR_TYPE_GRAY)) { + png_set_add_alpha (pngdec->png, 0xffff, PNG_FILLER_BEFORE); + png_set_swap (pngdec->png); + } #if 0 /* We used to have this HACK to reverse the outgoing bytes, but the problem * that originally required the hack seems to have been in ffmpegcolorspace's @@ -424,11 +425,16 @@ gst_pngdec_caps_create_and_set (GstPngDec * pngdec) png_set_bgr (pngdec->png); #endif - /* Gray scale converted to RGB and upscaled to 8 bits */ + /* Gray scale with alpha channel converted to RGB */ + if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { + GST_LOG_OBJECT (pngdec, + "converting grayscale png with alpha channel to RGB"); + png_set_gray_to_rgb (pngdec->png); + } + + /* Gray scale converted to upscaled to 8 bits */ if ((color_type == PNG_COLOR_TYPE_GRAY_ALPHA) || (color_type == PNG_COLOR_TYPE_GRAY)) { - GST_LOG_OBJECT (pngdec, "converting grayscale png to RGB"); - png_set_gray_to_rgb (pngdec->png); if (bpc < 8) { /* Convert to 8 bits */ GST_LOG_OBJECT (pngdec, "converting grayscale image to 8 bits"); #if PNG_LIBPNG_VER < 10400 @@ -466,7 +472,18 @@ gst_pngdec_caps_create_and_set (GstPngDec * pngdec) break; case PNG_COLOR_TYPE_RGB_ALPHA: GST_LOG_OBJECT (pngdec, "we have an alpha channel, depth is 32 bits"); - format = GST_VIDEO_FORMAT_RGBA; + if (bpc == 1) + format = GST_VIDEO_FORMAT_RGBA; + else + format = GST_VIDEO_FORMAT_ARGB64; + break; + case PNG_COLOR_TYPE_GRAY: + GST_LOG_OBJECT (pngdec, + "We have an gray image, depth is 8 or 16 (be) bits"); + if (bpc == 1) + format = GST_VIDEO_FORMAT_GRAY8; + else + format = GST_VIDEO_FORMAT_GRAY16_BE; break; default: GST_ELEMENT_ERROR (pngdec, STREAM, NOT_IMPLEMENTED, (NULL), diff --git a/ext/libpng/gstpngenc.c b/ext/libpng/gstpngenc.c index ebdc36902a..963405a81a 100644 --- a/ext/libpng/gstpngenc.c +++ b/ext/libpng/gstpngenc.c @@ -64,7 +64,7 @@ static GstStaticPadTemplate pngenc_sink_template = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ RGBA, RGB, GRAY8 }")) + GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ RGBA, RGB, GRAY8, GRAY16_BE }")) ); /* static GstElementClass *parent_class = NULL; */ @@ -153,12 +153,19 @@ gst_pngenc_setcaps (GstPngEnc * pngenc, GstCaps * caps) switch (GST_VIDEO_INFO_FORMAT (&info)) { case GST_VIDEO_FORMAT_RGBA: pngenc->png_color_type = PNG_COLOR_TYPE_RGBA; + pngenc->depth = 8; break; case GST_VIDEO_FORMAT_RGB: pngenc->png_color_type = PNG_COLOR_TYPE_RGB; + pngenc->depth = 8; break; case GST_VIDEO_FORMAT_GRAY8: pngenc->png_color_type = PNG_COLOR_TYPE_GRAY; + pngenc->depth = 8; + break; + case GST_VIDEO_FORMAT_GRAY16_BE: + pngenc->png_color_type = PNG_COLOR_TYPE_GRAY; + pngenc->depth = 16; break; default: ret = FALSE; @@ -314,7 +321,7 @@ gst_pngenc_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) pngenc->png_info_ptr, pngenc->width, pngenc->height, - 8, + pngenc->depth, pngenc->png_color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); diff --git a/ext/libpng/gstpngenc.h b/ext/libpng/gstpngenc.h index ff5b94e22c..ba306b9d98 100644 --- a/ext/libpng/gstpngenc.h +++ b/ext/libpng/gstpngenc.h @@ -52,6 +52,7 @@ struct _GstPngEnc GstVideoInfo info; gint png_color_type; + gint depth; gint width; gint height; guint compression_level; diff --git a/ext/speex/gstspeexdec.c b/ext/speex/gstspeexdec.c index 6032341cc0..7027d20dd9 100644 --- a/ext/speex/gstspeexdec.c +++ b/ext/speex/gstspeexdec.c @@ -310,8 +310,9 @@ gst_speex_dec_parse_comments (GstSpeexDec * dec, GstBuffer * buf) GST_INFO_OBJECT (dec, "tags: %" GST_PTR_FORMAT, list); - gst_pad_push_event (GST_AUDIO_DECODER_SRC_PAD (dec), - gst_event_new_tag (list)); + gst_audio_decoder_merge_tags (GST_AUDIO_DECODER (dec), list, + GST_TAG_MERGE_REPLACE); + gst_tag_list_free (list); g_free (encoder); g_free (ver); diff --git a/ext/wavpack/gstwavpackstreamreader.c b/ext/wavpack/gstwavpackstreamreader.c index 074a2e7d5d..da1fdc27bc 100644 --- a/ext/wavpack/gstwavpackstreamreader.c +++ b/ext/wavpack/gstwavpackstreamreader.c @@ -78,9 +78,10 @@ gst_wavpack_stream_reader_push_back_byte (void *id, int c) GST_DEBUG ("Pushing back one byte: 0x%x", c); + if (rid->position == 0) + return rid->position; + rid->position -= 1; - if (rid->position < 0) - rid->position = 0; return rid->position; } diff --git a/gst/audioparsers/gstflacparse.c b/gst/audioparsers/gstflacparse.c index f5ad16945c..f50a057635 100644 --- a/gst/audioparsers/gstflacparse.c +++ b/gst/audioparsers/gstflacparse.c @@ -378,7 +378,8 @@ typedef enum static FrameHeaderCheckReturn gst_flac_parse_frame_header_is_valid (GstFlacParse * flacparse, - const guint8 * data, guint size, gboolean set, guint16 * block_size_ret) + const guint8 * data, guint size, gboolean set, guint16 * block_size_ret, + gboolean * suspect) { GstBitReader reader = GST_BIT_READER_INIT (data, size); guint8 blocking_strategy; @@ -572,6 +573,8 @@ gst_flac_parse_frame_header_is_valid (GstFlacParse * flacparse, /* TODO: can we know we're on the last frame, to avoid warning ? */ GST_WARNING_OBJECT (flacparse, "Block size is not constant"); block_size = flacparse->block_size; + if (suspect) + *suspect = TRUE; } } } @@ -620,6 +623,7 @@ gst_flac_parse_frame_is_valid (GstFlacParse * flacparse, guint i, search_start, search_end; FrameHeaderCheckReturn header_ret; guint16 block_size; + gboolean suspect_start = FALSE, suspect_end = FALSE; gboolean result = FALSE; buffer = frame->buffer; @@ -630,7 +634,7 @@ gst_flac_parse_frame_is_valid (GstFlacParse * flacparse, header_ret = gst_flac_parse_frame_header_is_valid (flacparse, map.data, map.size, TRUE, - &block_size); + &block_size, &suspect_start); if (header_ret == FRAME_HEADER_INVALID) { *ret = 0; goto cleanup; @@ -650,16 +654,23 @@ gst_flac_parse_frame_is_valid (GstFlacParse * flacparse, for (i = search_start; i < search_end; i++, remaining--) { if ((GST_READ_UINT16_BE (map.data + i) & 0xfffe) == 0xfff8) { + GST_LOG_OBJECT (flacparse, "possible frame end at offset %d", i); + suspect_end = FALSE; header_ret = gst_flac_parse_frame_header_is_valid (flacparse, map.data + i, - remaining, FALSE, NULL); + remaining, FALSE, NULL, &suspect_end); if (header_ret == FRAME_HEADER_VALID) { if (flacparse->check_frame_checksums) { guint16 actual_crc = gst_flac_calculate_crc16 (map.data, i - 2); guint16 expected_crc = GST_READ_UINT16_BE (map.data + i - 2); - if (actual_crc != expected_crc) + GST_LOG_OBJECT (flacparse, + "checking checksum, frame suspect (%d, %d)", + suspect_start, suspect_end); + if (actual_crc != expected_crc) { + GST_DEBUG_OBJECT (flacparse, "checksum did not match"); continue; + } } *ret = i; flacparse->block_size = block_size; @@ -691,6 +702,15 @@ gst_flac_parse_frame_is_valid (GstFlacParse * flacparse, } } + /* so we searched to expected end and found nothing, + * give up on this frame (start) */ + if (flacparse->max_framesize && i > 2 * flacparse->max_framesize) { + GST_LOG_OBJECT (flacparse, + "could not determine valid frame end, discarding frame (start)"); + *ret = 1; + return FALSE; + } + need_more: max = flacparse->max_framesize + 16; if (max == 16) @@ -1397,7 +1417,7 @@ gst_flac_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame, flacparse->offset = GST_BUFFER_OFFSET (buffer); ret = gst_flac_parse_frame_header_is_valid (flacparse, - map.data, map.size, TRUE, NULL); + map.data, map.size, TRUE, NULL, NULL); if (ret != FRAME_HEADER_VALID) { GST_ERROR_OBJECT (flacparse, "Baseclass didn't provide a complete frame"); diff --git a/gst/deinterlace/gstdeinterlace.c b/gst/deinterlace/gstdeinterlace.c index e5b0878624..e29f38bea2 100644 --- a/gst/deinterlace/gstdeinterlace.c +++ b/gst/deinterlace/gstdeinterlace.c @@ -1984,7 +1984,8 @@ gst_deinterlace_chain (GstPad * pad, GstBuffer * buf) self->fields = self->new_fields; if (self->new_mode != -1) self->mode = self->new_mode; - self->new_mode = self->new_fields = -1; + self->new_mode = -1; + self->new_fields = -1; self->reconfigure = FALSE; GST_OBJECT_UNLOCK (self); diff --git a/gst/deinterlace/tvtime/greedyh.asm b/gst/deinterlace/tvtime/greedyh.asm index d87b9e392d..c710b4a1f2 100644 --- a/gst/deinterlace/tvtime/greedyh.asm +++ b/gst/deinterlace/tvtime/greedyh.asm @@ -43,7 +43,7 @@ FUNCT_NAME_YUY2 (GstDeinterlaceMethodGreedyH *self, const guint8 * L1, const gui gint64 MotionSense; gint64 i; glong LoopCtr; - glong oldbx; + glong oldbx = 0; gint64 QW256B; gint64 LastAvg = 0; //interp value from left qword @@ -262,7 +262,7 @@ FUNCT_NAME_UYVY (GstDeinterlaceMethodGreedyH *self, const guint8 * L1, const gui gint64 MotionSense; gint64 i; glong LoopCtr; - glong oldbx; + glong oldbx = 0; gint64 QW256B; gint64 LastAvg = 0; //interp value from left qword diff --git a/gst/deinterlace/tvtime/tomsmocomp/SearchLoopTop.inc b/gst/deinterlace/tvtime/tomsmocomp/SearchLoopTop.inc index 9d6a490f50..275c7dd982 100644 --- a/gst/deinterlace/tvtime/tomsmocomp/SearchLoopTop.inc +++ b/gst/deinterlace/tvtime/tomsmocomp/SearchLoopTop.inc @@ -92,7 +92,7 @@ long Last8; int64_t Max_Vals = 0x0000000000000000ull; int64_t ShiftMask = 0xfefffefffefffeffull; - long oldbx; + long oldbx = 0; // pretend it's indented -->> __asm__ __volatile__ diff --git a/gst/flv/gstflvmux.c b/gst/flv/gstflvmux.c index 8119e9db33..555e536db6 100644 --- a/gst/flv/gstflvmux.c +++ b/gst/flv/gstflvmux.c @@ -1165,6 +1165,7 @@ gst_flv_mux_write_header (GstFlvMux * mux) "streamable=false. Will ignore that and create streamable output " "instead"); } + gst_query_unref (query); } header = gst_flv_mux_create_header (mux); diff --git a/gst/isomp4/gstqtmux.c b/gst/isomp4/gstqtmux.c index e3064e9f5c..531df78062 100644 --- a/gst/isomp4/gstqtmux.c +++ b/gst/isomp4/gstqtmux.c @@ -1654,6 +1654,7 @@ gst_qt_mux_start_file (GstQTMux * qtmux) "streamable=false. Will ignore that and create streamable output " "instead"); } + gst_query_unref (query); } /* let downstream know we think in BYTES and expect to do seeking later on */ diff --git a/gst/matroska/matroska-demux.c b/gst/matroska/matroska-demux.c index 08a53fcf6e..33dedd7382 100644 --- a/gst/matroska/matroska-demux.c +++ b/gst/matroska/matroska-demux.c @@ -1903,6 +1903,7 @@ gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux, GstMatroskaTrackContext *track = NULL; GstSegment seeksegment = { 0, }; gboolean update = TRUE; + gboolean pad_locked = FALSE; if (pad) track = gst_pad_get_element_private (pad); @@ -2001,6 +2002,7 @@ next: * forever. */ GST_DEBUG_OBJECT (demux, "Waiting for streaming to stop"); GST_PAD_STREAM_LOCK (demux->common.sinkpad); + pad_locked = TRUE; /* pull mode without index can do some scanning */ if (!demux->streaming && !entry) { @@ -2069,13 +2071,17 @@ exit: (GstTaskFunction) gst_matroska_demux_loop, demux->common.sinkpad); /* streaming can continue now */ - GST_PAD_STREAM_UNLOCK (demux->common.sinkpad); + if (pad_locked) { + GST_PAD_STREAM_UNLOCK (demux->common.sinkpad); + } return TRUE; seek_error: { - GST_PAD_STREAM_UNLOCK (demux->common.sinkpad); + if (pad_locked) { + GST_PAD_STREAM_UNLOCK (demux->common.sinkpad); + } GST_ELEMENT_ERROR (demux, STREAM, DEMUX, (NULL), ("Got a seek error")); return FALSE; } diff --git a/gst/matroska/matroska-mux.c b/gst/matroska/matroska-mux.c index 4b5c8f6afd..850494f0d4 100644 --- a/gst/matroska/matroska-mux.c +++ b/gst/matroska/matroska-mux.c @@ -2361,6 +2361,7 @@ gst_matroska_mux_start (GstMatroskaMux * mux) "streamable=false. Will ignore that and create streamable output " "instead"); } + gst_query_unref (query); } if (!strcmp (mux->doctype, GST_MATROSKA_DOCTYPE_WEBM)) { diff --git a/gst/rtp/gstrtpdvdepay.c b/gst/rtp/gstrtpdvdepay.c index ab9a83b91a..7d81a95a68 100644 --- a/gst/rtp/gstrtpdvdepay.c +++ b/gst/rtp/gstrtpdvdepay.c @@ -336,12 +336,14 @@ gst_rtp_dv_depay_process (GstRTPBaseDepayload * base, GstBuffer * in) GST_LOG_OBJECT (dvdepay, "got block at location %d", location); } - /* get the byte offset of the dif block */ - offset = location * 80; + if (location != -1) { + /* get the byte offset of the dif block */ + offset = location * 80; - /* And copy it in, provided the location is sane. */ - if (offset >= 0 && offset <= dvdepay->frame_size - 80) - gst_buffer_fill (dvdepay->acc, offset, payload, 80); + /* And copy it in, provided the location is sane. */ + if (offset <= dvdepay->frame_size - 80) + gst_buffer_fill (dvdepay->acc, offset, payload, 80); + } payload += 80; payload_len -= 80; diff --git a/gst/rtsp/gstrtspsrc.c b/gst/rtsp/gstrtspsrc.c index 448af25198..e8e58887f4 100644 --- a/gst/rtsp/gstrtspsrc.c +++ b/gst/rtsp/gstrtspsrc.c @@ -170,6 +170,7 @@ gst_rtsp_src_buffer_mode_get_type (void) #define DEFAULT_CONNECTION_SPEED 0 #define DEFAULT_NAT_METHOD GST_RTSP_NAT_DUMMY #define DEFAULT_DO_RTCP TRUE +#define DEFAULT_DO_RTSP_KEEP_ALIVE TRUE #define DEFAULT_PROXY NULL #define DEFAULT_RTP_BLOCKSIZE 0 #define DEFAULT_USER_ID NULL @@ -191,6 +192,7 @@ enum PROP_CONNECTION_SPEED, PROP_NAT_METHOD, PROP_DO_RTCP, + PROP_DO_RTSP_KEEP_ALIVE, PROP_PROXY, PROP_RTP_BLOCKSIZE, PROP_USER_ID, @@ -372,6 +374,20 @@ gst_rtspsrc_class_init (GstRTSPSrcClass * klass) "Send RTCP packets, disable for old incompatible server.", DEFAULT_DO_RTCP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstRTSPSrc::do-rtsp-keep-alive + * + * Enable RTSP keep laive support. Some old server don't like RTSP + * keep alive and then this property needs to be set to FALSE. + * + * Since: 0.10.32 + */ + g_object_class_install_property (gobject_class, PROP_DO_RTSP_KEEP_ALIVE, + g_param_spec_boolean ("do-rtsp-keep-alive", "Do RTSP Keep Alive", + "Send RTSP keep alive packets, disable for old incompatible server.", + DEFAULT_DO_RTSP_KEEP_ALIVE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** * GstRTSPSrc::proxy * @@ -492,6 +508,7 @@ gst_rtspsrc_init (GstRTSPSrc * src) src->connection_speed = DEFAULT_CONNECTION_SPEED; src->nat_method = DEFAULT_NAT_METHOD; src->do_rtcp = DEFAULT_DO_RTCP; + src->do_rtsp_keep_alive = DEFAULT_DO_RTSP_KEEP_ALIVE; gst_rtspsrc_set_proxy (src, DEFAULT_PROXY); src->rtp_blocksize = DEFAULT_RTP_BLOCKSIZE; src->user_id = g_strdup (DEFAULT_USER_ID); @@ -650,6 +667,9 @@ gst_rtspsrc_set_property (GObject * object, guint prop_id, const GValue * value, case PROP_DO_RTCP: rtspsrc->do_rtcp = g_value_get_boolean (value); break; + case PROP_DO_RTSP_KEEP_ALIVE: + rtspsrc->do_rtsp_keep_alive = g_value_get_boolean (value); + break; case PROP_PROXY: gst_rtspsrc_set_proxy (rtspsrc, g_value_get_string (value)); break; @@ -740,6 +760,9 @@ gst_rtspsrc_get_property (GObject * object, guint prop_id, GValue * value, case PROP_DO_RTCP: g_value_set_boolean (value, rtspsrc->do_rtcp); break; + case PROP_DO_RTSP_KEEP_ALIVE: + g_value_set_boolean (value, rtspsrc->do_rtsp_keep_alive); + break; case PROP_PROXY: { gchar *str; @@ -3420,6 +3443,12 @@ gst_rtspsrc_send_keep_alive (GstRTSPSrc * src) GstRTSPMethod method; gchar *control; + if (src->do_rtsp_keep_alive == FALSE) { + GST_DEBUG_OBJECT (src, "do-rtsp-keep-alive is FALSE, not sending."); + gst_rtsp_connection_reset_timeout (src->conninfo.connection); + return GST_RTSP_OK; + } + GST_DEBUG_OBJECT (src, "creating server keep-alive"); /* find a method to use for keep-alive */ @@ -3764,7 +3793,11 @@ gst_rtspsrc_loop_udp (GstRTSPSrc * src) goto connect_error; continue; + case GST_RTSP_ENET: + GST_DEBUG_OBJECT (src, "An ethernet problem occured."); default: + GST_ELEMENT_WARNING (src, RESOURCE, READ, (NULL), + ("Unhandled return value %d.", res)); goto receive_error; } @@ -3923,17 +3956,17 @@ no_protocols: ("Could not receive any UDP packets for %.4f seconds, maybe your " "firewall is blocking it. No other protocols to try.", gst_guint64_to_gdouble (src->udp_timeout / 1000000.0))); - return GST_FLOW_ERROR; + return GST_RTSP_ERROR; } open_failed: { GST_DEBUG_OBJECT (src, "open failed"); - return GST_FLOW_OK; + return GST_RTSP_OK; } play_failed: { GST_DEBUG_OBJECT (src, "play failed"); - return GST_FLOW_OK; + return GST_RTSP_OK; } } diff --git a/gst/rtsp/gstrtspsrc.h b/gst/rtsp/gstrtspsrc.h index 9e208bfd0a..eb7f8e528c 100644 --- a/gst/rtsp/gstrtspsrc.h +++ b/gst/rtsp/gstrtspsrc.h @@ -204,6 +204,7 @@ struct _GstRTSPSrc { guint64 connection_speed; GstRTSPNatMethod nat_method; gboolean do_rtcp; + gboolean do_rtsp_keep_alive; gchar *proxy_host; guint proxy_port; gchar *proxy_user; diff --git a/gst/smpte/gstsmpte.c b/gst/smpte/gstsmpte.c index beb979fc61..afd30a2529 100644 --- a/gst/smpte/gstsmpte.c +++ b/gst/smpte/gstsmpte.c @@ -408,8 +408,7 @@ gst_smpte_blend_i420 (guint8 * in1, guint8 * in2, guint8 * out, GstMask * mask, gint i, j; gint min, max; guint8 *in1u, *in1v, *in2u, *in2v, *outu, *outv; - gint lumsize = width * height; - gint chromsize = lumsize >> 2; + gint uoffset, voffset, ystr, ustr, vstr; if (border == 0) border++; @@ -417,12 +416,19 @@ gst_smpte_blend_i420 (guint8 * in1, guint8 * in2, guint8 * out, GstMask * mask, min = pos - border; max = pos; - in1u = in1 + lumsize; - in1v = in1u + chromsize; - in2u = in2 + lumsize; - in2v = in2u + chromsize; - outu = out + lumsize; - outv = outu + chromsize; + uoffset = I420_U_OFFSET (width, height); + voffset = I420_V_OFFSET (width, height); + + ystr = I420_Y_ROWSTRIDE (width); + ustr = I420_U_ROWSTRIDE (width); + vstr = I420_V_ROWSTRIDE (width); + + in1u = in1 + uoffset; + in1v = in1 + voffset; + in2u = in2 + uoffset; + in2v = in2 + voffset; + outu = out + uoffset; + outv = out + voffset; maskp = mask->data; @@ -431,12 +437,25 @@ gst_smpte_blend_i420 (guint8 * in1, guint8 * in2, guint8 * out, GstMask * mask, value = *maskp++; value = ((CLAMP (value, min, max) - min) << 8) / border; - *out++ = ((*in1++ * value) + (*in2++ * (256 - value))) >> 8; + out[j] = ((in1[j] * value) + (in2[j] * (256 - value))) >> 8; if (!(i & 1) && !(j & 1)) { - *outu++ = ((*in1u++ * value) + (*in2u++ * (256 - value))) >> 8; - *outv++ = ((*in1v++ * value) + (*in2v++ * (256 - value))) >> 8; + outu[j / 2] = + ((in1u[j / 2] * value) + (in2u[j / 2] * (256 - value))) >> 8; + outv[j / 2] = + ((in1v[j / 2] * value) + (in2v[j / 2] * (256 - value))) >> 8; } } + out += ystr; + in1 += ystr; + in2 += ystr; + if (!(i & 1)) { + outu += ustr; + in1u += ustr; + in2u += ustr; + outv += vstr; + in1v += vstr; + in2v += vstr; + } } } diff --git a/sys/ximage/gstximagesrc.c b/sys/ximage/gstximagesrc.c index eee74d420b..0ec9688b4a 100644 --- a/sys/ximage/gstximagesrc.c +++ b/sys/ximage/gstximagesrc.c @@ -1053,8 +1053,7 @@ gst_ximage_src_get_caps (GstBaseSrc * bs, GstCaps * filter) if (s->endx >= s->startx && s->endy >= s->starty) { /* this means user has put in values */ if (s->startx < xcontext->width && s->endx < xcontext->width && - s->starty < xcontext->height && s->endy < xcontext->height && - s->startx >= 0 && s->starty >= 0) { + s->starty < xcontext->height && s->endy < xcontext->height) { /* values are fine */ s->width = width = s->endx - s->startx + 1; s->height = height = s->endy - s->starty + 1;