diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | configure.ac | 20 | ||||
-rw-r--r-- | ext/vorbis/gstvorbisdeclib.h | 75 | ||||
-rw-r--r-- | gst-libs/gst/audio/gstaudiodecoder.c | 20 | ||||
-rw-r--r-- | gst-libs/gst/audio/gstaudiodecoder.h | 12 | ||||
-rw-r--r-- | gst-libs/gst/audio/gstaudioencoder.c | 50 | ||||
-rw-r--r-- | gst-libs/gst/audio/gstaudioencoder.h | 12 | ||||
-rw-r--r-- | gst-libs/gst/riff/riff-ids.h | 5 | ||||
-rw-r--r-- | gst-libs/gst/riff/riff-read.c | 38 | ||||
-rw-r--r-- | gst-libs/gst/video/video-overlay-composition.c | 43 | ||||
-rw-r--r-- | gst/playback/gstplaybin2.c | 10 | ||||
-rw-r--r-- | gst/playback/gstplaysink.c | 16 | ||||
-rw-r--r-- | gst/playback/gstplaysinkconvertbin.c | 3 | ||||
-rw-r--r-- | gst/playback/gsturidecodebin.c | 2 | ||||
-rw-r--r-- | tests/check/libs/video.c | 118 |
15 files changed, 351 insertions, 74 deletions
diff --git a/.gitignore b/.gitignore index 4378578c5..98a665aab 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/configure.ac b/configure.ac index d6328bbd2..f0bb62177 100644 --- a/configure.ac +++ b/configure.ac @@ -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]) diff --git a/ext/vorbis/gstvorbisdeclib.h b/ext/vorbis/gstvorbisdeclib.h index a9e108c3b..caefa402b 100644 --- a/ext/vorbis/gstvorbisdeclib.h +++ b/ext/vorbis/gstvorbisdeclib.h @@ -30,11 +30,6 @@ #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); diff --git a/gst-libs/gst/audio/gstaudiodecoder.c b/gst-libs/gst/audio/gstaudiodecoder.c index 46d28af86..72c8f7a1c 100644 --- a/gst-libs/gst/audio/gstaudiodecoder.c +++ b/gst-libs/gst/audio/gstaudiodecoder.c @@ -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 diff --git a/gst-libs/gst/audio/gstaudiodecoder.h b/gst-libs/gst/audio/gstaudiodecoder.h index 5c3380665..4971ea29b 100644 --- a/gst-libs/gst/audio/gstaudiodecoder.h +++ b/gst-libs/gst/audio/gstaudiodecoder.h @@ -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); diff --git a/gst-libs/gst/audio/gstaudioencoder.c b/gst-libs/gst/audio/gstaudioencoder.c index 1ff557371..d45e6fb14 100644 --- a/gst-libs/gst/audio/gstaudioencoder.c +++ b/gst-libs/gst/audio/gstaudioencoder.c @@ -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 diff --git a/gst-libs/gst/audio/gstaudioencoder.h b/gst-libs/gst/audio/gstaudioencoder.h index 02f1d09fd..a154eb57c 100644 --- a/gst-libs/gst/audio/gstaudioencoder.h +++ b/gst-libs/gst/audio/gstaudioencoder.h @@ -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); diff --git a/gst-libs/gst/riff/riff-ids.h b/gst-libs/gst/riff/riff-ids.h index 106f71aa7..9442018b5 100644 --- a/gst-libs/gst/riff/riff-ids.h +++ b/gst-libs/gst/riff/riff-ids.h @@ -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) diff --git a/gst-libs/gst/riff/riff-read.c b/gst-libs/gst/riff/riff-read.c index 5b03021bf..78cd3f27a 100644 --- a/gst-libs/gst/riff/riff-read.c +++ b/gst-libs/gst/riff/riff-read.c @@ -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; diff --git a/gst-libs/gst/video/video-overlay-composition.c b/gst-libs/gst/video/video-overlay-composition.c index 9b984dff1..abe16f8e8 100644 --- a/gst-libs/gst/video/video-overlay-composition.c +++ b/gst-libs/gst/video/video-overlay-composition.c @@ -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); diff --git a/gst/playback/gstplaybin2.c b/gst/playback/gstplaybin2.c index 75515efc6..39026bc8d 100644 --- a/gst/playback/gstplaybin2.c +++ b/gst/playback/gstplaybin2.c @@ -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); diff --git a/gst/playback/gstplaysink.c b/gst/playback/gstplaysink.c index 3291ea967..85ec99070 100644 --- a/gst/playback/gstplaysink.c +++ b/gst/playback/gstplaysink.c @@ -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); diff --git a/gst/playback/gstplaysinkconvertbin.c b/gst/playback/gstplaysinkconvertbin.c index f67e29d37..a5fcf3f9b 100644 --- a/gst/playback/gstplaysinkconvertbin.c +++ b/gst/playback/gstplaysinkconvertbin.c @@ -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); } } diff --git a/gst/playback/gsturidecodebin.c b/gst/playback/gsturidecodebin.c index 095a400e4..d3699044f 100644 --- a/gst/playback/gsturidecodebin.c +++ b/gst/playback/gsturidecodebin.c @@ -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); diff --git a/tests/check/libs/video.c b/tests/check/libs/video.c index abc6f22c5..95105cbe4 100644 --- a/tests/check/libs/video.c +++ b/tests/check/libs/video.c @@ -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; |