mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 20:21:24 +00:00
Merge branch 'master' into 0.11
Conflicts: docs/libs/Makefile.am tests/check/elements/decodebin2.c
This commit is contained in:
commit
0f654f3feb
10 changed files with 719 additions and 136 deletions
2
common
2
common
|
@ -1 +1 @@
|
|||
Subproject commit a39eb835fb3be2a4c5a6a89b5ca5cc064e79b2e2
|
||||
Subproject commit 11f0cd5a3fba36f85cf3e434150bfe66b1bf08d4
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
658
tests/check/elements/decodebin2.c
Normal file
658
tests/check/elements/decodebin2.c
Normal 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);
|
Loading…
Reference in a new issue