Merge branch 'master' into 0.11
authorWim Taymans <wim.taymans@collabora.co.uk>
Thu, 22 Mar 2012 10:35:13 +0000 (11:35 +0100)
committerWim Taymans <wim.taymans@collabora.co.uk>
Thu, 22 Mar 2012 10:35:13 +0000 (11:35 +0100)
Conflicts:
.gitignore
common
configure.ac
ext/vorbis/gstvorbisdeclib.h
gst-libs/gst/audio/gstaudioencoder.c
gst-libs/gst/riff/riff-read.c
gst/playback/gstplaysink.c
gst/playback/gstplaysinkconvertbin.c
tests/check/libs/video.c

15 files changed:
.gitignore
configure.ac
ext/vorbis/gstvorbisdeclib.h
gst-libs/gst/audio/gstaudiodecoder.c
gst-libs/gst/audio/gstaudiodecoder.h
gst-libs/gst/audio/gstaudioencoder.c
gst-libs/gst/audio/gstaudioencoder.h
gst-libs/gst/riff/riff-ids.h
gst-libs/gst/riff/riff-read.c
gst-libs/gst/video/video-overlay-composition.c
gst/playback/gstplaybin2.c
gst/playback/gstplaysink.c
gst/playback/gstplaysinkconvertbin.c
gst/playback/gsturidecodebin.c
tests/check/libs/video.c

index 4378578..98a665a 100644 (file)
@@ -49,6 +49,7 @@ Makefile
 
 /gst-libs/gst/audio/audio-marshal.[ch]
 /gst-libs/gst/video/video-marshal.[ch]
+/tests/examples/playback/playback-test
 
 tmp-orc.c
 gst*orc.h
index d6328bb..f0bb621 100644 (file)
@@ -176,14 +176,18 @@ AC_HEADER_STDC
 
 ac_cppflags_save="$CPPFLAGS"
 CPPFLAGS="`$PKG_CONFIG --cflags libxml-2.0`"
-AC_COMPILE_IFELSE(
-  AC_LANG_PROGRAM([
+AC_COMPILE_IFELSE([
+  AC_LANG_PROGRAM([[
 #include <libxml/HTMLparser.h>
-                     ],[
+]],[[
 #ifndef LIBXML_HTML_ENABLED
 #error libxml2 has no HTML support
 #endif /* LIBXML_HTML_ENABLED */
-                   ]), HAVE_LIBXML_HTML="yes", HAVE_LIBXML_HTML="no")
+]])], [
+  HAVE_LIBXML_HTML="yes"
+], [
+  HAVE_LIBXML_HTML="no"
+])
 CPPFLAGS="$ac_cppflags_save"
 AM_CONDITIONAL(HAVE_LIBXML_HTML, test "x$HAVE_LIBXML_HTML" = "xyes")
 
@@ -694,14 +698,14 @@ AG_GST_CHECK_FEATURE(VORBIS, [Xiph Vorbis audio codec], vorbis, [
 
 if test "x$HAVE_VORBIS" = "xyes"; then
   ac_cflags_save="$CFLAGS"
-  AC_COMPILE_IFELSE(
-    AC_LANG_PROGRAM([
+  AC_COMPILE_IFELSE([
+    AC_LANG_PROGRAM([[
 #include <vorbis/codec.h>
-                     ],[
+                     ]],[[
 vorbis_dsp_state *v;
 
 vorbis_synthesis_restart (v);
-                     ]), HAVE_VSR=yes, HAVE_VSR=no)
+                     ]])], HAVE_VSR=yes, HAVE_VSR=no)
   if test "x$HAVE_VSR" = "xyes"; then
     AC_DEFINE_UNQUOTED(HAVE_VORBIS_SYNTHESIS_RESTART, 1,
                        [defined if vorbis_synthesis_restart is present])
index a9e108c..caefa40 100644 (file)
 
 #ifndef TREMOR
 
-#include <vorbis/codec.h>
-
-typedef float                          vorbis_sample_t;
-typedef ogg_packet                     ogg_packet_wrapper;
-
 #define GST_VORBIS_DEC_DESCRIPTION "decode raw vorbis streams to float audio"
 
 #define GST_VORBIS_AUDIO_FORMAT     GST_AUDIO_FORMAT_F32
@@ -50,6 +45,42 @@ typedef ogg_packet                     ogg_packet_wrapper;
 
 #define GST_VORBIS_DEC_GLIB_TYPE_NAME      GstVorbisDec
 
+#else /* TREMOR */
+
+#define GST_VORBIS_DEC_DESCRIPTION "decode raw vorbis streams to integer audio"
+
+#define GST_VORBIS_AUDIO_FORMAT GST_AUDIO_FORMAT_S16
+#define GST_VORBIS_AUDIO_FORMAT_STR GST_AUDIO_NE (S16)
+
+#define GST_VORBIS_DEC_SRC_CAPS        \
+    GST_STATIC_CAPS ("audio/x-raw, "   \
+        "format = (string) " GST_VORBIS_AUDIO_FORMAT_STR ", "      \
+        "rate = (int) [ 1, MAX ], "    \
+        "channels = (int) [ 1, 6 ]")
+
+#define GST_VORBIS_DEC_DEFAULT_SAMPLE_WIDTH           (16)
+
+/* we need a different type name here */
+#define GST_VORBIS_DEC_GLIB_TYPE_NAME      GstIVorbisDec
+
+/* and still have it compile */
+typedef struct _GstVorbisDec               GstIVorbisDec;
+typedef struct _GstVorbisDecClass          GstIVorbisDecClass;
+
+#endif /* TREMOR */
+
+#ifndef USE_TREMOLO
+
+#ifdef TREMOR
+ #include <tremor/ivorbiscodec.h>
+ typedef ogg_int32_t                    vorbis_sample_t;
+#else
+ #include <vorbis/codec.h>
+ typedef float                          vorbis_sample_t;
+#endif
+
+typedef ogg_packet                     ogg_packet_wrapper;
+
 static inline guint8 *
 gst_ogg_packet_data (ogg_packet * p)
 {
@@ -84,17 +115,11 @@ gst_ogg_packet_from_wrapper (ogg_packet_wrapper * packet)
   return packet;
 }
 
-#else
-
-#ifdef USE_TREMOLO
-  #include <Tremolo/ivorbiscodec.h>
-  #include <Tremolo/codec_internal.h>
-  typedef ogg_int16_t                    vorbis_sample_t;
-#else
-  #include <tremor/ivorbiscodec.h>
-  typedef ogg_int32_t                    vorbis_sample_t;
-#endif
+#else /* USE_TREMOLO */
 
+#include <Tremolo/ivorbiscodec.h>
+#include <Tremolo/codec_internal.h>
+typedef ogg_int16_t                    vorbis_sample_t;
 typedef struct _ogg_packet_wrapper     ogg_packet_wrapper;
 
 struct _ogg_packet_wrapper {
@@ -103,24 +128,6 @@ struct _ogg_packet_wrapper {
   ogg_buffer          buf;
 };
 
-#define GST_VORBIS_DEC_DESCRIPTION "decode raw vorbis streams to integer audio"
-
-#define GST_VORBIS_AUDIO_FORMAT GST_AUDIO_FORMAT_S16
-#define GST_VORBIS_AUDIO_FORMAT_STR GST_AUDIO_NE (S16)
-
-#define GST_VORBIS_DEC_SRC_CAPS        \
-    GST_STATIC_CAPS ("audio/x-raw, "   \
-        "format = (string) " GST_VORBIS_AUDIO_FORMAT_STR ", "      \
-        "rate = (int) [ 1, MAX ], "    \
-        "channels = (int) [ 1, 6 ]")
-
-/* we need a different type name here */
-#define GST_VORBIS_DEC_GLIB_TYPE_NAME      GstIVorbisDec
-
-/* and still have it compile */
-typedef struct _GstVorbisDec               GstIVorbisDec;
-typedef struct _GstVorbisDecClass          GstIVorbisDecClass;
-
 /* compensate minor variation */
 #define vorbis_synthesis(a, b)             vorbis_synthesis (a, b, 1)
 
@@ -179,7 +186,7 @@ gst_ogg_packet_from_wrapper (ogg_packet_wrapper * packet)
   return &(packet->packet);
 }
 
-#endif
+#endif /* USE_TREMOLO */
 
 typedef void (*CopySampleFunc)(vorbis_sample_t *out, vorbis_sample_t **in,
                            guint samples, gint channels);
index 46d28af..72c8f7a 100644 (file)
@@ -2087,12 +2087,18 @@ static GstStateChangeReturn
 gst_audio_decoder_change_state (GstElement * element, GstStateChange transition)
 {
   GstAudioDecoder *codec;
+  GstAudioDecoderClass *klass;
   GstStateChangeReturn ret;
 
   codec = GST_AUDIO_DECODER (element);
+  klass = GST_AUDIO_DECODER_GET_CLASS (codec);
 
   switch (transition) {
     case GST_STATE_CHANGE_NULL_TO_READY:
+      if (klass->open) {
+        if (!klass->open (codec))
+          goto open_failed;
+      }
       break;
     case GST_STATE_CHANGE_READY_TO_PAUSED:
       if (!gst_audio_decoder_start (codec)) {
@@ -2116,6 +2122,10 @@ gst_audio_decoder_change_state (GstElement * element, GstStateChange transition)
       }
       break;
     case GST_STATE_CHANGE_READY_TO_NULL:
+      if (klass->close) {
+        if (!klass->close (codec))
+          goto close_failed;
+      }
       break;
     default:
       break;
@@ -2133,6 +2143,16 @@ stop_failed:
     GST_ELEMENT_ERROR (codec, LIBRARY, INIT, (NULL), ("Failed to stop codec"));
     return GST_STATE_CHANGE_FAILURE;
   }
+open_failed:
+  {
+    GST_ELEMENT_ERROR (codec, LIBRARY, INIT, (NULL), ("Failed to open codec"));
+    return GST_STATE_CHANGE_FAILURE;
+  }
+close_failed:
+  {
+    GST_ELEMENT_ERROR (codec, LIBRARY, INIT, (NULL), ("Failed to close codec"));
+    return GST_STATE_CHANGE_FAILURE;
+  }
 }
 
 GstFlowReturn
index 5c33806..4971ea2 100644 (file)
@@ -201,6 +201,12 @@ struct _GstAudioDecoder
  *                  Called just prior to pushing (encoded data) buffer downstream.
  *                  Subclass has full discretionary access to buffer,
  *                  and a not OK flow return will abort downstream pushing.
+ * @open:           Optional.
+ *                  Called when the element changes to GST_STATE_READY.
+ *                  Allows opening external resources. Since: 0.10.37.
+ * @close:          Optional.
+ *                  Called when the element changes to GST_STATE_NULL.
+ *                  Allows closing external resources. Since: 0.10.37.
  *
  * Subclasses can override any of the available virtual methods or not, as
  * needed. At minimum @handle_frame (and likely @set_format) needs to be
@@ -237,8 +243,12 @@ struct _GstAudioDecoderClass
   gboolean      (*event)              (GstAudioDecoder *dec,
                                        GstEvent *event);
 
+  gboolean      (*open)               (GstAudioDecoder *dec);
+  
+  gboolean      (*close)              (GstAudioDecoder *dec);
+
   /*< private >*/
-  gpointer       _gst_reserved[GST_PADDING_LARGE];
+  gpointer       _gst_reserved[GST_PADDING_LARGE-2];
 };
 
 GType             gst_audio_decoder_get_type (void);
index 1ff5573..d45e6fb 100644 (file)
@@ -315,13 +315,17 @@ static gboolean gst_audio_encoder_src_query (GstPad * pad, GstObject * parent,
     GstQuery * query);
 static gboolean gst_audio_encoder_sink_query (GstPad * pad, GstObject * parent,
     GstQuery * query);
+static GstStateChangeReturn gst_audio_encoder_change_state (GstElement *
+    element, GstStateChange transition);
 
 static void
 gst_audio_encoder_class_init (GstAudioEncoderClass * klass)
 {
   GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
 
   gobject_class = G_OBJECT_CLASS (klass);
+  gstelement_class = GST_ELEMENT_CLASS (klass);
   parent_class = g_type_class_peek_parent (klass);
 
   GST_DEBUG_CATEGORY_INIT (gst_audio_encoder_debug, "audioencoder", 0,
@@ -353,6 +357,9 @@ gst_audio_encoder_class_init (GstAudioEncoderClass * klass)
           0, G_MAXINT64, DEFAULT_TOLERANCE,
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_audio_encoder_change_state);
+
   klass->getcaps = gst_audio_encoder_getcaps_default;
   klass->event = gst_audio_encoder_sink_event_default;
 }
@@ -460,6 +467,49 @@ gst_audio_encoder_finalize (GObject * object)
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
+static GstStateChangeReturn
+gst_audio_encoder_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+  GstAudioEncoder *enc = GST_AUDIO_ENCODER (element);
+  GstAudioEncoderClass *klass = GST_AUDIO_ENCODER_GET_CLASS (enc);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      if (klass->open) {
+        if (!klass->open (enc))
+          goto open_failed;
+      }
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      if (klass->close) {
+        if (!klass->close (enc))
+          goto close_failed;
+      }
+    default:
+      break;
+  }
+
+  return ret;
+
+open_failed:
+  {
+    GST_ELEMENT_ERROR (enc, LIBRARY, INIT, (NULL), ("Failed to open codec"));
+    return GST_STATE_CHANGE_FAILURE;
+  }
+close_failed:
+  {
+    GST_ELEMENT_ERROR (enc, LIBRARY, INIT, (NULL), ("Failed to close codec"));
+    return GST_STATE_CHANGE_FAILURE;
+  }
+}
+
 /**
  * gst_audio_encoder_finish_frame:
  * @enc: a #GstAudioEncoder
index 02f1d09..a154eb5 100644 (file)
@@ -152,6 +152,12 @@ struct _GstAudioEncoder {
  *                  for multichannel input specification).  If not implemented,
  *                  default returns gst_audio_encoder_proxy_getcaps
  *                  applied to sink template caps.
+ * @open:           Optional.
+ *                  Called when the element changes to GST_STATE_READY.
+ *                  Allows opening external resources. Since: 0.10.37.
+ * @close:          Optional.
+ *                  Called when the element changes to GST_STATE_NULL.
+ *                  Allows closing external resources. Since: 0.10.37.
  *
  * Subclasses can override any of the available virtual methods or not, as
  * needed. At minimum @set_format and @handle_frame needs to be overridden.
@@ -184,8 +190,12 @@ struct _GstAudioEncoderClass {
 
   GstCaps *     (*getcaps)            (GstAudioEncoder *enc, GstCaps *filter);
 
+  gboolean      (*open)               (GstAudioEncoder *enc);
+
+  gboolean      (*close)              (GstAudioEncoder *enc);
+
   /*< private >*/
-  gpointer       _gst_reserved[GST_PADDING_LARGE];
+  gpointer       _gst_reserved[GST_PADDING_LARGE-2];
 };
 
 GType           gst_audio_encoder_get_type         (void);
index 106f71a..9442018 100644 (file)
@@ -96,7 +96,7 @@ G_BEGIN_DECLS
 #define GST_RIFF_INFO_IMED GST_MAKE_FOURCC ('I','M','E','D') /* medium */
 #define GST_RIFF_INFO_INAM GST_MAKE_FOURCC ('I','N','A','M') /* name */
 #define GST_RIFF_INFO_IPLT GST_MAKE_FOURCC ('I','P','L','T') /* palette setting */
-#define GST_RIFF_INFO_IPRD GST_MAKE_FOURCC ('I','P','R','D') /* product */
+#define GST_RIFF_INFO_IPRD GST_MAKE_FOURCC ('I','P','R','D') /* product (album) */
 #define GST_RIFF_INFO_ISBJ GST_MAKE_FOURCC ('I','S','B','J') /* subject */
 #define GST_RIFF_INFO_ISFT GST_MAKE_FOURCC ('I','S','F','T') /* software */
 #define GST_RIFF_INFO_ISHP GST_MAKE_FOURCC ('I','S','H','P') /* sharpness */
@@ -104,6 +104,9 @@ G_BEGIN_DECLS
 #define GST_RIFF_INFO_ISRF GST_MAKE_FOURCC ('I','S','R','F') /* source form */
 #define GST_RIFF_INFO_ITCH GST_MAKE_FOURCC ('I','T','C','H') /* technician(s) */
 
+#define GST_RIFF_INFO_IAAR GST_MAKE_FOURCC ('I','A','A','R') /* album artist */
+#define GST_RIFF_INFO_ITRK GST_MAKE_FOURCC ('I','T','R','K') /* track number */
+
 /*********Chunk Names***************/
 #define GST_RIFF_FF00 GST_MAKE_FOURCC (0xFF,0xFF,0x00,0x00)
 #define GST_RIFF_00   GST_MAKE_FOURCC ('0', '0',0x00,0x00)
index 5b03021..78cd3f2 100644 (file)
@@ -657,6 +657,9 @@ gst_riff_parse_info (GstElement * element,
   while (left > 8) {
     tag = GST_READ_UINT32_LE (ptr);
     tsize = GST_READ_UINT32_LE (ptr + 4);
+
+    GST_MEMDUMP_OBJECT (element, "tag chunk", ptr, MIN (tsize + 8, left));
+
     left -= 8;
     ptr += 8;
 
@@ -670,11 +673,17 @@ gst_riff_parse_info (GstElement * element,
       tsize = left;
     }
 
+    /* make uppercase */
+    tag = tag & 0xDFDFDFDF;
+
     /* find out the type of metadata */
     switch (tag) {
       case GST_RIFF_INFO_IARL:
         type = GST_TAG_LOCATION;
         break;
+      case GST_RIFF_INFO_IAAR:
+        type = GST_TAG_ALBUM_ARTIST;
+        break;
       case GST_RIFF_INFO_IART:
         type = GST_TAG_ARTIST;
         break;
@@ -721,7 +730,7 @@ gst_riff_parse_info (GstElement * element,
         type = NULL;            /*"Palette"; */
         break;
       case GST_RIFF_INFO_IPRD:
-        type = NULL;            /*"Product"; */
+        type = GST_TAG_ALBUM;
         break;
       case GST_RIFF_INFO_ISBJ:
         type = NULL;            /*"Subject"; */
@@ -741,6 +750,9 @@ gst_riff_parse_info (GstElement * element,
       case GST_RIFF_INFO_ITCH:
         type = NULL;            /*"Technician"; */
         break;
+      case GST_RIFF_INFO_ITRK:
+        type = GST_TAG_TRACK_NUMBER;
+        break;
       default:
         type = NULL;
         GST_WARNING_OBJECT (element,
@@ -753,12 +765,31 @@ gst_riff_parse_info (GstElement * element,
       static const gchar *env_vars[] = { "GST_AVI_TAG_ENCODING",
         "GST_RIFF_TAG_ENCODING", "GST_TAG_ENCODING", NULL
       };
+      GType tag_type;
       gchar *val;
 
+      GST_DEBUG_OBJECT (element, "mapped tag %" GST_FOURCC_FORMAT " to tag %s",
+          GST_FOURCC_ARGS (tag), type);
+
+      tag_type = gst_tag_get_type (type);
       val = gst_tag_freeform_string_to_utf8 ((gchar *) ptr, tsize, env_vars);
 
-      if (val) {
-        gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, type, val, NULL);
+      if (val != NULL) {
+        if (tag_type == G_TYPE_STRING) {
+          gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, type, val, NULL);
+        } else {
+          GValue tag_val = { 0, };
+
+          g_value_init (&tag_val, tag_type);
+          if (gst_value_deserialize (&tag_val, val)) {
+            gst_tag_list_add_value (taglist, GST_TAG_MERGE_APPEND, type,
+                &tag_val);
+          } else {
+            GST_WARNING_OBJECT (element, "could not deserialize '%s' into a "
+                "tag %s of type %s", val, type, g_type_name (tag_type));
+          }
+          g_value_unset (&tag_val);
+        }
         g_free (val);
       } else {
         GST_WARNING_OBJECT (element, "could not extract %s tag", type);
@@ -776,6 +807,7 @@ gst_riff_parse_info (GstElement * element,
   }
 
   if (!gst_tag_list_is_empty (taglist)) {
+    GST_INFO_OBJECT (element, "extracted tags: %" GST_PTR_FORMAT, taglist);
     *_taglist = taglist;
   } else {
     *_taglist = NULL;
index 9b984df..abe16f8 100644 (file)
@@ -849,6 +849,19 @@ gst_video_overlay_rectangle_set_render_rectangle (GstVideoOverlayRectangle *
   rectangle->render_height = render_height;
 }
 
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+# define ARGB_A 3
+# define ARGB_R 2
+# define ARGB_G 1
+# define ARGB_B 0
+#else
+# define ARGB_A 0
+# define ARGB_R 1
+# define ARGB_G 2
+# define ARGB_B 3
+#endif
+
+/* FIXME: orc-ify */
 static void
 gst_video_overlay_rectangle_premultiply (GstBlendVideoFormatInfo * info)
 {
@@ -856,15 +869,16 @@ gst_video_overlay_rectangle_premultiply (GstBlendVideoFormatInfo * info)
   for (j = 0; j < info->height; ++j) {
     guint8 *line = info->pixels + info->stride[0] * j;
     for (i = 0; i < info->width; ++i) {
-      int a = line[0];
-      line[1] = line[1] * a / 255;
-      line[2] = line[2] * a / 255;
-      line[3] = line[3] * a / 255;
+      int a = line[ARGB_A];
+      line[ARGB_R] = line[ARGB_R] * a / 255;
+      line[ARGB_G] = line[ARGB_G] * a / 255;
+      line[ARGB_B] = line[ARGB_B] * a / 255;
       line += 4;
     }
   }
 }
 
+/* FIXME: orc-ify */
 static void
 gst_video_overlay_rectangle_unpremultiply (GstBlendVideoFormatInfo * info)
 {
@@ -872,11 +886,11 @@ gst_video_overlay_rectangle_unpremultiply (GstBlendVideoFormatInfo * info)
   for (j = 0; j < info->height; ++j) {
     guint8 *line = info->pixels + info->stride[0] * j;
     for (i = 0; i < info->width; ++i) {
-      int a = line[0];
+      int a = line[ARGB_A];
       if (a) {
-        line[1] = MIN ((line[1] * 255 + a / 2) / a, 255);
-        line[2] = MIN ((line[2] * 255 + a / 2) / a, 255);
-        line[3] = MIN ((line[3] * 255 + a / 2) / a, 255);
+        line[ARGB_R] = MIN ((line[ARGB_R] * 255 + a / 2) / a, 255);
+        line[ARGB_G] = MIN ((line[ARGB_G] * 255 + a / 2) / a, 255);
+        line[ARGB_B] = MIN ((line[ARGB_B] * 255 + a / 2) / a, 255);
       }
       line += 4;
     }
@@ -888,6 +902,7 @@ gst_video_overlay_rectangle_get_pixels_argb_internal (GstVideoOverlayRectangle *
     rectangle, guint * stride, GstVideoOverlayFormatFlags flags,
     gboolean unscaled)
 {
+  GstVideoOverlayFormatFlags new_flags;
   GstVideoOverlayRectangle *scaled_rect = NULL;
   GstBlendVideoFormatInfo info;
   GstBuffer *buf;
@@ -915,8 +930,7 @@ gst_video_overlay_rectangle_get_pixels_argb_internal (GstVideoOverlayRectangle *
 
     if (r->width == wanted_width &&
         r->height == wanted_height &&
-        gst_video_overlay_rectangle_is_same_alpha_type (rectangle->flags,
-            flags)) {
+        gst_video_overlay_rectangle_is_same_alpha_type (r->flags, flags)) {
       /* we'll keep these rectangles around until finalize, so it's ok not
        * to take our own ref here */
       scaled_rect = r;
@@ -936,13 +950,20 @@ gst_video_overlay_rectangle_get_pixels_argb_internal (GstVideoOverlayRectangle *
 
   if (wanted_width != rectangle->width || wanted_height != rectangle->height) {
     video_blend_scale_linear_RGBA (&info, wanted_height, wanted_width);
+  } else {
+    /* if we don't have to scale, we have to modify the alpha values, so we
+     * need to make a copy of the pixel memory (and we take ownership below) */
+    info.pixels = g_memdup (info.pixels, info.size);
   }
 
+  new_flags = rectangle->flags;
   if (!gst_video_overlay_rectangle_is_same_alpha_type (rectangle->flags, flags)) {
     if (rectangle->flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA) {
       gst_video_overlay_rectangle_unpremultiply (&info);
+      new_flags &= ~GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA;
     } else {
       gst_video_overlay_rectangle_premultiply (&info);
+      new_flags |= GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA;
     }
   }
 
@@ -953,7 +974,7 @@ gst_video_overlay_rectangle_get_pixels_argb_internal (GstVideoOverlayRectangle *
 
   scaled_rect = gst_video_overlay_rectangle_new_argb (buf,
       wanted_width, wanted_height, info.stride[0],
-      0, 0, wanted_width, wanted_height, rectangle->flags);
+      0, 0, wanted_width, wanted_height, new_flags);
 
   gst_buffer_unref (buf);
 
index 75515ef..39026bc 100644 (file)
@@ -3535,7 +3535,10 @@ activate_group (GstPlayBin * playbin, GstSourceGroup * group, GstState target)
     GST_DEBUG_OBJECT (playbin, "reusing existing uridecodebin");
     uridecodebin = group->uridecodebin;
     gst_element_set_state (uridecodebin, GST_STATE_READY);
-    gst_bin_add (GST_BIN_CAST (playbin), gst_object_ref (uridecodebin));
+    /* no need to take extra ref, we already have one
+     * and the bin will add one since it is no longer floating,
+     * as it was at least added once before (below) */
+    gst_bin_add (GST_BIN_CAST (playbin), uridecodebin);
   } else {
     GST_DEBUG_OBJECT (playbin, "making new uridecodebin");
     uridecodebin = gst_element_factory_make ("uridecodebin", NULL);
@@ -3598,7 +3601,10 @@ activate_group (GstPlayBin * playbin, GstSourceGroup * group, GstState target)
       GST_DEBUG_OBJECT (playbin, "reusing existing suburidecodebin");
       suburidecodebin = group->suburidecodebin;
       gst_element_set_state (suburidecodebin, GST_STATE_READY);
-      gst_bin_add (GST_BIN_CAST (playbin), gst_object_ref (suburidecodebin));
+      /* no need to take extra ref, we already have one
+       * and the bin will add one since it is no longer floating,
+       * as it was at least added once before (below) */
+      gst_bin_add (GST_BIN_CAST (playbin), suburidecodebin);
     } else {
       GST_DEBUG_OBJECT (playbin, "making new suburidecodebin");
       suburidecodebin = gst_element_factory_make ("uridecodebin", NULL);
index 3291ea9..85ec990 100644 (file)
@@ -3298,8 +3298,7 @@ video_set_blocked (GstPlaySink * playsink, gboolean blocked)
     if (blocked && playsink->video_block_id == 0) {
       playsink->video_block_id =
           gst_pad_add_probe (opad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
-          sinkpad_blocked_cb, gst_object_ref (playsink),
-          (GDestroyNotify) gst_object_unref);
+          sinkpad_blocked_cb, playsink, NULL);
     } else if (!blocked && playsink->video_block_id) {
       gst_pad_remove_probe (opad, playsink->video_block_id);
       PENDING_FLAG_UNSET (playsink, GST_PLAY_SINK_TYPE_VIDEO_RAW);
@@ -3321,8 +3320,7 @@ audio_set_blocked (GstPlaySink * playsink, gboolean blocked)
     if (blocked && playsink->audio_block_id == 0) {
       playsink->audio_block_id =
           gst_pad_add_probe (opad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
-          sinkpad_blocked_cb, gst_object_ref (playsink),
-          (GDestroyNotify) gst_object_unref);
+          sinkpad_blocked_cb, playsink, NULL);
     } else if (!blocked && playsink->audio_block_id) {
       gst_pad_remove_probe (opad, playsink->audio_block_id);
       PENDING_FLAG_UNSET (playsink, GST_PLAY_SINK_TYPE_AUDIO_RAW);
@@ -3344,8 +3342,7 @@ text_set_blocked (GstPlaySink * playsink, gboolean blocked)
     if (blocked && playsink->text_block_id == 0) {
       playsink->text_block_id =
           gst_pad_add_probe (opad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
-          sinkpad_blocked_cb, gst_object_ref (playsink),
-          (GDestroyNotify) gst_object_unref);
+          sinkpad_blocked_cb, playsink, NULL);
     } else if (!blocked && playsink->text_block_id) {
       gst_pad_remove_probe (opad, playsink->text_block_id);
       PENDING_FLAG_UNSET (playsink, GST_PLAY_SINK_TYPE_TEXT);
@@ -3567,8 +3564,7 @@ gst_play_sink_request_pad (GstPlaySink * playsink, GstPlaySinkType type)
 
       *block_id =
           gst_pad_add_probe (blockpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
-          sinkpad_blocked_cb, gst_object_ref (playsink),
-          (GDestroyNotify) gst_object_unref);
+          sinkpad_blocked_cb, playsink, NULL);
       PENDING_FLAG_SET (playsink, type);
       gst_object_unref (blockpad);
     }
@@ -4248,6 +4244,10 @@ gst_play_sink_navigation_send_event (GstNavigation * navigation,
       gst_navigation_send_event (GST_NAVIGATION (nav), structure);
       structure = NULL;
       gst_object_unref (nav);
+    } else {
+      GstEvent *event = gst_event_new_navigation (structure);
+      structure = NULL;
+      gst_element_send_event (GST_ELEMENT (bin), event);
     }
 
     gst_object_unref (bin);
index f67e29d..a5fcf3f 100644 (file)
@@ -304,8 +304,7 @@ block_proxypad (GstPlaySinkConvertBin * self)
   if (self->sink_proxypad_block_id == 0) {
     self->sink_proxypad_block_id =
         gst_pad_add_probe (self->sink_proxypad,
-        GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, pad_blocked_cb,
-        gst_object_ref (self), (GDestroyNotify) gst_object_unref);
+        GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, pad_blocked_cb, self, NULL);
   }
 }
 
index 095a400..d369904 100644 (file)
@@ -1528,6 +1528,8 @@ remove_decoders (GstURIDecodeBin * bin, gboolean force)
       caps = DEFAULT_CAPS;
       g_object_set (decoder, "caps", caps, NULL);
       gst_caps_unref (caps);
+      /* make it freshly floating again */
+      g_object_force_floating (G_OBJECT (decoder));
 
       bin->pending_decodebins =
           g_slist_prepend (bin->pending_decodebins, decoder);
index abc6f22..95105cb 100644 (file)
@@ -3,6 +3,7 @@
  * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
  * Copyright (C) <2006> Jan Schmidt <thaytan@mad.scientist.com>
  * Copyright (C) <2008,2011> Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) <2012> Collabora Ltd. <tim.muller@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
@@ -858,9 +859,6 @@ GST_START_TEST (test_video_size_from_caps)
 
 GST_END_TEST;
 
-#undef ASSERT_CRITICAL
-#define ASSERT_CRITICAL(code) while(0){}        /* nothing */
-
 #if 0
 /* FIXME 0.11: port overlay composition to buffer meta */
 GST_START_TEST (test_overlay_composition)
@@ -986,6 +984,7 @@ GST_START_TEST (test_overlay_composition)
   fail_unless (gst_video_buffer_get_overlay_composition (buf) == NULL);
 
   gst_buffer_ref (buf);
+  /* buffer now has refcount of 2, so its metadata is not writable */
   ASSERT_CRITICAL (gst_video_buffer_set_overlay_composition (buf, comp1));
   gst_buffer_unref (buf);
   gst_video_buffer_set_overlay_composition (buf, comp1);
@@ -1004,6 +1003,118 @@ GST_START_TEST (test_overlay_composition)
 }
 
 GST_END_TEST;
+
+GST_START_TEST (test_overlay_composition_premultiplied_alpha)
+{
+  GstVideoOverlayRectangle *rect1;
+  GstBuffer *pix1, *pix2, *pix3, *pix4, *pix5;
+  GstBuffer *pix6, *pix7, *pix8, *pix9, *pix10;
+  guint8 *data5, *data7;
+  guint w, h, stride, w2, h2, stride2;
+
+  pix1 = gst_buffer_new_and_alloc (200 * sizeof (guint32) * 50);
+  memset (GST_BUFFER_DATA (pix1), 0x80, GST_BUFFER_SIZE (pix1));
+
+  rect1 = gst_video_overlay_rectangle_new_argb (pix1, 200, 50, 200 * 4,
+      600, 50, 300, 50, GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
+  gst_buffer_unref (pix1);
+
+  /* same flags, unscaled, should be the same buffer */
+  pix2 = gst_video_overlay_rectangle_get_pixels_unscaled_argb (rect1, &w, &h,
+      &stride, GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
+  fail_unless (pix1 == pix2);
+
+  /* same flags, but scaled */
+  pix3 = gst_video_overlay_rectangle_get_pixels_argb (rect1, &stride,
+      GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
+  fail_if (pix3 == pix1 || pix3 == pix2);
+
+  /* same again, should hopefully get the same (cached) buffer as before */
+  pix4 = gst_video_overlay_rectangle_get_pixels_argb (rect1, &stride,
+      GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
+  fail_unless (pix4 == pix3);
+
+  /* just to update the vars */
+  pix2 = gst_video_overlay_rectangle_get_pixels_unscaled_argb (rect1, &w, &h,
+      &stride, GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
+
+  /* now, let's try to get premultiplied alpha from the unpremultiplied input */
+  pix5 = gst_video_overlay_rectangle_get_pixels_unscaled_argb (rect1, &w2, &h2,
+      &stride2, GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA);
+  fail_if (pix5 == pix1 || pix5 == pix2 || pix5 == pix3);
+  fail_unless_equals_int (stride, stride2);
+  fail_unless_equals_int (w, w2);
+  fail_unless_equals_int (h, h2);
+  fail_unless_equals_int (GST_BUFFER_SIZE (pix2), GST_BUFFER_SIZE (pix5));
+  data5 = GST_BUFFER_DATA (pix5);
+  fail_if (memcmp (data5, GST_BUFFER_DATA (pix2), GST_BUFFER_SIZE (pix5)) == 0);
+
+  /* make sure it actually did what we expected it to do (input=0x80808080) */
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+  /* B - G - R - A */
+  fail_unless_equals_int (data5[0], 0x40);
+  fail_unless_equals_int (data5[1], 0x40);
+  fail_unless_equals_int (data5[2], 0x40);
+  fail_unless_equals_int (data5[3], 0x80);
+#else
+  /* A - R - G - B */
+  fail_unless_equals_int (data5[0], 0x40);
+  fail_unless_equals_int (data5[1], 0x40);
+  fail_unless_equals_int (data5[2], 0x40);
+  fail_unless_equals_int (data5[3], 0x80);
+#endif
+
+  /* same again, now we should be getting back the same buffer as before,
+   * as it should have been cached */
+  pix6 = gst_video_overlay_rectangle_get_pixels_unscaled_argb (rect1, &w2, &h2,
+      &stride2, GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA);
+  fail_unless (pix6 == pix5);
+
+  /* just to update the stride var */
+  pix3 = gst_video_overlay_rectangle_get_pixels_argb (rect1, &stride,
+      GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
+  fail_unless (pix3 == pix4);
+
+  /* now try to get scaled premultiplied alpha from unpremultiplied input */
+  pix7 = gst_video_overlay_rectangle_get_pixels_argb (rect1, &stride2,
+      GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA);
+  fail_if (pix7 == pix1 || pix7 == pix2 || pix7 == pix3 || pix7 == pix5);
+  fail_unless_equals_int (stride, stride2);
+
+  data7 = GST_BUFFER_DATA (pix7);
+  /* make sure it actually did what we expected it to do (input=0x80808080)
+   * hoping that the scaling didn't mess up our values */
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+  /* B - G - R - A */
+  fail_unless_equals_int (data7[0], 0x40);
+  fail_unless_equals_int (data7[1], 0x40);
+  fail_unless_equals_int (data7[2], 0x40);
+  fail_unless_equals_int (data7[3], 0x80);
+#else
+  /* A - R - G - B */
+  fail_unless_equals_int (data7[0], 0x40);
+  fail_unless_equals_int (data7[1], 0x40);
+  fail_unless_equals_int (data7[2], 0x40);
+  fail_unless_equals_int (data7[3], 0x80);
+#endif
+
+  /* and the same again, it should be cached now */
+  pix8 = gst_video_overlay_rectangle_get_pixels_argb (rect1, &stride2,
+      GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA);
+  fail_unless (pix8 == pix7);
+
+  /* make sure other cached stuff is still there */
+  pix9 = gst_video_overlay_rectangle_get_pixels_argb (rect1, &stride,
+      GST_VIDEO_OVERLAY_FORMAT_FLAG_NONE);
+  fail_unless (pix9 == pix3);
+  pix10 = gst_video_overlay_rectangle_get_pixels_unscaled_argb (rect1, &w2, &h2,
+      &stride2, GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA);
+  fail_unless (pix10 == pix5);
+
+  gst_video_overlay_rectangle_unref (rect1);
+}
+
+GST_END_TEST;
 #endif
 
 static Suite *
@@ -1025,6 +1136,7 @@ video_suite (void)
 #if 0
   /* FIXME 0.11: port overlay compositions */
   tcase_add_test (tc_chain, test_overlay_composition);
+  tcase_add_test (tc_chain, test_overlay_composition_premultiplied_alpha);
 #endif
 
   return s;