diff --git a/autogen.sh b/autogen.sh index 1fcf9f2827..645b2aeb38 100755 --- a/autogen.sh +++ b/autogen.sh @@ -29,6 +29,9 @@ then ln -s ../../common/hooks/pre-commit.hook .git/hooks/pre-commit fi +# GNU gettext automake support doesn't get along with git. +# https://bugzilla.gnome.org/show_bug.cgi?id=661128 +touch -t 200001010000 po/gst-plugins-good-0.10.pot CONFIGURE_DEF_OPT='--enable-maintainer-mode --enable-gtk-doc' diff --git a/configure.ac b/configure.ac index fe60f9cade..9669204e9c 100644 --- a/configure.ac +++ b/configure.ac @@ -314,9 +314,8 @@ dnl Make sure you have a space before and after all plugins GST_PLUGINS_NONPORTED="deinterlace interleave flx \ imagefreeze smpte \ videobox \ - cairo cairo_gobject dv1394 gdk_pixbuf \ + cairo cairo_gobject dv1394 \ oss oss4 \ - wavpack \ osx_video osx_audio " AC_SUBST(GST_PLUGINS_NONPORTED) diff --git a/docs/plugins/Makefile.am b/docs/plugins/Makefile.am index 51dbc1259b..c39680140a 100644 --- a/docs/plugins/Makefile.am +++ b/docs/plugins/Makefile.am @@ -84,7 +84,6 @@ EXTRA_HFILES = \ $(top_srcdir)/ext/speex/gstspeexdec.h \ $(top_srcdir)/ext/wavpack/gstwavpackdec.h \ $(top_srcdir)/ext/wavpack/gstwavpackenc.h \ - $(top_srcdir)/ext/wavpack/gstwavpackparse.h \ $(top_srcdir)/gst/alpha/gstalpha.h \ $(top_srcdir)/gst/alpha/gstalphacolor.h \ $(top_srcdir)/gst/apetag/gstapedemux.h \ diff --git a/ext/aalib/gstaasink.c b/ext/aalib/gstaasink.c index 62a885b6e3..5679c8940d 100644 --- a/ext/aalib/gstaasink.c +++ b/ext/aalib/gstaasink.c @@ -273,7 +273,7 @@ gst_aasink_init (GstAASink * aasink) static void gst_aasink_scale (GstAASink * aasink, guchar * src, guchar * dest, - gint sw, gint sh, gint dw, gint dh) + gint sw, gint sh, gint ss, gint dw, gint dh) { gint ypos, yinc, y; gint xpos, xinc, x; @@ -287,7 +287,7 @@ gst_aasink_scale (GstAASink * aasink, guchar * src, guchar * dest, for (y = dh; y; y--) { while (ypos > 0x10000) { ypos -= 0x10000; - src += sw; + src += ss; } xpos = 0x10000; { @@ -334,6 +334,7 @@ gst_aasink_render (GstBaseSink * basesink, GstBuffer * buffer) aa_image (aasink->context), /* dest */ GST_VIDEO_INFO_WIDTH (&aasink->info), /* sw */ GST_VIDEO_INFO_HEIGHT (&aasink->info), /* sh */ + GST_VIDEO_FRAME_PLANE_STRIDE (&frame, 0), /* ss */ aa_imgwidth (aasink->context), /* dw */ aa_imgheight (aasink->context)); /* dh */ diff --git a/ext/annodex/gstannodex.c b/ext/annodex/gstannodex.c index 789091cfe5..f4c9631092 100644 --- a/ext/annodex/gstannodex.c +++ b/ext/annodex/gstannodex.c @@ -21,6 +21,10 @@ * Boston, MA 02111-1307, USA. */ +/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray + * with newer GLib versions (>= 2.31.0) */ +#define GLIB_DISABLE_DEPRECATION_WARNINGS + #ifdef HAVE_CONFIG_H #include "config.h" #endif diff --git a/ext/annodex/gstcmmlparser.c b/ext/annodex/gstcmmlparser.c index 0e2f7cd8e3..b76cf4a0bd 100644 --- a/ext/annodex/gstcmmlparser.c +++ b/ext/annodex/gstcmmlparser.c @@ -21,6 +21,10 @@ * Boston, MA 02111-1307, USA. */ +/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray + * with newer GLib versions (>= 2.31.0) */ +#define GLIB_DISABLE_DEPRECATION_WARNINGS + #include #include #include diff --git a/ext/annodex/gstcmmltag.c b/ext/annodex/gstcmmltag.c index 2cf5d5fef1..8b2a1893e0 100644 --- a/ext/annodex/gstcmmltag.c +++ b/ext/annodex/gstcmmltag.c @@ -21,6 +21,10 @@ * Boston, MA 02111-1307, USA. */ +/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray + * with newer GLib versions (>= 2.31.0) */ +#define GLIB_DISABLE_DEPRECATION_WARNINGS + #ifdef HAVE_CONFIG_H #include "config.h" #endif diff --git a/ext/flac/gstflacenc.c b/ext/flac/gstflacenc.c index f53a24160b..c63f7a8b6c 100644 --- a/ext/flac/gstflacenc.c +++ b/ext/flac/gstflacenc.c @@ -761,7 +761,6 @@ gst_flac_enc_set_format (GstAudioEncoder * enc, GstAudioInfo * info) encoder_already_initialized: { g_warning ("flac already initialized -- fixme allow this"); - gst_object_unref (flacenc); return FALSE; } setting_src_caps_failed: @@ -769,14 +768,12 @@ setting_src_caps_failed: GST_DEBUG_OBJECT (flacenc, "Couldn't set caps on source pad: %" GST_PTR_FORMAT, caps); gst_caps_unref (caps); - gst_object_unref (flacenc); return FALSE; } failed_to_initialize: { GST_ELEMENT_ERROR (flacenc, LIBRARY, INIT, (NULL), ("could not initialize encoder (wrong parameters?)")); - gst_object_unref (flacenc); return FALSE; } } @@ -1104,43 +1101,9 @@ gst_flac_enc_sink_event (GstAudioEncoder * enc, GstEvent * event) GST_DEBUG ("Received %s event on sinkpad", GST_EVENT_TYPE_NAME (event)); switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_SEGMENT:{ - GstSegment seg; - gint64 start, stream_time; - - if (flacenc->offset == 0) { - gst_event_copy_segment (event, &seg); - start = seg.start; - stream_time = seg.time; - } else { - start = -1; - stream_time = -1; - } - - if (start > 0) { - if (flacenc->offset > 0) - GST_DEBUG ("Not handling mid-stream newsegment event"); - else - GST_DEBUG ("Not handling newsegment event with non-zero start"); - } else { - GstEvent *e; - - gst_segment_init (&seg, GST_FORMAT_BYTES); - e = gst_event_new_segment (&seg); - ret = gst_pad_push_event (GST_AUDIO_ENCODER_SRC_PAD (enc), e); - } - - if (stream_time > 0) { - GST_DEBUG ("Not handling non-zero stream time"); - } - - /* don't push it downstream, we'll generate our own via seek to 0 */ - gst_event_unref (event); - ret = TRUE; - break; - } case GST_EVENT_EOS: flacenc->eos = TRUE; + ret = GST_AUDIO_ENCODER_CLASS (parent_class)->event (enc, event); break; case GST_EVENT_TAG: if (flacenc->tags) { @@ -1150,8 +1113,10 @@ gst_flac_enc_sink_event (GstAudioEncoder * enc, GstEvent * event) } else { g_assert_not_reached (); } + ret = GST_AUDIO_ENCODER_CLASS (parent_class)->event (enc, event); break; default: + ret = GST_AUDIO_ENCODER_CLASS (parent_class)->event (enc, event); break; } diff --git a/ext/gdk_pixbuf/gstgdkpixbuf.c b/ext/gdk_pixbuf/gstgdkpixbuf.c index a65d2e8632..638acdd5ad 100644 --- a/ext/gdk_pixbuf/gstgdkpixbuf.c +++ b/ext/gdk_pixbuf/gstgdkpixbuf.c @@ -36,7 +36,6 @@ GST_DEBUG_CATEGORY_STATIC (gst_gdk_pixbuf_debug); enum { ARG_0, - ARG_SILENT /* FIXME 0.11: remove */ }; static GstStaticPadTemplate gst_gdk_pixbuf_sink_template = @@ -67,44 +66,40 @@ static GstStaticPadTemplate gst_gdk_pixbuf_src_template = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB "; " GST_VIDEO_CAPS_RGBA) + GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("RGB") "; " + GST_VIDEO_CAPS_MAKE ("RGBA")) ); -static void gst_gdk_pixbuf_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); -static void gst_gdk_pixbuf_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec); - static GstStateChangeReturn gst_gdk_pixbuf_change_state (GstElement * element, GstStateChange transition); -static GstFlowReturn gst_gdk_pixbuf_chain (GstPad * pad, GstBuffer * buffer); -static gboolean gst_gdk_pixbuf_sink_event (GstPad * pad, GstEvent * event); +static GstFlowReturn gst_gdk_pixbuf_chain (GstPad * pad, GstObject * parent, + GstBuffer * buffer); +static gboolean gst_gdk_pixbuf_sink_event (GstPad * pad, GstObject * parent, + GstEvent * event); #ifdef enable_typefind static void gst_gdk_pixbuf_type_find (GstTypeFind * tf, gpointer ignore); #endif -GST_BOILERPLATE (GstGdkPixbuf, gst_gdk_pixbuf, GstElement, GST_TYPE_ELEMENT); +#define gst_gdk_pixbuf_parent_class parent_class +G_DEFINE_TYPE (GstGdkPixbuf, gst_gdk_pixbuf, GST_TYPE_ELEMENT); static gboolean -gst_gdk_pixbuf_sink_setcaps (GstPad * pad, GstCaps * caps) +gst_gdk_pixbuf_sink_setcaps (GstGdkPixbuf * filter, GstCaps * caps) { - GstGdkPixbuf *filter; const GValue *framerate; GstStructure *s; - filter = GST_GDK_PIXBUF (GST_PAD_PARENT (pad)); s = gst_caps_get_structure (caps, 0); if ((framerate = gst_structure_get_value (s, "framerate")) != NULL) { - filter->framerate_numerator = gst_value_get_fraction_numerator (framerate); - filter->framerate_denominator = - gst_value_get_fraction_denominator (framerate); + filter->in_fps_n = gst_value_get_fraction_numerator (framerate); + filter->in_fps_d = gst_value_get_fraction_denominator (framerate); GST_DEBUG_OBJECT (filter, "got framerate of %d/%d fps => packetized mode", - filter->framerate_numerator, filter->framerate_denominator); + filter->in_fps_n, filter->in_fps_d); } else { - filter->framerate_numerator = 0; - filter->framerate_denominator = 1; + filter->in_fps_n = 0; + filter->in_fps_d = 1; GST_DEBUG_OBJECT (filter, "no framerate, assuming single image"); } @@ -112,7 +107,7 @@ gst_gdk_pixbuf_sink_setcaps (GstPad * pad, GstCaps * caps) } static GstCaps * -gst_gdk_pixbuf_get_capslist (void) +gst_gdk_pixbuf_get_capslist (GstCaps * filter) { GSList *slist; GSList *slist0; @@ -132,7 +127,7 @@ gst_gdk_pixbuf_get_capslist (void) mimetypes = gdk_pixbuf_format_get_mime_types (pixbuf_format); for (mimetype = mimetypes; *mimetype; mimetype++) { - gst_caps_append_structure (capslist, gst_structure_new (*mimetype, NULL)); + gst_caps_append_structure (capslist, gst_structure_new_empty (*mimetype)); } g_strfreev (mimetypes); } @@ -143,61 +138,72 @@ gst_gdk_pixbuf_get_capslist (void) gst_caps_unref (tmpl_caps); gst_caps_unref (capslist); + + if (filter && return_caps) { + GstCaps *temp; + + temp = gst_caps_intersect (return_caps, filter); + gst_caps_unref (return_caps); + return_caps = temp; + } + return return_caps; } -static GstCaps * -gst_gdk_pixbuf_sink_getcaps (GstPad * pad) +static gboolean +gst_gdk_pixbuf_sink_query (GstPad * pad, GstObject * parent, GstQuery * query) { - return gst_gdk_pixbuf_get_capslist (); + gboolean res; + + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_CAPS: + { + GstCaps *filter, *caps; + + gst_query_parse_caps (query, &filter); + caps = gst_gdk_pixbuf_get_capslist (filter); + gst_query_set_caps_result (query, caps); + gst_caps_unref (caps); + + res = TRUE; + break; + } + default: + res = gst_pad_query_default (pad, parent, query); + break; + } + return res; } -static void -gst_gdk_pixbuf_base_init (gpointer g_class) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_gdk_pixbuf_src_template)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&gst_gdk_pixbuf_sink_template)); - gst_element_class_set_details_simple (element_class, - "GdkPixbuf image decoder", "Codec/Decoder/Image", - "Decodes images in a video stream using GdkPixbuf", - "David A. Schleef , Renato Filho "); -} /* initialize the plugin's class */ static void gst_gdk_pixbuf_class_init (GstGdkPixbufClass * klass) { - GObjectClass *gobject_class; GstElementClass *gstelement_class; - gobject_class = (GObjectClass *) klass; gstelement_class = (GstElementClass *) klass; - gobject_class->set_property = gst_gdk_pixbuf_set_property; - gobject_class->get_property = gst_gdk_pixbuf_get_property; - - g_object_class_install_property (gobject_class, ARG_SILENT, - g_param_spec_boolean ("silent", "Silent", - "Produce verbose output ? (deprecated)", FALSE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_change_state); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&gst_gdk_pixbuf_src_template)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&gst_gdk_pixbuf_sink_template)); + gst_element_class_set_details_simple (gstelement_class, + "GdkPixbuf image decoder", "Codec/Decoder/Image", + "Decodes images in a video stream using GdkPixbuf", + "David A. Schleef , Renato Filho "); } static void -gst_gdk_pixbuf_init (GstGdkPixbuf * filter, GstGdkPixbufClass * klass) +gst_gdk_pixbuf_init (GstGdkPixbuf * filter) { filter->sinkpad = gst_pad_new_from_static_template (&gst_gdk_pixbuf_sink_template, "sink"); - gst_pad_set_setcaps_function (filter->sinkpad, - GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_sink_setcaps)); - gst_pad_set_getcaps_function (filter->sinkpad, - GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_sink_getcaps)); + gst_pad_set_query_function (filter->sinkpad, + GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_sink_query)); gst_pad_set_chain_function (filter->sinkpad, GST_DEBUG_FUNCPTR (gst_gdk_pixbuf_chain)); gst_pad_set_event_function (filter->sinkpad, @@ -213,6 +219,55 @@ gst_gdk_pixbuf_init (GstGdkPixbuf * filter, GstGdkPixbufClass * klass) filter->pixbuf_loader = NULL; } +static gboolean +gst_gdk_pixbuf_setup_pool (GstGdkPixbuf * filter, GstVideoInfo * info) +{ + GstCaps *target; + GstQuery *query; + GstBufferPool *pool = NULL; + guint size, min, max, prefix, alignment; + + target = gst_pad_get_current_caps (filter->srcpad); + + /* try to get a bufferpool now */ + /* find a pool for the negotiated caps now */ + query = gst_query_new_allocation (target, TRUE); + + if (gst_pad_peer_query (filter->srcpad, query)) { + /* we got configuration from our peer, parse them */ + gst_query_parse_allocation_params (query, &size, &min, &max, &prefix, + &alignment, &pool); + } else { + size = info->size; + min = max = 0; + prefix = 0; + alignment = 0; + } + + if (pool == NULL) { + GstStructure *config; + + /* we did not get a pool, make one ourselves then */ + pool = gst_buffer_pool_new (); + + config = gst_buffer_pool_get_config (pool); + gst_buffer_pool_config_set (config, target, size, min, max, prefix, + alignment); + gst_buffer_pool_set_config (pool, config); + } + + if (filter->pool) + gst_object_unref (filter->pool); + filter->pool = pool; + + /* and activate */ + gst_buffer_pool_set_active (filter->pool, TRUE); + + gst_caps_unref (target); + + return TRUE; +} + static GstFlowReturn gst_gdk_pixbuf_flush (GstGdkPixbuf * filter) { @@ -221,48 +276,54 @@ gst_gdk_pixbuf_flush (GstGdkPixbuf * filter) int y; guint8 *out_pix; guint8 *in_pix; - int in_rowstride; + int in_rowstride, out_rowstride; GstFlowReturn ret; GstCaps *caps = NULL; + gint width, height; gint n_channels; + GstVideoFrame frame; pixbuf = gdk_pixbuf_loader_get_pixbuf (filter->pixbuf_loader); if (pixbuf == NULL) goto no_pixbuf; - if (filter->image_size == 0) { - filter->width = gdk_pixbuf_get_width (pixbuf); - filter->height = gdk_pixbuf_get_height (pixbuf); - filter->rowstride = gdk_pixbuf_get_rowstride (pixbuf); - filter->image_size = filter->rowstride * filter->height; + width = gdk_pixbuf_get_width (pixbuf); + height = gdk_pixbuf_get_height (pixbuf); + + if (GST_VIDEO_INFO_FORMAT (&filter->info) == GST_VIDEO_FORMAT_UNKNOWN) { + GstVideoInfo info; + GstVideoFormat fmt; + + GST_DEBUG ("Set size to %dx%d", width, height); n_channels = gdk_pixbuf_get_n_channels (pixbuf); switch (n_channels) { case 3: - caps = gst_caps_from_string (GST_VIDEO_CAPS_RGB); + fmt = GST_VIDEO_FORMAT_RGB; break; case 4: - caps = gst_caps_from_string (GST_VIDEO_CAPS_RGBA); + fmt = GST_VIDEO_FORMAT_RGBA; break; default: goto channels_not_supported; } - gst_caps_set_simple (caps, - "width", G_TYPE_INT, filter->width, - "height", G_TYPE_INT, filter->height, - "framerate", GST_TYPE_FRACTION, filter->framerate_numerator, - filter->framerate_denominator, NULL); - GST_DEBUG ("Set size to %dx%d", filter->width, filter->height); + gst_video_info_init (&info); + gst_video_info_set_format (&info, fmt, width, height); + info.fps_n = filter->in_fps_n; + info.fps_d = filter->in_fps_d; + caps = gst_video_info_to_caps (&info); + + filter->info = info; + gst_pad_set_caps (filter->srcpad, caps); gst_caps_unref (caps); + + gst_gdk_pixbuf_setup_pool (filter, &info); } - ret = gst_pad_alloc_buffer_and_set_caps (filter->srcpad, - GST_BUFFER_OFFSET_NONE, - filter->image_size, GST_PAD_CAPS (filter->srcpad), &outbuf); - + ret = gst_buffer_pool_acquire_buffer (filter->pool, &outbuf, NULL); if (ret != GST_FLOW_OK) goto no_buffer; @@ -271,16 +332,20 @@ gst_gdk_pixbuf_flush (GstGdkPixbuf * filter) in_pix = gdk_pixbuf_get_pixels (pixbuf); in_rowstride = gdk_pixbuf_get_rowstride (pixbuf); - out_pix = GST_BUFFER_DATA (outbuf); - /* FIXME, last line might not have rowstride pixels */ - for (y = 0; y < filter->height; y++) { - memcpy (out_pix, in_pix, filter->rowstride); + gst_video_frame_map (&frame, &filter->info, outbuf, GST_MAP_WRITE); + out_pix = GST_VIDEO_FRAME_PLANE_DATA (&frame, 0); + out_rowstride = GST_VIDEO_FRAME_PLANE_STRIDE (&frame, 0); + + for (y = 0; y < height; y++) { + memcpy (out_pix, in_pix, width * GST_VIDEO_FRAME_COMP_PSTRIDE (&frame, 0)); in_pix += in_rowstride; - out_pix += filter->rowstride; + out_pix += out_rowstride; } - GST_DEBUG ("pushing... %d bytes", GST_BUFFER_SIZE (outbuf)); + gst_video_frame_unmap (&frame); + + GST_DEBUG ("pushing... %d bytes", gst_buffer_get_size (outbuf)); ret = gst_pad_push (filter->srcpad, outbuf); if (ret != GST_FLOW_OK) @@ -308,15 +373,24 @@ no_buffer: } static gboolean -gst_gdk_pixbuf_sink_event (GstPad * pad, GstEvent * event) +gst_gdk_pixbuf_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { GstFlowReturn res = GST_FLOW_OK; - gboolean ret = TRUE; + gboolean ret = TRUE, forward = TRUE; GstGdkPixbuf *pixbuf; - pixbuf = GST_GDK_PIXBUF (gst_pad_get_parent (pad)); + pixbuf = GST_GDK_PIXBUF (parent); switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_CAPS: + { + GstCaps *caps; + + gst_event_parse_caps (event, &caps); + ret = gst_gdk_pixbuf_sink_setcaps (pixbuf, caps); + forward = FALSE; + break; + } case GST_EVENT_EOS: if (pixbuf->pixbuf_loader != NULL) { gdk_pixbuf_loader_close (pixbuf->pixbuf_loader, NULL); @@ -329,10 +403,12 @@ gst_gdk_pixbuf_sink_event (GstPad * pad, GstEvent * event) if (res != GST_FLOW_OK && res != GST_FLOW_FLUSHING) { GST_ELEMENT_ERROR (pixbuf, STREAM, FAILED, (NULL), ("Flow: %s", gst_flow_get_name (res))); + forward = FALSE; + ret = FALSE; } } break; - case GST_EVENT_NEWSEGMENT: + case GST_EVENT_SEGMENT: case GST_EVENT_FLUSH_STOP: if (pixbuf->pixbuf_loader != NULL) { gdk_pixbuf_loader_close (pixbuf->pixbuf_loader, NULL); @@ -343,29 +419,24 @@ gst_gdk_pixbuf_sink_event (GstPad * pad, GstEvent * event) default: break; } - - if (res == GST_FLOW_OK) { - ret = gst_pad_event_default (pad, event); + if (forward) { + ret = gst_pad_event_default (pad, parent, event); } else { - ret = FALSE; + gst_event_unref (event); } - - gst_object_unref (pixbuf); - return ret; } static GstFlowReturn -gst_gdk_pixbuf_chain (GstPad * pad, GstBuffer * buf) +gst_gdk_pixbuf_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { GstGdkPixbuf *filter; GstFlowReturn ret = GST_FLOW_OK; GError *error = NULL; GstClockTime timestamp; - guint8 *data; - guint size; + GstMapInfo map; - filter = GST_GDK_PIXBUF (gst_pad_get_parent (pad)); + filter = GST_GDK_PIXBUF (parent); timestamp = GST_BUFFER_TIMESTAMP (buf); @@ -378,23 +449,23 @@ gst_gdk_pixbuf_chain (GstPad * pad, GstBuffer * buf) if (filter->pixbuf_loader == NULL) filter->pixbuf_loader = gdk_pixbuf_loader_new (); - data = GST_BUFFER_DATA (buf); - size = GST_BUFFER_SIZE (buf); + gst_buffer_map (buf, &map, GST_MAP_READ); - GST_LOG_OBJECT (filter, "Writing buffer size %d", size); - if (!gdk_pixbuf_loader_write (filter->pixbuf_loader, data, size, &error)) + GST_LOG_OBJECT (filter, "Writing buffer size %d", (gint) map.size); + if (!gdk_pixbuf_loader_write (filter->pixbuf_loader, map.data, map.size, + &error)) goto error; /* packetised mode? */ - if (filter->framerate_numerator != 0) { + if (filter->in_fps_n != 0) { gdk_pixbuf_loader_close (filter->pixbuf_loader, NULL); ret = gst_gdk_pixbuf_flush (filter); g_object_unref (filter->pixbuf_loader); filter->pixbuf_loader = NULL; } + gst_buffer_unmap (buf, &map); gst_buffer_unref (buf); - gst_object_unref (filter); return ret; @@ -404,40 +475,12 @@ error: GST_ELEMENT_ERROR (filter, STREAM, DECODE, (NULL), ("gdk_pixbuf_loader_write error: %s", error->message)); g_error_free (error); + gst_buffer_unmap (buf, &map); gst_buffer_unref (buf); - gst_object_unref (filter); return GST_FLOW_ERROR; } } -static void -gst_gdk_pixbuf_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - switch (prop_id) { - case ARG_SILENT: - /* filter->silent = g_value_get_boolean (value); */ - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_gdk_pixbuf_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - switch (prop_id) { - case ARG_SILENT: - /* g_value_set_boolean (value, filter->silent); */ - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - static GstStateChangeReturn gst_gdk_pixbuf_change_state (GstElement * element, GstStateChange transition) { @@ -447,8 +490,9 @@ gst_gdk_pixbuf_change_state (GstElement * element, GstStateChange transition) switch (transition) { case GST_STATE_CHANGE_READY_TO_PAUSED: /* default to single image mode, setcaps function might not be called */ - dec->framerate_numerator = 0; - dec->framerate_denominator = 1; + dec->in_fps_n = 0; + dec->in_fps_d = 1; + gst_video_info_init (&dec->info); break; default: break; @@ -460,8 +504,12 @@ gst_gdk_pixbuf_change_state (GstElement * element, GstStateChange transition) switch (transition) { case GST_STATE_CHANGE_PAUSED_TO_READY: - dec->framerate_numerator = 0; - dec->framerate_denominator = 0; + dec->in_fps_n = 0; + dec->in_fps_d = 0; + if (dec->pool) { + gst_buffer_pool_set_active (dec->pool, FALSE); + gst_object_replace ((GstObject **) & dec->pool, NULL); + } break; default: break; diff --git a/ext/gdk_pixbuf/gstgdkpixbuf.h b/ext/gdk_pixbuf/gstgdkpixbuf.h index a4c6ee557c..11ddca3087 100644 --- a/ext/gdk_pixbuf/gstgdkpixbuf.h +++ b/ext/gdk_pixbuf/gstgdkpixbuf.h @@ -49,13 +49,10 @@ struct _GstGdkPixbuf GstClockTime last_timestamp; GdkPixbufLoader *pixbuf_loader; - int width; - int height; - int rowstride; - unsigned int image_size; + gint in_fps_n, in_fps_d; - gint framerate_numerator; - gint framerate_denominator; + GstVideoInfo info; + GstBufferPool *pool; }; struct _GstGdkPixbufClass diff --git a/ext/gdk_pixbuf/gstgdkpixbufsink.c b/ext/gdk_pixbuf/gstgdkpixbufsink.c index 9235386779..509fc7e978 100644 --- a/ext/gdk_pixbuf/gstgdkpixbufsink.c +++ b/ext/gdk_pixbuf/gstgdkpixbufsink.c @@ -103,15 +103,13 @@ enum { PROP_0, - PROP_SEND_MESSAGES, PROP_POST_MESSAGES, PROP_LAST_PIXBUF, PROP_LAST }; -GST_BOILERPLATE (GstGdkPixbufSink, gst_gdk_pixbuf_sink, GstVideoSink, - GST_TYPE_VIDEO_SINK); +G_DEFINE_TYPE (GstGdkPixbufSink, gst_gdk_pixbuf_sink, GST_TYPE_VIDEO_SINK); static void gst_gdk_pixbuf_sink_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); @@ -129,18 +127,20 @@ static GstFlowReturn gst_gdk_pixbuf_sink_preroll (GstBaseSink * bsink, static GdkPixbuf *gst_gdk_pixbuf_sink_get_pixbuf_from_buffer (GstGdkPixbufSink * sink, GstBuffer * buf); -#define WxH ", width = (int) [ 16, 4096 ], height = (int) [ 16, 4096 ]" - static GstStaticPadTemplate pixbufsink_sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB WxH ";" GST_VIDEO_CAPS_RGBA WxH)); + GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("RGB") ";" + GST_VIDEO_CAPS_MAKE ("RGBA")) + ); static void -gst_gdk_pixbuf_sink_base_init (gpointer g_class) +gst_gdk_pixbuf_sink_class_init (GstGdkPixbufSinkClass * klass) { - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + GstBaseSinkClass *basesink_class = GST_BASE_SINK_CLASS (klass); + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gst_element_class_set_details_simple (element_class, "GdkPixbuf sink", "Sink/Video", "Output images as GdkPixbuf objects in bus messages", @@ -148,23 +148,10 @@ gst_gdk_pixbuf_sink_base_init (gpointer g_class) gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&pixbufsink_sink_factory)); -} - -static void -gst_gdk_pixbuf_sink_class_init (GstGdkPixbufSinkClass * klass) -{ - GstBaseSinkClass *basesink_class = GST_BASE_SINK_CLASS (klass); - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->set_property = gst_gdk_pixbuf_sink_set_property; gobject_class->get_property = gst_gdk_pixbuf_sink_get_property; - /* FIXME 0.11, remove in favour of post-messages */ - g_object_class_install_property (gobject_class, PROP_SEND_MESSAGES, - g_param_spec_boolean ("send-messages", "Send Messages", - "Whether to post messages containing pixbufs on the bus " - " (deprecated, use post-messages)", - DEFAULT_SEND_MESSAGES, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * GstGdkPixbuf:post-messages: * @@ -190,8 +177,7 @@ gst_gdk_pixbuf_sink_class_init (GstGdkPixbufSinkClass * klass) } static void -gst_gdk_pixbuf_sink_init (GstGdkPixbufSink * sink, - GstGdkPixbufSinkClass * klass) +gst_gdk_pixbuf_sink_init (GstGdkPixbufSink * sink) { sink->par_n = 0; sink->par_d = 0; @@ -240,46 +226,51 @@ static gboolean gst_gdk_pixbuf_sink_set_caps (GstBaseSink * basesink, GstCaps * caps) { GstGdkPixbufSink *sink = GST_GDK_PIXBUF_SINK (basesink); + GstVideoInfo info; GstVideoFormat fmt; - gint w, h, par_n, par_d; + gint w, h, s, par_n, par_d; GST_LOG_OBJECT (sink, "caps: %" GST_PTR_FORMAT, caps); - if (!gst_video_format_parse_caps (caps, &fmt, &w, &h)) { + if (!gst_video_info_from_caps (&info, caps)) { GST_WARNING_OBJECT (sink, "parse_caps failed"); return FALSE; } - if (!gst_video_parse_caps_pixel_aspect_ratio (caps, &par_n, &par_d)) { - GST_LOG_OBJECT (sink, "no pixel aspect ratio"); - return FALSE; - } + fmt = GST_VIDEO_INFO_FORMAT (&info); + w = GST_VIDEO_INFO_WIDTH (&info); + h = GST_VIDEO_INFO_HEIGHT (&info); + s = GST_VIDEO_INFO_COMP_PSTRIDE (&info, 0); + par_n = GST_VIDEO_INFO_PAR_N (&info); + par_d = GST_VIDEO_INFO_PAR_N (&info); - g_assert ((fmt == GST_VIDEO_FORMAT_RGB && - gst_video_format_get_pixel_stride (fmt, 0) == 3) || - (fmt == GST_VIDEO_FORMAT_RGBA && - gst_video_format_get_pixel_stride (fmt, 0) == 4)); + g_assert ((fmt == GST_VIDEO_FORMAT_RGB && s == 3) || + (fmt == GST_VIDEO_FORMAT_RGBA && s == 4)); GST_VIDEO_SINK_WIDTH (sink) = w; GST_VIDEO_SINK_HEIGHT (sink) = h; - sink->rowstride = gst_video_format_get_row_stride (fmt, 0, w); - sink->has_alpha = (fmt == GST_VIDEO_FORMAT_RGBA); - sink->par_n = par_n; sink->par_d = par_d; + sink->has_alpha = GST_VIDEO_INFO_HAS_ALPHA (&info); + GST_INFO_OBJECT (sink, "format : %d", fmt); GST_INFO_OBJECT (sink, "width x height : %d x %d", w, h); GST_INFO_OBJECT (sink, "pixel-aspect-ratio : %d/%d", par_n, par_d); + sink->info = info; + return TRUE; } static void -gst_gdk_pixbuf_sink_pixbuf_destroy_notify (guchar * pixels, GstBuffer * buf) +gst_gdk_pixbuf_sink_pixbuf_destroy_notify (guchar * pixels, + GstVideoFrame * frame) { - gst_buffer_unref (buf); + gst_video_frame_unmap (frame); + gst_buffer_unref (frame->buffer); + g_slice_free (GstVideoFrame, frame); } static GdkPixbuf * @@ -287,24 +278,30 @@ gst_gdk_pixbuf_sink_get_pixbuf_from_buffer (GstGdkPixbufSink * sink, GstBuffer * buf) { GdkPixbuf *pix = NULL; + GstVideoFrame *frame; gint minsize, bytes_per_pixel; g_return_val_if_fail (GST_VIDEO_SINK_WIDTH (sink) > 0, NULL); g_return_val_if_fail (GST_VIDEO_SINK_HEIGHT (sink) > 0, NULL); + frame = g_slice_new0 (GstVideoFrame); + gst_video_frame_map (frame, &sink->info, buf, GST_MAP_READ); + bytes_per_pixel = (sink->has_alpha) ? 4 : 3; /* last row needn't have row padding */ - minsize = (sink->rowstride * (GST_VIDEO_SINK_HEIGHT (sink) - 1)) + + minsize = (GST_VIDEO_FRAME_COMP_STRIDE (frame, 0) * + (GST_VIDEO_SINK_HEIGHT (sink) - 1)) + (bytes_per_pixel * GST_VIDEO_SINK_WIDTH (sink)); - g_return_val_if_fail (GST_BUFFER_SIZE (buf) >= minsize, NULL); + g_return_val_if_fail (gst_buffer_get_size (buf) >= minsize, NULL); - pix = gdk_pixbuf_new_from_data (GST_BUFFER_DATA (buf), + gst_buffer_ref (buf); + pix = gdk_pixbuf_new_from_data (GST_VIDEO_FRAME_COMP_DATA (frame, 0), GDK_COLORSPACE_RGB, sink->has_alpha, 8, GST_VIDEO_SINK_WIDTH (sink), - GST_VIDEO_SINK_HEIGHT (sink), sink->rowstride, + GST_VIDEO_SINK_HEIGHT (sink), GST_VIDEO_FRAME_COMP_STRIDE (frame, 0), (GdkPixbufDestroyNotify) gst_gdk_pixbuf_sink_pixbuf_destroy_notify, - gst_buffer_ref (buf)); + frame); return pix; } @@ -387,7 +384,6 @@ gst_gdk_pixbuf_sink_set_property (GObject * object, guint prop_id, sink = GST_GDK_PIXBUF_SINK (object); switch (prop_id) { - case PROP_SEND_MESSAGES: case PROP_POST_MESSAGES: GST_OBJECT_LOCK (sink); sink->post_messages = g_value_get_boolean (value); @@ -408,7 +404,6 @@ gst_gdk_pixbuf_sink_get_property (GObject * object, guint prop_id, sink = GST_GDK_PIXBUF_SINK (object); switch (prop_id) { - case PROP_SEND_MESSAGES: case PROP_POST_MESSAGES: GST_OBJECT_LOCK (sink); g_value_set_boolean (value, sink->post_messages); diff --git a/ext/gdk_pixbuf/gstgdkpixbufsink.h b/ext/gdk_pixbuf/gstgdkpixbufsink.h index b0eff5e5a8..f42436eaf9 100644 --- a/ext/gdk_pixbuf/gstgdkpixbufsink.h +++ b/ext/gdk_pixbuf/gstgdkpixbufsink.h @@ -21,7 +21,7 @@ #define GST_GDK_PIXBUF_SINK_H #include - +#include #include #include @@ -47,9 +47,9 @@ struct _GstGdkPixbufSink /*< private >*/ /* current caps */ + GstVideoInfo info; gint width; gint height; - gint rowstride; gint par_n; gint par_d; gboolean has_alpha; diff --git a/ext/gdk_pixbuf/pixbufscale.c b/ext/gdk_pixbuf/pixbufscale.c index bedd982524..35af64e6dd 100644 --- a/ext/gdk_pixbuf/pixbufscale.c +++ b/ext/gdk_pixbuf/pixbufscale.c @@ -57,14 +57,14 @@ static GstStaticPadTemplate gst_pixbufscale_src_template = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB) + GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("RGB")) ); static GstStaticPadTemplate gst_pixbufscale_sink_template = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB) + GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("RGB")) ); #define GST_TYPE_PIXBUFSCALE_METHOD (gst_pixbufscale_method_get_type()) @@ -93,28 +93,32 @@ static void gst_pixbufscale_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); static GstCaps *gst_pixbufscale_transform_caps (GstBaseTransform * trans, - GstPadDirection direction, GstCaps * caps); -static gboolean gst_pixbufscale_set_caps (GstBaseTransform * trans, - GstCaps * in, GstCaps * out); -static gboolean gst_pixbufscale_get_unit_size (GstBaseTransform * trans, - GstCaps * caps, guint * size); -static void gst_pixbufscale_fixate_caps (GstBaseTransform * base, + GstPadDirection direction, GstCaps * caps, GstCaps * filter); +static gboolean gst_pixbufscale_set_info (GstVideoFilter * filter, + GstCaps * in, GstVideoInfo * in_info, GstCaps * out, + GstVideoInfo * out_info); +static GstCaps *gst_pixbufscale_fixate_caps (GstBaseTransform * base, GstPadDirection direction, GstCaps * caps, GstCaps * othercaps); -static GstFlowReturn gst_pixbufscale_transform (GstBaseTransform * trans, - GstBuffer * in, GstBuffer * out); -static gboolean gst_pixbufscale_handle_src_event (GstPad * pad, +static GstFlowReturn gst_pixbufscale_transform_frame (GstVideoFilter * filter, + GstVideoFrame * in, GstVideoFrame * out); +static gboolean gst_pixbufscale_handle_src_event (GstBaseTransform * trans, GstEvent * event); - -static gboolean parse_caps (GstCaps * caps, gint * width, gint * height); - -GST_BOILERPLATE (GstPixbufScale, gst_pixbufscale, GstBaseTransform, - GST_TYPE_BASE_TRANSFORM); +#define gst_pixbufscale_parent_class parent_class +G_DEFINE_TYPE (GstPixbufScale, gst_pixbufscale, GST_TYPE_VIDEO_FILTER); static void -gst_pixbufscale_base_init (gpointer g_class) +gst_pixbufscale_class_init (GstPixbufScaleClass * klass) { - GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + GObjectClass *gobject_class; + GstElementClass *element_class; + GstBaseTransformClass *trans_class; + GstVideoFilterClass *filter_class; + + gobject_class = (GObjectClass *) klass; + element_class = (GstElementClass *) klass; + trans_class = (GstBaseTransformClass *) klass; + filter_class = (GstVideoFilterClass *) klass; gst_element_class_set_details_simple (element_class, "GdkPixbuf image scaler", "Filter/Effect/Video", "Resizes video", @@ -126,16 +130,6 @@ gst_pixbufscale_base_init (gpointer g_class) gst_static_pad_template_get (&gst_pixbufscale_src_template)); gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&gst_pixbufscale_sink_template)); -} - -static void -gst_pixbufscale_class_init (GstPixbufScaleClass * klass) -{ - GObjectClass *gobject_class; - GstBaseTransformClass *trans_class; - - gobject_class = (GObjectClass *) klass; - trans_class = (GstBaseTransformClass *) klass; gobject_class->set_property = gst_pixbufscale_set_property; gobject_class->get_property = gst_pixbufscale_get_property; @@ -148,26 +142,21 @@ gst_pixbufscale_class_init (GstPixbufScaleClass * klass) trans_class->transform_caps = GST_DEBUG_FUNCPTR (gst_pixbufscale_transform_caps); - trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_pixbufscale_set_caps); - trans_class->get_unit_size = - GST_DEBUG_FUNCPTR (gst_pixbufscale_get_unit_size); - trans_class->transform = GST_DEBUG_FUNCPTR (gst_pixbufscale_transform); trans_class->fixate_caps = GST_DEBUG_FUNCPTR (gst_pixbufscale_fixate_caps); + trans_class->src_event = GST_DEBUG_FUNCPTR (gst_pixbufscale_handle_src_event); trans_class->passthrough_on_same_caps = TRUE; + filter_class->set_info = GST_DEBUG_FUNCPTR (gst_pixbufscale_set_info); + filter_class->transform_frame = + GST_DEBUG_FUNCPTR (gst_pixbufscale_transform_frame); + parent_class = g_type_class_peek_parent (klass); } static void -gst_pixbufscale_init (GstPixbufScale * pixbufscale, - GstPixbufScaleClass * kclass) +gst_pixbufscale_init (GstPixbufScale * pixbufscale) { - GstBaseTransform *trans; - GST_DEBUG_OBJECT (pixbufscale, "_init"); - trans = GST_BASE_TRANSFORM (pixbufscale); - - gst_pad_set_event_function (trans->srcpad, gst_pixbufscale_handle_src_event); pixbufscale->method = GST_PIXBUFSCALE_TILES; pixbufscale->gdk_method = GDK_INTERP_TILES; @@ -227,7 +216,7 @@ gst_pixbufscale_get_property (GObject * object, guint prop_id, GValue * value, static GstCaps * gst_pixbufscale_transform_caps (GstBaseTransform * trans, - GstPadDirection direction, GstCaps * caps) + GstPadDirection direction, GstCaps * caps, GstCaps * filter) { GstCaps *ret; int i; @@ -243,76 +232,46 @@ gst_pixbufscale_transform_caps (GstBaseTransform * trans, gst_structure_remove_field (structure, "pixel-aspect-ratio"); } + if (filter) { + GstCaps *intersection; + + intersection = + gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST); + gst_caps_unref (ret); + ret = intersection; + } + GST_DEBUG_OBJECT (trans, "returning caps: %" GST_PTR_FORMAT, ret); return ret; } static gboolean -parse_caps (GstCaps * caps, gint * width, gint * height) +gst_pixbufscale_set_info (GstVideoFilter * filter, GstCaps * in, + GstVideoInfo * in_info, GstCaps * out, GstVideoInfo * out_info) { - gboolean ret; - GstStructure *structure; + if (in_info->width == out_info->width && in_info->height == out_info->height) { + gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (filter), TRUE); + } else { + gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (filter), FALSE); + } - structure = gst_caps_get_structure (caps, 0); - ret = gst_structure_get_int (structure, "width", width); - ret &= gst_structure_get_int (structure, "height", height); - - return ret; -} - -static gboolean -gst_pixbufscale_set_caps (GstBaseTransform * trans, GstCaps * in, GstCaps * out) -{ - GstPixbufScale *pixbufscale; - gboolean ret; - - pixbufscale = GST_PIXBUFSCALE (trans); - ret = parse_caps (in, &pixbufscale->from_width, &pixbufscale->from_height); - ret &= parse_caps (out, &pixbufscale->to_width, &pixbufscale->to_height); - if (!ret) - goto done; - - pixbufscale->from_stride = GST_ROUND_UP_4 (pixbufscale->from_width * 3); - pixbufscale->from_buf_size = - pixbufscale->from_stride * pixbufscale->from_height; - - pixbufscale->to_stride = GST_ROUND_UP_4 (pixbufscale->to_width * 3); - pixbufscale->to_buf_size = pixbufscale->to_stride * pixbufscale->to_height; - - GST_DEBUG_OBJECT (pixbufscale, "from=%dx%d, size %d -> to=%dx%d, size %d", - pixbufscale->from_width, pixbufscale->from_height, - pixbufscale->from_buf_size, pixbufscale->to_width, pixbufscale->to_height, - pixbufscale->to_buf_size); - -done: - return ret; -} - - -static gboolean -gst_pixbufscale_get_unit_size (GstBaseTransform * trans, - GstCaps * caps, guint * size) -{ - gint width, height; - - g_assert (size); - - if (!parse_caps (caps, &width, &height)) - return FALSE; - - *size = GST_ROUND_UP_4 (width * 3) * height; + GST_DEBUG_OBJECT (filter, "from=%dx%d, size %" G_GSIZE_FORMAT + " -> to=%dx%d, size %" G_GSIZE_FORMAT, + in_info->width, in_info->height, in_info->size, + out_info->width, out_info->height, out_info->size); return TRUE; } -static void +static GstCaps * gst_pixbufscale_fixate_caps (GstBaseTransform * base, GstPadDirection direction, GstCaps * caps, GstCaps * othercaps) { GstStructure *ins, *outs; const GValue *from_par, *to_par; - g_return_if_fail (gst_caps_is_fixed (caps)); + othercaps = gst_caps_make_writable (othercaps); + gst_caps_truncate (othercaps); GST_DEBUG_OBJECT (base, "trying to fixate othercaps %" GST_PTR_FORMAT " based on caps %" GST_PTR_FORMAT, othercaps, caps); @@ -337,7 +296,7 @@ gst_pixbufscale_fixate_caps (GstBaseTransform * base, GstPadDirection direction, if (count == 2) { GST_DEBUG_OBJECT (base, "dimensions already set to %dx%d, not fixating", w, h); - return; + goto done; } gst_structure_get_int (ins, "width", &from_w); @@ -396,33 +355,39 @@ gst_pixbufscale_fixate_caps (GstBaseTransform * base, GstPadDirection direction, } } +done: GST_DEBUG_OBJECT (base, "fixated othercaps to %" GST_PTR_FORMAT, othercaps); + + return othercaps; } static GstFlowReturn -gst_pixbufscale_transform (GstBaseTransform * trans, - GstBuffer * in, GstBuffer * out) +gst_pixbufscale_transform_frame (GstVideoFilter * filter, + GstVideoFrame * in, GstVideoFrame * out) { GstPixbufScale *scale; GdkPixbuf *src_pixbuf, *dest_pixbuf; - scale = GST_PIXBUFSCALE (trans); + scale = GST_PIXBUFSCALE (filter); src_pixbuf = - gdk_pixbuf_new_from_data (GST_BUFFER_DATA (in), GDK_COLORSPACE_RGB, FALSE, - 8, scale->from_width, scale->from_height, - GST_RGB24_ROWSTRIDE (scale->from_width), NULL, NULL); + gdk_pixbuf_new_from_data (GST_VIDEO_FRAME_COMP_DATA (in, 0), + GDK_COLORSPACE_RGB, FALSE, 8, GST_VIDEO_FRAME_WIDTH (in), + GST_VIDEO_FRAME_HEIGHT (in), + GST_VIDEO_FRAME_COMP_STRIDE (in, 0), NULL, NULL); dest_pixbuf = - gdk_pixbuf_new_from_data (GST_BUFFER_DATA (out), GDK_COLORSPACE_RGB, - FALSE, 8, scale->to_width, scale->to_height, - GST_RGB24_ROWSTRIDE (scale->to_width), NULL, NULL); + gdk_pixbuf_new_from_data (GST_VIDEO_FRAME_COMP_DATA (out, 0), + GDK_COLORSPACE_RGB, FALSE, 8, GST_VIDEO_FRAME_WIDTH (out), + GST_VIDEO_FRAME_HEIGHT (out), + GST_VIDEO_FRAME_COMP_STRIDE (out, 0), NULL, NULL); gdk_pixbuf_scale (src_pixbuf, dest_pixbuf, 0, 0, - scale->to_width, - scale->to_height, 0, 0, - (double) scale->to_width / scale->from_width, - (double) scale->to_height / scale->from_height, scale->gdk_method); + GST_VIDEO_FRAME_WIDTH (out), + GST_VIDEO_FRAME_HEIGHT (out), 0, 0, + (double) GST_VIDEO_FRAME_WIDTH (out) / GST_VIDEO_FRAME_WIDTH (in), + (double) GST_VIDEO_FRAME_HEIGHT (out) / GST_VIDEO_FRAME_HEIGHT (in), + scale->gdk_method); g_object_unref (src_pixbuf); g_object_unref (dest_pixbuf); @@ -431,14 +396,14 @@ gst_pixbufscale_transform (GstBaseTransform * trans, } static gboolean -gst_pixbufscale_handle_src_event (GstPad * pad, GstEvent * event) +gst_pixbufscale_handle_src_event (GstBaseTransform * trans, GstEvent * event) { GstPixbufScale *pixbufscale; gboolean ret; double a; GstStructure *structure; - pixbufscale = GST_PIXBUFSCALE (gst_pad_get_parent (pad)); + pixbufscale = GST_PIXBUFSCALE (trans); GST_DEBUG_OBJECT (pixbufscale, "handling %s event", GST_EVENT_TYPE_NAME (event)); @@ -462,9 +427,7 @@ gst_pixbufscale_handle_src_event (GstPad * pad, GstEvent * event) break; } - ret = gst_pad_event_default (pad, event); - - gst_object_unref (pixbufscale); + ret = GST_BASE_TRANSFORM_CLASS (parent_class)->src_event (trans, event); return ret; } diff --git a/ext/gdk_pixbuf/pixbufscale.h b/ext/gdk_pixbuf/pixbufscale.h index 3e40477724..0b3afcb561 100644 --- a/ext/gdk_pixbuf/pixbufscale.h +++ b/ext/gdk_pixbuf/pixbufscale.h @@ -25,6 +25,8 @@ #include #include +#include + #include G_BEGIN_DECLS @@ -52,7 +54,7 @@ typedef struct _GstPixbufScale GstPixbufScale; typedef struct _GstPixbufScaleClass GstPixbufScaleClass; struct _GstPixbufScale { - GstBaseTransform element; + GstVideoFilter element; /* video state */ gint to_width; @@ -72,7 +74,7 @@ struct _GstPixbufScale { }; struct _GstPixbufScaleClass { - GstBaseTransformClass parent_class; + GstVideoFilterClass parent_class; }; GType gst_pixbufscale_get_type(void); diff --git a/ext/jack/gstjack.c b/ext/jack/gstjack.c index 019bef9f8d..680a12d5d9 100644 --- a/ext/jack/gstjack.c +++ b/ext/jack/gstjack.c @@ -52,16 +52,14 @@ gst_jack_transport_get_type (void) static volatile gsize type = 0; if (g_once_init_enter (&type)) { - static const GEnumValue enum_values[] = { - {GST_JACK_TRANSPORT_AUTONOMOUS, - "No transport support", "autonomous"}, + static const GFlagsValue flag_values[] = { {GST_JACK_TRANSPORT_MASTER, "Start and stop transport with state changes", "master"}, {GST_JACK_TRANSPORT_SLAVE, "Follow transport state changes", "slave"}, {0, NULL, NULL}, }; - GType tmp = g_enum_register_static ("GstJackTransport", enum_values); + GType tmp = g_flags_register_static ("GstJackTransport", flag_values); g_once_init_leave (&type, tmp); } return (GType) type; diff --git a/ext/jack/gstjack.h b/ext/jack/gstjack.h index 15233ca5c0..1291bc7e73 100644 --- a/ext/jack/gstjack.h +++ b/ext/jack/gstjack.h @@ -53,9 +53,9 @@ typedef enum { * client behaviour regarding to the transport mechanism. */ typedef enum { - GST_JACK_TRANSPORT_AUTONOMOUS, - GST_JACK_TRANSPORT_MASTER, - GST_JACK_TRANSPORT_SLAVE + GST_JACK_TRANSPORT_AUTONOMOUS = 0, + GST_JACK_TRANSPORT_MASTER = (1 << 0), + GST_JACK_TRANSPORT_SLAVE = (1 << 1), } GstJackTransport; typedef jack_default_audio_sample_t sample_t; diff --git a/ext/jack/gstjackaudioclient.c b/ext/jack/gstjackaudioclient.c index 79a24c38dd..f7f6be6c14 100644 --- a/ext/jack/gstjackaudioclient.c +++ b/ext/jack/gstjackaudioclient.c @@ -88,10 +88,10 @@ static gboolean jack_handle_transport_change (GstJackAudioClient * client, GstState state) { GstObject *obj = GST_OBJECT_PARENT (client->user_data); - GstJackTransport mode; + guint mode; g_object_get (obj, "transport", &mode, NULL); - if ((mode == GST_JACK_TRANSPORT_SLAVE) && (GST_STATE (obj) != state)) { + if ((mode & GST_JACK_TRANSPORT_SLAVE) && (GST_STATE (obj) != state)) { GST_INFO_OBJECT (obj, "requesting state change: %s", gst_element_state_get_name (state)); gst_element_post_message (GST_ELEMENT (obj), diff --git a/ext/jack/gstjackaudiosink.c b/ext/jack/gstjackaudiosink.c index c4b3afdd50..f57e86ca41 100644 --- a/ext/jack/gstjackaudiosink.c +++ b/ext/jack/gstjackaudiosink.c @@ -564,7 +564,7 @@ gst_jack_ring_buffer_start (GstAudioRingBuffer * buf) GST_DEBUG_OBJECT (sink, "start"); - if (sink->transport == GST_JACK_TRANSPORT_MASTER) { + if (sink->transport & GST_JACK_TRANSPORT_MASTER) { jack_client_t *client; client = gst_jack_audio_client_get_client (sink->client); @@ -583,7 +583,7 @@ gst_jack_ring_buffer_pause (GstAudioRingBuffer * buf) GST_DEBUG_OBJECT (sink, "pause"); - if (sink->transport == GST_JACK_TRANSPORT_MASTER) { + if (sink->transport & GST_JACK_TRANSPORT_MASTER) { jack_client_t *client; client = gst_jack_audio_client_get_client (sink->client); @@ -602,7 +602,7 @@ gst_jack_ring_buffer_stop (GstAudioRingBuffer * buf) GST_DEBUG_OBJECT (sink, "stop"); - if (sink->transport == GST_JACK_TRANSPORT_MASTER) { + if (sink->transport & GST_JACK_TRANSPORT_MASTER) { jack_client_t *client; client = gst_jack_audio_client_get_client (sink->client); @@ -761,7 +761,7 @@ gst_jack_audio_sink_class_init (GstJackAudioSinkClass * klass) * Since: 0.10.31 */ g_object_class_install_property (gobject_class, PROP_TRANSPORT, - g_param_spec_enum ("transport", "Transport mode", + g_param_spec_flags ("transport", "Transport mode", "Jack transport behaviour of the client", GST_TYPE_JACK_TRANSPORT, DEFAULT_PROP_TRANSPORT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -840,7 +840,7 @@ gst_jack_audio_sink_set_property (GObject * object, guint prop_id, } break; case PROP_TRANSPORT: - sink->transport = g_value_get_enum (value); + sink->transport = g_value_get_flags (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -870,7 +870,7 @@ gst_jack_audio_sink_get_property (GObject * object, guint prop_id, g_value_set_boxed (value, sink->jclient); break; case PROP_TRANSPORT: - g_value_set_enum (value, sink->transport); + g_value_set_flags (value, sink->transport); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); diff --git a/ext/jack/gstjackaudiosink.h b/ext/jack/gstjackaudiosink.h index 2073286767..e8b28903a3 100644 --- a/ext/jack/gstjackaudiosink.h +++ b/ext/jack/gstjackaudiosink.h @@ -59,7 +59,7 @@ struct _GstJackAudioSink { gchar *server; jack_client_t *jclient; gchar *client_name; - GstJackTransport transport; + guint transport; /* our client */ GstJackAudioClient *client; diff --git a/ext/jack/gstjackaudiosrc.c b/ext/jack/gstjackaudiosrc.c index d0e7646a64..343357de9c 100644 --- a/ext/jack/gstjackaudiosrc.c +++ b/ext/jack/gstjackaudiosrc.c @@ -576,7 +576,7 @@ gst_jack_ring_buffer_start (GstAudioRingBuffer * buf) GST_DEBUG_OBJECT (src, "start"); - if (src->transport == GST_JACK_TRANSPORT_MASTER) { + if (src->transport & GST_JACK_TRANSPORT_MASTER) { jack_client_t *client; client = gst_jack_audio_client_get_client (src->client); @@ -595,7 +595,7 @@ gst_jack_ring_buffer_pause (GstAudioRingBuffer * buf) GST_DEBUG_OBJECT (src, "pause"); - if (src->transport == GST_JACK_TRANSPORT_MASTER) { + if (src->transport & GST_JACK_TRANSPORT_MASTER) { jack_client_t *client; client = gst_jack_audio_client_get_client (src->client); @@ -614,7 +614,7 @@ gst_jack_ring_buffer_stop (GstAudioRingBuffer * buf) GST_DEBUG_OBJECT (src, "stop"); - if (src->transport == GST_JACK_TRANSPORT_MASTER) { + if (src->transport & GST_JACK_TRANSPORT_MASTER) { jack_client_t *client; client = gst_jack_audio_client_get_client (src->client); @@ -782,7 +782,7 @@ gst_jack_audio_src_class_init (GstJackAudioSrcClass * klass) * Since: 0.10.31 */ g_object_class_install_property (gobject_class, PROP_TRANSPORT, - g_param_spec_enum ("transport", "Transport mode", + g_param_spec_flags ("transport", "Transport mode", "Jack transport behaviour of the client", GST_TYPE_JACK_TRANSPORT, DEFAULT_PROP_TRANSPORT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -859,7 +859,7 @@ gst_jack_audio_src_set_property (GObject * object, guint prop_id, } break; case PROP_TRANSPORT: - src->transport = g_value_get_enum (value); + src->transport = g_value_get_flags (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -887,7 +887,7 @@ gst_jack_audio_src_get_property (GObject * object, guint prop_id, g_value_set_boxed (value, src->jclient); break; case PROP_TRANSPORT: - g_value_set_enum (value, src->transport); + g_value_set_flags (value, src->transport); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); diff --git a/ext/jack/gstjackaudiosrc.h b/ext/jack/gstjackaudiosrc.h index ed8f593332..20d78aeef7 100644 --- a/ext/jack/gstjackaudiosrc.h +++ b/ext/jack/gstjackaudiosrc.h @@ -72,11 +72,11 @@ struct _GstJackAudioSrc GstCaps *caps; /* properties */ - GstJackConnect connect; + GstJackConnect connect; gchar *server; jack_client_t *jclient; gchar *client_name; - GstJackTransport transport; + guint transport; /* our client */ GstJackAudioClient *client; diff --git a/ext/pulse/pulsemixerctrl.h b/ext/pulse/pulsemixerctrl.h index 077b8841aa..dbb0f99aa1 100644 --- a/ext/pulse/pulsemixerctrl.h +++ b/ext/pulse/pulsemixerctrl.h @@ -92,7 +92,7 @@ void gst_pulsemixer_ctrl_set_record (GstPulseMixerCtrl * mixer, GstMixerTrack * track, gboolean record); GstMixerFlags gst_pulsemixer_ctrl_get_mixer_flags (GstPulseMixerCtrl * mixer); -#define GST_IMPLEMENT_PULSEMIXER_CTRL_METHODS(Type, interface_as_function) \ +#define GST_IMPLEMENT_PULSEMIXER_CTRL_METHODS(Type, interface_as_function) \ static const GList* \ interface_as_function ## _list_tracks (GstMixer * mixer) \ { \ @@ -155,19 +155,23 @@ interface_as_function ## _get_mixer_flags (GstMixer * mixer) g_return_val_if_fail (this != NULL, GST_MIXER_FLAG_NONE); \ g_return_val_if_fail (this->mixer != NULL, GST_MIXER_FLAG_NONE); \ \ - return gst_pulsemixer_ctrl_get_mixer_flags (this->mixer); \ + return gst_pulsemixer_ctrl_get_mixer_flags (this->mixer); \ } \ -static void \ -interface_as_function ## _mixer_interface_init (GstMixerInterface * iface) \ +static GstMixerType \ +interface_as_function ## _get_mixer_type (GstMixer * mixer) \ +{ \ + return GST_MIXER_HARDWARE; \ +} \ +static void \ +interface_as_function ## _mixer_interface_init (GstMixerInterface * iface) \ { \ - GST_MIXER_TYPE (iface) = GST_MIXER_HARDWARE; \ - \ iface->list_tracks = interface_as_function ## _list_tracks; \ iface->set_volume = interface_as_function ## _set_volume; \ iface->get_volume = interface_as_function ## _get_volume; \ iface->set_mute = interface_as_function ## _set_mute; \ iface->set_record = interface_as_function ## _set_record; \ - iface->get_mixer_flags = interface_as_function ## _get_mixer_flags; \ + iface->get_mixer_flags = interface_as_function ## _get_mixer_flags; \ + iface->get_mixer_type = interface_as_function ## _get_mixer_type; \ } G_END_DECLS diff --git a/ext/pulse/pulseprobe.c b/ext/pulse/pulseprobe.c index 55f02005e8..06e0986222 100644 --- a/ext/pulse/pulseprobe.c +++ b/ext/pulse/pulseprobe.c @@ -21,6 +21,10 @@ * USA. */ +/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray + * with newer GLib versions (>= 2.31.0) */ +#define GLIB_DISABLE_DEPRECATION_WARNINGS + #ifdef HAVE_CONFIG_H #include "config.h" #endif diff --git a/ext/speex/gstspeexenc.c b/ext/speex/gstspeexenc.c index 9023ec5e82..32e39fb6ce 100644 --- a/ext/speex/gstspeexenc.c +++ b/ext/speex/gstspeexenc.c @@ -530,7 +530,7 @@ gst_speex_enc_sink_event (GstAudioEncoder * benc, GstEvent * event) } /* we only peeked, let base class handle it */ - return FALSE; + return GST_AUDIO_ENCODER_CLASS (parent_class)->event (benc, event); } static GstFlowReturn diff --git a/ext/wavpack/Makefile.am b/ext/wavpack/Makefile.am index 70d2431468..7c748da163 100644 --- a/ext/wavpack/Makefile.am +++ b/ext/wavpack/Makefile.am @@ -3,7 +3,6 @@ plugin_LTLIBRARIES = libgstwavpack.la libgstwavpack_la_SOURCES = \ gstwavpack.c \ gstwavpackcommon.c \ - gstwavpackparse.c \ gstwavpackdec.c \ gstwavpackenc.c \ gstwavpackstreamreader.c @@ -16,7 +15,6 @@ libgstwavpack_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstwavpack_la_LIBTOOLFLAGS = --tag=disable-static noinst_HEADERS = \ - gstwavpackparse.h \ gstwavpackdec.h \ gstwavpackenc.h \ gstwavpackcommon.h \ diff --git a/ext/wavpack/gstwavpack.c b/ext/wavpack/gstwavpack.c index b01f443d29..6f765f7f97 100644 --- a/ext/wavpack/gstwavpack.c +++ b/ext/wavpack/gstwavpack.c @@ -25,7 +25,6 @@ #include -#include "gstwavpackparse.h" #include "gstwavpackdec.h" #include "gstwavpackenc.h" @@ -44,8 +43,7 @@ plugin_init (GstPlugin * plugin) bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); #endif - return (gst_wavpack_parse_plugin_init (plugin) - && gst_wavpack_dec_plugin_init (plugin) + return (gst_wavpack_dec_plugin_init (plugin) && gst_wavpack_enc_plugin_init (plugin)); } diff --git a/ext/wavpack/gstwavpackcommon.c b/ext/wavpack/gstwavpackcommon.c index 252b64cc23..c38447079e 100644 --- a/ext/wavpack/gstwavpackcommon.c +++ b/ext/wavpack/gstwavpackcommon.c @@ -29,7 +29,6 @@ #include #include -#include GST_DEBUG_CATEGORY_EXTERN (wavpack_debug); #define GST_CAT_DEFAULT wavpack_debug @@ -147,7 +146,7 @@ static const struct 0x00001, GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT}, { 0x00002, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, { 0x00004, GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER}, { - 0x00008, GST_AUDIO_CHANNEL_POSITION_LFE}, { + 0x00008, GST_AUDIO_CHANNEL_POSITION_LFE1}, { 0x00010, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT}, { 0x00020, GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT}, { 0x00040, GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER}, { @@ -155,37 +154,25 @@ static const struct 0x00100, GST_AUDIO_CHANNEL_POSITION_REAR_CENTER}, { 0x00200, GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT}, { 0x00400, GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT}, { - 0x00800, GST_AUDIO_CHANNEL_POSITION_INVALID}, /* TOP_CENTER */ - { - 0x01000, GST_AUDIO_CHANNEL_POSITION_INVALID}, /* TOP_FRONT_LEFT */ - { - 0x02000, GST_AUDIO_CHANNEL_POSITION_INVALID}, /* TOP_FRONT_CENTER */ - { - 0x04000, GST_AUDIO_CHANNEL_POSITION_INVALID}, /* TOP_FRONT_RIGHT */ - { - 0x08000, GST_AUDIO_CHANNEL_POSITION_INVALID}, /* TOP_BACK_LEFT */ - { - 0x10000, GST_AUDIO_CHANNEL_POSITION_INVALID}, /* TOP_BACK_CENTER */ - { - 0x20000, GST_AUDIO_CHANNEL_POSITION_INVALID} /* TOP_BACK_RIGHT */ + 0x00800, GST_AUDIO_CHANNEL_POSITION_TOP_CENTER}, { + 0x01000, GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_LEFT}, { + 0x02000, GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_CENTER}, { + 0x04000, GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_RIGHT}, { + 0x08000, GST_AUDIO_CHANNEL_POSITION_TOP_REAR_LEFT}, { + 0x10000, GST_AUDIO_CHANNEL_POSITION_TOP_REAR_CENTER}, { + 0x20000, GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT} }; #define MAX_CHANNEL_POSITIONS G_N_ELEMENTS (layout_mapping) gboolean -gst_wavpack_set_channel_layout (GstCaps * caps, gint layout) +gst_wavpack_get_channel_positions (gint num_channels, gint layout, + GstAudioChannelPosition * pos) { - GstAudioChannelPosition pos[MAX_CHANNEL_POSITIONS]; - GstStructure *s; - gint num_channels, i, p; - - s = gst_caps_get_structure (caps, 0); - if (!gst_structure_get_int (s, "channels", &num_channels)) - g_return_val_if_reached (FALSE); + gint i, p; if (num_channels == 1 && layout == 0x00004) { - pos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_MONO; - gst_audio_set_channel_positions (s, pos); + pos[0] = GST_AUDIO_CHANNEL_POSITION_MONO; return TRUE; } @@ -214,7 +201,6 @@ gst_wavpack_set_channel_layout (GstCaps * caps, gint layout) return FALSE; } - gst_audio_set_channel_positions (s, pos); return TRUE; } @@ -242,7 +228,7 @@ gst_wavpack_get_channel_mask_from_positions (GstAudioChannelPosition * pos, gint channel_mask = 0; gint i, j; - if (nchannels == 1 && pos[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_MONO) { + if (nchannels == 1 && pos[0] == GST_AUDIO_CHANNEL_POSITION_MONO) { channel_mask = 0x00000004; return channel_mask; } diff --git a/ext/wavpack/gstwavpackcommon.h b/ext/wavpack/gstwavpackcommon.h index 6a9e51609d..4f05683549 100644 --- a/ext/wavpack/gstwavpackcommon.h +++ b/ext/wavpack/gstwavpackcommon.h @@ -24,7 +24,7 @@ #define __GST_WAVPACK_COMMON_H__ #include -#include +#include #include typedef struct @@ -67,7 +67,7 @@ gboolean gst_wavpack_read_header (WavpackHeader * header, guint8 * buf); gboolean gst_wavpack_read_metadata (GstWavpackMetadata * meta, guint8 * header_data, guint8 ** p_data); gint gst_wavpack_get_default_channel_mask (gint nchannels); -gboolean gst_wavpack_set_channel_layout (GstCaps * caps, gint layout); +gboolean gst_wavpack_get_channel_positions (gint nchannels, gint layout, GstAudioChannelPosition *pos); GstAudioChannelPosition *gst_wavpack_get_default_channel_positions (gint nchannels); gint gst_wavpack_get_channel_mask_from_positions (GstAudioChannelPosition *pos, gint nchannels); gboolean gst_wavpack_set_channel_mapping (GstAudioChannelPosition *pos, gint nchannels, gint8 *channel_mapping); diff --git a/ext/wavpack/gstwavpackdec.c b/ext/wavpack/gstwavpackdec.c index f7c96ba14d..5673b7d604 100644 --- a/ext/wavpack/gstwavpackdec.c +++ b/ext/wavpack/gstwavpackdec.c @@ -44,7 +44,6 @@ #include #include -#include #include #include @@ -55,8 +54,6 @@ #include "gstwavpackstreamreader.h" -#define WAVPACK_DEC_MAX_ERRORS 16 - GST_DEBUG_CATEGORY_STATIC (gst_wavpack_dec_debug); #define GST_CAT_DEFAULT gst_wavpack_dec_debug @@ -64,7 +61,7 @@ static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS ("audio/x-wavpack, " - "width = (int) [ 1, 32 ], " + "depth = (int) [ 1, 32 ], " "channels = (int) [ 1, 8 ], " "rate = (int) [ 6000, 192000 ], " "framed = (boolean) true") ); @@ -72,28 +69,41 @@ static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-raw-int, " - "width = (int) 32, " - "depth = (int) [ 1, 32 ], " + GST_STATIC_CAPS ("audio/x-raw, " + "format = (string) S8, " + "layout = (string) interleaved, " "channels = (int) [ 1, 8 ], " - "rate = (int) [ 6000, 192000 ], " - "endianness = (int) BYTE_ORDER, " "signed = (boolean) true") + "rate = (int) [ 6000, 192000 ]; " + "audio/x-raw, " + "format = (string) " GST_AUDIO_NE (S16) ", " + "layout = (string) interleaved, " + "channels = (int) [ 1, 8 ], " + "rate = (int) [ 6000, 192000 ]; " + "audio/x-raw, " + "format = (string) " GST_AUDIO_NE (S32) ", " + "layout = (string) interleaved, " + "channels = (int) [ 1, 8 ], " "rate = (int) [ 6000, 192000 ]") ); -static GstFlowReturn gst_wavpack_dec_chain (GstPad * pad, GstBuffer * buffer); -static gboolean gst_wavpack_dec_sink_set_caps (GstPad * pad, GstCaps * caps); -static gboolean gst_wavpack_dec_sink_event (GstPad * pad, GstEvent * event); +static gboolean gst_wavpack_dec_start (GstAudioDecoder * dec); +static gboolean gst_wavpack_dec_stop (GstAudioDecoder * dec); +static gboolean gst_wavpack_dec_set_format (GstAudioDecoder * dec, + GstCaps * caps); +static GstFlowReturn gst_wavpack_dec_handle_frame (GstAudioDecoder * dec, + GstBuffer * buffer); + static void gst_wavpack_dec_finalize (GObject * object); -static GstStateChangeReturn gst_wavpack_dec_change_state (GstElement * element, - GstStateChange transition); static void gst_wavpack_dec_post_tags (GstWavpackDec * dec); -GST_BOILERPLATE (GstWavpackDec, gst_wavpack_dec, GstElement, GST_TYPE_ELEMENT); +#define gst_wavpack_dec_parent_class parent_class +G_DEFINE_TYPE (GstWavpackDec, gst_wavpack_dec, GST_TYPE_AUDIO_DECODER); static void -gst_wavpack_dec_base_init (gpointer klass) +gst_wavpack_dec_class_init (GstWavpackDecClass * klass) { - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + GObjectClass *gobject_class = (GObjectClass *) klass; + GstElementClass *element_class = (GstElementClass *) (klass); + GstAudioDecoderClass *base_class = (GstAudioDecoderClass *) (klass); gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&src_factory)); @@ -104,17 +114,13 @@ gst_wavpack_dec_base_init (gpointer klass) "Decodes Wavpack audio data", "Arwed v. Merkatz , " "Sebastian Dröge "); -} -static void -gst_wavpack_dec_class_init (GstWavpackDecClass * klass) -{ - GObjectClass *gobject_class = (GObjectClass *) klass; - GstElementClass *gstelement_class = (GstElementClass *) klass; - - gstelement_class->change_state = - GST_DEBUG_FUNCPTR (gst_wavpack_dec_change_state); gobject_class->finalize = gst_wavpack_dec_finalize; + + base_class->start = GST_DEBUG_FUNCPTR (gst_wavpack_dec_start); + base_class->stop = GST_DEBUG_FUNCPTR (gst_wavpack_dec_stop); + base_class->set_format = GST_DEBUG_FUNCPTR (gst_wavpack_dec_set_format); + base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_wavpack_dec_handle_frame); } static void @@ -123,33 +129,15 @@ gst_wavpack_dec_reset (GstWavpackDec * dec) dec->wv_id.buffer = NULL; dec->wv_id.position = dec->wv_id.length = 0; - dec->error_count = 0; - dec->channels = 0; dec->channel_mask = 0; dec->sample_rate = 0; dec->depth = 0; - - gst_segment_init (&dec->segment, GST_FORMAT_TIME); - dec->next_block_index = 0; } static void -gst_wavpack_dec_init (GstWavpackDec * dec, GstWavpackDecClass * gklass) +gst_wavpack_dec_init (GstWavpackDec * dec) { - dec->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink"); - gst_pad_set_chain_function (dec->sinkpad, - GST_DEBUG_FUNCPTR (gst_wavpack_dec_chain)); - gst_pad_set_setcaps_function (dec->sinkpad, - GST_DEBUG_FUNCPTR (gst_wavpack_dec_sink_set_caps)); - gst_pad_set_event_function (dec->sinkpad, - GST_DEBUG_FUNCPTR (gst_wavpack_dec_sink_event)); - gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad); - - dec->srcpad = gst_pad_new_from_static_template (&src_factory, "src"); - gst_pad_use_fixed_caps (dec->srcpad); - gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad); - dec->context = NULL; dec->stream_reader = gst_wavpack_stream_reader_new (); @@ -168,54 +156,85 @@ gst_wavpack_dec_finalize (GObject * object) } static gboolean -gst_wavpack_dec_sink_set_caps (GstPad * pad, GstCaps * caps) +gst_wavpack_dec_start (GstAudioDecoder * dec) { - GstWavpackDec *dec = GST_WAVPACK_DEC (gst_pad_get_parent (pad)); - GstStructure *structure = gst_caps_get_structure (caps, 0); + GST_DEBUG_OBJECT (dec, "start"); - /* Check if we can set the caps here already */ - if (gst_structure_get_int (structure, "channels", &dec->channels) && - gst_structure_get_int (structure, "rate", &dec->sample_rate) && - gst_structure_get_int (structure, "width", &dec->depth)) { - GstCaps *caps; - GstAudioChannelPosition *pos; + /* never mind a few errors */ + gst_audio_decoder_set_max_errors (dec, 16); + /* don't bother us with flushing */ + gst_audio_decoder_set_drainable (dec, FALSE); + /* aim for some perfect timestamping */ + gst_audio_decoder_set_tolerance (dec, 10 * GST_MSECOND); - caps = gst_caps_new_simple ("audio/x-raw-int", - "rate", G_TYPE_INT, dec->sample_rate, - "channels", G_TYPE_INT, dec->channels, - "depth", G_TYPE_INT, dec->depth, - "width", G_TYPE_INT, 32, - "endianness", G_TYPE_INT, G_BYTE_ORDER, - "signed", G_TYPE_BOOLEAN, TRUE, NULL); + return TRUE; +} - /* If we already have the channel layout set from upstream - * take this */ - if (gst_structure_has_field (structure, "channel-positions")) { - pos = gst_audio_get_channel_positions (structure); - if (pos != NULL && dec->channels > 2) { - GstStructure *new_str = gst_caps_get_structure (caps, 0); +static gboolean +gst_wavpack_dec_stop (GstAudioDecoder * dec) +{ + GstWavpackDec *wpdec = GST_WAVPACK_DEC (dec); - gst_audio_set_channel_positions (new_str, pos); - dec->channel_mask = - gst_wavpack_get_channel_mask_from_positions (pos, dec->channels); - } + GST_DEBUG_OBJECT (dec, "stop"); - if (pos != NULL) - g_free (pos); - } - - GST_DEBUG_OBJECT (dec, "setting caps %" GST_PTR_FORMAT, caps); - - /* should always succeed */ - gst_pad_set_caps (dec->srcpad, caps); - gst_caps_unref (caps); - - /* send GST_TAG_AUDIO_CODEC and GST_TAG_BITRATE tags before something - * is decoded or after the format has changed */ - gst_wavpack_dec_post_tags (dec); + if (wpdec->context) { + WavpackCloseFile (wpdec->context); + wpdec->context = NULL; } - gst_object_unref (dec); + gst_wavpack_dec_reset (wpdec); + + return TRUE; +} + +static void +gst_wavpack_dec_negotiate (GstWavpackDec * dec) +{ + GstAudioInfo info; + GstAudioFormat fmt; + GstAudioChannelPosition pos[64] = { GST_AUDIO_CHANNEL_POSITION_INVALID, }; + + /* arrange for 1, 2 or 4-byte width == depth output */ + dec->width = dec->depth; + switch (dec->depth) { + case 8: + fmt = GST_AUDIO_FORMAT_S8; + break; + case 16: + fmt = _GST_AUDIO_FORMAT_NE (S16); + break; + case 24: + case 32: + fmt = _GST_AUDIO_FORMAT_NE (S32); + dec->width = 32; + break; + default: + g_assert_not_reached (); + break; + } + + g_assert (dec->channel_mask != 0); + + if (!gst_wavpack_get_channel_positions (dec->channels, + dec->channel_mask, pos)) + GST_WARNING_OBJECT (dec, "Failed to set channel layout"); + + gst_audio_info_init (&info); + gst_audio_info_set_format (&info, fmt, dec->sample_rate, dec->channels, pos); + + gst_audio_channel_positions_to_valid_order (info.position, info.channels); + gst_audio_get_channel_reorder_map (info.channels, + info.position, pos, dec->channel_reorder_map); + + /* should always succeed */ + gst_audio_decoder_set_output_format (GST_AUDIO_DECODER (dec), &info); +} + +static gboolean +gst_wavpack_dec_set_format (GstAudioDecoder * bdec, GstCaps * caps) +{ + /* pretty much nothing to do here, + * we'll parse it all from the stream and setup then */ return TRUE; } @@ -227,28 +246,26 @@ gst_wavpack_dec_post_tags (GstWavpackDec * dec) GstFormat format_time = GST_FORMAT_TIME, format_bytes = GST_FORMAT_BYTES; gint64 duration, size; - list = gst_tag_list_new (); - - gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, - GST_TAG_AUDIO_CODEC, "Wavpack", NULL); - /* try to estimate the average bitrate */ - if (gst_pad_query_peer_duration (dec->sinkpad, &format_bytes, &size) && - gst_pad_query_peer_duration (dec->sinkpad, &format_time, &duration) && - size > 0 && duration > 0) { + if (gst_pad_peer_query_duration (GST_AUDIO_DECODER_SINK_PAD (dec), + format_bytes, &size) && + gst_pad_peer_query_duration (GST_AUDIO_DECODER_SINK_PAD (dec), + format_time, &duration) && size > 0 && duration > 0) { guint64 bitrate; + list = gst_tag_list_new_empty (); + bitrate = gst_util_uint64_scale (size, 8 * GST_SECOND, duration); gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, (guint) bitrate, NULL); - } - gst_element_post_message (GST_ELEMENT (dec), - gst_message_new_tag (GST_OBJECT (dec), list)); + gst_element_post_message (GST_ELEMENT (dec), + gst_message_new_tag (GST_OBJECT (dec), list)); + } } static GstFlowReturn -gst_wavpack_dec_chain (GstPad * pad, GstBuffer * buf) +gst_wavpack_dec_handle_frame (GstAudioDecoder * bdec, GstBuffer * buf) { GstWavpackDec *dec; GstBuffer *outbuf = NULL; @@ -256,24 +273,32 @@ gst_wavpack_dec_chain (GstPad * pad, GstBuffer * buf) WavpackHeader wph; int32_t decoded, unpacked_size; gboolean format_changed; + gint width, depth, i, j, max; + gint32 *dec_data = NULL; + guint8 *out_data; + GstMapInfo map, omap; - dec = GST_WAVPACK_DEC (GST_PAD_PARENT (pad)); + dec = GST_WAVPACK_DEC (bdec); + + g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR); + + gst_buffer_map (buf, &map, GST_MAP_READ); /* check input, we only accept framed input with complete chunks */ - if (GST_BUFFER_SIZE (buf) < sizeof (WavpackHeader)) + if (map.size < sizeof (WavpackHeader)) goto input_not_framed; - if (!gst_wavpack_read_header (&wph, GST_BUFFER_DATA (buf))) + if (!gst_wavpack_read_header (&wph, map.data)) goto invalid_header; - if (GST_BUFFER_SIZE (buf) < wph.ckSize + 4 * 1 + 4) + if (map.size < wph.ckSize + 4 * 1 + 4) goto input_not_framed; if (!(wph.flags & INITIAL_BLOCK)) goto input_not_framed; - dec->wv_id.buffer = GST_BUFFER_DATA (buf); - dec->wv_id.length = GST_BUFFER_SIZE (buf); + dec->wv_id.buffer = map.data; + dec->wv_id.length = map.size; dec->wv_id.position = 0; /* create a new wavpack context if there is none yet but if there @@ -285,46 +310,32 @@ gst_wavpack_dec_chain (GstPad * pad, GstBuffer * buf) dec->context = WavpackOpenFileInputEx (dec->stream_reader, &dec->wv_id, NULL, error_msg, OPEN_STREAMING, 0); + /* expect this to work */ if (!dec->context) { - GST_WARNING ("Couldn't decode buffer: %s", error_msg); - dec->error_count++; - if (dec->error_count <= WAVPACK_DEC_MAX_ERRORS) { - goto out; /* just return OK for now */ - } else { - goto decode_error; - } + GST_WARNING_OBJECT (dec, "Couldn't decode buffer: %s", error_msg); + goto context_failed; } } g_assert (dec->context != NULL); - dec->error_count = 0; - format_changed = (dec->sample_rate != WavpackGetSampleRate (dec->context)) || (dec->channels != WavpackGetNumChannels (dec->context)) || - (dec->depth != WavpackGetBitsPerSample (dec->context)) || + (dec->depth != WavpackGetBytesPerSample (dec->context) * 8) || #ifdef WAVPACK_OLD_API (dec->channel_mask != dec->context->config.channel_mask); #else (dec->channel_mask != WavpackGetChannelMask (dec->context)); #endif - if (!GST_PAD_CAPS (dec->srcpad) || format_changed) { - GstCaps *caps; + if (!gst_pad_has_current_caps (GST_AUDIO_DECODER_SRC_PAD (dec)) || + format_changed) { gint channel_mask; dec->sample_rate = WavpackGetSampleRate (dec->context); dec->channels = WavpackGetNumChannels (dec->context); - dec->depth = WavpackGetBitsPerSample (dec->context); - - caps = gst_caps_new_simple ("audio/x-raw-int", - "rate", G_TYPE_INT, dec->sample_rate, - "channels", G_TYPE_INT, dec->channels, - "depth", G_TYPE_INT, dec->depth, - "width", G_TYPE_INT, 32, - "endianness", G_TYPE_INT, G_BYTE_ORDER, - "signed", G_TYPE_BOOLEAN, TRUE, NULL); + dec->depth = WavpackGetBytesPerSample (dec->context) * 8; #ifdef WAVPACK_OLD_API channel_mask = dec->context->config.channel_mask; @@ -336,17 +347,7 @@ gst_wavpack_dec_chain (GstPad * pad, GstBuffer * buf) dec->channel_mask = channel_mask; - /* Only set the channel layout for more than two channels - * otherwise things break unfortunately */ - if (channel_mask != 0 && dec->channels > 2) - if (!gst_wavpack_set_channel_layout (caps, channel_mask)) - GST_WARNING_OBJECT (dec, "Failed to set channel layout"); - - GST_DEBUG_OBJECT (dec, "setting caps %" GST_PTR_FORMAT, caps); - - /* should always succeed */ - gst_pad_set_caps (dec->srcpad, caps); - gst_caps_unref (caps); + gst_wavpack_dec_negotiate (dec); /* send GST_TAG_AUDIO_CODEC and GST_TAG_BITRATE tags before something * is decoded or after the format has changed */ @@ -354,58 +355,97 @@ gst_wavpack_dec_chain (GstPad * pad, GstBuffer * buf) } /* alloc output buffer */ - unpacked_size = 4 * wph.block_samples * dec->channels; - ret = gst_pad_alloc_buffer (dec->srcpad, GST_BUFFER_OFFSET (buf), - unpacked_size, GST_PAD_CAPS (dec->srcpad), &outbuf); - - if (ret != GST_FLOW_OK) - goto out; - - gst_buffer_copy_metadata (outbuf, buf, GST_BUFFER_COPY_TIMESTAMPS); - - /* If we got a DISCONT buffer forward the flag. Nothing else - * has to be done as libwavpack doesn't store state between - * Wavpack blocks */ - if (GST_BUFFER_IS_DISCONT (buf) || dec->next_block_index != wph.block_index) - GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); - - dec->next_block_index = wph.block_index + wph.block_samples; + dec_data = g_malloc (4 * wph.block_samples * dec->channels); /* decode */ - decoded = WavpackUnpackSamples (dec->context, - (int32_t *) GST_BUFFER_DATA (outbuf), wph.block_samples); + decoded = WavpackUnpackSamples (dec->context, dec_data, wph.block_samples); if (decoded != wph.block_samples) goto decode_error; - if ((outbuf = gst_audio_buffer_clip (outbuf, &dec->segment, - dec->sample_rate, 4 * dec->channels))) { - GST_LOG_OBJECT (dec, "pushing buffer with time %" GST_TIME_FORMAT, - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf))); - ret = gst_pad_push (dec->srcpad, outbuf); + unpacked_size = (dec->width / 8) * wph.block_samples * dec->channels; + outbuf = gst_buffer_new_and_alloc (unpacked_size); + + /* legacy; pass along offset, whatever that might entail */ + GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET (buf); + + gst_buffer_map (outbuf, &omap, GST_MAP_WRITE); + out_data = omap.data; + + width = dec->width; + depth = dec->depth; + max = dec->channels * wph.block_samples; + if (width == 8) { + gint8 *outbuffer = (gint8 *) out_data; + gint *reorder_map = dec->channel_reorder_map; + + for (i = 0; i < max; i += dec->channels) { + for (j = 0; j < dec->channels; j++) + *outbuffer++ = (gint8) (dec_data[i + reorder_map[j]]); + } + } else if (width == 16) { + gint16 *outbuffer = (gint16 *) out_data; + gint *reorder_map = dec->channel_reorder_map; + + for (i = 0; i < max; i += dec->channels) { + for (j = 0; j < dec->channels; j++) + *outbuffer++ = (gint16) (dec_data[i + reorder_map[j]]); + } + } else if (dec->width == 32) { + gint32 *outbuffer = (gint32 *) out_data; + gint *reorder_map = dec->channel_reorder_map; + + if (width != depth) { + for (i = 0; i < max; i += dec->channels) { + for (j = 0; j < dec->channels; j++) + *outbuffer++ = + (gint32) (dec_data[i + reorder_map[j]] << (width - depth)); + } + } else { + for (i = 0; i < max; i += dec->channels) { + for (j = 0; j < dec->channels; j++) + *outbuffer++ = (gint32) (dec_data[i + reorder_map[j]]); + } + } + } else { + g_assert_not_reached (); } + gst_buffer_unmap (outbuf, &omap); + gst_buffer_unmap (buf, &map); + buf = NULL; + + g_free (dec_data); + + ret = gst_audio_decoder_finish_frame (bdec, outbuf, 1); + out: + if (buf) + gst_buffer_unmap (buf, &map); if (G_UNLIKELY (ret != GST_FLOW_OK)) { GST_DEBUG_OBJECT (dec, "flow: %s", gst_flow_get_name (ret)); } - gst_buffer_unref (buf); - return ret; /* ERRORS */ input_not_framed: { GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("Expected framed input")); - gst_buffer_unref (buf); - return GST_FLOW_ERROR; + ret = GST_FLOW_ERROR; + goto out; } invalid_header: { GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("Invalid wavpack header")); - gst_buffer_unref (buf); - return GST_FLOW_ERROR; + ret = GST_FLOW_ERROR; + goto out; + } +context_failed: + { + GST_AUDIO_DECODER_ERROR (bdec, 1, LIBRARY, INIT, (NULL), + ("error creating Wavpack context"), ret); + goto out; } decode_error: { @@ -420,95 +460,22 @@ decode_error: } else { reason = "couldn't create decoder context"; } - GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), - ("Failed to decode wavpack stream: %s", reason)); - if (outbuf) - gst_buffer_unref (outbuf); - gst_buffer_unref (buf); - return GST_FLOW_ERROR; + GST_AUDIO_DECODER_ERROR (bdec, 1, STREAM, DECODE, (NULL), + ("decoding error: %s", reason), ret); + g_free (dec_data); + if (ret == GST_FLOW_OK) + gst_audio_decoder_finish_frame (bdec, NULL, 1); + goto out; } } -static gboolean -gst_wavpack_dec_sink_event (GstPad * pad, GstEvent * event) -{ - GstWavpackDec *dec = GST_WAVPACK_DEC (gst_pad_get_parent (pad)); - - GST_LOG_OBJECT (dec, "Received %s event", GST_EVENT_TYPE_NAME (event)); - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_NEWSEGMENT:{ - GstFormat fmt; - gboolean is_update; - gint64 start, end, base; - gdouble rate; - - gst_event_parse_new_segment (event, &is_update, &rate, &fmt, &start, - &end, &base); - if (fmt == GST_FORMAT_TIME) { - GST_DEBUG ("Got NEWSEGMENT event in GST_FORMAT_TIME, passing on (%" - GST_TIME_FORMAT " - %" GST_TIME_FORMAT ")", GST_TIME_ARGS (start), - GST_TIME_ARGS (end)); - gst_segment_set_newsegment (&dec->segment, is_update, rate, fmt, - start, end, base); - } else { - gst_segment_init (&dec->segment, GST_FORMAT_TIME); - } - break; - } - default: - break; - } - - gst_object_unref (dec); - return gst_pad_event_default (pad, event); -} - -static GstStateChangeReturn -gst_wavpack_dec_change_state (GstElement * element, GstStateChange transition) -{ - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - GstWavpackDec *dec = GST_WAVPACK_DEC (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - if (dec->context) { - WavpackCloseFile (dec->context); - dec->context = NULL; - } - - gst_wavpack_dec_reset (dec); - break; - case GST_STATE_CHANGE_READY_TO_NULL: - break; - default: - break; - } - - return ret; -} - gboolean gst_wavpack_dec_plugin_init (GstPlugin * plugin) { if (!gst_element_register (plugin, "wavpackdec", GST_RANK_PRIMARY, GST_TYPE_WAVPACK_DEC)) return FALSE; - GST_DEBUG_CATEGORY_INIT (gst_wavpack_dec_debug, "wavpack_dec", 0, + GST_DEBUG_CATEGORY_INIT (gst_wavpack_dec_debug, "wavpackdec", 0, "Wavpack decoder"); return TRUE; } diff --git a/ext/wavpack/gstwavpackdec.h b/ext/wavpack/gstwavpackdec.h index eb6e4c3bb8..006428ceac 100644 --- a/ext/wavpack/gstwavpackdec.h +++ b/ext/wavpack/gstwavpackdec.h @@ -24,6 +24,7 @@ #define __GST_WAVPACK_DEC_H__ #include +#include #include @@ -45,31 +46,28 @@ typedef struct _GstWavpackDecClass GstWavpackDecClass; struct _GstWavpackDec { - GstElement element; + GstAudioDecoder element; /*< private > */ - GstPad *sinkpad; - GstPad *srcpad; WavpackContext *context; WavpackStreamReader *stream_reader; read_id wv_id; - GstSegment segment; /* used for clipping, TIME format */ - guint32 next_block_index; - gint sample_rate; gint depth; + gint width; gint channels; gint channel_mask; - gint error_count; + gint channel_reorder_map[64]; + }; struct _GstWavpackDecClass { - GstElementClass parent; + GstAudioDecoderClass parent; }; GType gst_wavpack_dec_get_type (void); diff --git a/ext/wavpack/gstwavpackenc.c b/ext/wavpack/gstwavpackenc.c index c871772e73..a2f05351ca 100644 --- a/ext/wavpack/gstwavpackenc.c +++ b/ext/wavpack/gstwavpackenc.c @@ -31,7 +31,7 @@ * |[ * gst-launch audiotestsrc num-buffers=500 ! audioconvert ! wavpackenc ! filesink location=sinewave.wv * ]| This pipeline encodes audio from audiotestsrc into a Wavpack file. The audioconvert element is needed - * as the Wavpack encoder only accepts input with 32 bit width (and every depth between 1 and 32 bits). + * as the Wavpack encoder only accepts input with 32 bit width. * |[ * gst-launch cdda://1 ! audioconvert ! wavpackenc ! filesink location=track1.wv * ]| This pipeline encodes audio from an audio CD into a Wavpack file using @@ -55,12 +55,18 @@ #include "gstwavpackenc.h" #include "gstwavpackcommon.h" -static GstFlowReturn gst_wavpack_enc_chain (GstPad * pad, GstBuffer * buffer); -static gboolean gst_wavpack_enc_sink_set_caps (GstPad * pad, GstCaps * caps); +static gboolean gst_wavpack_enc_start (GstAudioEncoder * enc); +static gboolean gst_wavpack_enc_stop (GstAudioEncoder * enc); +static gboolean gst_wavpack_enc_set_format (GstAudioEncoder * enc, + GstAudioInfo * info); +static GstFlowReturn gst_wavpack_enc_handle_frame (GstAudioEncoder * enc, + GstBuffer * in_buf); +static gboolean gst_wavpack_enc_sink_event (GstAudioEncoder * enc, + GstEvent * event); + static int gst_wavpack_enc_push_block (void *id, void *data, int32_t count); -static gboolean gst_wavpack_enc_sink_event (GstPad * pad, GstEvent * event); -static GstStateChangeReturn gst_wavpack_enc_change_state (GstElement * element, - GstStateChange transition); +static GstFlowReturn gst_wavpack_enc_drain (GstWavpackEnc * enc); + static void gst_wavpack_enc_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_wavpack_enc_get_property (GObject * object, guint prop_id, @@ -84,20 +90,18 @@ GST_DEBUG_CATEGORY_STATIC (gst_wavpack_enc_debug); static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-raw-int, " - "width = (int) 32, " - "depth = (int) [ 1, 32], " - "endianness = (int) BYTE_ORDER, " - "channels = (int) [ 1, 8 ], " - "rate = (int) [ 6000, 192000 ]," "signed = (boolean) TRUE") + GST_STATIC_CAPS ("audio/x-raw, " + "format = (string) " GST_AUDIO_NE (S32) ", " + "layout = (string) interleaved, " + "channels = (int) [ 1, 8 ], " "rate = (int) [ 6000, 192000 ]") ); static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS ("audio/x-wavpack, " - "width = (int) [ 1, 32 ], " - "channels = (int) [ 1, 2 ], " + "depth = (int) [ 1, 32 ], " + "channels = (int) [ 1, 8 ], " "rate = (int) [ 6000, 192000 ], " "framed = (boolean) TRUE") ); @@ -196,26 +200,15 @@ gst_wavpack_enc_joint_stereo_mode_get_type (void) return qtype; } -static void -_do_init (GType object_type) -{ - const GInterfaceInfo preset_interface_info = { - NULL, /* interface_init */ - NULL, /* interface_finalize */ - NULL /* interface_data */ - }; - - g_type_add_interface_static (object_type, GST_TYPE_PRESET, - &preset_interface_info); -} - -GST_BOILERPLATE_FULL (GstWavpackEnc, gst_wavpack_enc, GstElement, - GST_TYPE_ELEMENT, _do_init); +#define gst_wavpack_enc_parent_class parent_class +G_DEFINE_TYPE (GstWavpackEnc, gst_wavpack_enc, GST_TYPE_AUDIO_ENCODER); static void -gst_wavpack_enc_base_init (gpointer klass) +gst_wavpack_enc_class_init (GstWavpackEncClass * klass) { - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + GObjectClass *gobject_class = (GObjectClass *) klass; + GstElementClass *element_class = (GstElementClass *) (klass); + GstAudioEncoderClass *base_class = (GstAudioEncoderClass *) (klass); /* add pad templates */ gst_element_class_add_pad_template (element_class, @@ -230,25 +223,17 @@ gst_wavpack_enc_base_init (gpointer klass) "Codec/Encoder/Audio", "Encodes audio with the Wavpack lossless/lossy audio codec", "Sebastian Dröge "); -} - - -static void -gst_wavpack_enc_class_init (GstWavpackEncClass * klass) -{ - GObjectClass *gobject_class = (GObjectClass *) klass; - GstElementClass *gstelement_class = (GstElementClass *) klass; - - parent_class = g_type_class_peek_parent (klass); - - /* set state change handler */ - gstelement_class->change_state = - GST_DEBUG_FUNCPTR (gst_wavpack_enc_change_state); /* set property handlers */ gobject_class->set_property = gst_wavpack_enc_set_property; gobject_class->get_property = gst_wavpack_enc_get_property; + base_class->start = GST_DEBUG_FUNCPTR (gst_wavpack_enc_start); + base_class->stop = GST_DEBUG_FUNCPTR (gst_wavpack_enc_stop); + base_class->set_format = GST_DEBUG_FUNCPTR (gst_wavpack_enc_set_format); + base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_wavpack_enc_handle_frame); + base_class->event = GST_DEBUG_FUNCPTR (gst_wavpack_enc_sink_event); + /* install all properties */ g_object_class_install_property (gobject_class, ARG_MODE, g_param_spec_enum ("mode", "Encoding mode", @@ -306,6 +291,9 @@ gst_wavpack_enc_reset (GstWavpackEnc * enc) g_checksum_free (enc->md5_context); enc->md5_context = NULL; } + if (enc->pending_segment) + gst_event_unref (enc->pending_segment); + enc->pending_segment = NULL; if (enc->pending_buffer) { gst_buffer_unref (enc->pending_buffer); @@ -330,20 +318,9 @@ gst_wavpack_enc_reset (GstWavpackEnc * enc) } static void -gst_wavpack_enc_init (GstWavpackEnc * enc, GstWavpackEncClass * gclass) +gst_wavpack_enc_init (GstWavpackEnc * enc) { - enc->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink"); - gst_pad_set_setcaps_function (enc->sinkpad, - GST_DEBUG_FUNCPTR (gst_wavpack_enc_sink_set_caps)); - gst_pad_set_chain_function (enc->sinkpad, - GST_DEBUG_FUNCPTR (gst_wavpack_enc_chain)); - gst_pad_set_event_function (enc->sinkpad, - GST_DEBUG_FUNCPTR (gst_wavpack_enc_sink_event)); - gst_element_add_pad (GST_ELEMENT (enc), enc->sinkpad); - - /* setup src pad */ - enc->srcpad = gst_pad_new_from_static_template (&src_factory, "src"); - gst_element_add_pad (GST_ELEMENT (enc), enc->srcpad); + GstAudioEncoder *benc = GST_AUDIO_ENCODER (enc); /* initialize object attributes */ enc->wp_config = NULL; @@ -367,37 +344,53 @@ gst_wavpack_enc_init (GstWavpackEnc * enc, GstWavpackEncClass * gclass) enc->md5 = FALSE; enc->extra_processing = 0; enc->joint_stereo_mode = GST_WAVPACK_JS_MODE_AUTO; + + /* require perfect ts */ + gst_audio_encoder_set_perfect_timestamp (benc, TRUE); +} + + +static gboolean +gst_wavpack_enc_start (GstAudioEncoder * enc) +{ + GST_DEBUG_OBJECT (enc, "start"); + + return TRUE; } static gboolean -gst_wavpack_enc_sink_set_caps (GstPad * pad, GstCaps * caps) +gst_wavpack_enc_stop (GstAudioEncoder * enc) { - GstWavpackEnc *enc = GST_WAVPACK_ENC (gst_pad_get_parent (pad)); - GstStructure *structure = gst_caps_get_structure (caps, 0); + GstWavpackEnc *wpenc = GST_WAVPACK_ENC (enc); + + GST_DEBUG_OBJECT (enc, "stop"); + gst_wavpack_enc_reset (wpenc); + + return TRUE; +} + +static gboolean +gst_wavpack_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info) +{ + GstWavpackEnc *enc = GST_WAVPACK_ENC (benc); GstAudioChannelPosition *pos; + GstAudioChannelPosition opos[64] = { GST_AUDIO_CHANNEL_POSITION_INVALID, }; + GstCaps *caps; + guint64 mask = 0; - if (!gst_structure_get_int (structure, "channels", &enc->channels) || - !gst_structure_get_int (structure, "rate", &enc->samplerate) || - !gst_structure_get_int (structure, "depth", &enc->depth)) { - GST_ELEMENT_ERROR (enc, LIBRARY, INIT, (NULL), - ("got invalid caps: %" GST_PTR_FORMAT, caps)); - gst_object_unref (enc); - return FALSE; - } + /* we may be configured again, but that change should have cleanup context */ + g_assert (enc->wp_context == NULL); + + enc->channels = GST_AUDIO_INFO_CHANNELS (info); + enc->depth = GST_AUDIO_INFO_DEPTH (info); + enc->samplerate = GST_AUDIO_INFO_RATE (info); + + pos = info->position; + g_assert (pos); - pos = gst_audio_get_channel_positions (structure); /* If one channel is NONE they'll be all undefined */ if (pos != NULL && pos[0] == GST_AUDIO_CHANNEL_POSITION_NONE) { - g_free (pos); - pos = NULL; - } - - if (pos == NULL) { - GST_ELEMENT_ERROR (enc, STREAM, FORMAT, (NULL), - ("input has no valid channel layout")); - - gst_object_unref (enc); - return FALSE; + goto invalid_channels; } enc->channel_mask = @@ -405,29 +398,41 @@ gst_wavpack_enc_sink_set_caps (GstPad * pad, GstCaps * caps) enc->need_channel_remap = gst_wavpack_set_channel_mapping (pos, enc->channels, enc->channel_mapping); - g_free (pos); + + /* wavpack caps hold gst mask, not wavpack mask */ + gst_audio_channel_positions_to_mask (opos, enc->channels, &mask); /* set fixed src pad caps now that we know what we will get */ caps = gst_caps_new_simple ("audio/x-wavpack", "channels", G_TYPE_INT, enc->channels, "rate", G_TYPE_INT, enc->samplerate, - "width", G_TYPE_INT, enc->depth, "framed", G_TYPE_BOOLEAN, TRUE, NULL); + "depth", G_TYPE_INT, enc->depth, "framed", G_TYPE_BOOLEAN, TRUE, NULL); - if (!gst_wavpack_set_channel_layout (caps, enc->channel_mask)) - GST_WARNING_OBJECT (enc, "setting channel layout failed"); + if (mask) + gst_caps_set_simple (caps, "channel-mask", GST_TYPE_BITMASK, mask, NULL); - if (!gst_pad_set_caps (enc->srcpad, caps)) { - GST_ELEMENT_ERROR (enc, LIBRARY, INIT, (NULL), - ("setting caps failed: %" GST_PTR_FORMAT, caps)); - gst_caps_unref (caps); - gst_object_unref (enc); - return FALSE; - } - gst_pad_use_fixed_caps (enc->srcpad); + if (!gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc), caps)) + goto setting_src_caps_failed; gst_caps_unref (caps); - gst_object_unref (enc); + + /* no special feedback to base class; should provide all available samples */ + return TRUE; + + /* ERRORS */ +setting_src_caps_failed: + { + GST_DEBUG_OBJECT (enc, + "Couldn't set caps on source pad: %" GST_PTR_FORMAT, caps); + gst_caps_unref (caps); + return FALSE; + } +invalid_channels: + { + GST_DEBUG_OBJECT (enc, "input has invalid channel layout"); + return FALSE; + } } static void @@ -549,22 +554,15 @@ gst_wavpack_enc_push_block (void *id, void *data, int32_t count) GstBuffer *buffer; GstPad *pad; guchar *block = (guchar *) data; + gint samples = 0; - pad = (wid->correction) ? enc->wvcsrcpad : enc->srcpad; + pad = (wid->correction) ? enc->wvcsrcpad : GST_AUDIO_ENCODER_SRC_PAD (enc); flow = - (wid->correction) ? &enc->wvcsrcpad_last_return : &enc-> - srcpad_last_return; + (wid->correction) ? &enc-> + wvcsrcpad_last_return : &enc->srcpad_last_return; - *flow = gst_pad_alloc_buffer_and_set_caps (pad, GST_BUFFER_OFFSET_NONE, - count, GST_PAD_CAPS (pad), &buffer); - - if (*flow != GST_FLOW_OK) { - GST_WARNING_OBJECT (enc, "flow on %s:%s = %s", - GST_DEBUG_PAD_NAME (pad), gst_flow_get_name (*flow)); - return FALSE; - } - - g_memmove (GST_BUFFER_DATA (buffer), block, count); + buffer = gst_buffer_new_and_alloc (count); + gst_buffer_fill (buffer, 0, data, count); if (count > sizeof (WavpackHeader) && memcmp (block, "wvpk", 4) == 0) { /* if it's a Wavpack block set buffer timestamp and duration, etc */ @@ -599,44 +597,50 @@ gst_wavpack_enc_push_block (void *id, void *data, int32_t count) enc->pending_buffer = NULL; enc->pending_offset = 0; - /* if it's the first wavpack block, send a NEW_SEGMENT event */ - if (wph.block_index == 0) { - gst_pad_push_event (pad, - gst_event_new_new_segment (FALSE, - 1.0, GST_FORMAT_TIME, 0, GST_BUFFER_OFFSET_NONE, 0)); + /* only send segment on correction pad, + * regular pad is handled normally by baseclass */ + if (wid->correction && enc->pending_segment) { + gst_pad_push_event (pad, enc->pending_segment); + enc->pending_segment = NULL; + } + if (wph.block_index == 0) { /* save header for later reference, so we can re-send it later on * EOS with fixed up values for total sample count etc. */ if (enc->first_block == NULL && !wid->correction) { - enc->first_block = - g_memdup (GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer)); - enc->first_block_size = GST_BUFFER_SIZE (buffer); + GstMapInfo map; + + gst_buffer_map (buffer, &map, GST_MAP_READ); + enc->first_block = g_memdup (map.data, map.size); + enc->first_block_size = map.size; + gst_buffer_unmap (buffer, &map); } } } + samples = wph.block_samples; - /* set buffer timestamp, duration, offset, offset_end from - * the wavpack header */ - GST_BUFFER_TIMESTAMP (buffer) = enc->timestamp_offset + - gst_util_uint64_scale_int (GST_SECOND, wph.block_index, - enc->samplerate); - GST_BUFFER_DURATION (buffer) = - gst_util_uint64_scale_int (GST_SECOND, wph.block_samples, - enc->samplerate); + /* decorate buffer */ + /* NOTE: this will get overwritten by baseclass, but stay for those + * that are pushed directly + * FIXME: add setting to baseclass to avoid overwriting it ?? */ GST_BUFFER_OFFSET (buffer) = wph.block_index; GST_BUFFER_OFFSET_END (buffer) = wph.block_index + wph.block_samples; } else { /* if it's something else set no timestamp and duration on the buffer */ GST_DEBUG_OBJECT (enc, "got %d bytes of unknown data", count); - - GST_BUFFER_TIMESTAMP (buffer) = GST_CLOCK_TIME_NONE; - GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE; } - /* push the buffer and forward errors */ - GST_DEBUG_OBJECT (enc, "pushing buffer with %d bytes", - GST_BUFFER_SIZE (buffer)); - *flow = gst_pad_push (pad, buffer); + if (wid->correction || wid->passthrough) { + /* push the buffer and forward errors */ + GST_DEBUG_OBJECT (enc, "pushing buffer with %d bytes", + gst_buffer_get_size (buffer)); + *flow = gst_pad_push (pad, buffer); + } else { + GST_DEBUG_OBJECT (enc, "handing frame of %d bytes", + gst_buffer_get_size (buffer)); + *flow = gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (enc), buffer, + samples); + } if (*flow != GST_FLOW_OK) { GST_WARNING_OBJECT (enc, "flow on %s:%s = %s", @@ -666,18 +670,26 @@ gst_wavpack_enc_fix_channel_order (GstWavpackEnc * enc, gint32 * data, } static GstFlowReturn -gst_wavpack_enc_chain (GstPad * pad, GstBuffer * buf) +gst_wavpack_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf) { - GstWavpackEnc *enc = GST_WAVPACK_ENC (gst_pad_get_parent (pad)); - uint32_t sample_count = GST_BUFFER_SIZE (buf) / 4; + GstWavpackEnc *enc = GST_WAVPACK_ENC (benc); + uint32_t sample_count; GstFlowReturn ret; + GstMapInfo map; + + /* base class ensures configuration */ + g_return_val_if_fail (enc->depth != 0, GST_FLOW_NOT_NEGOTIATED); /* reset the last returns to GST_FLOW_OK. This is only set to something else * while WavpackPackSamples() or more specific gst_wavpack_enc_push_block() * so not valid anymore */ enc->srcpad_last_return = enc->wvcsrcpad_last_return = GST_FLOW_OK; - GST_DEBUG ("got %u raw samples", sample_count); + if (G_UNLIKELY (!buf)) + return gst_wavpack_enc_drain (enc); + + sample_count = gst_buffer_get_size (buf) / 4; + GST_DEBUG_OBJECT (enc, "got %u raw samples", sample_count); /* check if we already have a valid WavpackContext, otherwise make one */ if (!enc->wp_context) { @@ -685,13 +697,8 @@ gst_wavpack_enc_chain (GstPad * pad, GstBuffer * buf) enc->wp_context = WavpackOpenFileOutput (gst_wavpack_enc_push_block, &enc->wv_id, (enc->correction_mode > 0) ? &enc->wvc_id : NULL); - if (!enc->wp_context) { - GST_ELEMENT_ERROR (enc, LIBRARY, INIT, (NULL), - ("error creating Wavpack context")); - gst_object_unref (enc); - gst_buffer_unref (buf); - return GST_FLOW_ERROR; - } + if (!enc->wp_context) + goto context_failed; /* set the WavpackConfig according to our parameters */ gst_wavpack_enc_set_wp_config (enc); @@ -701,99 +708,36 @@ gst_wavpack_enc_chain (GstPad * pad, GstBuffer * buf) if (!WavpackSetConfiguration (enc->wp_context, enc->wp_config, (uint32_t) (-1)) || !WavpackPackInit (enc->wp_context)) { - GST_ELEMENT_ERROR (enc, LIBRARY, SETTINGS, (NULL), - ("error setting up wavpack encoding context")); WavpackCloseFile (enc->wp_context); - gst_object_unref (enc); - gst_buffer_unref (buf); - return GST_FLOW_ERROR; + goto config_failed; } - GST_DEBUG ("setup of encoding context successfull"); + GST_DEBUG_OBJECT (enc, "setup of encoding context successfull"); } - /* Save the timestamp of the first buffer. This will be later - * used as offset for all following buffers */ - if (enc->timestamp_offset == GST_CLOCK_TIME_NONE) { - if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { - enc->timestamp_offset = GST_BUFFER_TIMESTAMP (buf); - enc->next_ts = GST_BUFFER_TIMESTAMP (buf); - } else { - enc->timestamp_offset = 0; - enc->next_ts = 0; - } - } - - /* Check if we have a continous stream, if not drop some samples or the buffer or - * insert some silence samples */ - if (enc->next_ts != GST_CLOCK_TIME_NONE && - GST_BUFFER_TIMESTAMP (buf) < enc->next_ts) { - guint64 diff = enc->next_ts - GST_BUFFER_TIMESTAMP (buf); - guint64 diff_bytes; - - GST_WARNING_OBJECT (enc, "Buffer is older than previous " - "timestamp + duration (%" GST_TIME_FORMAT "< %" GST_TIME_FORMAT - "), cannot handle. Clipping buffer.", - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), - GST_TIME_ARGS (enc->next_ts)); - - diff_bytes = - GST_CLOCK_TIME_TO_FRAMES (diff, enc->samplerate) * enc->channels * 2; - if (diff_bytes >= GST_BUFFER_SIZE (buf)) { - gst_buffer_unref (buf); - return GST_FLOW_OK; - } - buf = gst_buffer_make_metadata_writable (buf); - GST_BUFFER_DATA (buf) += diff_bytes; - GST_BUFFER_SIZE (buf) -= diff_bytes; - - GST_BUFFER_TIMESTAMP (buf) += diff; - if (GST_BUFFER_DURATION_IS_VALID (buf)) - GST_BUFFER_DURATION (buf) -= diff; - } - - /* Allow a diff of at most 5 ms */ - if (enc->next_ts != GST_CLOCK_TIME_NONE - && GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { - if (GST_BUFFER_TIMESTAMP (buf) != enc->next_ts && - GST_BUFFER_TIMESTAMP (buf) - enc->next_ts > 5 * GST_MSECOND) { - GST_WARNING_OBJECT (enc, - "Discontinuity detected: %" G_GUINT64_FORMAT " > %" G_GUINT64_FORMAT, - GST_BUFFER_TIMESTAMP (buf) - enc->next_ts, 5 * GST_MSECOND); - - WavpackFlushSamples (enc->wp_context); - enc->timestamp_offset += (GST_BUFFER_TIMESTAMP (buf) - enc->next_ts); - } - } - - if (GST_BUFFER_TIMESTAMP_IS_VALID (buf) - && GST_BUFFER_DURATION_IS_VALID (buf)) - enc->next_ts = GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf); - else - enc->next_ts = GST_CLOCK_TIME_NONE; - if (enc->need_channel_remap) { buf = gst_buffer_make_writable (buf); - gst_wavpack_enc_fix_channel_order (enc, (gint32 *) GST_BUFFER_DATA (buf), - sample_count); + gst_buffer_map (buf, &map, GST_MAP_WRITE); + gst_wavpack_enc_fix_channel_order (enc, (gint32 *) map.data, sample_count); + gst_buffer_unmap (buf, &map); } + gst_buffer_map (buf, &map, GST_MAP_READ); + /* if we want to append the MD5 sum to the stream update it here * with the current raw samples */ if (enc->md5) { - g_checksum_update (enc->md5_context, GST_BUFFER_DATA (buf), - GST_BUFFER_SIZE (buf)); + g_checksum_update (enc->md5_context, map.data, map.size); } /* encode and handle return values from encoding */ - if (WavpackPackSamples (enc->wp_context, (int32_t *) GST_BUFFER_DATA (buf), + if (WavpackPackSamples (enc->wp_context, (int32_t *) map.data, sample_count / enc->channels)) { - GST_DEBUG ("encoding samples successful"); + GST_DEBUG_OBJECT (enc, "encoding samples successful"); + gst_buffer_unmap (buf, &map); ret = GST_FLOW_OK; } else { - if ((enc->srcpad_last_return == GST_FLOW_RESEND) || - (enc->wvcsrcpad_last_return == GST_FLOW_RESEND)) { - ret = GST_FLOW_RESEND; - } else if ((enc->srcpad_last_return == GST_FLOW_OK) || + gst_buffer_unmap (buf, &map); + if ((enc->srcpad_last_return == GST_FLOW_OK) || (enc->wvcsrcpad_last_return == GST_FLOW_OK)) { ret = GST_FLOW_OK; } else if ((enc->srcpad_last_return == GST_FLOW_NOT_LINKED) && @@ -803,22 +747,41 @@ gst_wavpack_enc_chain (GstPad * pad, GstBuffer * buf) (enc->wvcsrcpad_last_return == GST_FLOW_FLUSHING)) { ret = GST_FLOW_FLUSHING; } else { - GST_ELEMENT_ERROR (enc, LIBRARY, ENCODE, (NULL), - ("encoding samples failed")); - ret = GST_FLOW_ERROR; + goto encoding_failed; } } - gst_buffer_unref (buf); - gst_object_unref (enc); +exit: return ret; + + /* ERRORS */ +encoding_failed: + { + GST_ELEMENT_ERROR (enc, LIBRARY, ENCODE, (NULL), + ("encoding samples failed")); + ret = GST_FLOW_ERROR; + goto exit; + } +config_failed: + { + GST_ELEMENT_ERROR (enc, LIBRARY, SETTINGS, (NULL), + ("error setting up wavpack encoding context")); + ret = GST_FLOW_ERROR; + goto exit; + } +context_failed: + { + GST_ELEMENT_ERROR (enc, LIBRARY, INIT, (NULL), + ("error creating Wavpack context")); + ret = GST_FLOW_ERROR; + goto exit; + } } static void gst_wavpack_enc_rewrite_first_block (GstWavpackEnc * enc) { - GstEvent *event = gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_BYTES, - 0, GST_BUFFER_OFFSET_NONE, 0); + GstSegment segment; gboolean ret; g_return_if_fail (enc); @@ -828,7 +791,9 @@ gst_wavpack_enc_rewrite_first_block (GstWavpackEnc * enc) WavpackUpdateNumSamples (enc->wp_context, enc->first_block); /* try to seek to the beginning of the output */ - ret = gst_pad_push_event (enc->srcpad, event); + gst_segment_init (&segment, GST_FORMAT_BYTES); + ret = gst_pad_push_event (GST_AUDIO_ENCODER_SRC_PAD (enc), + gst_event_new_segment (&segment)); if (ret) { /* try to rewrite the first block */ GST_DEBUG_OBJECT (enc, "rewriting first block ..."); @@ -836,111 +801,84 @@ gst_wavpack_enc_rewrite_first_block (GstWavpackEnc * enc) ret = gst_wavpack_enc_push_block (&enc->wv_id, enc->first_block, enc->first_block_size); enc->wv_id.passthrough = FALSE; + g_free (enc->first_block); + enc->first_block = NULL; } else { GST_WARNING_OBJECT (enc, "rewriting of first block failed. " "Seeking to first block failed!"); } } -static gboolean -gst_wavpack_enc_sink_event (GstPad * pad, GstEvent * event) +static GstFlowReturn +gst_wavpack_enc_drain (GstWavpackEnc * enc) { - GstWavpackEnc *enc = GST_WAVPACK_ENC (gst_pad_get_parent (pad)); - gboolean ret = TRUE; + if (!enc->wp_context) + return GST_FLOW_OK; - GST_DEBUG ("Received %s event on sinkpad", GST_EVENT_TYPE_NAME (event)); + GST_DEBUG_OBJECT (enc, "draining"); + + /* Encode all remaining samples and flush them to the src pads */ + WavpackFlushSamples (enc->wp_context); + + /* Drop all remaining data, this is no complete block otherwise + * it would've been pushed already */ + if (enc->pending_buffer) { + gst_buffer_unref (enc->pending_buffer); + enc->pending_buffer = NULL; + enc->pending_offset = 0; + } + + /* write the MD5 sum if we have to write one */ + if ((enc->md5) && (enc->md5_context)) { + guint8 md5_digest[16]; + gsize digest_len = sizeof (md5_digest); + + g_checksum_get_digest (enc->md5_context, md5_digest, &digest_len); + if (digest_len == sizeof (md5_digest)) { + WavpackStoreMD5Sum (enc->wp_context, md5_digest); + WavpackFlushSamples (enc->wp_context); + } else + GST_WARNING_OBJECT (enc, "Calculating MD5 digest failed"); + } + + /* Try to rewrite the first frame with the correct sample number */ + if (enc->first_block) + gst_wavpack_enc_rewrite_first_block (enc); + + /* close the context if not already happened */ + if (enc->wp_context) { + WavpackCloseFile (enc->wp_context); + enc->wp_context = NULL; + } + + return GST_FLOW_OK; +} + +static gboolean +gst_wavpack_enc_sink_event (GstAudioEncoder * benc, GstEvent * event) +{ + GstWavpackEnc *enc = GST_WAVPACK_ENC (benc); + + GST_DEBUG_OBJECT (enc, "Received %s event on sinkpad", + GST_EVENT_TYPE_NAME (event)); switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_EOS: - /* Encode all remaining samples and flush them to the src pads */ - WavpackFlushSamples (enc->wp_context); - - /* Drop all remaining data, this is no complete block otherwise - * it would've been pushed already */ - if (enc->pending_buffer) { - gst_buffer_unref (enc->pending_buffer); - enc->pending_buffer = NULL; - enc->pending_offset = 0; - } - - /* write the MD5 sum if we have to write one */ - if ((enc->md5) && (enc->md5_context)) { - guint8 md5_digest[16]; - gsize digest_len = sizeof (md5_digest); - - g_checksum_get_digest (enc->md5_context, md5_digest, &digest_len); - if (digest_len == sizeof (md5_digest)) - WavpackStoreMD5Sum (enc->wp_context, md5_digest); - else - GST_WARNING_OBJECT (enc, "Calculating MD5 digest failed"); - } - - /* Try to rewrite the first frame with the correct sample number */ - if (enc->first_block) - gst_wavpack_enc_rewrite_first_block (enc); - - /* close the context if not already happened */ - if (enc->wp_context) { - WavpackCloseFile (enc->wp_context); - enc->wp_context = NULL; - } - - ret = gst_pad_event_default (pad, event); - break; - case GST_EVENT_NEWSEGMENT: + case GST_EVENT_SEGMENT: if (enc->wp_context) { GST_WARNING_OBJECT (enc, "got NEWSEGMENT after encoding " "already started"); } - /* drop NEWSEGMENT events, we create our own when pushing - * the first buffer to the pads */ - gst_event_unref (event); - ret = TRUE; - break; - default: - ret = gst_pad_event_default (pad, event); - break; - } - - gst_object_unref (enc); - return ret; -} - -static GstStateChangeReturn -gst_wavpack_enc_change_state (GstElement * element, GstStateChange transition) -{ - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - GstWavpackEnc *enc = GST_WAVPACK_ENC (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - /* set the last returned GstFlowReturns of the two pads to GST_FLOW_OK - * as they're only set to something else in WavpackPackSamples() or more - * specific gst_wavpack_enc_push_block() and nothing happened there yet */ - enc->srcpad_last_return = enc->wvcsrcpad_last_return = GST_FLOW_OK; - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - gst_wavpack_enc_reset (enc); - break; - case GST_STATE_CHANGE_READY_TO_NULL: + /* peek and hold NEWSEGMENT events for sending on correction pad */ + if (enc->pending_segment) + gst_event_unref (enc->pending_segment); + enc->pending_segment = gst_event_ref (event); break; default: break; } - return ret; + /* baseclass handles rest */ + return GST_AUDIO_ENCODER_CLASS (parent_class)->event (benc, event); } static void @@ -1044,7 +982,7 @@ gst_wavpack_enc_plugin_init (GstPlugin * plugin) GST_RANK_NONE, GST_TYPE_WAVPACK_ENC)) return FALSE; - GST_DEBUG_CATEGORY_INIT (gst_wavpack_enc_debug, "wavpack_enc", 0, + GST_DEBUG_CATEGORY_INIT (gst_wavpack_enc_debug, "wavpackenc", 0, "Wavpack encoder"); return TRUE; diff --git a/ext/wavpack/gstwavpackenc.h b/ext/wavpack/gstwavpackenc.h index d2df844e50..aab4296fbf 100644 --- a/ext/wavpack/gstwavpackenc.h +++ b/ext/wavpack/gstwavpackenc.h @@ -23,6 +23,7 @@ #define __GST_WAVPACK_ENC_H__ #include +#include #include @@ -50,10 +51,9 @@ typedef struct struct _GstWavpackEnc { - GstElement element; + GstAudioEncoder element; /*< private > */ - GstPad *sinkpad, *srcpad; GstPad *wvcsrcpad; GstFlowReturn srcpad_last_return; @@ -86,6 +86,7 @@ struct _GstWavpackEnc GstBuffer *pending_buffer; gint32 pending_offset; + GstEvent *pending_segment; GstClockTime timestamp_offset; GstClockTime next_ts; @@ -93,7 +94,7 @@ struct _GstWavpackEnc struct _GstWavpackEncClass { - GstElementClass parent; + GstAudioEncoderClass parent; }; GType gst_wavpack_enc_get_type (void); diff --git a/ext/wavpack/gstwavpackparse.c b/ext/wavpack/gstwavpackparse.c deleted file mode 100644 index 5ffa7a5f34..0000000000 --- a/ext/wavpack/gstwavpackparse.c +++ /dev/null @@ -1,1341 +0,0 @@ -/* GStreamer wavpack plugin - * Copyright (c) 2005 Arwed v. Merkatz - * Copyright (c) 2006 Tim-Philipp MĂ¼ller - * Copyright (c) 2006 Sebastian Dröge - * - * gstwavpackparse.c: wavpack file parser - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/** - * SECTION:element-wavpackparse - * - * WavpackParse takes raw, unframed Wavpack streams and splits them into - * single Wavpack chunks with information like bit depth and the position - * in the stream. - * Wavpack is an open-source - * audio codec that features both lossless and lossy encoding. - * - * - * Example launch line - * |[ - * gst-launch filesrc location=test.wv ! wavpackparse ! wavpackdec ! fakesink - * ]| This pipeline decodes the Wavpack file test.wv into raw audio buffers. - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include - -#include -#include - -#include -#include "gstwavpackparse.h" -#include "gstwavpackstreamreader.h" -#include "gstwavpackcommon.h" - -GST_DEBUG_CATEGORY_STATIC (gst_wavpack_parse_debug); -#define GST_CAT_DEFAULT gst_wavpack_parse_debug - -static inline GstWavpackParseIndexEntry * -gst_wavpack_parse_index_entry_new (void) -{ - return g_slice_new (GstWavpackParseIndexEntry); -} - -static inline void -gst_wavpack_parse_index_entry_free (GstWavpackParseIndexEntry * entry) -{ - g_slice_free (GstWavpackParseIndexEntry, entry); -} - -static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-wavpack, " - "framed = (boolean) false; " - "audio/x-wavpack-correction, " "framed = (boolean) false") - ); - -static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_SOMETIMES, - GST_STATIC_CAPS ("audio/x-wavpack, " - "width = (int) [ 1, 32 ], " - "channels = (int) [ 1, 8 ], " - "rate = (int) [ 6000, 192000 ], " "framed = (boolean) true") - ); - -static GstStaticPadTemplate wvc_src_factory = GST_STATIC_PAD_TEMPLATE ("wvcsrc", - GST_PAD_SRC, - GST_PAD_SOMETIMES, - GST_STATIC_CAPS ("audio/x-wavpack-correction, " "framed = (boolean) true") - ); - -static gboolean gst_wavpack_parse_sink_activate (GstPad * sinkpad); - -static gboolean -gst_wavpack_parse_sink_activate_pull (GstPad * sinkpad, gboolean active); - -static void gst_wavpack_parse_loop (GstElement * element); - -static GstStateChangeReturn gst_wavpack_parse_change_state (GstElement * - element, GstStateChange transition); -static void gst_wavpack_parse_reset (GstWavpackParse * parse); - -static gint64 gst_wavpack_parse_get_upstream_length (GstWavpackParse * wvparse); - -static GstBuffer *gst_wavpack_parse_pull_buffer (GstWavpackParse * wvparse, - gint64 offset, guint size, GstFlowReturn * flow); -static GstFlowReturn gst_wavpack_parse_chain (GstPad * pad, GstBuffer * buf); - -GST_BOILERPLATE (GstWavpackParse, gst_wavpack_parse, GstElement, - GST_TYPE_ELEMENT); - -static void -gst_wavpack_parse_base_init (gpointer klass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&src_factory)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&wvc_src_factory)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&sink_factory)); - - gst_element_class_set_details_simple (element_class, "Wavpack parser", - "Codec/Demuxer/Audio", - "Parses Wavpack files", - "Arwed v. Merkatz , " - "Sebastian Dröge "); -} - -static void -gst_wavpack_parse_finalize (GObject * object) -{ - gst_wavpack_parse_reset (GST_WAVPACK_PARSE (object)); - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -static void -gst_wavpack_parse_class_init (GstWavpackParseClass * klass) -{ - GObjectClass *gobject_class; - - GstElementClass *gstelement_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - - gobject_class->finalize = gst_wavpack_parse_finalize; - gstelement_class->change_state = - GST_DEBUG_FUNCPTR (gst_wavpack_parse_change_state); -} - -static GstWavpackParseIndexEntry * -gst_wavpack_parse_index_get_last_entry (GstWavpackParse * wvparse) -{ - g_assert (wvparse->entries != NULL); - - return wvparse->entries->data; -} - -static GstWavpackParseIndexEntry * -gst_wavpack_parse_index_get_entry_from_sample (GstWavpackParse * wvparse, - gint64 sample_offset) -{ - gint i; - - GSList *node; - - if (wvparse->entries == NULL) - return NULL; - - for (node = wvparse->entries, i = 0; node; node = node->next, i++) { - GstWavpackParseIndexEntry *entry; - - entry = node->data; - - GST_LOG_OBJECT (wvparse, "Index entry %03u: sample %" G_GINT64_FORMAT " @" - " byte %" G_GINT64_FORMAT, i, entry->sample_offset, entry->byte_offset); - - if (entry->sample_offset <= sample_offset && - sample_offset < entry->sample_offset_end) { - GST_LOG_OBJECT (wvparse, "found match"); - return entry; - } - - /* as the list is sorted and we first look at the latest entry - * we can abort searching for an entry if the sample we want is - * after the latest one */ - if (sample_offset >= entry->sample_offset_end) - break; - } - GST_LOG_OBJECT (wvparse, "no match in index"); - return NULL; -} - -static void -gst_wavpack_parse_index_append_entry (GstWavpackParse * wvparse, - gint64 byte_offset, gint64 sample_offset, gint64 num_samples) -{ - GstWavpackParseIndexEntry *entry; - - /* do we have this one already? */ - if (wvparse->entries) { - entry = gst_wavpack_parse_index_get_last_entry (wvparse); - if (entry->byte_offset >= byte_offset - || entry->sample_offset >= sample_offset) - return; - } - - GST_LOG_OBJECT (wvparse, "Adding index entry %8" G_GINT64_FORMAT " - %" - GST_TIME_FORMAT " @ offset 0x%08" G_GINT64_MODIFIER "x", sample_offset, - GST_TIME_ARGS (gst_util_uint64_scale_int (sample_offset, - GST_SECOND, wvparse->samplerate)), byte_offset); - - entry = gst_wavpack_parse_index_entry_new (); - entry->byte_offset = byte_offset; - entry->sample_offset = sample_offset; - entry->sample_offset_end = sample_offset + num_samples; - wvparse->entries = g_slist_prepend (wvparse->entries, entry); -} - -static void -gst_wavpack_parse_reset (GstWavpackParse * parse) -{ - parse->total_samples = G_GINT64_CONSTANT (-1); - parse->samplerate = 0; - parse->channels = 0; - - gst_segment_init (&parse->segment, GST_FORMAT_UNDEFINED); - parse->next_block_index = 0; - - parse->current_offset = 0; - parse->need_newsegment = TRUE; - parse->discont = TRUE; - parse->upstream_length = -1; - - if (parse->entries) { - g_slist_foreach (parse->entries, (GFunc) gst_wavpack_parse_index_entry_free, - NULL); - g_slist_free (parse->entries); - parse->entries = NULL; - } - - if (parse->adapter) { - gst_adapter_clear (parse->adapter); - g_object_unref (parse->adapter); - parse->adapter = NULL; - } - - if (parse->srcpad != NULL) { - gboolean res; - - GST_DEBUG_OBJECT (parse, "Removing src pad"); - res = gst_element_remove_pad (GST_ELEMENT (parse), parse->srcpad); - g_return_if_fail (res != FALSE); - gst_object_unref (parse->srcpad); - parse->srcpad = NULL; - } - - g_list_foreach (parse->queued_events, (GFunc) gst_mini_object_unref, NULL); - g_list_free (parse->queued_events); - parse->queued_events = NULL; - - if (parse->pending_buffer) - gst_buffer_unref (parse->pending_buffer); - - parse->pending_buffer = NULL; -} - -static const GstQueryType * -gst_wavpack_parse_get_src_query_types (GstPad * pad) -{ - static const GstQueryType types[] = { - GST_QUERY_POSITION, - GST_QUERY_DURATION, - GST_QUERY_SEEKING, - 0 - }; - - return types; -} - -static gboolean -gst_wavpack_parse_src_query (GstPad * pad, GstQuery * query) -{ - GstWavpackParse *parse = GST_WAVPACK_PARSE (gst_pad_get_parent (pad)); - - GstFormat format; - - gboolean ret = FALSE; - - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_POSITION:{ - gint64 cur; - - guint rate; - - GST_OBJECT_LOCK (parse); - cur = parse->segment.last_stop; - rate = parse->samplerate; - GST_OBJECT_UNLOCK (parse); - - if (rate == 0) { - GST_DEBUG_OBJECT (parse, "haven't read header yet"); - break; - } - - gst_query_parse_position (query, &format, NULL); - - switch (format) { - case GST_FORMAT_TIME: - cur = gst_util_uint64_scale_int (cur, GST_SECOND, rate); - gst_query_set_position (query, GST_FORMAT_TIME, cur); - ret = TRUE; - break; - case GST_FORMAT_DEFAULT: - gst_query_set_position (query, GST_FORMAT_DEFAULT, cur); - ret = TRUE; - break; - default: - GST_DEBUG_OBJECT (parse, "cannot handle position query in " - "%s format. Forwarding upstream.", gst_format_get_name (format)); - ret = gst_pad_query_default (pad, query); - break; - } - break; - } - case GST_QUERY_DURATION:{ - gint64 len; - - guint rate; - - GST_OBJECT_LOCK (parse); - rate = parse->samplerate; - len = parse->total_samples; - GST_OBJECT_UNLOCK (parse); - - if (rate == 0) { - GST_DEBUG_OBJECT (parse, "haven't read header yet"); - break; - } - - gst_query_parse_duration (query, &format, NULL); - - switch (format) { - case GST_FORMAT_TIME: - if (len != G_GINT64_CONSTANT (-1)) - len = gst_util_uint64_scale_int (len, GST_SECOND, rate); - gst_query_set_duration (query, GST_FORMAT_TIME, len); - ret = TRUE; - break; - case GST_FORMAT_DEFAULT: - gst_query_set_duration (query, GST_FORMAT_DEFAULT, len); - ret = TRUE; - break; - default: - GST_DEBUG_OBJECT (parse, "cannot handle duration query in " - "%s format. Forwarding upstream.", gst_format_get_name (format)); - ret = gst_pad_query_default (pad, query); - break; - } - break; - } - case GST_QUERY_SEEKING:{ - gst_query_parse_seeking (query, &format, NULL, NULL, NULL); - if (format == GST_FORMAT_TIME || format == GST_FORMAT_DEFAULT) { - gboolean seekable; - - gint64 duration = -1; - - /* only fails if we didn't read the headers yet and can't say - * anything about our seeking capabilities */ - if (!gst_pad_query_duration (pad, &format, &duration)) - break; - - /* can't seek in streaming mode yet */ - GST_OBJECT_LOCK (parse); - seekable = (parse->adapter == NULL); - GST_OBJECT_UNLOCK (parse); - - gst_query_set_seeking (query, format, seekable, 0, duration); - ret = TRUE; - } - break; - } - default:{ - ret = gst_pad_query_default (pad, query); - break; - } - } - - gst_object_unref (parse); - return ret; - -} - -/* returns TRUE on success, with byte_offset set to the offset of the - * wavpack chunk containing the sample requested. start_sample will be - * set to the first sample in the chunk starting at byte_offset. - * Scanning from the last known header offset to the wanted position - * when seeking forward isn't very clever, but seems fast enough in - * practice and has the nice side effect of populating our index - * table */ -static gboolean -gst_wavpack_parse_scan_to_find_sample (GstWavpackParse * parse, - gint64 sample, gint64 * byte_offset, gint64 * start_sample) -{ - GstWavpackParseIndexEntry *entry; - - GstFlowReturn ret; - - gint64 off = 0; - - /* first, check if we have to scan at all */ - entry = gst_wavpack_parse_index_get_entry_from_sample (parse, sample); - if (entry) { - *byte_offset = entry->byte_offset; - *start_sample = entry->sample_offset; - GST_LOG_OBJECT (parse, "Found index entry: sample %" G_GINT64_FORMAT - " @ offset %" G_GINT64_FORMAT, entry->sample_offset, - entry->byte_offset); - return TRUE; - } - - GST_LOG_OBJECT (parse, "No matching entry in index, scanning file ..."); - - /* if we have an index, we can start scanning from the last known offset - * in there, after all we know our wanted sample is not in the index */ - if (parse->entries) { - GstWavpackParseIndexEntry *entry; - - entry = gst_wavpack_parse_index_get_last_entry (parse); - off = entry->byte_offset; - } - - /* now scan forward until we find the chunk we're looking for or hit EOS */ - do { - WavpackHeader header; - - GstBuffer *buf; - - buf = gst_wavpack_parse_pull_buffer (parse, off, sizeof (WavpackHeader), - &ret); - - if (buf == NULL) - break; - - gst_wavpack_read_header (&header, GST_BUFFER_DATA (buf)); - gst_buffer_unref (buf); - - if (header.flags & INITIAL_BLOCK) - gst_wavpack_parse_index_append_entry (parse, off, header.block_index, - header.block_samples); - else - continue; - - if (header.block_index <= sample && - sample < (header.block_index + header.block_samples)) { - *byte_offset = off; - *start_sample = header.block_index; - return TRUE; - } - - off += header.ckSize + 8; - } while (1); - - GST_DEBUG_OBJECT (parse, "scan failed: %s (off=0x%08" G_GINT64_MODIFIER "x)", - gst_flow_get_name (ret), off); - - return FALSE; -} - -static gboolean -gst_wavpack_parse_send_newsegment (GstWavpackParse * wvparse, gboolean update) -{ - GstSegment *s = &wvparse->segment; - - gboolean ret; - - gint64 stop_time = -1; - - gint64 start_time = 0; - - gint64 cur_pos_time; - - gint64 diff; - - /* segment is in DEFAULT format, but we want to send a TIME newsegment */ - start_time = gst_util_uint64_scale_int (s->start, GST_SECOND, - wvparse->samplerate); - - if (s->stop != -1) { - stop_time = gst_util_uint64_scale_int (s->stop, GST_SECOND, - wvparse->samplerate); - } - - GST_DEBUG_OBJECT (wvparse, "sending newsegment from %" GST_TIME_FORMAT - " to %" GST_TIME_FORMAT, GST_TIME_ARGS (start_time), - GST_TIME_ARGS (stop_time)); - - /* after a seek, s->last_stop will point to a chunk boundary, ie. from - * which sample we will start sending data again, while s->start will - * point to the sample we actually want to seek to and want to start - * playing right after the seek. Adjust clock-time for the difference - * so we start playing from start_time */ - cur_pos_time = gst_util_uint64_scale_int (s->last_stop, GST_SECOND, - wvparse->samplerate); - diff = start_time - cur_pos_time; - - ret = gst_pad_push_event (wvparse->srcpad, - gst_event_new_new_segment (update, s->rate, GST_FORMAT_TIME, - start_time, stop_time, start_time - diff)); - - return ret; -} - -static gboolean -gst_wavpack_parse_handle_seek_event (GstWavpackParse * wvparse, - GstEvent * event) -{ - GstSeekFlags seek_flags; - - GstSeekType start_type; - - GstSeekType stop_type; - - GstSegment segment; - - GstFormat format; - - gboolean only_update; - - gboolean flush, ret; - - gdouble speed; - - gint64 stop; - - gint64 start; /* sample we want to seek to */ - - gint64 byte_offset; /* byte offset the chunk we seek to starts at */ - - gint64 chunk_start; /* first sample in chunk we seek to */ - - guint rate; - - gint64 last_stop; - - if (wvparse->adapter) { - GST_DEBUG_OBJECT (wvparse, "seeking in streaming mode not implemented yet"); - return FALSE; - } - - gst_event_parse_seek (event, &speed, &format, &seek_flags, &start_type, - &start, &stop_type, &stop); - - if (format != GST_FORMAT_DEFAULT && format != GST_FORMAT_TIME) { - GST_DEBUG ("seeking is only supported in TIME or DEFAULT format"); - return FALSE; - } - - if (speed < 0.0) { - GST_DEBUG ("only forward playback supported, rate %f not allowed", speed); - return FALSE; - } - - GST_OBJECT_LOCK (wvparse); - - rate = wvparse->samplerate; - if (rate == 0) { - GST_OBJECT_UNLOCK (wvparse); - GST_DEBUG ("haven't read header yet"); - return FALSE; - } - - /* figure out the last position we need to play. If it's configured (stop != - * -1), use that, else we play until the total duration of the file */ - if (stop == -1) - stop = wvparse->segment.duration; - - /* convert from time to samples if necessary */ - if (format == GST_FORMAT_TIME) { - if (start_type != GST_SEEK_TYPE_NONE) - start = gst_util_uint64_scale_int (start, rate, GST_SECOND); - if (stop_type != GST_SEEK_TYPE_NONE) - stop = gst_util_uint64_scale_int (stop, rate, GST_SECOND); - } - - if (start < 0) { - GST_OBJECT_UNLOCK (wvparse); - GST_DEBUG_OBJECT (wvparse, "Invalid start sample %" G_GINT64_FORMAT, start); - return FALSE; - } - - flush = ((seek_flags & GST_SEEK_FLAG_FLUSH) != 0); - - /* operate on segment copy until we know the seek worked */ - segment = wvparse->segment; - - gst_segment_set_seek (&segment, speed, GST_FORMAT_DEFAULT, - seek_flags, start_type, start, stop_type, stop, &only_update); - -#if 0 - if (only_update) { - wvparse->segment = segment; - gst_wavpack_parse_send_newsegment (wvparse, TRUE); - goto done; - } -#endif - - gst_pad_push_event (wvparse->sinkpad, gst_event_new_flush_start ()); - - if (flush) { - gst_pad_push_event (wvparse->srcpad, gst_event_new_flush_start ()); - } else { - gst_pad_pause_task (wvparse->sinkpad); - } - - GST_PAD_STREAM_LOCK (wvparse->sinkpad); - - /* Save current position */ - last_stop = wvparse->segment.last_stop; - - gst_pad_push_event (wvparse->sinkpad, gst_event_new_flush_stop ()); - - if (flush) { - gst_pad_push_event (wvparse->srcpad, gst_event_new_flush_stop ()); - } - - GST_DEBUG_OBJECT (wvparse, "Performing seek to %" GST_TIME_FORMAT " sample %" - G_GINT64_FORMAT, GST_TIME_ARGS (segment.start * GST_SECOND / rate), - start); - - ret = gst_wavpack_parse_scan_to_find_sample (wvparse, segment.start, - &byte_offset, &chunk_start); - - if (ret) { - GST_DEBUG_OBJECT (wvparse, "new offset: %" G_GINT64_FORMAT, byte_offset); - wvparse->current_offset = byte_offset; - /* we want to send a newsegment event with the actual seek position - * as start, even though our first buffer might start before the - * configured segment. We leave it up to the decoder or sink to crop - * the output buffers accordingly */ - wvparse->segment = segment; - wvparse->segment.last_stop = chunk_start; - wvparse->need_newsegment = TRUE; - wvparse->discont = (last_stop != chunk_start) ? TRUE : FALSE; - - /* if we're doing a segment seek, post a SEGMENT_START message */ - if (wvparse->segment.flags & GST_SEEK_FLAG_SEGMENT) { - gst_element_post_message (GST_ELEMENT_CAST (wvparse), - gst_message_new_segment_start (GST_OBJECT_CAST (wvparse), - wvparse->segment.format, wvparse->segment.last_stop)); - } - } else { - GST_DEBUG_OBJECT (wvparse, "seek failed: don't know where to seek to"); - } - - GST_PAD_STREAM_UNLOCK (wvparse->sinkpad); - GST_OBJECT_UNLOCK (wvparse); - - gst_pad_start_task (wvparse->sinkpad, - (GstTaskFunction) gst_wavpack_parse_loop, wvparse); - - return ret; -} - -static gboolean -gst_wavpack_parse_sink_event (GstPad * pad, GstEvent * event) -{ - GstWavpackParse *parse; - - gboolean ret = TRUE; - - parse = GST_WAVPACK_PARSE (gst_pad_get_parent (pad)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_FLUSH_STOP:{ - if (parse->adapter) { - gst_adapter_clear (parse->adapter); - } - if (parse->pending_buffer) { - gst_buffer_unref (parse->pending_buffer); - parse->pending_buffer = NULL; - parse->pending_offset = 0; - } - ret = gst_pad_push_event (parse->srcpad, event); - break; - } - case GST_EVENT_NEWSEGMENT:{ - parse->need_newsegment = TRUE; - gst_event_unref (event); - ret = TRUE; - break; - } - case GST_EVENT_EOS:{ - if (parse->adapter) { - /* remove all bytes that are left in the adapter after EOS. They can't - * be a complete Wavpack block and we can't do anything with them */ - gst_adapter_clear (parse->adapter); - } - if (parse->pending_buffer) { - gst_buffer_unref (parse->pending_buffer); - parse->pending_buffer = NULL; - parse->pending_offset = 0; - } - ret = gst_pad_push_event (parse->srcpad, event); - break; - } - default:{ - /* stream lock is recursive, should be fine for all events */ - GST_PAD_STREAM_LOCK (pad); - if (parse->srcpad == NULL) { - parse->queued_events = g_list_append (parse->queued_events, event); - } else { - ret = gst_pad_push_event (parse->srcpad, event); - } - GST_PAD_STREAM_UNLOCK (pad); - } - } - - - gst_object_unref (parse); - return ret; -} - -static gboolean -gst_wavpack_parse_src_event (GstPad * pad, GstEvent * event) -{ - GstWavpackParse *parse; - - gboolean ret; - - parse = GST_WAVPACK_PARSE (gst_pad_get_parent (pad)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_SEEK: - ret = gst_wavpack_parse_handle_seek_event (parse, event); - break; - default: - ret = gst_pad_event_default (pad, event); - break; - } - - gst_object_unref (parse); - return ret; -} - -static void -gst_wavpack_parse_init (GstWavpackParse * parse, GstWavpackParseClass * gclass) -{ - GstElementClass *klass = GST_ELEMENT_GET_CLASS (parse); - - GstPadTemplate *tmpl; - - tmpl = gst_element_class_get_pad_template (klass, "sink"); - parse->sinkpad = gst_pad_new_from_template (tmpl, "sink"); - - gst_pad_set_activate_function (parse->sinkpad, - GST_DEBUG_FUNCPTR (gst_wavpack_parse_sink_activate)); - gst_pad_set_activatepull_function (parse->sinkpad, - GST_DEBUG_FUNCPTR (gst_wavpack_parse_sink_activate_pull)); - gst_pad_set_event_function (parse->sinkpad, - GST_DEBUG_FUNCPTR (gst_wavpack_parse_sink_event)); - gst_pad_set_chain_function (parse->sinkpad, - GST_DEBUG_FUNCPTR (gst_wavpack_parse_chain)); - - gst_element_add_pad (GST_ELEMENT (parse), parse->sinkpad); - - parse->srcpad = NULL; - gst_wavpack_parse_reset (parse); -} - -static gint64 -gst_wavpack_parse_get_upstream_length (GstWavpackParse * parse) -{ - gint64 length = -1; - - GstFormat format = GST_FORMAT_BYTES; - - if (!gst_pad_query_peer_duration (parse->sinkpad, &format, &length)) { - length = -1; - } else { - GST_DEBUG ("upstream length: %" G_GINT64_FORMAT, length); - } - return length; -} - -static GstBuffer * -gst_wavpack_parse_pull_buffer (GstWavpackParse * wvparse, gint64 offset, - guint size, GstFlowReturn * flow) -{ - GstFlowReturn flow_ret; - - GstBuffer *buf = NULL; - - if (offset + size > wvparse->upstream_length) { - wvparse->upstream_length = gst_wavpack_parse_get_upstream_length (wvparse); - if (offset + size > wvparse->upstream_length) { - GST_DEBUG_OBJECT (wvparse, "EOS: %" G_GINT64_FORMAT " + %u > %" - G_GINT64_FORMAT, offset, size, wvparse->upstream_length); - flow_ret = GST_FLOW_EOS; - goto done; - } - } - - flow_ret = gst_pad_pull_range (wvparse->sinkpad, offset, size, &buf); - - if (flow_ret != GST_FLOW_OK) { - GST_DEBUG_OBJECT (wvparse, "pull_range (%" G_GINT64_FORMAT ", %u) " - "failed, flow: %s", offset, size, gst_flow_get_name (flow_ret)); - buf = NULL; - goto done; - } - - if (GST_BUFFER_SIZE (buf) < size) { - GST_DEBUG_OBJECT (wvparse, "Short read at offset %" G_GINT64_FORMAT - ", got only %u of %u bytes", offset, GST_BUFFER_SIZE (buf), size); - gst_buffer_unref (buf); - buf = NULL; - flow_ret = GST_FLOW_EOS; - } - -done: - if (flow) - *flow = flow_ret; - return buf; -} - -static gboolean -gst_wavpack_parse_create_src_pad (GstWavpackParse * wvparse, GstBuffer * buf, - WavpackHeader * header) -{ - GstWavpackMetadata meta; - - GstCaps *caps = NULL; - - guchar *bufptr; - - g_assert (wvparse->srcpad == NULL); - - bufptr = GST_BUFFER_DATA (buf) + sizeof (WavpackHeader); - - while (gst_wavpack_read_metadata (&meta, GST_BUFFER_DATA (buf), &bufptr)) { - switch (meta.id) { - case ID_WVC_BITSTREAM:{ - caps = gst_caps_new_simple ("audio/x-wavpack-correction", - "framed", G_TYPE_BOOLEAN, TRUE, NULL); - wvparse->srcpad = - gst_pad_new_from_template (gst_element_class_get_pad_template - (GST_ELEMENT_GET_CLASS (wvparse), "wvcsrc"), "wvcsrc"); - break; - } - case ID_WV_BITSTREAM: - case ID_WVX_BITSTREAM:{ - WavpackStreamReader *stream_reader = gst_wavpack_stream_reader_new (); - - WavpackContext *wpc; - - gchar error_msg[80]; - - read_id rid; - - gint channel_mask; - - rid.buffer = GST_BUFFER_DATA (buf); - rid.length = GST_BUFFER_SIZE (buf); - rid.position = 0; - - wpc = - WavpackOpenFileInputEx (stream_reader, &rid, NULL, error_msg, 0, 0); - - if (!wpc) - return FALSE; - - wvparse->samplerate = WavpackGetSampleRate (wpc); - wvparse->channels = WavpackGetNumChannels (wpc); - wvparse->total_samples = - (header->total_samples == - 0xffffffff) ? G_GINT64_CONSTANT (-1) : header->total_samples; - - caps = gst_caps_new_simple ("audio/x-wavpack", - "width", G_TYPE_INT, WavpackGetBitsPerSample (wpc), - "channels", G_TYPE_INT, wvparse->channels, - "rate", G_TYPE_INT, wvparse->samplerate, - "framed", G_TYPE_BOOLEAN, TRUE, NULL); -#ifdef WAVPACK_OLD_API - channel_mask = wpc->config.channel_mask; -#else - channel_mask = WavpackGetChannelMask (wpc); -#endif - if (channel_mask == 0) - channel_mask = - gst_wavpack_get_default_channel_mask (wvparse->channels); - - if (channel_mask != 0) { - if (!gst_wavpack_set_channel_layout (caps, channel_mask)) { - GST_WARNING_OBJECT (wvparse, "Failed to set channel layout"); - gst_caps_unref (caps); - caps = NULL; - WavpackCloseFile (wpc); - g_free (stream_reader); - break; - } - } - - wvparse->srcpad = - gst_pad_new_from_template (gst_element_class_get_pad_template - (GST_ELEMENT_GET_CLASS (wvparse), "src"), "src"); - WavpackCloseFile (wpc); - g_free (stream_reader); - break; - } - default:{ - GST_LOG_OBJECT (wvparse, "unhandled ID: 0x%02x", meta.id); - break; - } - } - if (caps != NULL) - break; - } - - if (caps == NULL || wvparse->srcpad == NULL) - return FALSE; - - GST_DEBUG_OBJECT (wvparse, "Added src pad with caps %" GST_PTR_FORMAT, caps); - - gst_pad_set_query_function (wvparse->srcpad, - GST_DEBUG_FUNCPTR (gst_wavpack_parse_src_query)); - gst_pad_set_query_type_function (wvparse->srcpad, - GST_DEBUG_FUNCPTR (gst_wavpack_parse_get_src_query_types)); - gst_pad_set_event_function (wvparse->srcpad, - GST_DEBUG_FUNCPTR (gst_wavpack_parse_src_event)); - - gst_pad_set_caps (wvparse->srcpad, caps); - gst_caps_unref (caps); - gst_pad_use_fixed_caps (wvparse->srcpad); - - gst_object_ref (wvparse->srcpad); - gst_pad_set_active (wvparse->srcpad, TRUE); - gst_element_add_pad (GST_ELEMENT (wvparse), wvparse->srcpad); - gst_element_no_more_pads (GST_ELEMENT (wvparse)); - - return TRUE; -} - -static GstFlowReturn -gst_wavpack_parse_push_buffer (GstWavpackParse * wvparse, GstBuffer * buf, - WavpackHeader * header) -{ - GstFlowReturn ret; - wvparse->current_offset += header->ckSize + 8; - - wvparse->segment.last_stop = header->block_index; - - if (wvparse->need_newsegment) { - if (gst_wavpack_parse_send_newsegment (wvparse, FALSE)) - wvparse->need_newsegment = FALSE; - } - - /* send any queued events */ - if (wvparse->queued_events) { - GList *l; - - for (l = wvparse->queued_events; l != NULL; l = l->next) { - gst_pad_push_event (wvparse->srcpad, GST_EVENT (l->data)); - } - g_list_free (wvparse->queued_events); - wvparse->queued_events = NULL; - } - - if (wvparse->pending_buffer == NULL) { - wvparse->pending_buffer = buf; - wvparse->pending_offset = header->block_index; - } else if (wvparse->pending_offset == header->block_index) { - wvparse->pending_buffer = gst_buffer_join (wvparse->pending_buffer, buf); - } else { - GST_ERROR ("Got incomplete block, dropping"); - gst_buffer_unref (wvparse->pending_buffer); - wvparse->pending_buffer = buf; - wvparse->pending_offset = header->block_index; - } - - if (!(header->flags & FINAL_BLOCK)) - return GST_FLOW_OK; - - buf = wvparse->pending_buffer; - wvparse->pending_buffer = NULL; - - GST_BUFFER_TIMESTAMP (buf) = gst_util_uint64_scale_int (header->block_index, - GST_SECOND, wvparse->samplerate); - GST_BUFFER_DURATION (buf) = gst_util_uint64_scale_int (header->block_samples, - GST_SECOND, wvparse->samplerate); - GST_BUFFER_OFFSET (buf) = header->block_index; - GST_BUFFER_OFFSET_END (buf) = header->block_index + header->block_samples; - - if (wvparse->discont || wvparse->next_block_index != header->block_index) { - GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); - wvparse->discont = FALSE; - } - - wvparse->next_block_index = header->block_index + header->block_samples; - - gst_buffer_set_caps (buf, GST_PAD_CAPS (wvparse->srcpad)); - - GST_LOG_OBJECT (wvparse, "Pushing buffer with time %" GST_TIME_FORMAT, - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); - - ret = gst_pad_push (wvparse->srcpad, buf); - - wvparse->segment.last_stop = wvparse->next_block_index; - - return ret; -} - -static guint8 * -gst_wavpack_parse_find_marker (guint8 * buf, guint size) -{ - int i; - - guint8 *ret = NULL; - - if (G_UNLIKELY (size < 4)) - return NULL; - - for (i = 0; i < size - 4; i++) { - if (memcmp (buf + i, "wvpk", 4) == 0) { - ret = buf + i; - break; - } - } - return ret; -} - -static GstFlowReturn -gst_wavpack_parse_resync_loop (GstWavpackParse * parse, WavpackHeader * header) -{ - GstFlowReturn flow_ret = GST_FLOW_EOS; - - GstBuffer *buf = NULL; - - /* loop until we have a frame header or reach the end of the stream */ - while (1) { - guint8 *data, *marker; - - guint len, size; - - if (buf) { - gst_buffer_unref (buf); - buf = NULL; - } - - if (parse->upstream_length == 0 || - parse->upstream_length <= parse->current_offset) { - parse->upstream_length = gst_wavpack_parse_get_upstream_length (parse); - if (parse->upstream_length == 0 || - parse->upstream_length <= parse->current_offset) { - break; - } - } - - len = MIN (parse->upstream_length - parse->current_offset, 2048); - - GST_LOG_OBJECT (parse, "offset: %" G_GINT64_FORMAT, parse->current_offset); - - buf = gst_wavpack_parse_pull_buffer (parse, parse->current_offset, - len, &flow_ret); - - /* whatever the problem is, there's nothing more for us to do for now */ - if (flow_ret != GST_FLOW_OK) - break; - - data = GST_BUFFER_DATA (buf); - size = GST_BUFFER_SIZE (buf); - - /* not enough data for a header? */ - if (size < sizeof (WavpackHeader)) - break; - - /* got a header right where we are at now? */ - if (gst_wavpack_read_header (header, data)) - break; - - /* nope, let's see if we can find one */ - marker = gst_wavpack_parse_find_marker (data + 1, size - 1); - - if (marker) { - parse->current_offset += marker - data; - /* do one more loop iteration to make sure we pull enough - * data for a full header, we'll bail out then */ - } else { - parse->current_offset += len - 4; - } - } - - if (buf) - gst_buffer_unref (buf); - - return flow_ret; -} - -static void -gst_wavpack_parse_loop (GstElement * element) -{ - GstWavpackParse *parse = GST_WAVPACK_PARSE (element); - - GstFlowReturn flow_ret; - WavpackHeader header = { {0,}, 0, }; - GstBuffer *buf = NULL; - - flow_ret = gst_wavpack_parse_resync_loop (parse, &header); - - if (flow_ret != GST_FLOW_OK) - goto pause; - - GST_LOG_OBJECT (parse, "Read header at offset %" G_GINT64_FORMAT - ": chunk size = %u+8", parse->current_offset, header.ckSize); - - buf = gst_wavpack_parse_pull_buffer (parse, parse->current_offset, - header.ckSize + 8, &flow_ret); - - if (flow_ret != GST_FLOW_OK) - goto pause; - - if (parse->srcpad == NULL) { - if (!gst_wavpack_parse_create_src_pad (parse, buf, &header)) { - GST_ERROR_OBJECT (parse, "Failed to create src pad"); - flow_ret = GST_FLOW_ERROR; - goto pause; - } - } - if (header.flags & INITIAL_BLOCK) - gst_wavpack_parse_index_append_entry (parse, parse->current_offset, - header.block_index, header.block_samples); - - flow_ret = gst_wavpack_parse_push_buffer (parse, buf, &header); - if (flow_ret != GST_FLOW_OK) - goto pause; - - return; - -pause: - { - const gchar *reason = gst_flow_get_name (flow_ret); - - GST_LOG_OBJECT (parse, "pausing task, reason %s", reason); - gst_pad_pause_task (parse->sinkpad); - - if (flow_ret == GST_FLOW_EOS && parse->srcpad) { - if (parse->segment.flags & GST_SEEK_FLAG_SEGMENT) { - GstClockTime stop; - - GST_LOG_OBJECT (parse, "Sending segment done"); - - if ((stop = parse->segment.stop) == -1) - stop = parse->segment.duration; - - gst_element_post_message (GST_ELEMENT_CAST (parse), - gst_message_new_segment_done (GST_OBJECT_CAST (parse), - parse->segment.format, stop)); - } else { - GST_LOG_OBJECT (parse, "Sending EOS, at end of stream"); - gst_pad_push_event (parse->srcpad, gst_event_new_eos ()); - } - } else if (flow_ret == GST_FLOW_NOT_LINKED || flow_ret < GST_FLOW_EOS) { - GST_ELEMENT_ERROR (parse, STREAM, FAILED, - (_("Internal data stream error.")), ("stream stopped, reason %s", - reason)); - if (parse->srcpad) - gst_pad_push_event (parse->srcpad, gst_event_new_eos ()); - } - return; - } -} - -static gboolean -gst_wavpack_parse_resync_adapter (GstAdapter * adapter) -{ - const guint8 *buf, *marker; - - guint avail = gst_adapter_available (adapter); - - if (avail < 4) - return FALSE; - - /* if the marker is at the beginning don't do the expensive search */ - buf = gst_adapter_peek (adapter, 4); - if (memcmp (buf, "wvpk", 4) == 0) - return TRUE; - - if (avail == 4) - return FALSE; - - /* search for the marker in the complete content of the adapter */ - buf = gst_adapter_peek (adapter, avail); - if (buf && (marker = gst_wavpack_parse_find_marker ((guint8 *) buf, avail))) { - gst_adapter_flush (adapter, marker - buf); - return TRUE; - } - - /* flush everything except the last 4 bytes. they could contain - * the start of a new marker */ - gst_adapter_flush (adapter, avail - 4); - - return FALSE; -} - -static GstFlowReturn -gst_wavpack_parse_chain (GstPad * pad, GstBuffer * buf) -{ - GstWavpackParse *wvparse = GST_WAVPACK_PARSE (GST_PAD_PARENT (pad)); - - GstFlowReturn ret = GST_FLOW_OK; - - WavpackHeader wph; - - const guint8 *tmp_buf; - - if (!wvparse->adapter) { - wvparse->adapter = gst_adapter_new (); - } - - if (GST_BUFFER_IS_DISCONT (buf)) { - gst_adapter_clear (wvparse->adapter); - wvparse->discont = TRUE; - } - - gst_adapter_push (wvparse->adapter, buf); - - if (gst_adapter_available (wvparse->adapter) < sizeof (WavpackHeader)) - return ret; - - if (!gst_wavpack_parse_resync_adapter (wvparse->adapter)) - return ret; - - tmp_buf = gst_adapter_peek (wvparse->adapter, sizeof (WavpackHeader)); - gst_wavpack_read_header (&wph, (guint8 *) tmp_buf); - - while (gst_adapter_available (wvparse->adapter) >= wph.ckSize + 4 * 1 + 4) { - GstBuffer *outbuf = - gst_adapter_take_buffer (wvparse->adapter, wph.ckSize + 4 * 1 + 4); - - if (!outbuf) - return GST_FLOW_ERROR; - - if (wvparse->srcpad == NULL) { - if (!gst_wavpack_parse_create_src_pad (wvparse, outbuf, &wph)) { - GST_ERROR_OBJECT (wvparse, "Failed to create src pad"); - ret = GST_FLOW_ERROR; - break; - } - } - - ret = gst_wavpack_parse_push_buffer (wvparse, outbuf, &wph); - - if (ret != GST_FLOW_OK) - break; - - if (gst_adapter_available (wvparse->adapter) >= sizeof (WavpackHeader)) { - tmp_buf = gst_adapter_peek (wvparse->adapter, sizeof (WavpackHeader)); - - if (!gst_wavpack_parse_resync_adapter (wvparse->adapter)) - break; - - gst_wavpack_read_header (&wph, (guint8 *) tmp_buf); - } - } - - return ret; -} - -static GstStateChangeReturn -gst_wavpack_parse_change_state (GstElement * element, GstStateChange transition) -{ - GstWavpackParse *wvparse = GST_WAVPACK_PARSE (element); - - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_PAUSED: - gst_segment_init (&wvparse->segment, GST_FORMAT_DEFAULT); - wvparse->segment.last_stop = 0; - default: - break; - } - - if (GST_ELEMENT_CLASS (parent_class)->change_state) - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_READY: - gst_wavpack_parse_reset (wvparse); - break; - default: - break; - } - - return ret; -} - -static gboolean -gst_wavpack_parse_sink_activate (GstPad * sinkpad) -{ - if (gst_pad_check_pull_range (sinkpad)) { - return gst_pad_activate_pull (sinkpad, TRUE); - } else { - return gst_pad_activate_push (sinkpad, TRUE); - } -} - -static gboolean -gst_wavpack_parse_sink_activate_pull (GstPad * sinkpad, gboolean active) -{ - gboolean result; - - if (active) { - result = gst_pad_start_task (sinkpad, - (GstTaskFunction) gst_wavpack_parse_loop, GST_PAD_PARENT (sinkpad)); - } else { - result = gst_pad_stop_task (sinkpad); - } - - return result; -} - -gboolean -gst_wavpack_parse_plugin_init (GstPlugin * plugin) -{ - if (!gst_element_register (plugin, "wavpackparse", - GST_RANK_PRIMARY, GST_TYPE_WAVPACK_PARSE)) { - return FALSE; - } - - GST_DEBUG_CATEGORY_INIT (gst_wavpack_parse_debug, "wavpack_parse", 0, - "Wavpack file parser"); - - return TRUE; -} diff --git a/ext/wavpack/gstwavpackparse.h b/ext/wavpack/gstwavpackparse.h deleted file mode 100644 index 60504a7ca6..0000000000 --- a/ext/wavpack/gstwavpackparse.h +++ /dev/null @@ -1,97 +0,0 @@ -/* GStreamer wavpack plugin - * (c) 2005 Arwed v. Merkatz - * - * gstwavpackparse.h: wavpack file parser - * - * 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_WAVPACK_PARSE_H__ -#define __GST_WAVPACK_PARSE_H__ - -#include -#include - -G_BEGIN_DECLS -#define GST_TYPE_WAVPACK_PARSE \ - (gst_wavpack_parse_get_type()) -#define GST_WAVPACK_PARSE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_WAVPACK_PARSE,GstWavpackParse)) -#define GST_WAVPACK_PARSE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_WAVPACK_PARSE,GstWavpackParseClass)) -#define GST_IS_WAVPACK_PARSE(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_WAVPACK_PARSE)) -#define GST_IS_WAVPACK_PARSE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_WAVPACK_PARSE)) -typedef struct _GstWavpackParse GstWavpackParse; -typedef struct _GstWavpackParseClass GstWavpackParseClass; -typedef struct _GstWavpackParseIndexEntry GstWavpackParseIndexEntry; - -struct _GstWavpackParseIndexEntry -{ - gint64 byte_offset; /* byte offset of this chunk */ - gint64 sample_offset; /* first sample in this chunk */ - gint64 sample_offset_end; /* first sample in next chunk */ -}; - -struct _GstWavpackParse -{ - GstElement element; - - /*< private > */ - GstPad *sinkpad; - GstPad *srcpad; - - guint samplerate; - guint channels; - gint64 total_samples; - - gboolean need_newsegment; - gboolean discont; - - gint64 current_offset; /* byte offset on sink pad */ - gint64 upstream_length; /* length of file in bytes */ - - GstSegment segment; /* the currently configured segment, in - * samples/audio frames (DEFAULT format) */ - - GstBuffer *pending_buffer; - gint32 pending_offset; - guint32 next_block_index; - - GstAdapter *adapter; /* when operating chain-based, otherwise NULL */ - - /* List of GstWavpackParseIndexEntry structs, mapping known - * sample offsets to byte offsets. Is kept increasing without - * gaps (ie. append only and consecutive entries must always - * map to consecutive chunks in the file). */ - GSList *entries; - - /* Queued events (e.g. tag events we receive before we create the src pad) */ - GList *queued_events; /* STREAM_LOCK */ -}; - -struct _GstWavpackParseClass -{ - GstElementClass parent; -}; - -GType gst_wavpack_parse_get_type (void); - -gboolean gst_wavpack_parse_plugin_init (GstPlugin * plugin); - -G_END_DECLS -#endif /* __GST_WAVPACK_PARSE_H__ */ diff --git a/gst/alpha/gstalpha.c b/gst/alpha/gstalpha.c index 4b53a80ce5..a0c3fab31c 100644 --- a/gst/alpha/gstalpha.c +++ b/gst/alpha/gstalpha.c @@ -393,7 +393,7 @@ gst_alpha_set_property (GObject * object, guint prop_id, } if (reconfigure) - gst_base_transform_reconfigure (GST_BASE_TRANSFORM_CAST (alpha)); + gst_base_transform_reconfigure_src (GST_BASE_TRANSFORM_CAST (alpha)); GST_ALPHA_UNLOCK (alpha); } diff --git a/gst/audiofx/audiofirfilter.c b/gst/audiofx/audiofirfilter.c index 100df0ce09..57fa360e1e 100644 --- a/gst/audiofx/audiofirfilter.c +++ b/gst/audiofx/audiofirfilter.c @@ -45,6 +45,10 @@ * */ +/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray + * with newer GLib versions (>= 2.31.0) */ +#define GLIB_DISABLE_DEPRECATION_WARNINGS + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -130,7 +134,7 @@ gst_audio_fir_filter_class_init (GstAudioFIRFilterClass * klass) gst_audio_fir_filter_signals[SIGNAL_RATE_CHANGED] = g_signal_new ("rate-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstAudioFIRFilterClass, rate_changed), - NULL, NULL, gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); + NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_INT); gst_element_class_set_details_simple (gstelement_class, "Audio FIR filter", "Filter/Effect/Audio", diff --git a/gst/audiofx/audioiirfilter.c b/gst/audiofx/audioiirfilter.c index 5907a161df..adcca1de21 100644 --- a/gst/audiofx/audioiirfilter.c +++ b/gst/audiofx/audioiirfilter.c @@ -41,6 +41,10 @@ * */ +/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray + * with newer GLib versions (>= 2.31.0) */ +#define GLIB_DISABLE_DEPRECATION_WARNINGS + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -128,7 +132,7 @@ gst_audio_iir_filter_class_init (GstAudioIIRFilterClass * klass) gst_audio_iir_filter_signals[SIGNAL_RATE_CHANGED] = g_signal_new ("rate-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstAudioIIRFilterClass, rate_changed), - NULL, NULL, gst_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); + NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_INT); gst_element_class_set_details_simple (gstelement_class, "Audio IIR filter", "Filter/Effect/Audio", diff --git a/gst/audioparsers/Makefile.am b/gst/audioparsers/Makefile.am index 22bc81fa09..4d4d53ed21 100644 --- a/gst/audioparsers/Makefile.am +++ b/gst/audioparsers/Makefile.am @@ -3,7 +3,7 @@ plugin_LTLIBRARIES = libgstaudioparsers.la libgstaudioparsers_la_SOURCES = \ gstaacparse.c gstamrparse.c gstac3parse.c \ gstdcaparse.c gstflacparse.c gstmpegaudioparse.c \ - plugin.c + gstwavpackparse.c plugin.c libgstaudioparsers_la_CFLAGS = \ $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) @@ -15,4 +15,4 @@ libgstaudioparsers_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstaudioparsers_la_LIBTOOLFLAGS = --tag=disable-static noinst_HEADERS = gstaacparse.h gstamrparse.h gstac3parse.h \ - gstdcaparse.h gstflacparse.h gstmpegaudioparse.h + gstdcaparse.h gstflacparse.h gstmpegaudioparse.h gstwavpackparse.h diff --git a/gst/audioparsers/gstmpegaudioparse.c b/gst/audioparsers/gstmpegaudioparse.c index 7566c03d32..f8987bf9c7 100644 --- a/gst/audioparsers/gstmpegaudioparse.c +++ b/gst/audioparsers/gstmpegaudioparse.c @@ -196,6 +196,7 @@ gst_mpeg_audio_parse_reset (GstMpegAudioParse * mp3parse) mp3parse->sent_codec_tag = FALSE; mp3parse->last_posted_crc = CRC_UNKNOWN; mp3parse->last_posted_channel_mode = MPEG_AUDIO_CHANNEL_MODE_UNKNOWN; + mp3parse->freerate = 0; mp3parse->hdr_bitrate = 0; @@ -302,14 +303,16 @@ mp3_type_frame_length_from_header (GstMpegAudioParse * mp3parse, guint32 header, bitrate = (header >> 12) & 0xF; bitrate = mp3types_bitrates[lsf][layer - 1][bitrate] * 1000; - /* The caller has ensured we have a valid header, so bitrate can't be - zero here. */ - g_assert (bitrate != 0); + if (!bitrate) { + GST_LOG_OBJECT (mp3parse, "using freeform bitrate"); + bitrate = mp3parse->freerate; + } samplerate = (header >> 10) & 0x3; samplerate = mp3types_freqs[lsf + mpg25][samplerate]; - padding = (header >> 9) & 0x1; + /* force 0 length if 0 bitrate */ + padding = (bitrate > 0) ? (header >> 9) & 0x1 : 0; mode = (header >> 6) & 0x3; channels = (mode == 3) ? 1 : 2; @@ -414,8 +417,7 @@ gst_mp3parse_validate_extended (GstMpegAudioParse * mp3parse, GstBuffer * buf, (guint) next_header & HDRMASK, bpf); *valid = FALSE; goto cleanup; - } else if ((((next_header >> 12) & 0xf) == 0) || - (((next_header >> 12) & 0xf) == 0xf)) { + } else if (((next_header >> 12) & 0xf) == 0xf) { /* The essential parts were the same, but the bitrate held an invalid value - also reject */ GST_DEBUG_OBJECT (mp3parse, "next header invalid (bitrate)"); @@ -426,6 +428,13 @@ gst_mp3parse_validate_extended (GstMpegAudioParse * mp3parse, GstBuffer * buf, bpf = mp3_type_frame_length_from_header (mp3parse, next_header, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + /* if no bitrate, and no freeform rate known, then fail */ + if (G_UNLIKELY (!bpf)) { + GST_DEBUG_OBJECT (mp3parse, "next header invalid (bitrate 0)"); + *valid = FALSE; + return TRUE; + } + offset += bpf; frames_found++; } @@ -459,11 +468,6 @@ gst_mpeg_audio_parse_head_check (GstMpegAudioParse * mp3parse, return FALSE; } /* if it's an invalid bitrate */ - if (((head >> 12) & 0xf) == 0x0) { - GST_WARNING_OBJECT (mp3parse, "invalid bitrate: 0x%lx." - "Free format files are not supported yet", (head >> 12) & 0xf); - return FALSE; - } if (((head >> 12) & 0xf) == 0xf) { GST_WARNING_OBJECT (mp3parse, "invalid bitrate: 0x%lx", (head >> 12) & 0xf); return FALSE; @@ -484,6 +488,115 @@ gst_mpeg_audio_parse_head_check (GstMpegAudioParse * mp3parse, return TRUE; } +/* Determines possible freeform frame rate/size by looking for next + * header with valid bitrate (0 or otherwise valid) (and sufficiently + * matching current header). + * + * Returns TRUE if we've found such one, and *rate then contains rate + * (or *rate contains 0 if decided no freeframe size could be determined). + * If not enough data, returns FALSE. + */ +static gboolean +gst_mp3parse_find_freerate (GstMpegAudioParse * mp3parse, GstMapInfo * map, + guint32 header, gboolean at_eos, gint * _rate) +{ + guint32 next_header; + const guint8 *data; + guint available; + int offset = 4; + gulong samplerate, rate, layer, padding; + gboolean valid; + gint lsf, mpg25; + + available = map->size; + data = map->data; + + *_rate = 0; + + /* pick apart header again partially */ + if (header & (1 << 20)) { + lsf = (header & (1 << 19)) ? 0 : 1; + mpg25 = 0; + } else { + lsf = 1; + mpg25 = 1; + } + layer = 4 - ((header >> 17) & 0x3); + samplerate = (header >> 10) & 0x3; + samplerate = mp3types_freqs[lsf + mpg25][samplerate]; + padding = (header >> 9) & 0x1; + + for (; offset < available; ++offset) { + /* Check if we have enough data for all these frames, plus the next + frame header. */ + if (available < offset + 4) { + if (at_eos) { + /* Running out of data; failed to determine size */ + return TRUE; + } else { + return FALSE; + } + } + + valid = FALSE; + next_header = GST_READ_UINT32_BE (data + offset); + if ((next_header & 0xFFE00000) != 0xFFE00000) + goto next; + + GST_DEBUG_OBJECT (mp3parse, "At %d: header=%08X, header2=%08X", + offset, (unsigned int) header, (unsigned int) next_header); + + if ((next_header & HDRMASK) != (header & HDRMASK)) { + /* If any of the unmasked bits don't match, then it's not valid */ + GST_DEBUG_OBJECT (mp3parse, "next header doesn't match " + "(header=%08X (%08X), header2=%08X (%08X))", + (guint) header, (guint) header & HDRMASK, (guint) next_header, + (guint) next_header & HDRMASK); + goto next; + } else if (((next_header >> 12) & 0xf) == 0xf) { + /* The essential parts were the same, but the bitrate held an + invalid value - also reject */ + GST_DEBUG_OBJECT (mp3parse, "next header invalid (bitrate)"); + goto next; + } + + valid = TRUE; + + next: + /* almost accept as free frame */ + if (layer == 1) { + rate = samplerate * (offset - 4 * padding + 4) / 48000; + } else { + rate = samplerate * (offset - padding + 1) / (144 >> lsf) / 1000; + } + + if (valid) { + GST_LOG_OBJECT (mp3parse, "calculated rate %lu", rate * 1000); + if (rate < 8 || (layer == 3 && rate > 640)) { + GST_DEBUG_OBJECT (mp3parse, "rate invalid"); + if (rate < 8) { + /* maybe some hope */ + continue; + } else { + GST_DEBUG_OBJECT (mp3parse, "aborting"); + /* give up */ + break; + } + } + *_rate = rate * 1000; + break; + } else { + /* avoid indefinite searching */ + if (rate > 1000) { + GST_DEBUG_OBJECT (mp3parse, "exceeded sanity rate; aborting"); + break; + } + } + } + + return TRUE; +} + static GstFlowReturn gst_mpeg_audio_parse_handle_frame (GstBaseParse * parse, GstBaseParseFrame * frame, gint * skipsize) @@ -532,9 +645,14 @@ gst_mpeg_audio_parse_handle_frame (GstBaseParse * parse, GST_LOG_OBJECT (parse, "got frame"); + lost_sync = GST_BASE_PARSE_LOST_SYNC (parse); + draining = GST_BASE_PARSE_DRAINING (parse); + + if (G_UNLIKELY (lost_sync)) + mp3parse->freerate = 0; + bpf = mp3_type_frame_length_from_header (mp3parse, header, &version, &layer, &channels, &bitrate, &rate, &mode, &crc); - g_assert (bpf != 0); if (channels != mp3parse->channels || rate != mp3parse->rate || layer != mp3parse->layer || version != mp3parse->version) @@ -542,8 +660,31 @@ gst_mpeg_audio_parse_handle_frame (GstBaseParse * parse, else caps_change = FALSE; - lost_sync = GST_BASE_PARSE_LOST_SYNC (parse); - draining = GST_BASE_PARSE_DRAINING (parse); + /* maybe free format */ + if (bpf == 0) { + GST_LOG_OBJECT (mp3parse, "possibly free format"); + if (lost_sync || mp3parse->freerate == 0) { + GST_DEBUG_OBJECT (mp3parse, "finding free format rate"); + if (!gst_mp3parse_find_freerate (mp3parse, &map, header, draining, + &valid)) { + /* not enough data */ + gst_base_parse_set_min_frame_size (parse, valid); + *skipsize = 0; + return FALSE; + } else { + GST_DEBUG_OBJECT (parse, "determined freeform size %d", valid); + mp3parse->freerate = valid; + } + } + /* try again */ + bpf = mp3_type_frame_length_from_header (mp3parse, header, + &version, &layer, &channels, &bitrate, &rate, &mode, &crc); + if (!bpf) { + /* did not come up with valid freeform length, reject after all */ + *skipsize = 1; + return FALSE; + } + } if (!draining && (lost_sync || caps_change)) { if (!gst_mp3parse_validate_extended (mp3parse, buf, header, bpf, draining, diff --git a/gst/audioparsers/gstmpegaudioparse.h b/gst/audioparsers/gstmpegaudioparse.h index 7580001309..6b42673552 100644 --- a/gst/audioparsers/gstmpegaudioparse.h +++ b/gst/audioparsers/gstmpegaudioparse.h @@ -60,6 +60,8 @@ struct _GstMpegAudioParse { /* samples per frame */ gint spf; + gint freerate; + gboolean sent_codec_tag; guint last_posted_bitrate; gint last_posted_crc, last_crc; diff --git a/gst/audioparsers/gstwavpackparse.c b/gst/audioparsers/gstwavpackparse.c new file mode 100644 index 0000000000..637198d74d --- /dev/null +++ b/gst/audioparsers/gstwavpackparse.c @@ -0,0 +1,640 @@ +/* GStreamer Wavpack parser + * Copyright (C) 2012 Mark Nauwelaerts + * Copyright (C) 2012 Nokia Corporation. All rights reserved. + * Contact: Stefan Kost + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +/** + * SECTION:element-wavpackparse + * @short_description: Wavpack parser + * @see_also: #GstAmrParse, #GstAACParse + * + * This is an Wavpack parser. + * + * + * Example launch line + * |[ + * gst-launch filesrc location=abc.wavpack ! wavpackparse ! wavpackdec ! audioresample ! audioconvert ! autoaudiosink + * ]| + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "gstwavpackparse.h" + +#include +#include + +GST_DEBUG_CATEGORY_STATIC (wavpack_parse_debug); +#define GST_CAT_DEFAULT wavpack_parse_debug + +static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("audio/x-wavpack, " + "depth = (int) [ 1, 32 ], " + "channels = (int) [ 1, 8 ], " + "rate = (int) [ 6000, 192000 ], " "framed = (boolean) TRUE; " + "audio/x-wavpack-correction, " "framed = (boolean) TRUE") + ); + +static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("audio/x-wavpack")); + +static void gst_wavpack_parse_finalize (GObject * object); + +static gboolean gst_wavpack_parse_start (GstBaseParse * parse); +static gboolean gst_wavpack_parse_stop (GstBaseParse * parse); +static GstFlowReturn gst_wavpack_parse_handle_frame (GstBaseParse * parse, + GstBaseParseFrame * frame, gint * skipsize); +static GstCaps *gst_wavpack_parse_get_sink_caps (GstBaseParse * parse, + GstCaps * filter); + +#define gst_wavpack_parse_parent_class parent_class +G_DEFINE_TYPE (GstWavpackParse, gst_wavpack_parse, GST_TYPE_BASE_PARSE); + +static void +gst_wavpack_parse_class_init (GstWavpackParseClass * klass) +{ + GstBaseParseClass *parse_class = GST_BASE_PARSE_CLASS (klass); + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + GST_DEBUG_CATEGORY_INIT (wavpack_parse_debug, "wavpackparse", 0, + "Wavpack audio stream parser"); + + object_class->finalize = gst_wavpack_parse_finalize; + + parse_class->start = GST_DEBUG_FUNCPTR (gst_wavpack_parse_start); + parse_class->stop = GST_DEBUG_FUNCPTR (gst_wavpack_parse_stop); + parse_class->handle_frame = + GST_DEBUG_FUNCPTR (gst_wavpack_parse_handle_frame); + parse_class->get_sink_caps = + GST_DEBUG_FUNCPTR (gst_wavpack_parse_get_sink_caps); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&sink_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&src_template)); + + gst_element_class_set_details_simple (element_class, + "Wavpack audio stream parser", "Codec/Parser/Audio", + "Wavpack parser", "Mark Nauwelaerts "); +} + +static void +gst_wavpack_parse_reset (GstWavpackParse * wvparse) +{ + wvparse->channels = -1; + wvparse->channel_mask = 0; + wvparse->sample_rate = -1; + wvparse->width = -1; + wvparse->total_samples = 0; +} + +static void +gst_wavpack_parse_init (GstWavpackParse * wvparse) +{ + gst_wavpack_parse_reset (wvparse); +} + +static void +gst_wavpack_parse_finalize (GObject * object) +{ + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static gboolean +gst_wavpack_parse_start (GstBaseParse * parse) +{ + GstWavpackParse *wvparse = GST_WAVPACK_PARSE (parse); + + GST_DEBUG_OBJECT (parse, "starting"); + + gst_wavpack_parse_reset (wvparse); + + /* need header at least */ + gst_base_parse_set_min_frame_size (GST_BASE_PARSE (wvparse), + sizeof (WavpackHeader)); + + /* inform baseclass we can come up with ts, based on counters in packets */ + gst_base_parse_set_has_timing_info (GST_BASE_PARSE_CAST (wvparse), TRUE); + gst_base_parse_set_syncable (GST_BASE_PARSE_CAST (wvparse), TRUE); + + return TRUE; +} + +static gboolean +gst_wavpack_parse_stop (GstBaseParse * parse) +{ + GST_DEBUG_OBJECT (parse, "stopping"); + + return TRUE; +} + +static gint +gst_wavpack_get_default_channel_mask (gint nchannels) +{ + gint channel_mask = 0; + + /* Set the default channel mask for the given number of channels. + * It's the same as for WAVE_FORMAT_EXTENDED: + * http://www.microsoft.com/whdc/device/audio/multichaud.mspx + */ + switch (nchannels) { + case 11: + channel_mask |= 0x00400; + channel_mask |= 0x00200; + case 9: + channel_mask |= 0x00100; + case 8: + channel_mask |= 0x00080; + channel_mask |= 0x00040; + case 6: + channel_mask |= 0x00020; + channel_mask |= 0x00010; + case 4: + channel_mask |= 0x00008; + case 3: + channel_mask |= 0x00004; + case 2: + channel_mask |= 0x00002; + channel_mask |= 0x00001; + break; + case 1: + /* For mono use front center */ + channel_mask |= 0x00004; + break; + } + + return channel_mask; +} + +static const struct +{ + const guint32 ms_mask; + const GstAudioChannelPosition gst_pos; +} layout_mapping[] = { + { + 0x00001, GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT}, { + 0x00002, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, { + 0x00004, GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER}, { + 0x00008, GST_AUDIO_CHANNEL_POSITION_LFE1}, { + 0x00010, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT}, { + 0x00020, GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT}, { + 0x00040, GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER}, { + 0x00080, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER}, { + 0x00100, GST_AUDIO_CHANNEL_POSITION_REAR_CENTER}, { + 0x00200, GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT}, { + 0x00400, GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT}, { + 0x00800, GST_AUDIO_CHANNEL_POSITION_TOP_CENTER}, { + 0x01000, GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_LEFT}, { + 0x02000, GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_CENTER}, { + 0x04000, GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_RIGHT}, { + 0x08000, GST_AUDIO_CHANNEL_POSITION_TOP_REAR_LEFT}, { + 0x10000, GST_AUDIO_CHANNEL_POSITION_TOP_REAR_CENTER}, { + 0x20000, GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT} +}; + +#define MAX_CHANNEL_POSITIONS G_N_ELEMENTS (layout_mapping) + +static gboolean +gst_wavpack_get_channel_positions (gint num_channels, gint layout, + GstAudioChannelPosition * pos) +{ + gint i, p; + + if (num_channels == 1 && layout == 0x00004) { + pos[0] = GST_AUDIO_CHANNEL_POSITION_MONO; + return TRUE; + } + + p = 0; + for (i = 0; i < MAX_CHANNEL_POSITIONS; ++i) { + if ((layout & layout_mapping[i].ms_mask) != 0) { + if (p >= num_channels) { + GST_WARNING ("More bits set in the channel layout map than there " + "are channels! Broken file"); + return FALSE; + } + if (layout_mapping[i].gst_pos == GST_AUDIO_CHANNEL_POSITION_INVALID) { + GST_WARNING ("Unsupported channel position (mask 0x%08x) in channel " + "layout map - ignoring those channels", layout_mapping[i].ms_mask); + /* what to do? just ignore it and let downstream deal with a channel + * layout that has INVALID positions in it for now ... */ + } + pos[p] = layout_mapping[i].gst_pos; + ++p; + } + } + + if (p != num_channels) { + GST_WARNING ("Only %d bits set in the channel layout map, but there are " + "supposed to be %d channels! Broken file", p, num_channels); + return FALSE; + } + + return TRUE; +} + +static const guint32 sample_rates[] = { + 6000, 8000, 9600, 11025, 12000, 16000, 22050, + 24000, 32000, 44100, 48000, 64000, 88200, 96000, 192000 +}; + +#define CHECK(call) { \ + if (!call) \ + goto read_failed; \ +} + +/* caller ensures properly sync'ed with enough data */ +static gboolean +gst_wavpack_parse_frame_metadata (GstWavpackParse * parse, GstBuffer * buf, + gint skip, WavpackHeader * wph, WavpackInfo * wpi) +{ + GstByteReader br; + gint i; + GstMapInfo map; + + g_return_val_if_fail (wph != NULL || wpi != NULL, FALSE); + g_return_val_if_fail (gst_buffer_get_size (buf) >= + skip + sizeof (WavpackHeader), FALSE); + + gst_buffer_map (buf, &map, GST_MAP_READ); + + gst_byte_reader_init (&br, map.data + skip, wph->ckSize + 8); + /* skip past header */ + gst_byte_reader_skip_unchecked (&br, sizeof (WavpackHeader)); + + /* get some basics from header */ + i = (wph->flags >> 23) & 0xF; + if (!wpi->rate) + wpi->rate = (i < G_N_ELEMENTS (sample_rates)) ? sample_rates[i] : 44100; + wpi->width = ((wph->flags & 0x3) + 1) * 8; + if (!wpi->channels) + wpi->channels = (wph->flags & 0x4) ? 1 : 2; + if (!wpi->channel_mask) + wpi->channel_mask = 5 - wpi->channels; + + /* need to dig metadata blocks for some more */ + while (gst_byte_reader_get_remaining (&br)) { + gint size = 0; + guint16 size2 = 0; + guint8 c, id; + const guint8 *data; + GstByteReader mbr; + + CHECK (gst_byte_reader_get_uint8 (&br, &id)); + CHECK (gst_byte_reader_get_uint8 (&br, &c)); + if (id & ID_LARGE) + CHECK (gst_byte_reader_get_uint16_le (&br, &size2)); + size = size2; + size <<= 8; + size += c; + size <<= 1; + if (id & ID_ODD_SIZE) + size--; + + CHECK (gst_byte_reader_get_data (&br, size + (size & 1), &data)); + gst_byte_reader_init (&mbr, data, size); + + switch (id) { + case ID_WVC_BITSTREAM: + GST_LOG_OBJECT (parse, "correction bitstream"); + wpi->correction = TRUE; + break; + case ID_WV_BITSTREAM: + case ID_WVX_BITSTREAM: + break; + case ID_SAMPLE_RATE: + if (size == 3) { + CHECK (gst_byte_reader_get_uint24_le (&mbr, &wpi->rate)); + GST_LOG_OBJECT (parse, "updated with custom rate %d", wpi->rate); + } else { + GST_DEBUG_OBJECT (parse, "unexpected size for SAMPLE_RATE metadata"); + } + break; + case ID_CHANNEL_INFO: + { + guint16 channels; + guint32 mask = 0; + + if (size == 6) { + CHECK (gst_byte_reader_get_uint16_le (&mbr, &channels)); + channels = channels & 0xFFF; + CHECK (gst_byte_reader_get_uint24_le (&mbr, &mask)); + } else if (size) { + CHECK (gst_byte_reader_get_uint8 (&mbr, &c)); + channels = c; + while (gst_byte_reader_get_uint8 (&mbr, &c)) + mask |= (((guint32) c) << 8); + } else { + GST_DEBUG_OBJECT (parse, "unexpected size for CHANNEL_INFO metadata"); + break; + } + wpi->channels = channels; + wpi->channel_mask = mask; + break; + } + default: + GST_LOG_OBJECT (parse, "unparsed ID 0x%x", id); + break; + } + } + + gst_buffer_unmap (buf, &map); + + return TRUE; + + /* ERRORS */ +read_failed: + { + gst_buffer_unmap (buf, &map); + GST_DEBUG_OBJECT (parse, "short read while parsing metadata"); + /* let's look the other way anyway */ + return TRUE; + } +} + +/* caller ensures properly sync'ed with enough data */ +static gboolean +gst_wavpack_parse_frame_header (GstWavpackParse * parse, GstBuffer * buf, + gint skip, WavpackHeader * _wph) +{ + GstByteReader br; + WavpackHeader wph; + GstMapInfo map; + + g_return_val_if_fail (gst_buffer_get_size (buf) >= + skip + sizeof (WavpackHeader), FALSE); + + gst_buffer_map (buf, &map, GST_MAP_READ); + gst_byte_reader_init (&br, map.data, map.size); + + /* marker */ + gst_byte_reader_skip_unchecked (&br, skip + 4); + + /* read */ + gst_byte_reader_get_uint32_le (&br, &wph.ckSize); + gst_byte_reader_get_uint16_le (&br, &wph.version); + gst_byte_reader_get_uint8 (&br, &wph.track_no); + gst_byte_reader_get_uint8 (&br, &wph.index_no); + gst_byte_reader_get_uint32_le (&br, &wph.total_samples); + gst_byte_reader_get_uint32_le (&br, &wph.block_index); + gst_byte_reader_get_uint32_le (&br, &wph.block_samples); + gst_byte_reader_get_uint32_le (&br, &wph.flags); + gst_byte_reader_get_uint32_le (&br, &wph.crc); + + /* dump */ + GST_LOG_OBJECT (parse, "size %d", wph.ckSize); + GST_LOG_OBJECT (parse, "version 0x%x", wph.version); + GST_LOG_OBJECT (parse, "total samples %d", wph.total_samples); + GST_LOG_OBJECT (parse, "block index %d", wph.block_index); + GST_LOG_OBJECT (parse, "block samples %d", wph.block_samples); + GST_LOG_OBJECT (parse, "flags 0x%x", wph.flags); + GST_LOG_OBJECT (parse, "crc 0x%x", wph.flags); + + if (!parse->total_samples && wph.block_index == 0 && wph.total_samples != -1) { + GST_DEBUG_OBJECT (parse, "determined duration of %u samples", + wph.total_samples); + parse->total_samples = wph.total_samples; + } + + if (_wph) + *_wph = wph; + + gst_buffer_unmap (buf, &map); + + return TRUE; +} + +static GstFlowReturn +gst_wavpack_parse_handle_frame (GstBaseParse * parse, + GstBaseParseFrame * frame, gint * skipsize) +{ + GstWavpackParse *wvparse = GST_WAVPACK_PARSE (parse); + GstBuffer *buf = frame->buffer; + GstByteReader reader; + gint off; + guint rate, chans, width, mask; + gboolean lost_sync, draining, final; + guint frmsize = 0; + WavpackHeader wph; + WavpackInfo wpi = { 0, }; + GstMapInfo map; + + if (G_UNLIKELY (gst_buffer_get_size (buf) < sizeof (WavpackHeader))) + return FALSE; + + gst_buffer_map (buf, &map, GST_MAP_READ); + gst_byte_reader_init (&reader, map.data, map.size); + + /* scan for 'wvpk' marker */ + off = gst_byte_reader_masked_scan_uint32 (&reader, 0xffffffff, 0x7776706b, + 0, map.size); + + GST_LOG_OBJECT (parse, "possible sync at buffer offset %d", off); + + /* didn't find anything that looks like a sync word, skip */ + if (off < 0) { + *skipsize = map.size - 3; + goto skip; + } + + /* possible frame header, but not at offset 0? skip bytes before sync */ + if (off > 0) { + *skipsize = off; + goto skip; + } + + /* make sure the values in the frame header look sane */ + gst_wavpack_parse_frame_header (wvparse, buf, 0, &wph); + frmsize = wph.ckSize + 8; + + /* need the entire frame for parsing */ + if (gst_byte_reader_get_remaining (&reader) < frmsize) + goto more; + + /* got a frame, now we can dig for some more metadata */ + GST_LOG_OBJECT (parse, "got frame"); + gst_wavpack_parse_frame_metadata (wvparse, buf, 0, &wph, &wpi); + + lost_sync = GST_BASE_PARSE_LOST_SYNC (parse); + draining = GST_BASE_PARSE_DRAINING (parse); + + while (!(final = (wph.flags & FLAG_FINAL_BLOCK)) || (lost_sync && !draining)) { + guint32 word = 0; + + GST_LOG_OBJECT (wvparse, "checking next frame syncword; " + "lost_sync: %d, draining: %d, final: %d", lost_sync, draining, final); + + if (!gst_byte_reader_skip (&reader, wph.ckSize + 8) || + !gst_byte_reader_peek_uint32_be (&reader, &word)) { + GST_DEBUG_OBJECT (wvparse, "... but not sufficient data"); + frmsize += 4; + goto more; + } else { + if (word != 0x7776706b) { + GST_DEBUG_OBJECT (wvparse, "0x%x not OK", word); + *skipsize = off + 2; + goto skip; + } + /* need to parse each frame/block for metadata if several ones */ + if (!final) { + gint av; + + GST_LOG_OBJECT (wvparse, "checking frame at offset %d (0x%x)", + frmsize, frmsize); + av = gst_byte_reader_get_remaining (&reader); + if (av < sizeof (WavpackHeader)) { + frmsize += sizeof (WavpackHeader); + goto more; + } + gst_wavpack_parse_frame_header (wvparse, buf, frmsize, &wph); + off = frmsize; + frmsize += wph.ckSize + 8; + if (av < wph.ckSize + 8) + goto more; + gst_wavpack_parse_frame_metadata (wvparse, buf, off, &wph, &wpi); + /* could also check for matching block_index and block_samples ?? */ + } + } + + /* resynced if we make it here */ + lost_sync = FALSE; + } + + rate = wpi.rate; + width = wpi.width; + chans = wpi.channels; + mask = wpi.channel_mask; + + GST_LOG_OBJECT (parse, "rate: %u, width: %u, chans: %u", rate, width, chans); + + GST_BUFFER_TIMESTAMP (buf) = + gst_util_uint64_scale_int (wph.block_index, GST_SECOND, rate); + GST_BUFFER_DURATION (buf) = + gst_util_uint64_scale_int (wph.block_index + wph.block_samples, + GST_SECOND, rate) - GST_BUFFER_TIMESTAMP (buf); + + if (G_UNLIKELY (wvparse->sample_rate != rate || wvparse->channels != chans + || wvparse->width != width || wvparse->channel_mask != mask)) { + GstCaps *caps; + + if (wpi.correction) { + caps = gst_caps_new_simple ("audio/x-wavpack-correction", + "framed", G_TYPE_BOOLEAN, TRUE, NULL); + } else { + caps = gst_caps_new_simple ("audio/x-wavpack", + "channels", G_TYPE_INT, chans, + "rate", G_TYPE_INT, rate, + "depth", G_TYPE_INT, width, "framed", G_TYPE_BOOLEAN, TRUE, NULL); + + if (!mask) + mask = gst_wavpack_get_default_channel_mask (wvparse->channels); + if (mask != 0) { + GstAudioChannelPosition pos[64] = + { GST_AUDIO_CHANNEL_POSITION_INVALID, }; + guint64 gmask; + + if (!gst_wavpack_get_channel_positions (chans, mask, pos)) { + GST_WARNING_OBJECT (wvparse, "Failed to determine channel layout"); + } else { + gst_audio_channel_positions_to_mask (pos, chans, &gmask); + if (gmask) + gst_caps_set_simple (caps, + "channel-mask", GST_TYPE_BITMASK, gmask, NULL); + } + } + } + + gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps); + gst_caps_unref (caps); + + wvparse->sample_rate = rate; + wvparse->channels = chans; + wvparse->width = width; + wvparse->channel_mask = mask; + + if (wvparse->total_samples) { + GST_DEBUG_OBJECT (wvparse, "setting duration"); + gst_base_parse_set_duration (GST_BASE_PARSE (wvparse), + GST_FORMAT_TIME, gst_util_uint64_scale_int (wvparse->total_samples, + GST_SECOND, wvparse->sample_rate), 0); + } + } + + /* return to normal size */ + gst_base_parse_set_min_frame_size (parse, sizeof (WavpackHeader)); + gst_buffer_unmap (buf, &map); + + return gst_base_parse_finish_frame (parse, frame, frmsize); + +skip: + gst_buffer_unmap (buf, &map); + GST_LOG_OBJECT (wvparse, "skipping %d", *skipsize); + return GST_FLOW_OK; + +more: + gst_buffer_unmap (buf, &map); + GST_LOG_OBJECT (wvparse, "need at least %u", frmsize); + gst_base_parse_set_min_frame_size (parse, frmsize); + *skipsize = 0; + return GST_FLOW_OK; +} + +static GstCaps * +gst_wavpack_parse_get_sink_caps (GstBaseParse * parse, GstCaps * filter) +{ + GstCaps *peercaps; + GstCaps *res; + + /* FIXME: handle filter caps */ + + peercaps = gst_pad_get_allowed_caps (GST_BASE_PARSE_SRC_PAD (parse)); + if (peercaps) { + guint i, n; + + /* Remove the framed field */ + peercaps = gst_caps_make_writable (peercaps); + n = gst_caps_get_size (peercaps); + for (i = 0; i < n; i++) { + GstStructure *s = gst_caps_get_structure (peercaps, i); + + gst_structure_remove_field (s, "framed"); + } + + res = + gst_caps_intersect_full (peercaps, + gst_pad_get_pad_template_caps (GST_BASE_PARSE_SRC_PAD (parse)), + GST_CAPS_INTERSECT_FIRST); + gst_caps_unref (peercaps); + } else { + res = + gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_PARSE_SINK_PAD + (parse))); + } + + return res; +} diff --git a/gst/audioparsers/gstwavpackparse.h b/gst/audioparsers/gstwavpackparse.h new file mode 100644 index 0000000000..72ad340a15 --- /dev/null +++ b/gst/audioparsers/gstwavpackparse.h @@ -0,0 +1,131 @@ +/* GStreamer Wavpack parser + * Copyright (C) 2012 Mark Nauwelaerts + * Copyright (C) 2012 Nokia Corporation. All rights reserved. + * Contact: Stefan Kost + * + * 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_WAVPACK_PARSE_H__ +#define __GST_WAVPACK_PARSE_H__ + +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_WAVPACK_PARSE \ + (gst_wavpack_parse_get_type()) +#define GST_WAVPACK_PARSE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_WAVPACK_PARSE, GstWavpackParse)) +#define GST_WAVPACK_PARSE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_WAVPACK_PARSE, GstWavpackParseClass)) +#define GST_IS_WAVPACK_PARSE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_WAVPACK_PARSE)) +#define GST_IS_WAVPACK_PARSE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_WAVPACK_PARSE)) + + +#define ID_UNIQUE 0x3f +#define ID_OPTIONAL_DATA 0x20 +#define ID_ODD_SIZE 0x40 +#define ID_LARGE 0x80 + +#define ID_DUMMY 0x0 +#define ID_ENCODER_INFO 0x1 +#define ID_DECORR_TERMS 0x2 +#define ID_DECORR_WEIGHTS 0x3 +#define ID_DECORR_SAMPLES 0x4 +#define ID_ENTROPY_VARS 0x5 +#define ID_HYBRID_PROFILE 0x6 +#define ID_SHAPING_WEIGHTS 0x7 +#define ID_FLOAT_INFO 0x8 +#define ID_INT32_INFO 0x9 +#define ID_WV_BITSTREAM 0xa +#define ID_WVC_BITSTREAM 0xb +#define ID_WVX_BITSTREAM 0xc +#define ID_CHANNEL_INFO 0xd + +#define ID_RIFF_HEADER (ID_OPTIONAL_DATA | 0x1) +#define ID_RIFF_TRAILER (ID_OPTIONAL_DATA | 0x2) +#define ID_REPLAY_GAIN (ID_OPTIONAL_DATA | 0x3) +#define ID_CUESHEET (ID_OPTIONAL_DATA | 0x4) +#define ID_CONFIG_BLOCK (ID_OPTIONAL_DATA | 0x5) +#define ID_MD5_CHECKSUM (ID_OPTIONAL_DATA | 0x6) +#define ID_SAMPLE_RATE (ID_OPTIONAL_DATA | 0x7) + +#define FLAG_FINAL_BLOCK (1 << 12) + +typedef struct { + char ckID [4]; /* "wvpk" */ + guint32 ckSize; /* size of entire block (minus 8, of course) */ + guint16 version; /* 0x402 to 0x410 are currently valid for decode */ + guchar track_no; /* track number (0 if not used, like now) */ + guchar index_no; /* track sub-index (0 if not used, like now) */ + guint32 total_samples; /* total samples for entire file, but this is + * only valid if block_index == 0 and a value of + * -1 indicates unknown length */ + guint32 block_index; /* index of first sample in block relative to + * beginning of file (normally this would start + * at 0 for the first block) */ + guint32 block_samples; /* number of samples in this block (0 = no audio) */ + guint32 flags; /* various flags for id and decoding */ + guint32 crc; /* crc for actual decoded data */ +} WavpackHeader; + +typedef struct { + gboolean correction; + guint rate; + guint width; + guint channels; + guint channel_mask; +} WavpackInfo; + +typedef struct _GstWavpackParse GstWavpackParse; +typedef struct _GstWavpackParseClass GstWavpackParseClass; + +/** + * GstWavpackParse: + * + * The opaque GstWavpackParse object + */ +struct _GstWavpackParse { + GstBaseParse baseparse; + + /*< private >*/ + gint sample_rate; + gint channels; + gint width; + gint channel_mask; + + guint total_samples; +}; + +/** + * GstWavpackParseClass: + * @parent_class: Element parent class. + * + * The opaque GstWavpackParseClass data structure. + */ +struct _GstWavpackParseClass { + GstBaseParseClass baseparse_class; +}; + +GType gst_wavpack_parse_get_type (void); + +G_END_DECLS + +#endif /* __GST_WAVPACK_PARSE_H__ */ diff --git a/gst/audioparsers/plugin.c b/gst/audioparsers/plugin.c index ae8332d3fc..fe64a8a419 100644 --- a/gst/audioparsers/plugin.c +++ b/gst/audioparsers/plugin.c @@ -27,6 +27,7 @@ #include "gstdcaparse.h" #include "gstflacparse.h" #include "gstmpegaudioparse.h" +#include "gstwavpackparse.h" static gboolean plugin_init (GstPlugin * plugin) @@ -45,6 +46,8 @@ plugin_init (GstPlugin * plugin) GST_RANK_PRIMARY + 1, GST_TYPE_FLAC_PARSE); ret &= gst_element_register (plugin, "mpegaudioparse", GST_RANK_PRIMARY + 2, GST_TYPE_MPEG_AUDIO_PARSE); + ret &= gst_element_register (plugin, "wavpackparse", + GST_RANK_PRIMARY + 1, GST_TYPE_WAVPACK_PARSE); return ret; } diff --git a/gst/avi/gstavimux.c b/gst/avi/gstavimux.c index dfa6044425..10601eb2f3 100644 --- a/gst/avi/gstavimux.c +++ b/gst/avi/gstavimux.c @@ -178,7 +178,7 @@ static GstStaticPadTemplate audio_sink_factory = "rate = (int) [ 1000, 96000 ], " "channels = (int) [ 1, 2 ]; " #endif*/ "audio/x-ac3, " - "rate = (int) [ 1000, 96000 ], " "channels = (int) [ 1, 2 ]; " + "rate = (int) [ 1000, 96000 ], " "channels = (int) [ 1, 6 ]; " "audio/x-alaw, " "rate = (int) [ 1000, 48000 ], " "channels = (int) [ 1, 2 ]; " "audio/x-mulaw, " diff --git a/gst/debugutils/gstcapssetter.c b/gst/debugutils/gstcapssetter.c index 977a502b40..ee065ff03b 100644 --- a/gst/debugutils/gstcapssetter.c +++ b/gst/debugutils/gstcapssetter.c @@ -294,7 +294,7 @@ gst_caps_setter_set_property (GObject * object, guint prop_id, } /* try to activate these new caps next time around */ - gst_base_transform_reconfigure (GST_BASE_TRANSFORM (filter)); + gst_base_transform_reconfigure_src (GST_BASE_TRANSFORM (filter)); break; } case PROP_JOIN: diff --git a/gst/flv/gstflvmux.c b/gst/flv/gstflvmux.c index 1fa60afd72..8119e9db33 100644 --- a/gst/flv/gstflvmux.c +++ b/gst/flv/gstflvmux.c @@ -1144,6 +1144,29 @@ gst_flv_mux_write_header (GstFlvMux * mux) GSList *l; GstFlowReturn ret; + /* if not streaming, check if downstream is seekable */ + if (!mux->streamable) { + gboolean seekable; + GstQuery *query; + + query = gst_query_new_seeking (GST_FORMAT_BYTES); + if (gst_pad_peer_query (mux->srcpad, query)) { + gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL); + GST_INFO_OBJECT (mux, "downstream is %sseekable", seekable ? "" : "not "); + } else { + /* have to assume seeking is supported if query not handled downstream */ + GST_WARNING_OBJECT (mux, "downstream did not handle seeking query"); + seekable = FALSE; + } + if (!seekable) { + mux->streamable = TRUE; + g_object_notify (G_OBJECT (mux), "streamable"); + GST_WARNING_OBJECT (mux, "downstream is not seekable, but " + "streamable=false. Will ignore that and create streamable output " + "instead"); + } + } + header = gst_flv_mux_create_header (mux); metadata = gst_flv_mux_create_metadata (mux, TRUE); video_codec_data = NULL; diff --git a/gst/flv/gstindex.c b/gst/flv/gstindex.c index 792d4b6f09..aff8dc124b 100644 --- a/gst/flv/gstindex.c +++ b/gst/flv/gstindex.c @@ -172,7 +172,7 @@ gst_index_class_init (GstIndexClass * klass) gst_index_signals[ENTRY_ADDED] = g_signal_new ("entry-added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstIndexClass, entry_added), NULL, NULL, - gst_marshal_VOID__BOXED, G_TYPE_NONE, 1, GST_TYPE_INDEX_ENTRY); + NULL, G_TYPE_NONE, 1, GST_TYPE_INDEX_ENTRY); gobject_class->set_property = gst_index_set_property; gobject_class->get_property = gst_index_get_property; diff --git a/gst/goom2k1/gstgoom.c b/gst/goom2k1/gstgoom.c index 4421b17bb8..96c11e5dac 100644 --- a/gst/goom2k1/gstgoom.c +++ b/gst/goom2k1/gstgoom.c @@ -508,7 +508,7 @@ gst_goom_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) } GST_DEBUG_OBJECT (goom, - "Input buffer has %d samples, time=%" G_GUINT64_FORMAT, + "Input buffer has %" G_GSIZE_FORMAT " samples, time=%" G_GUINT64_FORMAT, gst_buffer_get_size (buffer) / goom->bps, GST_BUFFER_TIMESTAMP (buffer)); /* Collect samples until we have enough for an output frame */ diff --git a/gst/interleave/interleave.c b/gst/interleave/interleave.c index 6a0758d70e..e09b37fbe9 100644 --- a/gst/interleave/interleave.c +++ b/gst/interleave/interleave.c @@ -57,6 +57,10 @@ * */ +/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray + * with newer GLib versions (>= 2.31.0) */ +#define GLIB_DISABLE_DEPRECATION_WARNINGS + #ifdef HAVE_CONFIG_H # include "config.h" #endif diff --git a/gst/isomp4/gstqtmux.c b/gst/isomp4/gstqtmux.c index d06cbc8f07..9e567637ec 100644 --- a/gst/isomp4/gstqtmux.c +++ b/gst/isomp4/gstqtmux.c @@ -1629,6 +1629,30 @@ gst_qt_mux_start_file (GstQTMux * qtmux) gst_pad_set_caps (qtmux->srcpad, caps); gst_caps_unref (caps); + /* if not streaming, check if downstream is seekable */ + if (!qtmux->streamable) { + gboolean seekable; + GstQuery *query; + + query = gst_query_new_seeking (GST_FORMAT_BYTES); + if (gst_pad_peer_query (qtmux->srcpad, query)) { + gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL); + GST_INFO_OBJECT (qtmux, "downstream is %sseekable", + seekable ? "" : "not "); + } else { + /* have to assume seeking is supported if query not handled downstream */ + GST_WARNING_OBJECT (qtmux, "downstream did not handle seeking query"); + seekable = FALSE; + } + if (!seekable) { + qtmux->streamable = TRUE; + g_object_notify (G_OBJECT (qtmux), "streamable"); + GST_WARNING_OBJECT (qtmux, "downstream is not seekable, but " + "streamable=false. Will ignore that and create streamable output " + "instead"); + } + } + /* let downstream know we think in BYTES and expect to do seeking later on */ gst_segment_init (&segment, GST_FORMAT_BYTES); gst_pad_push_event (qtmux->srcpad, gst_event_new_segment (&segment)); diff --git a/gst/matroska/matroska-mux.c b/gst/matroska/matroska-mux.c index f2d3d54d4a..4b5c8f6afd 100644 --- a/gst/matroska/matroska-mux.c +++ b/gst/matroska/matroska-mux.c @@ -2340,6 +2340,29 @@ gst_matroska_mux_start (GstMatroskaMux * mux) guint32 segment_uid[4]; GTimeVal time = { 0, 0 }; + /* if not streaming, check if downstream is seekable */ + if (!mux->streamable) { + gboolean seekable; + GstQuery *query; + + query = gst_query_new_seeking (GST_FORMAT_BYTES); + if (gst_pad_peer_query (mux->srcpad, query)) { + gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL); + GST_INFO_OBJECT (mux, "downstream is %sseekable", seekable ? "" : "not "); + } else { + /* have to assume seeking is supported if query not handled downstream */ + GST_WARNING_OBJECT (mux, "downstream did not handle seeking query"); + seekable = FALSE; + } + if (!seekable) { + mux->streamable = TRUE; + g_object_notify (G_OBJECT (mux), "streamable"); + GST_WARNING_OBJECT (mux, "downstream is not seekable, but " + "streamable=false. Will ignore that and create streamable output " + "instead"); + } + } + if (!strcmp (mux->doctype, GST_MATROSKA_DOCTYPE_WEBM)) { ebml->caps = gst_caps_new_empty_simple ("video/webm"); } else { diff --git a/gst/rtpmanager/rtpsession.c b/gst/rtpmanager/rtpsession.c index 6b9061977d..95378403c0 100644 --- a/gst/rtpmanager/rtpsession.c +++ b/gst/rtpmanager/rtpsession.c @@ -17,6 +17,10 @@ * Boston, MA 02111-1307, USA. */ +/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray + * with newer GLib versions (>= 2.31.0) */ +#define GLIB_DISABLE_DEPRECATION_WARNINGS + #include #include diff --git a/gst/udp/gstdynudpsink.c b/gst/udp/gstdynudpsink.c index 4768475910..2f689c249a 100644 --- a/gst/udp/gstdynudpsink.c +++ b/gst/udp/gstdynudpsink.c @@ -21,6 +21,10 @@ * Boston, MA 02111-1307, USA. */ +/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray + * with newer GLib versions (>= 2.31.0) */ +#define GLIB_DISABLE_DEPRECATION_WARNINGS + #ifdef HAVE_CONFIG_H #include "config.h" #endif diff --git a/gst/udp/gstmultiudpsink.c b/gst/udp/gstmultiudpsink.c index 2781892557..e4d8fbb6b7 100644 --- a/gst/udp/gstmultiudpsink.c +++ b/gst/udp/gstmultiudpsink.c @@ -29,6 +29,10 @@ * It can be combined with rtp payload encoders to implement RTP streaming. */ +/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray + * with newer GLib versions (>= 2.31.0) */ +#define GLIB_DISABLE_DEPRECATION_WARNINGS + #ifdef HAVE_CONFIG_H #include "config.h" #endif diff --git a/gst/videocrop/gstvideocrop.c b/gst/videocrop/gstvideocrop.c index 8654f90e16..34cec28fa6 100644 --- a/gst/videocrop/gstvideocrop.c +++ b/gst/videocrop/gstvideocrop.c @@ -711,7 +711,7 @@ gst_video_crop_set_property (GObject * object, guint prop_id, video_crop->crop_top); GST_OBJECT_UNLOCK (video_crop); - gst_base_transform_reconfigure (GST_BASE_TRANSFORM (video_crop)); + gst_base_transform_reconfigure_src (GST_BASE_TRANSFORM (video_crop)); g_mutex_unlock (&video_crop->lock); } diff --git a/gst/videofilter/gstvideobalance.c b/gst/videofilter/gstvideobalance.c index 2716c8fe30..9d76c70331 100644 --- a/gst/videofilter/gstvideobalance.c +++ b/gst/videofilter/gstvideobalance.c @@ -637,13 +637,19 @@ gst_video_balance_colorbalance_get_value (GstColorBalance * balance, return value; } +static GstColorBalanceType +gst_video_balance_colorbalance_get_balance_type (GstColorBalance * balance) +{ + return GST_COLOR_BALANCE_SOFTWARE; +} + static void gst_video_balance_colorbalance_init (GstColorBalanceInterface * iface) { - GST_COLOR_BALANCE_TYPE (iface) = GST_COLOR_BALANCE_SOFTWARE; iface->list_channels = gst_video_balance_colorbalance_list_channels; iface->set_value = gst_video_balance_colorbalance_set_value; iface->get_value = gst_video_balance_colorbalance_get_value; + iface->get_balance_type = gst_video_balance_colorbalance_get_balance_type; } static GstColorBalanceChannel * diff --git a/gst/videofilter/gstvideoflip.c b/gst/videofilter/gstvideoflip.c index 9075a36e5c..35624b1c39 100644 --- a/gst/videofilter/gstvideoflip.c +++ b/gst/videofilter/gstvideoflip.c @@ -965,7 +965,7 @@ gst_video_flip_set_property (GObject * object, guint prop_id, gst_base_transform_set_passthrough (btrans, method == GST_VIDEO_FLIP_METHOD_IDENTITY); - gst_base_transform_reconfigure (btrans); + gst_base_transform_reconfigure_src (btrans); } else { GST_OBJECT_UNLOCK (videoflip); } diff --git a/sys/oss4/oss4-audio.c b/sys/oss4/oss4-audio.c index 09f8495963..6317400dc5 100644 --- a/sys/oss4/oss4-audio.c +++ b/sys/oss4/oss4-audio.c @@ -17,6 +17,10 @@ * Boston, MA 02111-1307, USA. */ +/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray + * with newer GLib versions (>= 2.31.0) */ +#define GLIB_DISABLE_DEPRECATION_WARNINGS + #ifdef HAVE_CONFIG_H #include "config.h" #endif diff --git a/sys/oss4/oss4-property-probe.c b/sys/oss4/oss4-property-probe.c index a99410ea27..5674da50a4 100644 --- a/sys/oss4/oss4-property-probe.c +++ b/sys/oss4/oss4-property-probe.c @@ -17,6 +17,10 @@ * Boston, MA 02111-1307, USA. */ +/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray + * with newer GLib versions (>= 2.31.0) */ +#define GLIB_DISABLE_DEPRECATION_WARNINGS + #ifdef HAVE_CONFIG_H #include #endif diff --git a/sys/v4l2/gstv4l2bufferpool.c b/sys/v4l2/gstv4l2bufferpool.c index 4e149dd764..7a68926657 100644 --- a/sys/v4l2/gstv4l2bufferpool.c +++ b/sys/v4l2/gstv4l2bufferpool.c @@ -57,6 +57,19 @@ GST_DEBUG_CATEGORY_EXTERN (v4l2_debug); /* * GstV4l2Buffer: */ +GType +gst_v4l2_meta_api_get_type (void) +{ + static volatile GType type; + static const gchar *tags[] = { "memory", NULL }; + + if (g_once_init_enter (&type)) { + GType _type = gst_meta_api_type_register ("GstV4l2MetaAPI", tags); + g_once_init_leave (&type, _type); + } + return type; +} + const GstMetaInfo * gst_v4l2_meta_get_info (void) { @@ -64,10 +77,9 @@ gst_v4l2_meta_get_info (void) if (meta_info == NULL) { meta_info = - gst_meta_register ("GstV4l2Meta", "GstV4l2Meta", + gst_meta_register (gst_v4l2_meta_api_get_type (), "GstV4l2Meta", sizeof (GstV4l2Meta), (GstMetaInitFunction) NULL, - (GstMetaFreeFunction) NULL, (GstMetaCopyFunction) NULL, - (GstMetaTransformFunction) NULL); + (GstMetaFreeFunction) NULL, (GstMetaTransformFunction) NULL); } return meta_info; } @@ -864,6 +876,7 @@ GstBufferPool * gst_v4l2_buffer_pool_new (GstV4l2Object * obj, GstCaps * caps) { GstV4l2BufferPool *pool; + GstStructure *s; gint fd; fd = v4l2_dup (obj->video_fd); @@ -874,8 +887,9 @@ gst_v4l2_buffer_pool_new (GstV4l2Object * obj, GstCaps * caps) pool->video_fd = fd; pool->obj = obj; - gst_buffer_pool_config_set (GST_BUFFER_POOL_CAST (pool)->config, caps, - obj->sizeimage, 2, 0, 0, 0); + s = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool)); + gst_buffer_pool_config_set (s, caps, obj->sizeimage, 2, 0, 0, 0); + gst_buffer_pool_set_config (GST_BUFFER_POOL_CAST (pool), s); return GST_BUFFER_POOL (pool); diff --git a/sys/v4l2/gstv4l2bufferpool.h b/sys/v4l2/gstv4l2bufferpool.h index 12d3ccc7df..5503628174 100644 --- a/sys/v4l2/gstv4l2bufferpool.h +++ b/sys/v4l2/gstv4l2bufferpool.h @@ -79,8 +79,9 @@ struct _GstV4l2Meta { struct v4l2_buffer vbuffer; }; +GType gst_v4l2_meta_api_get_type (void); const GstMetaInfo * gst_v4l2_meta_get_info (void); -#define GST_V4L2_META_GET(buf) ((GstV4l2Meta *)gst_buffer_get_meta(buf,gst_v4l2_meta_get_info())) +#define GST_V4L2_META_GET(buf) ((GstV4l2Meta *)gst_buffer_get_meta(buf,gst_v4l2_meta_api_get_type())) #define GST_V4L2_META_ADD(buf) ((GstV4l2Meta *)gst_buffer_add_meta(buf,gst_v4l2_meta_get_info(),NULL)) GType gst_v4l2_buffer_pool_get_type (void); diff --git a/sys/v4l2/gstv4l2colorbalance.h b/sys/v4l2/gstv4l2colorbalance.h index 4e6a75e369..7bf47e1fb4 100644 --- a/sys/v4l2/gstv4l2colorbalance.h +++ b/sys/v4l2/gstv4l2colorbalance.h @@ -90,15 +90,20 @@ interface_as_function ## _color_balance_get_value (GstColorBalance * balance, return gst_v4l2_color_balance_get_value(this->v4l2object, channel); \ } \ \ +static GstColorBalanceType \ +interface_as_function ## _color_balance_get_balance_type (GstColorBalance * balance) \ +{ \ + return GST_COLOR_BALANCE_HARDWARE; \ +} \ + \ static void \ interface_as_function ## _color_balance_interface_init (GstColorBalanceInterface * iface) \ { \ - GST_COLOR_BALANCE_TYPE (iface) = GST_COLOR_BALANCE_HARDWARE; \ - \ /* default virtual functions */ \ iface->list_channels = interface_as_function ## _color_balance_list_channels; \ iface->set_value = interface_as_function ## _color_balance_set_value; \ iface->get_value = interface_as_function ## _color_balance_get_value; \ + iface->get_balance_type = interface_as_function ## _color_balance_get_balance_type; \ } \ #endif /* __GST_V4L2_COLOR_BALANCE_H__ */ diff --git a/sys/v4l2/gstv4l2object.c b/sys/v4l2/gstv4l2object.c index 8924ea1fb7..6bcbf16b89 100644 --- a/sys/v4l2/gstv4l2object.c +++ b/sys/v4l2/gstv4l2object.c @@ -18,6 +18,10 @@ * USA. */ +/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray + * with newer GLib versions (>= 2.31.0) */ +#define GLIB_DISABLE_DEPRECATION_WARNINGS + #ifdef HAVE_CONFIG_H #include #endif @@ -1307,7 +1311,7 @@ gst_v4l2_object_v4l2fourcc_to_structure (guint32 fourcc) break; #ifdef V4L2_PIX_FMT_SBGGR8 case V4L2_PIX_FMT_SBGGR8: - structure = gst_structure_new_empty ("video/x-raw-bayer"); + structure = gst_structure_new_empty ("video/x-bayer"); break; #endif #ifdef V4L2_PIX_FMT_SN9C10X @@ -1468,7 +1472,7 @@ gst_v4l2_object_get_caps_info (GstV4l2Object * v4l2object, GstCaps * caps, } else if (g_str_equal (mimetype, "image/jpeg")) { fourcc = V4L2_PIX_FMT_JPEG; #ifdef V4L2_PIX_FMT_SBGGR8 - } else if (g_str_equal (mimetype, "video/x-raw-bayer")) { + } else if (g_str_equal (mimetype, "video/x-bayer")) { fourcc = V4L2_PIX_FMT_SBGGR8; #endif #ifdef V4L2_PIX_FMT_SN9C10X diff --git a/sys/v4l2/gstv4l2sink.c b/sys/v4l2/gstv4l2sink.c index 5e1e2d0d28..bcb0bb4a5f 100644 --- a/sys/v4l2/gstv4l2sink.c +++ b/sys/v4l2/gstv4l2sink.c @@ -653,8 +653,8 @@ gst_v4l2sink_propose_allocation (GstBaseSink * bsink, GstQuery * query) gst_query_set_allocation_params (query, size, 2, 0, 0, 0, pool); /* we also support various metadata */ - gst_query_add_allocation_meta (query, GST_VIDEO_META_API); - gst_query_add_allocation_meta (query, GST_VIDEO_CROP_META_API); + gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE); + gst_query_add_allocation_meta (query, GST_VIDEO_CROP_META_API_TYPE); if (pool) gst_object_unref (pool); diff --git a/sys/v4l2/gstv4l2src.c b/sys/v4l2/gstv4l2src.c index 4e29931ba3..5722bdea84 100644 --- a/sys/v4l2/gstv4l2src.c +++ b/sys/v4l2/gstv4l2src.c @@ -571,7 +571,7 @@ gst_v4l2src_decide_allocation (GstBaseSrc * bsrc, GstQuery * query) alignment); /* if downstream supports video metadata, add this to the pool config */ - if (gst_query_has_allocation_meta (query, GST_VIDEO_META_API)) + if (gst_query_has_allocation_meta (query, GST_VIDEO_META_API_TYPE)) gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META); diff --git a/sys/v4l2/gstv4l2videooverlay.c b/sys/v4l2/gstv4l2videooverlay.c index 702c1a5c18..ae9a317918 100644 --- a/sys/v4l2/gstv4l2videooverlay.c +++ b/sys/v4l2/gstv4l2videooverlay.c @@ -31,6 +31,8 @@ #include #include #include +/* for XkbKeycodeToKeysym */ +#include #include @@ -323,7 +325,7 @@ event_refresh (gpointer data) case KeyPress: case KeyRelease: g_mutex_lock (&v4l2xv->mutex); - keysym = XKeycodeToKeysym (v4l2xv->dpy, e.xkey.keycode, 0); + keysym = XkbKeycodeToKeysym (v4l2xv->dpy, e.xkey.keycode, 0, 0); if (keysym != NoSymbol) { key_str = XKeysymToString (keysym); } else { diff --git a/sys/ximage/Makefile.am b/sys/ximage/Makefile.am index db3ab228df..553226e30a 100644 --- a/sys/ximage/Makefile.am +++ b/sys/ximage/Makefile.am @@ -7,7 +7,7 @@ libgstximagesrc_la_CFLAGS = \ $(GST_CFLAGS) \ $(X_CFLAGS) $(XFIXES_CFLAGS) $(XDAMAGE_CFLAGS) libgstximagesrc_la_LIBADD = \ - $(GST_PLUGINS_BASE_LIBS) \ + $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_MAJORMINOR) \ $(GST_BASE_LIBS) \ $(X_LIBS) $(XSHM_LIBS) $(XFIXES_LIBS) $(XDAMAGE_LIBS) libgstximagesrc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) diff --git a/sys/ximage/gstximagesrc.c b/sys/ximage/gstximagesrc.c index ef24e7158d..51b46d7c01 100644 --- a/sys/ximage/gstximagesrc.c +++ b/sys/ximage/gstximagesrc.c @@ -30,7 +30,7 @@ * * Example pipelines * |[ - * gst-launch ximagesrc ! video/x-raw-rgb,framerate=5/1 ! ffmpegcolorspace ! theoraenc ! oggmux ! filesink location=desktop.ogg + * gst-launch ximagesrc ! video/x-raw,framerate=5/1 ! ffmpegcolorspace ! theoraenc ! oggmux ! filesink location=desktop.ogg * ]| Encodes your X display to an Ogg theora video at 5 frames per second. * */ @@ -48,6 +48,7 @@ #include #include +#include #include "gst/glib-compat-private.h" @@ -56,7 +57,7 @@ GST_DEBUG_CATEGORY_STATIC (gst_debug_ximage_src); static GstStaticPadTemplate t = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/x-raw-rgb, " + GST_STATIC_CAPS ("video/x-raw, " "framerate = (fraction) [ 0, MAX ], " "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ], " "pixel-aspect-ratio = (fraction) [ 0, MAX ]")); @@ -1018,6 +1019,7 @@ gst_ximage_src_get_caps (GstBaseSrc * bs, GstCaps * filter) GstXImageSrc *s = GST_XIMAGE_SRC (bs); GstXContext *xcontext; gint width, height; + GstVideoFormat format; if ((!s->xcontext) && (!gst_ximage_src_open_display (s, s->display_name))) return @@ -1072,13 +1074,14 @@ gst_ximage_src_get_caps (GstBaseSrc * bs, GstCaps * filter) s->endy = height - 1; } GST_DEBUG ("width = %d, height=%d", width, height); - return gst_caps_new_simple ("video/x-raw-rgb", - "bpp", G_TYPE_INT, xcontext->bpp, - "depth", G_TYPE_INT, xcontext->depth, - "endianness", G_TYPE_INT, xcontext->endianness, - "red_mask", G_TYPE_INT, xcontext->r_mask_output, - "green_mask", G_TYPE_INT, xcontext->g_mask_output, - "blue_mask", G_TYPE_INT, xcontext->b_mask_output, + + format = + gst_video_format_from_masks (xcontext->depth, xcontext->bpp, + xcontext->endianness, xcontext->r_mask_output, xcontext->g_mask_output, + xcontext->b_mask_output, 0); + + return gst_caps_new_simple ("video/x-raw", + "format", G_TYPE_STRING, gst_video_format_to_string (format), "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, "framerate", GST_TYPE_FRACTION_RANGE, 1, G_MAXINT, G_MAXINT, 1, diff --git a/sys/ximage/ximageutil.c b/sys/ximage/ximageutil.c index c221a58dc4..907aa3aefd 100644 --- a/sys/ximage/ximageutil.c +++ b/sys/ximage/ximageutil.c @@ -23,6 +23,19 @@ #include "ximageutil.h" +GType +gst_meta_ximage_api_get_type (void) +{ + static volatile GType type; + static const gchar *tags[] = { "memory", NULL }; + + if (g_once_init_enter (&type)) { + GType _type = gst_meta_api_type_register ("GstMetaXImageSrcAPI", tags); + g_once_init_leave (&type, _type); + } + return type; +} + const GstMetaInfo * gst_meta_ximage_get_info (void) { @@ -30,10 +43,9 @@ gst_meta_ximage_get_info (void) if (meta_ximage_info == NULL) { meta_ximage_info = - gst_meta_register ("GstMetaXImageSrc", "GstMetaXImageSrc", + gst_meta_register (gst_meta_ximage_api_get_type (), "GstMetaXImageSrc", sizeof (GstMetaXImage), (GstMetaInitFunction) NULL, - (GstMetaFreeFunction) NULL, (GstMetaCopyFunction) NULL, - (GstMetaTransformFunction) NULL); + (GstMetaFreeFunction) NULL, (GstMetaTransformFunction) NULL); } return meta_ximage_info; } diff --git a/sys/ximage/ximageutil.h b/sys/ximage/ximageutil.h index aa674de8fa..aa03e7a857 100644 --- a/sys/ximage/ximageutil.h +++ b/sys/ximage/ximageutil.h @@ -160,8 +160,9 @@ struct _GstMetaXImage { BufferReturnFunc return_func; }; +GType gst_meta_ximage_api_get_type (void); const GstMetaInfo * gst_meta_ximage_get_info (void); -#define GST_META_XIMAGE_GET(buf) ((GstMetaXImage *)gst_buffer_get_meta(buf,gst_meta_ximage_get_info())) +#define GST_META_XIMAGE_GET(buf) ((GstMetaXImage *)gst_buffer_get_meta(buf,gst_meta_ximage_api_get_type())) #define GST_META_XIMAGE_ADD(buf) ((GstMetaXImage *)gst_buffer_add_meta(buf,gst_meta_ximage_get_info(),NULL)) GstBuffer *gst_ximageutil_ximage_new (GstXContext *xcontext, diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index ec2bbb4997..8bf8f2b254 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -83,7 +83,6 @@ endif if USE_WAVPACK check_wavpack = \ - elements/wavpackparse \ elements/wavpackdec \ elements/wavpackenc \ pipelines/wavpack @@ -150,6 +149,7 @@ check_PROGRAMS = \ elements/udpsrc \ elements/videocrop \ elements/videofilter \ + elements/wavpackparse \ elements/y4menc \ pipelines/simple-launch-lines \ pipelines/effectv \ diff --git a/tests/check/elements/interleave.c b/tests/check/elements/interleave.c index e456a3e25e..6f2d51f406 100644 --- a/tests/check/elements/interleave.c +++ b/tests/check/elements/interleave.c @@ -18,6 +18,10 @@ * Boston, MA 02111-1307, USA. */ +/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray + * with newer GLib versions (>= 2.31.0) */ +#define GLIB_DISABLE_DEPRECATION_WARNINGS + #ifdef HAVE_CONFIG_H # include "config.h" #endif diff --git a/tests/check/elements/wavpackdec.c b/tests/check/elements/wavpackdec.c index 0d17323336..01ae67d202 100644 --- a/tests/check/elements/wavpackdec.c +++ b/tests/check/elements/wavpackdec.c @@ -29,6 +29,12 @@ * get_peer, and then remove references in every test function */ static GstPad *mysrcpad, *mysinkpad; +#if G_BYTE_ORDER == G_BIG_ENDIAN +#define AUDIO_FORMAT "S16BE" +#else +#define AUDIO_FORMAT "S16LE" +#endif + guint8 test_frame[] = { 0x77, 0x76, 0x70, 0x6B, /* "wvpk" */ 0x2E, 0x00, 0x00, 0x00, /* ckSize */ @@ -51,13 +57,12 @@ guint8 test_frame[] = { static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-raw-int, " - "width = (int) 32, " - "depth = (int) 16, " - "channels = (int) 1, " - "rate = (int) 44100, " - "endianness = (int) BYTE_ORDER, " "signed = (boolean) true") + GST_STATIC_CAPS ("audio/x-raw, " + "format = (string) " AUDIO_FORMAT ", " + "layout = (string) interleaved, " + "channels = (int) 1, " "rate = (int) 44100") ); + static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, @@ -73,8 +78,8 @@ setup_wavpackdec (void) GST_DEBUG ("setup_wavpackdec"); wavpackdec = gst_check_setup_element ("wavpackdec"); - mysrcpad = gst_check_setup_src_pad (wavpackdec, &srctemplate, NULL); - mysinkpad = gst_check_setup_sink_pad (wavpackdec, &sinktemplate, NULL); + mysrcpad = gst_check_setup_src_pad (wavpackdec, &srctemplate); + mysinkpad = gst_check_setup_sink_pad (wavpackdec, &sinktemplate); gst_pad_set_active (mysrcpad, TRUE); gst_pad_set_active (mysinkpad, TRUE); @@ -100,6 +105,7 @@ GST_START_TEST (test_decode_frame) GstBuffer *inbuffer, *outbuffer; GstBus *bus; int i; + GstMapInfo map; wavpackdec = setup_wavpackdec (); @@ -109,27 +115,29 @@ GST_START_TEST (test_decode_frame) bus = gst_bus_new (); inbuffer = gst_buffer_new_and_alloc (sizeof (test_frame)); - memcpy (GST_BUFFER_DATA (inbuffer), test_frame, sizeof (test_frame)); + gst_buffer_fill (inbuffer, 0, test_frame, sizeof (test_frame)); ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); GST_BUFFER_TIMESTAMP (inbuffer) = 0; - gst_buffer_ref (inbuffer); gst_element_set_bus (wavpackdec, bus); /* should decode the buffer without problems */ fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK); - ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); - gst_buffer_unref (inbuffer); outbuffer = GST_BUFFER (buffers->data); fail_if (outbuffer == NULL); - /* uncompressed data should be 102400 bytes */ - fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer), 102400); - /* and all 102400 bytes must be 0, i.e. silence */ - for (i = 0; i < 102400; i++) - fail_unless_equals_int (GST_BUFFER_DATA (outbuffer)[i], 0); + gst_buffer_map (outbuffer, &map, GST_MAP_READ); + + /* uncompressed data should be 102400 bytes */ + fail_unless_equals_int (map.size, 51200); + + /* and all bytes must be 0, i.e. silence */ + for (i = 0; i < 51200; i++) + fail_unless_equals_int (map.data[i], 0); + + gst_buffer_unmap (outbuffer, &map); ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1); gst_buffer_unref (outbuffer); @@ -161,19 +169,16 @@ GST_START_TEST (test_decode_frame_with_broken_header) bus = gst_bus_new (); inbuffer = gst_buffer_new_and_alloc (sizeof (test_frame)); - memcpy (GST_BUFFER_DATA (inbuffer), test_frame, sizeof (test_frame)); + gst_buffer_fill (inbuffer, 0, test_frame, sizeof (test_frame)); /* break header */ - GST_BUFFER_DATA (inbuffer)[2] = 'e'; + gst_buffer_memset (inbuffer, 2, 'e', 1); ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); GST_BUFFER_TIMESTAMP (inbuffer) = 0; - gst_buffer_ref (inbuffer); gst_element_set_bus (wavpackdec, bus); /* should fail gracefully */ fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_ERROR); - ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); - gst_buffer_unref (inbuffer); fail_if ((message = gst_bus_pop (bus)) == NULL); fail_unless_message_error (message, STREAM, DECODE); @@ -201,17 +206,14 @@ GST_START_TEST (test_decode_frame_with_incomplete_frame) bus = gst_bus_new (); inbuffer = gst_buffer_new_and_alloc (sizeof (test_frame) - 2); - memcpy (GST_BUFFER_DATA (inbuffer), test_frame, sizeof (test_frame) - 2); + gst_buffer_fill (inbuffer, 0, test_frame, sizeof (test_frame) - 2); ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); GST_BUFFER_TIMESTAMP (inbuffer) = 0; - gst_buffer_ref (inbuffer); gst_element_set_bus (wavpackdec, bus); /* should fail gracefully */ fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_ERROR); - ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); - gst_buffer_unref (inbuffer); fail_if ((message = gst_bus_pop (bus)) == NULL); fail_unless_message_error (message, STREAM, DECODE); diff --git a/tests/check/elements/wavpackenc.c b/tests/check/elements/wavpackenc.c index 153668a9df..72f6cd11c7 100644 --- a/tests/check/elements/wavpackenc.c +++ b/tests/check/elements/wavpackenc.c @@ -30,16 +30,20 @@ static GstPad *mysrcpad, *mysinkpad; static GstBus *bus; -#define RAW_CAPS_STRING "audio/x-raw-int, " \ - "width = (int) 32, " \ - "depth = (int) 16, " \ +#if G_BYTE_ORDER == G_BIG_ENDIAN +#define AUDIO_FORMAT "S32BE" +#else +#define AUDIO_FORMAT "S32LE" +#endif + +#define RAW_CAPS_STRING "audio/x-raw, " \ + "format = (string) " AUDIO_FORMAT ", " \ + "layout = (string) interleaved, " \ "channels = (int) 1, " \ - "rate = (int) 44100, " \ - "endianness = (int) BYTE_ORDER, " \ - "signed = (boolean) true" + "rate = (int) 44100" #define WAVPACK_CAPS_STRING "audio/x-wavpack, " \ - "width = (int) 16, " \ + "width = (int) 32, " \ "channels = (int) 1, " \ "rate = (int) 44100, " \ "framed = (boolean) true" @@ -48,19 +52,17 @@ static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS ("audio/x-wavpack, " - "width = (int) 16, " + "width = (int) 32, " "channels = (int) 1, " "rate = (int) 44100, " "framed = (boolean) true")); static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-raw-int, " - "width = (int) 32, " - "depth = (int) 16, " - "channels = (int) 1, " - "rate = (int) 44100, " - "endianness = (int) BYTE_ORDER, " "signed = (boolean) true")); + GST_STATIC_CAPS ("audio/x-raw, " + "format = (string) " AUDIO_FORMAT ", " + "layout = (string) interleaved, " + "channels = (int) 1, " "rate = (int) 44100")); static GstElement * setup_wavpackenc (void) @@ -69,8 +71,8 @@ setup_wavpackenc (void) GST_DEBUG ("setup_wavpackenc"); wavpackenc = gst_check_setup_element ("wavpackenc"); - mysrcpad = gst_check_setup_src_pad (wavpackenc, &srctemplate, NULL); - mysinkpad = gst_check_setup_sink_pad (wavpackenc, &sinktemplate, NULL); + mysrcpad = gst_check_setup_src_pad (wavpackenc, &srctemplate); + mysinkpad = gst_check_setup_sink_pad (wavpackenc, &sinktemplate); gst_pad_set_active (mysrcpad, TRUE); gst_pad_set_active (mysinkpad, TRUE); @@ -111,20 +113,16 @@ GST_START_TEST (test_encode_silence) wavpackenc = setup_wavpackenc (); inbuffer = gst_buffer_new_and_alloc (1000); - for (i = 0; i < 1000; i++) - GST_BUFFER_DATA (inbuffer)[i] = 0; + gst_buffer_memset (inbuffer, 0, 0, 1000); caps = gst_caps_from_string (RAW_CAPS_STRING); - gst_buffer_set_caps (inbuffer, caps); + fail_unless (gst_pad_set_caps (mysrcpad, caps)); gst_caps_unref (caps); GST_BUFFER_TIMESTAMP (inbuffer) = 0; ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); - gst_buffer_ref (inbuffer); gst_element_set_bus (wavpackenc, bus); fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK); - ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1); - gst_buffer_unref (inbuffer); fail_if (gst_pad_push_event (mysrcpad, eos) != TRUE); @@ -134,11 +132,9 @@ GST_START_TEST (test_encode_silence) fail_if (outbuffer == NULL); fail_unless_equals_int (GST_BUFFER_TIMESTAMP (outbuffer), 0); - fail_unless_equals_int (GST_BUFFER_OFFSET (outbuffer), 0); fail_unless_equals_int (GST_BUFFER_DURATION (outbuffer), 5668934); - fail_unless_equals_int (GST_BUFFER_OFFSET_END (outbuffer), 250); - fail_unless (memcmp (GST_BUFFER_DATA (outbuffer), "wvpk", 4) == 0, + fail_unless (gst_buffer_memcmp (outbuffer, 0, "wvpk", 4) == 0, "Failed to encode to valid Wavpack frames"); /* free all buffers */ diff --git a/tests/check/elements/wavpackparse.c b/tests/check/elements/wavpackparse.c index 5083903204..ca69670998 100644 --- a/tests/check/elements/wavpackparse.c +++ b/tests/check/elements/wavpackparse.c @@ -28,8 +28,6 @@ * src and sink pads we create; otherwise we always have to do get_pad, * get_peer, and then remove references in every test function */ static GstPad *mysrcpad, *mysinkpad; -static GstBus *bus; -static GstElement *wavpackparse; /* Wavpack file with 2 frames of silence */ guint8 test_file[] = { @@ -69,99 +67,53 @@ static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_ALWAYS, GST_STATIC_CAPS ("audio/x-wavpack")); -static void -wavpackparse_found_pad (GstElement * src, GstPad * pad, gpointer data) -{ - GstPad *srcpad; - - mysinkpad = gst_pad_new_from_static_template (&sinktemplate, "sink"); - fail_if (mysinkpad == NULL, "Couldn't create sinkpad"); - srcpad = gst_element_get_static_pad (wavpackparse, "src"); - fail_if (srcpad == NULL, "Failed to get srcpad from wavpackparse"); - gst_pad_set_chain_function (mysinkpad, gst_check_chain_func); - fail_unless (gst_pad_link (srcpad, mysinkpad) == GST_PAD_LINK_OK, - "Failed to link pads"); - gst_pad_set_active (mysinkpad, TRUE); - gst_object_unref (srcpad); -} - -static void +static GstElement * setup_wavpackparse (void) { - GstPad *sinkpad; + GstElement *wavpackparse; GST_DEBUG ("setup_wavpackparse"); - wavpackparse = gst_element_factory_make ("wavpackparse", "wavpackparse"); - fail_if (wavpackparse == NULL, "Could not create wavpackparse"); + wavpackparse = gst_check_setup_element ("wavpackparse"); + mysrcpad = gst_check_setup_src_pad (wavpackparse, &srctemplate); + mysinkpad = gst_check_setup_sink_pad (wavpackparse, &sinktemplate); + gst_pad_set_active (mysrcpad, TRUE); + gst_pad_set_active (mysinkpad, TRUE); - mysrcpad = gst_pad_new_from_static_template (&srctemplate, "src"); - fail_if (mysrcpad == NULL, "Could not create srcpad"); - - sinkpad = gst_element_get_static_pad (wavpackparse, "sink"); - fail_if (sinkpad == NULL, "Failed to get sinkpad from wavpackparse"); - fail_unless (gst_pad_link (mysrcpad, sinkpad) == GST_PAD_LINK_OK, - "Failed to link pads"); - gst_object_unref (sinkpad); - - g_signal_connect (wavpackparse, "pad-added", - G_CALLBACK (wavpackparse_found_pad), NULL); - - bus = gst_bus_new (); - gst_element_set_bus (wavpackparse, bus); - - fail_unless (gst_element_set_state (wavpackparse, - GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, - "could not set to playing"); + return wavpackparse; } static void -cleanup_wavpackparse (void) +cleanup_wavpackparse (GstElement * wavpackparse) { - GstPad *sinkpad, *srcpad; - GST_DEBUG ("cleanup_wavpackparse"); + gst_element_set_state (wavpackparse, GST_STATE_NULL); - gst_bus_set_flushing (bus, TRUE); - gst_element_set_bus (wavpackparse, NULL); - gst_object_unref (GST_OBJECT (bus)); - - sinkpad = gst_element_get_static_pad (wavpackparse, "sink"); - fail_if (sinkpad == NULL, "Failed to get sinkpad from wavpackparse"); - fail_unless (gst_pad_unlink (mysrcpad, sinkpad), "Failed to unlink pads"); - gst_pad_set_caps (mysrcpad, NULL); - gst_object_unref (sinkpad); - gst_object_unref (mysrcpad); - - srcpad = gst_element_get_static_pad (wavpackparse, "src"); - fail_if (srcpad == NULL, "Failed to get srcpad from wavpackparse"); - fail_unless (gst_pad_unlink (srcpad, mysinkpad), "Failed to unlink pads"); - gst_pad_set_caps (mysinkpad, NULL); - gst_object_unref (srcpad); - gst_object_unref (mysinkpad); - - fail_unless (gst_element_set_state (wavpackparse, GST_STATE_NULL) == - GST_STATE_CHANGE_SUCCESS, "could not set to null"); - - gst_object_unref (wavpackparse); + gst_pad_set_active (mysrcpad, FALSE); + gst_pad_set_active (mysinkpad, FALSE); + gst_check_teardown_src_pad (wavpackparse); + gst_check_teardown_sink_pad (wavpackparse); + gst_check_teardown_element (wavpackparse); } GST_START_TEST (test_parsing_valid_frames) { + GstElement *wavpackparse; GstBuffer *inbuffer, *outbuffer; int i, num_buffers; - GstFormat format = GST_FORMAT_DEFAULT; + GstFormat format = GST_FORMAT_TIME; gint64 pos; - setup_wavpackparse (); + wavpackparse = setup_wavpackparse (); + fail_unless (gst_element_set_state (wavpackparse, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); inbuffer = gst_buffer_new_and_alloc (sizeof (test_file)); - memcpy (GST_BUFFER_DATA (inbuffer), test_file, sizeof (test_file)); - gst_buffer_ref (inbuffer); + gst_buffer_fill (inbuffer, 0, test_file, sizeof (test_file)); /* should decode the buffer without problems */ fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK); - gst_buffer_unref (inbuffer); num_buffers = g_list_length (buffers); /* should get 2 buffers, each one complete wavpack frame */ @@ -171,21 +123,17 @@ GST_START_TEST (test_parsing_valid_frames) outbuffer = GST_BUFFER (buffers->data); fail_if (outbuffer == NULL); - fail_unless (memcmp (GST_BUFFER_DATA (outbuffer), "wvpk", 4) == 0, + fail_unless (gst_buffer_memcmp (outbuffer, 0, "wvpk", 4) == 0, "Buffer contains no Wavpack frame"); fail_unless_equals_int (GST_BUFFER_DURATION (outbuffer), 580498866); switch (i) { case 0:{ fail_unless_equals_int (GST_BUFFER_TIMESTAMP (outbuffer), 0); - fail_unless_equals_int (GST_BUFFER_OFFSET (outbuffer), 0); - fail_unless_equals_int (GST_BUFFER_OFFSET_END (outbuffer), 25600); break; } case 1:{ fail_unless_equals_int (GST_BUFFER_TIMESTAMP (outbuffer), 580498866); - fail_unless_equals_int (GST_BUFFER_OFFSET (outbuffer), 25600); - fail_unless_equals_int (GST_BUFFER_OFFSET_END (outbuffer), 51200); break; } } @@ -196,35 +144,37 @@ GST_START_TEST (test_parsing_valid_frames) outbuffer = NULL; } - fail_unless (gst_element_query_position (wavpackparse, &format, &pos), + fail_unless (gst_element_query_position (wavpackparse, format, &pos), "Position query failed"); - fail_unless_equals_int (pos, 51200); - fail_unless (gst_element_query_duration (wavpackparse, &format, NULL), + fail_unless_equals_int64 (pos, 580498866 * 2); + fail_unless (gst_element_query_duration (wavpackparse, format, NULL), "Duration query failed"); g_list_free (buffers); buffers = NULL; - cleanup_wavpackparse (); + cleanup_wavpackparse (wavpackparse); } GST_END_TEST; GST_START_TEST (test_parsing_invalid_first_header) { + GstElement *wavpackparse; GstBuffer *inbuffer, *outbuffer; int i, num_buffers; - setup_wavpackparse (); + wavpackparse = setup_wavpackparse (); + fail_unless (gst_element_set_state (wavpackparse, + GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS, + "could not set to playing"); inbuffer = gst_buffer_new_and_alloc (sizeof (test_file)); - memcpy (GST_BUFFER_DATA (inbuffer), test_file, sizeof (test_file)); - GST_BUFFER_DATA (inbuffer)[0] = 'k'; - gst_buffer_ref (inbuffer); + gst_buffer_fill (inbuffer, 0, test_file, sizeof (test_file)); + gst_buffer_memset (inbuffer, 0, 'k', 1); /* should decode the buffer without problems */ fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK); - gst_buffer_unref (inbuffer); num_buffers = g_list_length (buffers); @@ -235,14 +185,13 @@ GST_START_TEST (test_parsing_invalid_first_header) outbuffer = GST_BUFFER (buffers->data); fail_if (outbuffer == NULL); - fail_unless (memcmp (GST_BUFFER_DATA (outbuffer), "wvpk", 4) == 0, + fail_unless (gst_buffer_memcmp (outbuffer, 0, "wvpk", 4) == 0, "Buffer contains no Wavpack frame"); fail_unless_equals_int (GST_BUFFER_DURATION (outbuffer), 580498866); switch (i) { case 0:{ fail_unless_equals_int (GST_BUFFER_TIMESTAMP (outbuffer), 580498866); - fail_unless_equals_int (GST_BUFFER_OFFSET (outbuffer), 25600); break; } } @@ -256,7 +205,7 @@ GST_START_TEST (test_parsing_invalid_first_header) g_list_free (buffers); buffers = NULL; - cleanup_wavpackparse (); + cleanup_wavpackparse (wavpackparse); } GST_END_TEST; diff --git a/tests/check/pipelines/wavpack.c b/tests/check/pipelines/wavpack.c index 6a166b2795..7fcba8740a 100644 --- a/tests/check/pipelines/wavpack.c +++ b/tests/check/pipelines/wavpack.c @@ -96,6 +96,7 @@ GST_START_TEST (test_encode_decode) GMainLoop *loop; GstBuffer *in, *out; guint bus_watch = 0; + GstMapInfo map; srcadapter = gst_adapter_new (); fail_unless (srcadapter != NULL); @@ -170,9 +171,10 @@ GST_START_TEST (test_encode_decode) gst_adapter_available (sinkadapter)); fail_unless (out != NULL); - fail_unless_equals_int (GST_BUFFER_SIZE (in), GST_BUFFER_SIZE (out)); - fail_unless (memcmp (GST_BUFFER_DATA (in), GST_BUFFER_DATA (out), - GST_BUFFER_SIZE (in)) == 0); + fail_unless_equals_int (gst_buffer_get_size (in), gst_buffer_get_size (out)); + gst_buffer_map (out, &map, GST_MAP_READ); + fail_unless (gst_buffer_memcmp (in, 0, map.data, map.size) == 0); + gst_buffer_unmap (out, &map); gst_buffer_unref (in); gst_buffer_unref (out); diff --git a/tests/examples/audiofx/firfilter-example.c b/tests/examples/audiofx/firfilter-example.c index b344e74e63..e2fa2dc25b 100644 --- a/tests/examples/audiofx/firfilter-example.c +++ b/tests/examples/audiofx/firfilter-example.c @@ -21,6 +21,10 @@ * by transforming the frequency response to the filter kernel. */ +/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray + * with newer GLib versions (>= 2.31.0) */ +#define GLIB_DISABLE_DEPRECATION_WARNINGS + #include #include diff --git a/tests/examples/audiofx/iirfilter-example.c b/tests/examples/audiofx/iirfilter-example.c index 7fac2ac92b..708bde1e1d 100644 --- a/tests/examples/audiofx/iirfilter-example.c +++ b/tests/examples/audiofx/iirfilter-example.c @@ -23,6 +23,10 @@ * of the IIR filter that is used. */ +/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray + * with newer GLib versions (>= 2.31.0) */ +#define GLIB_DISABLE_DEPRECATION_WARNINGS + #include #include diff --git a/tests/examples/pulse/pulse.c b/tests/examples/pulse/pulse.c index c82316349d..f1d5b26ead 100644 --- a/tests/examples/pulse/pulse.c +++ b/tests/examples/pulse/pulse.c @@ -17,6 +17,10 @@ * Boston, MA 02111-1307, USA. */ +/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray + * with newer GLib versions (>= 2.31.0) */ +#define GLIB_DISABLE_DEPRECATION_WARNINGS + #include #if 0 diff --git a/tests/examples/rtp/server-alsasrc-PCMA.c b/tests/examples/rtp/server-alsasrc-PCMA.c index 85647993ef..625a6ba9f5 100644 --- a/tests/examples/rtp/server-alsasrc-PCMA.c +++ b/tests/examples/rtp/server-alsasrc-PCMA.c @@ -17,6 +17,10 @@ * Boston, MA 02111-1307, USA. */ +/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray + * with newer GLib versions (>= 2.31.0) */ +#define GLIB_DISABLE_DEPRECATION_WARNINGS + #include #include diff --git a/tests/icles/test-oss4.c b/tests/icles/test-oss4.c index ad8f46cd04..67e08e914e 100644 --- a/tests/icles/test-oss4.c +++ b/tests/icles/test-oss4.c @@ -17,6 +17,10 @@ * Boston, MA 02111-1307, USA. */ +/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray + * with newer GLib versions (>= 2.31.0) */ +#define GLIB_DISABLE_DEPRECATION_WARNINGS + #ifdef HAVE_CONFIG_H #include #endif