Merge branch 'master' into 0.11

Conflicts:
	docs/libs/Makefile.am
	tests/check/elements/decodebin2.c
This commit is contained in:
Sebastian Dröge 2011-09-08 14:42:00 +02:00
commit 0f654f3feb
10 changed files with 719 additions and 136 deletions

2
common

@ -1 +1 @@
Subproject commit a39eb835fb3be2a4c5a6a89b5ca5cc064e79b2e2
Subproject commit 11f0cd5a3fba36f85cf3e434150bfe66b1bf08d4

View file

@ -13,43 +13,17 @@ FORMATS=html
html: html-build.stamp
include $(top_srcdir)/common/upload-doc.mak
# generated basefiles
#basefiles = \
## $(DOC_MODULE).types \
# $(DOC_MODULE)-sections.txt \
# $(DOC_MODULE)-docs.sgml
# ugly hack to make -unused.sgml work
#unused-build.stamp:
# BUILDDIR=`pwd` && \
# cd $(srcdir)/tmpl && \
# ln -sf gstreamer-libs-unused.sgml \
# $$BUILDDIR/tmpl/gstreamer-libs-@GST_MAJORMINOR@-unused.sgml
# touch unused-build.stamp
# these rules are added to create parallel docs using GST_MAJORMINOR
#$(basefiles): gstreamer-libs-@GST_MAJORMINOR@%: gstreamer-libs%
# cp $< $@
#CLEANFILES = $(basefiles)
# The top-level SGML file. Change it if you want.
DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml
# The directory containing the source code. Relative to $(top_srcdir).
# The directory containing the source code.
# gtk-doc will search all .c & .h files beneath here for inline comments
# documenting functions and macros.
DOC_SOURCE_DIR=$(top_srcdir)/gst-libs/gst
DOC_BUILD_DIR=$(top_builddir)/gst-libs/gst
# Extra options to supply to gtkdoc-scan.
SCAN_OPTIONS=--deprecated-guards="GST_DISABLE_DEPRECATED"
# FIXME :
# there's something wrong with gstreamer-sections.txt not being in the dist
# maybe it doesn't resolve; we're adding it below for now
#EXTRA_DIST = gstreamer.types.in gstreamer.hierarchy $(DOC_MODULE)-sections.txt gstreamer-sections.txt $(DOC_MAIN_SGML_FILE)
# Extra options to supply to gtkdoc-mkdb.
MKDB_OPTIONS=--sgml-mode --output-format=xml
@ -58,25 +32,8 @@ FIXXREF_OPTIONS=--extra-dir=$(GLIB_PREFIX)/share/gtk-doc/html \
--extra-dir=$(GST_PREFIX)/share/gtk-doc/html
# Used for dependencies.
HFILE_GLOB=$(DOC_SOURCE_DIR)/*/*.h
CFILE_GLOB=$(DOC_SOURCE_DIR)/*/*.c
# this is a wingo addition
# thomasvs: another nice wingo addition would be an explanation on why
# this is useful ;)
SCANOBJ_DEPS = \
$(top_builddir)/gst-libs/gst/interfaces/libgstinterfaces-@GST_MAJORMINOR@.la \
$(top_builddir)/gst-libs/gst/audio/libgstaudio-@GST_MAJORMINOR@.la \
$(top_builddir)/gst-libs/gst/cdda/libgstcdda-@GST_MAJORMINOR@.la \
$(top_builddir)/gst-libs/gst/fft/libgstfft-@GST_MAJORMINOR@.la \
$(top_builddir)/gst-libs/gst/rtp/libgstrtp-@GST_MAJORMINOR@.la \
$(top_builddir)/gst-libs/gst/rtsp/libgstrtsp-@GST_MAJORMINOR@.la \
$(top_builddir)/gst-libs/gst/sdp/libgstsdp-@GST_MAJORMINOR@.la \
$(top_builddir)/gst-libs/gst/tag/libgsttag-@GST_MAJORMINOR@.la \
$(top_builddir)/gst-libs/gst/video/libgstvideo-@GST_MAJORMINOR@.la \
$(top_builddir)/gst-libs/gst/app/libgstapp-@GST_MAJORMINOR@.la \
$(top_builddir)/gst-libs/gst/pbutils/libgstpbutils-@GST_MAJORMINOR@.la
HFILE_GLOB=$(top_srcdir)/gst-libs/gst/*/*.h
CFILE_GLOB=$(top_srcdir)/gst-libs/gst/*/*.c
# Header files to ignore when scanning.
IGNORE_HFILES = pbutils-private.h gsttageditingprivate.h id3v2.h \
@ -99,14 +56,24 @@ extra_files =
# CFLAGS and LDFLAGS for compiling scan program. Only needed if your app/lib
# contains GtkObjects/GObjects and you want to document signals and properties.
GTKDOC_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) -DGST_USE_UNSTABLE_API
GTKDOC_LIBS = $(SCANOBJ_DEPS) $(GST_BASE_LIBS)
GTKDOC_LIBS = \
$(top_builddir)/gst-libs/gst/interfaces/libgstinterfaces-@GST_MAJORMINOR@.la \
$(top_builddir)/gst-libs/gst/audio/libgstaudio-@GST_MAJORMINOR@.la \
$(top_builddir)/gst-libs/gst/cdda/libgstcdda-@GST_MAJORMINOR@.la \
$(top_builddir)/gst-libs/gst/fft/libgstfft-@GST_MAJORMINOR@.la \
$(top_builddir)/gst-libs/gst/rtp/libgstrtp-@GST_MAJORMINOR@.la \
$(top_builddir)/gst-libs/gst/rtsp/libgstrtsp-@GST_MAJORMINOR@.la \
$(top_builddir)/gst-libs/gst/sdp/libgstsdp-@GST_MAJORMINOR@.la \
$(top_builddir)/gst-libs/gst/tag/libgsttag-@GST_MAJORMINOR@.la \
$(top_builddir)/gst-libs/gst/video/libgstvideo-@GST_MAJORMINOR@.la \
$(top_builddir)/gst-libs/gst/app/libgstapp-@GST_MAJORMINOR@.la \
$(top_builddir)/gst-libs/gst/pbutils/libgstpbutils-@GST_MAJORMINOR@.la \
$(GST_BASE_LIBS)
GTKDOC_CC=$(LIBTOOL) --tag=CC --mode=compile $(CC)
GTKDOC_LD=$(LIBTOOL) --tag=CC --mode=link $(CC)
# If you need to override some of the declarations, place them in this file
# and uncomment this line.
#DOC_OVERRIDES = $(DOC_MODULE)-overrides.txt
DOC_OVERRIDES =
DOC_OVERRIDES = $(DOC_MODULE)-overrides.txt
include $(top_srcdir)/common/gtk-doc.mak

View file

@ -13,33 +13,13 @@ FORMATS=html
html: html-build.stamp
include $(top_srcdir)/common/upload-doc.mak
# generated basefiles
#basefiles = \
## $(DOC_MODULE).types \
# $(DOC_MODULE)-sections.txt \
# $(DOC_MODULE)-docs.sgml
# ugly hack to make -unused.sgml work
#unused-build.stamp:
# BUILDDIR=`pwd` && \
# cd $(srcdir)/tmpl && \
# ln -sf gstreamer-libs-unused.sgml \
# $$BUILDDIR/tmpl/gstreamer-libs-@GST_MAJORMINOR@-unused.sgml
# touch unused-build.stamp
# these rules are added to create parallel docs using GST_MAJORMINOR
#$(basefiles): gstreamer-libs-@GST_MAJORMINOR@%: gstreamer-libs%
# cp $< $@
#CLEANFILES = $(basefiles)
# The top-level SGML file. Change it if you want.
DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml
# The directory containing the source code. Relative to $(top_srcdir).
# The directory containing the source code.
# gtk-doc will search all .c & .h files beneath here for inline comments
# documenting functions and macros.
DOC_SOURCE_DIR = $(top_srcdir)
DOC_SOURCE_DIR = $(top_srcdir)/gst $(top_srcdir)/ext $(top_srcdir)/sys
# Extra options to supply to gtkdoc-scan.
SCAN_OPTIONS=
@ -54,14 +34,8 @@ FIXXREF_OPTIONS=--extra-dir=$(top_builddir)/docs/libs/html \
--extra-dir=$(datadir)/gtk-doc/html
# Used for dependencies.
HFILE_GLOB=$(DOC_SOURCE_DIR)/*/*/*.h
CFILE_GLOB=$(DOC_SOURCE_DIR)/*/*/*.c
# this is a wingo addition
# thomasvs: another nice wingo addition would be an explanation on why
# this is useful ;)
SCANOBJ_DEPS =
HFILE_GLOB=$(top_srcdir)/gst/*/*.h $(top_srcdir)/ext/*/*.h $(top_srcdir)/sys/*/*.h
CFILE_GLOB=$(top_srcdir)/gst/*/*.c $(top_srcdir)/ext/*/*.c $(top_srcdir)/sys/*/*.c
# Header files to ignore when scanning.
IGNORE_HFILES = avcodec.h dsputil.h arch.h speex_resampler.h speex_resampler_wrapper.h fixed_arm4.h fixed_arm5e.h fixed_bfin.h fixed_debug.h fixed_generic.h resample_sse.h
@ -136,14 +110,12 @@ extra_files =
# CFLAGS and LDFLAGS for compiling scan program. Only needed if your app/lib
# contains GtkObjects/GObjects and you want to document signals and properties.
GTKDOC_CFLAGS = $(GST_BASE_CFLAGS) -I$(top_builddir) -I$(top_builddir)/gst-libs
GTKDOC_LIBS = $(SCANOBJ_DEPS) $(GST_BASE_LIBS)
GTKDOC_LIBS = $(GST_BASE_LIBS)
GTKDOC_CC=$(LIBTOOL) --tag=CC --mode=compile $(CC)
GTKDOC_LD=$(LIBTOOL) --tag=CC --mode=link $(CC)
# If you need to override some of the declarations, place them in this file
# and uncomment this line.
#DOC_OVERRIDES = $(DOC_MODULE)-overrides.txt
DOC_OVERRIDES =
DOC_OVERRIDES = $(DOC_MODULE)-overrides.txt
include $(top_srcdir)/common/gtk-doc-plugins.mak

View file

@ -488,7 +488,13 @@ theora_enc_reset (GstTheoraEnc * enc)
GST_OBJECT_LOCK (enc);
enc->info.target_bitrate = enc->video_bitrate;
enc->info.quality = enc->video_quality;
if (enc->quality_changed) {
enc->info.quality = enc->video_quality;
} else {
if (enc->video_bitrate == 0) {
enc->info.quality = enc->video_quality;
}
}
enc->bitrate_changed = FALSE;
enc->quality_changed = FALSE;
GST_OBJECT_UNLOCK (enc);

View file

@ -220,6 +220,9 @@ GStreamer Plugins Base library development and header files.
%{_includedir}/gstreamer-%{majorminor}/gst/pbutils/gstpluginsbaseversion.h
%{_includedir}/gstreamer-%{majorminor}/gst/tag/xmpwriter.h
%{_includedir}/gstreamer-%{majorminor}/gst/audio/gstaudioiec61937.h
%{_includedir}/gstreamer-%{majorminor}/gst/audio/gstaudiodecoder.h
%{_includedir}/gstreamer-%{majorminor}/gst/audio/gstaudioencoder.h
%{_includedir}/gstreamer-%{majorminor}/gst/tag/gsttagmux.h
%{_libdir}/libgstfft-%{majorminor}.so
%{_libdir}/libgstrtsp-%{majorminor}.so
@ -280,6 +283,7 @@ GStreamer Plugins Base library development and header files.
# gtk-doc documentation
%doc %{_datadir}/gtk-doc/html/gst-plugins-base-libs-%{majorminor}
%doc %{_datadir}/gtk-doc/html/gst-plugins-base-plugins-%{majorminor}
%doc %{_datadir}/gst-plugins-base/license-translations.dict
%changelog
* Sun Aug 07 2011 Thomas Vander Stichele <thomas at apestaart dot org>

View file

@ -53,6 +53,8 @@ G_BEGIN_DECLS
* @GST_AUDIO_TEST_SRC_WAVE_TICKS: periodic ticks
* @GST_AUDIO_TEST_SRC_WAVE_GAUSSIAN_WHITE_NOISE: white (zero mean) Gaussian noise; volume sets the standard deviation of the noise in units of the range of values of the sample type, e.g. volume=0.1 produces noise with a standard deviation of 0.1*32767=3277 with 16-bit integer samples, or 0.1*1.0=0.1 with floating-point samples.
* @GST_AUDIO_TEST_SRC_WAVE_RED_NOISE: red (brownian) noise
* @GST_AUDIO_TEST_SRC_WAVE_BLUE_NOISE: spectraly inverted pink noise
* @GST_AUDIO_TEST_SRC_WAVE_VIOLET_NOISE: spectraly inverted red (brownian) noise
*
* Different types of supported sound waves.
*/

View file

@ -1339,13 +1339,14 @@ analyze_new_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad,
GstDecodePad *dpad;
GstElementFactory *factory;
const gchar *classification;
gboolean is_parser_converter;
gboolean is_parser_converter = FALSE;
GST_DEBUG_OBJECT (dbin, "Pad %s:%s caps:%" GST_PTR_FORMAT,
GST_DEBUG_PAD_NAME (pad), caps);
if (chain->elements
&& src != ((GstDecodeElement *) chain->elements->data)->element) {
&& src != ((GstDecodeElement *) chain->elements->data)->element
&& src != ((GstDecodeElement *) chain->elements->data)->capsfilter) {
GST_ERROR_OBJECT (dbin, "New pad from not the last element in this chain");
return;
}
@ -1516,7 +1517,7 @@ analyze_new_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad,
for (i = 0; i < factories->n_values; i++) {
GstElementFactory *factory =
g_value_get_object (g_value_array_get_nth (factories, i));
GstCaps *tcaps;
GstCaps *tcaps, *intersection;
const GList *tmps;
GST_DEBUG ("Trying factory %s",
@ -1533,7 +1534,9 @@ analyze_new_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad,
if (st->direction != GST_PAD_SINK || st->presence != GST_PAD_ALWAYS)
continue;
tcaps = gst_static_pad_template_get_caps (st);
gst_caps_merge (filter_caps, gst_caps_copy (tcaps));
intersection =
gst_caps_intersect_full (tcaps, caps, GST_CAPS_INTERSECT_FIRST);
gst_caps_merge (filter_caps, intersection);
gst_caps_unref (tcaps);
}
}
@ -1554,6 +1557,11 @@ analyze_new_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad,
p = gst_element_get_static_pad (delem->capsfilter, "src");
gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (dpad), p);
pad = p;
if (!gst_caps_is_fixed (caps)) {
g_value_array_free (factories);
goto non_fixed;
}
}
/* 1.h else continue autoplugging something from the list. */
@ -1664,6 +1672,12 @@ setup_caps_delay:
g_signal_connect (G_OBJECT (pad), "notify::caps",
G_CALLBACK (caps_notify_cb), chain);
CHAIN_MUTEX_UNLOCK (chain);
/* If we're here because we have a Parser/Converter
* we have to unref the pad */
if (is_parser_converter)
gst_object_unref (pad);
return;
}
}
@ -1727,48 +1741,6 @@ connect_pad (GstDecodeBin * dbin, GstElement * src, GstDecodePad * dpad,
/* Remove selected factory from the list. */
g_value_array_remove (factories, 0);
/* Check if the caps are really supported by the factory. The
* factory list is non-empty-subset filtered while caps
* are only accepted by a pad if they are a subset of the
* pad caps.
*
* FIXME: Only do this for fixed caps here. Non-fixed caps
* can happen if a Parser/Converter was autoplugged before
* this. We then assume that it will be able to convert to
* everything that the decoder would want.
*
* A subset check will fail here because the parser caps
* will be generic and while the decoder will only
* support a subset of the parser caps.
*/
if (gst_caps_is_fixed (caps)) {
const GList *templs;
gboolean skip = FALSE;
templs = gst_element_factory_get_static_pad_templates (factory);
while (templs) {
GstStaticPadTemplate *templ = (GstStaticPadTemplate *) templs->data;
if (templ->direction == GST_PAD_SINK) {
GstCaps *templcaps = gst_static_caps_get (&templ->static_caps);
if (!gst_caps_is_subset (caps, templcaps)) {
gst_caps_unref (templcaps);
skip = TRUE;
break;
}
gst_caps_unref (templcaps);
}
templs = g_list_next (templs);
}
if (skip) {
gst_object_unref (factory);
continue;
}
}
/* If the factory is for a parser we first check if the factory
* was already used for the current chain. If it was used already
* we would otherwise create an infinite loop here because the

View file

@ -2113,7 +2113,8 @@ gst_play_sink_reconfigure (GstPlaySink * playsink)
GST_OBJECT_UNLOCK (playsink);
/* figure out which components we need */
if (flags & GST_PLAY_FLAG_TEXT && playsink->text_pad) {
if (flags & GST_PLAY_FLAG_TEXT && playsink->video_pad_raw
&& playsink->text_pad) {
/* we have subtitles and we are requested to show it */
need_text = TRUE;
}
@ -3027,14 +3028,14 @@ caps_notify_cb (GstPad * pad, GParamSpec * unused, GstPlaySink * playsink)
if (pad == playsink->audio_pad) {
raw = is_raw_pad (pad);
reconfigure = (!!playsink->audio_pad_raw != !!raw)
reconfigure = (! !playsink->audio_pad_raw != ! !raw)
&& playsink->audiochain;
GST_DEBUG_OBJECT (pad,
"Audio caps changed: raw %d reconfigure %d caps %" GST_PTR_FORMAT, raw,
reconfigure, caps);
} else if (pad == playsink->video_pad) {
raw = is_raw_pad (pad);
reconfigure = (!!playsink->video_pad_raw != !!raw)
reconfigure = (! !playsink->video_pad_raw != ! !raw)
&& playsink->videochain;
GST_DEBUG_OBJECT (pad,
"Video caps changed: raw %d reconfigure %d caps %" GST_PTR_FORMAT, raw,

View file

@ -404,7 +404,8 @@ GST_START_TEST (test_large_discont)
audiorate = gst_check_setup_element ("audiorate");
caps = gst_caps_new_simple ("audio/x-raw-float",
"channels", G_TYPE_INT, 1,
"rate", G_TYPE_INT, 44100, "width", G_TYPE_INT, 32, NULL);
"rate", G_TYPE_INT, 44100, "width", G_TYPE_INT, 32,
"endianness", G_TYPE_INT, G_BYTE_ORDER, NULL);
srcpad = gst_check_setup_src_pad (audiorate, &srctemplate, caps);
sinkpad = gst_check_setup_sink_pad (audiorate, &sinktemplate, caps);

View file

@ -0,0 +1,658 @@
/* GStreamer unit tests for decodebin2
*
* Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
* Copyright (C) 2011 Hewlett-Packard Development Company, L.P.
* Author: Tim-Philipp Müller <tim.muller@collabora.co.uk>, Collabora Ltd.
* Sebastian Dröge <sebastian.droege@collabora.co.uk>, Collabora Ltd.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <gst/check/gstcheck.h>
#include <gst/base/gstbaseparse.h>
#include <gst/base/gstbasetransform.h>
#include <unistd.h>
static const gchar dummytext[] =
"Quick Brown Fox Jumps over a Lazy Frog Quick Brown "
"Fox Jumps over a Lazy Frog Quick Brown Fox Jumps over a Lazy Frog Quick "
"Brown Fox Jumps over a Lazy Frog Quick Brown Fox Jumps over a Lazy Frog "
"Quick Brown Fox Jumps over a Lazy Frog Quick Brown Fox Jumps over a Lazy "
"Frog Quick Brown Fox Jumps over a Lazy Frog Quick Brown Fox Jumps over a "
"Lazy Frog Quick Brown Fox Jumps over a Lazy Frog Quick Brown Fox Jumps "
"over a Lazy Frog Quick Brown Fox Jumps over a Lazy Frog Quick Brown Fox "
"jumps over a Lazy Frog Quick Brown Fox Jumps over a Lazy Frog Quick Brown "
"Fox Jumps over a Lazy Frog Quick Brown Fox Jumps over a Lazy Frog Quick "
"Brown Fox Jumps over a Lazy Frog Quick Brown Fox Jumps over a Lazy Frog "
"Quick Brown Fox Jumps over a Lazy Frog Quick Brown Fox Jumps over a Lazy "
"Frog Quick Brown Fox Jumps over a Lazy Frog Quick Brown Fox Jumps over a "
"Lazy Frog Quick Brown Fox Jumps over a Lazy Frog Quick Brown Fox Jumps "
"over a Lazy Frog Quick Brown Fox Jumps over a Lazy Frog Quick Brown Fox ";
static void
src_handoff_cb (GstElement * src, GstBuffer * buf, GstPad * pad, gpointer data)
{
GST_BUFFER_DATA (buf) = (guint8 *) dummytext;
GST_BUFFER_SIZE (buf) = sizeof (dummytext);
GST_BUFFER_OFFSET (buf) = 0;
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_READONLY);
}
static void
decodebin_new_decoded_pad_cb (GstElement * decodebin, GstPad * pad,
gboolean last, gboolean * p_flag)
{
/* we should not be reached */
fail_unless (decodebin == NULL, "new-decoded-pad should not be emitted");
}
/* make sure that decodebin errors out instead of creating a new decoded pad
* if the entire stream is a plain text file */
GST_START_TEST (test_text_plain_streams)
{
GstElement *pipe, *src, *decodebin;
GstMessage *msg;
pipe = gst_pipeline_new (NULL);
fail_unless (pipe != NULL, "failed to create pipeline");
src = gst_element_factory_make ("fakesrc", "src");
fail_unless (src != NULL, "Failed to create fakesrc element");
g_object_set (src, "signal-handoffs", TRUE, NULL);
g_object_set (src, "num-buffers", 1, NULL);
g_object_set (src, "can-activate-pull", FALSE, NULL);
g_signal_connect (src, "handoff", G_CALLBACK (src_handoff_cb), NULL);
decodebin = gst_element_factory_make ("decodebin2", "decodebin");
fail_unless (decodebin != NULL, "Failed to create decodebin element");
g_signal_connect (decodebin, "new-decoded-pad",
G_CALLBACK (decodebin_new_decoded_pad_cb), NULL);
fail_unless (gst_bin_add (GST_BIN (pipe), src));
fail_unless (gst_bin_add (GST_BIN (pipe), decodebin));
fail_unless (gst_element_link (src, decodebin), "can't link src<->decodebin");
fail_unless_equals_int (gst_element_set_state (pipe, GST_STATE_READY),
GST_STATE_CHANGE_SUCCESS);
/* it's push-based, so should be async */
fail_unless_equals_int (gst_element_set_state (pipe, GST_STATE_PAUSED),
GST_STATE_CHANGE_ASYNC);
/* it should error out at some point */
msg = gst_bus_poll (GST_ELEMENT_BUS (pipe), GST_MESSAGE_ERROR, -1);
fail_unless (msg != NULL);
fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR);
gst_message_unref (msg);
gst_element_set_state (pipe, GST_STATE_NULL);
gst_object_unref (pipe);
}
GST_END_TEST;
static void
new_decoded_pad_plug_fakesink_cb (GstElement * decodebin, GstPad * srcpad,
gboolean last, GstElement * pipeline)
{
GstElement *sink;
GstPad *sinkpad;
GST_LOG ("Linking fakesink");
sink = gst_element_factory_make ("fakesink", "sink");
fail_unless (sink != NULL, "Failed to create fakesink element");
gst_bin_add (GST_BIN (pipeline), sink);
sinkpad = gst_element_get_static_pad (sink, "sink");
fail_unless_equals_int (gst_pad_link (srcpad, sinkpad), GST_PAD_LINK_OK);
gst_object_unref (sinkpad);
gst_element_set_state (sink, GST_STATE_PLAYING);
}
GST_START_TEST (test_reuse_without_decoders)
{
GstElement *pipe, *src, *decodebin, *sink;
pipe = gst_pipeline_new (NULL);
fail_unless (pipe != NULL, "failed to create pipeline");
src = gst_element_factory_make ("audiotestsrc", "src");
fail_unless (src != NULL, "Failed to create audiotestsrc element");
decodebin = gst_element_factory_make ("decodebin2", "decodebin");
fail_unless (decodebin != NULL, "Failed to create decodebin element");
g_signal_connect (decodebin, "new-decoded-pad",
G_CALLBACK (new_decoded_pad_plug_fakesink_cb), pipe);
fail_unless (gst_bin_add (GST_BIN (pipe), src));
fail_unless (gst_bin_add (GST_BIN (pipe), decodebin));
fail_unless (gst_element_link (src, decodebin), "can't link src<->decodebin");
fail_unless_equals_int (gst_element_set_state (pipe, GST_STATE_READY),
GST_STATE_CHANGE_SUCCESS);
/* it's push-based, so should be async */
fail_unless_equals_int (gst_element_set_state (pipe, GST_STATE_PAUSED),
GST_STATE_CHANGE_ASYNC);
/* wait for state change to complete */
fail_unless_equals_int (gst_element_get_state (pipe, NULL, NULL, -1),
GST_STATE_CHANGE_SUCCESS);
/* there shouldn't be any errors */
fail_if (gst_bus_poll (GST_ELEMENT_BUS (pipe), GST_MESSAGE_ERROR, 0) != NULL);
/* reset */
gst_element_set_state (pipe, GST_STATE_READY);
sink = gst_bin_get_by_name (GST_BIN (pipe), "sink");
gst_bin_remove (GST_BIN (pipe), sink);
gst_element_set_state (sink, GST_STATE_NULL);
gst_object_unref (sink);
GST_LOG ("second try");
fail_unless_equals_int (gst_element_set_state (pipe, GST_STATE_READY),
GST_STATE_CHANGE_SUCCESS);
/* it's push-based, so should be async */
fail_unless_equals_int (gst_element_set_state (pipe, GST_STATE_PAUSED),
GST_STATE_CHANGE_ASYNC);
/* wait for state change to complete */
fail_unless_equals_int (gst_element_get_state (pipe, NULL, NULL, -1),
GST_STATE_CHANGE_SUCCESS);
/* there shouldn't be any errors */
fail_if (gst_bus_poll (GST_ELEMENT_BUS (pipe), GST_MESSAGE_ERROR, 0) != NULL);
gst_element_set_state (pipe, GST_STATE_NULL);
gst_object_unref (pipe);
}
GST_END_TEST;
/* Fake mp3 parser for test */
typedef GstBaseParse TestMpegAudioParse;
typedef GstBaseParseClass TestMpegAudioParseClass;
static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/mpeg, mpegversion=1, layer=[1,3], parsed=(b)true")
);
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/mpeg, mpegversion=1, parsed=(bool) { false, true }")
);
static GType test_mpeg_audio_parse_get_type (void);
static gboolean test_mpeg_audio_parse_start (GstBaseParse * parse);
static gboolean test_mpeg_audio_parse_stop (GstBaseParse * parse);
static gboolean test_mpeg_audio_parse_check_valid_frame (GstBaseParse * parse,
GstBaseParseFrame * frame, guint * size, gint * skipsize);
static GstFlowReturn test_mpeg_audio_parse_parse_frame (GstBaseParse * parse,
GstBaseParseFrame * frame);
GST_BOILERPLATE (TestMpegAudioParse, test_mpeg_audio_parse, GstBaseParse,
GST_TYPE_BASE_PARSE);
static void
test_mpeg_audio_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 (&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, "MPEG1 Audio Parser",
"Codec/Parser/Audio", "Pretends to parse mpeg1 audio stream",
"Foo Bar <foo@bar.com>");
}
static void
test_mpeg_audio_parse_class_init (TestMpegAudioParseClass * klass)
{
GstBaseParseClass *parse_class = GST_BASE_PARSE_CLASS (klass);
parse_class->start = test_mpeg_audio_parse_start;
parse_class->stop = test_mpeg_audio_parse_stop;
parse_class->check_valid_frame = test_mpeg_audio_parse_check_valid_frame;
parse_class->parse_frame = test_mpeg_audio_parse_parse_frame;
}
static gint num_parse_instances = 0;
static void
test_mpeg_audio_parse_init (TestMpegAudioParse * mp3parse,
TestMpegAudioParseClass * klass)
{
/* catch decodebin plugging parsers in a loop early */
fail_unless (++num_parse_instances < 10);
}
static gboolean
test_mpeg_audio_parse_start (GstBaseParse * parse)
{
gst_base_parse_set_min_frame_size (parse, 6);
return TRUE;
}
static gboolean
test_mpeg_audio_parse_stop (GstBaseParse * parse)
{
return TRUE;
}
static gboolean
test_mpeg_audio_parse_check_valid_frame (GstBaseParse * parse,
GstBaseParseFrame * frame, guint * framesize, gint * skipsize)
{
const guint8 *data = GST_BUFFER_DATA (frame->buffer);
if ((GST_READ_UINT16_BE (data) & 0xffe0) == 0xffe0) {
/* this framesize is hard-coded for ../test.mp3 */
*framesize = 1045;
return TRUE;
} else {
*skipsize = 1;
return FALSE;
}
}
static GstFlowReturn
test_mpeg_audio_parse_parse_frame (GstBaseParse * parse,
GstBaseParseFrame * frame)
{
if (GST_BUFFER_OFFSET (frame->buffer) == 0) {
GstCaps *caps;
caps = gst_caps_new_simple ("audio/mpeg", "mpegversion", G_TYPE_INT, 1,
"mpegaudioversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, 3,
"rate", G_TYPE_INT, 44100, "channels", G_TYPE_INT, 2, NULL);
gst_buffer_set_caps (frame->buffer, caps);
gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps);
gst_caps_unref (caps);
}
return GST_FLOW_OK;
}
static gboolean
plugin_init (GstPlugin * plugin)
{
return gst_element_register (plugin, "testmpegaudioparse", GST_RANK_NONE,
test_mpeg_audio_parse_get_type ());
}
GST_START_TEST (test_mp3_parser_loop)
{
GstStateChangeReturn sret;
GstPluginFeature *feature;
GstMessage *msg;
GstElement *pipe, *src, *dec;
gchar *path;
num_parse_instances = 0;
gst_plugin_register_static (GST_VERSION_MAJOR, GST_VERSION_MINOR,
"fakemp3parse", "fakemp3parse", plugin_init, VERSION, "LGPL",
"gst-plugins-base", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
feature = gst_default_registry_find_feature ("testmpegaudioparse",
GST_TYPE_ELEMENT_FACTORY);
gst_plugin_feature_set_rank (feature, GST_RANK_PRIMARY + 100);
pipe = gst_pipeline_new (NULL);
src = gst_element_factory_make ("filesrc", NULL);
fail_unless (src != NULL);
path = g_build_filename (GST_TEST_FILES_PATH, "test.mp3", NULL);
g_object_set (src, "location", path, NULL);
g_free (path);
dec = gst_element_factory_make ("decodebin2", NULL);
fail_unless (dec != NULL);
gst_bin_add_many (GST_BIN (pipe), src, dec, NULL);
gst_element_link_many (src, dec, NULL);
sret = gst_element_set_state (pipe, GST_STATE_PLAYING);
fail_unless_equals_int (sret, GST_STATE_CHANGE_ASYNC);
/* wait for unlinked error */
msg = gst_bus_timed_pop_filtered (GST_ELEMENT_BUS (pipe),
GST_CLOCK_TIME_NONE, GST_MESSAGE_ERROR);
gst_message_unref (msg);
gst_element_set_state (pipe, GST_STATE_NULL);
gst_object_unref (pipe);
/* make sure out parser got plugged at all though */
fail_unless_equals_int (num_parse_instances, 1);
/* don't want to interfere with any other of the other tests */
gst_plugin_feature_set_rank (feature, GST_RANK_NONE);
gst_object_unref (feature);
}
GST_END_TEST;
/* Fake parser/decoder for parser_negotiation test */
static GType gst_fake_h264_parser_get_type (void);
static GType gst_fake_h264_decoder_get_type (void);
#undef parent_class
#define parent_class fake_h264_parser_parent_class
typedef struct _GstFakeH264Parser GstFakeH264Parser;
typedef GstBaseTransformClass GstFakeH264ParserClass;
struct _GstFakeH264Parser
{
GstBaseTransform parent;
};
GST_BOILERPLATE (GstFakeH264Parser, gst_fake_h264_parser, GstBaseTransform,
GST_TYPE_BASE_TRANSFORM);
static void
gst_fake_h264_parser_base_init (gpointer klass)
{
static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK, GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-h264"));
static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC, GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-h264, "
"stream-format=(string) { avc, byte-stream }"));
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&sink_templ));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&src_templ));
gst_element_class_set_details_simple (element_class,
"FakeH264Parser", "Codec/Parser/Converter/Video", "yep", "me");
}
static GstFlowReturn
gst_fake_h264_parser_transform (GstBaseTransform * trans, GstBuffer * inbuf,
GstBuffer * outbuf)
{
return GST_FLOW_OK;
}
static GstCaps *
gst_fake_h264_parser_transform_caps (GstBaseTransform * trans,
GstPadDirection direction, GstCaps * caps)
{
if (direction == GST_PAD_SRC)
return gst_caps_from_string ("video/x-h264");
else
return gst_caps_from_string ("video/x-h264, "
"stream-format=(string) { avc, byte-stream }");
}
static gboolean
gst_fake_h264_parser_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
guint * size)
{
*size = 1;
return TRUE;
}
static gboolean
gst_fake_h264_parser_set_caps (GstBaseTransform * trans, GstCaps * incaps,
GstCaps * outcaps)
{
GstStructure *s;
const gchar *stream_format;
s = gst_caps_get_structure (incaps, 0);
fail_unless (gst_structure_has_name (s, "video/x-h264"));
s = gst_caps_get_structure (outcaps, 0);
fail_unless (gst_structure_has_name (s, "video/x-h264"));
stream_format = gst_structure_get_string (s, "stream-format");
fail_unless_equals_string ("byte-stream", stream_format);
return TRUE;
}
static GstFlowReturn
gst_fake_h264_parser_prepare_output_buffer (GstBaseTransform * trans,
GstBuffer * inbuf, gint size, GstCaps * caps, GstBuffer ** outbuf)
{
*outbuf = gst_buffer_ref (inbuf);
return GST_FLOW_OK;
}
static void
gst_fake_h264_parser_class_init (GstFakeH264ParserClass * klass)
{
GstBaseTransformClass *basetrans_class = (GstBaseTransformClass *) klass;
basetrans_class->transform = gst_fake_h264_parser_transform;
basetrans_class->transform_caps = gst_fake_h264_parser_transform_caps;
basetrans_class->get_unit_size = gst_fake_h264_parser_get_unit_size;
basetrans_class->set_caps = gst_fake_h264_parser_set_caps;
basetrans_class->prepare_output_buffer =
gst_fake_h264_parser_prepare_output_buffer;
}
static void
gst_fake_h264_parser_init (GstFakeH264Parser * self,
GstFakeH264ParserClass * klass)
{
}
#undef parent_class
#define parent_class fake_h264_decoder_parent_class
typedef struct _GstFakeH264Decoder GstFakeH264Decoder;
typedef GstBaseTransformClass GstFakeH264DecoderClass;
struct _GstFakeH264Decoder
{
GstBaseTransform parent;
};
GST_BOILERPLATE (GstFakeH264Decoder, gst_fake_h264_decoder, GstBaseTransform,
GST_TYPE_BASE_TRANSFORM);
static void
gst_fake_h264_decoder_base_init (gpointer klass)
{
static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK, GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-h264, " "stream-format=(string) byte-stream"));
static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC, GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-raw-yuv"));
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&sink_templ));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&src_templ));
gst_element_class_set_details_simple (element_class,
"FakeH264Decoder", "Codec/Decoder/Video", "yep", "me");
}
static GstFlowReturn
gst_fake_h264_decoder_transform (GstBaseTransform * trans, GstBuffer * inbuf,
GstBuffer * outbuf)
{
return GST_FLOW_OK;
}
static GstCaps *
gst_fake_h264_decoder_transform_caps (GstBaseTransform * trans,
GstPadDirection direction, GstCaps * caps)
{
if (direction == GST_PAD_SRC)
return gst_caps_from_string ("video/x-h264, "
"stream-format=(string) byte-stream");
else
return gst_caps_from_string ("video/x-raw-yuv");
}
static gboolean
gst_fake_h264_decoder_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
guint * size)
{
*size = 1;
return TRUE;
}
static gboolean
gst_fake_h264_decoder_set_caps (GstBaseTransform * trans, GstCaps * incaps,
GstCaps * outcaps)
{
GstStructure *s;
const gchar *stream_format;
s = gst_caps_get_structure (incaps, 0);
fail_unless (gst_structure_has_name (s, "video/x-h264"));
stream_format = gst_structure_get_string (s, "stream-format");
fail_unless_equals_string ("byte-stream", stream_format);
s = gst_caps_get_structure (outcaps, 0);
fail_unless (gst_structure_has_name (s, "video/x-raw-yuv"));
return TRUE;
}
static GstFlowReturn
gst_fake_h264_decoder_prepare_output_buffer (GstBaseTransform * trans,
GstBuffer * inbuf, gint size, GstCaps * caps, GstBuffer ** outbuf)
{
*outbuf = gst_buffer_ref (inbuf);
return GST_FLOW_OK;
}
static void
gst_fake_h264_decoder_class_init (GstFakeH264DecoderClass * klass)
{
GstBaseTransformClass *basetrans_class = (GstBaseTransformClass *) klass;
basetrans_class->transform = gst_fake_h264_decoder_transform;
basetrans_class->transform_caps = gst_fake_h264_decoder_transform_caps;
basetrans_class->get_unit_size = gst_fake_h264_decoder_get_unit_size;
basetrans_class->set_caps = gst_fake_h264_decoder_set_caps;
basetrans_class->prepare_output_buffer =
gst_fake_h264_decoder_prepare_output_buffer;
}
static void
gst_fake_h264_decoder_init (GstFakeH264Decoder * self,
GstFakeH264DecoderClass * klass)
{
}
static void
parser_negotiation_pad_added_cb (GstElement * dec, GstPad * pad,
gpointer user_data)
{
GstBin *pipe = user_data;
GstElement *sink;
GstPad *sinkpad;
sink = gst_element_factory_make ("fakesink", NULL);
gst_bin_add (pipe, sink);
gst_element_sync_state_with_parent (sink);
sinkpad = gst_element_get_static_pad (sink, "sink");
gst_pad_link (pad, sinkpad);
gst_object_unref (sinkpad);
}
GST_START_TEST (test_parser_negotiation)
{
GstStateChangeReturn sret;
GstMessage *msg;
GstCaps *caps;
GstElement *pipe, *src, *filter, *dec;
gst_element_register (NULL, "fakeh264parse", GST_RANK_PRIMARY + 101,
gst_fake_h264_parser_get_type ());
gst_element_register (NULL, "fakeh264dec", GST_RANK_PRIMARY + 100,
gst_fake_h264_decoder_get_type ());
pipe = gst_pipeline_new (NULL);
src = gst_element_factory_make ("fakesrc", NULL);
fail_unless (src != NULL);
g_object_set (G_OBJECT (src), "num-buffers", 5, "sizetype", 2, "filltype", 2,
"can-activate-pull", FALSE, NULL);
filter = gst_element_factory_make ("capsfilter", NULL);
fail_unless (filter != NULL);
caps = gst_caps_from_string ("video/x-h264");
g_object_set (G_OBJECT (filter), "caps", caps, NULL);
gst_caps_unref (caps);
dec = gst_element_factory_make ("decodebin2", NULL);
fail_unless (dec != NULL);
g_signal_connect (dec, "pad-added",
G_CALLBACK (parser_negotiation_pad_added_cb), pipe);
gst_bin_add_many (GST_BIN (pipe), src, filter, dec, NULL);
gst_element_link_many (src, filter, dec, NULL);
sret = gst_element_set_state (pipe, GST_STATE_PLAYING);
fail_unless_equals_int (sret, GST_STATE_CHANGE_ASYNC);
/* wait for EOS or error */
msg = gst_bus_timed_pop_filtered (GST_ELEMENT_BUS (pipe),
GST_CLOCK_TIME_NONE, GST_MESSAGE_ERROR | GST_MESSAGE_EOS);
fail_unless (msg != NULL);
fail_unless (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS);
gst_message_unref (msg);
gst_element_set_state (pipe, GST_STATE_NULL);
gst_object_unref (pipe);
}
GST_END_TEST;
static Suite *
decodebin2_suite (void)
{
Suite *s = suite_create ("decodebin2");
TCase *tc_chain = tcase_create ("general");
suite_add_tcase (s, tc_chain);
tcase_add_test (tc_chain, test_text_plain_streams);
tcase_add_test (tc_chain, test_reuse_without_decoders);
tcase_add_test (tc_chain, test_mp3_parser_loop);
tcase_add_test (tc_chain, test_parser_negotiation);
return s;
}
GST_CHECK_MAIN (decodebin2);