LOCAL_SHARED_LIBRARIES := \
libdl \
- libgstreamer-0.10 \
- libgstbase-0.10 \
+ libgstreamer-0.11 \
+ libgstbase-0.11 \
libglib-2.0 \
libgthread-2.0 \
libgmodule-2.0 \
libgobject-2.0 \
- libgstinterfaces-0.10 \
- libgstaudio-0.10
+ libgstinterfaces-0.11 \
+ libgstaudio-0.11
LOCAL_MODULE:= libgstalsa
#
LOCAL_PRELINK_MODULE := false
-#It's a gstreamer plugins, and it must be installed on ..../lib/gstreamer-0.10
-LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/gstreamer-0.10
+#It's a gstreamer plugins, and it must be installed on ..../lib/gstreamer-0.11
+LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/gstreamer-0.11
$(TARGET_OUT)/lib/libgstalsa.so:
LOCAL_PATH:= $(call my-dir)
#----------------------------------------
# include
-gst_app_COPY_HEADERS_TO := gstreamer-0.10/gst/app
+gst_app_COPY_HEADERS_TO := gstreamer-0.11/gst/app
gst_app_COPY_HEADERS := \
../gst-libs/gst/app/gstappbuffer.h \
../gst-libs/gst/app/gstappsink.h \
LOCAL_SRC_FILES:= $(addprefix ../,$(app_LOCAL_SRC_FILES_BASE))
LOCAL_SHARED_LIBRARIES := \
- libgstreamer-0.10 \
- libgstbase-0.10 \
+ libgstreamer-0.11 \
+ libgstbase-0.11 \
libglib-2.0 \
libgthread-2.0 \
libgmodule-2.0 \
libgobject-2.0
-LOCAL_MODULE:= libgstapp-0.10
+LOCAL_MODULE:= libgstapp-0.11
LOCAL_CFLAGS := -DHAVE_CONFIG_H -DGSTREAMER_BUILT_FOR_ANDROID \
$(GST_PLUGINS_BASE_CFLAGS)
LOCAL_SRC_FILES:= $(addprefix ../,$(app_plugin_LOCAL_SRC_FILES))
LOCAL_SHARED_LIBRARIES := \
- libgstreamer-0.10 \
- libgstbase-0.10 \
+ libgstreamer-0.11 \
+ libgstbase-0.11 \
libglib-2.0 \
libgthread-2.0 \
libgmodule-2.0 \
libgobject-2.0 \
- libgstapp-0.10
+ libgstapp-0.11
LOCAL_MODULE:= libgstapp
#
LOCAL_PRELINK_MODULE := false
-#It's a gstreamer plugins, and it must be installed on ..../lib/gstreamer-0.10
-LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/gstreamer-0.10
+#It's a gstreamer plugins, and it must be installed on ..../lib/gstreamer-0.11
+LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/gstreamer-0.11
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)
LOCAL_PATH:= $(call my-dir)
#----------------------------------------
# include
-gst_audio_COPY_HEADERS_TO := gstreamer-0.10/gst/audio
+gst_audio_COPY_HEADERS_TO := gstreamer-0.11/gst/audio
gst_audio_COPY_HEADERS_BASE := \
gst-libs/gst/audio/audio.h \
gst-libs/gst/audio/gstaudioclock.h \
LOCAL_SRC_FILES:= $(addprefix ../,$(audio_LOCAL_SRC_FILES_BASE))
LOCAL_SHARED_LIBRARIES := \
- libgstreamer-0.10 \
- libgstbase-0.10 \
+ libgstreamer-0.11 \
+ libgstbase-0.11 \
libglib-2.0 \
libgthread-2.0 \
libgmodule-2.0 \
libgobject-2.0 \
- libgstinterfaces-0.10
+ libgstinterfaces-0.11
-LOCAL_MODULE:= libgstaudio-0.10
+LOCAL_MODULE:= libgstaudio-0.11
LOCAL_CFLAGS := -DHAVE_CONFIG_H -DGSTREAMER_BUILT_FOR_ANDROID \
$(GST_PLUGINS_BASE_CFLAGS)
LOCAL_SRC_FILES:= $(addprefix ../,$(audioconvert_LOCAL_SRC_FILES))
LOCAL_SHARED_LIBRARIES := \
- libgstaudio-0.10 \
- libgstreamer-0.10 \
- libgstbase-0.10 \
+ libgstaudio-0.11 \
+ libgstreamer-0.11 \
+ libgstbase-0.11 \
libglib-2.0 \
libgthread-2.0 \
libgmodule-2.0 \
libgobject-2.0 \
- libgstpbutils-0.10
+ libgstpbutils-0.11
LOCAL_MODULE:= libgstaudioconvert
#
LOCAL_PRELINK_MODULE := false
-#It's a gstreamer plugins, and it must be installed on ..../lib/gstreamer-0.10
-LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/gstreamer-0.10
+#It's a gstreamer plugins, and it must be installed on ..../lib/gstreamer-0.11
+LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/gstreamer-0.11
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)
LOCAL_SRC_FILES:= $(addprefix ../,$(decodebin_LOCAL_SRC_FILES_BASE))
LOCAL_SHARED_LIBRARIES := \
- libgstreamer-0.10 \
- libgstbase-0.10 \
+ libgstreamer-0.11 \
+ libgstbase-0.11 \
libglib-2.0 \
libgthread-2.0 \
libgmodule-2.0 \
libgobject-2.0 \
- libgstpbutils-0.10
+ libgstpbutils-0.11
LOCAL_MODULE:= libgstdecodebin
#
LOCAL_PRELINK_MODULE := false
-#It's a gstreamer plugins, and it must be installed on ..../lib/gstreamer-0.10
-LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/gstreamer-0.10
+#It's a gstreamer plugins, and it must be installed on ..../lib/gstreamer-0.11
+LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/gstreamer-0.11
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)
LOCAL_SRC_FILES:= $(addprefix ../,$(decodebin2_LOCAL_SRC_FILES_BASE))
LOCAL_SHARED_LIBRARIES := \
- libgstreamer-0.10 \
- libgstbase-0.10 \
+ libgstreamer-0.11 \
+ libgstbase-0.11 \
libglib-2.0 \
libgthread-2.0 \
libgmodule-2.0 \
libgobject-2.0 \
- libgstpbutils-0.10
+ libgstpbutils-0.11
LOCAL_MODULE:= libgstdecodebin2
#
LOCAL_PRELINK_MODULE := false
-#It's a gstreamer plugins, and it must be installed on ..../lib/gstreamer-0.10
-LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/gstreamer-0.10
+#It's a gstreamer plugins, and it must be installed on ..../lib/gstreamer-0.11
+LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/gstreamer-0.11
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)
LOCAL_SRC_FILES:= $(addprefix ../,$(gdp_LOCAL_SRC_FILES))
LOCAL_SHARED_LIBRARIES := \
- libgstreamer-0.10 \
- libgstbase-0.10 \
+ libgstreamer-0.11 \
+ libgstbase-0.11 \
libglib-2.0 \
libgthread-2.0 \
libgmodule-2.0 \
libgobject-2.0 \
- libgstdataprotocol-0.10
+ libgstdataprotocol-0.11
LOCAL_MODULE:= libgstgdp
#
LOCAL_PRELINK_MODULE := false
-#It's a gstreamer plugins, and it must be installed on ..../lib/gstreamer-0.10
-LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/gstreamer-0.10
+#It's a gstreamer plugins, and it must be installed on ..../lib/gstreamer-0.11
+LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/gstreamer-0.11
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)
LOCAL_PATH:= $(call my-dir)
#----------------------------------------
# include
-gst_interfaces_COPY_HEADERS_TO := gstreamer-0.10/gst/interfaces
+gst_interfaces_COPY_HEADERS_TO := gstreamer-0.11/gst/interfaces
gst_interfaces_COPY_HEADERS_BASE := \
gst-libs/gst/interfaces/colorbalance.h \
gst-libs/gst/interfaces/colorbalancechannel.h \
$(addprefix ../android/,$(interfaces_LOCAL_SRC_FILES_ANDROID))
LOCAL_SHARED_LIBRARIES := \
- libgstreamer-0.10 \
- libgstbase-0.10 \
+ libgstreamer-0.11 \
+ libgstbase-0.11 \
libglib-2.0 \
libgthread-2.0 \
libgmodule-2.0 \
libgobject-2.0
-LOCAL_MODULE:= libgstinterfaces-0.10
-
+LOCAL_MODULE:= libgstinterfaces-0.11
LOCAL_CFLAGS := -DHAVE_CONFIG_H -DGSTREAMER_BUILT_FOR_ANDROID \
$(GST_PLUGINS_BASE_CFLAGS)
LOCAL_PATH:= $(call my-dir)
#----------------------------------------
# include
-gst_netbuffer_COPY_HEADERS_TO := gstreamer-0.10/gst/netbuffer
+gst_netbuffer_COPY_HEADERS_TO := gstreamer-0.11/gst/netbuffer
gst_netbuffer_COPY_HEADERS := \
../gst-libs/gst/netbuffer/gstnetbuffer.h
LOCAL_SRC_FILES:= $(addprefix ../,$(netbuffer_LOCAL_SRC_FILES))
LOCAL_SHARED_LIBRARIES := \
- libgstreamer-0.10 \
- libgstbase-0.10 \
+ libgstreamer-0.11 \
+ libgstbase-0.11 \
libglib-2.0 \
libgthread-2.0 \
libgmodule-2.0 \
libgobject-2.0
-LOCAL_MODULE:= libgstnetbuffer-0.10
+LOCAL_MODULE:= libgstnetbuffer-0.11
LOCAL_CFLAGS := -DHAVE_CONFIG_H -DGSTREAMER_BUILT_FOR_ANDROID \
$(GST_PLUGINS_BASE_CFLAGS)
GST_PBUTILS_DIR := gst-libs/gst/pbutils/
-gst_pbutils_COPY_HEADERS_TO := gstreamer-0.10/gst/pbutils
+gst_pbutils_COPY_HEADERS_TO := gstreamer-0.11/gst/pbutils
gst_pbutils_COPY_HEADERS_BASE := \
gst-libs/gst/pbutils/descriptions.h \
gst-libs/gst/pbutils/install-plugins.h \
LOCAL_SHARED_LIBRARIES := \
- libgstvideo-0.10 \
- libgstreamer-0.10 \
- libgstbase-0.10 \
+ libgstvideo-0.11 \
+ libgstreamer-0.11 \
+ libgstbase-0.11 \
libglib-2.0 \
libgthread-2.0 \
libgmodule-2.0 \
libgobject-2.0
-LOCAL_MODULE:= libgstpbutils-0.10
+LOCAL_MODULE:= libgstpbutils-0.11
LOCAL_CFLAGS := -DGSTREAMER_BUILT_FOR_ANDROID \
$(GST_PLUGINS_BASE_CFLAGS)
#
LOCAL_SRC_FILES:= $(addprefix ../,$(playbin_LOCAL_SRC_FILES_BASE))
LOCAL_SHARED_LIBRARIES := \
- libgstreamer-0.10 \
- libgstbase-0.10 \
+ libgstreamer-0.11 \
+ libgstbase-0.11 \
libglib-2.0 \
libgthread-2.0 \
libgmodule-2.0 \
libgobject-2.0 \
- libgstpbutils-0.10 \
- libgstinterfaces-0.10 \
- libgstvideo-0.10
+ libgstpbutils-0.11 \
+ libgstinterfaces-0.11 \
+ libgstvideo-0.11
LOCAL_MODULE:= libgstplaybin
#
LOCAL_PRELINK_MODULE := false
-#It's a gstreamer plugins, and it must be installed on ..../lib/gstreamer-0.10
-LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/gstreamer-0.10
+#It's a gstreamer plugins, and it must be installed on ..../lib/gstreamer-0.11
+LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/gstreamer-0.11
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)
LOCAL_SHARED_LIBRARIES := \
- libgstreamer-0.10 \
- libgstbase-0.10 \
+ libgstreamer-0.11 \
+ libgstbase-0.11 \
libglib-2.0 \
libgthread-2.0 \
libgmodule-2.0 \
libgobject-2.0 \
- libgstpbutils-0.10
+ libgstpbutils-0.11
LOCAL_MODULE:= libgstqueue2
#
LOCAL_PRELINK_MODULE := false
-#It's a gstreamer plugins, and it must be installed on ..../lib/gstreamer-0.10
-LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/gstreamer-0.10
+#It's a gstreamer plugins, and it must be installed on ..../lib/gstreamer-0.11
+LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/gstreamer-0.11
include $(BUILD_SHARED_LIBRARY)
LOCAL_PATH:= $(call my-dir)
#----------------------------------------
# include
-gst_riffs_COPY_HEADERS_TO := gstreamer-0.10/gst/riff
+gst_riffs_COPY_HEADERS_TO := gstreamer-0.11/gst/riff
gst_riffs_COPY_HEADERS := \
../gst-libs/gst/riff/riff-ids.h \
../gst-libs/gst/riff/riff-media.h \
LOCAL_SRC_FILES:= $(addprefix ../,$(riff_LOCAL_SRC_FILES))
LOCAL_SHARED_LIBRARIES := \
- libgstreamer-0.10 \
- libgstbase-0.10 \
+ libgstreamer-0.11 \
+ libgstbase-0.11 \
libglib-2.0 \
libgthread-2.0 \
libgmodule-2.0 \
libgobject-2.0 \
- libgsttag-0.10 \
- libgstaudio-0.10
+ libgsttag-0.11 \
+ libgstaudio-0.11
-LOCAL_MODULE:= libgstriff-0.10
+LOCAL_MODULE:= libgstriff-0.11
LOCAL_CFLAGS := -DHAVE_CONFIG_H -DGSTREAMER_BUILT_FOR_ANDROID \
$(GST_PLUGINS_BASE_CFLAGS)
LOCAL_PATH:= $(call my-dir)
#----------------------------------------
# include
-gst_rtp_COPY_HEADERS_TO := gstreamer-0.10/gst/rtp
+gst_rtp_COPY_HEADERS_TO := gstreamer-0.11/gst/rtp
gst_rtp_COPY_HEADERS := \
../gst-libs/gst/rtp/gstbasertpaudiopayload.h \
../gst-libs/gst/rtp/gstbasertpdepayload.h \
LOCAL_SHARED_LIBRARIES := \
libdl \
- libgstreamer-0.10 \
- libgstbase-0.10 \
+ libgstreamer-0.11 \
+ libgstbase-0.11 \
libglib-2.0 \
libgthread-2.0 \
libgmodule-2.0 \
libgobject-2.0
-LOCAL_MODULE:= libgstrtp-0.10
+LOCAL_MODULE:= libgstrtp-0.11
LOCAL_CFLAGS := -DHAVE_CONFIG_H -DGSTREAMER_BUILT_FOR_ANDROID \
$(GST_PLUGINS_BASE_CFLAGS)
#
LOCAL_PATH:= $(call my-dir)
#----------------------------------------
# include
-gst_rtsp_COPY_HEADERS_TO := gstreamer-0.10/gst/rtsp
+gst_rtsp_COPY_HEADERS_TO := gstreamer-0.11/gst/rtsp
gst_rtsp_COPY_HEADERS_BASE := \
gst-libs/gst/rtsp/gstrtspbase64.h \
gst-libs/gst/rtsp/gstrtspdefs.h \
LOCAL_SRC_FILES:= $(addprefix ../,$(rtsp_LOCAL_SRC_FILES_BASE))
LOCAL_SHARED_LIBRARIES := \
- libgstreamer-0.10 \
- libgstbase-0.10 \
+ libgstreamer-0.11 \
+ libgstbase-0.11 \
libglib-2.0 \
libgthread-2.0 \
libgmodule-2.0 \
libgobject-2.0
-LOCAL_MODULE:= libgstrtsp-0.10
+LOCAL_MODULE:= libgstrtsp-0.11
LOCAL_CFLAGS := -DHAVE_CONFIG_H -DINET_ADDRSTRLEN=16 -DGSTREAMER_BUILT_FOR_ANDROID \
$(GST_PLUGINS_BASE_CFLAGS)
LOCAL_PATH:= $(call my-dir)
#----------------------------------------
# include
-gst_sdp_COPY_HEADERS_TO := gstreamer-0.10/gst/sdp
+gst_sdp_COPY_HEADERS_TO := gstreamer-0.11/gst/sdp
gst_sdp_COPY_HEADERS := \
../gst-libs/gst/sdp/gstsdp.h \
../gst-libs/gst/sdp/gstsdpmessage.h
LOCAL_SRC_FILES:= $(addprefix ../,$(sdp_LOCAL_SRC_FILES))
LOCAL_SHARED_LIBRARIES := \
- libgstreamer-0.10 \
- libgstbase-0.10 \
+ libgstreamer-0.11 \
+ libgstbase-0.11 \
libglib-2.0 \
libgthread-2.0 \
libgmodule-2.0 \
libgobject-2.0
-LOCAL_MODULE:= libgstsdp-0.10
+LOCAL_MODULE:= libgstsdp-0.11
LOCAL_CFLAGS := -DHAVE_CONFIG_H -DGSTREAMER_BUILT_FOR_ANDROID \
$(GST_PLUGINS_BASE_CFLAGS)
#
LOCAL_PATH:= $(call my-dir)
#----------------------------------------
# include
-gst_tag_COPY_HEADERS_TO := gstreamer-0.10/gst/tag
+gst_tag_COPY_HEADERS_TO := gstreamer-0.11/gst/tag
gst_tag_COPY_HEADERS := \
../gst-libs/gst/tag/gsttagdemux.h \
../gst-libs/gst/tag/tag.h
LOCAL_SRC_FILES:= $(addprefix ../,$(tag_LOCAL_SRC_FILES))
LOCAL_SHARED_LIBRARIES := \
- libgstreamer-0.10 \
- libgstbase-0.10 \
+ libgstreamer-0.11 \
+ libgstbase-0.11 \
libglib-2.0 \
libgthread-2.0 \
libgmodule-2.0 \
libgobject-2.0
-LOCAL_MODULE:= libgsttag-0.10
-
+LOCAL_MODULE:= libgsttag-0.11
LOCAL_CFLAGS := -DHAVE_CONFIG_H -DGSTREAMER_BUILT_FOR_ANDROID \
$(GST_PLUGINS_BASE_CFLAGS)
LOCAL_SRC_FILES:= $(addprefix ../,$(tcp_LOCAL_SRC_FILES_BASE))
LOCAL_SHARED_LIBRARIES := \
- libgstreamer-0.10 \
- libgstbase-0.10 \
+ libgstreamer-0.11 \
+ libgstbase-0.11 \
libglib-2.0 \
libgthread-2.0 \
libgmodule-2.0 \
libgobject-2.0 \
- libgstdataprotocol-0.10
+ libgstdataprotocol-0.11
LOCAL_MODULE:= libgsttcp
#
LOCAL_PRELINK_MODULE := false
-#It's a gstreamer plugins, and it must be installed on ..../lib/gstreamer-0.10
-LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/gstreamer-0.10
+#It's a gstreamer plugins, and it must be installed on ..../lib/gstreamer-0.11
+LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/gstreamer-0.11
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)
LOCAL_SRC_FILES:= $(addprefix ../,$(typefindfunctions_LOCAL_SRC_FILES))
LOCAL_SHARED_LIBRARIES := \
- libgstreamer-0.10 \
- libgstbase-0.10 \
- libgstpbutils-0.10 \
+ libgstreamer-0.11 \
+ libgstbase-0.11 \
+ libgstpbutils-0.11 \
libglib-2.0 \
libgthread-2.0 \
libgmodule-2.0 \
#
LOCAL_PRELINK_MODULE := false
-#It's a gstreamer plugins, and it must be installed on ..../lib/gstreamer-0.10
-LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/gstreamer-0.10
+#It's a gstreamer plugins, and it must be installed on ..../lib/gstreamer-0.11
+LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/gstreamer-0.11
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)
LOCAL_PATH:= $(call my-dir)
#----------------------------------------
# include
-gst_video_COPY_HEADERS_TO := gstreamer-0.10/gst/video
+gst_video_COPY_HEADERS_TO := gstreamer-0.11/gst/video
gst_video_COPY_HEADERS_BASE := \
gst-libs/gst/video/gstvideofilter.h \
gst-libs/gst/video/gstvideosink.h \
LOCAL_SRC_FILES:= $(addprefix ../,$(video_LOCAL_SRC_FILES_BASE))
LOCAL_SHARED_LIBRARIES := \
- libgstreamer-0.10 \
- libgstbase-0.10 \
+ libgstreamer-0.11 \
+ libgstbase-0.11 \
libglib-2.0 \
libgthread-2.0 \
libgmodule-2.0 \
libgobject-2.0
-LOCAL_MODULE:= libgstvideo-0.10
+LOCAL_MODULE:= libgstvideo-0.11
LOCAL_CFLAGS := -DHAVE_CONFIG_H -DGSTREAMER_BUILT_FOR_ANDROID \
$(GST_PLUGINS_BASE_CFLAGS)
dnl initialize autoconf
dnl releases only do -Wall, git and prerelease does -Werror too
dnl use a three digit version number for releases, and four for git/prerelease
-AC_INIT(GStreamer Base Plug-ins, 0.10.34.1,
+AC_INIT(GStreamer Base Plug-ins, 0.11.0.1,
http://bugzilla.gnome.org/enter_bug.cgi?product=GStreamer,
gst-plugins-base)
dnl our libraries and install dirs use major.minor as a version
GST_MAJORMINOR=$PACKAGE_VERSION_MAJOR.$PACKAGE_VERSION_MINOR
dnl we override it here if we need to for the release candidate of new series
-GST_MAJORMINOR=0.10
+GST_MAJORMINOR=0.11
AC_SUBST(GST_MAJORMINOR)
dnl CURRENT, REVISION, AGE
AM_PROG_LIBTOOL
dnl *** required versions of GStreamer stuff ***
-GST_REQ=0.10.34.1
+GST_REQ=0.11.0
dnl *** autotools stuff ****
dnl check for gstreamer core features (subsystems)
dnl FIXME: this assumes srcdir == builddir for uninstalled setups
-GST_CONFIGPATH=`$PKG_CONFIG --variable=includedir gstreamer-0.10`"/gst/gstconfig.h"
+GST_CONFIGPATH=`$PKG_CONFIG --variable=includedir gstreamer-0.11`"/gst/gstconfig.h"
AG_GST_PARSE_SUBSYSTEM_DISABLES($GST_CONFIGPATH)
AM_CONDITIONAL(USE_XML, test $GST_DISABLE_XML != "1")
-e "s/.* PACKAGE_STRING$/#define PACKAGE_STRING \"$PACKAGE_STRING\"/" \
-e 's/.* PACKAGE_TARNAME$/#define PACKAGE_TARNAME "'$PACKAGE_TARNAME'"/' \
-e 's/.* PACKAGE_VERSION$/#define PACKAGE_VERSION "'$PACKAGE_VERSION'"/' \
- -e 's/.* PLUGINDIR$/#ifdef _DEBUG\n# define PLUGINDIR PREFIX "\\\\debug\\\\lib\\\\gstreamer-0.10"\n#else\n# define PLUGINDIR PREFIX "\\\\lib\\\\gstreamer-0.10"\n#endif/' \
+ -e 's/.* PLUGINDIR$/#ifdef _DEBUG\n# define PLUGINDIR PREFIX "\\\\debug\\\\lib\\\\gstreamer-0.11"\n#else\n# define PLUGINDIR PREFIX "\\\\lib\\\\gstreamer-0.11"\n#endif/' \
-e 's/.* USE_BINARY_REGISTRY$/#define USE_BINARY_REGISTRY/' \
-e 's/.* VERSION$/#define VERSION "'$VERSION'"/' \
-e "s/.* DEFAULT_AUDIOSINK$/#define DEFAULT_AUDIOSINK \"directsoundsink\"/" \
GObject
- GInputStream
- GOutputStream
- GstColorBalanceChannel
+ GInitiallyUnowned
+ GstObject
+ GstPad
+ GstPadTemplate
+ GstPluginFeature
+ GstElementFactory
+ GstTypeFindFactory
+ GstIndexFactory
+ GstElement
+ GstBin
+ GstPipeline
+ GstPlayBaseBin
+ GstPlayBin
+ GstPlayBin2
+ GstEncodeBin
+ GstDecodeBin
+ GstPlaySink
+ GstSubtitleOverlay
+ GstDecodeBin2
+ GstURIDecodeBin
+ GstVisual
+ GstVisualjess
+ GstVisualbumpscope
+ GstVisualcorona
+ GstVisualinfinite
+ GstVisualjakdaw
+ GstVisuallv_analyzer
+ GstVisuallv_scope
+ GstVisualoinksie
+ GstBaseSrc
+ GstGnomeVFSSrc
+ GstGioBaseSrc
+ GstGioSrc
+ GstGioStreamSrc
+ GstPushSrc
+ GstCddaBaseSrc
+ GstCdParanoiaSrc
+ GstBaseAudioSrc
+ GstAudioSrc
+ GstAlsaSrc
+ GstV4lElement
+ GstV4lSrc
+ GstVideoTestSrc
+ GstTCPClientSrc
+ GstTCPServerSrc
+ GstAppSrc
+ GstAudioTestSrc
+ GstBaseSink
+ GstGnomeVFSSink
+ GstGioBaseSink
+ GstGioSink
+ GstGioStreamSink
+ GstBaseAudioSink
+ GstAudioSink
+ GstAlsaSink
+ GstVideoSink
+ GstXvImageSink
+ GstXImageSink
+ GstAppSink
+ GstTCPClientSink
+ GstMultiFdSink
+ GstTCPServerSink
+ GstTheoraDec
+ GstTheoraEnc
+ GstTheoraParse
+ GstBaseTextOverlay
+ GstTextOverlay
+ GstTimeOverlay
+ GstClockOverlay
+ GstTextRender
+ GstOggDemux
+ GstOggMux
+ GstOgmParse
+ GstOgmAudioParse
+ GstOgmVideoParse
+ GstOgmTextParse
+ GstOggParse
+ GstOggAviParse
+ GstVorbisEnc
+ GstVorbisDec
+ GstVorbisParse
+ GstVorbisTag
+ GstAlsaMixerElement
+ GstSubParse
+ GstSsaParse
+ GstBaseTransform
+ GstAudioFilter
+ GstVolume
+ GstVideoFilter
+ GstVideoScale
+ GstFFMpegCsp
+ GstAudioResample
+ GstAudioConvert
+ GstGDPDepay
+ GstGDPPay
+ GstAudioRate
+ GstAdder
+ GstVideoRate
+ GstStreamSelector
+ GstBus
+ GstTask
+ GstTaskPool
+ GstClock
+ GstSystemClock
+ GstAudioClock
+ GstPlugin
+ GstRegistry
+ GstRingBuffer
+ GstAudioSrcRingBuffer
+ GstAudioSinkRingBuffer
GstMixerTrack
- GstObject
- GstBus
- GstClock
- GstSystemClock
- GstAudioClock
- GstElement
- GstAdder
- GstAlsaMixerElement
- GstAudioRate
- GstBaseSink
- GstAppSink
- GstBaseAudioSink
- GstAudioSink
- GstAlsaSink
- GstGioBaseSink
- GstGioSink
- GstGioStreamSink
- GstGnomeVFSSink
- GstMultiFdSink
- GstTCPServerSink
- GstTCPClientSink
- GstVideoSink
- GstXImageSink
- GstXvImageSink
- GstBaseSrc
- GstAppSrc
- GstAudioTestSrc
- GstGioBaseSrc
- GstGioSrc
- GstGioStreamSrc
- GstGnomeVFSSrc
- GstPushSrc
- GstBaseAudioSrc
- GstAudioSrc
- GstAlsaSrc
- GstCddaBaseSrc
- GstCdParanoiaSrc
- GstTCPClientSrc
- GstTCPServerSrc
- GstV4lElement
- GstV4lSrc
- GstVideoTestSrc
- GstBaseTransform
- GstAudioConvert
- GstAudioFilter
- GstVolume
- GstAudioResample
- GstVideoFilter
- GstFFMpegCsp
- GstVideoScale
- GstBin
- GstDecodeBin
- GstDecodeBin2
- GstEncodeBin
- GstPipeline
- GstPlayBaseBin
- GstPlayBin
- GstPlayBin2
- GstPlaySink
- GstSubtitleOverlay
- GstURIDecodeBin
- GstGDPDepay
- GstGDPPay
- GstOggAviParse
- GstOggDemux
- GstOggMux
- GstOggParse
- GstOgmParse
- GstOgmAudioParse
- GstOgmTextParse
- GstOgmVideoParse
- GstSsaParse
- GstStreamSelector
- GstSubParse
- GstTextOverlay
- GstClockOverlay
- GstTimeOverlay
- GstTextRender
- GstTheoraDec
- GstTheoraEnc
- GstTheoraParse
- GstVideoRate
- GstVisual
- GstVisualbumpscope
- GstVisualcorona
- GstVisualgforce
- GstVisualinfinite
- GstVisualjakdaw
- GstVisualjess
- GstVisuallv_scope
- GstVisualoinksie
- GstVorbisDec
- GstVorbisEnc
- GstVorbisParse
- GstVorbisTag
- GstPad
- GstPadTemplate
- GstPlugin
- GstPluginFeature
- GstElementFactory
- GstIndexFactory
- GstTypeFindFactory
- GstRegistry
- GstRingBuffer
- GstAudioSinkRingBuffer
- GstAudioSrcRingBuffer
- GstTask
- GstTaskPool
- GstSignalObject
GstStreamInfo
- GstTunerChannel
+ GstEncodingProfile
GstTunerNorm
- PangoContext
+ GstTunerChannel
+ GstColorBalanceChannel
PangoFontMap
PangoFcFontMap
PangoCairoFcFontMap
+ PangoContext
+ GInputStream
+ GOutputStream
GInterface
- GFile
GTypePlugin
GstChildProxy
- GstColorBalance
+ GstURIHandler
+ GstPreset
+ GstTagSetter
GstImplementsInterface
GstMixer
- GstNavigation
- GstPreset
GstPropertyProbe
- GstStreamVolume
- GstTagSetter
- GstTuner
- GstURIHandler
+ GstNavigation
GstXOverlay
+ GstColorBalance
+ GstTuner
+ GstStreamVolume
PangoCairoFontMap
+ GFile
-GstAlsaMixerElement GstImplementsInterface GstMixer GstPropertyProbe
-GstAlsaSink GstPropertyProbe
-GstAlsaSrc GstImplementsInterface GstMixer GstPropertyProbe
-GstAppSink GstURIHandler
-GstAppSrc GstURIHandler
GstBin GstChildProxy
-GstCdParanoiaSrc GstURIHandler
-GstCddaBaseSrc GstURIHandler
-GstDecodeBin GstChildProxy
-GstDecodeBin2 GstChildProxy
-GstEncodeBin GstChildProxy
-GstGioSink GstURIHandler
-GstGioSrc GstURIHandler
-GstGnomeVFSSink GstURIHandler
-GstGnomeVFSSrc GstURIHandler
-GstOggMux GstPreset
GstPipeline GstChildProxy
GstPlayBaseBin GstChildProxy
GstPlayBin GstChildProxy
GstPlayBin2 GstChildProxy GstStreamVolume
+GstEncodeBin GstChildProxy
+GstDecodeBin GstChildProxy
GstPlaySink GstChildProxy
GstSubtitleOverlay GstChildProxy
-GstTheoraEnc GstPreset
+GstDecodeBin2 GstChildProxy
GstURIDecodeBin GstChildProxy
+GstGnomeVFSSrc GstURIHandler
+GstGioSrc GstURIHandler
+GstCddaBaseSrc GstURIHandler
+GstCdParanoiaSrc GstURIHandler
+GstAlsaSrc GstImplementsInterface GstMixer GstPropertyProbe
GstV4lElement GstImplementsInterface GstTuner GstXOverlay GstColorBalance GstPropertyProbe
GstV4lSrc GstImplementsInterface GstTuner GstXOverlay GstColorBalance GstPropertyProbe
-GstVolume GstImplementsInterface GstMixer GstStreamVolume
+GstAppSrc GstURIHandler
+GstGnomeVFSSink GstURIHandler
+GstGioSink GstURIHandler
+GstAlsaSink GstPropertyProbe
+GstXvImageSink GstImplementsInterface GstNavigation GstXOverlay GstColorBalance GstPropertyProbe
+GstXImageSink GstImplementsInterface GstNavigation GstXOverlay
+GstAppSink GstURIHandler
+GstTheoraEnc GstPreset
+GstOggMux GstPreset
GstVorbisEnc GstTagSetter GstPreset
GstVorbisTag GstTagSetter
-GstXImageSink GstImplementsInterface GstNavigation GstXOverlay
-GstXvImageSink GstImplementsInterface GstNavigation GstXOverlay GstColorBalance GstPropertyProbe
+GstAlsaMixerElement GstImplementsInterface GstMixer GstPropertyProbe
+GstVolume GstImplementsInterface GstMixer GstStreamVolume
PangoCairoFcFontMap PangoCairoFontMap
-GFile GObject
GstChildProxy GstObject
-GstColorBalance GstImplementsInterface GstElement
+GstTagSetter GstElement
GstImplementsInterface GstElement
GstMixer GstImplementsInterface GstElement
-GstStreamVolume GObject
-GstTagSetter GstElement
-GstTuner GstImplementsInterface GstElement
GstXOverlay GstImplementsInterface GstElement
+GstColorBalance GstImplementsInterface GstElement
+GstTuner GstImplementsInterface GstElement
+GstStreamVolume GObject
PangoCairoFontMap PangoFontMap
+GFile GObject
#include "gstalsadeviceprobe.h"
#include "gst/interfaces/propertyprobe.h"
+G_LOCK_DEFINE_STATIC (probe_lock);
+
static const GList *
gst_alsa_device_property_probe_get_properties (GstPropertyProbe * probe)
{
GObjectClass *klass = G_OBJECT_GET_CLASS (probe);
static GList *list = NULL;
- /* well, not perfect, but better than no locking at all.
- * In the worst case we leak a list node, so who cares? */
- GST_CLASS_LOCK (GST_OBJECT_CLASS (klass));
+ G_LOCK (probe_lock);
if (!list) {
GParamSpec *pspec;
list = g_list_append (NULL, pspec);
}
- GST_CLASS_UNLOCK (GST_OBJECT_CLASS (klass));
+ G_UNLOCK (probe_lock);
return list;
}
};
static void gst_alsa_mixer_element_init_interfaces (GType type);
-
-GST_BOILERPLATE_FULL (GstAlsaMixerElement, gst_alsa_mixer_element,
- GstElement, GST_TYPE_ELEMENT, gst_alsa_mixer_element_init_interfaces);
+#define gst_alsa_mixer_element_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstAlsaMixerElement, gst_alsa_mixer_element,
+ GST_TYPE_ELEMENT,
+ gst_alsa_mixer_element_init_interfaces (g_define_type_id));
/* massive macro that takes care of all the GstMixer stuff */
GST_IMPLEMENT_ALSA_MIXER_METHODS (GstAlsaMixerElement, gst_alsa_mixer_element);
}
static void
-gst_alsa_mixer_element_base_init (gpointer klass)
-{
- gst_element_class_set_details_simple (GST_ELEMENT_CLASS (klass),
- "Alsa mixer", "Generic/Audio",
- "Control sound input and output levels with ALSA",
- "Leif Johnson <leif@ambient.2y.net>");
-}
-
-static void
gst_alsa_mixer_element_class_init (GstAlsaMixerElementClass * klass)
{
GstElementClass *element_class;
"Human-readable name of the sound device",
DEFAULT_PROP_DEVICE_NAME, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+ gst_element_class_set_details_simple (element_class,
+ "Alsa mixer", "Generic/Audio",
+ "Control sound input and output levels with ALSA",
+ "Leif Johnson <leif@ambient.2y.net>");
+
element_class->change_state =
GST_DEBUG_FUNCPTR (gst_alsa_mixer_element_change_state);
}
}
static void
-gst_alsa_mixer_element_init (GstAlsaMixerElement * this,
- GstAlsaMixerElementClass * klass)
+gst_alsa_mixer_element_init (GstAlsaMixerElement * this)
{
this->mixer = NULL;
this->device = g_strdup (DEFAULT_PROP_DEVICE);
GST_LOG ("[%s] created new mixer track %p", name, track);
/* This reflects the assumptions used for GstAlsaMixerTrack */
- if (!(!!(flags & GST_MIXER_TRACK_OUTPUT) ^ !!(flags & GST_MIXER_TRACK_INPUT))) {
+ if (!(! !(flags & GST_MIXER_TRACK_OUTPUT) ^ ! !(flags &
+ GST_MIXER_TRACK_INPUT))) {
GST_ERROR ("Mixer track must be either output or input!");
g_return_val_if_reached (NULL);
}
}
}
- if (!!(audible) != !(track->flags & GST_MIXER_TRACK_MUTE)) {
+ if (! !(audible) != !(track->flags & GST_MIXER_TRACK_MUTE)) {
if (audible) {
track->flags &= ~GST_MIXER_TRACK_MUTE;
};
static void gst_alsasink_init_interfaces (GType type);
-
-GST_BOILERPLATE_FULL (GstAlsaSink, gst_alsasink, GstAudioSink,
- GST_TYPE_AUDIO_SINK, gst_alsasink_init_interfaces);
+#define gst_alsasink_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstAlsaSink, gst_alsasink,
+ GST_TYPE_AUDIO_SINK, gst_alsasink_init_interfaces (g_define_type_id));
static void gst_alsasink_finalise (GObject * object);
static void gst_alsasink_set_property (GObject * object,
static void gst_alsasink_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec);
-static GstCaps *gst_alsasink_getcaps (GstBaseSink * bsink);
+static GstCaps *gst_alsasink_getcaps (GstBaseSink * bsink, GstCaps * filter);
static gboolean gst_alsasink_open (GstAudioSink * asink);
static gboolean gst_alsasink_prepare (GstAudioSink * asink,
}
static void
-gst_alsasink_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_set_details_simple (element_class,
- "Audio sink (ALSA)", "Sink/Audio",
- "Output to a sound card via ALSA", "Wim Taymans <wim@fluendo.com>");
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&alsasink_sink_factory));
-}
-
-static void
gst_alsasink_class_init (GstAlsaSinkClass * klass)
{
GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
GstBaseSinkClass *gstbasesink_class;
GstAudioSinkClass *gstaudiosink_class;
gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
gstbasesink_class = (GstBaseSinkClass *) klass;
gstaudiosink_class = (GstAudioSinkClass *) klass;
gobject_class->get_property = gst_alsasink_get_property;
gobject_class->set_property = gst_alsasink_set_property;
+ gst_element_class_set_details_simple (gstelement_class,
+ "Audio sink (ALSA)", "Sink/Audio",
+ "Output to a sound card via ALSA", "Wim Taymans <wim@fluendo.com>");
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&alsasink_sink_factory));
+
gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_alsasink_getcaps);
gstaudiosink_class->open = GST_DEBUG_FUNCPTR (gst_alsasink_open);
}
static void
-gst_alsasink_init (GstAlsaSink * alsasink, GstAlsaSinkClass * g_class)
+gst_alsasink_init (GstAlsaSink * alsasink)
{
GST_DEBUG_OBJECT (alsasink, "initializing alsasink");
} G_STMT_END;
static GstCaps *
-gst_alsasink_getcaps (GstBaseSink * bsink)
+gst_alsasink_getcaps (GstBaseSink * bsink, GstCaps * filter)
{
GstElementClass *element_class;
GstPadTemplate *pad_template;
GstAlsaSink *sink = GST_ALSA_SINK (bsink);
- GstCaps *caps;
+ GstCaps *caps, *templ_caps;
if (sink->handle == NULL) {
GST_DEBUG_OBJECT (sink, "device not open, using template caps");
if (sink->cached_caps) {
GST_LOG_OBJECT (sink, "Returning cached caps");
- return gst_caps_ref (sink->cached_caps);
+ if (filter)
+ return gst_caps_intersect_full (filter, sink->cached_caps,
+ GST_CAPS_INTERSECT_FIRST);
+ else
+ return gst_caps_ref (sink->cached_caps);
}
element_class = GST_ELEMENT_GET_CLASS (sink);
pad_template = gst_element_class_get_pad_template (element_class, "sink");
g_return_val_if_fail (pad_template != NULL, NULL);
+ templ_caps = gst_pad_template_get_caps (pad_template);
caps = gst_alsa_probe_supported_formats (GST_OBJECT (sink), sink->handle,
- gst_pad_template_get_caps (pad_template));
+ templ_caps);
+ gst_caps_unref (templ_caps);
if (caps) {
sink->cached_caps = gst_caps_ref (caps);
GST_INFO_OBJECT (sink, "returning caps %" GST_PTR_FORMAT, caps);
- return caps;
+ if (filter) {
+ GstCaps *intersection;
+
+ intersection =
+ gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+ gst_caps_unref (caps);
+ return intersection;
+ } else {
+ return caps;
+ }
}
static int
};
static void gst_alsasrc_init_interfaces (GType type);
-
-GST_BOILERPLATE_FULL (GstAlsaSrc, gst_alsasrc, GstAudioSrc,
- GST_TYPE_AUDIO_SRC, gst_alsasrc_init_interfaces);
+#define gst_alsasrc_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstAlsaSrc, gst_alsasrc,
+ GST_TYPE_AUDIO_SRC, gst_alsasrc_init_interfaces (g_define_type_id));
GST_IMPLEMENT_ALSA_MIXER_METHODS (GstAlsaSrc, gst_alsasrc_mixer);
static void gst_alsasrc_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec);
-static GstCaps *gst_alsasrc_getcaps (GstBaseSrc * bsrc);
+static GstCaps *gst_alsasrc_getcaps (GstBaseSrc * bsrc, GstCaps * filter);
static gboolean gst_alsasrc_open (GstAudioSrc * asrc);
static gboolean gst_alsasrc_prepare (GstAudioSrc * asrc,
}
static void
-gst_alsasrc_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_set_details_simple (element_class,
- "Audio source (ALSA)", "Source/Audio",
- "Read from a sound card via ALSA", "Wim Taymans <wim@fluendo.com>");
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&alsasrc_src_factory));
-}
-
-static void
gst_alsasrc_class_init (GstAlsaSrcClass * klass)
{
GObjectClass *gobject_class;
gobject_class->get_property = gst_alsasrc_get_property;
gobject_class->set_property = gst_alsasrc_set_property;
+ gst_element_class_set_details_simple (gstelement_class,
+ "Audio source (ALSA)", "Source/Audio",
+ "Read from a sound card via ALSA", "Wim Taymans <wim@fluendo.com>");
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&alsasrc_src_factory));
+
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_alsasrc_change_state);
gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_alsasrc_getcaps);
}
static void
-gst_alsasrc_init (GstAlsaSrc * alsasrc, GstAlsaSrcClass * g_class)
+gst_alsasrc_init (GstAlsaSrc * alsasrc)
{
GST_DEBUG_OBJECT (alsasrc, "initializing");
static GstCaps *
-gst_alsasrc_getcaps (GstBaseSrc * bsrc)
+gst_alsasrc_getcaps (GstBaseSrc * bsrc, GstCaps * filter)
{
GstElementClass *element_class;
GstPadTemplate *pad_template;
GstAlsaSrc *src;
- GstCaps *caps;
+ GstCaps *caps, *templ_caps;
src = GST_ALSA_SRC (bsrc);
if (src->cached_caps) {
GST_LOG_OBJECT (src, "Returning cached caps");
- return gst_caps_ref (src->cached_caps);
+ if (filter)
+ return gst_caps_intersect_full (filter, src->cached_caps,
+ GST_CAPS_INTERSECT_FIRST);
+ else
+ return gst_caps_ref (src->cached_caps);
}
element_class = GST_ELEMENT_GET_CLASS (src);
pad_template = gst_element_class_get_pad_template (element_class, "src");
g_return_val_if_fail (pad_template != NULL, NULL);
+ templ_caps = gst_pad_template_get_caps (pad_template);
caps = gst_alsa_probe_supported_formats (GST_OBJECT (src), src->handle,
- gst_pad_template_get_caps (pad_template));
+ templ_caps);
+ gst_caps_unref (templ_caps);
if (caps) {
src->cached_caps = gst_caps_ref (caps);
GST_INFO_OBJECT (src, "returning caps %" GST_PTR_FORMAT, caps);
- return caps;
+ if (filter) {
+ GstCaps *intersection;
+
+ intersection =
+ gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+ gst_caps_unref (caps);
+ return intersection;
+ } else {
+ return caps;
+ }
}
static int
GST_DEBUG_CATEGORY_STATIC (gst_cd_paranoia_src_debug);
#define GST_CAT_DEFAULT gst_cd_paranoia_src_debug
-GST_BOILERPLATE (GstCdParanoiaSrc, gst_cd_paranoia_src, GstCddaBaseSrc,
- GST_TYPE_CDDA_BASE_SRC);
+#define gst_cd_paranoia_src_parent_class parent_class
+G_DEFINE_TYPE (GstCdParanoiaSrc, gst_cd_paranoia_src, GST_TYPE_CDDA_BASE_SRC);
static void gst_cd_paranoia_src_finalize (GObject * obj);
static void gst_cd_paranoia_src_get_property (GObject * object, guint prop_id,
}
static void
-gst_cd_paranoia_src_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_set_details_simple (element_class,
- "CD Audio (cdda) Source, Paranoia IV", "Source/File",
- "Read audio from CD in paranoid mode",
- "Erik Walthinsen <omega@cse.ogi.edu>, Wim Taymans <wim@fluendo.com>");
-}
-
-static void
-gst_cd_paranoia_src_init (GstCdParanoiaSrc * src, GstCdParanoiaSrcClass * klass)
+gst_cd_paranoia_src_init (GstCdParanoiaSrc * src)
{
src->d = NULL;
src->p = NULL;
gst_cd_paranoia_src_class_init (GstCdParanoiaSrcClass * klass)
{
GstCddaBaseSrcClass *cddabasesrc_class = GST_CDDA_BASE_SRC_CLASS (klass);
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->set_property = gst_cd_paranoia_src_set_property;
gobject_class->get_property = gst_cd_paranoia_src_get_property;
gobject_class->finalize = gst_cd_paranoia_src_finalize;
+ gst_element_class_set_details_simple (element_class,
+ "CD Audio (cdda) Source, Paranoia IV", "Source/File",
+ "Read audio from CD in paranoid mode",
+ "Erik Walthinsen <omega@cse.ogi.edu>, Wim Taymans <wim@fluendo.com>");
+
cddabasesrc_class->open = gst_cd_paranoia_src_open;
cddabasesrc_class->close = gst_cd_paranoia_src_close;
cddabasesrc_class->read_sector = gst_cd_paranoia_src_read_sector;
goto read_failed;
buf = gst_buffer_new_and_alloc (CD_FRAMESIZE_RAW);
- memcpy (GST_BUFFER_DATA (buf), cdda_buf, CD_FRAMESIZE_RAW);
+ gst_buffer_fill (buf, 0, cdda_buf, CD_FRAMESIZE_RAW);
/* cdda base class will take care of timestamping etc. */
++src->next_sector;
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
-GST_BOILERPLATE (GstGioBaseSink, gst_gio_base_sink, GstBaseSink,
- GST_TYPE_BASE_SINK);
+#define gst_gio_base_sink_parent_class parent_class
+G_DEFINE_TYPE (GstGioBaseSink, gst_gio_base_sink, GST_TYPE_BASE_SINK);
static void gst_gio_base_sink_finalize (GObject * object);
static gboolean gst_gio_base_sink_start (GstBaseSink * base_sink);
static gboolean gst_gio_base_sink_query (GstPad * pad, GstQuery * query);
static void
-gst_gio_base_sink_base_init (gpointer gclass)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
-
- GST_DEBUG_CATEGORY_INIT (gst_gio_base_sink_debug, "gio_base_sink", 0,
- "GIO base sink");
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&sink_factory));
-}
-
-static void
gst_gio_base_sink_class_init (GstGioBaseSinkClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
+ GstElementClass *gstelement_class = (GstElementClass *) klass;
GstBaseSinkClass *gstbasesink_class = (GstBaseSinkClass *) klass;
+ GST_DEBUG_CATEGORY_INIT (gst_gio_base_sink_debug, "gio_base_sink", 0,
+ "GIO base sink");
+
gobject_class->finalize = gst_gio_base_sink_finalize;
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&sink_factory));
+
gstbasesink_class->start = GST_DEBUG_FUNCPTR (gst_gio_base_sink_start);
gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_gio_base_sink_stop);
gstbasesink_class->unlock = GST_DEBUG_FUNCPTR (gst_gio_base_sink_unlock);
}
static void
-gst_gio_base_sink_init (GstGioBaseSink * sink, GstGioBaseSinkClass * gclass)
+gst_gio_base_sink_init (GstGioBaseSink * sink)
{
gst_pad_set_query_function (GST_BASE_SINK_PAD (sink),
GST_DEBUG_FUNCPTR (gst_gio_base_sink_query));
return TRUE;
switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_NEWSEGMENT:
+ case GST_EVENT_SEGMENT:
if (G_IS_OUTPUT_STREAM (sink->stream)) {
- GstFormat format;
- gint64 offset;
+ const GstSegment *segment;
- gst_event_parse_new_segment (event, NULL, NULL, &format, &offset, NULL,
- NULL);
+ gst_event_parse_segment (event, &segment);
- if (format != GST_FORMAT_BYTES) {
- GST_WARNING_OBJECT (sink, "ignored NEWSEGMENT event in %s format",
- gst_format_get_name (format));
+ if (segment->format != GST_FORMAT_BYTES) {
+ GST_WARNING_OBJECT (sink, "ignored SEGMENT event in %s format",
+ gst_format_get_name (segment->format));
break;
}
if (GST_GIO_STREAM_IS_SEEKABLE (sink->stream)) {
- ret = gst_gio_seek (sink, G_SEEKABLE (sink->stream), offset,
+ ret = gst_gio_seek (sink, G_SEEKABLE (sink->stream), segment->start,
sink->cancel);
if (ret == GST_FLOW_OK)
- sink->position = offset;
+ sink->position = segment->start;
} else {
ret = GST_FLOW_NOT_SUPPORTED;
}
{
GstGioBaseSink *sink = GST_GIO_BASE_SINK (base_sink);
gssize written;
+ guint8 *data;
+ gsize size;
gboolean success;
GError *err = NULL;
g_return_val_if_fail (G_IS_OUTPUT_STREAM (sink->stream), GST_FLOW_ERROR);
- GST_LOG_OBJECT (sink, "writing %u bytes to offset %" G_GUINT64_FORMAT,
- GST_BUFFER_SIZE (buffer), sink->position);
+ data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
+
+ GST_LOG_OBJECT (sink,
+ "writing %" G_GSIZE_FORMAT " bytes to offset %" G_GUINT64_FORMAT, size,
+ sink->position);
- written = g_output_stream_write (sink->stream,
- GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer), sink->cancel, &err);
+ written =
+ g_output_stream_write (sink->stream, data, size, sink->cancel, &err);
+ gst_buffer_unmap (buffer, data, size);
success = (written >= 0);
- if (G_UNLIKELY (success && written < GST_BUFFER_SIZE (buffer))) {
+ if (G_UNLIKELY (success && written < size)) {
/* FIXME: Can this happen? Should we handle it gracefully? gnomevfssink
* doesn't... */
GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, (NULL),
("Could not write to stream: (short write, only %"
- G_GSSIZE_FORMAT " bytes of %d bytes written)",
- written, GST_BUFFER_SIZE (buffer)));
+ G_GSSIZE_FORMAT " bytes of %" G_GSIZE_FORMAT " bytes written)",
+ written, size));
return GST_FLOW_ERROR;
}
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
-GST_BOILERPLATE (GstGioBaseSrc, gst_gio_base_src, GstBaseSrc,
- GST_TYPE_BASE_SRC);
+#define gst_gio_base_src_parent_class parent_class
+G_DEFINE_TYPE (GstGioBaseSrc, gst_gio_base_src, GST_TYPE_BASE_SRC);
static void gst_gio_base_src_finalize (GObject * object);
static gboolean gst_gio_base_src_is_seekable (GstBaseSrc * base_src);
static gboolean gst_gio_base_src_unlock (GstBaseSrc * base_src);
static gboolean gst_gio_base_src_unlock_stop (GstBaseSrc * base_src);
-static gboolean gst_gio_base_src_check_get_range (GstBaseSrc * base_src);
static GstFlowReturn gst_gio_base_src_create (GstBaseSrc * base_src,
guint64 offset, guint size, GstBuffer ** buf);
static gboolean gst_gio_base_src_query (GstBaseSrc * base_src,
GstQuery * query);
static void
-gst_gio_base_src_base_init (gpointer gclass)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
-
- GST_DEBUG_CATEGORY_INIT (gst_gio_base_src_debug, "gio_base_src", 0,
- "GIO base source");
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&src_factory));
-}
-
-static void
gst_gio_base_src_class_init (GstGioBaseSrcClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
+ GstElementClass *gstelement_class = (GstElementClass *) klass;
GstBaseSrcClass *gstbasesrc_class = (GstBaseSrcClass *) klass;
+ GST_DEBUG_CATEGORY_INIT (gst_gio_base_src_debug, "gio_base_src", 0,
+ "GIO base source");
+
gobject_class->finalize = gst_gio_base_src_finalize;
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&src_factory));
+
gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_gio_base_src_start);
gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_gio_base_src_stop);
gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_gio_base_src_get_size);
gstbasesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_gio_base_src_unlock);
gstbasesrc_class->unlock_stop =
GST_DEBUG_FUNCPTR (gst_gio_base_src_unlock_stop);
- gstbasesrc_class->check_get_range =
- GST_DEBUG_FUNCPTR (gst_gio_base_src_check_get_range);
gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_gio_base_src_create);
gstbasesrc_class->query = GST_DEBUG_FUNCPTR (gst_gio_base_src_query);
}
static void
-gst_gio_base_src_init (GstGioBaseSrc * src, GstGioBaseSrcClass * gclass)
+gst_gio_base_src_init (GstGioBaseSrc * src)
{
src->cancel = g_cancellable_new ();
}
return TRUE;
}
-static gboolean
-gst_gio_base_src_check_get_range (GstBaseSrc * base_src)
-{
- return GST_CALL_PARENT_WITH_DEFAULT (GST_BASE_SRC_CLASS,
- check_get_range, (base_src), FALSE);
-}
-
static GstFlowReturn
gst_gio_base_src_create (GstBaseSrc * base_src, guint64 offset, guint size,
GstBuffer ** buf_return)
GST_DEBUG_OBJECT (src, "Creating subbuffer from cached buffer: offset %"
G_GUINT64_FORMAT " length %u", offset, size);
- buf = gst_buffer_create_sub (src->cache,
+ buf = gst_buffer_copy_region (src->cache, GST_BUFFER_COPY_ALL,
offset - GST_BUFFER_OFFSET (src->cache), size);
GST_BUFFER_OFFSET (buf) = offset;
GST_BUFFER_OFFSET_END (buf) = offset + size;
- GST_BUFFER_SIZE (buf) = size;
} else {
guint cachesize = MAX (4096, size);
+ guint8 *bdata;
gssize read, res;
gboolean success, eos;
GError *err = NULL;
return ret;
}
- src->cache = gst_buffer_try_new_and_alloc (cachesize);
+ src->cache = gst_buffer_new_and_alloc (cachesize);
if (G_UNLIKELY (src->cache == NULL)) {
GST_ERROR_OBJECT (src, "Failed to allocate %u bytes", cachesize);
return GST_FLOW_ERROR;
* supports reads up to 64k. So we loop here until we get at
* at least the requested amount of bytes or a read returns
* nothing. */
+ bdata = gst_buffer_map (src->cache, NULL, NULL, GST_MAP_WRITE);
read = 0;
while (size - read > 0 && (res =
g_input_stream_read (G_INPUT_STREAM (src->stream),
- GST_BUFFER_DATA (src->cache) + read, cachesize - read,
- src->cancel, &err)) > 0) {
+ bdata + read, cachesize - read, src->cancel, &err)) > 0) {
read += res;
}
+ gst_buffer_unmap (src->cache, bdata, read);
success = (read >= 0);
eos = (cachesize > 0 && read == 0);
if (success && !eos) {
src->position += read;
- GST_BUFFER_SIZE (src->cache) = read;
GST_BUFFER_OFFSET (src->cache) = offset;
GST_BUFFER_OFFSET_END (src->cache) = offset + read;
"cached buffer: offset %" G_GUINT64_FORMAT " length %u", offset,
size);
- buf = gst_buffer_create_sub (src->cache, 0, MIN (size, read));
+ buf =
+ gst_buffer_copy_region (src->cache, GST_BUFFER_COPY_ALL, 0, MIN (size,
+ read));
GST_BUFFER_OFFSET (buf) = offset;
GST_BUFFER_OFFSET_END (buf) = offset + MIN (size, read);
- GST_BUFFER_SIZE (buf) = MIN (size, read);
} else {
GST_DEBUG_OBJECT (src, "Read not successful");
gst_buffer_unref (src->cache);
PROP_FILE
};
-GST_BOILERPLATE_FULL (GstGioSink, gst_gio_sink, GstGioBaseSink,
- GST_TYPE_GIO_BASE_SINK, gst_gio_uri_handler_do_init);
+#define gst_gio_sink_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstGioSink, gst_gio_sink, GST_TYPE_GIO_BASE_SINK,
+ gst_gio_uri_handler_do_init (g_define_type_id));
static void gst_gio_sink_finalize (GObject * object);
static void gst_gio_sink_set_property (GObject * object, guint prop_id,
static GOutputStream *gst_gio_sink_get_stream (GstGioBaseSink * base_sink);
static void
-gst_gio_sink_base_init (gpointer gclass)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
-
- GST_DEBUG_CATEGORY_INIT (gst_gio_sink_debug, "gio_sink", 0, "GIO sink");
-
- gst_element_class_set_details_simple (element_class, "GIO sink",
- "Sink/File",
- "Write to any GIO-supported location",
- "Ren\xc3\xa9 Stadler <mail@renestadler.de>, "
- "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
-}
-
-static void
gst_gio_sink_class_init (GstGioSinkClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
+ GstElementClass *gstelement_class = (GstElementClass *) klass;
GstGioBaseSinkClass *gstgiobasesink_class = (GstGioBaseSinkClass *) klass;
+ GST_DEBUG_CATEGORY_INIT (gst_gio_sink_debug, "gio_sink", 0, "GIO sink");
+
gobject_class->finalize = gst_gio_sink_finalize;
gobject_class->set_property = gst_gio_sink_set_property;
gobject_class->get_property = gst_gio_sink_get_property;
g_param_spec_object ("file", "File", "GFile to write to",
G_TYPE_FILE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ gst_element_class_set_details_simple (gstelement_class, "GIO sink",
+ "Sink/File",
+ "Write to any GIO-supported location",
+ "Ren\xc3\xa9 Stadler <mail@renestadler.de>, "
+ "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+
gstgiobasesink_class->get_stream =
GST_DEBUG_FUNCPTR (gst_gio_sink_get_stream);
gstgiobasesink_class->close_on_stop = TRUE;
}
static void
-gst_gio_sink_init (GstGioSink * sink, GstGioSinkClass * gclass)
+gst_gio_sink_init (GstGioSink * sink)
{
}
PROP_FILE
};
-GST_BOILERPLATE_FULL (GstGioSrc, gst_gio_src, GstGioBaseSrc,
- GST_TYPE_GIO_BASE_SRC, gst_gio_uri_handler_do_init);
+#define gst_gio_src_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstGioSrc, gst_gio_src,
+ GST_TYPE_GIO_BASE_SRC, gst_gio_uri_handler_do_init (g_define_type_id));
static void gst_gio_src_finalize (GObject * object);
static GInputStream *gst_gio_src_get_stream (GstGioBaseSrc * bsrc);
-static gboolean gst_gio_src_check_get_range (GstBaseSrc * base_src);
-
-static void
-gst_gio_src_base_init (gpointer gclass)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
-
- GST_DEBUG_CATEGORY_INIT (gst_gio_src_debug, "gio_src", 0, "GIO source");
-
- gst_element_class_set_details_simple (element_class, "GIO source",
- "Source/File",
- "Read from any GIO-supported location",
- "Ren\xc3\xa9 Stadler <mail@renestadler.de>, "
- "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
-}
+static gboolean gst_gio_src_query (GstBaseSrc * base_src, GstQuery * query);
static void
gst_gio_src_class_init (GstGioSrcClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
+ GstElementClass *gstelement_class = (GstElementClass *) klass;
GstBaseSrcClass *gstbasesrc_class = (GstBaseSrcClass *) klass;
GstGioBaseSrcClass *gstgiobasesrc_class = (GstGioBaseSrcClass *) klass;
+ GST_DEBUG_CATEGORY_INIT (gst_gio_src_debug, "gio_src", 0, "GIO source");
+
gobject_class->finalize = gst_gio_src_finalize;
gobject_class->set_property = gst_gio_src_set_property;
gobject_class->get_property = gst_gio_src_get_property;
g_param_spec_object ("file", "File", "GFile to read from",
G_TYPE_FILE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- gstbasesrc_class->check_get_range =
- GST_DEBUG_FUNCPTR (gst_gio_src_check_get_range);
+ gst_element_class_set_details_simple (gstelement_class, "GIO source",
+ "Source/File",
+ "Read from any GIO-supported location",
+ "Ren\xc3\xa9 Stadler <mail@renestadler.de>, "
+ "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+
+ gstbasesrc_class->query = GST_DEBUG_FUNCPTR (gst_gio_src_query);
gstgiobasesrc_class->get_stream = GST_DEBUG_FUNCPTR (gst_gio_src_get_stream);
gstgiobasesrc_class->close_on_stop = TRUE;
}
static void
-gst_gio_src_init (GstGioSrc * src, GstGioSrcClass * gclass)
+gst_gio_src_init (GstGioSrc * src)
{
}
}
static gboolean
-gst_gio_src_check_get_range (GstBaseSrc * base_src)
+gst_gio_src_query (GstBaseSrc * base_src, GstQuery * query)
{
+ gboolean res;
GstGioSrc *src = GST_GIO_SRC (base_src);
- gchar *scheme;
-
- if (src->file == NULL)
- goto done;
-
- scheme = g_file_get_uri_scheme (src->file);
- if (scheme == NULL)
- goto done;
-
- if (strcmp (scheme, "file") == 0) {
- GST_LOG_OBJECT (src, "local URI, assuming random access is possible");
- g_free (scheme);
- return TRUE;
- } else if (strcmp (scheme, "http") == 0 || strcmp (scheme, "https") == 0) {
- GST_LOG_OBJECT (src, "blacklisted protocol '%s', "
- "no random access possible", scheme);
- g_free (scheme);
- return FALSE;
- }
-
- g_free (scheme);
-done:
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_SCHEDULING:
+ {
+ gchar *scheme;
+ gboolean pull_mode;
+
+ pull_mode = FALSE;
+ if (src->file == NULL)
+ goto forward_parent;
+
+ scheme = g_file_get_uri_scheme (src->file);
+ if (scheme == NULL)
+ goto forward_parent;
+
+ if (strcmp (scheme, "file") == 0) {
+ GST_LOG_OBJECT (src, "local URI, assuming random access is possible");
+ pull_mode = TRUE;
+ } else if (strcmp (scheme, "http") == 0 || strcmp (scheme, "https") == 0) {
+ GST_LOG_OBJECT (src, "blacklisted protocol '%s', "
+ "no random access possible", scheme);
+ } else {
+ GST_LOG_OBJECT (src, "unhandled protocol '%s', asking parent", scheme);
+ goto forward_parent;
+ }
+ g_free (scheme);
- GST_DEBUG_OBJECT (src, "undecided about random access, asking base class");
+ gst_query_set_scheduling (query, pull_mode, pull_mode, FALSE, 1, -1, 1);
+ res = TRUE;
+ break;
+ }
+ default:
+ forward_parent:
+ res = GST_CALL_PARENT_WITH_DEFAULT (GST_BASE_SRC_CLASS,
+ query, (base_src, query), FALSE);
+ break;
+ }
- return GST_CALL_PARENT_WITH_DEFAULT (GST_BASE_SRC_CLASS,
- check_get_range, (base_src), FALSE);
+ return res;
}
-
static GInputStream *
gst_gio_src_get_stream (GstGioBaseSrc * bsrc)
{
PROP_STREAM
};
-GST_BOILERPLATE (GstGioStreamSink, gst_gio_stream_sink, GstGioBaseSink,
- GST_TYPE_GIO_BASE_SINK);
+#define gst_gio_stream_sink_parent_class parent_class
+G_DEFINE_TYPE (GstGioStreamSink, gst_gio_stream_sink, GST_TYPE_GIO_BASE_SINK);
static void gst_gio_stream_sink_finalize (GObject * object);
static void gst_gio_stream_sink_set_property (GObject * object, guint prop_id,
static GOutputStream *gst_gio_stream_sink_get_stream (GstGioBaseSink * bsink);
static void
-gst_gio_stream_sink_base_init (gpointer gclass)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
-
- GST_DEBUG_CATEGORY_INIT (gst_gio_stream_sink_debug, "gio_stream_sink", 0,
- "GIO stream sink");
-
- gst_element_class_set_details_simple (element_class, "GIO stream sink",
- "Sink",
- "Write to any GIO stream",
- "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
-}
-
-static void
gst_gio_stream_sink_class_init (GstGioStreamSinkClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
+ GstElementClass *gstelement_class = (GstElementClass *) klass;
GstGioBaseSinkClass *ggbsink_class = (GstGioBaseSinkClass *) klass;
+ GST_DEBUG_CATEGORY_INIT (gst_gio_stream_sink_debug, "gio_stream_sink", 0,
+ "GIO stream sink");
+
gobject_class->finalize = gst_gio_stream_sink_finalize;
gobject_class->set_property = gst_gio_stream_sink_set_property;
gobject_class->get_property = gst_gio_stream_sink_get_property;
g_param_spec_object ("stream", "Stream", "Stream to write to",
G_TYPE_OUTPUT_STREAM, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ gst_element_class_set_details_simple (gstelement_class, "GIO stream sink",
+ "Sink",
+ "Write to any GIO stream",
+ "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+
ggbsink_class->get_stream =
GST_DEBUG_FUNCPTR (gst_gio_stream_sink_get_stream);
}
static void
-gst_gio_stream_sink_init (GstGioStreamSink * sink,
- GstGioStreamSinkClass * gclass)
+gst_gio_stream_sink_init (GstGioStreamSink * sink)
{
}
PROP_STREAM
};
-GST_BOILERPLATE (GstGioStreamSrc, gst_gio_stream_src, GstGioBaseSrc,
- GST_TYPE_GIO_BASE_SRC);
+#define gst_gio_stream_src_parent_class parent_class
+G_DEFINE_TYPE (GstGioStreamSrc, gst_gio_stream_src, GST_TYPE_GIO_BASE_SRC);
static void gst_gio_stream_src_finalize (GObject * object);
static void gst_gio_stream_src_set_property (GObject * object, guint prop_id,
static GInputStream *gst_gio_stream_src_get_stream (GstGioBaseSrc * bsrc);
static void
-gst_gio_stream_src_base_init (gpointer gclass)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
-
- GST_DEBUG_CATEGORY_INIT (gst_gio_stream_src_debug, "gio_stream_src", 0,
- "GIO source");
-
- gst_element_class_set_details_simple (element_class, "GIO stream source",
- "Source",
- "Read from any GIO stream",
- "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
-}
-
-static void
gst_gio_stream_src_class_init (GstGioStreamSrcClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
+ GstElementClass *gstelement_class = (GstElementClass *) klass;
GstGioBaseSrcClass *gstgiobasesrc_class = (GstGioBaseSrcClass *) klass;
+ GST_DEBUG_CATEGORY_INIT (gst_gio_stream_src_debug, "gio_stream_src", 0,
+ "GIO source");
+
gobject_class->finalize = gst_gio_stream_src_finalize;
gobject_class->set_property = gst_gio_stream_src_set_property;
gobject_class->get_property = gst_gio_stream_src_get_property;
g_param_spec_object ("stream", "Stream", "Stream to read from",
G_TYPE_INPUT_STREAM, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ gst_element_class_set_details_simple (gstelement_class, "GIO stream source",
+ "Source",
+ "Read from any GIO stream",
+ "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+
gstgiobasesrc_class->get_stream =
GST_DEBUG_FUNCPTR (gst_gio_stream_src_get_stream);
}
static void
-gst_gio_stream_src_init (GstGioStreamSrc * src, GstGioStreamSrcClass * gclass)
+gst_gio_stream_src_init (GstGioStreamSrc * src)
{
}
"Gnome VFS sink element");
}
-GST_BOILERPLATE_FULL (GstGnomeVFSSink, gst_gnome_vfs_sink, GstBaseSink,
- GST_TYPE_BASE_SINK, gst_gnome_vfs_sink_do_init);
-
-static void
-gst_gnome_vfs_sink_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 (&sinktemplate));
-
- gst_element_class_set_details_simple (element_class,
- "GnomeVFS Sink", "Sink/File",
- "Write a stream to a GnomeVFS URI", "Bastien Nocera <hadess@hadess.net>");
-}
+#define gst_gnome_vfs_sink_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstGnomeVFSSink, gst_gnome_vfs_sink,
+ GST_TYPE_BASE_SINK, gst_gnome_vfs_sink_do_init (g_define_type_id));
static gboolean
_gst_boolean_allow_overwrite_accumulator (GSignalInvocationHint * ihint,
gst_gnome_vfs_sink_class_init (GstGnomeVFSSinkClass * klass)
{
GstBaseSinkClass *basesink_class;
+ GstElementClass *gstelement_class;
GObjectClass *gobject_class;
gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
basesink_class = (GstBaseSinkClass *) klass;
gobject_class->set_property = gst_gnome_vfs_sink_set_property;
_gst_boolean_allow_overwrite_accumulator, NULL,
gst_marshal_BOOLEAN__POINTER, G_TYPE_BOOLEAN, 1, GST_TYPE_GNOME_VFS_URI);
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&sinktemplate));
+
+ gst_element_class_set_details_simple (gstelement_class,
+ "GnomeVFS Sink", "Sink/File",
+ "Write a stream to a GnomeVFS URI", "Bastien Nocera <hadess@hadess.net>");
+
basesink_class->stop = GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_stop);
basesink_class->start = GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_start);
basesink_class->event = GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_handle_event);
}
static void
-gst_gnome_vfs_sink_init (GstGnomeVFSSink * sink, GstGnomeVFSSinkClass * klass)
+gst_gnome_vfs_sink_init (GstGnomeVFSSink * sink)
{
gst_pad_set_query_function (GST_BASE_SINK_PAD (sink),
GST_DEBUG_FUNCPTR (gst_gnome_vfs_sink_query));
GST_DEBUG_OBJECT (sink, "processing %s event", GST_EVENT_TYPE_NAME (event));
switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_NEWSEGMENT:{
+ case GST_EVENT_SEGMENT:{
GnomeVFSResult res;
- GstFormat format;
- gint64 offset;
+ const GstSegment *segment;
- gst_event_parse_new_segment (event, NULL, NULL, &format, &offset,
- NULL, NULL);
+ gst_event_parse_segment (event, &segment);
- if (format != GST_FORMAT_BYTES) {
+ if (segment->format != GST_FORMAT_BYTES) {
GST_WARNING_OBJECT (sink, "ignored NEWSEGMENT event in %s format",
- gst_format_get_name (format));
+ gst_format_get_name (segment->format));
break;
}
- GST_LOG_OBJECT (sink, "seeking to offset %" G_GINT64_FORMAT, offset);
- res = gnome_vfs_seek (sink->handle, GNOME_VFS_SEEK_START, offset);
+ GST_LOG_OBJECT (sink, "seeking to offset %" G_GINT64_FORMAT,
+ segment->start);
+ res = gnome_vfs_seek (sink->handle, GNOME_VFS_SEEK_START, segment->start);
if (res != GNOME_VFS_OK) {
GST_ERROR_OBJECT (sink, "Failed to seek to offset %"
- G_GINT64_FORMAT ": %s", offset, gnome_vfs_result_to_string (res));
+ G_GINT64_FORMAT ": %s", segment->start,
+ gnome_vfs_result_to_string (res));
ret = FALSE;
} else {
- sink->current_pos = offset;
+ sink->current_pos = segment->start;
}
break;
GstGnomeVFSSink *sink;
GnomeVFSResult result;
GstFlowReturn ret;
+ guint8 *data;
+ gsize size;
sink = GST_GNOME_VFS_SINK (basesink);
sink->current_pos = cur_pos;
}
- result = gnome_vfs_write (sink->handle, GST_BUFFER_DATA (buf),
- GST_BUFFER_SIZE (buf), &written);
+ data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
+ result = gnome_vfs_write (sink->handle, data, size, &written);
+ gst_buffer_unmap (buf, data, size);
switch (result) {
case GNOME_VFS_OK:{
GST_DEBUG_OBJECT (sink, "wrote %" G_GINT64_FORMAT " bytes at %"
G_GINT64_FORMAT, (gint64) written, (gint64) cur_pos);
- if (written < GST_BUFFER_SIZE (buf)) {
+ if (written < size) {
/* FIXME: what to do here? (tpm) */
- g_warning ("%s: %d bytes should be written, only %"
- G_GUINT64_FORMAT " bytes written", G_STRLOC,
- GST_BUFFER_SIZE (buf), written);
+ g_warning ("%s: %" G_GSIZE_FORMAT " bytes should be written, only %"
+ G_GUINT64_FORMAT " bytes written", G_STRLOC, size, written);
}
- sink->current_pos += GST_BUFFER_SIZE (buf);
+ sink->current_pos += size;
ret = GST_FLOW_OK;
break;
}
/* TODO: emit signal/send msg on out-of-diskspace and
* handle this gracefully (see open bug) (tpm) */
GST_ELEMENT_ERROR (sink, RESOURCE, NO_SPACE_LEFT, (NULL),
- ("bufsize=%u, written=%u", GST_BUFFER_SIZE (buf), (guint) written));
+ ("bufsize=%u, written=%u", size, (guint) written));
ret = GST_FLOW_ERROR;
break;
}
GST_ELEMENT_ERROR (sink, RESOURCE, WRITE,
(_("Error while writing to file \"%s\"."), filename),
("%s, bufsize=%u, written=%u", gnome_vfs_result_to_string (result),
- GST_BUFFER_SIZE (buf), (guint) written));
+ size, (guint) written));
g_free (filename);
ret = GST_FLOW_ERROR;
ARG_IRADIO_TITLE
};
-static void gst_gnome_vfs_src_base_init (gpointer g_class);
-static void gst_gnome_vfs_src_class_init (GstGnomeVFSSrcClass * klass);
-static void gst_gnome_vfs_src_init (GstGnomeVFSSrc * gnomevfssrc);
static void gst_gnome_vfs_src_finalize (GObject * object);
static void gst_gnome_vfs_src_uri_handler_init (gpointer g_iface,
gpointer iface_data);
static gboolean gst_gnome_vfs_src_stop (GstBaseSrc * src);
static gboolean gst_gnome_vfs_src_start (GstBaseSrc * src);
static gboolean gst_gnome_vfs_src_is_seekable (GstBaseSrc * src);
-static gboolean gst_gnome_vfs_src_check_get_range (GstBaseSrc * src);
static gboolean gst_gnome_vfs_src_unlock (GstBaseSrc * basesrc);
static gboolean gst_gnome_vfs_src_unlock_stop (GstBaseSrc * basesrc);
static gboolean gst_gnome_vfs_src_get_size (GstBaseSrc * src, guint64 * size);
guint64 offset, guint size, GstBuffer ** buffer);
static gboolean gst_gnome_vfs_src_query (GstBaseSrc * src, GstQuery * query);
-static GstElementClass *parent_class = NULL;
-
-GType
-gst_gnome_vfs_src_get_type (void)
-{
- static GType gnomevfssrc_type = 0;
-
- if (!gnomevfssrc_type) {
- static const GTypeInfo gnomevfssrc_info = {
- sizeof (GstGnomeVFSSrcClass),
- gst_gnome_vfs_src_base_init,
- NULL,
- (GClassInitFunc) gst_gnome_vfs_src_class_init,
- NULL,
- NULL,
- sizeof (GstGnomeVFSSrc),
- 0,
- (GInstanceInitFunc) gst_gnome_vfs_src_init,
- };
- static const GInterfaceInfo urihandler_info = {
- gst_gnome_vfs_src_uri_handler_init,
- NULL,
- NULL
- };
-
- gnomevfssrc_type =
- g_type_register_static (GST_TYPE_BASE_SRC,
- "GstGnomeVFSSrc", &gnomevfssrc_info, 0);
- g_type_add_interface_static (gnomevfssrc_type, GST_TYPE_URI_HANDLER,
- &urihandler_info);
- }
- return gnomevfssrc_type;
-}
-
-static void
-gst_gnome_vfs_src_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 (&srctemplate));
- gst_element_class_set_details_simple (element_class,
- "GnomeVFS Source", "Source/File",
- "Read from any GnomeVFS-supported file",
- "Bastien Nocera <hadess@hadess.net>, "
- "GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>");
-
- GST_DEBUG_CATEGORY_INIT (gnomevfssrc_debug, "gnomevfssrc", 0,
- "Gnome-VFS Source");
-}
+#define gst_gnome_vfs_src_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstGnomeVFSSrc, gst_gnome_vfs_src, GST_TYPE_BASE_SRC,
+ G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER,
+ gst_gnome_vfs_src_uri_handler_init));
static void
gst_gnome_vfs_src_class_init (GstGnomeVFSSrcClass * klass)
{
GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
GstBaseSrcClass *gstbasesrc_class;
gobject_class = G_OBJECT_CLASS (klass);
+ gstelement_class = GST_ELEMENT_CLASS (klass);
gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
- parent_class = g_type_class_peek_parent (klass);
+ GST_DEBUG_CATEGORY_INIT (gnomevfssrc_debug, "gnomevfssrc", 0,
+ "Gnome-VFS Source");
gobject_class->finalize = gst_gnome_vfs_src_finalize;
gobject_class->set_property = gst_gnome_vfs_src_set_property;
"Name of currently playing song", NULL,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&srctemplate));
+ gst_element_class_set_details_simple (gstelement_class,
+ "GnomeVFS Source", "Source/File",
+ "Read from any GnomeVFS-supported file",
+ "Bastien Nocera <hadess@hadess.net>, "
+ "GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>");
+
gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_gnome_vfs_src_start);
gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_gnome_vfs_src_stop);
gstbasesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_gnome_vfs_src_unlock);
gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_gnome_vfs_src_get_size);
gstbasesrc_class->is_seekable =
GST_DEBUG_FUNCPTR (gst_gnome_vfs_src_is_seekable);
- gstbasesrc_class->check_get_range =
- GST_DEBUG_FUNCPTR (gst_gnome_vfs_src_check_get_range);
gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_gnome_vfs_src_create);
gstbasesrc_class->query = GST_DEBUG_FUNCPTR (gst_gnome_vfs_src_query);
}
GnomeVFSResult res;
GstBuffer *buf;
GnomeVFSFileSize readbytes;
- guint8 *data;
- guint todo;
+ guint8 *data, *ptr;
+ gsize todo;
GstGnomeVFSSrc *src;
gboolean interrupted = FALSE;
}
}
- buf = gst_buffer_try_new_and_alloc (size);
+ buf = gst_buffer_new_and_alloc (size);
if (G_UNLIKELY (buf == NULL)) {
GST_ERROR_OBJECT (src, "Failed to allocate %u bytes", size);
return GST_FLOW_ERROR;
}
- data = GST_BUFFER_DATA (buf);
+ data = gst_buffer_map (buf, NULL, NULL, GST_MAP_WRITE);
+ ptr = data;
todo = size;
while (!src->interrupted && todo > 0) {
/* this can return less that we ask for */
/* Just take what we've so far gotten and return */
size = size - todo;
- GST_BUFFER_SIZE (buf) = size;
todo = 0;
interrupted = TRUE;
break;
goto read_failed;
if (readbytes < todo) {
- data = &data[readbytes];
+ ptr += readbytes;
todo -= readbytes;
} else {
todo = 0;
}
GST_LOG (" got size %" G_GUINT64_FORMAT, readbytes);
}
+ gst_buffer_unmap (buf, data, size);
if (interrupted)
goto interrupted;
}
read_failed:
{
+ gst_buffer_unmap (buf, data, size);
gst_buffer_unref (buf);
GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
("Failed to read data: %s", gnome_vfs_result_to_string (res)));
}
eos:
{
+ gst_buffer_unmap (buf, data, size);
gst_buffer_unref (buf);
GST_DEBUG_OBJECT (src, "Reading data gave EOS");
return GST_FLOW_UNEXPECTED;
}
static gboolean
-gst_gnome_vfs_src_query (GstBaseSrc * basesrc, GstQuery * query)
-{
- gboolean ret = FALSE;
- GstGnomeVFSSrc *src = GST_GNOME_VFS_SRC (basesrc);
-
- switch (GST_QUERY_TYPE (query)) {
- case GST_QUERY_URI:
- gst_query_set_uri (query, src->uri_name);
- ret = TRUE;
- break;
- default:
- ret = FALSE;
- break;
- }
-
- if (!ret)
- ret = GST_BASE_SRC_CLASS (parent_class)->query (basesrc, query);
-
- return ret;
-}
-
-static gboolean
gst_gnome_vfs_src_is_seekable (GstBaseSrc * basesrc)
{
GstGnomeVFSSrc *src;
}
static gboolean
-gst_gnome_vfs_src_check_get_range (GstBaseSrc * basesrc)
+gst_gnome_vfs_src_scheduling (GstBaseSrc * basesrc, GstQuery * query)
{
GstGnomeVFSSrc *src;
const gchar *protocol;
+ gboolean pull_mode;
src = GST_GNOME_VFS_SRC (basesrc);
+ pull_mode = FALSE;
+
if (src->uri == NULL) {
GST_WARNING_OBJECT (src, "no URI set yet");
- return FALSE;
+ goto undecided;
}
if (gnome_vfs_uri_is_local (src->uri)) {
GST_LOG_OBJECT (src, "local URI (%s), assuming random access is possible",
GST_STR_NULL (src->uri_name));
- return TRUE;
- }
-
- /* blacklist certain protocols we know won't work getrange-based */
- protocol = gnome_vfs_uri_get_scheme (src->uri);
- if (protocol == NULL)
+ pull_mode = TRUE;
+ } else {
+ /* blacklist certain protocols we know won't work getrange-based */
+ protocol = gnome_vfs_uri_get_scheme (src->uri);
+ if (protocol == NULL)
+ goto undecided;
+
+ if (strcmp (protocol, "http") == 0 || strcmp (protocol, "https") == 0) {
+ GST_LOG_OBJECT (src,
+ "blacklisted protocol '%s', no random access possible" " (URI=%s)",
+ protocol, GST_STR_NULL (src->uri_name));
+ } else {
+ GST_LOG_OBJECT (src, "undecided about URI '%s', let base class handle it",
+ GST_STR_NULL (src->uri_name));
+ }
goto undecided;
-
- if (strcmp (protocol, "http") == 0 || strcmp (protocol, "https") == 0) {
- GST_LOG_OBJECT (src, "blacklisted protocol '%s', no random access possible"
- " (URI=%s)", protocol, GST_STR_NULL (src->uri_name));
- return FALSE;
}
+ gst_query_set_scheduling (query, pull_mode, pull_mode, FALSE, 1, -1, 1);
- /* fall through to undecided */
+ return TRUE;
+ /* fall through to undecided */
undecided:
{
/* don't know what to do, let the basesrc class decide for us */
- GST_LOG_OBJECT (src, "undecided about URI '%s', let base class handle it",
- GST_STR_NULL (src->uri_name));
+ return GST_BASE_SRC_CLASS (parent_class)->query (basesrc, query);
+ }
+}
- if (GST_BASE_SRC_CLASS (parent_class)->check_get_range)
- return GST_BASE_SRC_CLASS (parent_class)->check_get_range (basesrc);
+static gboolean
+gst_gnome_vfs_src_query (GstBaseSrc * basesrc, GstQuery * query)
+{
+ gboolean ret = FALSE;
+ GstGnomeVFSSrc *src = GST_GNOME_VFS_SRC (basesrc);
- return FALSE;
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_URI:
+ gst_query_set_uri (query, src->uri_name);
+ ret = TRUE;
+ break;
+ case GST_QUERY_SCHEDULING:
+ ret = gst_gnome_vfs_src_scheduling (basesrc, query);
+ break;
+ default:
+ ret = GST_BASE_SRC_CLASS (parent_class)->query (basesrc, query);
+ break;
}
+
+ return ret;
}
/* Interrupt a blocking request. */
gint height;
GstClockTime duration;
guint outsize;
+ GstBufferPool *pool;
/* samples per frame based on caps */
guint spf;
static void gst_visual_class_init (gpointer g_class, gpointer class_data);
static void gst_visual_init (GstVisual * visual);
-static void gst_visual_dispose (GObject * object);
+static void gst_visual_finalize (GObject * object);
static GstStateChangeReturn gst_visual_change_state (GstElement * element,
GstStateChange transition);
static gboolean gst_visual_src_query (GstPad * pad, GstQuery * query);
static gboolean gst_visual_sink_setcaps (GstPad * pad, GstCaps * caps);
-static gboolean gst_visual_src_setcaps (GstPad * pad, GstCaps * caps);
-static GstCaps *gst_visual_getcaps (GstPad * pad);
+static GstCaps *gst_visual_getcaps (GstPad * pad, GstCaps * filter);
static void libvisual_log_handler (const char *message, const char *funcname,
void *priv);
gst_static_pad_template_get (&src_template));
gst_element_class_add_pad_template (element,
gst_static_pad_template_get (&sink_template));
+
gst_element_class_set_details_simple (element,
longname, "Visualization",
klass->plugin->info->about, "Benjamin Otte <otte@gnome.org>");
g_free (longname);
}
- object->dispose = gst_visual_dispose;
+ object->finalize = gst_visual_finalize;
}
static void
{
/* create the sink and src pads */
visual->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
- gst_pad_set_setcaps_function (visual->sinkpad, gst_visual_sink_setcaps);
gst_pad_set_chain_function (visual->sinkpad, gst_visual_chain);
gst_pad_set_event_function (visual->sinkpad, gst_visual_sink_event);
gst_element_add_pad (GST_ELEMENT (visual), visual->sinkpad);
visual->srcpad = gst_pad_new_from_static_template (&src_template, "src");
- gst_pad_set_setcaps_function (visual->srcpad, gst_visual_src_setcaps);
gst_pad_set_getcaps_function (visual->srcpad, gst_visual_getcaps);
gst_pad_set_event_function (visual->srcpad, gst_visual_src_event);
gst_pad_set_query_function (visual->srcpad, gst_visual_src_query);
}
static void
-gst_visual_dispose (GObject * object)
+gst_visual_finalize (GObject * object)
{
GstVisual *visual = GST_VISUAL (object);
- if (visual->adapter) {
- g_object_unref (visual->adapter);
- visual->adapter = NULL;
- }
+ g_object_unref (visual->adapter);
+ if (visual->pool)
+ gst_object_unref (visual->pool);
gst_visual_clear_actors (visual);
- GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
+ GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
}
static void
}
static GstCaps *
-gst_visual_getcaps (GstPad * pad)
+gst_visual_getcaps (GstPad * pad, GstCaps * filter)
{
GstCaps *ret;
GstVisual *visual = GST_VISUAL (gst_pad_get_parent (pad));
int depths;
if (!visual->actor) {
- ret = gst_caps_copy (gst_pad_get_pad_template_caps (visual->srcpad));
+ ret = gst_pad_get_pad_template_caps (visual->srcpad);
goto beach;
}
beach:
+ if (filter) {
+ GstCaps *intersection;
+
+ intersection =
+ gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST);
+ gst_caps_unref (ret);
+ ret = intersection;
+ }
+
GST_DEBUG_OBJECT (visual, "returning caps %" GST_PTR_FORMAT, ret);
gst_object_unref (visual);
return ret;
}
static gboolean
-gst_visual_src_setcaps (GstPad * pad, GstCaps * caps)
+gst_visual_src_setcaps (GstVisual * visual, GstCaps * caps)
{
- GstVisual *visual = GST_VISUAL (gst_pad_get_parent (pad));
GstStructure *structure;
gint depth, pitch;
visual->duration =
gst_util_uint64_scale_int (GST_SECOND, visual->fps_d, visual->fps_n);
- gst_object_unref (visual);
+ gst_pad_push_event (visual->srcpad, gst_event_new_caps (caps));
+
return TRUE;
/* ERRORS */
error:
{
GST_DEBUG_OBJECT (visual, "error parsing caps");
- gst_object_unref (visual);
return FALSE;
}
}
GstCaps *othercaps, *target;
GstStructure *structure;
GstCaps *caps;
+ GstQuery *query;
+ GstBufferPool *pool = NULL;
+ guint size, min, max, prefix, alignment;
- caps = gst_pad_get_caps (visual->srcpad);
+ caps = gst_pad_get_caps (visual->srcpad, NULL);
/* see what the peer can do */
- othercaps = gst_pad_peer_get_caps (visual->srcpad);
+ othercaps = gst_pad_peer_get_caps (visual->srcpad, caps);
if (othercaps) {
- target = gst_caps_intersect (othercaps, caps);
- gst_caps_unref (othercaps);
+ target = othercaps;
gst_caps_unref (caps);
if (gst_caps_is_empty (target))
goto no_format;
+ target = gst_caps_make_writable (target);
gst_caps_truncate (target);
} else {
/* need a copy, we'll be modifying it when fixating */
gst_structure_fixate_field_nearest_fraction (structure, "framerate",
DEFAULT_FPS_N, DEFAULT_FPS_D);
- gst_pad_set_caps (visual->srcpad, target);
+ gst_visual_src_setcaps (visual, target);
+
+ /* 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 (visual->srcpad, query)) {
+ /* we got configuration from our peer, parse them */
+ gst_query_parse_allocation_params (query, &size, &min, &max, &prefix,
+ &alignment, &pool);
+ } else {
+ size = visual->outsize;
+ min = max = 0;
+ prefix = 0;
+ alignment = 1;
+ }
+
+ 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, 0,
+ alignment);
+ gst_buffer_pool_set_config (pool, config);
+ }
+
+ if (visual->pool)
+ gst_object_unref (visual->pool);
+ visual->pool = pool;
+
+ /* and activate */
+ gst_buffer_pool_set_active (pool, TRUE);
+
gst_caps_unref (target);
return TRUE;
gst_visual_reset (visual);
res = gst_pad_push_event (visual->srcpad, event);
break;
- case GST_EVENT_NEWSEGMENT:
+ case GST_EVENT_CAPS:
{
- GstFormat format;
- gdouble rate, arate;
- gint64 start, stop, time;
- gboolean update;
+ GstCaps *caps;
+ gst_event_parse_caps (event, &caps);
+ res = gst_visual_sink_setcaps (pad, caps);
+ break;
+ }
+ case GST_EVENT_SEGMENT:
+ {
/* the newsegment values are used to clip the input samples
* and to convert the incomming timestamps to running time so
* we can do QoS */
- gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
- &start, &stop, &time);
-
- /* now configure the values */
- gst_segment_set_newsegment_full (&visual->segment, update,
- rate, arate, format, start, stop, time);
+ gst_event_copy_segment (event, &visual->segment);
/* and forward */
res = gst_pad_push_event (visual->srcpad, event);
break;
}
default:
- res = gst_pad_push_event (visual->srcpad, event);
+ res = gst_pad_event_default (pad, event);
break;
}
GstClockTimeDiff diff;
GstClockTime timestamp;
- gst_event_parse_qos (event, &proportion, &diff, ×tamp);
+ gst_event_parse_qos (event, NULL, &proportion, &diff, ×tamp);
/* save stuff for the _chain function */
GST_OBJECT_LOCK (visual);
res = gst_pad_push_event (visual->sinkpad, event);
break;
}
+ case GST_EVENT_RECONFIGURE:
+ /* dont't forward */
+ gst_event_unref (event);
+ res = TRUE;
+ break;
default:
- res = gst_pad_push_event (visual->sinkpad, event);
+ res = gst_pad_event_default (pad, event);
break;
}
* function will negotiate one. After calling this function, a
* reverse negotiation could have happened. */
static GstFlowReturn
-get_buffer (GstVisual * visual, GstBuffer ** outbuf)
+ensure_negotiated (GstVisual * visual)
{
- GstFlowReturn ret;
+ gboolean reconfigure;
+
+ GST_OBJECT_LOCK (visual->srcpad);
+ reconfigure = GST_PAD_NEEDS_RECONFIGURE (visual->srcpad);
+ GST_OBJECT_FLAG_UNSET (visual->srcpad, GST_PAD_NEED_RECONFIGURE);
+ GST_OBJECT_UNLOCK (visual->srcpad);
/* we don't know an output format yet, pick one */
- if (GST_PAD_CAPS (visual->srcpad) == NULL) {
+ if (reconfigure || !gst_pad_has_current_caps (visual->srcpad)) {
if (!gst_vis_src_negotiate (visual))
return GST_FLOW_NOT_NEGOTIATED;
}
-
- GST_DEBUG_OBJECT (visual, "allocating output buffer with caps %"
- GST_PTR_FORMAT, GST_PAD_CAPS (visual->srcpad));
-
- /* now allocate a buffer with the last negotiated format.
- * Downstream could renegotiate a new format, which will trigger
- * our setcaps function on the source pad. */
- ret =
- gst_pad_alloc_buffer_and_set_caps (visual->srcpad,
- GST_BUFFER_OFFSET_NONE, visual->outsize,
- GST_PAD_CAPS (visual->srcpad), outbuf);
-
- /* no buffer allocated, we don't care why. */
- if (ret != GST_FLOW_OK)
- return ret;
-
return GST_FLOW_OK;
}
GST_DEBUG_OBJECT (visual, "chain function called");
- /* If we don't have an output format yet, preallocate a buffer to try and
- * set one */
- if (GST_PAD_CAPS (visual->srcpad) == NULL) {
- ret = get_buffer (visual, &outbuf);
- if (ret != GST_FLOW_OK) {
- gst_buffer_unref (buffer);
- goto beach;
- }
+ /* Make sure have an output format */
+ ret = ensure_negotiated (visual);
+ if (ret != GST_FLOW_OK) {
+ gst_buffer_unref (buffer);
+ goto beach;
}
/* resync on DISCONT */
GST_DEBUG_OBJECT (visual,
"Input buffer has %d samples, time=%" G_GUINT64_FORMAT,
- GST_BUFFER_SIZE (buffer) / visual->bps, GST_BUFFER_TIMESTAMP (buffer));
+ gst_buffer_get_size (buffer) / visual->bps,
+ GST_BUFFER_TIMESTAMP (buffer));
gst_adapter_push (visual->adapter, buffer);
gboolean need_skip;
const guint16 *data;
guint64 dist, timestamp;
+ guint8 *outdata;
+ gsize outsize;
GST_DEBUG_OBJECT (visual, "processing buffer");
/* Read VISUAL_SAMPLES samples per channel */
data =
- (const guint16 *) gst_adapter_peek (visual->adapter,
+ (const guint16 *) gst_adapter_map (visual->adapter,
VISUAL_SAMPLES * visual->bps);
#if defined(VISUAL_API_VERSION) && VISUAL_API_VERSION >= 4000 && VISUAL_API_VERSION < 5000
/* alloc a buffer if we don't have one yet, this happens
* when we pushed a buffer in this while loop before */
if (outbuf == NULL) {
- ret = get_buffer (visual, &outbuf);
+ GST_DEBUG_OBJECT (visual, "allocating output buffer");
+ ret = gst_buffer_pool_acquire_buffer (visual->pool, &outbuf, NULL);
if (ret != GST_FLOW_OK) {
+ gst_adapter_unmap (visual->adapter, 0);
goto beach;
}
}
- visual_video_set_buffer (visual->video, GST_BUFFER_DATA (outbuf));
+ outdata = gst_buffer_map (outbuf, &outsize, NULL, GST_MAP_WRITE);
+ visual_video_set_buffer (visual->video, outdata);
visual_audio_analyze (visual->audio);
visual_actor_run (visual->actor, visual->audio);
visual_video_set_buffer (visual->video, NULL);
+ gst_buffer_unmap (outbuf, outdata, outsize);
GST_DEBUG_OBJECT (visual, "rendered one frame");
+ gst_adapter_unmap (visual->adapter, 0);
+
GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
GST_BUFFER_DURATION (outbuf) = visual->duration;
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
+ if (visual->pool) {
+ gst_buffer_pool_set_active (visual->pool, FALSE);
+ gst_object_unref (visual->pool);
+ visual->pool = NULL;
+ }
break;
case GST_STATE_CHANGE_READY_TO_NULL:
gst_visual_clear_actors (visual);
GstStructure *structure;
const GValue *codec_data;
GstBuffer *buffer;
- guint8 *data;
- guint size;
+ guint8 *data, *ptr;
+ gsize size, left;
guint32 sizes[3];
GstCaps *outcaps;
gint i, offs;
/* first 22 bytes are bits_per_sample, channel_mask, GUID
* Then we get 3 LE guint32 with the 3 header sizes
* then we get the bytes of the 3 headers. */
- data = GST_BUFFER_DATA (buffer);
- size = GST_BUFFER_SIZE (buffer);
+ data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
+
+ ptr = data;
+ left = size;
- GST_LOG_OBJECT (ogg, "configuring codec_data of size %u", size);
+ GST_LOG_OBJECT (ogg, "configuring codec_data of size %u", left);
/* skip headers */
- data += 22;
- size -= 22;
+ ptr += 22;
+ left -= 22;
/* we need at least 12 bytes for the packet sizes of the 3 headers */
- if (size < 12)
+ if (left < 12)
goto buffer_too_small;
/* read sizes of the 3 headers */
- sizes[0] = GST_READ_UINT32_LE (data);
- sizes[1] = GST_READ_UINT32_LE (data + 4);
- sizes[2] = GST_READ_UINT32_LE (data + 8);
+ sizes[0] = GST_READ_UINT32_LE (ptr);
+ sizes[1] = GST_READ_UINT32_LE (ptr + 4);
+ sizes[2] = GST_READ_UINT32_LE (ptr + 8);
GST_DEBUG_OBJECT (ogg, "header sizes: %u %u %u", sizes[0], sizes[1],
sizes[2]);
- size -= 12;
+ left -= 12;
/* and we need at least enough data for all the headers */
- if (size < sizes[0] + sizes[1] + sizes[2])
+ if (left < sizes[0] + sizes[1] + sizes[2])
goto buffer_too_small;
/* set caps */
GstBuffer *out;
/* now output the raw vorbis header packets */
- out = gst_buffer_create_sub (buffer, offs, sizes[i]);
- gst_buffer_set_caps (out, outcaps);
+ out = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, offs, sizes[i]);
gst_pad_push (ogg->srcpad, out);
offs += sizes[i];
}
+ gst_buffer_unmap (buffer, data, size);
gst_caps_unref (outcaps);
return TRUE;
buffer_too_small:
{
GST_DEBUG_OBJECT (ogg, "codec_data is too small");
+ gst_buffer_unmap (buffer, data, size);
return FALSE;
}
}
/* allocate space for header and body */
buffer = gst_buffer_new_and_alloc (packet->bytes);
- memcpy (GST_BUFFER_DATA (buffer), packet->packet, packet->bytes);
+ gst_buffer_fill (buffer, 0, packet->packet, packet->bytes);
GST_LOG_OBJECT (ogg, "created buffer %p from page", buffer);
{
GstFlowReturn result = GST_FLOW_OK;
GstOggAviParse *ogg;
- guint8 *data;
guint size;
gchar *oggbuf;
gint ret = -1;
ogg = GST_OGG_AVI_PARSE (GST_OBJECT_PARENT (pad));
- data = GST_BUFFER_DATA (buffer);
- size = GST_BUFFER_SIZE (buffer);
+ size = gst_buffer_get_size (buffer);
GST_LOG_OBJECT (ogg, "Chain function received buffer of size %d", size);
/* write data to sync layer */
oggbuf = ogg_sync_buffer (&ogg->sync, size);
- memcpy (oggbuf, data, size);
+ gst_buffer_extract (buffer, 0, oggbuf, size);
ogg_sync_wrote (&ogg->sync, size);
gst_buffer_unref (buffer);
static const GstQueryType *gst_ogg_pad_query_types (GstPad * pad);
static gboolean gst_ogg_pad_src_query (GstPad * pad, GstQuery * query);
static gboolean gst_ogg_pad_event (GstPad * pad, GstEvent * event);
-static GstCaps *gst_ogg_pad_getcaps (GstPad * pad);
static GstOggPad *gst_ogg_chain_get_stream (GstOggChain * chain,
glong serialno);
{
gst_pad_set_event_function (GST_PAD (pad),
GST_DEBUG_FUNCPTR (gst_ogg_pad_event));
- gst_pad_set_getcaps_function (GST_PAD (pad),
- GST_DEBUG_FUNCPTR (gst_ogg_pad_getcaps));
gst_pad_set_query_type_function (GST_PAD (pad),
GST_DEBUG_FUNCPTR (gst_ogg_pad_query_types));
gst_pad_set_query_function (GST_PAD (pad),
GST_DEBUG_FUNCPTR (gst_ogg_pad_src_query));
+ gst_pad_use_fixed_caps (GST_PAD (pad));
pad->mode = GST_OGG_PAD_MODE_INIT;
pad->start_time = GST_CLOCK_TIME_NONE;
- pad->last_stop = GST_CLOCK_TIME_NONE;
+ pad->position = GST_CLOCK_TIME_NONE;
pad->have_type = FALSE;
pad->continued = NULL;
return query_types;
}
-static GstCaps *
-gst_ogg_pad_getcaps (GstPad * pad)
-{
- return gst_caps_ref (GST_PAD_CAPS (pad));
-}
-
static gboolean
gst_ogg_pad_src_query (GstPad * pad, GstQuery * query)
{
pad->continued = NULL;
pad->last_ret = GST_FLOW_OK;
- pad->last_stop = GST_CLOCK_TIME_NONE;
+ pad->position = GST_CLOCK_TIME_NONE;
pad->current_granule = -1;
pad->keyframe_granule = -1;
pad->is_eos = FALSE;
goto not_added;
buf = gst_buffer_new_and_alloc (packet->bytes - offset - trim);
- gst_buffer_set_caps (buf, GST_PAD_CAPS (pad));
/* set delta flag for OGM content */
if (delta_unit)
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
/* copy packet in buffer */
- memcpy (buf->data, packet->packet + offset, packet->bytes - offset - trim);
+ gst_buffer_fill (buf, 0, packet->packet + offset,
+ packet->bytes - offset - trim);
GST_BUFFER_TIMESTAMP (buf) = out_timestamp;
GST_BUFFER_DURATION (buf) = out_duration;
pad->discont = FALSE;
}
- pad->last_stop = ogg->segment.last_stop;
+ pad->position = ogg->segment.position;
/* don't push the header packets when we are asked to skip them */
if (!packet->b_o_s || push_headers) {
/* check if valid granulepos, then we can calculate the current
* position. We know the granule for each packet but we only want to update
- * the last_stop when we have a valid granulepos on the packet because else
+ * the position when we have a valid granulepos on the packet because else
* our time jumps around for the different streams. */
if (packet->granulepos < 0)
goto done;
}
/* and store as the current position */
- gst_segment_set_last_stop (&ogg->segment, GST_FORMAT_TIME, current_time);
+ ogg->segment.position = current_time;
GST_DEBUG_OBJECT (ogg, "ogg current time %" GST_TIME_FORMAT,
GST_TIME_ARGS (current_time));
if (start_time != G_MAXUINT64) {
gint64 segment_time;
+ GstSegment segment;
GST_DEBUG_OBJECT (ogg, "start_time: %" GST_TIME_FORMAT,
GST_TIME_ARGS (start_time));
segment_time = chain->begin_time;
/* create the newsegment event we are going to send out */
- event = gst_event_new_new_segment (FALSE, ogg->segment.rate,
- GST_FORMAT_TIME, start_time, chain->segment_stop, segment_time);
+ gst_segment_init (&segment, GST_FORMAT_TIME);
+ segment.rate = ogg->segment.rate;
+ segment.applied_rate = ogg->segment.applied_rate;
+ segment.start = start_time;
+ segment.stop = chain->segment_stop;
+ segment.time = segment_time;
+ event = gst_event_new_segment (&segment);
ogg->resync = FALSE;
}
/* see if we have enough info to activate the chain, we have enough info
* when all streams have a valid start time. */
if (gst_ogg_demux_collect_chain_info (ogg, chain)) {
+ GstSegment segment;
GST_DEBUG_OBJECT (ogg, "segment_start: %" GST_TIME_FORMAT,
GST_TIME_ARGS (chain->segment_start));
GST_TIME_ARGS (chain->begin_time));
/* create the newsegment event we are going to send out */
- event = gst_event_new_new_segment (FALSE, ogg->segment.rate,
- GST_FORMAT_TIME, chain->segment_start, chain->segment_stop,
- chain->begin_time);
+ gst_segment_init (&segment, GST_FORMAT_TIME);
+ segment.rate = ogg->segment.rate;
+ segment.applied_rate = ogg->segment.applied_rate;
+ segment.start = chain->segment_start;
+ segment.stop = chain->segment_stop;
+ segment.time = chain->begin_time;
+ event = gst_event_new_segment (&segment);
}
}
ret = g_object_new (GST_TYPE_OGG_PAD, NULL);
/* we own this one */
- gst_object_ref (ret);
- gst_object_sink (ret);
+ gst_object_ref_sink (ret);
GST_PAD_DIRECTION (ret) = GST_PAD_SRC;
gst_ogg_pad_mark_discont (ret);
static void gst_ogg_print (GstOggDemux * demux);
-GST_BOILERPLATE (GstOggDemux, gst_ogg_demux, GstElement, GST_TYPE_ELEMENT);
+#define gst_ogg_demux_parent_class parent_class
+G_DEFINE_TYPE (GstOggDemux, gst_ogg_demux, GST_TYPE_ELEMENT);
static void
-gst_ogg_demux_base_init (gpointer g_class)
+gst_ogg_demux_class_init (GstOggDemuxClass * klass)
{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+ GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
- gst_element_class_set_details_simple (element_class,
+ gst_element_class_set_details_simple (gstelement_class,
"Ogg demuxer", "Codec/Demuxer",
"demux ogg streams (info about ogg: http://xiph.org)",
"Wim Taymans <wim@fluendo.com>");
- gst_element_class_add_pad_template (element_class,
+ gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&ogg_demux_sink_template_factory));
- gst_element_class_add_pad_template (element_class,
+ gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&ogg_demux_src_template_factory));
-}
-
-static void
-gst_ogg_demux_class_init (GstOggDemuxClass * klass)
-{
- GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gstelement_class->change_state = gst_ogg_demux_change_state;
gstelement_class->send_event = gst_ogg_demux_receive_event;
}
static void
-gst_ogg_demux_init (GstOggDemux * ogg, GstOggDemuxClass * g_class)
+gst_ogg_demux_init (GstOggDemux * ogg)
{
/* create the sink pad */
ogg->sinkpad =
res = gst_ogg_demux_send_event (ogg, event);
gst_ogg_demux_reset_streams (ogg);
break;
- case GST_EVENT_NEWSEGMENT:
+ case GST_EVENT_SEGMENT:
GST_DEBUG_OBJECT (ogg, "got a new segment event");
gst_event_unref (event);
res = TRUE;
static GstFlowReturn
gst_ogg_demux_submit_buffer (GstOggDemux * ogg, GstBuffer * buffer)
{
- gint size;
+ gsize size;
guint8 *data;
gchar *oggbuffer;
GstFlowReturn ret = GST_FLOW_OK;
- size = GST_BUFFER_SIZE (buffer);
- data = GST_BUFFER_DATA (buffer);
+ data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
- GST_DEBUG_OBJECT (ogg, "submitting %u bytes", size);
+ GST_DEBUG_OBJECT (ogg, "submitting %" G_GSIZE_FORMAT " bytes", size);
if (G_UNLIKELY (size == 0))
goto done;
goto write_failed;
done:
+ gst_buffer_unmap (buffer, data, size);
gst_buffer_unref (buffer);
return ret;
if (ret != GST_FLOW_OK)
goto error;
- ogg->read_offset += GST_BUFFER_SIZE (buffer);
+ ogg->read_offset += gst_buffer_get_size (buffer);
ret = gst_ogg_demux_submit_buffer (ogg, buffer);
ogg_packet *op = headers->data;
g_assert (op);
buffer = gst_buffer_new_and_alloc (op->bytes);
- memcpy (GST_BUFFER_DATA (buffer), op->packet, op->bytes);
+ gst_buffer_fill (buffer, 0, op->packet, op->bytes);
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_IN_CAPS);
g_value_init (&value, GST_TYPE_BUFFER);
gst_value_take_buffer (&value, buffer);
gst_ogg_pad_mark_discont (pad);
pad->last_ret = GST_FLOW_OK;
- if (pad->map.is_skeleton || pad->added || GST_PAD_CAPS (pad) == NULL)
+ if (pad->map.is_skeleton || pad->added
+ || !gst_pad_has_current_caps (GST_PAD_CAST (pad)))
continue;
GST_DEBUG_OBJECT (ogg, "adding pad %" GST_PTR_FORMAT, pad);
gint i, pending, len;
gboolean first_parsed_page = TRUE;
- position = segment->last_stop;
+ position = segment->position;
/* first find the chain to search in */
total = ogg->total_time;
if (keyframe) {
if (segment->rate > 0.0)
segment->time = keytarget;
- segment->last_stop = keytarget - begintime;
+ segment->position = keytarget - begintime;
}
*rchain = chain;
* forever. */
GST_PAD_STREAM_LOCK (ogg->sinkpad);
- if (ogg->segment_running && !flush) {
- /* create the segment event to close the current segment */
- if ((chain = ogg->current_chain)) {
- GstEvent *newseg;
- gint64 chain_start = 0;
-
- if (chain->segment_start != GST_CLOCK_TIME_NONE)
- chain_start = chain->segment_start;
-
- newseg = gst_event_new_new_segment (TRUE, ogg->segment.rate,
- GST_FORMAT_TIME, ogg->segment.start + chain_start,
- ogg->segment.last_stop + chain_start, ogg->segment.time);
- /* set the seqnum of the running segment */
- gst_event_set_seqnum (newseg, ogg->seqnum);
-
- /* send segment on old chain, FIXME, must be sent from streaming thread. */
- gst_ogg_demux_send_event (ogg, newseg);
- }
- }
-
if (event) {
- gst_segment_set_seek (&ogg->segment, rate, format, flags,
+ gst_segment_do_seek (&ogg->segment, rate, format, flags,
cur_type, cur, stop_type, stop, &update);
}
GstEvent *event;
gint64 stop;
gint64 start;
- gint64 last_stop, begin_time;
+ gint64 position, begin_time;
+ GstSegment segment;
/* we have to send the flush to the old chain, not the new one */
if (flush) {
stop = MIN (stop, chain->segment_stop);
}
- last_stop = ogg->segment.last_stop;
+ position = ogg->segment.position;
if (chain->segment_start != GST_CLOCK_TIME_NONE)
- last_stop += chain->segment_start;
+ position += chain->segment_start;
- /* create the segment event we are going to send out */
- if (ogg->segment.rate >= 0.0)
- event = gst_event_new_new_segment (FALSE, ogg->segment.rate,
- ogg->segment.format, last_stop, stop, ogg->segment.time);
- else
- event = gst_event_new_new_segment (FALSE, ogg->segment.rate,
- ogg->segment.format, start, last_stop, ogg->segment.time);
+ gst_segment_copy_into (&ogg->segment, &segment);
+ /* create the segment event we are going to send out */
+ if (ogg->segment.rate >= 0.0) {
+ segment.start = position;
+ segment.stop = stop;
+ } else {
+ segment.start = start;
+ segment.stop = position;
+ }
+ event = gst_event_new_segment (&segment);
gst_event_set_seqnum (event, seqnum);
if (chain != ogg->current_chain) {
GstMessage *message;
message = gst_message_new_segment_start (GST_OBJECT (ogg),
- GST_FORMAT_TIME, ogg->segment.last_stop);
+ GST_FORMAT_TIME, ogg->segment.position);
gst_message_set_seqnum (message, seqnum);
gst_element_post_message (GST_ELEMENT (ogg), message);
}
- ogg->segment_running = TRUE;
ogg->seqnum = seqnum;
/* restart our task since it might have been stopped when we did the
* flush. */
ogg->total_time += chain->total_time;
}
- gst_segment_set_duration (&ogg->segment, GST_FORMAT_TIME, ogg->total_time);
+ ogg->segment.duration = ogg->total_time;
}
/* find all the chains in the ogg file, this reads the first and
if (chain) {
GstEvent *event;
gint64 start = 0;
+ GstSegment segment;
if (chain->segment_start != GST_CLOCK_TIME_NONE)
start = chain->segment_start;
/* create the newsegment event we are going to send out */
- event = gst_event_new_new_segment (FALSE, ogg->segment.rate,
- GST_FORMAT_TIME, start, chain->segment_stop, chain->begin_time);
+ gst_segment_copy_into (&ogg->segment, &segment);
+ segment.start = start;
+ segment.stop = chain->segment_stop;
+ segment.time = chain->begin_time;
+ event = gst_event_new_segment (&segment);
gst_event_set_seqnum (event, ogg->seqnum);
GST_DEBUG_OBJECT (ogg,
if (ogg->pullmode)
goto unknown_chain;
- current_time = ogg->segment.last_stop;
+ current_time = ogg->segment.position;
/* time of new chain is current time */
chain_time = current_time;
goto done;
}
- ogg->offset += GST_BUFFER_SIZE (buffer);
+ ogg->offset += gst_buffer_get_size (buffer);
if (G_UNLIKELY (ogg->newsegment)) {
gst_ogg_demux_send_event (ogg, ogg->newsegment);
guint i;
chain = ogg->current_chain;
- cur = ogg->segment.last_stop;
+ cur = ogg->segment.position;
if (chain == NULL || cur == -1)
return;
/* Theoretically, we should be doing this for all streams, but we're only
* doing it for known-to-be-sparse streams at the moment in order not to
* break things for wrongly-muxed streams (like we used to produce once) */
- if (stream->map.is_sparse && stream->last_stop != GST_CLOCK_TIME_NONE) {
+ if (stream->map.is_sparse && stream->position != GST_CLOCK_TIME_NONE) {
/* Does this stream lag? Random threshold of 2 seconds */
- if (GST_CLOCK_DIFF (stream->last_stop, cur) > (2 * GST_SECOND)) {
+ if (GST_CLOCK_DIFF (stream->position, cur) > (2 * GST_SECOND)) {
GST_DEBUG_OBJECT (stream, "synchronizing stream with others by "
"advancing time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
- GST_TIME_ARGS (stream->last_stop), GST_TIME_ARGS (cur));
- stream->last_stop = cur;
+ GST_TIME_ARGS (stream->position), GST_TIME_ARGS (cur));
+
+ stream->position = cur;
+
+#if 0
+ ogg->segment.base += cur - stream->position;
/* advance stream time (FIXME: is this right, esp. time_pos?) */
gst_pad_push_event (GST_PAD_CAST (stream),
gst_event_new_new_segment (TRUE, ogg->segment.rate,
- GST_FORMAT_TIME, stream->last_stop, -1, stream->last_stop));
+ ogg->segment.applied_rate,
+ GST_FORMAT_TIME, stream->position, -1, stream->position));
+#endif
}
}
}
GstEvent *event = NULL;
GST_LOG_OBJECT (ogg, "pausing task, reason %s", reason);
- ogg->segment_running = FALSE;
gst_pad_pause_task (ogg->sinkpad);
if (ret == GST_FLOW_UNEXPECTED) {
static gboolean
gst_ogg_demux_sink_activate (GstPad * sinkpad)
{
- if (gst_pad_check_pull_range (sinkpad)) {
- GST_DEBUG_OBJECT (sinkpad, "activating pull");
- return gst_pad_activate_pull (sinkpad, TRUE);
- } else {
+ GstQuery *query;
+ gboolean pull_mode;
+
+ query = gst_query_new_scheduling ();
+
+ if (!gst_pad_peer_query (sinkpad, query)) {
+ gst_query_unref (query);
+ goto activate_push;
+ }
+
+ gst_query_parse_scheduling (query, &pull_mode, NULL, NULL, NULL, NULL, NULL);
+
+ if (!pull_mode)
+ goto activate_push;
+
+ GST_DEBUG_OBJECT (sinkpad, "activating pull");
+ return gst_pad_activate_pull (sinkpad, TRUE);
+
+activate_push:
+ {
GST_DEBUG_OBJECT (sinkpad, "activating push");
return gst_pad_activate_push (sinkpad, TRUE);
}
ogg_sync_reset (&ogg->sync);
ogg->running = FALSE;
ogg->bitrate = 0;
- ogg->segment_running = FALSE;
ogg->total_time = -1;
gst_segment_init (&ogg->segment, GST_FORMAT_TIME);
break;
break;
}
- result = parent_class->change_state (element, transition);
+ result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
switch (transition) {
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
gst_ogg_demux_clear_chains (ogg);
GST_OBJECT_LOCK (ogg);
ogg->running = FALSE;
- ogg->segment_running = FALSE;
GST_OBJECT_UNLOCK (ogg);
break;
case GST_STATE_CHANGE_READY_TO_NULL:
gint64 first_granule; /* the granulepos of first page == first sample in next page */
GstClockTime first_time; /* the timestamp of the second page or granuletime of first page */
- GstClockTime last_stop; /* last_stop when last push occured; used to detect when we
+ GstClockTime position; /* position when last push occured; used to detect when we
* need to send a newsegment update event for sparse streams */
GList *continued;
/* playback start/stop positions */
GstSegment segment;
- gboolean segment_running;
guint32 seqnum;
GstEvent *event;
"subtitle/x-kate; application/x-kate")
);
-static void gst_ogg_mux_base_init (gpointer g_class);
-static void gst_ogg_mux_class_init (GstOggMuxClass * klass);
-static void gst_ogg_mux_init (GstOggMux * ogg_mux);
static void gst_ogg_mux_finalize (GObject * object);
static GstFlowReturn
gst_ogg_mux_collected (GstCollectPads * pads, GstOggMux * ogg_mux);
static gboolean gst_ogg_mux_handle_src_event (GstPad * pad, GstEvent * event);
static GstPad *gst_ogg_mux_request_new_pad (GstElement * element,
- GstPadTemplate * templ, const gchar * name);
+ GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
static void gst_ogg_mux_release_pad (GstElement * element, GstPad * pad);
static void gst_ogg_mux_set_property (GObject * object,
static GstStateChangeReturn gst_ogg_mux_change_state (GstElement * element,
GstStateChange transition);
-static GstElementClass *parent_class = NULL;
-
/*static guint gst_ogg_mux_signals[LAST_SIGNAL] = { 0 }; */
-
-GType
-gst_ogg_mux_get_type (void)
-{
- static GType ogg_mux_type = 0;
-
- if (G_UNLIKELY (ogg_mux_type == 0)) {
- static const GTypeInfo ogg_mux_info = {
- sizeof (GstOggMuxClass),
- gst_ogg_mux_base_init,
- NULL,
- (GClassInitFunc) gst_ogg_mux_class_init,
- NULL,
- NULL,
- sizeof (GstOggMux),
- 0,
- (GInstanceInitFunc) gst_ogg_mux_init,
- };
- static const GInterfaceInfo preset_info = {
- NULL,
- NULL,
- NULL
- };
-
- ogg_mux_type =
- g_type_register_static (GST_TYPE_ELEMENT, "GstOggMux", &ogg_mux_info,
- 0);
-
- g_type_add_interface_static (ogg_mux_type, GST_TYPE_PRESET, &preset_info);
- }
- return ogg_mux_type;
-}
-
-static void
-gst_ogg_mux_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 (&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,
- "Ogg muxer", "Codec/Muxer",
- "mux ogg streams (info about ogg: http://xiph.org)",
- "Wim Taymans <wim@fluendo.com>");
-}
+#define gst_ogg_mux_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstOggMux, gst_ogg_mux, GST_TYPE_ELEMENT,
+ G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL));
static void
gst_ogg_mux_class_init (GstOggMuxClass * klass)
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
- parent_class = g_type_class_peek_parent (klass);
-
gobject_class->finalize = gst_ogg_mux_finalize;
gobject_class->get_property = gst_ogg_mux_get_property;
gobject_class->set_property = gst_ogg_mux_set_property;
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&src_factory));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&sink_factory));
+
+ gst_element_class_set_details_simple (gstelement_class,
+ "Ogg muxer", "Codec/Muxer",
+ "mux ogg streams (info about ogg: http://xiph.org)",
+ "Wim Taymans <wim@fluendo.com>");
+
gstelement_class->request_new_pad = gst_ogg_mux_request_new_pad;
gstelement_class->release_pad = gst_ogg_mux_release_pad;
GST_DEBUG_OBJECT (pad, "Got %s event", GST_EVENT_TYPE_NAME (event));
switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_NEWSEGMENT:{
- gboolean update;
- gdouble rate;
- gdouble applied_rate;
- GstFormat format;
- gint64 start, stop, position;
+ case GST_EVENT_SEGMENT:
+ {
+ const GstSegment *segment;
- gst_event_parse_new_segment_full (event, &update, &rate,
- &applied_rate, &format, &start, &stop, &position);
+ gst_event_parse_segment (event, &segment);
/* We don't support non time NEWSEGMENT events */
- if (format != GST_FORMAT_TIME) {
+ if (segment->format != GST_FORMAT_TIME) {
gst_event_unref (event);
event = NULL;
break;
}
- gst_segment_set_newsegment_full (&ogg_pad->segment, update, rate,
- applied_rate, format, start, stop, position);
-
+ gst_segment_copy_into (segment, &ogg_pad->segment);
break;
}
case GST_EVENT_FLUSH_STOP:{
static GstPad *
gst_ogg_mux_request_new_pad (GstElement * element,
- GstPadTemplate * templ, const gchar * req_name)
+ GstPadTemplate * templ, const gchar * req_name, const GstCaps * caps)
{
GstOggMux *ogg_mux;
GstPad *newpad;
/* allocate space for header and body */
buffer = gst_buffer_new_and_alloc (page->header_len + page->body_len);
- memcpy (GST_BUFFER_DATA (buffer), page->header, page->header_len);
- memcpy (GST_BUFFER_DATA (buffer) + page->header_len,
- page->body, page->body_len);
+ gst_buffer_fill (buffer, 0, page->header, page->header_len);
+ gst_buffer_fill (buffer, page->header_len, page->body, page->body_len);
/* Here we set granulepos as our OFFSET_END to give easy direct access to
* this value later. Before we push it, we reset this to OFFSET + SIZE
gst_ogg_mux_push_buffer (GstOggMux * mux, GstBuffer * buffer,
GstOggPadData * oggpad)
{
- GstCaps *caps;
-
/* fix up OFFSET and OFFSET_END again */
GST_BUFFER_OFFSET (buffer) = mux->offset;
- mux->offset += GST_BUFFER_SIZE (buffer);
+ mux->offset += gst_buffer_get_size (buffer);
GST_BUFFER_OFFSET_END (buffer) = mux->offset;
/* Ensure we have monotonically increasing timestamps in the output. */
mux->last_ts = run_time;
}
- caps = gst_pad_get_negotiated_caps (mux->srcpad);
- gst_buffer_set_caps (buffer, caps);
- if (caps)
- gst_caps_unref (caps);
-
return gst_pad_push (mux->srcpad, buffer);
}
/* and we have one */
ogg_packet packet;
gboolean is_header;
+ gsize size;
- packet.packet = GST_BUFFER_DATA (buf);
- packet.bytes = GST_BUFFER_SIZE (buf);
+ packet.packet = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
+ packet.bytes = size;
if (GST_BUFFER_OFFSET_END_IS_VALID (buf))
packet.granulepos = GST_BUFFER_OFFSET_END (buf);
/* if we're not yet in data mode, ensure we're setup on the first packet */
if (!pad->have_type) {
+ GstCaps *caps;
+
/* Use headers in caps, if any; this will allow us to be resilient
* to starting streams on the fly, and some streams (like VP8
* at least) do not send headers packets, as other muxers don't
* expect/need them. */
+ caps = gst_pad_get_current_caps (GST_PAD_CAST (pad));
pad->have_type =
- gst_ogg_stream_setup_map_from_caps_headers (&pad->map,
- GST_BUFFER_CAPS (buf));
+ gst_ogg_stream_setup_map_from_caps_headers (&pad->map, caps);
if (!pad->have_type) {
/* fallback on the packet */
}
if (!pad->have_type) {
GST_ERROR_OBJECT (pad, "mapper didn't recognise input stream "
- "(pad caps: %" GST_PTR_FORMAT ")", GST_PAD_CAPS (pad));
+ "(pad caps: %" GST_PTR_FORMAT ")", caps);
} else {
GST_DEBUG_OBJECT (pad, "caps detected: %" GST_PTR_FORMAT,
pad->map.caps);
}
+ if (caps)
+ gst_caps_unref (caps);
}
if (pad->have_type)
else /* fallback (FIXME 0.11: remove IN_CAPS hack) */
is_header = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
+ gst_buffer_unmap (buf, packet.packet, size);
+
if (is_header) {
GST_DEBUG_OBJECT (ogg_mux,
"got header buffer in control state, ignoring");
walk = walk->next;
/* mark buffer */
- GST_LOG ("Setting IN_CAPS on buffer of length %d", GST_BUFFER_SIZE (buf));
+ GST_LOG ("Setting IN_CAPS on buffer of length %d",
+ gst_buffer_get_size (buf));
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
g_value_init (&value, GST_TYPE_BUFFER);
GstCaps *caps;
GstStructure *structure;
GstBuffer *hbuf;
+ gsize size;
pad = (GstOggPadData *) walk->data;
thepad = pad->collect.pad;
}
/* create a packet from the buffer */
- packet.packet = GST_BUFFER_DATA (buf);
- packet.bytes = GST_BUFFER_SIZE (buf);
+ packet.packet = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
+ packet.bytes = size;
packet.granulepos = GST_BUFFER_OFFSET_END (buf);
if (packet.granulepos == -1)
packet.granulepos = 0;
/* swap the packet in */
ogg_stream_packetin (&pad->map.stream, &packet);
+
+ gst_buffer_unmap (buf, packet.packet, size);
gst_buffer_unref (buf);
GST_LOG_OBJECT (thepad, "flushing out BOS page");
GstBuffer *buf = GST_BUFFER (hwalk->data);
ogg_packet packet;
ogg_page page;
+ gsize size;
hwalk = hwalk->next;
/* create a packet from the buffer */
- packet.packet = GST_BUFFER_DATA (buf);
- packet.bytes = GST_BUFFER_SIZE (buf);
+ packet.packet = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
+ packet.bytes = size;
packet.granulepos = GST_BUFFER_OFFSET_END (buf);
if (packet.granulepos == -1)
packet.granulepos = 0;
/* swap the packet in */
ogg_stream_packetin (&pad->map.stream, &packet);
+ gst_buffer_unmap (buf, packet.packet, size);
gst_buffer_unref (buf);
/* if last header, flush page */
/* hbufs holds all buffers for the headers now */
/* create caps with the buffers */
- caps = gst_pad_get_caps (mux->srcpad);
+ caps = gst_pad_get_caps (mux->srcpad, NULL);
if (caps) {
caps = gst_ogg_mux_set_header_on_caps (caps, hbufs);
gst_pad_set_caps (mux->srcpad, caps);
GstOggPadData *pad = ogg_mux->pulling;
gint64 duration;
gboolean force_flush;
+ gsize size;
GST_LOG_OBJECT (ogg_mux->pulling->collect.pad, "pulling from pad");
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
}
/* create a packet from the buffer */
- packet.packet = GST_BUFFER_DATA (buf);
- packet.bytes = GST_BUFFER_SIZE (buf);
+ packet.packet = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
+ packet.bytes = size;
packet.granulepos = GST_BUFFER_OFFSET_END (buf);
if (packet.granulepos == -1)
packet.granulepos = 0;
GST_DEBUG_OBJECT (pad->collect.pad, "swapping in BOS packet");
ogg_stream_packetin (&pad->map.stream, &packet);
+ gst_buffer_unmap (buf, packet.packet, size);
pad->data_pushed = TRUE;
gp_time = GST_BUFFER_OFFSET (pad->buffer);
static GstFlowReturn
gst_ogg_parse_submit_buffer (GstOggParse * ogg, GstBuffer * buffer)
{
- guint size;
+ gsize size;
guint8 *data;
gchar *oggbuffer;
GstFlowReturn ret = GST_FLOW_OK;
- size = GST_BUFFER_SIZE (buffer);
- data = GST_BUFFER_DATA (buffer);
+ data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
- GST_DEBUG_OBJECT (ogg, "submitting %u bytes", size);
+ GST_DEBUG_OBJECT (ogg, "submitting %" G_GSIZE_FORMAT " bytes", size);
if (G_UNLIKELY (size == 0))
goto done;
}
done:
+ gst_buffer_unmap (buffer, data, size);
gst_buffer_unref (buffer);
return ret;
int size = page->header_len + page->body_len;
GstBuffer *buf = gst_buffer_new_and_alloc (size);
- memcpy (GST_BUFFER_DATA (buf), page->header, page->header_len);
- memcpy (GST_BUFFER_DATA (buf) + page->header_len, page->body, page->body_len);
+ gst_buffer_fill (buf, 0, page->header, page->header_len);
+ gst_buffer_fill (buf, page->header_len, page->body, page->body_len);
GST_BUFFER_TIMESTAMP (buf) = timestamp;
GST_BUFFER_OFFSET (buf) = offset;
ogg = GST_OGG_PARSE (GST_OBJECT_PARENT (pad));
- GST_LOG_OBJECT (ogg, "Chain function received buffer of size %d",
- GST_BUFFER_SIZE (buffer));
+ GST_LOG_OBJECT (ogg,
+ "Chain function received buffer of size %" G_GSIZE_FORMAT,
+ gst_buffer_get_size (buffer));
gst_ogg_parse_submit_buffer (ogg, buffer);
}
}
- caps = gst_pad_get_caps (ogg->srcpad);
+ caps = gst_pad_get_caps (ogg->srcpad, NULL);
caps = gst_caps_make_writable (caps);
structure = gst_caps_get_structure (caps, 0);
GstOggStream *stream = (GstOggStream *) l->data;
GstBuffer *buf = GST_BUFFER (stream->headers->data);
- buf = gst_buffer_make_metadata_writable (buf);
- gst_buffer_set_caps (buf, caps);
-
result = gst_pad_push (ogg->srcpad, buf);
if (result != GST_FLOW_OK)
return result;
for (j = stream->headers->next; j != NULL; j = j->next) {
GstBuffer *buf = GST_BUFFER (j->data);
- buf = gst_buffer_make_metadata_writable (buf);
- gst_buffer_set_caps (buf, caps);
-
result = gst_pad_push (ogg->srcpad, buf);
if (result != GST_FLOW_OK)
return result;
g_list_length (stream->unknown_pages) + 1);
for (k = stream->unknown_pages; k != NULL; k = k->next) {
- GstBuffer *buf;
+ GstBuffer *buf = GST_BUFFER (k->data);
- buf = gst_buffer_make_metadata_writable (GST_BUFFER (k->data));
- gst_buffer_set_caps (buf, caps);
result = gst_pad_push (ogg->srcpad, buf);
if (result != GST_FLOW_OK)
return result;
while (stream->stored_buffers) {
GstBuffer *buf = stream->stored_buffers->data;
- buf = gst_buffer_make_metadata_writable (buf);
- gst_buffer_set_caps (buf, ogg->caps);
+ buf = gst_buffer_make_writable (buf);
+
GST_BUFFER_TIMESTAMP (buf) = buffertimestamp;
if (!keyframe) {
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
stream->stored_buffers);
}
- pagebuffer = gst_buffer_make_metadata_writable (pagebuffer);
- gst_buffer_set_caps (pagebuffer, ogg->caps);
+ pagebuffer = gst_buffer_make_writable (pagebuffer);
if (!keyframe) {
GST_BUFFER_FLAG_SET (pagebuffer, GST_BUFFER_FLAG_DELTA_UNIT);
} else {
tag_list_from_vorbiscomment_packet (ogg_packet * packet,
const guint8 * id_data, const guint id_data_length, GstTagList ** tags)
{
- GstBuffer *buf = NULL;
gchar *encoder = NULL;
GstTagList *list;
gboolean ret = TRUE;
g_return_val_if_fail (tags != NULL, FALSE);
- buf = gst_buffer_new ();
- GST_BUFFER_DATA (buf) = (guint8 *) packet->packet;
- GST_BUFFER_SIZE (buf) = packet->bytes;
-
- list = gst_tag_list_from_vorbiscomment_buffer (buf, id_data, id_data_length,
- &encoder);
+ list = gst_tag_list_from_vorbiscomment (packet->packet, packet->bytes,
+ id_data, id_data_length, &encoder);
if (!list) {
GST_WARNING ("failed to decode vorbis comments");
gst_tag_list_free (*tags);
*tags = list;
- gst_buffer_unref (buf);
-
return ret;
}
gst_ogg_stream_setup_map_from_caps_headers (GstOggStream * pad,
const GstCaps * caps)
{
+ GstBuffer *buf;
const GstStructure *structure;
- const GstBuffer *buf;
const GValue *streamheader;
const GValue *first_element;
ogg_packet packet;
+ guint8 *data;
+ gsize size;
+ gboolean ret;
GST_INFO ("Checking streamheader on caps %" GST_PTR_FORMAT, caps);
}
buf = gst_value_get_buffer (first_element);
- if (buf == NULL || GST_BUFFER_SIZE (buf) == 0) {
+ if (buf == NULL) {
+ GST_ERROR ("no first streamheader buffer");
+ return FALSE;
+ }
+
+ data = gst_buffer_map (buf, &size, 0, GST_MAP_READ);
+ if (data == NULL || size == 0) {
GST_ERROR ("invalid first streamheader buffer");
return FALSE;
}
- GST_MEMDUMP ("streamheader", GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
+ GST_MEMDUMP ("streamheader", data, size);
- packet.packet = GST_BUFFER_DATA (buf);
- packet.bytes = GST_BUFFER_SIZE (buf);
+ packet.packet = data;
+ packet.bytes = size;
GST_INFO ("Found headers on caps, using those to determine type");
- return gst_ogg_stream_setup_map (pad, &packet);
+ ret = gst_ogg_stream_setup_map (pad, &packet);
+
+ gst_buffer_unmap (buf, data, size);
+
+ return ret;
}
audio_src_templ = gst_pad_template_new ("src",
GST_PAD_SRC, GST_PAD_SOMETIMES, caps);
gst_element_class_add_pad_template (element_class, audio_src_templ);
+ gst_caps_unref (caps);
}
static void
video_src_templ = gst_pad_template_new ("src",
GST_PAD_SRC, GST_PAD_SOMETIMES, caps);
gst_element_class_add_pad_template (element_class, video_src_templ);
+ gst_caps_unref (caps);
}
static void
text_src_templ = gst_pad_template_new ("src",
GST_PAD_SRC, GST_PAD_SOMETIMES, caps);
gst_element_class_add_pad_template (element_class, text_src_templ);
+ gst_caps_unref (caps);
}
static void
goto cannot_decode;
if (ogm->srcpad) {
- GstCaps *current_caps = GST_PAD_CAPS (ogm->srcpad);
-
- if (current_caps && caps && !gst_caps_is_equal (current_caps, caps)) {
- GST_WARNING_OBJECT (ogm, "Already an existing pad %s:%s",
- GST_DEBUG_PAD_NAME (ogm->srcpad));
- gst_pad_set_active (ogm->srcpad, FALSE);
- gst_element_remove_pad (GST_ELEMENT (ogm), ogm->srcpad);
- ogm->srcpad = NULL;
- } else {
- GST_DEBUG_OBJECT (ogm, "Existing pad has the same caps, do nothing");
+ GstCaps *current_caps = gst_pad_get_current_caps (ogm->srcpad);
+
+ if (current_caps) {
+ if (caps && !gst_caps_is_equal (current_caps, caps)) {
+ GST_WARNING_OBJECT (ogm, "Already an existing pad %s:%s",
+ GST_DEBUG_PAD_NAME (ogm->srcpad));
+ gst_pad_set_active (ogm->srcpad, FALSE);
+ gst_element_remove_pad (GST_ELEMENT (ogm), ogm->srcpad);
+ ogm->srcpad = NULL;
+ } else {
+ GST_DEBUG_OBJECT (ogm, "Existing pad has the same caps, do nothing");
+ }
+ gst_caps_unref (current_caps);
}
}
ogm->srcpad = gst_pad_new_from_template (ogm->srcpadtempl, "src");
gst_pad_use_fixed_caps (ogm->srcpad);
- gst_pad_set_caps (ogm->srcpad, caps);
gst_pad_set_active (ogm->srcpad, TRUE);
+ gst_pad_set_caps (ogm->srcpad, caps);
gst_element_add_pad (GST_ELEMENT (ogm), ogm->srcpad);
GST_INFO_OBJECT (ogm, "Added pad %s:%s with caps %" GST_PTR_FORMAT,
GST_DEBUG_PAD_NAME (ogm->srcpad), caps);
/* do not push packet downstream, just let parent unref it */
ret = GST_FLOW_OK;
} else {
- buf = gst_buffer_copy (buf);
- gst_buffer_set_caps (buf, GST_PAD_CAPS (ogm->srcpad));
ret = gst_pad_push (ogm->srcpad, buf);
}
static void
gst_ogm_text_parse_strip_trailing_zeroes (GstOgmParse * ogm, GstBuffer * buf)
{
- const guint8 *data;
- guint size;
+ guint8 *data;
+ gsize size;
- g_assert (gst_buffer_is_metadata_writable (buf));
+ g_assert (gst_buffer_is_writable (buf));
/* zeroes are not valid UTF-8 characters, so strip them from output */
- data = GST_BUFFER_DATA (buf);
- size = GST_BUFFER_SIZE (buf);
+ data = gst_buffer_map (buf, &size, NULL, GST_MAP_WRITE);
while (size > 0 && data[size - 1] == '\0') {
--size;
}
-
- GST_BUFFER_SIZE (buf) = size;
+ gst_buffer_unmap (buf, data, size);
}
static GstFlowReturn
-gst_ogm_parse_data_packet (GstOgmParse * ogm, GstBuffer * buf)
+gst_ogm_parse_data_packet (GstOgmParse * ogm, GstBuffer * buf,
+ const guint8 * data, gsize size)
{
GstFlowReturn ret;
- const guint8 *data;
GstBuffer *sbuf;
gboolean keyframe;
- guint size, len, n, xsize = 0;
-
- data = GST_BUFFER_DATA (buf);
- size = GST_BUFFER_SIZE (buf);
+ guint len, n, xsize = 0;
if ((data[0] & 0x01) != 0)
goto invalid_startcode;
GST_LOG_OBJECT (ogm, "[0x%02x] samples: %d, hdrbytes: %d, datasize: %d",
data[0], xsize, len, size - len - 1);
- sbuf = gst_buffer_create_sub (buf, len + 1, size - len - 1);
+ sbuf =
+ gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, len + 1,
+ size - len - 1);
if (GST_BUFFER_OFFSET_END_IS_VALID (buf))
ogm->next_granulepos = GST_BUFFER_OFFSET_END (buf);
}
if (ogm->srcpad) {
- gst_buffer_set_caps (sbuf, GST_PAD_CAPS (ogm->srcpad));
GST_LOG_OBJECT (ogm, "Pushing buffer with ts=%" GST_TIME_FORMAT,
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (sbuf)));
ret = gst_pad_push (ogm->srcpad, sbuf);
{
GstFlowReturn ret = GST_FLOW_OK;
GstOgmParse *ogm = GST_OGM_PARSE (GST_PAD_PARENT (pad));
- guint8 *data = GST_BUFFER_DATA (buf);
- guint size = GST_BUFFER_SIZE (buf);
+ guint8 *data;
+ gsize size;
+ data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
if (size < 1)
goto buffer_too_small;
break;
}
default:{
- ret = gst_ogm_parse_data_packet (ogm, buf);
+ ret = gst_ogm_parse_data_packet (ogm, buf, data, size);
break;
}
}
+ gst_buffer_unmap (buf, data, size);
gst_buffer_unref (buf);
if (ret != GST_FLOW_OK) {
buffer_too_small:
{
GST_ELEMENT_ERROR (ogm, STREAM, DECODE, (NULL), ("buffer too small"));
+ gst_buffer_unmap (buf, data, size);
gst_buffer_unref (buf);
return GST_FLOW_ERROR;
}
plugin_LTLIBRARIES = libgstpango.la
noinst_HEADERS = \
+ gstbasetextoverlay.h \
gstclockoverlay.h \
gsttextoverlay.h \
gsttextrender.h \
gsttimeoverlay.h
libgstpango_la_SOURCES = \
+ gstbasetextoverlay.c \
gstclockoverlay.c \
gsttextoverlay.c \
gsttextrender.c \
--- /dev/null
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) <2003> David Schleef <ds@schleef.org>
+ * Copyright (C) <2006> Julien Moutte <julien@moutte.net>
+ * Copyright (C) <2006> Zeeshan Ali <zeeshan.ali@nokia.com>
+ * Copyright (C) <2006-2008> Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) <2009> Young-Ho Cha <ganadist@gmail.com>
+ *
+ * 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-textoverlay
+ * @see_also: #GstTextRender, #GstClockOverlay, #GstTimeOverlay, #GstSubParse
+ *
+ * This plugin renders text on top of a video stream. This can be either
+ * static text or text from buffers received on the text sink pad, e.g.
+ * as produced by the subparse element. If the text sink pad is not linked,
+ * the text set via the "text" property will be rendered. If the text sink
+ * pad is linked, text will be rendered as it is received on that pad,
+ * honouring and matching the buffer timestamps of both input streams.
+ *
+ * The text can contain newline characters and text wrapping is enabled by
+ * default.
+ *
+ * <refsect2>
+ * <title>Example launch lines</title>
+ * |[
+ * gst-launch -v videotestsrc ! textoverlay text="Room A" valign=top halign=left ! xvimagesink
+ * ]| Here is a simple pipeline that displays a static text in the top left
+ * corner of the video picture
+ * |[
+ * gst-launch -v filesrc location=subtitles.srt ! subparse ! txt. videotestsrc ! timeoverlay ! textoverlay name=txt shaded-background=yes ! xvimagesink
+ * ]| Here is another pipeline that displays subtitles from an .srt subtitle
+ * file, centered at the bottom of the picture and with a rectangular shading
+ * around the text in the background:
+ * <para>
+ * If you do not have such a subtitle file, create one looking like this
+ * in a text editor:
+ * |[
+ * 1
+ * 00:00:03,000 --> 00:00:05,000
+ * Hello? (3-5s)
+ *
+ * 2
+ * 00:00:08,000 --> 00:00:13,000
+ * Yes, this is a subtitle. Don't
+ * you like it? (8-13s)
+ *
+ * 3
+ * 00:00:18,826 --> 00:01:02,886
+ * Uh? What are you talking about?
+ * I don't understand (18-62s)
+ * ]|
+ * </para>
+ * </refsect2>
+ */
+
+/* FIXME: alloc segment as part of instance struct */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gst/video/video.h>
+
+#include "gstbasetextoverlay.h"
+#include "gsttextoverlay.h"
+#include "gsttimeoverlay.h"
+#include "gstclockoverlay.h"
+#include "gsttextrender.h"
+#include <string.h>
+
+/* FIXME:
+ * - use proper strides and offset for I420
+ * - if text is wider than the video picture, it does not get
+ * clipped properly during blitting (if wrapping is disabled)
+ * - make 'shading_value' a property (or enum: light/normal/dark/verydark)?
+ */
+
+GST_DEBUG_CATEGORY (pango_debug);
+#define GST_CAT_DEFAULT pango_debug
+
+#define DEFAULT_PROP_TEXT ""
+#define DEFAULT_PROP_SHADING FALSE
+#define DEFAULT_PROP_VALIGNMENT GST_BASE_TEXT_OVERLAY_VALIGN_BASELINE
+#define DEFAULT_PROP_HALIGNMENT GST_BASE_TEXT_OVERLAY_HALIGN_CENTER
+#define DEFAULT_PROP_VALIGN "baseline"
+#define DEFAULT_PROP_HALIGN "center"
+#define DEFAULT_PROP_XPAD 25
+#define DEFAULT_PROP_YPAD 25
+#define DEFAULT_PROP_DELTAX 0
+#define DEFAULT_PROP_DELTAY 0
+#define DEFAULT_PROP_XPOS 0.5
+#define DEFAULT_PROP_YPOS 0.5
+#define DEFAULT_PROP_WRAP_MODE GST_BASE_TEXT_OVERLAY_WRAP_MODE_WORD_CHAR
+#define DEFAULT_PROP_FONT_DESC ""
+#define DEFAULT_PROP_SILENT FALSE
+#define DEFAULT_PROP_LINE_ALIGNMENT GST_BASE_TEXT_OVERLAY_LINE_ALIGN_CENTER
+#define DEFAULT_PROP_WAIT_TEXT TRUE
+#define DEFAULT_PROP_AUTO_ADJUST_SIZE TRUE
+#define DEFAULT_PROP_VERTICAL_RENDER FALSE
+#define DEFAULT_PROP_COLOR 0xffffffff
+#define DEFAULT_PROP_OUTLINE_COLOR 0xff000000
+
+/* make a property of me */
+#define DEFAULT_SHADING_VALUE -80
+
+#define MINIMUM_OUTLINE_OFFSET 1.0
+#define DEFAULT_SCALE_BASIS 640
+
+#define COMP_Y(ret, r, g, b) \
+{ \
+ ret = (int) (((19595 * r) >> 16) + ((38470 * g) >> 16) + ((7471 * b) >> 16)); \
+ ret = CLAMP (ret, 0, 255); \
+}
+
+#define COMP_U(ret, r, g, b) \
+{ \
+ ret = (int) (-((11059 * r) >> 16) - ((21709 * g) >> 16) + ((32768 * b) >> 16) + 128); \
+ ret = CLAMP (ret, 0, 255); \
+}
+
+#define COMP_V(ret, r, g, b) \
+{ \
+ ret = (int) (((32768 * r) >> 16) - ((27439 * g) >> 16) - ((5329 * b) >> 16) + 128); \
+ ret = CLAMP (ret, 0, 255); \
+}
+
+#define BLEND(ret, alpha, v0, v1) \
+{ \
+ ret = (v0 * alpha + v1 * (255 - alpha)) / 255; \
+}
+
+#define OVER(ret, alphaA, Ca, alphaB, Cb, alphaNew) \
+{ \
+ gint _tmp; \
+ _tmp = (Ca * alphaA + Cb * alphaB * (255 - alphaA) / 255) / alphaNew; \
+ ret = CLAMP (_tmp, 0, 255); \
+}
+
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+# define CAIRO_ARGB_A 3
+# define CAIRO_ARGB_R 2
+# define CAIRO_ARGB_G 1
+# define CAIRO_ARGB_B 0
+#else
+# define CAIRO_ARGB_A 0
+# define CAIRO_ARGB_R 1
+# define CAIRO_ARGB_G 2
+# define CAIRO_ARGB_B 3
+#endif
+
+enum
+{
+ PROP_0,
+ PROP_TEXT,
+ PROP_SHADING,
+ PROP_VALIGN, /* deprecated */
+ PROP_HALIGN, /* deprecated */
+ PROP_HALIGNMENT,
+ PROP_VALIGNMENT,
+ PROP_XPAD,
+ PROP_YPAD,
+ PROP_DELTAX,
+ PROP_DELTAY,
+ PROP_XPOS,
+ PROP_YPOS,
+ PROP_WRAP_MODE,
+ PROP_FONT_DESC,
+ PROP_SILENT,
+ PROP_LINE_ALIGNMENT,
+ PROP_WAIT_TEXT,
+ PROP_AUTO_ADJUST_SIZE,
+ PROP_VERTICAL_RENDER,
+ PROP_COLOR,
+ PROP_SHADOW,
+ PROP_OUTLINE_COLOR,
+ PROP_LAST
+};
+
+static GstStaticPadTemplate src_template_factory =
+ GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_BGRx ";"
+ GST_VIDEO_CAPS_RGBx ";"
+ GST_VIDEO_CAPS_xRGB ";"
+ GST_VIDEO_CAPS_xBGR ";"
+ GST_VIDEO_CAPS_RGBA ";"
+ GST_VIDEO_CAPS_BGRA ";"
+ GST_VIDEO_CAPS_ARGB ";"
+ GST_VIDEO_CAPS_ABGR ";"
+ GST_VIDEO_CAPS_YUV ("{AYUV, I420, UYVY, NV12, NV21}"))
+ );
+
+static GstStaticPadTemplate video_sink_template_factory =
+ GST_STATIC_PAD_TEMPLATE ("video_sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_BGRx ";"
+ GST_VIDEO_CAPS_RGBx ";"
+ GST_VIDEO_CAPS_xRGB ";"
+ GST_VIDEO_CAPS_xBGR ";"
+ GST_VIDEO_CAPS_RGBA ";"
+ GST_VIDEO_CAPS_BGRA ";"
+ GST_VIDEO_CAPS_ARGB ";"
+ GST_VIDEO_CAPS_ABGR ";"
+ GST_VIDEO_CAPS_YUV ("{AYUV, I420, UYVY, NV12, NV21}"))
+ );
+
+#define GST_TYPE_BASE_TEXT_OVERLAY_VALIGN (gst_base_text_overlay_valign_get_type())
+static GType
+gst_base_text_overlay_valign_get_type (void)
+{
+ static GType base_text_overlay_valign_type = 0;
+ static const GEnumValue base_text_overlay_valign[] = {
+ {GST_BASE_TEXT_OVERLAY_VALIGN_BASELINE, "baseline", "baseline"},
+ {GST_BASE_TEXT_OVERLAY_VALIGN_BOTTOM, "bottom", "bottom"},
+ {GST_BASE_TEXT_OVERLAY_VALIGN_TOP, "top", "top"},
+ {GST_BASE_TEXT_OVERLAY_VALIGN_POS, "position", "position"},
+ {GST_BASE_TEXT_OVERLAY_VALIGN_CENTER, "center", "center"},
+ {0, NULL, NULL},
+ };
+
+ if (!base_text_overlay_valign_type) {
+ base_text_overlay_valign_type =
+ g_enum_register_static ("GstBaseTextOverlayVAlign",
+ base_text_overlay_valign);
+ }
+ return base_text_overlay_valign_type;
+}
+
+#define GST_TYPE_BASE_TEXT_OVERLAY_HALIGN (gst_base_text_overlay_halign_get_type())
+static GType
+gst_base_text_overlay_halign_get_type (void)
+{
+ static GType base_text_overlay_halign_type = 0;
+ static const GEnumValue base_text_overlay_halign[] = {
+ {GST_BASE_TEXT_OVERLAY_HALIGN_LEFT, "left", "left"},
+ {GST_BASE_TEXT_OVERLAY_HALIGN_CENTER, "center", "center"},
+ {GST_BASE_TEXT_OVERLAY_HALIGN_RIGHT, "right", "right"},
+ {GST_BASE_TEXT_OVERLAY_HALIGN_POS, "position", "position"},
+ {0, NULL, NULL},
+ };
+
+ if (!base_text_overlay_halign_type) {
+ base_text_overlay_halign_type =
+ g_enum_register_static ("GstBaseTextOverlayHAlign",
+ base_text_overlay_halign);
+ }
+ return base_text_overlay_halign_type;
+}
+
+
+#define GST_TYPE_BASE_TEXT_OVERLAY_WRAP_MODE (gst_base_text_overlay_wrap_mode_get_type())
+static GType
+gst_base_text_overlay_wrap_mode_get_type (void)
+{
+ static GType base_text_overlay_wrap_mode_type = 0;
+ static const GEnumValue base_text_overlay_wrap_mode[] = {
+ {GST_BASE_TEXT_OVERLAY_WRAP_MODE_NONE, "none", "none"},
+ {GST_BASE_TEXT_OVERLAY_WRAP_MODE_WORD, "word", "word"},
+ {GST_BASE_TEXT_OVERLAY_WRAP_MODE_CHAR, "char", "char"},
+ {GST_BASE_TEXT_OVERLAY_WRAP_MODE_WORD_CHAR, "wordchar", "wordchar"},
+ {0, NULL, NULL},
+ };
+
+ if (!base_text_overlay_wrap_mode_type) {
+ base_text_overlay_wrap_mode_type =
+ g_enum_register_static ("GstBaseTextOverlayWrapMode",
+ base_text_overlay_wrap_mode);
+ }
+ return base_text_overlay_wrap_mode_type;
+}
+
+#define GST_TYPE_BASE_TEXT_OVERLAY_LINE_ALIGN (gst_base_text_overlay_line_align_get_type())
+static GType
+gst_base_text_overlay_line_align_get_type (void)
+{
+ static GType base_text_overlay_line_align_type = 0;
+ static const GEnumValue base_text_overlay_line_align[] = {
+ {GST_BASE_TEXT_OVERLAY_LINE_ALIGN_LEFT, "left", "left"},
+ {GST_BASE_TEXT_OVERLAY_LINE_ALIGN_CENTER, "center", "center"},
+ {GST_BASE_TEXT_OVERLAY_LINE_ALIGN_RIGHT, "right", "right"},
+ {0, NULL, NULL}
+ };
+
+ if (!base_text_overlay_line_align_type) {
+ base_text_overlay_line_align_type =
+ g_enum_register_static ("GstBaseTextOverlayLineAlign",
+ base_text_overlay_line_align);
+ }
+ return base_text_overlay_line_align_type;
+}
+
+#define GST_BASE_TEXT_OVERLAY_GET_COND(ov) (((GstBaseTextOverlay *)ov)->cond)
+#define GST_BASE_TEXT_OVERLAY_WAIT(ov) (g_cond_wait (GST_BASE_TEXT_OVERLAY_GET_COND (ov), GST_OBJECT_GET_LOCK (ov)))
+#define GST_BASE_TEXT_OVERLAY_SIGNAL(ov) (g_cond_signal (GST_BASE_TEXT_OVERLAY_GET_COND (ov)))
+#define GST_BASE_TEXT_OVERLAY_BROADCAST(ov)(g_cond_broadcast (GST_BASE_TEXT_OVERLAY_GET_COND (ov)))
+
+static GstElementClass *parent_class = NULL;
+static void gst_base_text_overlay_base_init (gpointer g_class);
+static void gst_base_text_overlay_class_init (GstBaseTextOverlayClass * klass);
+static void gst_base_text_overlay_init (GstBaseTextOverlay * overlay,
+ GstBaseTextOverlayClass * klass);
+
+static GstStateChangeReturn gst_base_text_overlay_change_state (GstElement *
+ element, GstStateChange transition);
+
+static GstCaps *gst_base_text_overlay_getcaps (GstPad * pad, GstCaps * filter);
+static gboolean gst_base_text_overlay_setcaps (GstPad * pad, GstCaps * caps);
+static gboolean gst_base_text_overlay_setcaps_txt (GstPad * pad,
+ GstCaps * caps);
+static gboolean gst_base_text_overlay_src_event (GstPad * pad,
+ GstEvent * event);
+static gboolean gst_base_text_overlay_src_query (GstPad * pad,
+ GstQuery * query);
+
+static gboolean gst_base_text_overlay_video_event (GstPad * pad,
+ GstEvent * event);
+static GstFlowReturn gst_base_text_overlay_video_chain (GstPad * pad,
+ GstBuffer * buffer);
+
+static gboolean gst_base_text_overlay_text_event (GstPad * pad,
+ GstEvent * event);
+static GstFlowReturn gst_base_text_overlay_text_chain (GstPad * pad,
+ GstBuffer * buffer);
+static GstPadLinkReturn gst_base_text_overlay_text_pad_link (GstPad * pad,
+ GstPad * peer);
+static void gst_base_text_overlay_text_pad_unlink (GstPad * pad);
+static void gst_base_text_overlay_pop_text (GstBaseTextOverlay * overlay);
+static void gst_base_text_overlay_update_render_mode (GstBaseTextOverlay *
+ overlay);
+
+static void gst_base_text_overlay_finalize (GObject * object);
+static void gst_base_text_overlay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_base_text_overlay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+static void
+gst_base_text_overlay_adjust_values_with_fontdesc (GstBaseTextOverlay * overlay,
+ PangoFontDescription * desc);
+
+GType
+gst_base_text_overlay_get_type (void)
+{
+ static GType type = 0;
+
+ if (g_once_init_enter ((gsize *) & type)) {
+ static const GTypeInfo info = {
+ sizeof (GstBaseTextOverlayClass),
+ (GBaseInitFunc) gst_base_text_overlay_base_init,
+ NULL,
+ (GClassInitFunc) gst_base_text_overlay_class_init,
+ NULL,
+ NULL,
+ sizeof (GstBaseTextOverlay),
+ 0,
+ (GInstanceInitFunc) gst_base_text_overlay_init,
+ };
+
+ g_once_init_leave ((gsize *) & type,
+ g_type_register_static (GST_TYPE_ELEMENT, "GstBaseTextOverlay", &info,
+ 0));
+ }
+
+ return type;
+}
+
+static gchar *
+gst_base_text_overlay_get_text (GstBaseTextOverlay * overlay,
+ GstBuffer * video_frame)
+{
+ return g_strdup (overlay->default_text);
+}
+
+static void
+gst_base_text_overlay_base_init (gpointer g_class)
+{
+ GstBaseTextOverlayClass *klass = GST_BASE_TEXT_OVERLAY_CLASS (g_class);
+ PangoFontMap *fontmap;
+
+ /* Only lock for the subclasses here, the base class
+ * doesn't have this mutex yet and it's not necessary
+ * here */
+ if (klass->pango_lock)
+ g_mutex_lock (klass->pango_lock);
+ fontmap = pango_cairo_font_map_get_default ();
+ klass->pango_context =
+ pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (fontmap));
+ if (klass->pango_lock)
+ g_mutex_unlock (klass->pango_lock);
+}
+
+static void
+gst_base_text_overlay_class_init (GstBaseTextOverlayClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ gobject_class->finalize = gst_base_text_overlay_finalize;
+ gobject_class->set_property = gst_base_text_overlay_set_property;
+ gobject_class->get_property = gst_base_text_overlay_get_property;
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&src_template_factory));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&video_sink_template_factory));
+
+ gstelement_class->change_state =
+ GST_DEBUG_FUNCPTR (gst_base_text_overlay_change_state);
+
+ klass->pango_lock = g_mutex_new ();
+
+ klass->get_text = gst_base_text_overlay_get_text;
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TEXT,
+ g_param_spec_string ("text", "text",
+ "Text to be display.", DEFAULT_PROP_TEXT,
+ G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SHADING,
+ g_param_spec_boolean ("shaded-background", "shaded background",
+ "Whether to shade the background under the text area",
+ DEFAULT_PROP_SHADING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VALIGNMENT,
+ g_param_spec_enum ("valignment", "vertical alignment",
+ "Vertical alignment of the text", GST_TYPE_BASE_TEXT_OVERLAY_VALIGN,
+ DEFAULT_PROP_VALIGNMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HALIGNMENT,
+ g_param_spec_enum ("halignment", "horizontal alignment",
+ "Horizontal alignment of the text", GST_TYPE_BASE_TEXT_OVERLAY_HALIGN,
+ DEFAULT_PROP_HALIGNMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VALIGN,
+ g_param_spec_string ("valign", "vertical alignment",
+ "Vertical alignment of the text (deprecated; use valignment)",
+ DEFAULT_PROP_VALIGN, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HALIGN,
+ g_param_spec_string ("halign", "horizontal alignment",
+ "Horizontal alignment of the text (deprecated; use halignment)",
+ DEFAULT_PROP_HALIGN, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_XPAD,
+ g_param_spec_int ("xpad", "horizontal paddding",
+ "Horizontal paddding when using left/right alignment", 0, G_MAXINT,
+ DEFAULT_PROP_XPAD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_YPAD,
+ g_param_spec_int ("ypad", "vertical padding",
+ "Vertical padding when using top/bottom alignment", 0, G_MAXINT,
+ DEFAULT_PROP_YPAD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DELTAX,
+ g_param_spec_int ("deltax", "X position modifier",
+ "Shift X position to the left or to the right. Unit is pixels.",
+ G_MININT, G_MAXINT, DEFAULT_PROP_DELTAX,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DELTAY,
+ g_param_spec_int ("deltay", "Y position modifier",
+ "Shift Y position up or down. Unit is pixels.", G_MININT, G_MAXINT,
+ DEFAULT_PROP_DELTAY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ /**
+ * GstBaseTextOverlay:xpos
+ *
+ * Horizontal position of the rendered text when using positioned alignment.
+ *
+ * Since: 0.10.31
+ **/
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_XPOS,
+ g_param_spec_double ("xpos", "horizontal position",
+ "Horizontal position when using position alignment", 0, 1.0,
+ DEFAULT_PROP_XPOS,
+ G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+ /**
+ * GstBaseTextOverlay:ypos
+ *
+ * Vertical position of the rendered text when using positioned alignment.
+ *
+ * Since: 0.10.31
+ **/
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_YPOS,
+ g_param_spec_double ("ypos", "vertical position",
+ "Vertical position when using position alignment", 0, 1.0,
+ DEFAULT_PROP_YPOS,
+ G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_WRAP_MODE,
+ g_param_spec_enum ("wrap-mode", "wrap mode",
+ "Whether to wrap the text and if so how.",
+ GST_TYPE_BASE_TEXT_OVERLAY_WRAP_MODE, DEFAULT_PROP_WRAP_MODE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_FONT_DESC,
+ g_param_spec_string ("font-desc", "font description",
+ "Pango font description of font to be used for rendering. "
+ "See documentation of pango_font_description_from_string "
+ "for syntax.", DEFAULT_PROP_FONT_DESC,
+ G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+ /**
+ * GstBaseTextOverlay:color
+ *
+ * Color of the rendered text.
+ *
+ * Since: 0.10.31
+ **/
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_COLOR,
+ g_param_spec_uint ("color", "Color",
+ "Color to use for text (big-endian ARGB).", 0, G_MAXUINT32,
+ DEFAULT_PROP_COLOR,
+ G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+ /**
+ * GstTextOverlay:outline-color
+ *
+ * Color of the outline of the rendered text.
+ *
+ * Since: 0.10.35
+ **/
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_OUTLINE_COLOR,
+ g_param_spec_uint ("outline-color", "Text Outline Color",
+ "Color to use for outline the text (big-endian ARGB).", 0,
+ G_MAXUINT32, DEFAULT_PROP_OUTLINE_COLOR,
+ G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GstBaseTextOverlay:line-alignment
+ *
+ * Alignment of text lines relative to each other (for multi-line text)
+ *
+ * Since: 0.10.15
+ **/
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LINE_ALIGNMENT,
+ g_param_spec_enum ("line-alignment", "line alignment",
+ "Alignment of text lines relative to each other.",
+ GST_TYPE_BASE_TEXT_OVERLAY_LINE_ALIGN, DEFAULT_PROP_LINE_ALIGNMENT,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ /**
+ * GstBaseTextOverlay:silent
+ *
+ * If set, no text is rendered. Useful to switch off text rendering
+ * temporarily without removing the textoverlay element from the pipeline.
+ *
+ * Since: 0.10.15
+ **/
+ /* FIXME 0.11: rename to "visible" or "text-visible" or "render-text" */
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SILENT,
+ g_param_spec_boolean ("silent", "silent",
+ "Whether to render the text string",
+ DEFAULT_PROP_SILENT,
+ G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+ /**
+ * GstBaseTextOverlay:wait-text
+ *
+ * If set, the video will block until a subtitle is received on the text pad.
+ * If video and subtitles are sent in sync, like from the same demuxer, this
+ * property should be set.
+ *
+ * Since: 0.10.20
+ **/
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_WAIT_TEXT,
+ g_param_spec_boolean ("wait-text", "Wait Text",
+ "Whether to wait for subtitles",
+ DEFAULT_PROP_WAIT_TEXT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass),
+ PROP_AUTO_ADJUST_SIZE, g_param_spec_boolean ("auto-resize", "auto resize",
+ "Automatically adjust font size to screen-size.",
+ DEFAULT_PROP_AUTO_ADJUST_SIZE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VERTICAL_RENDER,
+ g_param_spec_boolean ("vertical-render", "vertical render",
+ "Vertical Render.", DEFAULT_PROP_VERTICAL_RENDER,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gst_base_text_overlay_finalize (GObject * object)
+{
+ GstBaseTextOverlay *overlay = GST_BASE_TEXT_OVERLAY (object);
+
+ g_free (overlay->default_text);
+
+ if (overlay->text_image) {
+ g_free (overlay->text_image);
+ overlay->text_image = NULL;
+ }
+
+ if (overlay->layout) {
+ g_object_unref (overlay->layout);
+ overlay->layout = NULL;
+ }
+
+ if (overlay->text_buffer) {
+ gst_buffer_unref (overlay->text_buffer);
+ overlay->text_buffer = NULL;
+ }
+
+ if (overlay->cond) {
+ g_cond_free (overlay->cond);
+ overlay->cond = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_base_text_overlay_init (GstBaseTextOverlay * overlay,
+ GstBaseTextOverlayClass * klass)
+{
+ GstPadTemplate *template;
+ PangoFontDescription *desc;
+
+ /* video sink */
+ template = gst_static_pad_template_get (&video_sink_template_factory);
+ overlay->video_sinkpad = gst_pad_new_from_template (template, "video_sink");
+ gst_object_unref (template);
+ gst_pad_set_getcaps_function (overlay->video_sinkpad,
+ GST_DEBUG_FUNCPTR (gst_base_text_overlay_getcaps));
+ gst_pad_set_setcaps_function (overlay->video_sinkpad,
+ GST_DEBUG_FUNCPTR (gst_base_text_overlay_setcaps));
+ gst_pad_set_event_function (overlay->video_sinkpad,
+ GST_DEBUG_FUNCPTR (gst_base_text_overlay_video_event));
+ gst_pad_set_chain_function (overlay->video_sinkpad,
+ GST_DEBUG_FUNCPTR (gst_base_text_overlay_video_chain));
+ gst_element_add_pad (GST_ELEMENT (overlay), overlay->video_sinkpad);
+
+ template =
+ gst_element_class_get_pad_template (GST_ELEMENT_CLASS (klass),
+ "text_sink");
+ if (template) {
+ /* text sink */
+ overlay->text_sinkpad = gst_pad_new_from_template (template, "text_sink");
+ gst_object_unref (template);
+
+ gst_pad_set_setcaps_function (overlay->text_sinkpad,
+ GST_DEBUG_FUNCPTR (gst_base_text_overlay_setcaps_txt));
+ gst_pad_set_event_function (overlay->text_sinkpad,
+ GST_DEBUG_FUNCPTR (gst_base_text_overlay_text_event));
+ gst_pad_set_chain_function (overlay->text_sinkpad,
+ GST_DEBUG_FUNCPTR (gst_base_text_overlay_text_chain));
+ gst_pad_set_link_function (overlay->text_sinkpad,
+ GST_DEBUG_FUNCPTR (gst_base_text_overlay_text_pad_link));
+ gst_pad_set_unlink_function (overlay->text_sinkpad,
+ GST_DEBUG_FUNCPTR (gst_base_text_overlay_text_pad_unlink));
+ gst_element_add_pad (GST_ELEMENT (overlay), overlay->text_sinkpad);
+ }
+
+ /* (video) source */
+ template = gst_static_pad_template_get (&src_template_factory);
+ overlay->srcpad = gst_pad_new_from_template (template, "src");
+ gst_object_unref (template);
+ gst_pad_set_getcaps_function (overlay->srcpad,
+ GST_DEBUG_FUNCPTR (gst_base_text_overlay_getcaps));
+ gst_pad_set_event_function (overlay->srcpad,
+ GST_DEBUG_FUNCPTR (gst_base_text_overlay_src_event));
+ gst_pad_set_query_function (overlay->srcpad,
+ GST_DEBUG_FUNCPTR (gst_base_text_overlay_src_query));
+ gst_element_add_pad (GST_ELEMENT (overlay), overlay->srcpad);
+
+ g_mutex_lock (GST_BASE_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
+ overlay->line_align = DEFAULT_PROP_LINE_ALIGNMENT;
+ overlay->layout =
+ pango_layout_new (GST_BASE_TEXT_OVERLAY_GET_CLASS
+ (overlay)->pango_context);
+ desc =
+ pango_context_get_font_description (GST_BASE_TEXT_OVERLAY_GET_CLASS
+ (overlay)->pango_context);
+ gst_base_text_overlay_adjust_values_with_fontdesc (overlay, desc);
+
+ overlay->color = DEFAULT_PROP_COLOR;
+ overlay->outline_color = DEFAULT_PROP_OUTLINE_COLOR;
+ overlay->halign = DEFAULT_PROP_HALIGNMENT;
+ overlay->valign = DEFAULT_PROP_VALIGNMENT;
+ overlay->xpad = DEFAULT_PROP_XPAD;
+ overlay->ypad = DEFAULT_PROP_YPAD;
+ overlay->deltax = DEFAULT_PROP_DELTAX;
+ overlay->deltay = DEFAULT_PROP_DELTAY;
+ overlay->xpos = DEFAULT_PROP_XPOS;
+ overlay->ypos = DEFAULT_PROP_YPOS;
+
+ overlay->wrap_mode = DEFAULT_PROP_WRAP_MODE;
+
+ overlay->want_shading = DEFAULT_PROP_SHADING;
+ overlay->shading_value = DEFAULT_SHADING_VALUE;
+ overlay->silent = DEFAULT_PROP_SILENT;
+ overlay->wait_text = DEFAULT_PROP_WAIT_TEXT;
+ overlay->auto_adjust_size = DEFAULT_PROP_AUTO_ADJUST_SIZE;
+
+ overlay->default_text = g_strdup (DEFAULT_PROP_TEXT);
+ overlay->need_render = TRUE;
+ overlay->text_image = NULL;
+ overlay->use_vertical_render = DEFAULT_PROP_VERTICAL_RENDER;
+ gst_base_text_overlay_update_render_mode (overlay);
+
+ overlay->fps_n = 0;
+ overlay->fps_d = 1;
+
+ overlay->text_buffer = NULL;
+ overlay->text_linked = FALSE;
+ overlay->cond = g_cond_new ();
+ gst_segment_init (&overlay->segment, GST_FORMAT_TIME);
+ g_mutex_unlock (GST_BASE_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
+}
+
+static void
+gst_base_text_overlay_update_wrap_mode (GstBaseTextOverlay * overlay)
+{
+ if (overlay->wrap_mode == GST_BASE_TEXT_OVERLAY_WRAP_MODE_NONE) {
+ GST_DEBUG_OBJECT (overlay, "Set wrap mode NONE");
+ pango_layout_set_width (overlay->layout, -1);
+ } else {
+ int width;
+
+ if (overlay->auto_adjust_size) {
+ width = DEFAULT_SCALE_BASIS * PANGO_SCALE;
+ if (overlay->use_vertical_render) {
+ width = width * (overlay->height - overlay->ypad * 2) / overlay->width;
+ }
+ } else {
+ width =
+ (overlay->use_vertical_render ? overlay->height : overlay->width) *
+ PANGO_SCALE;
+ }
+
+ GST_DEBUG_OBJECT (overlay, "Set layout width %d", overlay->width);
+ GST_DEBUG_OBJECT (overlay, "Set wrap mode %d", overlay->wrap_mode);
+ pango_layout_set_width (overlay->layout, width);
+ pango_layout_set_wrap (overlay->layout, (PangoWrapMode) overlay->wrap_mode);
+ }
+}
+
+static void
+gst_base_text_overlay_update_render_mode (GstBaseTextOverlay * overlay)
+{
+ PangoMatrix matrix = PANGO_MATRIX_INIT;
+ PangoContext *context = pango_layout_get_context (overlay->layout);
+
+ if (overlay->use_vertical_render) {
+ pango_matrix_rotate (&matrix, -90);
+ pango_context_set_base_gravity (context, PANGO_GRAVITY_AUTO);
+ pango_context_set_matrix (context, &matrix);
+ pango_layout_set_alignment (overlay->layout, PANGO_ALIGN_LEFT);
+ } else {
+ pango_context_set_base_gravity (context, PANGO_GRAVITY_SOUTH);
+ pango_context_set_matrix (context, &matrix);
+ pango_layout_set_alignment (overlay->layout, overlay->line_align);
+ }
+}
+
+static gboolean
+gst_base_text_overlay_setcaps_txt (GstPad * pad, GstCaps * caps)
+{
+ GstBaseTextOverlay *overlay;
+ GstStructure *structure;
+
+ overlay = GST_BASE_TEXT_OVERLAY (gst_pad_get_parent (pad));
+
+ structure = gst_caps_get_structure (caps, 0);
+ overlay->have_pango_markup =
+ gst_structure_has_name (structure, "text/x-pango-markup");
+
+ gst_object_unref (overlay);
+
+ return TRUE;
+}
+
+/* FIXME: upstream nego (e.g. when the video window is resized) */
+
+static gboolean
+gst_base_text_overlay_setcaps (GstPad * pad, GstCaps * caps)
+{
+ GstBaseTextOverlay *overlay;
+ GstStructure *structure;
+ gboolean ret = FALSE;
+ const GValue *fps;
+
+ if (!GST_PAD_IS_SINK (pad))
+ return TRUE;
+
+ g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
+
+ overlay = GST_BASE_TEXT_OVERLAY (gst_pad_get_parent (pad));
+
+ overlay->width = 0;
+ overlay->height = 0;
+ structure = gst_caps_get_structure (caps, 0);
+ fps = gst_structure_get_value (structure, "framerate");
+
+ if (fps
+ && gst_video_format_parse_caps (caps, &overlay->format, &overlay->width,
+ &overlay->height)) {
+ ret = gst_pad_set_caps (overlay->srcpad, caps);
+ }
+
+ overlay->fps_n = gst_value_get_fraction_numerator (fps);
+ overlay->fps_d = gst_value_get_fraction_denominator (fps);
+
+ if (ret) {
+ GST_OBJECT_LOCK (overlay);
+ g_mutex_lock (GST_BASE_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
+ gst_base_text_overlay_update_wrap_mode (overlay);
+ g_mutex_unlock (GST_BASE_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
+ GST_OBJECT_UNLOCK (overlay);
+ }
+
+ gst_object_unref (overlay);
+
+ return ret;
+}
+
+static void
+gst_base_text_overlay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstBaseTextOverlay *overlay = GST_BASE_TEXT_OVERLAY (object);
+
+ GST_OBJECT_LOCK (overlay);
+ switch (prop_id) {
+ case PROP_TEXT:
+ g_free (overlay->default_text);
+ overlay->default_text = g_value_dup_string (value);
+ overlay->need_render = TRUE;
+ break;
+ case PROP_SHADING:
+ overlay->want_shading = g_value_get_boolean (value);
+ break;
+ case PROP_XPAD:
+ overlay->xpad = g_value_get_int (value);
+ break;
+ case PROP_YPAD:
+ overlay->ypad = g_value_get_int (value);
+ break;
+ case PROP_DELTAX:
+ overlay->deltax = g_value_get_int (value);
+ break;
+ case PROP_DELTAY:
+ overlay->deltay = g_value_get_int (value);
+ break;
+ case PROP_XPOS:
+ overlay->xpos = g_value_get_double (value);
+ break;
+ case PROP_YPOS:
+ overlay->ypos = g_value_get_double (value);
+ break;
+ case PROP_HALIGN:{
+ const gchar *s = g_value_get_string (value);
+
+ if (s && g_ascii_strcasecmp (s, "left") == 0)
+ overlay->halign = GST_BASE_TEXT_OVERLAY_HALIGN_LEFT;
+ else if (s && g_ascii_strcasecmp (s, "center") == 0)
+ overlay->halign = GST_BASE_TEXT_OVERLAY_HALIGN_CENTER;
+ else if (s && g_ascii_strcasecmp (s, "right") == 0)
+ overlay->halign = GST_BASE_TEXT_OVERLAY_HALIGN_RIGHT;
+ else
+ g_warning ("Invalid value '%s' for textoverlay property 'halign'",
+ GST_STR_NULL (s));
+ break;
+ }
+ case PROP_VALIGN:{
+ const gchar *s = g_value_get_string (value);
+
+ if (s && g_ascii_strcasecmp (s, "baseline") == 0)
+ overlay->valign = GST_BASE_TEXT_OVERLAY_VALIGN_BASELINE;
+ else if (s && g_ascii_strcasecmp (s, "bottom") == 0)
+ overlay->valign = GST_BASE_TEXT_OVERLAY_VALIGN_BOTTOM;
+ else if (s && g_ascii_strcasecmp (s, "top") == 0)
+ overlay->valign = GST_BASE_TEXT_OVERLAY_VALIGN_TOP;
+ else
+ g_warning ("Invalid value '%s' for textoverlay property 'valign'",
+ GST_STR_NULL (s));
+ break;
+ }
+ case PROP_VALIGNMENT:
+ overlay->valign = g_value_get_enum (value);
+ break;
+ case PROP_HALIGNMENT:
+ overlay->halign = g_value_get_enum (value);
+ break;
+ case PROP_WRAP_MODE:
+ overlay->wrap_mode = g_value_get_enum (value);
+ g_mutex_lock (GST_BASE_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
+ gst_base_text_overlay_update_wrap_mode (overlay);
+ g_mutex_unlock (GST_BASE_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
+ break;
+ case PROP_FONT_DESC:
+ {
+ PangoFontDescription *desc;
+ const gchar *fontdesc_str;
+
+ fontdesc_str = g_value_get_string (value);
+ g_mutex_lock (GST_BASE_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
+ desc = pango_font_description_from_string (fontdesc_str);
+ if (desc) {
+ GST_LOG_OBJECT (overlay, "font description set: %s", fontdesc_str);
+ pango_layout_set_font_description (overlay->layout, desc);
+ gst_base_text_overlay_adjust_values_with_fontdesc (overlay, desc);
+ pango_font_description_free (desc);
+ } else {
+ GST_WARNING_OBJECT (overlay, "font description parse failed: %s",
+ fontdesc_str);
+ }
+ g_mutex_unlock (GST_BASE_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
+ break;
+ }
+ case PROP_COLOR:
+ overlay->color = g_value_get_uint (value);
+ break;
+ case PROP_OUTLINE_COLOR:
+ overlay->outline_color = g_value_get_uint (value);
+ break;
+ case PROP_SILENT:
+ overlay->silent = g_value_get_boolean (value);
+ break;
+ case PROP_LINE_ALIGNMENT:
+ overlay->line_align = g_value_get_enum (value);
+ g_mutex_lock (GST_BASE_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
+ pango_layout_set_alignment (overlay->layout,
+ (PangoAlignment) overlay->line_align);
+ g_mutex_unlock (GST_BASE_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
+ break;
+ case PROP_WAIT_TEXT:
+ overlay->wait_text = g_value_get_boolean (value);
+ break;
+ case PROP_AUTO_ADJUST_SIZE:
+ overlay->auto_adjust_size = g_value_get_boolean (value);
+ overlay->need_render = TRUE;
+ break;
+ case PROP_VERTICAL_RENDER:
+ overlay->use_vertical_render = g_value_get_boolean (value);
+ g_mutex_lock (GST_BASE_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
+ gst_base_text_overlay_update_render_mode (overlay);
+ g_mutex_unlock (GST_BASE_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
+ overlay->need_render = TRUE;
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+
+ overlay->need_render = TRUE;
+ GST_OBJECT_UNLOCK (overlay);
+}
+
+static void
+gst_base_text_overlay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstBaseTextOverlay *overlay = GST_BASE_TEXT_OVERLAY (object);
+
+ GST_OBJECT_LOCK (overlay);
+ switch (prop_id) {
+ case PROP_TEXT:
+ g_value_set_string (value, overlay->default_text);
+ break;
+ case PROP_SHADING:
+ g_value_set_boolean (value, overlay->want_shading);
+ break;
+ case PROP_XPAD:
+ g_value_set_int (value, overlay->xpad);
+ break;
+ case PROP_YPAD:
+ g_value_set_int (value, overlay->ypad);
+ break;
+ case PROP_DELTAX:
+ g_value_set_int (value, overlay->deltax);
+ break;
+ case PROP_DELTAY:
+ g_value_set_int (value, overlay->deltay);
+ break;
+ case PROP_XPOS:
+ g_value_set_double (value, overlay->xpos);
+ break;
+ case PROP_YPOS:
+ g_value_set_double (value, overlay->ypos);
+ break;
+ case PROP_VALIGNMENT:
+ g_value_set_enum (value, overlay->valign);
+ break;
+ case PROP_HALIGNMENT:
+ g_value_set_enum (value, overlay->halign);
+ break;
+ case PROP_WRAP_MODE:
+ g_value_set_enum (value, overlay->wrap_mode);
+ break;
+ case PROP_SILENT:
+ g_value_set_boolean (value, overlay->silent);
+ break;
+ case PROP_LINE_ALIGNMENT:
+ g_value_set_enum (value, overlay->line_align);
+ break;
+ case PROP_WAIT_TEXT:
+ g_value_set_boolean (value, overlay->wait_text);
+ break;
+ case PROP_AUTO_ADJUST_SIZE:
+ g_value_set_boolean (value, overlay->auto_adjust_size);
+ break;
+ case PROP_VERTICAL_RENDER:
+ g_value_set_boolean (value, overlay->use_vertical_render);
+ break;
+ case PROP_COLOR:
+ g_value_set_uint (value, overlay->color);
+ break;
+ case PROP_OUTLINE_COLOR:
+ g_value_set_uint (value, overlay->outline_color);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+
+ overlay->need_render = TRUE;
+ GST_OBJECT_UNLOCK (overlay);
+}
+
+static gboolean
+gst_base_text_overlay_src_query (GstPad * pad, GstQuery * query)
+{
+ gboolean ret = FALSE;
+ GstBaseTextOverlay *overlay = NULL;
+
+ overlay = GST_BASE_TEXT_OVERLAY (gst_pad_get_parent (pad));
+
+ ret = gst_pad_peer_query (overlay->video_sinkpad, query);
+
+ gst_object_unref (overlay);
+
+ return ret;
+}
+
+static gboolean
+gst_base_text_overlay_src_event (GstPad * pad, GstEvent * event)
+{
+ gboolean ret = FALSE;
+ GstBaseTextOverlay *overlay = NULL;
+
+ overlay = GST_BASE_TEXT_OVERLAY (gst_pad_get_parent (pad));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_SEEK:{
+ GstSeekFlags flags;
+
+ /* We don't handle seek if we have not text pad */
+ if (!overlay->text_linked) {
+ GST_DEBUG_OBJECT (overlay, "seek received, pushing upstream");
+ ret = gst_pad_push_event (overlay->video_sinkpad, event);
+ goto beach;
+ }
+
+ GST_DEBUG_OBJECT (overlay, "seek received, driving from here");
+
+ gst_event_parse_seek (event, NULL, NULL, &flags, NULL, NULL, NULL, NULL);
+
+ /* Flush downstream, only for flushing seek */
+ if (flags & GST_SEEK_FLAG_FLUSH)
+ gst_pad_push_event (overlay->srcpad, gst_event_new_flush_start ());
+
+ /* Mark ourself as flushing, unblock chains */
+ GST_OBJECT_LOCK (overlay);
+ overlay->video_flushing = TRUE;
+ overlay->text_flushing = TRUE;
+ gst_base_text_overlay_pop_text (overlay);
+ GST_OBJECT_UNLOCK (overlay);
+
+ /* Seek on each sink pad */
+ gst_event_ref (event);
+ ret = gst_pad_push_event (overlay->video_sinkpad, event);
+ if (ret) {
+ ret = gst_pad_push_event (overlay->text_sinkpad, event);
+ } else {
+ gst_event_unref (event);
+ }
+ break;
+ }
+ default:
+ if (overlay->text_linked) {
+ gst_event_ref (event);
+ ret = gst_pad_push_event (overlay->video_sinkpad, event);
+ gst_pad_push_event (overlay->text_sinkpad, event);
+ } else {
+ ret = gst_pad_push_event (overlay->video_sinkpad, event);
+ }
+ break;
+ }
+
+beach:
+ gst_object_unref (overlay);
+
+ return ret;
+}
+
+static GstCaps *
+gst_base_text_overlay_getcaps (GstPad * pad, GstCaps * filter)
+{
+ GstBaseTextOverlay *overlay;
+ GstPad *otherpad;
+ GstCaps *caps;
+
+ overlay = GST_BASE_TEXT_OVERLAY (gst_pad_get_parent (pad));
+
+ if (pad == overlay->srcpad)
+ otherpad = overlay->video_sinkpad;
+ else
+ otherpad = overlay->srcpad;
+
+ /* we can do what the peer can */
+ caps = gst_pad_peer_get_caps (otherpad, filter);
+ if (caps) {
+ GstCaps *temp, *templ;
+
+ GST_DEBUG_OBJECT (pad, "peer caps %" GST_PTR_FORMAT, caps);
+
+ /* filtered against our padtemplate */
+ templ = gst_pad_get_pad_template_caps (otherpad);
+ GST_DEBUG_OBJECT (pad, "our template %" GST_PTR_FORMAT, templ);
+ temp = gst_caps_intersect_full (caps, templ, GST_CAPS_INTERSECT_FIRST);
+ GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
+ gst_caps_unref (caps);
+ gst_caps_unref (templ);
+ /* this is what we can do */
+ caps = temp;
+ } else {
+ /* no peer, our padtemplate is enough then */
+ caps = gst_pad_get_pad_template_caps (pad);
+ if (filter) {
+ GstCaps *intersection;
+
+ intersection =
+ gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+ gst_caps_unref (caps);
+ caps = intersection;
+ }
+ }
+
+ GST_DEBUG_OBJECT (overlay, "returning %" GST_PTR_FORMAT, caps);
+
+ gst_object_unref (overlay);
+
+ return caps;
+}
+
+static void
+gst_base_text_overlay_adjust_values_with_fontdesc (GstBaseTextOverlay * overlay,
+ PangoFontDescription * desc)
+{
+ gint font_size = pango_font_description_get_size (desc) / PANGO_SCALE;
+ overlay->shadow_offset = (double) (font_size) / 13.0;
+ overlay->outline_offset = (double) (font_size) / 15.0;
+ if (overlay->outline_offset < MINIMUM_OUTLINE_OFFSET)
+ overlay->outline_offset = MINIMUM_OUTLINE_OFFSET;
+}
+
+#define CAIRO_UNPREMULTIPLY(a,r,g,b) G_STMT_START { \
+ b = (a > 0) ? MIN ((b * 255 + a / 2) / a, 255) : 0; \
+ g = (a > 0) ? MIN ((g * 255 + a / 2) / a, 255) : 0; \
+ r = (a > 0) ? MIN ((r * 255 + a / 2) / a, 255) : 0; \
+} G_STMT_END
+
+static inline void
+gst_base_text_overlay_blit_1 (GstBaseTextOverlay * overlay, guchar * dest,
+ gint xpos, gint ypos, guchar * text_image, guint dest_stride)
+{
+ gint i, j = 0;
+ gint x, y;
+ guchar r, g, b, a;
+ guchar *pimage;
+ guchar *py;
+ gint width = overlay->image_width;
+ gint height = overlay->image_height;
+
+ if (xpos < 0) {
+ xpos = 0;
+ }
+
+ if (xpos + width > overlay->width) {
+ width = overlay->width - xpos;
+ }
+
+ if (ypos + height > overlay->height) {
+ height = overlay->height - ypos;
+ }
+
+ dest += (ypos / 1) * dest_stride;
+
+ for (i = 0; i < height; i++) {
+ pimage = text_image + 4 * (i * overlay->image_width);
+ py = dest + i * dest_stride + xpos;
+ for (j = 0; j < width; j++) {
+ b = pimage[CAIRO_ARGB_B];
+ g = pimage[CAIRO_ARGB_G];
+ r = pimage[CAIRO_ARGB_R];
+ a = pimage[CAIRO_ARGB_A];
+ CAIRO_UNPREMULTIPLY (a, r, g, b);
+
+ pimage += 4;
+ if (a == 0) {
+ py++;
+ continue;
+ }
+ COMP_Y (y, r, g, b);
+ x = *py;
+ BLEND (*py++, a, y, x);
+ }
+ }
+}
+
+static inline void
+gst_base_text_overlay_blit_sub2x2cbcr (GstBaseTextOverlay * overlay,
+ guchar * destcb, guchar * destcr, gint xpos, gint ypos, guchar * text_image,
+ guint destcb_stride, guint destcr_stride, guint pix_stride)
+{
+ gint i, j;
+ gint x, cb, cr;
+ gushort r, g, b, a;
+ gushort r1, g1, b1, a1;
+ guchar *pimage1, *pimage2;
+ guchar *pcb, *pcr;
+ gint width = overlay->image_width - 2;
+ gint height = overlay->image_height - 2;
+
+ xpos *= pix_stride;
+
+ if (xpos < 0) {
+ xpos = 0;
+ }
+
+ if (xpos + width > overlay->width) {
+ width = overlay->width - xpos;
+ }
+
+ if (ypos + height > overlay->height) {
+ height = overlay->height - ypos;
+ }
+
+ destcb += (ypos / 2) * destcb_stride;
+ destcr += (ypos / 2) * destcr_stride;
+
+ for (i = 0; i < height; i += 2) {
+ pimage1 = text_image + 4 * (i * overlay->image_width);
+ pimage2 = pimage1 + 4 * overlay->image_width;
+ pcb = destcb + (i / 2) * destcb_stride + xpos / 2;
+ pcr = destcr + (i / 2) * destcr_stride + xpos / 2;
+ for (j = 0; j < width; j += 2) {
+ b = pimage1[CAIRO_ARGB_B];
+ g = pimage1[CAIRO_ARGB_G];
+ r = pimage1[CAIRO_ARGB_R];
+ a = pimage1[CAIRO_ARGB_A];
+ CAIRO_UNPREMULTIPLY (a, r, g, b);
+ pimage1 += 4;
+
+ b1 = pimage1[CAIRO_ARGB_B];
+ g1 = pimage1[CAIRO_ARGB_G];
+ r1 = pimage1[CAIRO_ARGB_R];
+ a1 = pimage1[CAIRO_ARGB_A];
+ CAIRO_UNPREMULTIPLY (a1, r1, g1, b1);
+ b += b1;
+ g += g1;
+ r += r1;
+ a += a1;
+ pimage1 += 4;
+
+ b1 = pimage2[CAIRO_ARGB_B];
+ g1 = pimage2[CAIRO_ARGB_G];
+ r1 = pimage2[CAIRO_ARGB_R];
+ a1 = pimage2[CAIRO_ARGB_A];
+ CAIRO_UNPREMULTIPLY (a1, r1, g1, b1);
+ b += b1;
+ g += g1;
+ r += r1;
+ a += a1;
+ pimage2 += 4;
+
+ /* + 2 for rounding */
+ b1 = pimage2[CAIRO_ARGB_B];
+ g1 = pimage2[CAIRO_ARGB_G];
+ r1 = pimage2[CAIRO_ARGB_R];
+ a1 = pimage2[CAIRO_ARGB_A];
+ CAIRO_UNPREMULTIPLY (a1, r1, g1, b1);
+ b += b1 + 2;
+ g += g1 + 2;
+ r += r1 + 2;
+ a += a1 + 2;
+ pimage2 += 4;
+
+ b /= 4;
+ g /= 4;
+ r /= 4;
+ a /= 4;
+
+ if (a == 0) {
+ pcb += pix_stride;
+ pcr += pix_stride;
+ continue;
+ }
+ COMP_U (cb, r, g, b);
+ COMP_V (cr, r, g, b);
+
+ x = *pcb;
+ BLEND (*pcb, a, cb, x);
+ x = *pcr;
+ BLEND (*pcr, a, cr, x);
+
+ pcb += pix_stride;
+ pcr += pix_stride;
+ }
+ }
+}
+
+static void
+gst_base_text_overlay_render_pangocairo (GstBaseTextOverlay * overlay,
+ const gchar * string, gint textlen)
+{
+ cairo_t *cr;
+ cairo_surface_t *surface;
+ PangoRectangle ink_rect, logical_rect;
+ cairo_matrix_t cairo_matrix;
+ int width, height;
+ double scalef = 1.0;
+ double a, r, g, b;
+
+ g_mutex_lock (GST_BASE_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
+
+ if (overlay->auto_adjust_size) {
+ /* 640 pixel is default */
+ scalef = (double) (overlay->width) / DEFAULT_SCALE_BASIS;
+ }
+ pango_layout_set_width (overlay->layout, -1);
+ /* set text on pango layout */
+ pango_layout_set_markup (overlay->layout, string, textlen);
+
+ /* get subtitle image size */
+ pango_layout_get_pixel_extents (overlay->layout, &ink_rect, &logical_rect);
+
+ width = (logical_rect.width + overlay->shadow_offset) * scalef;
+
+ if (width + overlay->deltax >
+ (overlay->use_vertical_render ? overlay->height : overlay->width)) {
+ /*
+ * subtitle image width is larger then overlay width
+ * so rearrange overlay wrap mode.
+ */
+ gst_base_text_overlay_update_wrap_mode (overlay);
+ pango_layout_get_pixel_extents (overlay->layout, &ink_rect, &logical_rect);
+ width = overlay->width;
+ }
+
+ height =
+ (logical_rect.height + logical_rect.y + overlay->shadow_offset) * scalef;
+ if (height > overlay->height) {
+ height = overlay->height;
+ }
+ if (overlay->use_vertical_render) {
+ PangoRectangle rect;
+ PangoContext *context;
+ PangoMatrix matrix = PANGO_MATRIX_INIT;
+ int tmp;
+
+ context = pango_layout_get_context (overlay->layout);
+
+ pango_matrix_rotate (&matrix, -90);
+
+ rect.x = rect.y = 0;
+ rect.width = width;
+ rect.height = height;
+ pango_matrix_transform_pixel_rectangle (&matrix, &rect);
+ matrix.x0 = -rect.x;
+ matrix.y0 = -rect.y;
+
+ pango_context_set_matrix (context, &matrix);
+
+ cairo_matrix.xx = matrix.xx;
+ cairo_matrix.yx = matrix.yx;
+ cairo_matrix.xy = matrix.xy;
+ cairo_matrix.yy = matrix.yy;
+ cairo_matrix.x0 = matrix.x0;
+ cairo_matrix.y0 = matrix.y0;
+ cairo_matrix_scale (&cairo_matrix, scalef, scalef);
+
+ tmp = height;
+ height = width;
+ width = tmp;
+ } else {
+ cairo_matrix_init_scale (&cairo_matrix, scalef, scalef);
+ }
+
+ /* reallocate surface */
+ overlay->text_image = g_realloc (overlay->text_image, 4 * width * height);
+
+ surface = cairo_image_surface_create_for_data (overlay->text_image,
+ CAIRO_FORMAT_ARGB32, width, height, width * 4);
+ cr = cairo_create (surface);
+
+ /* clear surface */
+ cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
+ cairo_paint (cr);
+
+ cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+
+ if (overlay->want_shading)
+ cairo_paint_with_alpha (cr, overlay->shading_value);
+
+ /* apply transformations */
+ cairo_set_matrix (cr, &cairo_matrix);
+
+ /* FIXME: We use show_layout everywhere except for the surface
+ * because it's really faster and internally does all kinds of
+ * caching. Unfortunately we have to paint to a cairo path for
+ * the outline and this is slow. Once Pango supports user fonts
+ * we should use them, see
+ * https://bugzilla.gnome.org/show_bug.cgi?id=598695
+ *
+ * Idea would the be, to create a cairo user font that
+ * does shadow, outline, text painting in the
+ * render_glyph function.
+ */
+
+ /* draw shadow text */
+ cairo_save (cr);
+ cairo_translate (cr, overlay->shadow_offset, overlay->shadow_offset);
+ cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.5);
+ pango_cairo_show_layout (cr, overlay->layout);
+ cairo_restore (cr);
+
+ a = (overlay->outline_color >> 24) & 0xff;
+ r = (overlay->outline_color >> 16) & 0xff;
+ g = (overlay->outline_color >> 8) & 0xff;
+ b = (overlay->outline_color >> 0) & 0xff;
+
+ /* draw outline text */
+ cairo_save (cr);
+ cairo_set_source_rgba (cr, r / 255.0, g / 255.0, b / 255.0, a / 255.0);
+ cairo_set_line_width (cr, overlay->outline_offset);
+ pango_cairo_layout_path (cr, overlay->layout);
+ cairo_stroke (cr);
+ cairo_restore (cr);
+
+ a = (overlay->color >> 24) & 0xff;
+ r = (overlay->color >> 16) & 0xff;
+ g = (overlay->color >> 8) & 0xff;
+ b = (overlay->color >> 0) & 0xff;
+
+ /* draw text */
+ cairo_save (cr);
+ cairo_set_source_rgba (cr, r / 255.0, g / 255.0, b / 255.0, a / 255.0);
+ pango_cairo_show_layout (cr, overlay->layout);
+ cairo_restore (cr);
+
+ cairo_destroy (cr);
+ cairo_surface_destroy (surface);
+ overlay->image_width = width;
+ overlay->image_height = height;
+ overlay->baseline_y = ink_rect.y;
+ g_mutex_unlock (GST_BASE_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
+}
+
+#define BOX_XPAD 6
+#define BOX_YPAD 6
+
+static inline void
+gst_base_text_overlay_shade_planar_Y (GstBaseTextOverlay * overlay,
+ guchar * dest, gint x0, gint x1, gint y0, gint y1)
+{
+ gint i, j, dest_stride;
+
+ dest_stride = gst_video_format_get_row_stride (overlay->format, 0,
+ overlay->width);
+
+ x0 = CLAMP (x0 - BOX_XPAD, 0, overlay->width);
+ x1 = CLAMP (x1 + BOX_XPAD, 0, overlay->width);
+
+ y0 = CLAMP (y0 - BOX_YPAD, 0, overlay->height);
+ y1 = CLAMP (y1 + BOX_YPAD, 0, overlay->height);
+
+ for (i = y0; i < y1; ++i) {
+ for (j = x0; j < x1; ++j) {
+ gint y = dest[(i * dest_stride) + j] + overlay->shading_value;
+
+ dest[(i * dest_stride) + j] = CLAMP (y, 0, 255);
+ }
+ }
+}
+
+static inline void
+gst_base_text_overlay_shade_packed_Y (GstBaseTextOverlay * overlay,
+ guchar * dest, gint x0, gint x1, gint y0, gint y1)
+{
+ gint i, j;
+ guint dest_stride, pixel_stride, component_offset;
+
+ dest_stride = gst_video_format_get_row_stride (overlay->format, 0,
+ overlay->width);
+ pixel_stride = gst_video_format_get_pixel_stride (overlay->format, 0);
+ component_offset =
+ gst_video_format_get_component_offset (overlay->format, 0, overlay->width,
+ overlay->height);
+
+ x0 = CLAMP (x0 - BOX_XPAD, 0, overlay->width);
+ x1 = CLAMP (x1 + BOX_XPAD, 0, overlay->width);
+
+ y0 = CLAMP (y0 - BOX_YPAD, 0, overlay->height);
+ y1 = CLAMP (y1 + BOX_YPAD, 0, overlay->height);
+
+ if (x0 != 0)
+ x0 = gst_video_format_get_component_width (overlay->format, 0, x0);
+ if (x1 != 0)
+ x1 = gst_video_format_get_component_width (overlay->format, 0, x1);
+
+ if (y0 != 0)
+ y0 = gst_video_format_get_component_height (overlay->format, 0, y0);
+ if (y1 != 0)
+ y1 = gst_video_format_get_component_height (overlay->format, 0, y1);
+
+ for (i = y0; i < y1; i++) {
+ for (j = x0; j < x1; j++) {
+ gint y;
+ gint y_pos;
+
+ y_pos = (i * dest_stride) + j * pixel_stride + component_offset;
+ y = dest[y_pos] + overlay->shading_value;
+
+ dest[y_pos] = CLAMP (y, 0, 255);
+ }
+ }
+}
+
+#define gst_base_text_overlay_shade_BGRx gst_base_text_overlay_shade_xRGB
+#define gst_base_text_overlay_shade_RGBx gst_base_text_overlay_shade_xRGB
+#define gst_base_text_overlay_shade_xBGR gst_base_text_overlay_shade_xRGB
+static inline void
+gst_base_text_overlay_shade_xRGB (GstBaseTextOverlay * overlay, guchar * dest,
+ gint x0, gint x1, gint y0, gint y1)
+{
+ gint i, j;
+
+ x0 = CLAMP (x0 - BOX_XPAD, 0, overlay->width);
+ x1 = CLAMP (x1 + BOX_XPAD, 0, overlay->width);
+
+ y0 = CLAMP (y0 - BOX_YPAD, 0, overlay->height);
+ y1 = CLAMP (y1 + BOX_YPAD, 0, overlay->height);
+
+ for (i = y0; i < y1; i++) {
+ for (j = x0; j < x1; j++) {
+ gint y, y_pos, k;
+
+ y_pos = (i * 4 * overlay->width) + j * 4;
+ for (k = 0; k < 4; k++) {
+ y = dest[y_pos + k] + overlay->shading_value;
+ dest[y_pos + k] = CLAMP (y, 0, 255);
+ }
+ }
+ }
+}
+
+#define ARGB_SHADE_FUNCTION(name, OFFSET) \
+static inline void \
+gst_base_text_overlay_shade_##name (GstBaseTextOverlay * overlay, guchar * dest, \
+gint x0, gint x1, gint y0, gint y1) \
+{ \
+ gint i, j;\
+ \
+ x0 = CLAMP (x0 - BOX_XPAD, 0, overlay->width);\
+ x1 = CLAMP (x1 + BOX_XPAD, 0, overlay->width);\
+ \
+ y0 = CLAMP (y0 - BOX_YPAD, 0, overlay->height);\
+ y1 = CLAMP (y1 + BOX_YPAD, 0, overlay->height);\
+ \
+ for (i = y0; i < y1; i++) {\
+ for (j = x0; j < x1; j++) {\
+ gint y, y_pos, k;\
+ y_pos = (i * 4 * overlay->width) + j * 4;\
+ for (k = OFFSET; k < 3+OFFSET; k++) {\
+ y = dest[y_pos + k] + overlay->shading_value;\
+ dest[y_pos + k] = CLAMP (y, 0, 255);\
+ }\
+ }\
+ }\
+}
+ARGB_SHADE_FUNCTION (ARGB, 1);
+ARGB_SHADE_FUNCTION (ABGR, 1);
+ARGB_SHADE_FUNCTION (RGBA, 0);
+ARGB_SHADE_FUNCTION (BGRA, 0);
+
+
+/* FIXME:
+ * - use proper strides and offset for I420
+ * - don't draw over the edge of the picture (try a longer
+ * text with a huge font size)
+ */
+
+static inline void
+gst_base_text_overlay_blit_NV12_NV21 (GstBaseTextOverlay * overlay,
+ guint8 * yuv_pixels, gint xpos, gint ypos)
+{
+ int y_stride, uv_stride;
+ int u_offset, v_offset;
+ int h, w;
+
+ /* because U/V is 2x2 subsampled, we need to round, either up or down,
+ * to a boundary of integer number of U/V pixels:
+ */
+ xpos = GST_ROUND_UP_2 (xpos);
+ ypos = GST_ROUND_UP_2 (ypos);
+
+ w = overlay->width;
+ h = overlay->height;
+
+ y_stride = gst_video_format_get_row_stride (overlay->format, 0, w);
+ uv_stride = gst_video_format_get_row_stride (overlay->format, 1, w);
+ u_offset = gst_video_format_get_component_offset (overlay->format, 1, w, h);
+ v_offset = gst_video_format_get_component_offset (overlay->format, 2, w, h);
+
+ gst_base_text_overlay_blit_1 (overlay, yuv_pixels, xpos, ypos,
+ overlay->text_image, y_stride);
+ gst_base_text_overlay_blit_sub2x2cbcr (overlay, yuv_pixels + u_offset,
+ yuv_pixels + v_offset, xpos, ypos, overlay->text_image, uv_stride,
+ uv_stride, 2);
+}
+
+static inline void
+gst_base_text_overlay_blit_I420 (GstBaseTextOverlay * overlay,
+ guint8 * yuv_pixels, gint xpos, gint ypos)
+{
+ int y_stride, u_stride, v_stride;
+ int u_offset, v_offset;
+ int h, w;
+
+ /* because U/V is 2x2 subsampled, we need to round, either up or down,
+ * to a boundary of integer number of U/V pixels:
+ */
+ xpos = GST_ROUND_UP_2 (xpos);
+ ypos = GST_ROUND_UP_2 (ypos);
+
+ w = overlay->width;
+ h = overlay->height;
+
+ y_stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 0, w);
+ u_stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 1, w);
+ v_stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 2, w);
+ u_offset =
+ gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 1, w, h);
+ v_offset =
+ gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 2, w, h);
+
+ gst_base_text_overlay_blit_1 (overlay, yuv_pixels, xpos, ypos,
+ overlay->text_image, y_stride);
+ gst_base_text_overlay_blit_sub2x2cbcr (overlay, yuv_pixels + u_offset,
+ yuv_pixels + v_offset, xpos, ypos, overlay->text_image, u_stride,
+ v_stride, 1);
+}
+
+static inline void
+gst_base_text_overlay_blit_UYVY (GstBaseTextOverlay * overlay,
+ guint8 * yuv_pixels, gint xpos, gint ypos)
+{
+ int a0, r0, g0, b0;
+ int a1, r1, g1, b1;
+ int y0, y1, u, v;
+ int i, j;
+ int h, w;
+ guchar *pimage, *dest;
+
+ /* because U/V is 2x horizontally subsampled, we need to round to a
+ * boundary of integer number of U/V pixels in x dimension:
+ */
+ xpos = GST_ROUND_UP_2 (xpos);
+
+ w = overlay->image_width - 2;
+ h = overlay->image_height - 2;
+
+ if (xpos < 0) {
+ xpos = 0;
+ }
+
+ if (xpos + w > overlay->width) {
+ w = overlay->width - xpos;
+ }
+
+ if (ypos + h > overlay->height) {
+ h = overlay->height - ypos;
+ }
+
+ for (i = 0; i < h; i++) {
+ pimage = overlay->text_image + i * overlay->image_width * 4;
+ dest = yuv_pixels + (i + ypos) * overlay->width * 2 + xpos * 2;
+ for (j = 0; j < w; j += 2) {
+ b0 = pimage[CAIRO_ARGB_B];
+ g0 = pimage[CAIRO_ARGB_G];
+ r0 = pimage[CAIRO_ARGB_R];
+ a0 = pimage[CAIRO_ARGB_A];
+ CAIRO_UNPREMULTIPLY (a0, r0, g0, b0);
+ pimage += 4;
+
+ b1 = pimage[CAIRO_ARGB_B];
+ g1 = pimage[CAIRO_ARGB_G];
+ r1 = pimage[CAIRO_ARGB_R];
+ a1 = pimage[CAIRO_ARGB_A];
+ CAIRO_UNPREMULTIPLY (a1, r1, g1, b1);
+ pimage += 4;
+
+ a0 += a1 + 2;
+ a0 /= 2;
+ if (a0 == 0) {
+ dest += 4;
+ continue;
+ }
+
+ COMP_Y (y0, r0, g0, b0);
+ COMP_Y (y1, r1, g1, b1);
+
+ b0 += b1 + 2;
+ g0 += g1 + 2;
+ r0 += r1 + 2;
+
+ b0 /= 2;
+ g0 /= 2;
+ r0 /= 2;
+
+ COMP_U (u, r0, g0, b0);
+ COMP_V (v, r0, g0, b0);
+
+ BLEND (*dest, a0, u, *dest);
+ dest++;
+ BLEND (*dest, a0, y0, *dest);
+ dest++;
+ BLEND (*dest, a0, v, *dest);
+ dest++;
+ BLEND (*dest, a0, y1, *dest);
+ dest++;
+ }
+ }
+}
+
+static inline void
+gst_base_text_overlay_blit_AYUV (GstBaseTextOverlay * overlay,
+ guint8 * rgb_pixels, gint xpos, gint ypos)
+{
+ int a, r, g, b, a1;
+ int y, u, v;
+ int i, j;
+ int h, w;
+ guchar *pimage, *dest;
+
+ w = overlay->image_width;
+ h = overlay->image_height;
+
+ if (xpos < 0) {
+ xpos = 0;
+ }
+
+ if (xpos + w > overlay->width) {
+ w = overlay->width - xpos;
+ }
+
+ if (ypos + h > overlay->height) {
+ h = overlay->height - ypos;
+ }
+
+ for (i = 0; i < h; i++) {
+ pimage = overlay->text_image + i * overlay->image_width * 4;
+ dest = rgb_pixels + (i + ypos) * 4 * overlay->width + xpos * 4;
+ for (j = 0; j < w; j++) {
+ a = pimage[CAIRO_ARGB_A];
+ b = pimage[CAIRO_ARGB_B];
+ g = pimage[CAIRO_ARGB_G];
+ r = pimage[CAIRO_ARGB_R];
+
+ CAIRO_UNPREMULTIPLY (a, r, g, b);
+
+ // convert background to yuv
+ COMP_Y (y, r, g, b);
+ COMP_U (u, r, g, b);
+ COMP_V (v, r, g, b);
+
+ // preform text "OVER" background alpha compositing
+ a1 = a + (dest[0] * (255 - a)) / 255 + 1; // add 1 to prevent divide by 0
+ OVER (dest[1], a, y, dest[0], dest[1], a1);
+ OVER (dest[2], a, u, dest[0], dest[2], a1);
+ OVER (dest[3], a, v, dest[0], dest[3], a1);
+ dest[0] = a1 - 1; // remove the temporary 1 we added
+
+ pimage += 4;
+ dest += 4;
+ }
+ }
+}
+
+#define xRGB_BLIT_FUNCTION(name, R, G, B) \
+static inline void \
+gst_base_text_overlay_blit_##name (GstBaseTextOverlay * overlay, \
+ guint8 * rgb_pixels, gint xpos, gint ypos) \
+{ \
+ int a, r, g, b; \
+ int i, j; \
+ int h, w; \
+ guchar *pimage, *dest; \
+ \
+ w = overlay->image_width; \
+ h = overlay->image_height; \
+ \
+ if (xpos < 0) { \
+ xpos = 0; \
+ } \
+ \
+ if (xpos + w > overlay->width) { \
+ w = overlay->width - xpos; \
+ } \
+ \
+ if (ypos + h > overlay->height) { \
+ h = overlay->height - ypos; \
+ } \
+ \
+ for (i = 0; i < h; i++) { \
+ pimage = overlay->text_image + i * overlay->image_width * 4; \
+ dest = rgb_pixels + (i + ypos) * 4 * overlay->width + xpos * 4; \
+ for (j = 0; j < w; j++) { \
+ a = pimage[CAIRO_ARGB_A]; \
+ b = pimage[CAIRO_ARGB_B]; \
+ g = pimage[CAIRO_ARGB_G]; \
+ r = pimage[CAIRO_ARGB_R]; \
+ CAIRO_UNPREMULTIPLY (a, r, g, b); \
+ b = (b*a + dest[B] * (255-a)) / 255; \
+ g = (g*a + dest[G] * (255-a)) / 255; \
+ r = (r*a + dest[R] * (255-a)) / 255; \
+ \
+ dest[B] = b; \
+ dest[G] = g; \
+ dest[R] = r; \
+ pimage += 4; \
+ dest += 4; \
+ } \
+ } \
+}
+xRGB_BLIT_FUNCTION (xRGB, 1, 2, 3);
+xRGB_BLIT_FUNCTION (BGRx, 2, 1, 0);
+xRGB_BLIT_FUNCTION (xBGR, 3, 2, 1);
+xRGB_BLIT_FUNCTION (RGBx, 0, 1, 2);
+
+#define ARGB_BLIT_FUNCTION(name, A, R, G, B) \
+static inline void \
+gst_base_text_overlay_blit_##name (GstBaseTextOverlay * overlay, \
+ guint8 * rgb_pixels, gint xpos, gint ypos) \
+{ \
+ int a, r, g, b, a1; \
+ int i, j; \
+ int h, w; \
+ guchar *pimage, *dest; \
+ \
+ w = overlay->image_width; \
+ h = overlay->image_height; \
+ \
+ if (xpos < 0) { \
+ xpos = 0; \
+ } \
+ \
+ if (xpos + w > overlay->width) { \
+ w = overlay->width - xpos; \
+ } \
+ \
+ if (ypos + h > overlay->height) { \
+ h = overlay->height - ypos; \
+ } \
+ \
+ for (i = 0; i < h; i++) { \
+ pimage = overlay->text_image + i * overlay->image_width * 4; \
+ dest = rgb_pixels + (i + ypos) * 4 * overlay->width + xpos * 4; \
+ for (j = 0; j < w; j++) { \
+ a = pimage[CAIRO_ARGB_A]; \
+ b = pimage[CAIRO_ARGB_B]; \
+ g = pimage[CAIRO_ARGB_G]; \
+ r = pimage[CAIRO_ARGB_R]; \
+ CAIRO_UNPREMULTIPLY (a, r, g, b); \
+ a1 = a + (dest[A] * (255 - a)) / 255 + 1; \
+ OVER (dest[R], a, r, dest[0], dest[R], a1); \
+ OVER (dest[G], a, g, dest[0], dest[G], a1); \
+ OVER (dest[B], a, b, dest[0], dest[B], a1); \
+ dest[A] = a1 - 1; \
+ pimage += 4; \
+ dest += 4; \
+ } \
+ } \
+}
+ARGB_BLIT_FUNCTION (RGBA, 3, 0, 1, 2);
+ARGB_BLIT_FUNCTION (BGRA, 3, 2, 1, 0);
+ARGB_BLIT_FUNCTION (ARGB, 0, 1, 2, 3);
+ARGB_BLIT_FUNCTION (ABGR, 0, 3, 2, 1);
+
+static void
+gst_base_text_overlay_render_text (GstBaseTextOverlay * overlay,
+ const gchar * text, gint textlen)
+{
+ gchar *string;
+
+ if (!overlay->need_render) {
+ GST_DEBUG ("Using previously rendered text.");
+ return;
+ }
+
+ /* -1 is the whole string */
+ if (text != NULL && textlen < 0) {
+ textlen = strlen (text);
+ }
+
+ if (text != NULL) {
+ string = g_strndup (text, textlen);
+ } else { /* empty string */
+ string = g_strdup (" ");
+ }
+ g_strdelimit (string, "\r\t", ' ');
+ textlen = strlen (string);
+
+ /* FIXME: should we check for UTF-8 here? */
+
+ GST_DEBUG ("Rendering '%s'", string);
+ gst_base_text_overlay_render_pangocairo (overlay, string, textlen);
+
+ g_free (string);
+
+ overlay->need_render = FALSE;
+}
+
+static GstFlowReturn
+gst_base_text_overlay_push_frame (GstBaseTextOverlay * overlay,
+ GstBuffer * video_frame)
+{
+ gint xpos, ypos;
+ gint width, height;
+ GstBaseTextOverlayVAlign valign;
+ GstBaseTextOverlayHAlign halign;
+ guint8 *data;
+ gsize size;
+
+ width = overlay->image_width;
+ height = overlay->image_height;
+
+ video_frame = gst_buffer_make_writable (video_frame);
+
+ data = gst_buffer_map (video_frame, &size, NULL, GST_MAP_WRITE);
+
+ if (overlay->use_vertical_render)
+ halign = GST_BASE_TEXT_OVERLAY_HALIGN_RIGHT;
+ else
+ halign = overlay->halign;
+
+ switch (halign) {
+ case GST_BASE_TEXT_OVERLAY_HALIGN_LEFT:
+ xpos = overlay->xpad;
+ break;
+ case GST_BASE_TEXT_OVERLAY_HALIGN_CENTER:
+ xpos = (overlay->width - width) / 2;
+ break;
+ case GST_BASE_TEXT_OVERLAY_HALIGN_RIGHT:
+ xpos = overlay->width - width - overlay->xpad;
+ break;
+ case GST_BASE_TEXT_OVERLAY_HALIGN_POS:
+ xpos = (gint) (overlay->width * overlay->xpos) - width / 2;
+ xpos = CLAMP (xpos, 0, overlay->width - width);
+ if (xpos < 0)
+ xpos = 0;
+ break;
+ default:
+ xpos = 0;
+ }
+ xpos += overlay->deltax;
+
+ if (overlay->use_vertical_render)
+ valign = GST_BASE_TEXT_OVERLAY_VALIGN_TOP;
+ else
+ valign = overlay->valign;
+
+ switch (valign) {
+ case GST_BASE_TEXT_OVERLAY_VALIGN_BOTTOM:
+ ypos = overlay->height - height - overlay->ypad;
+ break;
+ case GST_BASE_TEXT_OVERLAY_VALIGN_BASELINE:
+ ypos = overlay->height - (height + overlay->ypad);
+ break;
+ case GST_BASE_TEXT_OVERLAY_VALIGN_TOP:
+ ypos = overlay->ypad;
+ break;
+ case GST_BASE_TEXT_OVERLAY_VALIGN_POS:
+ ypos = (gint) (overlay->height * overlay->ypos) - height / 2;
+ ypos = CLAMP (ypos, 0, overlay->height - height);
+ break;
+ case GST_BASE_TEXT_OVERLAY_VALIGN_CENTER:
+ ypos = (overlay->height - height) / 2;
+ break;
+ default:
+ ypos = overlay->ypad;
+ break;
+ }
+ ypos += overlay->deltay;
+
+ /* shaded background box */
+ if (overlay->want_shading) {
+ switch (overlay->format) {
+ case GST_VIDEO_FORMAT_I420:
+ case GST_VIDEO_FORMAT_NV12:
+ case GST_VIDEO_FORMAT_NV21:
+ gst_base_text_overlay_shade_planar_Y (overlay, data,
+ xpos, xpos + overlay->image_width,
+ ypos, ypos + overlay->image_height);
+ break;
+ case GST_VIDEO_FORMAT_AYUV:
+ case GST_VIDEO_FORMAT_UYVY:
+ gst_base_text_overlay_shade_packed_Y (overlay, data,
+ xpos, xpos + overlay->image_width,
+ ypos, ypos + overlay->image_height);
+ break;
+ case GST_VIDEO_FORMAT_xRGB:
+ gst_base_text_overlay_shade_xRGB (overlay, data,
+ xpos, xpos + overlay->image_width,
+ ypos, ypos + overlay->image_height);
+ break;
+ case GST_VIDEO_FORMAT_xBGR:
+ gst_base_text_overlay_shade_xBGR (overlay, data,
+ xpos, xpos + overlay->image_width,
+ ypos, ypos + overlay->image_height);
+ break;
+ case GST_VIDEO_FORMAT_BGRx:
+ gst_base_text_overlay_shade_BGRx (overlay, data,
+ xpos, xpos + overlay->image_width,
+ ypos, ypos + overlay->image_height);
+ break;
+ case GST_VIDEO_FORMAT_RGBx:
+ gst_base_text_overlay_shade_RGBx (overlay, data,
+ xpos, xpos + overlay->image_width,
+ ypos, ypos + overlay->image_height);
+ break;
+ case GST_VIDEO_FORMAT_ARGB:
+ gst_base_text_overlay_shade_ARGB (overlay, data,
+ xpos, xpos + overlay->image_width,
+ ypos, ypos + overlay->image_height);
+ break;
+ case GST_VIDEO_FORMAT_ABGR:
+ gst_base_text_overlay_shade_ABGR (overlay, data,
+ xpos, xpos + overlay->image_width,
+ ypos, ypos + overlay->image_height);
+ break;
+ case GST_VIDEO_FORMAT_RGBA:
+ gst_base_text_overlay_shade_RGBA (overlay, data,
+ xpos, xpos + overlay->image_width,
+ ypos, ypos + overlay->image_height);
+ break;
+ case GST_VIDEO_FORMAT_BGRA:
+ gst_base_text_overlay_shade_BGRA (overlay, data,
+ xpos, xpos + overlay->image_width,
+ ypos, ypos + overlay->image_height);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ }
+
+ if (ypos < 0)
+ ypos = 0;
+
+ if (overlay->text_image) {
+ switch (overlay->format) {
+ case GST_VIDEO_FORMAT_I420:
+ gst_base_text_overlay_blit_I420 (overlay, data, xpos, ypos);
+ break;
+ case GST_VIDEO_FORMAT_NV12:
+ case GST_VIDEO_FORMAT_NV21:
+ gst_base_text_overlay_blit_NV12_NV21 (overlay, data, xpos, ypos);
+ break;
+ case GST_VIDEO_FORMAT_UYVY:
+ gst_base_text_overlay_blit_UYVY (overlay, data, xpos, ypos);
+ break;
+ case GST_VIDEO_FORMAT_AYUV:
+ gst_base_text_overlay_blit_AYUV (overlay, data, xpos, ypos);
+ break;
+ case GST_VIDEO_FORMAT_BGRx:
+ gst_base_text_overlay_blit_BGRx (overlay, data, xpos, ypos);
+ break;
+ case GST_VIDEO_FORMAT_xRGB:
+ gst_base_text_overlay_blit_xRGB (overlay, data, xpos, ypos);
+ break;
+ case GST_VIDEO_FORMAT_RGBx:
+ gst_base_text_overlay_blit_RGBx (overlay, data, xpos, ypos);
+ break;
+ case GST_VIDEO_FORMAT_xBGR:
+ gst_base_text_overlay_blit_xBGR (overlay, data, xpos, ypos);
+ break;
+ case GST_VIDEO_FORMAT_ARGB:
+ gst_base_text_overlay_blit_ARGB (overlay, data, xpos, ypos);
+ break;
+ case GST_VIDEO_FORMAT_ABGR:
+ gst_base_text_overlay_blit_ABGR (overlay, data, xpos, ypos);
+ break;
+ case GST_VIDEO_FORMAT_RGBA:
+ gst_base_text_overlay_blit_RGBA (overlay, data, xpos, ypos);
+ break;
+ case GST_VIDEO_FORMAT_BGRA:
+ gst_base_text_overlay_blit_BGRA (overlay, data, xpos, ypos);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ }
+ gst_buffer_unmap (video_frame, data, size);
+
+ return gst_pad_push (overlay->srcpad, video_frame);
+}
+
+static GstPadLinkReturn
+gst_base_text_overlay_text_pad_link (GstPad * pad, GstPad * peer)
+{
+ GstBaseTextOverlay *overlay;
+
+ overlay = GST_BASE_TEXT_OVERLAY (gst_pad_get_parent (pad));
+
+ GST_DEBUG_OBJECT (overlay, "Text pad linked");
+
+ overlay->text_linked = TRUE;
+
+ gst_object_unref (overlay);
+
+ return GST_PAD_LINK_OK;
+}
+
+static void
+gst_base_text_overlay_text_pad_unlink (GstPad * pad)
+{
+ GstBaseTextOverlay *overlay;
+
+ /* don't use gst_pad_get_parent() here, will deadlock */
+ overlay = GST_BASE_TEXT_OVERLAY (GST_PAD_PARENT (pad));
+
+ GST_DEBUG_OBJECT (overlay, "Text pad unlinked");
+
+ overlay->text_linked = FALSE;
+
+ gst_segment_init (&overlay->text_segment, GST_FORMAT_UNDEFINED);
+}
+
+static gboolean
+gst_base_text_overlay_text_event (GstPad * pad, GstEvent * event)
+{
+ gboolean ret = FALSE;
+ GstBaseTextOverlay *overlay = NULL;
+
+ overlay = GST_BASE_TEXT_OVERLAY (gst_pad_get_parent (pad));
+
+ GST_LOG_OBJECT (pad, "received event %s", GST_EVENT_TYPE_NAME (event));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_SEGMENT:
+ {
+ const GstSegment *segment;
+
+ overlay->text_eos = FALSE;
+
+ gst_event_parse_segment (event, &segment);
+
+ if (segment->format == GST_FORMAT_TIME) {
+ GST_OBJECT_LOCK (overlay);
+ gst_segment_copy_into (segment, &overlay->text_segment);
+ GST_DEBUG_OBJECT (overlay, "TEXT SEGMENT now: %" GST_SEGMENT_FORMAT,
+ &overlay->text_segment);
+ GST_OBJECT_UNLOCK (overlay);
+ } else {
+ GST_ELEMENT_WARNING (overlay, STREAM, MUX, (NULL),
+ ("received non-TIME newsegment event on text input"));
+ }
+
+ gst_event_unref (event);
+ ret = TRUE;
+
+ /* wake up the video chain, it might be waiting for a text buffer or
+ * a text segment update */
+ GST_OBJECT_LOCK (overlay);
+ GST_BASE_TEXT_OVERLAY_BROADCAST (overlay);
+ GST_OBJECT_UNLOCK (overlay);
+ break;
+ }
+ case GST_EVENT_FLUSH_STOP:
+ GST_OBJECT_LOCK (overlay);
+ GST_INFO_OBJECT (overlay, "text flush stop");
+ overlay->text_flushing = FALSE;
+ overlay->text_eos = FALSE;
+ gst_base_text_overlay_pop_text (overlay);
+ gst_segment_init (&overlay->text_segment, GST_FORMAT_TIME);
+ GST_OBJECT_UNLOCK (overlay);
+ gst_event_unref (event);
+ ret = TRUE;
+ break;
+ case GST_EVENT_FLUSH_START:
+ GST_OBJECT_LOCK (overlay);
+ GST_INFO_OBJECT (overlay, "text flush start");
+ overlay->text_flushing = TRUE;
+ GST_BASE_TEXT_OVERLAY_BROADCAST (overlay);
+ GST_OBJECT_UNLOCK (overlay);
+ gst_event_unref (event);
+ ret = TRUE;
+ break;
+ case GST_EVENT_EOS:
+ GST_OBJECT_LOCK (overlay);
+ overlay->text_eos = TRUE;
+ GST_INFO_OBJECT (overlay, "text EOS");
+ /* wake up the video chain, it might be waiting for a text buffer or
+ * a text segment update */
+ GST_BASE_TEXT_OVERLAY_BROADCAST (overlay);
+ GST_OBJECT_UNLOCK (overlay);
+ gst_event_unref (event);
+ ret = TRUE;
+ break;
+ default:
+ ret = gst_pad_event_default (pad, event);
+ break;
+ }
+
+ gst_object_unref (overlay);
+
+ return ret;
+}
+
+static gboolean
+gst_base_text_overlay_video_event (GstPad * pad, GstEvent * event)
+{
+ gboolean ret = FALSE;
+ GstBaseTextOverlay *overlay = NULL;
+
+ overlay = GST_BASE_TEXT_OVERLAY (gst_pad_get_parent (pad));
+
+ GST_DEBUG_OBJECT (pad, "received event %s", GST_EVENT_TYPE_NAME (event));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_SEGMENT:
+ {
+ const GstSegment *segment;
+
+ GST_DEBUG_OBJECT (overlay, "received new segment");
+
+ gst_event_parse_segment (event, &segment);
+
+ if (segment->format == GST_FORMAT_TIME) {
+ GST_DEBUG_OBJECT (overlay, "VIDEO SEGMENT now: %" GST_SEGMENT_FORMAT,
+ &overlay->segment);
+
+ gst_segment_copy_into (segment, &overlay->segment);
+ } else {
+ GST_ELEMENT_WARNING (overlay, STREAM, MUX, (NULL),
+ ("received non-TIME newsegment event on video input"));
+ }
+
+ ret = gst_pad_event_default (pad, event);
+ break;
+ }
+ case GST_EVENT_EOS:
+ GST_OBJECT_LOCK (overlay);
+ GST_INFO_OBJECT (overlay, "video EOS");
+ overlay->video_eos = TRUE;
+ GST_OBJECT_UNLOCK (overlay);
+ ret = gst_pad_event_default (pad, event);
+ break;
+ case GST_EVENT_FLUSH_START:
+ GST_OBJECT_LOCK (overlay);
+ GST_INFO_OBJECT (overlay, "video flush start");
+ overlay->video_flushing = TRUE;
+ GST_BASE_TEXT_OVERLAY_BROADCAST (overlay);
+ GST_OBJECT_UNLOCK (overlay);
+ ret = gst_pad_event_default (pad, event);
+ break;
+ case GST_EVENT_FLUSH_STOP:
+ GST_OBJECT_LOCK (overlay);
+ GST_INFO_OBJECT (overlay, "video flush stop");
+ overlay->video_flushing = FALSE;
+ overlay->video_eos = FALSE;
+ gst_segment_init (&overlay->segment, GST_FORMAT_TIME);
+ GST_OBJECT_UNLOCK (overlay);
+ ret = gst_pad_event_default (pad, event);
+ break;
+ default:
+ ret = gst_pad_event_default (pad, event);
+ break;
+ }
+
+ gst_object_unref (overlay);
+
+ return ret;
+}
+
+/* Called with lock held */
+static void
+gst_base_text_overlay_pop_text (GstBaseTextOverlay * overlay)
+{
+ g_return_if_fail (GST_IS_BASE_TEXT_OVERLAY (overlay));
+
+ if (overlay->text_buffer) {
+ GST_DEBUG_OBJECT (overlay, "releasing text buffer %p",
+ overlay->text_buffer);
+ gst_buffer_unref (overlay->text_buffer);
+ overlay->text_buffer = NULL;
+ }
+
+ /* Let the text task know we used that buffer */
+ GST_BASE_TEXT_OVERLAY_BROADCAST (overlay);
+}
+
+/* We receive text buffers here. If they are out of segment we just ignore them.
+ If the buffer is in our segment we keep it internally except if another one
+ is already waiting here, in that case we wait that it gets kicked out */
+static GstFlowReturn
+gst_base_text_overlay_text_chain (GstPad * pad, GstBuffer * buffer)
+{
+ GstFlowReturn ret = GST_FLOW_OK;
+ GstBaseTextOverlay *overlay = NULL;
+ gboolean in_seg = FALSE;
+ guint64 clip_start = 0, clip_stop = 0;
+
+ overlay = GST_BASE_TEXT_OVERLAY (GST_PAD_PARENT (pad));
+
+ GST_OBJECT_LOCK (overlay);
+
+ if (overlay->text_flushing) {
+ GST_OBJECT_UNLOCK (overlay);
+ ret = GST_FLOW_WRONG_STATE;
+ GST_LOG_OBJECT (overlay, "text flushing");
+ goto beach;
+ }
+
+ if (overlay->text_eos) {
+ GST_OBJECT_UNLOCK (overlay);
+ ret = GST_FLOW_UNEXPECTED;
+ GST_LOG_OBJECT (overlay, "text EOS");
+ goto beach;
+ }
+
+ GST_LOG_OBJECT (overlay, "%" GST_SEGMENT_FORMAT " BUFFER: ts=%"
+ GST_TIME_FORMAT ", end=%" GST_TIME_FORMAT, &overlay->segment,
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer) +
+ GST_BUFFER_DURATION (buffer)));
+
+ if (G_LIKELY (GST_BUFFER_TIMESTAMP_IS_VALID (buffer))) {
+ GstClockTime stop;
+
+ if (G_LIKELY (GST_BUFFER_DURATION_IS_VALID (buffer)))
+ stop = GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer);
+ else
+ stop = GST_CLOCK_TIME_NONE;
+
+ in_seg = gst_segment_clip (&overlay->text_segment, GST_FORMAT_TIME,
+ GST_BUFFER_TIMESTAMP (buffer), stop, &clip_start, &clip_stop);
+ } else {
+ in_seg = TRUE;
+ }
+
+ if (in_seg) {
+ if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer))
+ GST_BUFFER_TIMESTAMP (buffer) = clip_start;
+ else if (GST_BUFFER_DURATION_IS_VALID (buffer))
+ GST_BUFFER_DURATION (buffer) = clip_stop - clip_start;
+
+ /* Wait for the previous buffer to go away */
+ while (overlay->text_buffer != NULL) {
+ GST_DEBUG ("Pad %s:%s has a buffer queued, waiting",
+ GST_DEBUG_PAD_NAME (pad));
+ GST_BASE_TEXT_OVERLAY_WAIT (overlay);
+ GST_DEBUG ("Pad %s:%s resuming", GST_DEBUG_PAD_NAME (pad));
+ if (overlay->text_flushing) {
+ GST_OBJECT_UNLOCK (overlay);
+ ret = GST_FLOW_WRONG_STATE;
+ goto beach;
+ }
+ }
+
+ if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer))
+ overlay->text_segment.position = clip_start;
+
+ overlay->text_buffer = buffer;
+ /* That's a new text buffer we need to render */
+ overlay->need_render = TRUE;
+
+ /* in case the video chain is waiting for a text buffer, wake it up */
+ GST_BASE_TEXT_OVERLAY_BROADCAST (overlay);
+ }
+
+ GST_OBJECT_UNLOCK (overlay);
+
+beach:
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_base_text_overlay_video_chain (GstPad * pad, GstBuffer * buffer)
+{
+ GstBaseTextOverlayClass *klass;
+ GstBaseTextOverlay *overlay;
+ GstFlowReturn ret = GST_FLOW_OK;
+ gboolean in_seg = FALSE;
+ guint64 start, stop, clip_start = 0, clip_stop = 0;
+ gchar *text = NULL;
+
+ overlay = GST_BASE_TEXT_OVERLAY (GST_PAD_PARENT (pad));
+ klass = GST_BASE_TEXT_OVERLAY_GET_CLASS (overlay);
+
+ if (!GST_BUFFER_TIMESTAMP_IS_VALID (buffer))
+ goto missing_timestamp;
+
+ /* ignore buffers that are outside of the current segment */
+ start = GST_BUFFER_TIMESTAMP (buffer);
+
+ if (!GST_BUFFER_DURATION_IS_VALID (buffer)) {
+ stop = GST_CLOCK_TIME_NONE;
+ } else {
+ stop = start + GST_BUFFER_DURATION (buffer);
+ }
+
+ GST_LOG_OBJECT (overlay, "%" GST_SEGMENT_FORMAT " BUFFER: ts=%"
+ GST_TIME_FORMAT ", end=%" GST_TIME_FORMAT, &overlay->segment,
+ GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
+
+ /* segment_clip() will adjust start unconditionally to segment_start if
+ * no stop time is provided, so handle this ourselves */
+ if (stop == GST_CLOCK_TIME_NONE && start < overlay->segment.start)
+ goto out_of_segment;
+
+ in_seg = gst_segment_clip (&overlay->segment, GST_FORMAT_TIME, start, stop,
+ &clip_start, &clip_stop);
+
+ if (!in_seg)
+ goto out_of_segment;
+
+ /* if the buffer is only partially in the segment, fix up stamps */
+ if (clip_start != start || (stop != -1 && clip_stop != stop)) {
+ GST_DEBUG_OBJECT (overlay, "clipping buffer timestamp/duration to segment");
+ buffer = gst_buffer_make_writable (buffer);
+ GST_BUFFER_TIMESTAMP (buffer) = clip_start;
+ if (stop != -1)
+ GST_BUFFER_DURATION (buffer) = clip_stop - clip_start;
+ }
+
+ /* now, after we've done the clipping, fix up end time if there's no
+ * duration (we only use those estimated values internally though, we
+ * don't want to set bogus values on the buffer itself) */
+ if (stop == -1) {
+ GstCaps *caps;
+ GstStructure *s;
+ gint fps_num, fps_denom;
+
+ /* FIXME, store this in setcaps */
+ caps = gst_pad_get_current_caps (pad);
+ s = gst_caps_get_structure (caps, 0);
+ if (gst_structure_get_fraction (s, "framerate", &fps_num, &fps_denom) &&
+ fps_num && fps_denom) {
+ GST_DEBUG_OBJECT (overlay, "estimating duration based on framerate");
+ stop = start + gst_util_uint64_scale_int (GST_SECOND, fps_denom, fps_num);
+ } else {
+ GST_WARNING_OBJECT (overlay, "no duration, assuming minimal duration");
+ stop = start + 1; /* we need to assume some interval */
+ }
+ gst_caps_unref (caps);
+ }
+
+ gst_object_sync_values (G_OBJECT (overlay), GST_BUFFER_TIMESTAMP (buffer));
+
+wait_for_text_buf:
+
+ GST_OBJECT_LOCK (overlay);
+
+ if (overlay->video_flushing)
+ goto flushing;
+
+ if (overlay->video_eos)
+ goto have_eos;
+
+ if (overlay->silent) {
+ GST_OBJECT_UNLOCK (overlay);
+ ret = gst_pad_push (overlay->srcpad, buffer);
+
+ /* Update position */
+ overlay->segment.position = clip_start;
+
+ return ret;
+ }
+
+ /* Text pad not linked, rendering internal text */
+ if (!overlay->text_linked) {
+ if (klass->get_text) {
+ text = klass->get_text (overlay, buffer);
+ } else {
+ text = g_strdup (overlay->default_text);
+ }
+
+ GST_LOG_OBJECT (overlay, "Text pad not linked, rendering default "
+ "text: '%s'", GST_STR_NULL (text));
+
+ GST_OBJECT_UNLOCK (overlay);
+
+ if (text != NULL && *text != '\0') {
+ /* Render and push */
+ gst_base_text_overlay_render_text (overlay, text, -1);
+ ret = gst_base_text_overlay_push_frame (overlay, buffer);
+ } else {
+ /* Invalid or empty string */
+ ret = gst_pad_push (overlay->srcpad, buffer);
+ }
+ } else {
+ /* Text pad linked, check if we have a text buffer queued */
+ if (overlay->text_buffer) {
+ gboolean pop_text = FALSE, valid_text_time = TRUE;
+ GstClockTime text_start = GST_CLOCK_TIME_NONE;
+ GstClockTime text_end = GST_CLOCK_TIME_NONE;
+ GstClockTime text_running_time = GST_CLOCK_TIME_NONE;
+ GstClockTime text_running_time_end = GST_CLOCK_TIME_NONE;
+ GstClockTime vid_running_time, vid_running_time_end;
+
+ /* if the text buffer isn't stamped right, pop it off the
+ * queue and display it for the current video frame only */
+ if (!GST_BUFFER_TIMESTAMP_IS_VALID (overlay->text_buffer) ||
+ !GST_BUFFER_DURATION_IS_VALID (overlay->text_buffer)) {
+ GST_WARNING_OBJECT (overlay,
+ "Got text buffer with invalid timestamp or duration");
+ pop_text = TRUE;
+ valid_text_time = FALSE;
+ } else {
+ text_start = GST_BUFFER_TIMESTAMP (overlay->text_buffer);
+ text_end = text_start + GST_BUFFER_DURATION (overlay->text_buffer);
+ }
+
+ vid_running_time =
+ gst_segment_to_running_time (&overlay->segment, GST_FORMAT_TIME,
+ start);
+ vid_running_time_end =
+ gst_segment_to_running_time (&overlay->segment, GST_FORMAT_TIME,
+ stop);
+
+ /* If timestamp and duration are valid */
+ if (valid_text_time) {
+ text_running_time =
+ gst_segment_to_running_time (&overlay->segment, GST_FORMAT_TIME,
+ text_start);
+ text_running_time_end =
+ gst_segment_to_running_time (&overlay->segment, GST_FORMAT_TIME,
+ text_end);
+ }
+
+ GST_LOG_OBJECT (overlay, "T: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (text_running_time),
+ GST_TIME_ARGS (text_running_time_end));
+ GST_LOG_OBJECT (overlay, "V: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (vid_running_time),
+ GST_TIME_ARGS (vid_running_time_end));
+
+ /* Text too old or in the future */
+ if (valid_text_time && text_running_time_end <= vid_running_time) {
+ /* text buffer too old, get rid of it and do nothing */
+ GST_LOG_OBJECT (overlay, "text buffer too old, popping");
+ pop_text = FALSE;
+ gst_base_text_overlay_pop_text (overlay);
+ GST_OBJECT_UNLOCK (overlay);
+ goto wait_for_text_buf;
+ } else if (valid_text_time && vid_running_time_end <= text_running_time) {
+ GST_LOG_OBJECT (overlay, "text in future, pushing video buf");
+ GST_OBJECT_UNLOCK (overlay);
+ /* Push the video frame */
+ ret = gst_pad_push (overlay->srcpad, buffer);
+ } else {
+ gchar *in_text, *otext;
+ gsize in_size, osize;
+
+ otext =
+ gst_buffer_map (overlay->text_buffer, &osize, NULL, GST_MAP_READ);
+ in_text = otext;
+ in_size = osize;
+
+ /* g_markup_escape_text() absolutely requires valid UTF8 input, it
+ * might crash otherwise. We don't fall back on GST_SUBTITLE_ENCODING
+ * here on purpose, this is something that needs fixing upstream */
+ if (!g_utf8_validate (in_text, in_size, NULL)) {
+ const gchar *end = NULL;
+
+ GST_WARNING_OBJECT (overlay, "received invalid UTF-8");
+ in_text = g_strndup (in_text, in_size);
+ while (!g_utf8_validate (in_text, in_size, &end) && end)
+ *((gchar *) end) = '*';
+ }
+
+ /* Get the string */
+ if (overlay->have_pango_markup) {
+ text = g_strndup (in_text, in_size);
+ } else {
+ text = g_markup_escape_text (in_text, in_size);
+ }
+
+ if (text != NULL && *text != '\0') {
+ gint text_len = strlen (text);
+
+ while (text_len > 0 && (text[text_len - 1] == '\n' ||
+ text[text_len - 1] == '\r')) {
+ --text_len;
+ }
+ GST_DEBUG_OBJECT (overlay, "Rendering text '%*s'", text_len, text);
+ gst_base_text_overlay_render_text (overlay, text, text_len);
+ } else {
+ GST_DEBUG_OBJECT (overlay, "No text to render (empty buffer)");
+ gst_base_text_overlay_render_text (overlay, " ", 1);
+ }
+ gst_buffer_unmap (overlay->text_buffer, otext, osize);
+
+ if (in_text != otext)
+ g_free (in_text);
+
+ GST_OBJECT_UNLOCK (overlay);
+ ret = gst_base_text_overlay_push_frame (overlay, buffer);
+
+ if (valid_text_time && text_running_time_end <= vid_running_time_end) {
+ GST_LOG_OBJECT (overlay, "text buffer not needed any longer");
+ pop_text = TRUE;
+ }
+ }
+ if (pop_text) {
+ GST_OBJECT_LOCK (overlay);
+ gst_base_text_overlay_pop_text (overlay);
+ GST_OBJECT_UNLOCK (overlay);
+ }
+ } else {
+ gboolean wait_for_text_buf = TRUE;
+
+ if (overlay->text_eos)
+ wait_for_text_buf = FALSE;
+
+ if (!overlay->wait_text)
+ wait_for_text_buf = FALSE;
+
+ /* Text pad linked, but no text buffer available - what now? */
+ if (overlay->text_segment.format == GST_FORMAT_TIME) {
+ GstClockTime text_start_running_time, text_position_running_time;
+ GstClockTime vid_running_time;
+
+ vid_running_time =
+ gst_segment_to_running_time (&overlay->segment, GST_FORMAT_TIME,
+ GST_BUFFER_TIMESTAMP (buffer));
+ text_start_running_time =
+ gst_segment_to_running_time (&overlay->text_segment,
+ GST_FORMAT_TIME, overlay->text_segment.start);
+ text_position_running_time =
+ gst_segment_to_running_time (&overlay->text_segment,
+ GST_FORMAT_TIME, overlay->text_segment.position);
+
+ if ((GST_CLOCK_TIME_IS_VALID (text_start_running_time) &&
+ vid_running_time < text_start_running_time) ||
+ (GST_CLOCK_TIME_IS_VALID (text_position_running_time) &&
+ vid_running_time < text_position_running_time)) {
+ wait_for_text_buf = FALSE;
+ }
+ }
+
+ if (wait_for_text_buf) {
+ GST_DEBUG_OBJECT (overlay, "no text buffer, need to wait for one");
+ GST_BASE_TEXT_OVERLAY_WAIT (overlay);
+ GST_DEBUG_OBJECT (overlay, "resuming");
+ GST_OBJECT_UNLOCK (overlay);
+ goto wait_for_text_buf;
+ } else {
+ GST_OBJECT_UNLOCK (overlay);
+ GST_LOG_OBJECT (overlay, "no need to wait for a text buffer");
+ ret = gst_pad_push (overlay->srcpad, buffer);
+ }
+ }
+ }
+
+ g_free (text);
+
+ /* Update position */
+ overlay->segment.position = clip_start;
+
+ return ret;
+
+missing_timestamp:
+ {
+ GST_WARNING_OBJECT (overlay, "buffer without timestamp, discarding");
+ gst_buffer_unref (buffer);
+ return GST_FLOW_OK;
+ }
+
+flushing:
+ {
+ GST_OBJECT_UNLOCK (overlay);
+ GST_DEBUG_OBJECT (overlay, "flushing, discarding buffer");
+ gst_buffer_unref (buffer);
+ return GST_FLOW_WRONG_STATE;
+ }
+have_eos:
+ {
+ GST_OBJECT_UNLOCK (overlay);
+ GST_DEBUG_OBJECT (overlay, "eos, discarding buffer");
+ gst_buffer_unref (buffer);
+ return GST_FLOW_UNEXPECTED;
+ }
+out_of_segment:
+ {
+ GST_DEBUG_OBJECT (overlay, "buffer out of segment, discarding");
+ gst_buffer_unref (buffer);
+ return GST_FLOW_OK;
+ }
+}
+
+static GstStateChangeReturn
+gst_base_text_overlay_change_state (GstElement * element,
+ GstStateChange transition)
+{
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+ GstBaseTextOverlay *overlay = GST_BASE_TEXT_OVERLAY (element);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ GST_OBJECT_LOCK (overlay);
+ overlay->text_flushing = TRUE;
+ overlay->video_flushing = TRUE;
+ /* pop_text will broadcast on the GCond and thus also make the video
+ * chain exit if it's waiting for a text buffer */
+ gst_base_text_overlay_pop_text (overlay);
+ GST_OBJECT_UNLOCK (overlay);
+ break;
+ default:
+ break;
+ }
+
+ ret = parent_class->change_state (element, transition);
+ if (ret == GST_STATE_CHANGE_FAILURE)
+ return ret;
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ GST_OBJECT_LOCK (overlay);
+ overlay->text_flushing = FALSE;
+ overlay->video_flushing = FALSE;
+ overlay->video_eos = FALSE;
+ overlay->text_eos = FALSE;
+ gst_segment_init (&overlay->segment, GST_FORMAT_TIME);
+ gst_segment_init (&overlay->text_segment, GST_FORMAT_TIME);
+ GST_OBJECT_UNLOCK (overlay);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ gst_controller_init (NULL, NULL);
+
+ if (!gst_element_register (plugin, "textoverlay", GST_RANK_NONE,
+ GST_TYPE_TEXT_OVERLAY) ||
+ !gst_element_register (plugin, "timeoverlay", GST_RANK_NONE,
+ GST_TYPE_TIME_OVERLAY) ||
+ !gst_element_register (plugin, "clockoverlay", GST_RANK_NONE,
+ GST_TYPE_CLOCK_OVERLAY) ||
+ !gst_element_register (plugin, "textrender", GST_RANK_NONE,
+ GST_TYPE_TEXT_RENDER)) {
+ return FALSE;
+ }
+
+ /*texttestsrc_plugin_init(module, plugin); */
+
+ GST_DEBUG_CATEGORY_INIT (pango_debug, "pango", 0, "Pango elements");
+
+ return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
+ "pango", "Pango-based text rendering and overlay", plugin_init,
+ VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
--- /dev/null
+#ifndef __GST_BASE_TEXT_OVERLAY_H__
+#define __GST_BASE_TEXT_OVERLAY_H__
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gst/controller/gstcontroller.h>
+#include <pango/pangocairo.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_BASE_TEXT_OVERLAY (gst_base_text_overlay_get_type())
+#define GST_BASE_TEXT_OVERLAY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
+ GST_TYPE_BASE_TEXT_OVERLAY, GstBaseTextOverlay))
+#define GST_BASE_TEXT_OVERLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),\
+ GST_TYPE_BASE_TEXT_OVERLAY,GstBaseTextOverlayClass))
+#define GST_BASE_TEXT_OVERLAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
+ GST_TYPE_BASE_TEXT_OVERLAY, GstBaseTextOverlayClass))
+#define GST_IS_BASE_TEXT_OVERLAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),\
+ GST_TYPE_BASE_TEXT_OVERLAY))
+#define GST_IS_BASE_TEXT_OVERLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),\
+ GST_TYPE_BASE_TEXT_OVERLAY))
+
+typedef struct _GstBaseTextOverlay GstBaseTextOverlay;
+typedef struct _GstBaseTextOverlayClass GstBaseTextOverlayClass;
+
+/**
+ * GstBaseTextOverlayVAlign:
+ * @GST_BASE_TEXT_OVERLAY_VALIGN_BASELINE: draw text on the baseline
+ * @GST_BASE_TEXT_OVERLAY_VALIGN_BOTTOM: draw text on the bottom
+ * @GST_BASE_TEXT_OVERLAY_VALIGN_TOP: draw text on top
+ * @GST_BASE_TEXT_OVERLAY_VALIGN_POS: draw text according to the #GstBaseTextOverlay:ypos property
+ * @GST_BASE_TEXT_OVERLAY_VALIGN_CENTER: draw text vertically centered
+ *
+ * Vertical alignment of the text.
+ */
+typedef enum {
+ GST_BASE_TEXT_OVERLAY_VALIGN_BASELINE,
+ GST_BASE_TEXT_OVERLAY_VALIGN_BOTTOM,
+ GST_BASE_TEXT_OVERLAY_VALIGN_TOP,
+ GST_BASE_TEXT_OVERLAY_VALIGN_POS,
+ GST_BASE_TEXT_OVERLAY_VALIGN_CENTER
+} GstBaseTextOverlayVAlign;
+
+/**
+ * GstBaseTextOverlayHAlign:
+ * @GST_BASE_TEXT_OVERLAY_HALIGN_LEFT: align text left
+ * @GST_BASE_TEXT_OVERLAY_HALIGN_CENTER: align text center
+ * @GST_BASE_TEXT_OVERLAY_HALIGN_RIGHT: align text right
+ * @GST_BASE_TEXT_OVERLAY_HALIGN_POS: position text according to the #GstBaseTextOverlay:xpos property
+ *
+ * Horizontal alignment of the text.
+ */
+/* FIXME 0.11: remove GST_BASE_TEXT_OVERLAY_HALIGN_UNUSED */
+typedef enum {
+ GST_BASE_TEXT_OVERLAY_HALIGN_LEFT,
+ GST_BASE_TEXT_OVERLAY_HALIGN_CENTER,
+ GST_BASE_TEXT_OVERLAY_HALIGN_RIGHT,
+ GST_BASE_TEXT_OVERLAY_HALIGN_UNUSED,
+ GST_BASE_TEXT_OVERLAY_HALIGN_POS
+} GstBaseTextOverlayHAlign;
+
+/**
+ * GstBaseTextOverlayWrapMode:
+ * @GST_BASE_TEXT_OVERLAY_WRAP_MODE_NONE: no wrapping
+ * @GST_BASE_TEXT_OVERLAY_WRAP_MODE_WORD: do word wrapping
+ * @GST_BASE_TEXT_OVERLAY_WRAP_MODE_CHAR: do char wrapping
+ * @GST_BASE_TEXT_OVERLAY_WRAP_MODE_WORD_CHAR: do word and char wrapping
+ *
+ * Whether to wrap the text and if so how.
+ */
+typedef enum {
+ GST_BASE_TEXT_OVERLAY_WRAP_MODE_NONE = -1,
+ GST_BASE_TEXT_OVERLAY_WRAP_MODE_WORD = PANGO_WRAP_WORD,
+ GST_BASE_TEXT_OVERLAY_WRAP_MODE_CHAR = PANGO_WRAP_CHAR,
+ GST_BASE_TEXT_OVERLAY_WRAP_MODE_WORD_CHAR = PANGO_WRAP_WORD_CHAR
+} GstBaseTextOverlayWrapMode;
+
+/**
+ * GstBaseTextOverlayLineAlign:
+ * @GST_BASE_TEXT_OVERLAY_LINE_ALIGN_LEFT: lines are left-aligned
+ * @GST_BASE_TEXT_OVERLAY_LINE_ALIGN_CENTER: lines are center-aligned
+ * @GST_BASE_TEXT_OVERLAY_LINE_ALIGN_RIGHT: lines are right-aligned
+ *
+ * Alignment of text lines relative to each other
+ */
+typedef enum {
+ GST_BASE_TEXT_OVERLAY_LINE_ALIGN_LEFT = PANGO_ALIGN_LEFT,
+ GST_BASE_TEXT_OVERLAY_LINE_ALIGN_CENTER = PANGO_ALIGN_CENTER,
+ GST_BASE_TEXT_OVERLAY_LINE_ALIGN_RIGHT = PANGO_ALIGN_RIGHT
+} GstBaseTextOverlayLineAlign;
+
+/**
+ * GstBaseTextOverlay:
+ *
+ * Opaque textoverlay object structure
+ */
+struct _GstBaseTextOverlay {
+ GstElement element;
+
+ GstPad *video_sinkpad;
+ GstPad *text_sinkpad;
+ GstPad *srcpad;
+
+ GstSegment segment;
+ GstSegment text_segment;
+ GstBuffer *text_buffer;
+ gboolean text_linked;
+ gboolean video_flushing;
+ gboolean video_eos;
+ gboolean text_flushing;
+ gboolean text_eos;
+
+ GCond *cond; /* to signal removal of a queued text
+ * buffer, arrival of a text buffer,
+ * a text segment update, or a change
+ * in status (e.g. shutdown, flushing) */
+
+ gint width;
+ gint height;
+ gint fps_n;
+ gint fps_d;
+ GstVideoFormat format;
+
+ GstBaseTextOverlayVAlign valign;
+ GstBaseTextOverlayHAlign halign;
+ GstBaseTextOverlayWrapMode wrap_mode;
+ GstBaseTextOverlayLineAlign line_align;
+
+ gint xpad;
+ gint ypad;
+ gint deltax;
+ gint deltay;
+ gdouble xpos;
+ gdouble ypos;
+ gchar *default_text;
+ gboolean want_shading;
+ gboolean silent;
+ gboolean wait_text;
+ guint color, outline_color;
+
+ PangoLayout *layout;
+ gdouble shadow_offset;
+ gdouble outline_offset;
+ guchar *text_image;
+ gint image_width;
+ gint image_height;
+ gint baseline_y;
+
+ gboolean auto_adjust_size;
+ gboolean need_render;
+
+ gint shading_value; /* for timeoverlay subclass */
+
+ gboolean have_pango_markup;
+ gboolean use_vertical_render;
+};
+
+struct _GstBaseTextOverlayClass {
+ GstElementClass parent_class;
+
+ PangoContext *pango_context;
+ GMutex *pango_lock;
+
+ gchar * (*get_text) (GstBaseTextOverlay *overlay, GstBuffer *video_frame);
+};
+
+GType gst_base_text_overlay_get_type(void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __GST_BASE_TEXT_OVERLAY_H */
/**
* SECTION:element-clockoverlay
- * @see_also: #GstTextOverlay, #GstTimeOverlay
+ * @see_also: #GstBaseTextOverlay, #GstTimeOverlay
*
* This element overlays the current clock time on top of a video
* stream. You can position the text and configure the font details
- * using the properties of the #GstTextOverlay class. By default, the
+ * using the properties of the #GstBaseTextOverlay class. By default, the
* time is displayed in the top left corner of the picture, with some
* padding to the left and to the top.
*
PROP_LAST
};
-GST_BOILERPLATE (GstClockOverlay, gst_clock_overlay, GstTextOverlay,
- GST_TYPE_TEXT_OVERLAY);
-
-static void
-gst_clock_overlay_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_set_details_simple (element_class, "Clock overlay",
- "Filter/Editor/Video",
- "Overlays the current clock time on a video stream",
- "Tim-Philipp Müller <tim@centricular.net>");
-}
-
+#define gst_clock_overlay_parent_class parent_class
+G_DEFINE_TYPE (GstClockOverlay, gst_clock_overlay, GST_TYPE_BASE_TEXT_OVERLAY);
static void gst_clock_overlay_finalize (GObject * object);
static void gst_clock_overlay_set_property (GObject * object, guint prop_id,
/* Called with lock held */
static gchar *
-gst_clock_overlay_get_text (GstTextOverlay * overlay, GstBuffer * video_frame)
+gst_clock_overlay_get_text (GstBaseTextOverlay * overlay,
+ GstBuffer * video_frame)
{
gchar *time_str, *txt, *ret;
GstClockOverlay *clock_overlay = GST_CLOCK_OVERLAY (overlay);
gst_clock_overlay_class_init (GstClockOverlayClass * klass)
{
GObjectClass *gobject_class;
- GstTextOverlayClass *gsttextoverlay_class;
+ GstElementClass *gstelement_class;
+ GstBaseTextOverlayClass *gsttextoverlay_class;
PangoContext *context;
PangoFontDescription *font_description;
gobject_class = (GObjectClass *) klass;
- gsttextoverlay_class = (GstTextOverlayClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gsttextoverlay_class = (GstBaseTextOverlayClass *) klass;
gobject_class->finalize = gst_clock_overlay_finalize;
gobject_class->set_property = gst_clock_overlay_set_property;
gobject_class->get_property = gst_clock_overlay_get_property;
+ gst_element_class_set_details_simple (gstelement_class, "Clock overlay",
+ "Filter/Editor/Video",
+ "Overlays the current clock time on a video stream",
+ "Tim-Philipp Müller <tim@centricular.net>");
+
gsttextoverlay_class->get_text = gst_clock_overlay_get_text;
g_object_class_install_property (gobject_class, PROP_TIMEFORMAT,
"Format to use for time and date value, as in strftime.",
DEFAULT_PROP_TIMEFORMAT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_mutex_lock (GST_TEXT_OVERLAY_CLASS (klass)->pango_lock);
- context = GST_TEXT_OVERLAY_CLASS (klass)->pango_context;
+ g_mutex_lock (gsttextoverlay_class->pango_lock);
+ context = gsttextoverlay_class->pango_context;
pango_context_set_language (context, pango_language_from_string ("en_US"));
pango_context_set_base_dir (context, PANGO_DIRECTION_LTR);
pango_font_description_set_size (font_description, 18 * PANGO_SCALE);
pango_context_set_font_description (context, font_description);
pango_font_description_free (font_description);
- g_mutex_unlock (GST_TEXT_OVERLAY_CLASS (klass)->pango_lock);
+ g_mutex_unlock (gsttextoverlay_class->pango_lock);
}
static void
-gst_clock_overlay_init (GstClockOverlay * overlay, GstClockOverlayClass * klass)
+gst_clock_overlay_init (GstClockOverlay * overlay)
{
- GstTextOverlay *textoverlay;
+ GstBaseTextOverlay *textoverlay;
- textoverlay = GST_TEXT_OVERLAY (overlay);
+ textoverlay = GST_BASE_TEXT_OVERLAY (overlay);
- textoverlay->valign = GST_TEXT_OVERLAY_VALIGN_TOP;
- textoverlay->halign = GST_TEXT_OVERLAY_HALIGN_LEFT;
+ textoverlay->valign = GST_BASE_TEXT_OVERLAY_VALIGN_TOP;
+ textoverlay->halign = GST_BASE_TEXT_OVERLAY_HALIGN_LEFT;
overlay->format = g_strdup (DEFAULT_PROP_TIMEFORMAT);
}
#ifndef __GST_CLOCK_OVERLAY_H__
#define __GST_CLOCK_OVERLAY_H__
-#include "gsttextoverlay.h"
+#include "gstbasetextoverlay.h"
G_BEGIN_DECLS
* Opaque clockoverlay data structure.
*/
struct _GstClockOverlay {
- GstTextOverlay textoverlay;
+ GstBaseTextOverlay textoverlay;
gchar *format; /* as in strftime () */
gchar *text;
};
struct _GstClockOverlayClass {
- GstTextOverlayClass parent_class;
+ GstBaseTextOverlayClass parent_class;
};
GType gst_clock_overlay_get_type (void);
* Copyright (C) <2006> Zeeshan Ali <zeeshan.ali@nokia.com>
* Copyright (C) <2006-2008> Tim-Philipp Müller <tim centricular net>
* Copyright (C) <2009> Young-Ho Cha <ganadist@gmail.com>
+ * Copyright (C) <2011> Sebastian Dröge <sebastian.droege@collabora.co.uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
/**
* SECTION:element-textoverlay
- * @see_also: #GstTextRender, #GstClockOverlay, #GstTimeOverlay, #GstSubParse
+ * @see_also: #GstTextRender, #GstTextOverlay, #GstTimeOverlay, #GstSubParse
*
* This plugin renders text on top of a video stream. This can be either
* static text or text from buffers received on the text sink pad, e.g.
* </refsect2>
*/
-/* FIXME: alloc segment as part of instance struct */
-
#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <gst/video/video.h>
-
-#include "gsttextoverlay.h"
-#include "gsttimeoverlay.h"
-#include "gstclockoverlay.h"
-#include "gsttextrender.h"
-#include <string.h>
-
-/* FIXME:
- * - use proper strides and offset for I420
- * - if text is wider than the video picture, it does not get
- * clipped properly during blitting (if wrapping is disabled)
- * - make 'shading_value' a property (or enum: light/normal/dark/verydark)?
- */
-
-GST_DEBUG_CATEGORY (pango_debug);
-#define GST_CAT_DEFAULT pango_debug
-
-#define DEFAULT_PROP_TEXT ""
-#define DEFAULT_PROP_SHADING FALSE
-#define DEFAULT_PROP_SHADOW TRUE
-#define DEFAULT_PROP_VALIGNMENT GST_TEXT_OVERLAY_VALIGN_BASELINE
-#define DEFAULT_PROP_HALIGNMENT GST_TEXT_OVERLAY_HALIGN_CENTER
-#define DEFAULT_PROP_VALIGN "baseline"
-#define DEFAULT_PROP_HALIGN "center"
-#define DEFAULT_PROP_XPAD 25
-#define DEFAULT_PROP_YPAD 25
-#define DEFAULT_PROP_DELTAX 0
-#define DEFAULT_PROP_DELTAY 0
-#define DEFAULT_PROP_XPOS 0.5
-#define DEFAULT_PROP_YPOS 0.5
-#define DEFAULT_PROP_WRAP_MODE GST_TEXT_OVERLAY_WRAP_MODE_WORD_CHAR
-#define DEFAULT_PROP_FONT_DESC ""
-#define DEFAULT_PROP_SILENT FALSE
-#define DEFAULT_PROP_LINE_ALIGNMENT GST_TEXT_OVERLAY_LINE_ALIGN_CENTER
-#define DEFAULT_PROP_WAIT_TEXT TRUE
-#define DEFAULT_PROP_AUTO_ADJUST_SIZE TRUE
-#define DEFAULT_PROP_VERTICAL_RENDER FALSE
-#define DEFAULT_PROP_COLOR 0xffffffff
-#define DEFAULT_PROP_OUTLINE_COLOR 0xff000000
-
-/* make a property of me */
-#define DEFAULT_SHADING_VALUE -80
-
-#define MINIMUM_OUTLINE_OFFSET 1.0
-#define DEFAULT_SCALE_BASIS 640
-
-#define COMP_Y(ret, r, g, b) \
-{ \
- ret = (int) (((19595 * r) >> 16) + ((38470 * g) >> 16) + ((7471 * b) >> 16)); \
- ret = CLAMP (ret, 0, 255); \
-}
-
-#define COMP_U(ret, r, g, b) \
-{ \
- ret = (int) (-((11059 * r) >> 16) - ((21709 * g) >> 16) + ((32768 * b) >> 16) + 128); \
- ret = CLAMP (ret, 0, 255); \
-}
-
-#define COMP_V(ret, r, g, b) \
-{ \
- ret = (int) (((32768 * r) >> 16) - ((27439 * g) >> 16) - ((5329 * b) >> 16) + 128); \
- ret = CLAMP (ret, 0, 255); \
-}
-
-#define BLEND(ret, alpha, v0, v1) \
-{ \
- ret = (v0 * alpha + v1 * (255 - alpha)) / 255; \
-}
-
-#define OVER(ret, alphaA, Ca, alphaB, Cb, alphaNew) \
-{ \
- gint _tmp; \
- _tmp = (Ca * alphaA + Cb * alphaB * (255 - alphaA) / 255) / alphaNew; \
- ret = CLAMP (_tmp, 0, 255); \
-}
-
-#if G_BYTE_ORDER == G_LITTLE_ENDIAN
-# define CAIRO_ARGB_A 3
-# define CAIRO_ARGB_R 2
-# define CAIRO_ARGB_G 1
-# define CAIRO_ARGB_B 0
-#else
-# define CAIRO_ARGB_A 0
-# define CAIRO_ARGB_R 1
-# define CAIRO_ARGB_G 2
-# define CAIRO_ARGB_B 3
+#include "config.h"
#endif
-enum
-{
- PROP_0,
- PROP_TEXT,
- PROP_SHADING,
- PROP_VALIGN, /* deprecated */
- PROP_HALIGN, /* deprecated */
- PROP_HALIGNMENT,
- PROP_VALIGNMENT,
- PROP_XPAD,
- PROP_YPAD,
- PROP_DELTAX,
- PROP_DELTAY,
- PROP_XPOS,
- PROP_YPOS,
- PROP_WRAP_MODE,
- PROP_FONT_DESC,
- PROP_SILENT,
- PROP_LINE_ALIGNMENT,
- PROP_WAIT_TEXT,
- PROP_AUTO_ADJUST_SIZE,
- PROP_VERTICAL_RENDER,
- PROP_COLOR,
- PROP_SHADOW,
- PROP_OUTLINE_COLOR,
- PROP_LAST
-};
-
-static GstStaticPadTemplate src_template_factory =
- GST_STATIC_PAD_TEMPLATE ("src",
- GST_PAD_SRC,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS (GST_VIDEO_CAPS_BGRx ";"
- GST_VIDEO_CAPS_RGBx ";"
- GST_VIDEO_CAPS_xRGB ";"
- GST_VIDEO_CAPS_xBGR ";"
- GST_VIDEO_CAPS_RGBA ";"
- GST_VIDEO_CAPS_BGRA ";"
- GST_VIDEO_CAPS_ARGB ";"
- GST_VIDEO_CAPS_ABGR ";"
- GST_VIDEO_CAPS_YUV ("{AYUV, I420, UYVY, NV12, NV21}"))
- );
-
-static GstStaticPadTemplate video_sink_template_factory =
- GST_STATIC_PAD_TEMPLATE ("video_sink",
- GST_PAD_SINK,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS (GST_VIDEO_CAPS_BGRx ";"
- GST_VIDEO_CAPS_RGBx ";"
- GST_VIDEO_CAPS_xRGB ";"
- GST_VIDEO_CAPS_xBGR ";"
- GST_VIDEO_CAPS_RGBA ";"
- GST_VIDEO_CAPS_BGRA ";"
- GST_VIDEO_CAPS_ARGB ";"
- GST_VIDEO_CAPS_ABGR ";"
- GST_VIDEO_CAPS_YUV ("{AYUV, I420, UYVY, NV12, NV21}"))
- );
+#include <gsttextoverlay.h>
static GstStaticPadTemplate text_sink_template_factory =
GST_STATIC_PAD_TEMPLATE ("text_sink",
GST_STATIC_CAPS ("text/x-pango-markup; text/plain")
);
-#define GST_TYPE_TEXT_OVERLAY_VALIGN (gst_text_overlay_valign_get_type())
-static GType
-gst_text_overlay_valign_get_type (void)
-{
- static GType text_overlay_valign_type = 0;
- static const GEnumValue text_overlay_valign[] = {
- {GST_TEXT_OVERLAY_VALIGN_BASELINE, "baseline", "baseline"},
- {GST_TEXT_OVERLAY_VALIGN_BOTTOM, "bottom", "bottom"},
- {GST_TEXT_OVERLAY_VALIGN_TOP, "top", "top"},
- {GST_TEXT_OVERLAY_VALIGN_POS, "position", "position"},
- {GST_TEXT_OVERLAY_VALIGN_CENTER, "center", "center"},
- {0, NULL, NULL},
- };
-
- if (!text_overlay_valign_type) {
- text_overlay_valign_type =
- g_enum_register_static ("GstTextOverlayVAlign", text_overlay_valign);
- }
- return text_overlay_valign_type;
-}
-
-#define GST_TYPE_TEXT_OVERLAY_HALIGN (gst_text_overlay_halign_get_type())
-static GType
-gst_text_overlay_halign_get_type (void)
-{
- static GType text_overlay_halign_type = 0;
- static const GEnumValue text_overlay_halign[] = {
- {GST_TEXT_OVERLAY_HALIGN_LEFT, "left", "left"},
- {GST_TEXT_OVERLAY_HALIGN_CENTER, "center", "center"},
- {GST_TEXT_OVERLAY_HALIGN_RIGHT, "right", "right"},
- {GST_TEXT_OVERLAY_HALIGN_POS, "position", "position"},
- {0, NULL, NULL},
- };
-
- if (!text_overlay_halign_type) {
- text_overlay_halign_type =
- g_enum_register_static ("GstTextOverlayHAlign", text_overlay_halign);
- }
- return text_overlay_halign_type;
-}
-
-
-#define GST_TYPE_TEXT_OVERLAY_WRAP_MODE (gst_text_overlay_wrap_mode_get_type())
-static GType
-gst_text_overlay_wrap_mode_get_type (void)
-{
- static GType text_overlay_wrap_mode_type = 0;
- static const GEnumValue text_overlay_wrap_mode[] = {
- {GST_TEXT_OVERLAY_WRAP_MODE_NONE, "none", "none"},
- {GST_TEXT_OVERLAY_WRAP_MODE_WORD, "word", "word"},
- {GST_TEXT_OVERLAY_WRAP_MODE_CHAR, "char", "char"},
- {GST_TEXT_OVERLAY_WRAP_MODE_WORD_CHAR, "wordchar", "wordchar"},
- {0, NULL, NULL},
- };
-
- if (!text_overlay_wrap_mode_type) {
- text_overlay_wrap_mode_type =
- g_enum_register_static ("GstTextOverlayWrapMode",
- text_overlay_wrap_mode);
- }
- return text_overlay_wrap_mode_type;
-}
-
-#define GST_TYPE_TEXT_OVERLAY_LINE_ALIGN (gst_text_overlay_line_align_get_type())
-static GType
-gst_text_overlay_line_align_get_type (void)
-{
- static GType text_overlay_line_align_type = 0;
- static const GEnumValue text_overlay_line_align[] = {
- {GST_TEXT_OVERLAY_LINE_ALIGN_LEFT, "left", "left"},
- {GST_TEXT_OVERLAY_LINE_ALIGN_CENTER, "center", "center"},
- {GST_TEXT_OVERLAY_LINE_ALIGN_RIGHT, "right", "right"},
- {0, NULL, NULL}
- };
-
- if (!text_overlay_line_align_type) {
- text_overlay_line_align_type =
- g_enum_register_static ("GstTextOverlayLineAlign",
- text_overlay_line_align);
- }
- return text_overlay_line_align_type;
-}
-
-#define GST_TEXT_OVERLAY_GET_COND(ov) (((GstTextOverlay *)ov)->cond)
-#define GST_TEXT_OVERLAY_WAIT(ov) (g_cond_wait (GST_TEXT_OVERLAY_GET_COND (ov), GST_OBJECT_GET_LOCK (ov)))
-#define GST_TEXT_OVERLAY_SIGNAL(ov) (g_cond_signal (GST_TEXT_OVERLAY_GET_COND (ov)))
-#define GST_TEXT_OVERLAY_BROADCAST(ov)(g_cond_broadcast (GST_TEXT_OVERLAY_GET_COND (ov)))
-
-static GstStateChangeReturn gst_text_overlay_change_state (GstElement * element,
- GstStateChange transition);
-
-static GstCaps *gst_text_overlay_getcaps (GstPad * pad);
-static gboolean gst_text_overlay_setcaps (GstPad * pad, GstCaps * caps);
-static gboolean gst_text_overlay_setcaps_txt (GstPad * pad, GstCaps * caps);
-static gboolean gst_text_overlay_src_event (GstPad * pad, GstEvent * event);
-static gboolean gst_text_overlay_src_query (GstPad * pad, GstQuery * query);
-
-static gboolean gst_text_overlay_video_event (GstPad * pad, GstEvent * event);
-static GstFlowReturn gst_text_overlay_video_chain (GstPad * pad,
- GstBuffer * buffer);
-static GstFlowReturn gst_text_overlay_video_bufferalloc (GstPad * pad,
- guint64 offset, guint size, GstCaps * caps, GstBuffer ** buffer);
-
-static gboolean gst_text_overlay_text_event (GstPad * pad, GstEvent * event);
-static GstFlowReturn gst_text_overlay_text_chain (GstPad * pad,
- GstBuffer * buffer);
-static GstPadLinkReturn gst_text_overlay_text_pad_link (GstPad * pad,
- GstPad * peer);
-static void gst_text_overlay_text_pad_unlink (GstPad * pad);
-static void gst_text_overlay_pop_text (GstTextOverlay * overlay);
-static void gst_text_overlay_update_render_mode (GstTextOverlay * overlay);
-
-static void gst_text_overlay_finalize (GObject * object);
-static void gst_text_overlay_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec);
-static void gst_text_overlay_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec);
-static void gst_text_overlay_adjust_values_with_fontdesc (GstTextOverlay *
- overlay, PangoFontDescription * desc);
-
-GST_BOILERPLATE (GstTextOverlay, gst_text_overlay, GstElement,
- GST_TYPE_ELEMENT);
+G_DEFINE_TYPE (GstTextOverlay, gst_text_overlay, GST_TYPE_BASE_TEXT_OVERLAY);
static void
-gst_text_overlay_base_init (gpointer g_class)
+gst_text_overlay_class_init (GstTextOverlayClass * klass)
{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
- GstTextOverlayClass *klass = GST_TEXT_OVERLAY_CLASS (g_class);
- PangoFontMap *fontmap;
+ GstElementClass *element_class = (GstElementClass *) klass;
gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&src_template_factory));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&video_sink_template_factory));
-
- /* ugh */
- if (!GST_IS_TIME_OVERLAY_CLASS (g_class) &&
- !GST_IS_CLOCK_OVERLAY_CLASS (g_class)) {
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&text_sink_template_factory));
- }
+ gst_static_pad_template_get (&text_sink_template_factory));
gst_element_class_set_details_simple (element_class, "Text overlay",
"Filter/Editor/Video",
"Adds text strings on top of a video buffer",
"David Schleef <ds@schleef.org>, " "Zeeshan Ali <zeeshan.ali@nokia.com>");
-
- /* Only lock for the subclasses here, the base class
- * doesn't have this mutex yet and it's not necessary
- * here */
- if (klass->pango_lock)
- g_mutex_lock (klass->pango_lock);
- fontmap = pango_cairo_font_map_get_default ();
- klass->pango_context =
- pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (fontmap));
- if (klass->pango_lock)
- g_mutex_unlock (klass->pango_lock);
-}
-
-static gchar *
-gst_text_overlay_get_text (GstTextOverlay * overlay, GstBuffer * video_frame)
-{
- return g_strdup (overlay->default_text);
-}
-
-static void
-gst_text_overlay_class_init (GstTextOverlayClass * klass)
-{
- GObjectClass *gobject_class;
- GstElementClass *gstelement_class;
-
- gobject_class = (GObjectClass *) klass;
- gstelement_class = (GstElementClass *) klass;
-
- gobject_class->finalize = gst_text_overlay_finalize;
- gobject_class->set_property = gst_text_overlay_set_property;
- gobject_class->get_property = gst_text_overlay_get_property;
-
- gstelement_class->change_state =
- GST_DEBUG_FUNCPTR (gst_text_overlay_change_state);
-
- klass->pango_lock = g_mutex_new ();
-
- klass->get_text = gst_text_overlay_get_text;
-
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TEXT,
- g_param_spec_string ("text", "text",
- "Text to be display.", DEFAULT_PROP_TEXT,
- G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SHADING,
- g_param_spec_boolean ("shaded-background", "shaded background",
- "Whether to shade the background under the text area",
- DEFAULT_PROP_SHADING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- /**
- * GstTextOverlay:shadow
- *
- * Whether to display a shadow of each letter under the text.
- *
- * Since: 0.10.35
- **/
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SHADOW,
- g_param_spec_boolean ("shadow", "create shadow of text",
- "Whether to create a shadow of the letters under the text",
- DEFAULT_PROP_SHADOW, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VALIGNMENT,
- g_param_spec_enum ("valignment", "vertical alignment",
- "Vertical alignment of the text", GST_TYPE_TEXT_OVERLAY_VALIGN,
- DEFAULT_PROP_VALIGNMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HALIGNMENT,
- g_param_spec_enum ("halignment", "horizontal alignment",
- "Horizontal alignment of the text", GST_TYPE_TEXT_OVERLAY_HALIGN,
- DEFAULT_PROP_HALIGNMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VALIGN,
- g_param_spec_string ("valign", "vertical alignment",
- "Vertical alignment of the text (deprecated; use valignment)",
- DEFAULT_PROP_VALIGN, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HALIGN,
- g_param_spec_string ("halign", "horizontal alignment",
- "Horizontal alignment of the text (deprecated; use halignment)",
- DEFAULT_PROP_HALIGN, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_XPAD,
- g_param_spec_int ("xpad", "horizontal paddding",
- "Horizontal paddding when using left/right alignment", 0, G_MAXINT,
- DEFAULT_PROP_XPAD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_YPAD,
- g_param_spec_int ("ypad", "vertical padding",
- "Vertical padding when using top/bottom alignment", 0, G_MAXINT,
- DEFAULT_PROP_YPAD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DELTAX,
- g_param_spec_int ("deltax", "X position modifier",
- "Shift X position to the left or to the right. Unit is pixels.",
- G_MININT, G_MAXINT, DEFAULT_PROP_DELTAX,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DELTAY,
- g_param_spec_int ("deltay", "Y position modifier",
- "Shift Y position up or down. Unit is pixels.", G_MININT, G_MAXINT,
- DEFAULT_PROP_DELTAY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- /**
- * GstTextOverlay:xpos
- *
- * Horizontal position of the rendered text when using positioned alignment.
- *
- * Since: 0.10.31
- **/
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_XPOS,
- g_param_spec_double ("xpos", "horizontal position",
- "Horizontal position when using position alignment", 0, 1.0,
- DEFAULT_PROP_XPOS,
- G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
- /**
- * GstTextOverlay:ypos
- *
- * Vertical position of the rendered text when using positioned alignment.
- *
- * Since: 0.10.31
- **/
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_YPOS,
- g_param_spec_double ("ypos", "vertical position",
- "Vertical position when using position alignment", 0, 1.0,
- DEFAULT_PROP_YPOS,
- G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_WRAP_MODE,
- g_param_spec_enum ("wrap-mode", "wrap mode",
- "Whether to wrap the text and if so how.",
- GST_TYPE_TEXT_OVERLAY_WRAP_MODE, DEFAULT_PROP_WRAP_MODE,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_FONT_DESC,
- g_param_spec_string ("font-desc", "font description",
- "Pango font description of font to be used for rendering. "
- "See documentation of pango_font_description_from_string "
- "for syntax.", DEFAULT_PROP_FONT_DESC,
- G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
- /**
- * GstTextOverlay:color
- *
- * Color of the rendered text.
- *
- * Since: 0.10.31
- **/
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_COLOR,
- g_param_spec_uint ("color", "Color",
- "Color to use for text (big-endian ARGB).", 0, G_MAXUINT32,
- DEFAULT_PROP_COLOR,
- G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
- /**
- * GstTextOverlay:outline-color
- *
- * Color of the outline of the rendered text.
- *
- * Since: 0.10.35
- **/
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_OUTLINE_COLOR,
- g_param_spec_uint ("outline-color", "Text Outline Color",
- "Color to use for outline the text (big-endian ARGB).", 0,
- G_MAXUINT32, DEFAULT_PROP_OUTLINE_COLOR,
- G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstTextOverlay:line-alignment
- *
- * Alignment of text lines relative to each other (for multi-line text)
- *
- * Since: 0.10.15
- **/
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LINE_ALIGNMENT,
- g_param_spec_enum ("line-alignment", "line alignment",
- "Alignment of text lines relative to each other.",
- GST_TYPE_TEXT_OVERLAY_LINE_ALIGN, DEFAULT_PROP_LINE_ALIGNMENT,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- /**
- * GstTextOverlay:silent
- *
- * If set, no text is rendered. Useful to switch off text rendering
- * temporarily without removing the textoverlay element from the pipeline.
- *
- * Since: 0.10.15
- **/
- /* FIXME 0.11: rename to "visible" or "text-visible" or "render-text" */
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SILENT,
- g_param_spec_boolean ("silent", "silent",
- "Whether to render the text string",
- DEFAULT_PROP_SILENT,
- G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
- /**
- * GstTextOverlay:wait-text
- *
- * If set, the video will block until a subtitle is received on the text pad.
- * If video and subtitles are sent in sync, like from the same demuxer, this
- * property should be set.
- *
- * Since: 0.10.20
- **/
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_WAIT_TEXT,
- g_param_spec_boolean ("wait-text", "Wait Text",
- "Whether to wait for subtitles",
- DEFAULT_PROP_WAIT_TEXT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property (G_OBJECT_CLASS (klass),
- PROP_AUTO_ADJUST_SIZE, g_param_spec_boolean ("auto-resize", "auto resize",
- "Automatically adjust font size to screen-size.",
- DEFAULT_PROP_AUTO_ADJUST_SIZE,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_VERTICAL_RENDER,
- g_param_spec_boolean ("vertical-render", "vertical render",
- "Vertical Render.", DEFAULT_PROP_VERTICAL_RENDER,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-}
-
-static void
-gst_text_overlay_finalize (GObject * object)
-{
- GstTextOverlay *overlay = GST_TEXT_OVERLAY (object);
-
- g_free (overlay->default_text);
-
- if (overlay->text_image) {
- g_free (overlay->text_image);
- overlay->text_image = NULL;
- }
-
- if (overlay->layout) {
- g_object_unref (overlay->layout);
- overlay->layout = NULL;
- }
-
- if (overlay->text_buffer) {
- gst_buffer_unref (overlay->text_buffer);
- overlay->text_buffer = NULL;
- }
-
- if (overlay->cond) {
- g_cond_free (overlay->cond);
- overlay->cond = NULL;
- }
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static void
-gst_text_overlay_init (GstTextOverlay * overlay, GstTextOverlayClass * klass)
-{
- GstPadTemplate *template;
- PangoFontDescription *desc;
-
- /* video sink */
- template = gst_static_pad_template_get (&video_sink_template_factory);
- overlay->video_sinkpad = gst_pad_new_from_template (template, "video_sink");
- gst_object_unref (template);
- gst_pad_set_getcaps_function (overlay->video_sinkpad,
- GST_DEBUG_FUNCPTR (gst_text_overlay_getcaps));
- gst_pad_set_setcaps_function (overlay->video_sinkpad,
- GST_DEBUG_FUNCPTR (gst_text_overlay_setcaps));
- gst_pad_set_event_function (overlay->video_sinkpad,
- GST_DEBUG_FUNCPTR (gst_text_overlay_video_event));
- gst_pad_set_chain_function (overlay->video_sinkpad,
- GST_DEBUG_FUNCPTR (gst_text_overlay_video_chain));
- gst_pad_set_bufferalloc_function (overlay->video_sinkpad,
- GST_DEBUG_FUNCPTR (gst_text_overlay_video_bufferalloc));
- gst_element_add_pad (GST_ELEMENT (overlay), overlay->video_sinkpad);
-
- if (!GST_IS_TIME_OVERLAY_CLASS (klass) && !GST_IS_CLOCK_OVERLAY_CLASS (klass)) {
- /* text sink */
- template = gst_static_pad_template_get (&text_sink_template_factory);
- overlay->text_sinkpad = gst_pad_new_from_template (template, "text_sink");
- gst_object_unref (template);
- gst_pad_set_setcaps_function (overlay->text_sinkpad,
- GST_DEBUG_FUNCPTR (gst_text_overlay_setcaps_txt));
- gst_pad_set_event_function (overlay->text_sinkpad,
- GST_DEBUG_FUNCPTR (gst_text_overlay_text_event));
- gst_pad_set_chain_function (overlay->text_sinkpad,
- GST_DEBUG_FUNCPTR (gst_text_overlay_text_chain));
- gst_pad_set_link_function (overlay->text_sinkpad,
- GST_DEBUG_FUNCPTR (gst_text_overlay_text_pad_link));
- gst_pad_set_unlink_function (overlay->text_sinkpad,
- GST_DEBUG_FUNCPTR (gst_text_overlay_text_pad_unlink));
- gst_element_add_pad (GST_ELEMENT (overlay), overlay->text_sinkpad);
- }
-
- /* (video) source */
- template = gst_static_pad_template_get (&src_template_factory);
- overlay->srcpad = gst_pad_new_from_template (template, "src");
- gst_object_unref (template);
- gst_pad_set_getcaps_function (overlay->srcpad,
- GST_DEBUG_FUNCPTR (gst_text_overlay_getcaps));
- gst_pad_set_event_function (overlay->srcpad,
- GST_DEBUG_FUNCPTR (gst_text_overlay_src_event));
- gst_pad_set_query_function (overlay->srcpad,
- GST_DEBUG_FUNCPTR (gst_text_overlay_src_query));
- gst_element_add_pad (GST_ELEMENT (overlay), overlay->srcpad);
-
- overlay->line_align = DEFAULT_PROP_LINE_ALIGNMENT;
- g_mutex_lock (GST_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
- overlay->layout =
- pango_layout_new (GST_TEXT_OVERLAY_GET_CLASS (overlay)->pango_context);
- desc =
- pango_context_get_font_description (GST_TEXT_OVERLAY_GET_CLASS
- (overlay)->pango_context);
- gst_text_overlay_adjust_values_with_fontdesc (overlay, desc);
-
- overlay->color = DEFAULT_PROP_COLOR;
- overlay->outline_color = DEFAULT_PROP_OUTLINE_COLOR;
- overlay->halign = DEFAULT_PROP_HALIGNMENT;
- overlay->valign = DEFAULT_PROP_VALIGNMENT;
- overlay->xpad = DEFAULT_PROP_XPAD;
- overlay->ypad = DEFAULT_PROP_YPAD;
- overlay->deltax = DEFAULT_PROP_DELTAX;
- overlay->deltay = DEFAULT_PROP_DELTAY;
- overlay->xpos = DEFAULT_PROP_XPOS;
- overlay->ypos = DEFAULT_PROP_YPOS;
-
- overlay->wrap_mode = DEFAULT_PROP_WRAP_MODE;
-
- overlay->want_shading = DEFAULT_PROP_SHADING;
- overlay->want_shadow = DEFAULT_PROP_SHADOW;
- overlay->shading_value = DEFAULT_SHADING_VALUE;
- overlay->silent = DEFAULT_PROP_SILENT;
- overlay->wait_text = DEFAULT_PROP_WAIT_TEXT;
- overlay->auto_adjust_size = DEFAULT_PROP_AUTO_ADJUST_SIZE;
-
- overlay->default_text = g_strdup (DEFAULT_PROP_TEXT);
- overlay->need_render = TRUE;
- overlay->text_image = NULL;
- overlay->use_vertical_render = DEFAULT_PROP_VERTICAL_RENDER;
- gst_text_overlay_update_render_mode (overlay);
-
- overlay->fps_n = 0;
- overlay->fps_d = 1;
-
- overlay->text_buffer = NULL;
- overlay->text_linked = FALSE;
- overlay->cond = g_cond_new ();
- gst_segment_init (&overlay->segment, GST_FORMAT_TIME);
- g_mutex_unlock (GST_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
-}
-
-static void
-gst_text_overlay_update_wrap_mode (GstTextOverlay * overlay)
-{
- if (overlay->wrap_mode == GST_TEXT_OVERLAY_WRAP_MODE_NONE) {
- GST_DEBUG_OBJECT (overlay, "Set wrap mode NONE");
- pango_layout_set_width (overlay->layout, -1);
- } else {
- int width;
-
- if (overlay->auto_adjust_size) {
- width = DEFAULT_SCALE_BASIS * PANGO_SCALE;
- if (overlay->use_vertical_render) {
- width = width * (overlay->height - overlay->ypad * 2) / overlay->width;
- }
- } else {
- width =
- (overlay->use_vertical_render ? overlay->height : overlay->width) *
- PANGO_SCALE;
- }
-
- GST_DEBUG_OBJECT (overlay, "Set layout width %d", overlay->width);
- GST_DEBUG_OBJECT (overlay, "Set wrap mode %d", overlay->wrap_mode);
- pango_layout_set_width (overlay->layout, width);
- pango_layout_set_wrap (overlay->layout, (PangoWrapMode) overlay->wrap_mode);
- }
-}
-
-static void
-gst_text_overlay_update_render_mode (GstTextOverlay * overlay)
-{
- PangoMatrix matrix = PANGO_MATRIX_INIT;
- PangoContext *context = pango_layout_get_context (overlay->layout);
-
- if (overlay->use_vertical_render) {
- pango_matrix_rotate (&matrix, -90);
- pango_context_set_base_gravity (context, PANGO_GRAVITY_AUTO);
- pango_context_set_matrix (context, &matrix);
- pango_layout_set_alignment (overlay->layout, PANGO_ALIGN_LEFT);
- } else {
- pango_context_set_base_gravity (context, PANGO_GRAVITY_SOUTH);
- pango_context_set_matrix (context, &matrix);
- pango_layout_set_alignment (overlay->layout, overlay->line_align);
- }
-}
-
-static gboolean
-gst_text_overlay_setcaps_txt (GstPad * pad, GstCaps * caps)
-{
- GstTextOverlay *overlay;
- GstStructure *structure;
-
- overlay = GST_TEXT_OVERLAY (gst_pad_get_parent (pad));
-
- structure = gst_caps_get_structure (caps, 0);
- overlay->have_pango_markup =
- gst_structure_has_name (structure, "text/x-pango-markup");
-
- gst_object_unref (overlay);
-
- return TRUE;
-}
-
-/* FIXME: upstream nego (e.g. when the video window is resized) */
-
-static gboolean
-gst_text_overlay_setcaps (GstPad * pad, GstCaps * caps)
-{
- GstTextOverlay *overlay;
- GstStructure *structure;
- gboolean ret = FALSE;
- const GValue *fps;
-
- if (!GST_PAD_IS_SINK (pad))
- return TRUE;
-
- g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
-
- overlay = GST_TEXT_OVERLAY (gst_pad_get_parent (pad));
-
- overlay->width = 0;
- overlay->height = 0;
- structure = gst_caps_get_structure (caps, 0);
- fps = gst_structure_get_value (structure, "framerate");
-
- if (fps
- && gst_video_format_parse_caps (caps, &overlay->format, &overlay->width,
- &overlay->height)) {
- ret = gst_pad_set_caps (overlay->srcpad, caps);
- }
-
- overlay->fps_n = gst_value_get_fraction_numerator (fps);
- overlay->fps_d = gst_value_get_fraction_denominator (fps);
-
- if (ret) {
- GST_OBJECT_LOCK (overlay);
- g_mutex_lock (GST_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
- gst_text_overlay_update_wrap_mode (overlay);
- g_mutex_unlock (GST_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
- GST_OBJECT_UNLOCK (overlay);
- }
-
- gst_object_unref (overlay);
-
- return ret;
-}
-
-static void
-gst_text_overlay_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstTextOverlay *overlay = GST_TEXT_OVERLAY (object);
-
- GST_OBJECT_LOCK (overlay);
- switch (prop_id) {
- case PROP_TEXT:
- g_free (overlay->default_text);
- overlay->default_text = g_value_dup_string (value);
- overlay->need_render = TRUE;
- break;
- case PROP_SHADING:
- overlay->want_shading = g_value_get_boolean (value);
- break;
- case PROP_SHADOW:
- overlay->want_shadow = g_value_get_boolean (value);
- break;
- case PROP_XPAD:
- overlay->xpad = g_value_get_int (value);
- break;
- case PROP_YPAD:
- overlay->ypad = g_value_get_int (value);
- break;
- case PROP_DELTAX:
- overlay->deltax = g_value_get_int (value);
- break;
- case PROP_DELTAY:
- overlay->deltay = g_value_get_int (value);
- break;
- case PROP_XPOS:
- overlay->xpos = g_value_get_double (value);
- break;
- case PROP_YPOS:
- overlay->ypos = g_value_get_double (value);
- break;
- case PROP_HALIGN:{
- const gchar *s = g_value_get_string (value);
-
- if (s && g_ascii_strcasecmp (s, "left") == 0)
- overlay->halign = GST_TEXT_OVERLAY_HALIGN_LEFT;
- else if (s && g_ascii_strcasecmp (s, "center") == 0)
- overlay->halign = GST_TEXT_OVERLAY_HALIGN_CENTER;
- else if (s && g_ascii_strcasecmp (s, "right") == 0)
- overlay->halign = GST_TEXT_OVERLAY_HALIGN_RIGHT;
- else
- g_warning ("Invalid value '%s' for textoverlay property 'halign'",
- GST_STR_NULL (s));
- break;
- }
- case PROP_VALIGN:{
- const gchar *s = g_value_get_string (value);
-
- if (s && g_ascii_strcasecmp (s, "baseline") == 0)
- overlay->valign = GST_TEXT_OVERLAY_VALIGN_BASELINE;
- else if (s && g_ascii_strcasecmp (s, "bottom") == 0)
- overlay->valign = GST_TEXT_OVERLAY_VALIGN_BOTTOM;
- else if (s && g_ascii_strcasecmp (s, "top") == 0)
- overlay->valign = GST_TEXT_OVERLAY_VALIGN_TOP;
- else
- g_warning ("Invalid value '%s' for textoverlay property 'valign'",
- GST_STR_NULL (s));
- break;
- }
- case PROP_VALIGNMENT:
- overlay->valign = g_value_get_enum (value);
- break;
- case PROP_HALIGNMENT:
- overlay->halign = g_value_get_enum (value);
- break;
- case PROP_WRAP_MODE:
- overlay->wrap_mode = g_value_get_enum (value);
- g_mutex_lock (GST_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
- gst_text_overlay_update_wrap_mode (overlay);
- g_mutex_unlock (GST_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
- break;
- case PROP_FONT_DESC:
- {
- PangoFontDescription *desc;
- const gchar *fontdesc_str;
-
- fontdesc_str = g_value_get_string (value);
- g_mutex_lock (GST_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
- desc = pango_font_description_from_string (fontdesc_str);
- if (desc) {
- GST_LOG_OBJECT (overlay, "font description set: %s", fontdesc_str);
- pango_layout_set_font_description (overlay->layout, desc);
- gst_text_overlay_adjust_values_with_fontdesc (overlay, desc);
- pango_font_description_free (desc);
- } else {
- GST_WARNING_OBJECT (overlay, "font description parse failed: %s",
- fontdesc_str);
- }
- g_mutex_unlock (GST_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
- break;
- }
- case PROP_COLOR:
- overlay->color = g_value_get_uint (value);
- break;
- case PROP_OUTLINE_COLOR:
- overlay->outline_color = g_value_get_uint (value);
- break;
- case PROP_SILENT:
- overlay->silent = g_value_get_boolean (value);
- break;
- case PROP_LINE_ALIGNMENT:
- overlay->line_align = g_value_get_enum (value);
- g_mutex_lock (GST_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
- pango_layout_set_alignment (overlay->layout,
- (PangoAlignment) overlay->line_align);
- g_mutex_unlock (GST_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
- break;
- case PROP_WAIT_TEXT:
- overlay->wait_text = g_value_get_boolean (value);
- break;
- case PROP_AUTO_ADJUST_SIZE:
- overlay->auto_adjust_size = g_value_get_boolean (value);
- overlay->need_render = TRUE;
- break;
- case PROP_VERTICAL_RENDER:
- overlay->use_vertical_render = g_value_get_boolean (value);
- g_mutex_lock (GST_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
- gst_text_overlay_update_render_mode (overlay);
- g_mutex_unlock (GST_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
- overlay->need_render = TRUE;
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-
- overlay->need_render = TRUE;
- GST_OBJECT_UNLOCK (overlay);
-}
-
-static void
-gst_text_overlay_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- GstTextOverlay *overlay = GST_TEXT_OVERLAY (object);
-
- GST_OBJECT_LOCK (overlay);
- switch (prop_id) {
- case PROP_TEXT:
- g_value_set_string (value, overlay->default_text);
- break;
- case PROP_SHADING:
- g_value_set_boolean (value, overlay->want_shading);
- break;
- case PROP_SHADOW:
- g_value_set_boolean (value, overlay->want_shadow);
- break;
- case PROP_XPAD:
- g_value_set_int (value, overlay->xpad);
- break;
- case PROP_YPAD:
- g_value_set_int (value, overlay->ypad);
- break;
- case PROP_DELTAX:
- g_value_set_int (value, overlay->deltax);
- break;
- case PROP_DELTAY:
- g_value_set_int (value, overlay->deltay);
- break;
- case PROP_XPOS:
- g_value_set_double (value, overlay->xpos);
- break;
- case PROP_YPOS:
- g_value_set_double (value, overlay->ypos);
- break;
- case PROP_VALIGNMENT:
- g_value_set_enum (value, overlay->valign);
- break;
- case PROP_HALIGNMENT:
- g_value_set_enum (value, overlay->halign);
- break;
- case PROP_WRAP_MODE:
- g_value_set_enum (value, overlay->wrap_mode);
- break;
- case PROP_SILENT:
- g_value_set_boolean (value, overlay->silent);
- break;
- case PROP_LINE_ALIGNMENT:
- g_value_set_enum (value, overlay->line_align);
- break;
- case PROP_WAIT_TEXT:
- g_value_set_boolean (value, overlay->wait_text);
- break;
- case PROP_AUTO_ADJUST_SIZE:
- g_value_set_boolean (value, overlay->auto_adjust_size);
- break;
- case PROP_VERTICAL_RENDER:
- g_value_set_boolean (value, overlay->use_vertical_render);
- break;
- case PROP_COLOR:
- g_value_set_uint (value, overlay->color);
- break;
- case PROP_OUTLINE_COLOR:
- g_value_set_uint (value, overlay->outline_color);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-
- overlay->need_render = TRUE;
- GST_OBJECT_UNLOCK (overlay);
-}
-
-static gboolean
-gst_text_overlay_src_query (GstPad * pad, GstQuery * query)
-{
- gboolean ret = FALSE;
- GstTextOverlay *overlay = NULL;
-
- overlay = GST_TEXT_OVERLAY (gst_pad_get_parent (pad));
-
- ret = gst_pad_peer_query (overlay->video_sinkpad, query);
-
- gst_object_unref (overlay);
-
- return ret;
-}
-
-static gboolean
-gst_text_overlay_src_event (GstPad * pad, GstEvent * event)
-{
- gboolean ret = FALSE;
- GstTextOverlay *overlay = NULL;
-
- overlay = GST_TEXT_OVERLAY (gst_pad_get_parent (pad));
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_SEEK:{
- GstSeekFlags flags;
-
- /* We don't handle seek if we have not text pad */
- if (!overlay->text_linked) {
- GST_DEBUG_OBJECT (overlay, "seek received, pushing upstream");
- ret = gst_pad_push_event (overlay->video_sinkpad, event);
- goto beach;
- }
-
- GST_DEBUG_OBJECT (overlay, "seek received, driving from here");
-
- gst_event_parse_seek (event, NULL, NULL, &flags, NULL, NULL, NULL, NULL);
-
- /* Flush downstream, only for flushing seek */
- if (flags & GST_SEEK_FLAG_FLUSH)
- gst_pad_push_event (overlay->srcpad, gst_event_new_flush_start ());
-
- /* Mark ourself as flushing, unblock chains */
- GST_OBJECT_LOCK (overlay);
- overlay->video_flushing = TRUE;
- overlay->text_flushing = TRUE;
- gst_text_overlay_pop_text (overlay);
- GST_OBJECT_UNLOCK (overlay);
-
- /* Seek on each sink pad */
- gst_event_ref (event);
- ret = gst_pad_push_event (overlay->video_sinkpad, event);
- if (ret) {
- ret = gst_pad_push_event (overlay->text_sinkpad, event);
- } else {
- gst_event_unref (event);
- }
- break;
- }
- default:
- if (overlay->text_linked) {
- gst_event_ref (event);
- ret = gst_pad_push_event (overlay->video_sinkpad, event);
- gst_pad_push_event (overlay->text_sinkpad, event);
- } else {
- ret = gst_pad_push_event (overlay->video_sinkpad, event);
- }
- break;
- }
-
-beach:
- gst_object_unref (overlay);
-
- return ret;
-}
-
-static GstCaps *
-gst_text_overlay_getcaps (GstPad * pad)
-{
- GstTextOverlay *overlay;
- GstPad *otherpad;
- GstCaps *caps;
-
- overlay = GST_TEXT_OVERLAY (gst_pad_get_parent (pad));
-
- if (pad == overlay->srcpad)
- otherpad = overlay->video_sinkpad;
- else
- otherpad = overlay->srcpad;
-
- /* we can do what the peer can */
- caps = gst_pad_peer_get_caps (otherpad);
- if (caps) {
- GstCaps *temp;
- const GstCaps *templ;
-
- GST_DEBUG_OBJECT (pad, "peer caps %" GST_PTR_FORMAT, caps);
-
- /* filtered against our padtemplate */
- templ = gst_pad_get_pad_template_caps (otherpad);
- GST_DEBUG_OBJECT (pad, "our template %" GST_PTR_FORMAT, templ);
- temp = gst_caps_intersect (caps, templ);
- GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
- gst_caps_unref (caps);
- /* this is what we can do */
- caps = temp;
- } else {
- /* no peer, our padtemplate is enough then */
- caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
- }
-
- GST_DEBUG_OBJECT (overlay, "returning %" GST_PTR_FORMAT, caps);
-
- gst_object_unref (overlay);
-
- return caps;
-}
-
-static void
-gst_text_overlay_adjust_values_with_fontdesc (GstTextOverlay * overlay,
- PangoFontDescription * desc)
-{
- gint font_size = pango_font_description_get_size (desc) / PANGO_SCALE;
- overlay->shadow_offset = (double) (font_size) / 13.0;
- overlay->outline_offset = (double) (font_size) / 15.0;
- if (overlay->outline_offset < MINIMUM_OUTLINE_OFFSET)
- overlay->outline_offset = MINIMUM_OUTLINE_OFFSET;
-}
-
-#define CAIRO_UNPREMULTIPLY(a,r,g,b) G_STMT_START { \
- b = (a > 0) ? MIN ((b * 255 + a / 2) / a, 255) : 0; \
- g = (a > 0) ? MIN ((g * 255 + a / 2) / a, 255) : 0; \
- r = (a > 0) ? MIN ((r * 255 + a / 2) / a, 255) : 0; \
-} G_STMT_END
-
-static inline void
-gst_text_overlay_blit_1 (GstTextOverlay * overlay, guchar * dest, gint xpos,
- gint ypos, guchar * text_image, guint dest_stride)
-{
- gint i, j = 0;
- gint x, y;
- guchar r, g, b, a;
- guchar *pimage;
- guchar *py;
- gint width = overlay->image_width;
- gint height = overlay->image_height;
-
- if (xpos < 0) {
- xpos = 0;
- }
-
- if (xpos + width > overlay->width) {
- width = overlay->width - xpos;
- }
-
- if (ypos + height > overlay->height) {
- height = overlay->height - ypos;
- }
-
- dest += (ypos / 1) * dest_stride;
-
- for (i = 0; i < height; i++) {
- pimage = text_image + 4 * (i * overlay->image_width);
- py = dest + i * dest_stride + xpos;
- for (j = 0; j < width; j++) {
- b = pimage[CAIRO_ARGB_B];
- g = pimage[CAIRO_ARGB_G];
- r = pimage[CAIRO_ARGB_R];
- a = pimage[CAIRO_ARGB_A];
- CAIRO_UNPREMULTIPLY (a, r, g, b);
-
- pimage += 4;
- if (a == 0) {
- py++;
- continue;
- }
- COMP_Y (y, r, g, b);
- x = *py;
- BLEND (*py++, a, y, x);
- }
- }
-}
-
-static inline void
-gst_text_overlay_blit_sub2x2cbcr (GstTextOverlay * overlay,
- guchar * destcb, guchar * destcr, gint xpos, gint ypos, guchar * text_image,
- guint destcb_stride, guint destcr_stride, guint pix_stride)
-{
- gint i, j;
- gint x, cb, cr;
- gushort r, g, b, a;
- gushort r1, g1, b1, a1;
- guchar *pimage1, *pimage2;
- guchar *pcb, *pcr;
- gint width = overlay->image_width - 2;
- gint height = overlay->image_height - 2;
-
- xpos *= pix_stride;
-
- if (xpos < 0) {
- xpos = 0;
- }
-
- if (xpos + width > overlay->width) {
- width = overlay->width - xpos;
- }
-
- if (ypos + height > overlay->height) {
- height = overlay->height - ypos;
- }
-
- destcb += (ypos / 2) * destcb_stride;
- destcr += (ypos / 2) * destcr_stride;
-
- for (i = 0; i < height; i += 2) {
- pimage1 = text_image + 4 * (i * overlay->image_width);
- pimage2 = pimage1 + 4 * overlay->image_width;
- pcb = destcb + (i / 2) * destcb_stride + xpos / 2;
- pcr = destcr + (i / 2) * destcr_stride + xpos / 2;
- for (j = 0; j < width; j += 2) {
- b = pimage1[CAIRO_ARGB_B];
- g = pimage1[CAIRO_ARGB_G];
- r = pimage1[CAIRO_ARGB_R];
- a = pimage1[CAIRO_ARGB_A];
- CAIRO_UNPREMULTIPLY (a, r, g, b);
- pimage1 += 4;
-
- b1 = pimage1[CAIRO_ARGB_B];
- g1 = pimage1[CAIRO_ARGB_G];
- r1 = pimage1[CAIRO_ARGB_R];
- a1 = pimage1[CAIRO_ARGB_A];
- CAIRO_UNPREMULTIPLY (a1, r1, g1, b1);
- b += b1;
- g += g1;
- r += r1;
- a += a1;
- pimage1 += 4;
-
- b1 = pimage2[CAIRO_ARGB_B];
- g1 = pimage2[CAIRO_ARGB_G];
- r1 = pimage2[CAIRO_ARGB_R];
- a1 = pimage2[CAIRO_ARGB_A];
- CAIRO_UNPREMULTIPLY (a1, r1, g1, b1);
- b += b1;
- g += g1;
- r += r1;
- a += a1;
- pimage2 += 4;
-
- /* + 2 for rounding */
- b1 = pimage2[CAIRO_ARGB_B];
- g1 = pimage2[CAIRO_ARGB_G];
- r1 = pimage2[CAIRO_ARGB_R];
- a1 = pimage2[CAIRO_ARGB_A];
- CAIRO_UNPREMULTIPLY (a1, r1, g1, b1);
- b += b1 + 2;
- g += g1 + 2;
- r += r1 + 2;
- a += a1 + 2;
- pimage2 += 4;
-
- b /= 4;
- g /= 4;
- r /= 4;
- a /= 4;
-
- if (a == 0) {
- pcb += pix_stride;
- pcr += pix_stride;
- continue;
- }
- COMP_U (cb, r, g, b);
- COMP_V (cr, r, g, b);
-
- x = *pcb;
- BLEND (*pcb, a, cb, x);
- x = *pcr;
- BLEND (*pcr, a, cr, x);
-
- pcb += pix_stride;
- pcr += pix_stride;
- }
- }
-}
-
-static void
-gst_text_overlay_render_pangocairo (GstTextOverlay * overlay,
- const gchar * string, gint textlen)
-{
- cairo_t *cr;
- cairo_surface_t *surface;
- PangoRectangle ink_rect, logical_rect;
- cairo_matrix_t cairo_matrix;
- int width, height;
- double scalef = 1.0;
- double a, r, g, b;
-
- g_mutex_lock (GST_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
-
- if (overlay->auto_adjust_size) {
- /* 640 pixel is default */
- scalef = (double) (overlay->width) / DEFAULT_SCALE_BASIS;
- }
- pango_layout_set_width (overlay->layout, -1);
- /* set text on pango layout */
- pango_layout_set_markup (overlay->layout, string, textlen);
-
- /* get subtitle image size */
- pango_layout_get_pixel_extents (overlay->layout, &ink_rect, &logical_rect);
-
- width = (logical_rect.width + overlay->shadow_offset) * scalef;
-
- if (width + overlay->deltax >
- (overlay->use_vertical_render ? overlay->height : overlay->width)) {
- /*
- * subtitle image width is larger then overlay width
- * so rearrange overlay wrap mode.
- */
- gst_text_overlay_update_wrap_mode (overlay);
- pango_layout_get_pixel_extents (overlay->layout, &ink_rect, &logical_rect);
- width = overlay->width;
- }
-
- height =
- (logical_rect.height + logical_rect.y + overlay->shadow_offset) * scalef;
- if (height > overlay->height) {
- height = overlay->height;
- }
- if (overlay->use_vertical_render) {
- PangoRectangle rect;
- PangoContext *context;
- PangoMatrix matrix = PANGO_MATRIX_INIT;
- int tmp;
-
- context = pango_layout_get_context (overlay->layout);
-
- pango_matrix_rotate (&matrix, -90);
-
- rect.x = rect.y = 0;
- rect.width = width;
- rect.height = height;
- pango_matrix_transform_pixel_rectangle (&matrix, &rect);
- matrix.x0 = -rect.x;
- matrix.y0 = -rect.y;
-
- pango_context_set_matrix (context, &matrix);
-
- cairo_matrix.xx = matrix.xx;
- cairo_matrix.yx = matrix.yx;
- cairo_matrix.xy = matrix.xy;
- cairo_matrix.yy = matrix.yy;
- cairo_matrix.x0 = matrix.x0;
- cairo_matrix.y0 = matrix.y0;
- cairo_matrix_scale (&cairo_matrix, scalef, scalef);
-
- tmp = height;
- height = width;
- width = tmp;
- } else {
- cairo_matrix_init_scale (&cairo_matrix, scalef, scalef);
- }
-
- /* reallocate surface */
- overlay->text_image = g_realloc (overlay->text_image, 4 * width * height);
-
- surface = cairo_image_surface_create_for_data (overlay->text_image,
- CAIRO_FORMAT_ARGB32, width, height, width * 4);
- cr = cairo_create (surface);
-
- /* clear surface */
- cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
- cairo_paint (cr);
-
- cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
-
- if (overlay->want_shading)
- cairo_paint_with_alpha (cr, overlay->shading_value);
-
- /* apply transformations */
- cairo_set_matrix (cr, &cairo_matrix);
-
- /* FIXME: We use show_layout everywhere except for the surface
- * because it's really faster and internally does all kinds of
- * caching. Unfortunately we have to paint to a cairo path for
- * the outline and this is slow. Once Pango supports user fonts
- * we should use them, see
- * https://bugzilla.gnome.org/show_bug.cgi?id=598695
- *
- * Idea would the be, to create a cairo user font that
- * does shadow, outline, text painting in the
- * render_glyph function.
- */
-
- /* draw shadow text */
- if (overlay->want_shadow) {
- cairo_save (cr);
- cairo_translate (cr, overlay->shadow_offset, overlay->shadow_offset);
- cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.5);
- pango_cairo_show_layout (cr, overlay->layout);
- cairo_restore (cr);
- }
-
- a = (overlay->outline_color >> 24) & 0xff;
- r = (overlay->outline_color >> 16) & 0xff;
- g = (overlay->outline_color >> 8) & 0xff;
- b = (overlay->outline_color >> 0) & 0xff;
-
- /* draw outline text */
- cairo_save (cr);
- cairo_set_source_rgba (cr, r / 255.0, g / 255.0, b / 255.0, a / 255.0);
- cairo_set_line_width (cr, overlay->outline_offset);
- pango_cairo_layout_path (cr, overlay->layout);
- cairo_stroke (cr);
- cairo_restore (cr);
-
- a = (overlay->color >> 24) & 0xff;
- r = (overlay->color >> 16) & 0xff;
- g = (overlay->color >> 8) & 0xff;
- b = (overlay->color >> 0) & 0xff;
-
- /* draw text */
- cairo_save (cr);
- cairo_set_source_rgba (cr, r / 255.0, g / 255.0, b / 255.0, a / 255.0);
- pango_cairo_show_layout (cr, overlay->layout);
- cairo_restore (cr);
-
- cairo_destroy (cr);
- cairo_surface_destroy (surface);
- overlay->image_width = width;
- overlay->image_height = height;
- overlay->baseline_y = ink_rect.y;
-
- g_mutex_unlock (GST_TEXT_OVERLAY_GET_CLASS (overlay)->pango_lock);
-}
-
-#define BOX_XPAD 6
-#define BOX_YPAD 6
-
-static inline void
-gst_text_overlay_shade_planar_Y (GstTextOverlay * overlay, guchar * dest,
- gint x0, gint x1, gint y0, gint y1)
-{
- gint i, j, dest_stride;
-
- dest_stride = gst_video_format_get_row_stride (overlay->format, 0,
- overlay->width);
-
- x0 = CLAMP (x0 - BOX_XPAD, 0, overlay->width);
- x1 = CLAMP (x1 + BOX_XPAD, 0, overlay->width);
-
- y0 = CLAMP (y0 - BOX_YPAD, 0, overlay->height);
- y1 = CLAMP (y1 + BOX_YPAD, 0, overlay->height);
-
- for (i = y0; i < y1; ++i) {
- for (j = x0; j < x1; ++j) {
- gint y = dest[(i * dest_stride) + j] + overlay->shading_value;
-
- dest[(i * dest_stride) + j] = CLAMP (y, 0, 255);
- }
- }
-}
-
-static inline void
-gst_text_overlay_shade_packed_Y (GstTextOverlay * overlay, guchar * dest,
- gint x0, gint x1, gint y0, gint y1)
-{
- gint i, j;
- guint dest_stride, pixel_stride, component_offset;
-
- dest_stride = gst_video_format_get_row_stride (overlay->format, 0,
- overlay->width);
- pixel_stride = gst_video_format_get_pixel_stride (overlay->format, 0);
- component_offset =
- gst_video_format_get_component_offset (overlay->format, 0, overlay->width,
- overlay->height);
-
- x0 = CLAMP (x0 - BOX_XPAD, 0, overlay->width);
- x1 = CLAMP (x1 + BOX_XPAD, 0, overlay->width);
-
- y0 = CLAMP (y0 - BOX_YPAD, 0, overlay->height);
- y1 = CLAMP (y1 + BOX_YPAD, 0, overlay->height);
-
- if (x0 != 0)
- x0 = gst_video_format_get_component_width (overlay->format, 0, x0);
- if (x1 != 0)
- x1 = gst_video_format_get_component_width (overlay->format, 0, x1);
-
- if (y0 != 0)
- y0 = gst_video_format_get_component_height (overlay->format, 0, y0);
- if (y1 != 0)
- y1 = gst_video_format_get_component_height (overlay->format, 0, y1);
-
- for (i = y0; i < y1; i++) {
- for (j = x0; j < x1; j++) {
- gint y;
- gint y_pos;
-
- y_pos = (i * dest_stride) + j * pixel_stride + component_offset;
- y = dest[y_pos] + overlay->shading_value;
-
- dest[y_pos] = CLAMP (y, 0, 255);
- }
- }
-}
-
-#define gst_text_overlay_shade_BGRx gst_text_overlay_shade_xRGB
-#define gst_text_overlay_shade_RGBx gst_text_overlay_shade_xRGB
-#define gst_text_overlay_shade_xBGR gst_text_overlay_shade_xRGB
-static inline void
-gst_text_overlay_shade_xRGB (GstTextOverlay * overlay, guchar * dest,
- gint x0, gint x1, gint y0, gint y1)
-{
- gint i, j;
-
- x0 = CLAMP (x0 - BOX_XPAD, 0, overlay->width);
- x1 = CLAMP (x1 + BOX_XPAD, 0, overlay->width);
-
- y0 = CLAMP (y0 - BOX_YPAD, 0, overlay->height);
- y1 = CLAMP (y1 + BOX_YPAD, 0, overlay->height);
-
- for (i = y0; i < y1; i++) {
- for (j = x0; j < x1; j++) {
- gint y, y_pos, k;
-
- y_pos = (i * 4 * overlay->width) + j * 4;
- for (k = 0; k < 4; k++) {
- y = dest[y_pos + k] + overlay->shading_value;
- dest[y_pos + k] = CLAMP (y, 0, 255);
- }
- }
- }
-}
-
-#define ARGB_SHADE_FUNCTION(name, OFFSET) \
-static inline void \
-gst_text_overlay_shade_##name (GstTextOverlay * overlay, guchar * dest, \
-gint x0, gint x1, gint y0, gint y1) \
-{ \
- gint i, j;\
- \
- x0 = CLAMP (x0 - BOX_XPAD, 0, overlay->width);\
- x1 = CLAMP (x1 + BOX_XPAD, 0, overlay->width);\
- \
- y0 = CLAMP (y0 - BOX_YPAD, 0, overlay->height);\
- y1 = CLAMP (y1 + BOX_YPAD, 0, overlay->height);\
- \
- for (i = y0; i < y1; i++) {\
- for (j = x0; j < x1; j++) {\
- gint y, y_pos, k;\
- y_pos = (i * 4 * overlay->width) + j * 4;\
- for (k = OFFSET; k < 3+OFFSET; k++) {\
- y = dest[y_pos + k] + overlay->shading_value;\
- dest[y_pos + k] = CLAMP (y, 0, 255);\
- }\
- }\
- }\
-}
-ARGB_SHADE_FUNCTION (ARGB, 1);
-ARGB_SHADE_FUNCTION (ABGR, 1);
-ARGB_SHADE_FUNCTION (RGBA, 0);
-ARGB_SHADE_FUNCTION (BGRA, 0);
-
-
-/* FIXME:
- * - use proper strides and offset for I420
- * - don't draw over the edge of the picture (try a longer
- * text with a huge font size)
- */
-
-static inline void
-gst_text_overlay_blit_NV12_NV21 (GstTextOverlay * overlay,
- guint8 * yuv_pixels, gint xpos, gint ypos)
-{
- int y_stride, uv_stride;
- int u_offset, v_offset;
- int h, w;
-
- /* because U/V is 2x2 subsampled, we need to round, either up or down,
- * to a boundary of integer number of U/V pixels:
- */
- xpos = GST_ROUND_UP_2 (xpos);
- ypos = GST_ROUND_UP_2 (ypos);
-
- w = overlay->width;
- h = overlay->height;
-
- y_stride = gst_video_format_get_row_stride (overlay->format, 0, w);
- uv_stride = gst_video_format_get_row_stride (overlay->format, 1, w);
- u_offset = gst_video_format_get_component_offset (overlay->format, 1, w, h);
- v_offset = gst_video_format_get_component_offset (overlay->format, 2, w, h);
-
- gst_text_overlay_blit_1 (overlay, yuv_pixels, xpos, ypos, overlay->text_image,
- y_stride);
- gst_text_overlay_blit_sub2x2cbcr (overlay, yuv_pixels + u_offset,
- yuv_pixels + v_offset, xpos, ypos, overlay->text_image, uv_stride,
- uv_stride, 2);
-}
-
-static inline void
-gst_text_overlay_blit_I420 (GstTextOverlay * overlay,
- guint8 * yuv_pixels, gint xpos, gint ypos)
-{
- int y_stride, u_stride, v_stride;
- int u_offset, v_offset;
- int h, w;
-
- /* because U/V is 2x2 subsampled, we need to round, either up or down,
- * to a boundary of integer number of U/V pixels:
- */
- xpos = GST_ROUND_UP_2 (xpos);
- ypos = GST_ROUND_UP_2 (ypos);
-
- w = overlay->width;
- h = overlay->height;
-
- y_stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 0, w);
- u_stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 1, w);
- v_stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 2, w);
- u_offset =
- gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 1, w, h);
- v_offset =
- gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 2, w, h);
-
- gst_text_overlay_blit_1 (overlay, yuv_pixels, xpos, ypos, overlay->text_image,
- y_stride);
- gst_text_overlay_blit_sub2x2cbcr (overlay, yuv_pixels + u_offset,
- yuv_pixels + v_offset, xpos, ypos, overlay->text_image, u_stride,
- v_stride, 1);
-}
-
-static inline void
-gst_text_overlay_blit_UYVY (GstTextOverlay * overlay,
- guint8 * yuv_pixels, gint xpos, gint ypos)
-{
- int a0, r0, g0, b0;
- int a1, r1, g1, b1;
- int y0, y1, u, v;
- int i, j;
- int h, w;
- guchar *pimage, *dest;
-
- /* because U/V is 2x horizontally subsampled, we need to round to a
- * boundary of integer number of U/V pixels in x dimension:
- */
- xpos = GST_ROUND_UP_2 (xpos);
-
- w = overlay->image_width - 2;
- h = overlay->image_height - 2;
-
- if (xpos < 0) {
- xpos = 0;
- }
-
- if (xpos + w > overlay->width) {
- w = overlay->width - xpos;
- }
-
- if (ypos + h > overlay->height) {
- h = overlay->height - ypos;
- }
-
- for (i = 0; i < h; i++) {
- pimage = overlay->text_image + i * overlay->image_width * 4;
- dest = yuv_pixels + (i + ypos) * overlay->width * 2 + xpos * 2;
- for (j = 0; j < w; j += 2) {
- b0 = pimage[CAIRO_ARGB_B];
- g0 = pimage[CAIRO_ARGB_G];
- r0 = pimage[CAIRO_ARGB_R];
- a0 = pimage[CAIRO_ARGB_A];
- CAIRO_UNPREMULTIPLY (a0, r0, g0, b0);
- pimage += 4;
-
- b1 = pimage[CAIRO_ARGB_B];
- g1 = pimage[CAIRO_ARGB_G];
- r1 = pimage[CAIRO_ARGB_R];
- a1 = pimage[CAIRO_ARGB_A];
- CAIRO_UNPREMULTIPLY (a1, r1, g1, b1);
- pimage += 4;
-
- a0 += a1 + 2;
- a0 /= 2;
- if (a0 == 0) {
- dest += 4;
- continue;
- }
-
- COMP_Y (y0, r0, g0, b0);
- COMP_Y (y1, r1, g1, b1);
-
- b0 += b1 + 2;
- g0 += g1 + 2;
- r0 += r1 + 2;
-
- b0 /= 2;
- g0 /= 2;
- r0 /= 2;
-
- COMP_U (u, r0, g0, b0);
- COMP_V (v, r0, g0, b0);
-
- BLEND (*dest, a0, u, *dest);
- dest++;
- BLEND (*dest, a0, y0, *dest);
- dest++;
- BLEND (*dest, a0, v, *dest);
- dest++;
- BLEND (*dest, a0, y1, *dest);
- dest++;
- }
- }
-}
-
-static inline void
-gst_text_overlay_blit_AYUV (GstTextOverlay * overlay,
- guint8 * rgb_pixels, gint xpos, gint ypos)
-{
- int a, r, g, b, a1;
- int y, u, v;
- int i, j;
- int h, w;
- guchar *pimage, *dest;
-
- w = overlay->image_width;
- h = overlay->image_height;
-
- if (xpos < 0) {
- xpos = 0;
- }
-
- if (xpos + w > overlay->width) {
- w = overlay->width - xpos;
- }
-
- if (ypos + h > overlay->height) {
- h = overlay->height - ypos;
- }
-
- for (i = 0; i < h; i++) {
- pimage = overlay->text_image + i * overlay->image_width * 4;
- dest = rgb_pixels + (i + ypos) * 4 * overlay->width + xpos * 4;
- for (j = 0; j < w; j++) {
- a = pimage[CAIRO_ARGB_A];
- b = pimage[CAIRO_ARGB_B];
- g = pimage[CAIRO_ARGB_G];
- r = pimage[CAIRO_ARGB_R];
-
- CAIRO_UNPREMULTIPLY (a, r, g, b);
-
- // convert background to yuv
- COMP_Y (y, r, g, b);
- COMP_U (u, r, g, b);
- COMP_V (v, r, g, b);
-
- // preform text "OVER" background alpha compositing
- a1 = a + (dest[0] * (255 - a)) / 255 + 1; // add 1 to prevent divide by 0
- OVER (dest[1], a, y, dest[0], dest[1], a1);
- OVER (dest[2], a, u, dest[0], dest[2], a1);
- OVER (dest[3], a, v, dest[0], dest[3], a1);
- dest[0] = a1 - 1; // remove the temporary 1 we added
-
- pimage += 4;
- dest += 4;
- }
- }
-}
-
-#define xRGB_BLIT_FUNCTION(name, R, G, B) \
-static inline void \
-gst_text_overlay_blit_##name (GstTextOverlay * overlay, \
- guint8 * rgb_pixels, gint xpos, gint ypos) \
-{ \
- int a, r, g, b; \
- int i, j; \
- int h, w; \
- guchar *pimage, *dest; \
- \
- w = overlay->image_width; \
- h = overlay->image_height; \
- \
- if (xpos < 0) { \
- xpos = 0; \
- } \
- \
- if (xpos + w > overlay->width) { \
- w = overlay->width - xpos; \
- } \
- \
- if (ypos + h > overlay->height) { \
- h = overlay->height - ypos; \
- } \
- \
- for (i = 0; i < h; i++) { \
- pimage = overlay->text_image + i * overlay->image_width * 4; \
- dest = rgb_pixels + (i + ypos) * 4 * overlay->width + xpos * 4; \
- for (j = 0; j < w; j++) { \
- a = pimage[CAIRO_ARGB_A]; \
- b = pimage[CAIRO_ARGB_B]; \
- g = pimage[CAIRO_ARGB_G]; \
- r = pimage[CAIRO_ARGB_R]; \
- CAIRO_UNPREMULTIPLY (a, r, g, b); \
- b = (b*a + dest[B] * (255-a)) / 255; \
- g = (g*a + dest[G] * (255-a)) / 255; \
- r = (r*a + dest[R] * (255-a)) / 255; \
- \
- dest[B] = b; \
- dest[G] = g; \
- dest[R] = r; \
- pimage += 4; \
- dest += 4; \
- } \
- } \
-}
-xRGB_BLIT_FUNCTION (xRGB, 1, 2, 3);
-xRGB_BLIT_FUNCTION (BGRx, 2, 1, 0);
-xRGB_BLIT_FUNCTION (xBGR, 3, 2, 1);
-xRGB_BLIT_FUNCTION (RGBx, 0, 1, 2);
-
-#define ARGB_BLIT_FUNCTION(name, A, R, G, B) \
-static inline void \
-gst_text_overlay_blit_##name (GstTextOverlay * overlay, \
- guint8 * rgb_pixels, gint xpos, gint ypos) \
-{ \
- int a, r, g, b, a1; \
- int i, j; \
- int h, w; \
- guchar *pimage, *dest; \
- \
- w = overlay->image_width; \
- h = overlay->image_height; \
- \
- if (xpos < 0) { \
- xpos = 0; \
- } \
- \
- if (xpos + w > overlay->width) { \
- w = overlay->width - xpos; \
- } \
- \
- if (ypos + h > overlay->height) { \
- h = overlay->height - ypos; \
- } \
- \
- for (i = 0; i < h; i++) { \
- pimage = overlay->text_image + i * overlay->image_width * 4; \
- dest = rgb_pixels + (i + ypos) * 4 * overlay->width + xpos * 4; \
- for (j = 0; j < w; j++) { \
- a = pimage[CAIRO_ARGB_A]; \
- b = pimage[CAIRO_ARGB_B]; \
- g = pimage[CAIRO_ARGB_G]; \
- r = pimage[CAIRO_ARGB_R]; \
- CAIRO_UNPREMULTIPLY (a, r, g, b); \
- a1 = a + (dest[A] * (255 - a)) / 255 + 1; \
- OVER (dest[R], a, r, dest[0], dest[R], a1); \
- OVER (dest[G], a, g, dest[0], dest[G], a1); \
- OVER (dest[B], a, b, dest[0], dest[B], a1); \
- dest[A] = a1 - 1; \
- pimage += 4; \
- dest += 4; \
- } \
- } \
}
-ARGB_BLIT_FUNCTION (RGBA, 3, 0, 1, 2);
-ARGB_BLIT_FUNCTION (BGRA, 3, 2, 1, 0);
-ARGB_BLIT_FUNCTION (ARGB, 0, 1, 2, 3);
-ARGB_BLIT_FUNCTION (ABGR, 0, 3, 2, 1);
static void
-gst_text_overlay_render_text (GstTextOverlay * overlay,
- const gchar * text, gint textlen)
+gst_text_overlay_init (GstTextOverlay * overlay)
{
- gchar *string;
-
- if (!overlay->need_render) {
- GST_DEBUG ("Using previously rendered text.");
- return;
- }
-
- /* -1 is the whole string */
- if (text != NULL && textlen < 0) {
- textlen = strlen (text);
- }
-
- if (text != NULL) {
- string = g_strndup (text, textlen);
- } else { /* empty string */
- string = g_strdup (" ");
- }
- g_strdelimit (string, "\r\t", ' ');
- textlen = strlen (string);
-
- /* FIXME: should we check for UTF-8 here? */
-
- GST_DEBUG ("Rendering '%s'", string);
- gst_text_overlay_render_pangocairo (overlay, string, textlen);
-
- g_free (string);
-
- overlay->need_render = FALSE;
}
-
-static GstFlowReturn
-gst_text_overlay_push_frame (GstTextOverlay * overlay, GstBuffer * video_frame)
-{
- gint xpos, ypos;
- gint width, height;
- GstTextOverlayVAlign valign;
- GstTextOverlayHAlign halign;
-
- width = overlay->image_width;
- height = overlay->image_height;
-
- video_frame = gst_buffer_make_writable (video_frame);
-
- if (overlay->use_vertical_render)
- halign = GST_TEXT_OVERLAY_HALIGN_RIGHT;
- else
- halign = overlay->halign;
-
- switch (halign) {
- case GST_TEXT_OVERLAY_HALIGN_LEFT:
- xpos = overlay->xpad;
- break;
- case GST_TEXT_OVERLAY_HALIGN_CENTER:
- xpos = (overlay->width - width) / 2;
- break;
- case GST_TEXT_OVERLAY_HALIGN_RIGHT:
- xpos = overlay->width - width - overlay->xpad;
- break;
- case GST_TEXT_OVERLAY_HALIGN_POS:
- xpos = (gint) (overlay->width * overlay->xpos) - width / 2;
- xpos = CLAMP (xpos, 0, overlay->width - width);
- if (xpos < 0)
- xpos = 0;
- break;
- default:
- xpos = 0;
- }
- xpos += overlay->deltax;
-
- if (overlay->use_vertical_render)
- valign = GST_TEXT_OVERLAY_VALIGN_TOP;
- else
- valign = overlay->valign;
-
- switch (valign) {
- case GST_TEXT_OVERLAY_VALIGN_BOTTOM:
- ypos = overlay->height - height - overlay->ypad;
- break;
- case GST_TEXT_OVERLAY_VALIGN_BASELINE:
- ypos = overlay->height - (height + overlay->ypad);
- break;
- case GST_TEXT_OVERLAY_VALIGN_TOP:
- ypos = overlay->ypad;
- break;
- case GST_TEXT_OVERLAY_VALIGN_POS:
- ypos = (gint) (overlay->height * overlay->ypos) - height / 2;
- ypos = CLAMP (ypos, 0, overlay->height - height);
- break;
- case GST_TEXT_OVERLAY_VALIGN_CENTER:
- ypos = (overlay->height - height) / 2;
- break;
- default:
- ypos = overlay->ypad;
- break;
- }
- ypos += overlay->deltay;
-
- /* shaded background box */
- if (overlay->want_shading) {
- switch (overlay->format) {
- case GST_VIDEO_FORMAT_I420:
- case GST_VIDEO_FORMAT_NV12:
- case GST_VIDEO_FORMAT_NV21:
- gst_text_overlay_shade_planar_Y (overlay,
- GST_BUFFER_DATA (video_frame), xpos, xpos + overlay->image_width,
- ypos, ypos + overlay->image_height);
- break;
- case GST_VIDEO_FORMAT_AYUV:
- case GST_VIDEO_FORMAT_UYVY:
- gst_text_overlay_shade_packed_Y (overlay,
- GST_BUFFER_DATA (video_frame), xpos, xpos + overlay->image_width,
- ypos, ypos + overlay->image_height);
- break;
- case GST_VIDEO_FORMAT_xRGB:
- gst_text_overlay_shade_xRGB (overlay,
- GST_BUFFER_DATA (video_frame), xpos, xpos + overlay->image_width,
- ypos, ypos + overlay->image_height);
- break;
- case GST_VIDEO_FORMAT_xBGR:
- gst_text_overlay_shade_xBGR (overlay,
- GST_BUFFER_DATA (video_frame), xpos, xpos + overlay->image_width,
- ypos, ypos + overlay->image_height);
- break;
- case GST_VIDEO_FORMAT_BGRx:
- gst_text_overlay_shade_BGRx (overlay,
- GST_BUFFER_DATA (video_frame), xpos, xpos + overlay->image_width,
- ypos, ypos + overlay->image_height);
- break;
- case GST_VIDEO_FORMAT_RGBx:
- gst_text_overlay_shade_RGBx (overlay,
- GST_BUFFER_DATA (video_frame), xpos, xpos + overlay->image_width,
- ypos, ypos + overlay->image_height);
- break;
- case GST_VIDEO_FORMAT_ARGB:
- gst_text_overlay_shade_ARGB (overlay,
- GST_BUFFER_DATA (video_frame), xpos, xpos + overlay->image_width,
- ypos, ypos + overlay->image_height);
- break;
- case GST_VIDEO_FORMAT_ABGR:
- gst_text_overlay_shade_ABGR (overlay,
- GST_BUFFER_DATA (video_frame), xpos, xpos + overlay->image_width,
- ypos, ypos + overlay->image_height);
- break;
- case GST_VIDEO_FORMAT_RGBA:
- gst_text_overlay_shade_RGBA (overlay,
- GST_BUFFER_DATA (video_frame), xpos, xpos + overlay->image_width,
- ypos, ypos + overlay->image_height);
- break;
- case GST_VIDEO_FORMAT_BGRA:
- gst_text_overlay_shade_BGRA (overlay,
- GST_BUFFER_DATA (video_frame), xpos, xpos + overlay->image_width,
- ypos, ypos + overlay->image_height);
- break;
- default:
- g_assert_not_reached ();
- }
- }
-
- if (ypos < 0)
- ypos = 0;
-
- if (overlay->text_image) {
- switch (overlay->format) {
- case GST_VIDEO_FORMAT_I420:
- gst_text_overlay_blit_I420 (overlay,
- GST_BUFFER_DATA (video_frame), xpos, ypos);
- break;
- case GST_VIDEO_FORMAT_NV12:
- case GST_VIDEO_FORMAT_NV21:
- gst_text_overlay_blit_NV12_NV21 (overlay,
- GST_BUFFER_DATA (video_frame), xpos, ypos);
- break;
- case GST_VIDEO_FORMAT_UYVY:
- gst_text_overlay_blit_UYVY (overlay,
- GST_BUFFER_DATA (video_frame), xpos, ypos);
- break;
- case GST_VIDEO_FORMAT_AYUV:
- gst_text_overlay_blit_AYUV (overlay,
- GST_BUFFER_DATA (video_frame), xpos, ypos);
- break;
- case GST_VIDEO_FORMAT_BGRx:
- gst_text_overlay_blit_BGRx (overlay,
- GST_BUFFER_DATA (video_frame), xpos, ypos);
- break;
- case GST_VIDEO_FORMAT_xRGB:
- gst_text_overlay_blit_xRGB (overlay,
- GST_BUFFER_DATA (video_frame), xpos, ypos);
- break;
- case GST_VIDEO_FORMAT_RGBx:
- gst_text_overlay_blit_RGBx (overlay,
- GST_BUFFER_DATA (video_frame), xpos, ypos);
- break;
- case GST_VIDEO_FORMAT_xBGR:
- gst_text_overlay_blit_xBGR (overlay,
- GST_BUFFER_DATA (video_frame), xpos, ypos);
- break;
- case GST_VIDEO_FORMAT_ARGB:
- gst_text_overlay_blit_ARGB (overlay,
- GST_BUFFER_DATA (video_frame), xpos, ypos);
- break;
- case GST_VIDEO_FORMAT_ABGR:
- gst_text_overlay_blit_ABGR (overlay,
- GST_BUFFER_DATA (video_frame), xpos, ypos);
- break;
- case GST_VIDEO_FORMAT_RGBA:
- gst_text_overlay_blit_RGBA (overlay,
- GST_BUFFER_DATA (video_frame), xpos, ypos);
- break;
- case GST_VIDEO_FORMAT_BGRA:
- gst_text_overlay_blit_BGRA (overlay,
- GST_BUFFER_DATA (video_frame), xpos, ypos);
- break;
- default:
- g_assert_not_reached ();
- }
- }
- return gst_pad_push (overlay->srcpad, video_frame);
-}
-
-static GstPadLinkReturn
-gst_text_overlay_text_pad_link (GstPad * pad, GstPad * peer)
-{
- GstTextOverlay *overlay;
-
- overlay = GST_TEXT_OVERLAY (gst_pad_get_parent (pad));
-
- GST_DEBUG_OBJECT (overlay, "Text pad linked");
-
- overlay->text_linked = TRUE;
-
- gst_object_unref (overlay);
-
- return GST_PAD_LINK_OK;
-}
-
-static void
-gst_text_overlay_text_pad_unlink (GstPad * pad)
-{
- GstTextOverlay *overlay;
-
- /* don't use gst_pad_get_parent() here, will deadlock */
- overlay = GST_TEXT_OVERLAY (GST_PAD_PARENT (pad));
-
- GST_DEBUG_OBJECT (overlay, "Text pad unlinked");
-
- overlay->text_linked = FALSE;
-
- gst_segment_init (&overlay->text_segment, GST_FORMAT_UNDEFINED);
-}
-
-static gboolean
-gst_text_overlay_text_event (GstPad * pad, GstEvent * event)
-{
- gboolean ret = FALSE;
- GstTextOverlay *overlay = NULL;
-
- overlay = GST_TEXT_OVERLAY (gst_pad_get_parent (pad));
-
- GST_LOG_OBJECT (pad, "received event %s", GST_EVENT_TYPE_NAME (event));
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_NEWSEGMENT:{
- GstFormat fmt;
- gboolean update;
- gdouble rate, applied_rate;
- gint64 cur, stop, time;
-
- overlay->text_eos = FALSE;
-
- gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
- &fmt, &cur, &stop, &time);
-
- if (fmt == GST_FORMAT_TIME) {
- GST_OBJECT_LOCK (overlay);
- gst_segment_set_newsegment_full (&overlay->text_segment, update, rate,
- applied_rate, GST_FORMAT_TIME, cur, stop, time);
- GST_DEBUG_OBJECT (overlay, "TEXT SEGMENT now: %" GST_SEGMENT_FORMAT,
- &overlay->text_segment);
- GST_OBJECT_UNLOCK (overlay);
- } else {
- GST_ELEMENT_WARNING (overlay, STREAM, MUX, (NULL),
- ("received non-TIME newsegment event on text input"));
- }
-
- gst_event_unref (event);
- ret = TRUE;
-
- /* wake up the video chain, it might be waiting for a text buffer or
- * a text segment update */
- GST_OBJECT_LOCK (overlay);
- GST_TEXT_OVERLAY_BROADCAST (overlay);
- GST_OBJECT_UNLOCK (overlay);
- break;
- }
- case GST_EVENT_FLUSH_STOP:
- GST_OBJECT_LOCK (overlay);
- GST_INFO_OBJECT (overlay, "text flush stop");
- overlay->text_flushing = FALSE;
- overlay->text_eos = FALSE;
- gst_text_overlay_pop_text (overlay);
- gst_segment_init (&overlay->text_segment, GST_FORMAT_TIME);
- GST_OBJECT_UNLOCK (overlay);
- gst_event_unref (event);
- ret = TRUE;
- break;
- case GST_EVENT_FLUSH_START:
- GST_OBJECT_LOCK (overlay);
- GST_INFO_OBJECT (overlay, "text flush start");
- overlay->text_flushing = TRUE;
- GST_TEXT_OVERLAY_BROADCAST (overlay);
- GST_OBJECT_UNLOCK (overlay);
- gst_event_unref (event);
- ret = TRUE;
- break;
- case GST_EVENT_EOS:
- GST_OBJECT_LOCK (overlay);
- overlay->text_eos = TRUE;
- GST_INFO_OBJECT (overlay, "text EOS");
- /* wake up the video chain, it might be waiting for a text buffer or
- * a text segment update */
- GST_TEXT_OVERLAY_BROADCAST (overlay);
- GST_OBJECT_UNLOCK (overlay);
- gst_event_unref (event);
- ret = TRUE;
- break;
- default:
- ret = gst_pad_event_default (pad, event);
- break;
- }
-
- gst_object_unref (overlay);
-
- return ret;
-}
-
-static gboolean
-gst_text_overlay_video_event (GstPad * pad, GstEvent * event)
-{
- gboolean ret = FALSE;
- GstTextOverlay *overlay = NULL;
-
- overlay = GST_TEXT_OVERLAY (gst_pad_get_parent (pad));
-
- GST_DEBUG_OBJECT (pad, "received event %s", GST_EVENT_TYPE_NAME (event));
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_NEWSEGMENT:
- {
- GstFormat format;
- gdouble rate;
- gint64 start, stop, time;
- gboolean update;
-
- GST_DEBUG_OBJECT (overlay, "received new segment");
-
- gst_event_parse_new_segment (event, &update, &rate, &format, &start,
- &stop, &time);
-
- if (format == GST_FORMAT_TIME) {
- GST_DEBUG_OBJECT (overlay, "VIDEO SEGMENT now: %" GST_SEGMENT_FORMAT,
- &overlay->segment);
-
- gst_segment_set_newsegment (&overlay->segment, update, rate, format,
- start, stop, time);
- } else {
- GST_ELEMENT_WARNING (overlay, STREAM, MUX, (NULL),
- ("received non-TIME newsegment event on video input"));
- }
-
- ret = gst_pad_event_default (pad, event);
- break;
- }
- case GST_EVENT_EOS:
- GST_OBJECT_LOCK (overlay);
- GST_INFO_OBJECT (overlay, "video EOS");
- overlay->video_eos = TRUE;
- GST_OBJECT_UNLOCK (overlay);
- ret = gst_pad_event_default (pad, event);
- break;
- case GST_EVENT_FLUSH_START:
- GST_OBJECT_LOCK (overlay);
- GST_INFO_OBJECT (overlay, "video flush start");
- overlay->video_flushing = TRUE;
- GST_TEXT_OVERLAY_BROADCAST (overlay);
- GST_OBJECT_UNLOCK (overlay);
- ret = gst_pad_event_default (pad, event);
- break;
- case GST_EVENT_FLUSH_STOP:
- GST_OBJECT_LOCK (overlay);
- GST_INFO_OBJECT (overlay, "video flush stop");
- overlay->video_flushing = FALSE;
- overlay->video_eos = FALSE;
- gst_segment_init (&overlay->segment, GST_FORMAT_TIME);
- GST_OBJECT_UNLOCK (overlay);
- ret = gst_pad_event_default (pad, event);
- break;
- default:
- ret = gst_pad_event_default (pad, event);
- break;
- }
-
- gst_object_unref (overlay);
-
- return ret;
-}
-
-static GstFlowReturn
-gst_text_overlay_video_bufferalloc (GstPad * pad, guint64 offset, guint size,
- GstCaps * caps, GstBuffer ** buffer)
-{
- GstTextOverlay *overlay = GST_TEXT_OVERLAY (gst_pad_get_parent (pad));
- GstFlowReturn ret = GST_FLOW_WRONG_STATE;
- GstPad *allocpad;
-
- GST_OBJECT_LOCK (overlay);
- allocpad = overlay->srcpad ? gst_object_ref (overlay->srcpad) : NULL;
- GST_OBJECT_UNLOCK (overlay);
-
- if (allocpad) {
- ret = gst_pad_alloc_buffer (allocpad, offset, size, caps, buffer);
- gst_object_unref (allocpad);
- }
-
- gst_object_unref (overlay);
- return ret;
-}
-
-/* Called with lock held */
-static void
-gst_text_overlay_pop_text (GstTextOverlay * overlay)
-{
- g_return_if_fail (GST_IS_TEXT_OVERLAY (overlay));
-
- if (overlay->text_buffer) {
- GST_DEBUG_OBJECT (overlay, "releasing text buffer %p",
- overlay->text_buffer);
- gst_buffer_unref (overlay->text_buffer);
- overlay->text_buffer = NULL;
- }
-
- /* Let the text task know we used that buffer */
- GST_TEXT_OVERLAY_BROADCAST (overlay);
-}
-
-/* We receive text buffers here. If they are out of segment we just ignore them.
- If the buffer is in our segment we keep it internally except if another one
- is already waiting here, in that case we wait that it gets kicked out */
-static GstFlowReturn
-gst_text_overlay_text_chain (GstPad * pad, GstBuffer * buffer)
-{
- GstFlowReturn ret = GST_FLOW_OK;
- GstTextOverlay *overlay = NULL;
- gboolean in_seg = FALSE;
- gint64 clip_start = 0, clip_stop = 0;
-
- overlay = GST_TEXT_OVERLAY (GST_PAD_PARENT (pad));
-
- GST_OBJECT_LOCK (overlay);
-
- if (overlay->text_flushing) {
- GST_OBJECT_UNLOCK (overlay);
- ret = GST_FLOW_WRONG_STATE;
- GST_LOG_OBJECT (overlay, "text flushing");
- goto beach;
- }
-
- if (overlay->text_eos) {
- GST_OBJECT_UNLOCK (overlay);
- ret = GST_FLOW_UNEXPECTED;
- GST_LOG_OBJECT (overlay, "text EOS");
- goto beach;
- }
-
- GST_LOG_OBJECT (overlay, "%" GST_SEGMENT_FORMAT " BUFFER: ts=%"
- GST_TIME_FORMAT ", end=%" GST_TIME_FORMAT, &overlay->segment,
- GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
- GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer) +
- GST_BUFFER_DURATION (buffer)));
-
- if (G_LIKELY (GST_BUFFER_TIMESTAMP_IS_VALID (buffer))) {
- GstClockTime stop;
-
- if (G_LIKELY (GST_BUFFER_DURATION_IS_VALID (buffer)))
- stop = GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer);
- else
- stop = GST_CLOCK_TIME_NONE;
-
- in_seg = gst_segment_clip (&overlay->text_segment, GST_FORMAT_TIME,
- GST_BUFFER_TIMESTAMP (buffer), stop, &clip_start, &clip_stop);
- } else {
- in_seg = TRUE;
- }
-
- if (in_seg) {
- if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer))
- GST_BUFFER_TIMESTAMP (buffer) = clip_start;
- else if (GST_BUFFER_DURATION_IS_VALID (buffer))
- GST_BUFFER_DURATION (buffer) = clip_stop - clip_start;
-
- /* Wait for the previous buffer to go away */
- while (overlay->text_buffer != NULL) {
- GST_DEBUG ("Pad %s:%s has a buffer queued, waiting",
- GST_DEBUG_PAD_NAME (pad));
- GST_TEXT_OVERLAY_WAIT (overlay);
- GST_DEBUG ("Pad %s:%s resuming", GST_DEBUG_PAD_NAME (pad));
- if (overlay->text_flushing) {
- GST_OBJECT_UNLOCK (overlay);
- ret = GST_FLOW_WRONG_STATE;
- goto beach;
- }
- }
-
- if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer))
- gst_segment_set_last_stop (&overlay->text_segment, GST_FORMAT_TIME,
- clip_start);
-
- overlay->text_buffer = buffer;
- /* That's a new text buffer we need to render */
- overlay->need_render = TRUE;
-
- /* in case the video chain is waiting for a text buffer, wake it up */
- GST_TEXT_OVERLAY_BROADCAST (overlay);
- }
-
- GST_OBJECT_UNLOCK (overlay);
-
-beach:
-
- return ret;
-}
-
-static GstFlowReturn
-gst_text_overlay_video_chain (GstPad * pad, GstBuffer * buffer)
-{
- GstTextOverlayClass *klass;
- GstTextOverlay *overlay;
- GstFlowReturn ret = GST_FLOW_OK;
- gboolean in_seg = FALSE;
- gint64 start, stop, clip_start = 0, clip_stop = 0;
- gchar *text = NULL;
-
- overlay = GST_TEXT_OVERLAY (GST_PAD_PARENT (pad));
- klass = GST_TEXT_OVERLAY_GET_CLASS (overlay);
-
- if (!GST_BUFFER_TIMESTAMP_IS_VALID (buffer))
- goto missing_timestamp;
-
- /* ignore buffers that are outside of the current segment */
- start = GST_BUFFER_TIMESTAMP (buffer);
-
- if (!GST_BUFFER_DURATION_IS_VALID (buffer)) {
- stop = GST_CLOCK_TIME_NONE;
- } else {
- stop = start + GST_BUFFER_DURATION (buffer);
- }
-
- GST_LOG_OBJECT (overlay, "%" GST_SEGMENT_FORMAT " BUFFER: ts=%"
- GST_TIME_FORMAT ", end=%" GST_TIME_FORMAT, &overlay->segment,
- GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
-
- /* segment_clip() will adjust start unconditionally to segment_start if
- * no stop time is provided, so handle this ourselves */
- if (stop == GST_CLOCK_TIME_NONE && start < overlay->segment.start)
- goto out_of_segment;
-
- in_seg = gst_segment_clip (&overlay->segment, GST_FORMAT_TIME, start, stop,
- &clip_start, &clip_stop);
-
- if (!in_seg)
- goto out_of_segment;
-
- /* if the buffer is only partially in the segment, fix up stamps */
- if (clip_start != start || (stop != -1 && clip_stop != stop)) {
- GST_DEBUG_OBJECT (overlay, "clipping buffer timestamp/duration to segment");
- buffer = gst_buffer_make_metadata_writable (buffer);
- GST_BUFFER_TIMESTAMP (buffer) = clip_start;
- if (stop != -1)
- GST_BUFFER_DURATION (buffer) = clip_stop - clip_start;
- }
-
- /* now, after we've done the clipping, fix up end time if there's no
- * duration (we only use those estimated values internally though, we
- * don't want to set bogus values on the buffer itself) */
- if (stop == -1) {
- GstStructure *s;
- gint fps_num, fps_denom;
-
- s = gst_caps_get_structure (GST_PAD_CAPS (pad), 0);
- if (gst_structure_get_fraction (s, "framerate", &fps_num, &fps_denom) &&
- fps_num && fps_denom) {
- GST_DEBUG_OBJECT (overlay, "estimating duration based on framerate");
- stop = start + gst_util_uint64_scale_int (GST_SECOND, fps_denom, fps_num);
- } else {
- GST_WARNING_OBJECT (overlay, "no duration, assuming minimal duration");
- stop = start + 1; /* we need to assume some interval */
- }
- }
-
- gst_object_sync_values (G_OBJECT (overlay), GST_BUFFER_TIMESTAMP (buffer));
-
-wait_for_text_buf:
-
- GST_OBJECT_LOCK (overlay);
-
- if (overlay->video_flushing)
- goto flushing;
-
- if (overlay->video_eos)
- goto have_eos;
-
- if (overlay->silent) {
- GST_OBJECT_UNLOCK (overlay);
- ret = gst_pad_push (overlay->srcpad, buffer);
-
- /* Update last_stop */
- gst_segment_set_last_stop (&overlay->segment, GST_FORMAT_TIME, clip_start);
-
- return ret;
- }
-
- /* Text pad not linked, rendering internal text */
- if (!overlay->text_linked) {
- if (klass->get_text) {
- text = klass->get_text (overlay, buffer);
- } else {
- text = g_strdup (overlay->default_text);
- }
-
- GST_LOG_OBJECT (overlay, "Text pad not linked, rendering default "
- "text: '%s'", GST_STR_NULL (text));
-
- GST_OBJECT_UNLOCK (overlay);
-
- if (text != NULL && *text != '\0') {
- /* Render and push */
- gst_text_overlay_render_text (overlay, text, -1);
- ret = gst_text_overlay_push_frame (overlay, buffer);
- } else {
- /* Invalid or empty string */
- ret = gst_pad_push (overlay->srcpad, buffer);
- }
- } else {
- /* Text pad linked, check if we have a text buffer queued */
- if (overlay->text_buffer) {
- gboolean pop_text = FALSE, valid_text_time = TRUE;
- GstClockTime text_start = GST_CLOCK_TIME_NONE;
- GstClockTime text_end = GST_CLOCK_TIME_NONE;
- GstClockTime text_running_time = GST_CLOCK_TIME_NONE;
- GstClockTime text_running_time_end = GST_CLOCK_TIME_NONE;
- GstClockTime vid_running_time, vid_running_time_end;
-
- /* if the text buffer isn't stamped right, pop it off the
- * queue and display it for the current video frame only */
- if (!GST_BUFFER_TIMESTAMP_IS_VALID (overlay->text_buffer) ||
- !GST_BUFFER_DURATION_IS_VALID (overlay->text_buffer)) {
- GST_WARNING_OBJECT (overlay,
- "Got text buffer with invalid timestamp or duration");
- pop_text = TRUE;
- valid_text_time = FALSE;
- } else {
- text_start = GST_BUFFER_TIMESTAMP (overlay->text_buffer);
- text_end = text_start + GST_BUFFER_DURATION (overlay->text_buffer);
- }
-
- vid_running_time =
- gst_segment_to_running_time (&overlay->segment, GST_FORMAT_TIME,
- start);
- vid_running_time_end =
- gst_segment_to_running_time (&overlay->segment, GST_FORMAT_TIME,
- stop);
-
- /* If timestamp and duration are valid */
- if (valid_text_time) {
- text_running_time =
- gst_segment_to_running_time (&overlay->segment, GST_FORMAT_TIME,
- text_start);
- text_running_time_end =
- gst_segment_to_running_time (&overlay->segment, GST_FORMAT_TIME,
- text_end);
- }
-
- GST_LOG_OBJECT (overlay, "T: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
- GST_TIME_ARGS (text_running_time),
- GST_TIME_ARGS (text_running_time_end));
- GST_LOG_OBJECT (overlay, "V: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
- GST_TIME_ARGS (vid_running_time),
- GST_TIME_ARGS (vid_running_time_end));
-
- /* Text too old or in the future */
- if (valid_text_time && text_running_time_end <= vid_running_time) {
- /* text buffer too old, get rid of it and do nothing */
- GST_LOG_OBJECT (overlay, "text buffer too old, popping");
- pop_text = FALSE;
- gst_text_overlay_pop_text (overlay);
- GST_OBJECT_UNLOCK (overlay);
- goto wait_for_text_buf;
- } else if (valid_text_time && vid_running_time_end <= text_running_time) {
- GST_LOG_OBJECT (overlay, "text in future, pushing video buf");
- GST_OBJECT_UNLOCK (overlay);
- /* Push the video frame */
- ret = gst_pad_push (overlay->srcpad, buffer);
- } else {
- gchar *in_text;
- gsize in_size;
-
- in_text = (gchar *) GST_BUFFER_DATA (overlay->text_buffer);
- in_size = GST_BUFFER_SIZE (overlay->text_buffer);
-
- /* g_markup_escape_text() absolutely requires valid UTF8 input, it
- * might crash otherwise. We don't fall back on GST_SUBTITLE_ENCODING
- * here on purpose, this is something that needs fixing upstream */
- if (!g_utf8_validate (in_text, in_size, NULL)) {
- const gchar *end = NULL;
-
- GST_WARNING_OBJECT (overlay, "received invalid UTF-8");
- in_text = g_strndup (in_text, in_size);
- while (!g_utf8_validate (in_text, in_size, &end) && end)
- *((gchar *) end) = '*';
- }
-
- /* Get the string */
- if (overlay->have_pango_markup) {
- text = g_strndup (in_text, in_size);
- } else {
- text = g_markup_escape_text (in_text, in_size);
- }
-
- if (text != NULL && *text != '\0') {
- gint text_len = strlen (text);
-
- while (text_len > 0 && (text[text_len - 1] == '\n' ||
- text[text_len - 1] == '\r')) {
- --text_len;
- }
- GST_DEBUG_OBJECT (overlay, "Rendering text '%*s'", text_len, text);
- gst_text_overlay_render_text (overlay, text, text_len);
- } else {
- GST_DEBUG_OBJECT (overlay, "No text to render (empty buffer)");
- gst_text_overlay_render_text (overlay, " ", 1);
- }
-
- if (in_text != (gchar *) GST_BUFFER_DATA (overlay->text_buffer))
- g_free (in_text);
-
- GST_OBJECT_UNLOCK (overlay);
- ret = gst_text_overlay_push_frame (overlay, buffer);
-
- if (valid_text_time && text_running_time_end <= vid_running_time_end) {
- GST_LOG_OBJECT (overlay, "text buffer not needed any longer");
- pop_text = TRUE;
- }
- }
- if (pop_text) {
- GST_OBJECT_LOCK (overlay);
- gst_text_overlay_pop_text (overlay);
- GST_OBJECT_UNLOCK (overlay);
- }
- } else {
- gboolean wait_for_text_buf = TRUE;
-
- if (overlay->text_eos)
- wait_for_text_buf = FALSE;
-
- if (!overlay->wait_text)
- wait_for_text_buf = FALSE;
-
- /* Text pad linked, but no text buffer available - what now? */
- if (overlay->text_segment.format == GST_FORMAT_TIME) {
- GstClockTime text_start_running_time, text_last_stop_running_time;
- GstClockTime vid_running_time;
-
- vid_running_time =
- gst_segment_to_running_time (&overlay->segment, GST_FORMAT_TIME,
- GST_BUFFER_TIMESTAMP (buffer));
- text_start_running_time =
- gst_segment_to_running_time (&overlay->text_segment,
- GST_FORMAT_TIME, overlay->text_segment.start);
- text_last_stop_running_time =
- gst_segment_to_running_time (&overlay->text_segment,
- GST_FORMAT_TIME, overlay->text_segment.last_stop);
-
- if ((GST_CLOCK_TIME_IS_VALID (text_start_running_time) &&
- vid_running_time < text_start_running_time) ||
- (GST_CLOCK_TIME_IS_VALID (text_last_stop_running_time) &&
- vid_running_time < text_last_stop_running_time)) {
- wait_for_text_buf = FALSE;
- }
- }
-
- if (wait_for_text_buf) {
- GST_DEBUG_OBJECT (overlay, "no text buffer, need to wait for one");
- GST_TEXT_OVERLAY_WAIT (overlay);
- GST_DEBUG_OBJECT (overlay, "resuming");
- GST_OBJECT_UNLOCK (overlay);
- goto wait_for_text_buf;
- } else {
- GST_OBJECT_UNLOCK (overlay);
- GST_LOG_OBJECT (overlay, "no need to wait for a text buffer");
- ret = gst_pad_push (overlay->srcpad, buffer);
- }
- }
- }
-
- g_free (text);
-
- /* Update last_stop */
- gst_segment_set_last_stop (&overlay->segment, GST_FORMAT_TIME, clip_start);
-
- return ret;
-
-missing_timestamp:
- {
- GST_WARNING_OBJECT (overlay, "buffer without timestamp, discarding");
- gst_buffer_unref (buffer);
- return GST_FLOW_OK;
- }
-
-flushing:
- {
- GST_OBJECT_UNLOCK (overlay);
- GST_DEBUG_OBJECT (overlay, "flushing, discarding buffer");
- gst_buffer_unref (buffer);
- return GST_FLOW_WRONG_STATE;
- }
-have_eos:
- {
- GST_OBJECT_UNLOCK (overlay);
- GST_DEBUG_OBJECT (overlay, "eos, discarding buffer");
- gst_buffer_unref (buffer);
- return GST_FLOW_UNEXPECTED;
- }
-out_of_segment:
- {
- GST_DEBUG_OBJECT (overlay, "buffer out of segment, discarding");
- gst_buffer_unref (buffer);
- return GST_FLOW_OK;
- }
-}
-
-static GstStateChangeReturn
-gst_text_overlay_change_state (GstElement * element, GstStateChange transition)
-{
- GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
- GstTextOverlay *overlay = GST_TEXT_OVERLAY (element);
-
- switch (transition) {
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- GST_OBJECT_LOCK (overlay);
- overlay->text_flushing = TRUE;
- overlay->video_flushing = TRUE;
- /* pop_text will broadcast on the GCond and thus also make the video
- * chain exit if it's waiting for a text buffer */
- gst_text_overlay_pop_text (overlay);
- GST_OBJECT_UNLOCK (overlay);
- break;
- default:
- break;
- }
-
- ret = parent_class->change_state (element, transition);
- if (ret == GST_STATE_CHANGE_FAILURE)
- return ret;
-
- switch (transition) {
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- GST_OBJECT_LOCK (overlay);
- overlay->text_flushing = FALSE;
- overlay->video_flushing = FALSE;
- overlay->video_eos = FALSE;
- overlay->text_eos = FALSE;
- gst_segment_init (&overlay->segment, GST_FORMAT_TIME);
- gst_segment_init (&overlay->text_segment, GST_FORMAT_TIME);
- GST_OBJECT_UNLOCK (overlay);
- break;
- default:
- break;
- }
-
- return ret;
-}
-
-static gboolean
-plugin_init (GstPlugin * plugin)
-{
- gst_controller_init (NULL, NULL);
-
- if (!gst_element_register (plugin, "textoverlay", GST_RANK_NONE,
- GST_TYPE_TEXT_OVERLAY) ||
- !gst_element_register (plugin, "timeoverlay", GST_RANK_NONE,
- GST_TYPE_TIME_OVERLAY) ||
- !gst_element_register (plugin, "clockoverlay", GST_RANK_NONE,
- GST_TYPE_CLOCK_OVERLAY) ||
- !gst_element_register (plugin, "textrender", GST_RANK_NONE,
- GST_TYPE_TEXT_RENDER)) {
- return FALSE;
- }
-
- /*texttestsrc_plugin_init(module, plugin); */
-
- GST_DEBUG_CATEGORY_INIT (pango_debug, "pango", 0, "Pango elements");
-
- return TRUE;
-}
-
-GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
- "pango", "Pango-based text rendering and overlay", plugin_init,
- VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
+/* GStreamer
+ * Copyright (C) 2011 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * 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_TEXT_OVERLAY_H__
#define __GST_TEXT_OVERLAY_H__
-#include <gst/gst.h>
-#include <gst/video/video.h>
-#include <gst/controller/gstcontroller.h>
-#include <pango/pangocairo.h>
+#include "gstbasetextoverlay.h"
G_BEGIN_DECLS
-#define GST_TYPE_TEXT_OVERLAY (gst_text_overlay_get_type())
-#define GST_TEXT_OVERLAY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
- GST_TYPE_TEXT_OVERLAY, GstTextOverlay))
-#define GST_TEXT_OVERLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),\
- GST_TYPE_TEXT_OVERLAY,GstTextOverlayClass))
-#define GST_TEXT_OVERLAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
- GST_TYPE_TEXT_OVERLAY, GstTextOverlayClass))
-#define GST_IS_TEXT_OVERLAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),\
- GST_TYPE_TEXT_OVERLAY))
-#define GST_IS_TEXT_OVERLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),\
- GST_TYPE_TEXT_OVERLAY))
-
-typedef struct _GstTextOverlay GstTextOverlay;
+#define GST_TYPE_TEXT_OVERLAY \
+ (gst_text_overlay_get_type())
+#define GST_TEXT_OVERLAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_TEXT_OVERLAY,GstTextOverlay))
+#define GST_TEXT_OVERLAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_TEXT_OVERLAY,GstTextOverlayClass))
+#define GST_IS_TEXT_OVERLAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_TEXT_OVERLAY))
+#define GST_IS_TEXT_OVERLAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_TEXT_OVERLAY))
+
+typedef struct _GstTextOverlay GstTextOverlay;
typedef struct _GstTextOverlayClass GstTextOverlayClass;
/**
- * GstTextOverlayVAlign:
- * @GST_TEXT_OVERLAY_VALIGN_BASELINE: draw text on the baseline
- * @GST_TEXT_OVERLAY_VALIGN_BOTTOM: draw text on the bottom
- * @GST_TEXT_OVERLAY_VALIGN_TOP: draw text on top
- * @GST_TEXT_OVERLAY_VALIGN_POS: draw text according to the #GstTextOverlay:ypos property
- * @GST_TEXT_OVERLAY_VALIGN_CENTER: draw text vertically centered
- *
- * Vertical alignment of the text.
- */
-typedef enum {
- GST_TEXT_OVERLAY_VALIGN_BASELINE,
- GST_TEXT_OVERLAY_VALIGN_BOTTOM,
- GST_TEXT_OVERLAY_VALIGN_TOP,
- GST_TEXT_OVERLAY_VALIGN_POS,
- GST_TEXT_OVERLAY_VALIGN_CENTER
-} GstTextOverlayVAlign;
-
-/**
- * GstTextOverlayHAlign:
- * @GST_TEXT_OVERLAY_HALIGN_LEFT: align text left
- * @GST_TEXT_OVERLAY_HALIGN_CENTER: align text center
- * @GST_TEXT_OVERLAY_HALIGN_RIGHT: align text right
- * @GST_TEXT_OVERLAY_HALIGN_POS: position text according to the #GstTextOverlay:xpos property
- *
- * Horizontal alignment of the text.
- */
-/* FIXME 0.11: remove GST_TEXT_OVERLAY_HALIGN_UNUSED */
-typedef enum {
- GST_TEXT_OVERLAY_HALIGN_LEFT,
- GST_TEXT_OVERLAY_HALIGN_CENTER,
- GST_TEXT_OVERLAY_HALIGN_RIGHT,
- GST_TEXT_OVERLAY_HALIGN_UNUSED,
- GST_TEXT_OVERLAY_HALIGN_POS
-} GstTextOverlayHAlign;
-
-/**
- * GstTextOverlayWrapMode:
- * @GST_TEXT_OVERLAY_WRAP_MODE_NONE: no wrapping
- * @GST_TEXT_OVERLAY_WRAP_MODE_WORD: do word wrapping
- * @GST_TEXT_OVERLAY_WRAP_MODE_CHAR: do char wrapping
- * @GST_TEXT_OVERLAY_WRAP_MODE_WORD_CHAR: do word and char wrapping
- *
- * Whether to wrap the text and if so how.
- */
-typedef enum {
- GST_TEXT_OVERLAY_WRAP_MODE_NONE = -1,
- GST_TEXT_OVERLAY_WRAP_MODE_WORD = PANGO_WRAP_WORD,
- GST_TEXT_OVERLAY_WRAP_MODE_CHAR = PANGO_WRAP_CHAR,
- GST_TEXT_OVERLAY_WRAP_MODE_WORD_CHAR = PANGO_WRAP_WORD_CHAR
-} GstTextOverlayWrapMode;
-
-/**
- * GstTextOverlayLineAlign:
- * @GST_TEXT_OVERLAY_LINE_ALIGN_LEFT: lines are left-aligned
- * @GST_TEXT_OVERLAY_LINE_ALIGN_CENTER: lines are center-aligned
- * @GST_TEXT_OVERLAY_LINE_ALIGN_RIGHT: lines are right-aligned
- *
- * Alignment of text lines relative to each other
- */
-typedef enum {
- GST_TEXT_OVERLAY_LINE_ALIGN_LEFT = PANGO_ALIGN_LEFT,
- GST_TEXT_OVERLAY_LINE_ALIGN_CENTER = PANGO_ALIGN_CENTER,
- GST_TEXT_OVERLAY_LINE_ALIGN_RIGHT = PANGO_ALIGN_RIGHT
-} GstTextOverlayLineAlign;
-
-/**
* GstTextOverlay:
*
- * Opaque textoverlay object structure
+ * Opaque textoverlay data structure.
*/
struct _GstTextOverlay {
- GstElement element;
-
- GstPad *video_sinkpad;
- GstPad *text_sinkpad;
- GstPad *srcpad;
-
- GstSegment segment;
- GstSegment text_segment;
- GstBuffer *text_buffer;
- gboolean text_linked;
- gboolean video_flushing;
- gboolean video_eos;
- gboolean text_flushing;
- gboolean text_eos;
-
- GCond *cond; /* to signal removal of a queued text
- * buffer, arrival of a text buffer,
- * a text segment update, or a change
- * in status (e.g. shutdown, flushing) */
-
- gint width;
- gint height;
- gint fps_n;
- gint fps_d;
- GstVideoFormat format;
-
- GstTextOverlayVAlign valign;
- GstTextOverlayHAlign halign;
- GstTextOverlayWrapMode wrap_mode;
- GstTextOverlayLineAlign line_align;
-
- gint xpad;
- gint ypad;
- gint deltax;
- gint deltay;
- gdouble xpos;
- gdouble ypos;
- gchar *default_text;
- gboolean want_shading;
- gboolean silent;
- gboolean wait_text;
- guint color, outline_color;
-
- PangoLayout *layout;
- gdouble shadow_offset;
- gboolean want_shadow;
- gdouble outline_offset;
- guchar *text_image;
- gint image_width;
- gint image_height;
- gint baseline_y;
-
- gboolean auto_adjust_size;
- gboolean need_render;
-
- gint shading_value; /* for timeoverlay subclass */
-
- gboolean have_pango_markup;
- gboolean use_vertical_render;
+ GstBaseTextOverlay parent;
};
struct _GstTextOverlayClass {
- GstElementClass parent_class;
-
- PangoContext *pango_context;
- GMutex *pango_lock;
-
- gchar * (*get_text) (GstTextOverlay *overlay, GstBuffer *video_frame);
+ GstBaseTextOverlayClass parent_class;
};
-GType gst_text_overlay_get_type(void) G_GNUC_CONST;
+GType gst_text_overlay_get_type (void);
G_END_DECLS
-#endif /* __GST_TEXT_OVERLAY_H */
+#endif /* __GST_TEXT_OVERLAY_H__ */
+
static void gst_text_render_adjust_values_with_fontdesc (GstTextRender *
render, PangoFontDescription * desc);
-GST_BOILERPLATE (GstTextRender, gst_text_render, GstElement, GST_TYPE_ELEMENT);
+#define gst_text_render_parent_class parent_class
+G_DEFINE_TYPE (GstTextRender, gst_text_render, GST_TYPE_ELEMENT);
static void gst_text_render_finalize (GObject * object);
static void gst_text_render_set_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec);
static void
-gst_text_render_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 (&src_template_factory));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&sink_template_factory));
-
- gst_element_class_set_details_simple (element_class, "Text renderer",
- "Filter/Editor/Video",
- "Renders a text string to an image bitmap",
- "David Schleef <ds@schleef.org>, "
- "GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>");
-}
-
-static void
gst_text_render_class_init (GstTextRenderClass * klass)
{
GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
PangoFontMap *fontmap;
gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
parent_class = g_type_class_peek_parent (klass);
gobject_class->set_property = gst_text_render_set_property;
gobject_class->get_property = gst_text_render_get_property;
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&src_template_factory));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&sink_template_factory));
+
+ gst_element_class_set_details_simple (gstelement_class, "Text renderer",
+ "Filter/Editor/Video",
+ "Renders a text string to an image bitmap",
+ "David Schleef <ds@schleef.org>, "
+ "GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>");
+
fontmap = pango_cairo_font_map_get_default ();
klass->pango_context =
pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (fontmap));
GstTextRender *render;
GstFlowReturn ret;
GstBuffer *outbuf;
- GstCaps *caps = NULL, *padcaps, *peercaps;
- guint8 *data = GST_BUFFER_DATA (inbuf);
- guint size = GST_BUFFER_SIZE (inbuf);
+ GstCaps *caps = NULL, *padcaps;
+ guint8 *data;
+ gsize size;
gint n;
gint xpos, ypos;
render = GST_TEXT_RENDER (gst_pad_get_parent (pad));
+ data = gst_buffer_map (inbuf, &size, NULL, GST_MAP_READ);
+
/* somehow pango barfs over "\0" buffers... */
while (size > 0 &&
(data[size - 1] == '\r' ||
GST_DEBUG ("rendering '%*s'", size, data);
pango_layout_set_markup (render->layout, (gchar *) data, size);
gst_text_render_render_pangocairo (render);
+ gst_buffer_unmap (inbuf, data, size);
gst_text_render_check_argb (render);
- peercaps = gst_pad_peer_get_caps (render->srcpad);
- padcaps = gst_pad_get_caps (render->srcpad);
- caps = gst_caps_intersect (padcaps, peercaps);
+ padcaps = gst_pad_get_caps (render->srcpad, NULL);
+ caps = gst_pad_peer_get_caps (render->srcpad, padcaps);
gst_caps_unref (padcaps);
- gst_caps_unref (peercaps);
if (!caps || gst_caps_is_empty (caps)) {
GST_ELEMENT_ERROR (render, CORE, NEGOTIATION, (NULL), (NULL));
}
GST_DEBUG ("Allocating buffer WxH = %dx%d", render->width, render->height);
- ret =
- gst_pad_alloc_buffer_and_set_caps (render->srcpad, GST_BUFFER_OFFSET_NONE,
- render->width * render->height * 4, caps, &outbuf);
-
- if (ret != GST_FLOW_OK)
- goto done;
+ outbuf = gst_buffer_new_and_alloc (render->width * render->height * 4);
- gst_buffer_copy_metadata (outbuf, inbuf, GST_BUFFER_COPY_TIMESTAMPS);
- data = GST_BUFFER_DATA (outbuf);
+ gst_buffer_copy_into (outbuf, inbuf, GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
+ data = gst_buffer_map (outbuf, &size, NULL, GST_MAP_WRITE);
if (render->use_ARGB) {
memset (data, 0, render->width * render->height * 4);
render->width * 4);
}
}
+ gst_buffer_unmap (outbuf, data, size);
ret = gst_pad_push (render->srcpad, outbuf);
}
static void
-gst_text_render_init (GstTextRender * render, GstTextRenderClass * klass)
+gst_text_render_init (GstTextRender * render)
{
GstPadTemplate *template;
/**
* SECTION:element-timeoverlay
- * @see_also: #GstTextOverlay, #GstClockOverlay
+ * @see_also: #GstBaseTextOverlay, #GstClockOverlay
*
* This element overlays the buffer time stamps of a video stream on
* top of itself. You can position the text and configure the font details
- * using the properties of the #GstTextOverlay class. By default, the
+ * using the properties of the #GstBaseTextOverlay class. By default, the
* time stamp is displayed in the top left corner of the picture, with some
* padding to the left and to the top.
*
#include <gsttimeoverlay.h>
-GST_BOILERPLATE (GstTimeOverlay, gst_time_overlay, GstTextOverlay,
- GST_TYPE_TEXT_OVERLAY);
-
-static void
-gst_time_overlay_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_set_details_simple (element_class, "Time overlay",
- "Filter/Editor/Video",
- "Overlays buffer time stamps on a video stream",
- "Tim-Philipp Müller <tim@centricular.net>");
-}
+#define gst_time_overlay_parent_class parent_class
+G_DEFINE_TYPE (GstTimeOverlay, gst_time_overlay, GST_TYPE_BASE_TEXT_OVERLAY);
static gchar *
gst_time_overlay_render_time (GstTimeOverlay * overlay, GstClockTime time)
/* Called with lock held */
static gchar *
-gst_time_overlay_get_text (GstTextOverlay * overlay, GstBuffer * video_frame)
+gst_time_overlay_get_text (GstBaseTextOverlay * overlay,
+ GstBuffer * video_frame)
{
GstClockTime time = GST_BUFFER_TIMESTAMP (video_frame);
gchar *time_str, *txt, *ret;
static void
gst_time_overlay_class_init (GstTimeOverlayClass * klass)
{
- GstTextOverlayClass *gsttextoverlay_class;
+ GstElementClass *gstelement_class;
+ GstBaseTextOverlayClass *gsttextoverlay_class;
PangoContext *context;
PangoFontDescription *font_description;
- gsttextoverlay_class = (GstTextOverlayClass *) klass;
+ gsttextoverlay_class = (GstBaseTextOverlayClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+
+ gst_element_class_set_details_simple (gstelement_class, "Time overlay",
+ "Filter/Editor/Video",
+ "Overlays buffer time stamps on a video stream",
+ "Tim-Philipp Müller <tim@centricular.net>");
gsttextoverlay_class->get_text = gst_time_overlay_get_text;
- g_mutex_lock (GST_TEXT_OVERLAY_CLASS (klass)->pango_lock);
- context = GST_TEXT_OVERLAY_CLASS (klass)->pango_context;
+ g_mutex_lock (gsttextoverlay_class->pango_lock);
+ context = gsttextoverlay_class->pango_context;
pango_context_set_language (context, pango_language_from_string ("en_US"));
pango_context_set_base_dir (context, PANGO_DIRECTION_LTR);
pango_font_description_set_size (font_description, 18 * PANGO_SCALE);
pango_context_set_font_description (context, font_description);
pango_font_description_free (font_description);
- g_mutex_unlock (GST_TEXT_OVERLAY_CLASS (klass)->pango_lock);
+ g_mutex_unlock (gsttextoverlay_class->pango_lock);
}
static void
-gst_time_overlay_init (GstTimeOverlay * overlay, GstTimeOverlayClass * klass)
+gst_time_overlay_init (GstTimeOverlay * overlay)
{
- GstTextOverlay *textoverlay;
+ GstBaseTextOverlay *textoverlay;
- textoverlay = GST_TEXT_OVERLAY (overlay);
+ textoverlay = GST_BASE_TEXT_OVERLAY (overlay);
- textoverlay->valign = GST_TEXT_OVERLAY_VALIGN_TOP;
- textoverlay->halign = GST_TEXT_OVERLAY_HALIGN_LEFT;
+ textoverlay->valign = GST_BASE_TEXT_OVERLAY_VALIGN_TOP;
+ textoverlay->halign = GST_BASE_TEXT_OVERLAY_HALIGN_LEFT;
}
#ifndef __GST_TIME_OVERLAY_H__
#define __GST_TIME_OVERLAY_H__
-#include "gsttextoverlay.h"
+#include "gstbasetextoverlay.h"
G_BEGIN_DECLS
* Opaque timeoverlay data structure.
*/
struct _GstTimeOverlay {
- GstTextOverlay textoverlay;
+ GstBaseTextOverlay textoverlay;
};
struct _GstTimeOverlayClass {
- GstTextOverlayClass parent_class;
+ GstBaseTextOverlayClass parent_class;
};
GType gst_time_overlay_get_type (void);
GST_STATIC_CAPS ("video/x-theora")
);
-GST_BOILERPLATE (GstTheoraDec, gst_theora_dec, GstElement, GST_TYPE_ELEMENT);
+#define gst_theora_dec_parent_class parent_class
+G_DEFINE_TYPE (GstTheoraDec, gst_theora_dec, GST_TYPE_ELEMENT);
static void theora_dec_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void theora_dec_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
+static gboolean theora_dec_setcaps (GstTheoraDec * dec, GstCaps * caps);
static gboolean theora_dec_sink_event (GstPad * pad, GstEvent * event);
-static gboolean theora_dec_setcaps (GstPad * pad, GstCaps * caps);
static GstFlowReturn theora_dec_chain (GstPad * pad, GstBuffer * buffer);
static GstStateChangeReturn theora_dec_change_state (GstElement * element,
GstStateChange transition);
#endif
static const GstQueryType *theora_get_query_types (GstPad * pad);
-
-static void
-gst_theora_dec_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 (&theora_dec_src_factory));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&theora_dec_sink_factory));
- gst_element_class_set_details_simple (element_class,
- "Theora video decoder", "Codec/Decoder/Video",
- "decode raw theora streams to raw YUV video",
- "Benjamin Otte <otte@gnome.org>, Wim Taymans <wim@fluendo.com>");
-}
-
static gboolean
gst_theora_dec_ctl_is_supported (int req)
{
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&theora_dec_src_factory));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&theora_dec_sink_factory));
+ gst_element_class_set_details_simple (gstelement_class,
+ "Theora video decoder", "Codec/Decoder/Video",
+ "decode raw theora streams to raw YUV video",
+ "Benjamin Otte <otte@gnome.org>, Wim Taymans <wim@fluendo.com>");
+
gstelement_class->change_state = theora_dec_change_state;
GST_DEBUG_CATEGORY_INIT (theoradec_debug, "theoradec", 0, "Theora decoder");
}
static void
-gst_theora_dec_init (GstTheoraDec * dec, GstTheoraDecClass * g_class)
+gst_theora_dec_init (GstTheoraDec * dec)
{
dec->sinkpad =
gst_pad_new_from_static_template (&theora_dec_sink_factory, "sink");
gst_pad_set_event_function (dec->sinkpad, theora_dec_sink_event);
- gst_pad_set_setcaps_function (dec->sinkpad, theora_dec_setcaps);
gst_pad_set_chain_function (dec->sinkpad, theora_dec_chain);
gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
GstClockTimeDiff diff;
GstClockTime timestamp;
- gst_event_parse_qos (event, &proportion, &diff, ×tamp);
+ gst_event_parse_qos (event, NULL, &proportion, &diff, ×tamp);
/* we cannot randomly skip frame decoding since we don't have
* B frames. we can however use the timestamp and diff to not
case GST_EVENT_EOS:
ret = gst_pad_push_event (dec->srcpad, event);
break;
- case GST_EVENT_NEWSEGMENT:
+ case GST_EVENT_SEGMENT:
{
- gboolean update;
- GstFormat format;
- gdouble rate, arate;
- gint64 start, stop, time;
+ const GstSegment *segment;
- gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
- &start, &stop, &time);
+ gst_event_parse_segment (event, &segment);
/* we need TIME format */
- if (format != GST_FORMAT_TIME)
+ if (segment->format != GST_FORMAT_TIME)
goto newseg_wrong_format;
- GST_DEBUG_OBJECT (dec,
- "newsegment: update %d, rate %g, arate %g, start %" GST_TIME_FORMAT
- ", stop %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT,
- update, rate, arate, GST_TIME_ARGS (start), GST_TIME_ARGS (stop),
- GST_TIME_ARGS (time));
+ GST_DEBUG_OBJECT (dec, "segment: %" GST_SEGMENT_FORMAT, segment);
/* now configure the values */
- gst_segment_set_newsegment_full (&dec->segment, update,
- rate, arate, format, start, stop, time);
+ gst_segment_copy_into (segment, &dec->segment);
dec->seqnum = gst_event_get_seqnum (event);
/* We don't forward this unless/until the decoder is initialised */
}
break;
}
+ case GST_EVENT_CAPS:
+ {
+ GstCaps *caps;
+
+ gst_event_parse_caps (event, &caps);
+ ret = theora_dec_setcaps (dec, caps);
+ break;
+ }
case GST_EVENT_TAG:
{
if (dec->have_header)
break;
}
default:
- ret = gst_pad_push_event (dec->srcpad, event);
+ ret = gst_pad_event_default (pad, event);
break;
}
done:
}
static gboolean
-theora_dec_setcaps (GstPad * pad, GstCaps * caps)
+theora_dec_setcaps (GstTheoraDec * dec, GstCaps * caps)
{
- GstTheoraDec *dec;
GstStructure *s;
const GValue *codec_data;
- dec = GST_THEORA_DEC (gst_pad_get_parent (pad));
-
s = gst_caps_get_structure (caps, 0);
/* parse the par, this overrides the encoded par */
if ((codec_data = gst_structure_get_value (s, "codec_data"))) {
if (G_VALUE_TYPE (codec_data) == GST_TYPE_BUFFER) {
GstBuffer *buffer;
- guint8 *data;
- guint size;
+ guint8 *data, *ptr;
+ gsize size, left;
guint offset;
buffer = gst_value_get_buffer (codec_data);
offset = 0;
- size = GST_BUFFER_SIZE (buffer);
- data = GST_BUFFER_DATA (buffer);
+ data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
- while (size > 2) {
+ ptr = data;
+ left = size;
+
+ while (left > 2) {
guint psize;
GstBuffer *buf;
- psize = (data[0] << 8) | data[1];
+ psize = (ptr[0] << 8) | ptr[1];
/* skip header */
- data += 2;
- size -= 2;
+ ptr += 2;
+ left -= 2;
offset += 2;
/* make sure we don't read too much */
- psize = MIN (psize, size);
+ psize = MIN (psize, left);
- buf = gst_buffer_create_sub (buffer, offset, psize);
+ buf =
+ gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, offset, psize);
/* first buffer is a discont buffer */
if (offset == 2)
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
/* now feed it to the decoder we can ignore the error */
- theora_dec_chain (pad, buf);
+ theora_dec_chain (dec->sinkpad, buf);
/* skip the data */
- size -= psize;
- data += psize;
+ left -= psize;
+ ptr += psize;
offset += psize;
}
+ gst_buffer_unmap (buffer, data, size);
}
}
- gst_object_unref (dec);
-
return TRUE;
}
theora_handle_comment_packet (GstTheoraDec * dec, ogg_packet * packet)
{
gchar *encoder = NULL;
- GstBuffer *buf;
GstTagList *list;
GST_DEBUG_OBJECT (dec, "parsing comment packet");
- buf = gst_buffer_new ();
- GST_BUFFER_SIZE (buf) = packet->bytes;
- GST_BUFFER_DATA (buf) = packet->packet;
-
list =
- gst_tag_list_from_vorbiscomment_buffer (buf, (guint8 *) "\201theora", 7,
- &encoder);
-
- gst_buffer_unref (buf);
+ gst_tag_list_from_vorbiscomment (packet->packet, packet->bytes,
+ (guint8 *) "\201theora", 7, &encoder);
if (!list) {
GST_ERROR_OBJECT (dec, "couldn't decode comments");
}
static GstFlowReturn
+theora_negotiate_pool (GstTheoraDec * dec, GstCaps * caps)
+{
+ GstQuery *query;
+ GstBufferPool *pool = NULL;
+ guint size, min, max, prefix, alignment;
+
+ /* find a pool for the negotiated caps now */
+ query = gst_query_new_allocation (caps, TRUE);
+
+ if (gst_pad_peer_query (dec->srcpad, query)) {
+ GST_DEBUG_OBJECT (dec, "got downstream ALLOCATION hints");
+ /* we got configuration from our peer, parse them */
+ gst_query_parse_allocation_params (query, &size, &min, &max, &prefix,
+ &alignment, &pool);
+ } else {
+ GST_DEBUG_OBJECT (dec, "didn't get downstream ALLOCATION hints");
+ size = gst_video_format_get_size (dec->format, dec->width, dec->height);
+ min = max = 0;
+ prefix = 0;
+ alignment = 1;
+ }
+
+ 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, caps, size, min, max, prefix, 0,
+ alignment);
+ gst_buffer_pool_set_config (pool, config);
+ }
+
+ if (dec->pool)
+ gst_object_unref (dec->pool);
+ dec->pool = pool;
+
+ /* FIXME, we can check if downstream supports clipping and/or video
+ * metadata. */
+
+ /* and activate */
+ gst_buffer_pool_set_active (pool, TRUE);
+
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
theora_handle_type_packet (GstTheoraDec * dec, ogg_packet * packet)
{
GstCaps *caps;
dec->info.pic_width, dec->info.pic_height,
dec->info.pic_x, dec->info.pic_y);
- if (dec->info.pixel_fmt == TH_PF_420) {
- dec->output_bpp = 12; /* Average bits per pixel. */
- fourcc = GST_MAKE_FOURCC ('I', '4', '2', '0');
- } else if (dec->info.pixel_fmt == TH_PF_422) {
- dec->output_bpp = 16;
- fourcc = GST_MAKE_FOURCC ('Y', '4', '2', 'B');
- } else if (dec->info.pixel_fmt == TH_PF_444) {
- dec->output_bpp = 24;
- fourcc = GST_MAKE_FOURCC ('Y', '4', '4', '4');
- } else {
- GST_ERROR_OBJECT (dec, "Invalid pixel format %d", dec->info.pixel_fmt);
- return GST_FLOW_ERROR;
+ switch (dec->info.pixel_fmt) {
+ case TH_PF_444:
+ dec->output_bpp = 24;
+ dec->format = GST_VIDEO_FORMAT_Y444;
+ fourcc = GST_MAKE_FOURCC ('Y', '4', '4', '4');
+ break;
+ case TH_PF_420:
+ dec->output_bpp = 12; /* Average bits per pixel. */
+ dec->format = GST_VIDEO_FORMAT_I420;
+ fourcc = GST_MAKE_FOURCC ('I', '4', '2', '0');
+ break;
+ case TH_PF_422:
+ dec->output_bpp = 16;
+ dec->format = GST_VIDEO_FORMAT_Y42B;
+ fourcc = GST_MAKE_FOURCC ('Y', '4', '2', 'B');
+ break;
+ default:
+ goto invalid_format;
}
if (dec->crop) {
gst_pad_set_caps (dec->srcpad, caps);
gst_caps_unref (caps);
+ /* negotiate a bufferpool */
+ if ((ret = theora_negotiate_pool (dec, caps)) != GST_FLOW_OK)
+ goto no_bufferpool;
+
dec->have_header = TRUE;
if (dec->pendingevents) {
}
return ret;
+
+ /* ERRORS */
+invalid_format:
+ {
+ GST_ERROR_OBJECT (dec, "Invalid pixel format %d", dec->info.pixel_fmt);
+ return GST_FLOW_ERROR;
+ }
+no_bufferpool:
+ {
+ return ret;
+ }
}
static GstFlowReturn
{
gboolean res = TRUE;
GstClockTime in_ts, in_dur, stop;
- gint64 cstart, cstop;
+ guint64 cstart, cstop;
in_ts = GST_BUFFER_TIMESTAMP (buf);
in_dur = GST_BUFFER_DURATION (buf);
gint width, height, stride;
GstFlowReturn result;
int i, plane;
- GstVideoFormat format;
guint8 *dest, *src;
+ gsize size;
+ guint8 *data;
+ gboolean reconfigure;
- switch (dec->info.pixel_fmt) {
- case TH_PF_444:
- format = GST_VIDEO_FORMAT_Y444;
- break;
- case TH_PF_420:
- format = GST_VIDEO_FORMAT_I420;
- break;
- case TH_PF_422:
- format = GST_VIDEO_FORMAT_Y42B;
- break;
- default:
- g_assert_not_reached ();
- }
+ GST_OBJECT_LOCK (dec->srcpad);
+ reconfigure = GST_PAD_NEEDS_RECONFIGURE (dec->srcpad);
+ GST_OBJECT_FLAG_UNSET (dec->srcpad, GST_PAD_NEED_RECONFIGURE);
+ GST_OBJECT_UNLOCK (dec->srcpad);
- result =
- gst_pad_alloc_buffer_and_set_caps (dec->srcpad, GST_BUFFER_OFFSET_NONE,
- gst_video_format_get_size (format, dec->width, dec->height),
- GST_PAD_CAPS (dec->srcpad), out);
- if (G_UNLIKELY (result != GST_FLOW_OK)) {
- GST_DEBUG_OBJECT (dec, "could not get buffer, reason: %s",
- gst_flow_get_name (result));
- return result;
+ if (reconfigure) {
+ GstCaps *caps;
+
+ caps = gst_pad_get_current_caps (dec->srcpad);
+ theora_negotiate_pool (dec, caps);
+ gst_caps_unref (caps);
}
+ result = gst_buffer_pool_acquire_buffer (dec->pool, out, NULL);
+ if (G_UNLIKELY (result != GST_FLOW_OK))
+ goto no_buffer;
+
+ data = gst_buffer_map (*out, &size, NULL, GST_MAP_WRITE);
+
+ /* FIXME, we can do things slightly more efficient when we know that
+ * downstream understands clipping and video metadata */
+
for (plane = 0; plane < 3; plane++) {
- width = gst_video_format_get_component_width (format, plane, dec->width);
- height = gst_video_format_get_component_height (format, plane, dec->height);
- stride = gst_video_format_get_row_stride (format, plane, dec->width);
+ width =
+ gst_video_format_get_component_width (dec->format, plane, dec->width);
+ height =
+ gst_video_format_get_component_height (dec->format, plane, dec->height);
+ stride = gst_video_format_get_row_stride (dec->format, plane, dec->width);
- dest =
- GST_BUFFER_DATA (*out) + gst_video_format_get_component_offset (format,
+ dest = data + gst_video_format_get_component_offset (dec->format,
plane, dec->width, dec->height);
src = buf[plane].data;
src += ((height == dec->height) ? dec->offset_y : dec->offset_y / 2)
src += buf[plane].stride;
}
}
+ gst_buffer_unmap (*out, data, size);
return GST_FLOW_OK;
+
+ /* ERRORS */
+no_buffer:
+ {
+ GST_DEBUG_OBJECT (dec, "could not get buffer, reason: %s",
+ gst_flow_get_name (result));
+ return result;
+ }
}
static GstFlowReturn
ogg_packet packet;
GstFlowReturn result = GST_FLOW_OK;
GstClockTime timestamp, duration;
+ gsize size;
/* make ogg_packet out of the buffer */
- packet.packet = GST_BUFFER_DATA (buf);
- packet.bytes = GST_BUFFER_SIZE (buf);
+ packet.packet = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
+ packet.bytes = size;
packet.granulepos = -1;
packet.packetno = 0; /* we don't really care */
packet.b_o_s = dec->have_header ? 0 : 1;
} else {
result = theora_handle_data_packet (dec, &packet, timestamp, duration);
}
-
done:
+ gst_buffer_unmap (buf, packet.packet, size);
+
return result;
}
GST_DEBUG_OBJECT (dec, "received discont,gathering buffers");
while (dec->gather) {
GstBuffer *gbuf;
- guint8 *data;
+ guint8 data[1];
gbuf = GST_BUFFER_CAST (dec->gather->data);
/* remove from the gather list */
dec->decode = g_list_prepend (dec->decode, gbuf);
/* if we copied a keyframe, flush and decode the decode queue */
- data = GST_BUFFER_DATA (gbuf);
+ gst_buffer_extract (gbuf, 0, data, 1);
if ((data[0] & 0x40) == 0) {
GST_DEBUG_OBJECT (dec, "copied keyframe");
res = theora_dec_flush_decode (dec);
/* add buffer to gather queue */
GST_DEBUG_OBJECT (dec, "gathering buffer %p, size %u", buf,
- GST_BUFFER_SIZE (buf));
+ gst_buffer_get_size (buf));
dec->gather = g_list_prepend (dec->gather, buf);
return res;
break;
}
- ret = parent_class->change_state (element, transition);
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
switch (transition) {
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
th_decode_free (dec->decoder);
dec->decoder = NULL;
gst_theora_dec_reset (dec);
+ if (dec->pool) {
+ gst_buffer_pool_set_active (dec->pool, FALSE);
+ gst_object_unref (dec->pool);
+ dec->pool = NULL;
+ }
break;
case GST_STATE_CHANGE_READY_TO_NULL:
break;
#include <gst/gst.h>
#include <theora/theoradec.h>
#include <string.h>
+#include <gst/video/video.h>
G_BEGIN_DECLS
/* theora decoder state */
th_dec_ctx *decoder;
- //theora_state state;
th_setup_info *setup;
th_info info;
th_comment comment;
GstClockTime last_timestamp;
guint64 frame_nr;
gboolean need_keyframe;
+ GstVideoFormat format;
gint width, height;
gint offset_x, offset_y;
gint output_bpp;
+ GstBufferPool *pool;
/* telemetry debuging options */
gint telemetry_mv;
GST_STATIC_CAPS ("video/x-theora")
);
-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 (GstTheoraEnc, gst_theora_enc, GstElement,
- GST_TYPE_ELEMENT, _do_init);
+#define gst_theora_enc_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstTheoraEnc, gst_theora_enc,
+ GST_TYPE_ELEMENT, G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL));
static gboolean theora_enc_sink_event (GstPad * pad, GstEvent * event);
static gboolean theora_enc_src_event (GstPad * pad, GstEvent * event);
static GstFlowReturn theora_enc_chain (GstPad * pad, GstBuffer * buffer);
static GstStateChangeReturn theora_enc_change_state (GstElement * element,
GstStateChange transition);
-static GstCaps *theora_enc_sink_getcaps (GstPad * pad);
+static GstCaps *theora_enc_sink_getcaps (GstPad * pad, GstCaps * filter);
static gboolean theora_enc_sink_setcaps (GstPad * pad, GstCaps * caps);
static void theora_enc_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
gboolean begin, gboolean eos);
static void
-gst_theora_enc_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 (&theora_enc_src_factory));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&theora_enc_sink_factory));
- gst_element_class_set_details_simple (element_class,
- "Theora video encoder", "Codec/Encoder/Video",
- "encode raw YUV video to a theora stream",
- "Wim Taymans <wim@fluendo.com>");
-}
-
-static void
gst_theora_enc_class_init (GstTheoraEncClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
THEORA_DEF_MULTIPASS_MODE,
(GParamFlags) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&theora_enc_src_factory));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&theora_enc_sink_factory));
+ gst_element_class_set_details_simple (gstelement_class,
+ "Theora video encoder", "Codec/Encoder/Video",
+ "encode raw YUV video to a theora stream",
+ "Wim Taymans <wim@fluendo.com>");
+
gstelement_class->change_state = theora_enc_change_state;
}
static void
-gst_theora_enc_init (GstTheoraEnc * enc, GstTheoraEncClass * g_class)
+gst_theora_enc_init (GstTheoraEnc * enc)
{
enc->sinkpad =
gst_pad_new_from_static_template (&theora_enc_sink_factory, "sink");
}
static GstCaps *
-theora_enc_sink_getcaps (GstPad * pad)
+theora_enc_sink_getcaps (GstPad * pad, GstCaps * filter)
{
GstCaps *caps;
char *supported_formats, *caps_string;
g_free (supported_formats);
GST_DEBUG ("Supported caps: %" GST_PTR_FORMAT, caps);
+ if (filter) {
+ GstCaps *intersection;
+
+ intersection =
+ gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+ gst_caps_unref (caps);
+ caps = intersection;
+ }
+
return caps;
}
goto done;
}
- memcpy (GST_BUFFER_DATA (buf), packet->packet, packet->bytes);
- gst_buffer_set_caps (buf, GST_PAD_CAPS (enc->srcpad));
+ gst_buffer_fill (buf, 0, packet->packet, packet->bytes);
/* see ext/ogg/README; OFFSET_END takes "our" granulepos, OFFSET its
* time representation */
GST_BUFFER_OFFSET_END (buf) =
{
GstFlowReturn ret;
- enc->bytes_out += GST_BUFFER_SIZE (buffer);
+ enc->bytes_out += gst_buffer_get_size (buffer);
ret = gst_pad_push (enc->srcpad, buffer);
enc = GST_THEORA_ENC (GST_PAD_PARENT (pad));
switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_NEWSEGMENT:
+ case GST_EVENT_SEGMENT:
{
- gboolean update;
- gdouble rate, applied_rate;
- GstFormat format;
- gint64 start, stop, time;
-
- gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
- &format, &start, &stop, &time);
-
- gst_segment_set_newsegment_full (&enc->segment, update, rate,
- applied_rate, format, start, stop, time);
+ gst_event_copy_segment (event, &enc->segment);
res = gst_pad_push_event (enc->srcpad, event);
break;
while (!done) {
if (gst_adapter_available (enc->multipass_cache_adapter) == 0) {
+ guint8 *data;
+ gsize size;
+
cache_buf = gst_buffer_new_and_alloc (512);
+
+ data = gst_buffer_map (cache_buf, &size, NULL, GST_MAP_READ);
stat = g_io_channel_read_chars (enc->multipass_cache_fd,
- (gchar *) GST_BUFFER_DATA (cache_buf), GST_BUFFER_SIZE (cache_buf),
- &bytes_read, NULL);
+ (gchar *) data, size, &bytes_read, NULL);
if (bytes_read <= 0) {
+ gst_buffer_unmap (cache_buf, data, 0);
gst_buffer_unref (cache_buf);
break;
} else {
- GST_BUFFER_SIZE (cache_buf) = bytes_read;
-
+ gst_buffer_unmap (cache_buf, data, bytes_read);
gst_adapter_push (enc->multipass_cache_adapter, cache_buf);
}
}
bytes_read =
MIN (gst_adapter_available (enc->multipass_cache_adapter), 512);
- cache_data = gst_adapter_peek (enc->multipass_cache_adapter, bytes_read);
+ cache_data = gst_adapter_map (enc->multipass_cache_adapter, bytes_read);
bytes_consumed =
th_encode_ctl (enc->encoder, TH_ENCCTL_2PASS_IN, (guint8 *) cache_data,
bytes_read);
+ gst_adapter_unmap (enc->multipass_cache_adapter, 0);
+
done = bytes_consumed <= 0;
if (bytes_consumed > 0)
gst_adapter_flush (enc->multipass_cache_adapter, bytes_consumed);
buffers = g_slist_reverse (buffers);
/* mark buffers and put on caps */
- caps = gst_pad_get_caps (enc->srcpad);
+ caps = gst_pad_get_caps (enc->srcpad, NULL);
caps = theora_set_header_on_caps (caps, buffers);
GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
gst_pad_set_caps (enc->srcpad, caps);
-
- g_slist_foreach (buffers, (GFunc) gst_buffer_set_caps, caps);
-
gst_caps_unref (caps);
/* push out the header buffers */
{
th_ycbcr_buffer ycbcr;
gint res;
+ guint8 *data;
+ gsize size;
- theora_enc_init_buffer (ycbcr, &enc->info, GST_BUFFER_DATA (buffer));
+ data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
+ theora_enc_init_buffer (ycbcr, &enc->info, data);
if (theora_enc_is_discontinuous (enc, running_time, duration)) {
theora_enc_reset (enc);
if (enc->multipass_cache_fd
&& enc->multipass_mode == MULTIPASS_MODE_SECOND_PASS) {
if (!theora_enc_read_multipass_cache (enc)) {
+ gst_buffer_unmap (buffer, data, size);
ret = GST_FLOW_ERROR;
goto multipass_read_failed;
}
if (enc->multipass_cache_fd
&& enc->multipass_mode == MULTIPASS_MODE_FIRST_PASS) {
if (!theora_enc_write_multipass_cache (enc, FALSE, FALSE)) {
+ gst_buffer_unmap (buffer, data, size);
ret = GST_FLOW_ERROR;
goto multipass_write_failed;
}
next_time - enc->next_ts);
enc->next_ts = next_time;
- if (ret != GST_FLOW_OK)
+ if (ret != GST_FLOW_OK) {
+ gst_buffer_unmap (buffer, data, size);
goto data_push;
+ }
}
+ gst_buffer_unmap (buffer, data, size);
gst_buffer_unref (buffer);
}
break;
}
- ret = parent_class->change_state (element, transition);
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
switch (transition) {
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
PROP_SYNCHRONIZATION_POINTS
};
-GST_BOILERPLATE (GstTheoraParse, gst_theora_parse, GstElement,
- GST_TYPE_ELEMENT);
+#define gst_theora_parse_parent_class parent_class
+G_DEFINE_TYPE (GstTheoraParse, gst_theora_parse, GST_TYPE_ELEMENT);
static void theora_parse_dispose (GObject * object);
static void theora_parse_get_property (GObject * object, guint prop_id,
static gboolean theora_parse_src_query (GstPad * pad, GstQuery * query);
static void
-gst_theora_parse_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 (&theora_parse_src_factory));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&theora_parse_sink_factory));
- gst_element_class_set_details_simple (element_class,
- "Theora video parser", "Codec/Parser/Video",
- "parse raw theora streams", "Andy Wingo <wingo@pobox.com>");
-}
-
-static void
gst_theora_parse_class_init (GstTheoraParseClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS),
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&theora_parse_src_factory));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&theora_parse_sink_factory));
+ gst_element_class_set_details_simple (gstelement_class,
+ "Theora video parser", "Codec/Parser/Video",
+ "parse raw theora streams", "Andy Wingo <wingo@pobox.com>");
+
gstelement_class->change_state = theora_parse_change_state;
GST_DEBUG_CATEGORY_INIT (theoraparse_debug, "theoraparse", 0,
}
static void
-gst_theora_parse_init (GstTheoraParse * parse, GstTheoraParseClass * g_class)
+gst_theora_parse_init (GstTheoraParse * parse)
{
parse->sinkpad =
gst_pad_new_from_static_template (&theora_parse_sink_factory, "sink");
if (bufs[i] == NULL)
continue;
- bufs[i] = gst_buffer_make_metadata_writable (bufs[i]);
+ bufs[i] = gst_buffer_make_writable (bufs[i]);
GST_BUFFER_FLAG_SET (bufs[i], GST_BUFFER_FLAG_IN_CAPS);
g_value_init (&value, GST_TYPE_BUFFER);
g_assert (!parse->streamheader_received);
- caps = gst_caps_make_writable (gst_pad_get_caps (parse->srcpad));
+ caps = gst_caps_make_writable (gst_pad_get_caps (parse->srcpad, NULL));
theora_parse_set_header_on_caps (parse, caps);
GST_DEBUG_OBJECT (parse, "here are the caps: %" GST_PTR_FORMAT, caps);
gst_pad_set_caps (parse->srcpad, caps);
ogg_packet packet;
GstBuffer *buf;
int ret;
+ gsize size;
buf = parse->streamheader[i];
if (buf == NULL)
continue;
- packet.packet = GST_BUFFER_DATA (buf);
- packet.bytes = GST_BUFFER_SIZE (buf);
+ packet.packet = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
+ packet.bytes = size;
packet.granulepos = GST_BUFFER_OFFSET_END (buf);
packet.packetno = i + 1;
packet.e_o_s = 0;
packet.b_o_s = (i == 0);
ret = th_decode_headerin (&parse->info, &parse->comment, &setup, &packet);
+ gst_buffer_unmap (buf, packet.packet, size);
if (ret < 0) {
GST_WARNING_OBJECT (parse, "Failed to decode Theora header %d: %d\n",
i + 1, ret);
GstBuffer *buf;
if ((buf = parse->streamheader[i])) {
- buf = gst_buffer_make_metadata_writable (buf);
- gst_buffer_set_caps (buf, GST_PAD_CAPS (parse->srcpad));
gst_pad_push (parse->srcpad, buf);
parse->streamheader[i] = NULL;
}
static gboolean
is_keyframe (GstBuffer * buf)
{
- if (!GST_BUFFER_DATA (buf))
- return FALSE;
- if (!GST_BUFFER_SIZE (buf))
+ gsize size;
+ guint8 data[1];
+
+ size = gst_buffer_get_size (buf);
+ if (size == 0)
return FALSE;
- return ((GST_BUFFER_DATA (buf)[0] & 0x40) == 0);
+
+ gst_buffer_extract (buf, 0, data, 1);
+
+ return ((data[0] & 0x40) == 0);
}
static void
GST_BUFFER_TIMESTAMP (buf) = this_time;
GST_BUFFER_DURATION (buf) = next_time - this_time;
- gst_buffer_set_caps (buf, GST_PAD_CAPS (parse->srcpad));
-
if (parse->times)
theora_parse_munge_granulepos (parse, buf, keyframe, frame);
{
GstFlowReturn ret = GST_FLOW_OK;
- buf = gst_buffer_make_metadata_writable (buf);
+ buf = gst_buffer_make_writable (buf);
g_queue_push_tail (parse->buffer_queue, buf);
{
GstFlowReturn ret;
GstTheoraParse *parse;
- guint8 *data;
- guint size;
+ guint8 *data, header;
+ gsize size;
gboolean have_header;
parse = GST_THEORA_PARSE (gst_pad_get_parent (pad));
- data = GST_BUFFER_DATA (buffer);
- size = GST_BUFFER_SIZE (buffer);
-
have_header = FALSE;
+
+ data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
+ header = data[0];
+ gst_buffer_unmap (buffer, data, size);
+
if (size >= 1) {
- if (data[0] & 0x80)
+ if (header & 0x80)
have_header = TRUE;
}
if (parse->send_streamheader) {
/* we need to collect the headers still */
/* so put it on the streamheader list and return */
- if (data[0] >= 0x80 && data[0] <= 0x82)
- parse->streamheader[data[0] - 0x80] = buffer;
+ if (header >= 0x80 && header <= 0x82)
+ parse->streamheader[header - 0x80] = buffer;
}
ret = GST_FLOW_OK;
} else {
break;
}
- ret = parent_class->change_state (element, transition);
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_READY:
GST_STATIC_CAPS ("audio/x-vorbis")
);
-GST_BOILERPLATE (GST_VORBIS_DEC_GLIB_TYPE_NAME, gst_vorbis_dec, GstElement,
- GST_TYPE_ELEMENT);
+#define gst_vorbis_dec_parent_class parent_class
+G_DEFINE_TYPE (GST_VORBIS_DEC_GLIB_TYPE_NAME, gst_vorbis_dec, GST_TYPE_ELEMENT);
static void vorbis_dec_finalize (GObject * object);
static gboolean vorbis_dec_sink_event (GstPad * pad, GstEvent * event);
static gboolean vorbis_dec_sink_query (GstPad * pad, GstQuery * query);
static void
-gst_vorbis_dec_base_init (gpointer g_class)
+gst_vorbis_dec_class_init (GstVorbisDecClass * klass)
{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
- GstPadTemplate *src_template, *sink_template;
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+
+ gobject_class->finalize = vorbis_dec_finalize;
- src_template = gst_static_pad_template_get (&vorbis_dec_src_factory);
- gst_element_class_add_pad_template (element_class, src_template);
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&vorbis_dec_src_factory));
- sink_template = gst_static_pad_template_get (&vorbis_dec_sink_factory);
- gst_element_class_add_pad_template (element_class, sink_template);
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&vorbis_dec_sink_factory));
- gst_element_class_set_details_simple (element_class,
+ gst_element_class_set_details_simple (gstelement_class,
"Vorbis audio decoder", "Codec/Decoder/Audio",
GST_VORBIS_DEC_DESCRIPTION,
"Benjamin Otte <otte@gnome.org>, Chris Lord <chris@openedhand.com>");
-}
-
-static void
-gst_vorbis_dec_class_init (GstVorbisDecClass * klass)
-{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
- GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
-
- gobject_class->finalize = vorbis_dec_finalize;
gstelement_class->change_state = GST_DEBUG_FUNCPTR (vorbis_dec_change_state);
}
}
static void
-gst_vorbis_dec_init (GstVorbisDec * dec, GstVorbisDecClass * g_class)
+gst_vorbis_dec_init (GstVorbisDec * dec)
{
dec->sinkpad = gst_pad_new_from_static_template (&vorbis_dec_sink_factory,
"sink");
gst_vorbis_dec_reset (dec);
ret = gst_pad_push_event (dec->srcpad, event);
break;
- case GST_EVENT_NEWSEGMENT:
+ case GST_EVENT_SEGMENT:
{
- GstFormat format;
- gdouble rate, arate;
- gint64 start, stop, time;
- gboolean update;
+ const GstSegment *segment;
- gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
- &start, &stop, &time);
+ gst_event_parse_segment (event, &segment);
/* we need time for now */
- if (format != GST_FORMAT_TIME)
+ if (segment->format != GST_FORMAT_TIME)
goto newseg_wrong_format;
- GST_DEBUG_OBJECT (dec,
- "newsegment: update %d, rate %g, arate %g, start %" GST_TIME_FORMAT
- ", stop %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT,
- update, rate, arate, GST_TIME_ARGS (start), GST_TIME_ARGS (stop),
- GST_TIME_ARGS (time));
+ GST_DEBUG_OBJECT (dec, "segment: %" GST_SEGMENT_FORMAT, segment);
/* now configure the values */
- gst_segment_set_newsegment_full (&dec->segment, update,
- rate, arate, format, start, stop, time);
+ gst_segment_copy_into (segment, &dec->segment);
dec->seqnum = gst_event_get_seqnum (event);
if (dec->initialized)
break;
}
default:
- ret = gst_pad_push_event (dec->srcpad, event);
+ ret = gst_pad_event_default (pad, event);
break;
}
done:
* for mono/stereo and avoid the depth switch in tremor case */
vd->copy_samples = get_copy_sample_func (vd->vi.channels, vd->width);
- caps = gst_caps_copy (gst_pad_get_pad_template_caps (vd->srcpad));
+ caps = gst_caps_make_writable (gst_pad_get_pad_template_caps (vd->srcpad));
gst_caps_set_simple (caps, "rate", G_TYPE_INT, vd->vi.rate,
"channels", G_TYPE_INT, vd->vi.channels,
"width", G_TYPE_INT, width, NULL);
guint bitrate = 0;
gchar *encoder = NULL;
GstTagList *list, *old_list;
- GstBuffer *buf;
+ guint8 *data;
+ gsize size;
GST_DEBUG_OBJECT (vd, "parsing comment packet");
- buf = gst_buffer_new ();
- GST_BUFFER_DATA (buf) = gst_ogg_packet_data (packet);
- GST_BUFFER_SIZE (buf) = gst_ogg_packet_size (packet);
+ data = gst_ogg_packet_data (packet);
+ size = gst_ogg_packet_size (packet);
list =
- gst_tag_list_from_vorbiscomment_buffer (buf, (guint8 *) "\003vorbis", 7,
+ gst_tag_list_from_vorbiscomment (data, size, (guint8 *) "\003vorbis", 7,
&encoder);
old_list = vd->taglist;
if (old_list)
gst_tag_list_free (old_list);
gst_tag_list_free (list);
- gst_buffer_unref (buf);
if (!vd->taglist) {
GST_ERROR_OBJECT (vd, "couldn't decode comments");
guint sample_count;
GstBuffer *out = NULL;
GstFlowReturn result;
- gint size;
+ guint8 *data;
+ gsize size;
if (G_UNLIKELY (!vd->initialized))
goto not_initialized;
size);
/* alloc buffer for it */
- result =
- gst_pad_alloc_buffer_and_set_caps (vd->srcpad, GST_BUFFER_OFFSET_NONE,
- size, GST_PAD_CAPS (vd->srcpad), &out);
- if (G_UNLIKELY (result != GST_FLOW_OK))
- goto done;
+ out = gst_buffer_new_and_alloc (size);
/* get samples ready for reading now, should be sample_count */
#ifdef USE_TREMOLO
#ifndef USE_TREMOLO
/* copy samples in buffer */
- vd->copy_samples ((vorbis_sample_t *) GST_BUFFER_DATA (out), pcm,
+ data = gst_buffer_map (out, NULL, NULL, GST_MAP_WRITE);
+ vd->copy_samples ((vorbis_sample_t *) data, pcm,
sample_count, vd->vi.channels, vd->width);
#endif
GST_LOG_OBJECT (vd, "setting output size to %d", size);
- GST_BUFFER_SIZE (out) = size;
+ gst_buffer_unmap (out, data, size);
/* this should not overflow */
if (duration == -1)
{
ogg_packet *packet;
ogg_packet_wrapper packet_wrapper;
+ GstFlowReturn ret;
- gst_ogg_packet_wrapper_from_buffer (&packet_wrapper, buffer);
+ gst_ogg_packet_wrapper_map (&packet_wrapper, buffer);
packet = gst_ogg_packet_from_wrapper (&packet_wrapper);
- return vorbis_handle_header_packet (vd, packet);
+ ret = vorbis_handle_header_packet (vd, packet);
+
+ gst_ogg_packet_wrapper_unmap (&packet_wrapper, buffer);
+
+ return ret;
}
vorbis_dec_handle_header_caps (GstVorbisDec * vd, GstBuffer * buffer)
{
GstFlowReturn result = GST_FLOW_OK;
- GstCaps *caps = GST_PAD_CAPS (vd->sinkpad);
- GstStructure *s = gst_caps_get_structure (caps, 0);
- const GValue *array = gst_structure_get_value (s, "streamheader");
-
- if (array && (gst_value_array_get_size (array) >= MIN_NUM_HEADERS)) {
- const GValue *value = NULL;
- GstBuffer *buf = NULL;
-
- /* initial header */
- value = gst_value_array_get_value (array, 0);
- buf = gst_value_get_buffer (value);
- if (!buf)
- goto null_buffer;
- result = vorbis_dec_handle_header_buffer (vd, buf);
-
- /* comment header */
- if (result == GST_FLOW_OK) {
- value = gst_value_array_get_value (array, 1);
- buf = gst_value_get_buffer (value);
- if (!buf)
- goto null_buffer;
- result = vorbis_dec_handle_header_buffer (vd, buf);
- }
+ GstCaps *caps;
+ GstStructure *s;
+ const GValue *array;
+ const GValue *value = NULL;
+ GstBuffer *buf = NULL;
- /* bitstream codebook header */
- if (result == GST_FLOW_OK) {
- value = gst_value_array_get_value (array, 2);
- buf = gst_value_get_buffer (value);
- if (!buf)
- goto null_buffer;
- result = vorbis_dec_handle_header_buffer (vd, buf);
- }
- } else
+ if ((caps = gst_pad_get_current_caps (vd->sinkpad)) == NULL)
+ goto no_caps;
+
+ if ((s = gst_caps_get_structure (caps, 0)) == NULL)
+ goto no_caps;
+
+ array = gst_structure_get_value (s, "streamheader");
+
+ if (array == NULL || (gst_value_array_get_size (array) < MIN_NUM_HEADERS))
goto array_error;
-done:
- return (result != GST_FLOW_OK ? GST_FLOW_NOT_NEGOTIATED : GST_FLOW_OK);
+ /* initial header */
+ value = gst_value_array_get_value (array, 0);
+ buf = gst_value_get_buffer (value);
+ if (!buf)
+ goto null_buffer;
+ result = vorbis_dec_handle_header_buffer (vd, buf);
+ if (result != GST_FLOW_OK)
+ goto buffer_error;
+
+ /* comment header */
+ value = gst_value_array_get_value (array, 1);
+ buf = gst_value_get_buffer (value);
+ if (!buf)
+ goto null_buffer;
+ result = vorbis_dec_handle_header_buffer (vd, buf);
+ if (result != GST_FLOW_OK)
+ goto buffer_error;
+
+ /* bitstream codebook header */
+ value = gst_value_array_get_value (array, 2);
+ buf = gst_value_get_buffer (value);
+ if (!buf)
+ goto null_buffer;
+ result = vorbis_dec_handle_header_buffer (vd, buf);
+ if (result != GST_FLOW_OK)
+ goto buffer_error;
+ return result;
+
+no_caps:
+ {
+ GST_WARNING_OBJECT (vd, "no caps negotiated");
+ return GST_FLOW_NOT_NEGOTIATED;
+ }
array_error:
{
GST_WARNING_OBJECT (vd, "streamheader array not found");
- result = GST_FLOW_ERROR;
- goto done;
+ return GST_FLOW_NOT_NEGOTIATED;
}
-
null_buffer:
{
GST_WARNING_OBJECT (vd, "streamheader with null buffer received");
- result = GST_FLOW_ERROR;
- goto done;
+ return GST_FLOW_NOT_NEGOTIATED;
+ }
+buffer_error:
+ {
+ GST_WARNING_OBJECT (vd, "error handling buffer");
+ return GST_FLOW_NOT_NEGOTIATED;
}
}
GstFlowReturn result = GST_FLOW_OK;
/* make ogg_packet out of the buffer */
- gst_ogg_packet_wrapper_from_buffer (&packet_wrapper, buffer);
+ gst_ogg_packet_wrapper_map (&packet_wrapper, buffer);
packet = gst_ogg_packet_from_wrapper (&packet_wrapper);
/* set some more stuff */
packet->granulepos = -1;
}
done:
+ gst_ogg_packet_wrapper_unmap (&packet_wrapper, buffer);
+
return result;
empty_buffer:
if (G_LIKELY (buf)) {
GST_DEBUG_OBJECT (vd,
"gathering buffer %p of size %u, time %" GST_TIME_FORMAT
- ", dur %" GST_TIME_FORMAT, buf, GST_BUFFER_SIZE (buf),
+ ", dur %" GST_TIME_FORMAT, buf, gst_buffer_get_size (buf),
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
break;
}
- res = parent_class->change_state (element, transition);
+ res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
switch (transition) {
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
}
static inline void
-gst_ogg_packet_wrapper_from_buffer (ogg_packet * packet, GstBuffer * buffer)
+gst_ogg_packet_wrapper_map (ogg_packet * packet, GstBuffer * buffer)
{
- packet->packet = GST_BUFFER_DATA (buffer);
- packet->bytes = GST_BUFFER_SIZE (buffer);
+ gsize size;
+
+ packet->packet = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
+ packet->bytes = size;
+}
+
+static inline void
+gst_ogg_packet_wrapper_unmap (ogg_packet * packet, GstBuffer * buffer)
+{
+ gst_buffer_unmap (buffer, packet->packet, packet->bytes);
}
static inline ogg_packet *
}
static inline void
-gst_ogg_packet_wrapper_from_buffer (ogg_packet_wrapper * packet,
+gst_ogg_packet_wrapper_map (ogg_packet_wrapper * packet,
GstBuffer * buffer)
{
ogg_reference *ref = &packet->ref;
ogg_buffer *buf = &packet->buf;
+ gsize size;
- buf->data = GST_BUFFER_DATA (buffer);
- buf->size = GST_BUFFER_SIZE (buffer);
+ buf->data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
+ buf->size = size;
buf->refcount = 1;
buf->ptr.owner = NULL;
buf->ptr.next = NULL;
packet->packet.bytes = ref->length;
}
+static inline void
+gst_ogg_packet_wrapper_unmap (ogg_packet_wrapper * packet,
+ GstBuffer * buffer)
+{
+ ogg_reference *ref = &packet->ref;
+ ogg_buffer *buf = &packet->buf;
+
+ gst_buffer_unmap (buffer, buf->data, buf->size);
+}
+
static inline ogg_packet *
gst_ogg_packet_from_wrapper (ogg_packet_wrapper * packet)
{
GstStateChange transition);
static void gst_vorbis_enc_add_interfaces (GType vorbisenc_type);
-GST_BOILERPLATE_FULL (GstVorbisEnc, gst_vorbis_enc, GstElement,
- GST_TYPE_ELEMENT, gst_vorbis_enc_add_interfaces);
+#define gst_vorbis_enc_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstVorbisEnc, gst_vorbis_enc,
+ GST_TYPE_ELEMENT, gst_vorbis_enc_add_interfaces (g_define_type_id));
static void
gst_vorbis_enc_add_interfaces (GType vorbisenc_type)
}
static void
-gst_vorbis_enc_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
- GstPadTemplate *src_template, *sink_template;
-
-
- src_template = gst_static_pad_template_get (&vorbis_enc_src_factory);
- gst_element_class_add_pad_template (element_class, src_template);
-
- sink_template = gst_static_pad_template_get (&vorbis_enc_sink_factory);
- gst_element_class_add_pad_template (element_class, sink_template);
- gst_element_class_set_details_simple (element_class,
- "Vorbis audio encoder", "Codec/Encoder/Audio",
- "Encodes audio in Vorbis format",
- "Monty <monty@xiph.org>, " "Wim Taymans <wim@fluendo.com>");
-}
-
-static void
gst_vorbis_enc_class_init (GstVorbisEncClass * klass)
{
GObjectClass *gobject_class;
"The last status message", NULL,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&vorbis_enc_src_factory));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&vorbis_enc_sink_factory));
+ gst_element_class_set_details_simple (gstelement_class,
+ "Vorbis audio encoder", "Codec/Encoder/Audio",
+ "Encodes audio in Vorbis format",
+ "Monty <monty@xiph.org>, " "Wim Taymans <wim@fluendo.com>");
+
gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_vorbis_enc_change_state);
}
}
static GstCaps *
-gst_vorbis_enc_sink_getcaps (GstPad * pad)
+gst_vorbis_enc_sink_getcaps (GstPad * pad, GstCaps * filter)
{
GstVorbisEnc *vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad));
if (vorbisenc->sinkcaps == NULL)
vorbisenc->sinkcaps = gst_vorbis_enc_generate_sink_caps ();
- return gst_caps_ref (vorbisenc->sinkcaps);
+ if (filter)
+ return gst_caps_intersect_full (filter, vorbisenc->sinkcaps,
+ GST_CAPS_INTERSECT_FIRST);
+ else
+ return gst_caps_ref (vorbisenc->sinkcaps);
}
static gboolean
}
static void
-gst_vorbis_enc_init (GstVorbisEnc * vorbisenc, GstVorbisEncClass * klass)
+gst_vorbis_enc_init (GstVorbisEnc * vorbisenc)
{
vorbisenc->sinkpad =
gst_pad_new_from_static_template (&vorbis_enc_sink_factory, "sink");
GstBuffer *outbuf;
outbuf = gst_buffer_new_and_alloc (packet->bytes);
- memcpy (GST_BUFFER_DATA (outbuf), packet->packet, packet->bytes);
+ gst_buffer_fill (outbuf, 0, packet->packet, packet->bytes);
/* see ext/ogg/README; OFFSET_END takes "our" granulepos, OFFSET its
* time representation */
GST_BUFFER_OFFSET_END (outbuf) = packet->granulepos +
/* update the next timestamp, taking granulepos_offset and subgranule offset
* into account */
vorbisenc->next_ts =
- granulepos_to_timestamp_offset (vorbisenc, packet->granulepos) +
- vorbisenc->initial_ts;
+ granulepos_to_timestamp_offset (vorbisenc, packet->granulepos);
GST_BUFFER_DURATION (outbuf) =
vorbisenc->next_ts - GST_BUFFER_TIMESTAMP (outbuf);
vorbisenc->next_discont = FALSE;
}
- gst_buffer_set_caps (outbuf, vorbisenc->srccaps);
-
GST_LOG_OBJECT (vorbisenc, "encoded buffer of %d bytes",
- GST_BUFFER_SIZE (outbuf));
+ gst_buffer_get_size (outbuf));
return outbuf;
}
GstBuffer *outbuf;
outbuf = gst_buffer_new_and_alloc (packet->bytes);
- memcpy (GST_BUFFER_DATA (outbuf), packet->packet, packet->bytes);
+ gst_buffer_fill (outbuf, 0, packet->packet, packet->bytes);
GST_BUFFER_OFFSET (outbuf) = vorbisenc->bytes_out;
GST_BUFFER_OFFSET_END (outbuf) = 0;
GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
- gst_buffer_set_caps (outbuf, vorbisenc->srccaps);
-
GST_DEBUG ("created header packet buffer, %d bytes",
- GST_BUFFER_SIZE (outbuf));
+ gst_buffer_get_size (outbuf));
return outbuf;
}
static GstFlowReturn
gst_vorbis_enc_push_buffer (GstVorbisEnc * vorbisenc, GstBuffer * buffer)
{
- vorbisenc->bytes_out += GST_BUFFER_SIZE (buffer);
+ vorbisenc->bytes_out += gst_buffer_get_size (buffer);
GST_DEBUG_OBJECT (vorbisenc,
"Pushing buffer with GP %" G_GINT64_FORMAT ", ts %" GST_TIME_FORMAT,
}
res = gst_pad_push_event (vorbisenc->srcpad, event);
break;
- case GST_EVENT_NEWSEGMENT:
+ case GST_EVENT_SEGMENT:
{
- gboolean update;
- gdouble rate, applied_rate;
- GstFormat format;
- gint64 start, stop, position;
-
- gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
- &format, &start, &stop, &position);
- if (format == GST_FORMAT_TIME) {
- gst_segment_set_newsegment (&vorbisenc->segment, update, rate, format,
- start, stop, position);
- if (vorbisenc->initial_ts == GST_CLOCK_TIME_NONE) {
- GST_DEBUG_OBJECT (vorbisenc, "Initial segment %" GST_SEGMENT_FORMAT,
- &vorbisenc->segment);
- vorbisenc->initial_ts = start;
- }
+ const GstSegment *segment;
+
+ gst_event_parse_segment (event, &segment);
+
+ if (segment->format == GST_FORMAT_TIME) {
+ gst_segment_copy_into (segment, &vorbisenc->segment);
}
}
/* fall through */
{
gboolean ret = FALSE;
+ GST_DEBUG_OBJECT (vorbisenc, "exp %" GST_TIME_FORMAT " time %" GST_TIME_FORMAT
+ "dur %" GST_TIME_FORMAT, GST_TIME_ARGS (vorbisenc->expected_ts),
+ GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration));
+
if (timestamp != GST_CLOCK_TIME_NONE &&
vorbisenc->expected_ts != GST_CLOCK_TIME_NONE &&
timestamp + duration != vorbisenc->expected_ts) {
{
GstVorbisEnc *vorbisenc;
GstFlowReturn ret = GST_FLOW_OK;
- gfloat *data;
+ gfloat *data, *ptr;
gulong size;
gulong i, j;
float **vorbis_buffer;
gboolean first = FALSE;
GstClockTime timestamp = GST_CLOCK_TIME_NONE;
GstClockTime running_time = GST_CLOCK_TIME_NONE;
+ gsize bsize;
vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad));
running_time =
gst_segment_to_running_time (&vorbisenc->segment, GST_FORMAT_TIME,
GST_BUFFER_TIMESTAMP (buffer));
- timestamp = running_time + vorbisenc->initial_ts;
- GST_DEBUG_OBJECT (vorbisenc, "Initial ts is %" GST_TIME_FORMAT,
- GST_TIME_ARGS (vorbisenc->initial_ts));
+ timestamp = running_time;
+ GST_DEBUG_OBJECT (vorbisenc, " timestamp %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (timestamp));
if (!vorbisenc->header_sent) {
/* Vorbis streams begin with three headers; the initial header (with
most of the codec setup parameters) which is mandated by the Ogg
GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
gst_pad_set_caps (vorbisenc->srcpad, caps);
- gst_buffer_set_caps (buf1, caps);
- gst_buffer_set_caps (buf2, caps);
- gst_buffer_set_caps (buf3, caps);
-
/* push out buffers */
/* push_buffer takes the reference even for failure */
if ((ret = gst_vorbis_enc_push_buffer (vorbisenc, buf1)) != GST_FLOW_OK)
(running_time, vorbisenc->frequency, GST_SECOND);
vorbisenc->subgranule_offset = 0;
vorbisenc->subgranule_offset =
- (vorbisenc->next_ts - vorbisenc->initial_ts) -
- granulepos_to_timestamp_offset (vorbisenc, 0);
+ vorbisenc->next_ts - granulepos_to_timestamp_offset (vorbisenc, 0);
vorbisenc->header_sent = TRUE;
first = TRUE;
timestamp < vorbisenc->expected_ts) {
guint64 diff = vorbisenc->expected_ts - timestamp;
guint64 diff_bytes;
+ gsize size;
GST_WARNING_OBJECT (vorbisenc, "Buffer is older than previous "
"timestamp + duration (%" GST_TIME_FORMAT "< %" GST_TIME_FORMAT
"), cannot handle. Clipping buffer.",
GST_TIME_ARGS (timestamp), GST_TIME_ARGS (vorbisenc->expected_ts));
+ size = gst_buffer_get_size (buffer);
+
diff_bytes =
GST_CLOCK_TIME_TO_FRAMES (diff,
vorbisenc->frequency) * vorbisenc->channels * sizeof (gfloat);
- if (diff_bytes >= GST_BUFFER_SIZE (buffer)) {
+ if (diff_bytes >= size) {
gst_buffer_unref (buffer);
return GST_FLOW_OK;
}
- buffer = gst_buffer_make_metadata_writable (buffer);
- GST_BUFFER_DATA (buffer) += diff_bytes;
- GST_BUFFER_SIZE (buffer) -= diff_bytes;
+ buffer = gst_buffer_make_writable (buffer);
+ gst_buffer_resize (buffer, diff_bytes, size - diff_bytes);
GST_BUFFER_TIMESTAMP (buffer) += diff;
if (GST_BUFFER_DURATION_IS_VALID (buffer))
}
/* Sending zero samples to libvorbis marks EOS, so we mustn't do that */
- if (GST_BUFFER_SIZE (buffer) == 0) {
+ data = gst_buffer_map (buffer, &bsize, NULL, GST_MAP_WRITE);
+ if (bsize == 0) {
+ gst_buffer_unmap (buffer, data, bsize);
gst_buffer_unref (buffer);
return GST_FLOW_OK;
}
/* data to encode */
- data = (gfloat *) GST_BUFFER_DATA (buffer);
- size = GST_BUFFER_SIZE (buffer) / (vorbisenc->channels * sizeof (float));
+ size = bsize / (vorbisenc->channels * sizeof (float));
+
+ ptr = data;
/* expose the buffer to submit data */
vorbis_buffer = vorbis_analysis_buffer (&vorbisenc->vd, size);
/* deinterleave samples, write the buffer data */
for (i = 0; i < size; i++) {
for (j = 0; j < vorbisenc->channels; j++) {
- vorbis_buffer[j][i] = *data++;
+ vorbis_buffer[j][i] = *ptr++;
}
}
/* tell the library how much we actually submitted */
vorbis_analysis_wrote (&vorbisenc->vd, size);
+ gst_buffer_unmap (buffer, data, bsize);
GST_LOG_OBJECT (vorbisenc, "wrote %lu samples to vorbis", size);
vorbisenc->next_discont = FALSE;
vorbisenc->header_sent = FALSE;
gst_segment_init (&vorbisenc->segment, GST_FORMAT_TIME);
- vorbisenc->initial_ts = GST_CLOCK_TIME_NONE;
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
break;
guint64 granulepos_offset;
gint64 subgranule_offset;
GstSegment segment;
- GstClockTime initial_ts;
GstTagList * tags;
GST_STATIC_CAPS ("audio/x-vorbis")
);
-GST_BOILERPLATE (GstVorbisParse, gst_vorbis_parse, GstElement,
- GST_TYPE_ELEMENT);
+#define gst_vorbis_parse_parent_class parent_class
+G_DEFINE_TYPE (GstVorbisParse, gst_vorbis_parse, GST_TYPE_ELEMENT);
static GstFlowReturn vorbis_parse_chain (GstPad * pad, GstBuffer * buffer);
static GstStateChangeReturn vorbis_parse_change_state (GstElement * element,
GstBuffer * buf);
static void
-gst_vorbis_parse_base_init (gpointer g_class)
+gst_vorbis_parse_class_init (GstVorbisParseClass * klass)
{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+ GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+
+ gstelement_class->change_state = vorbis_parse_change_state;
- gst_element_class_add_pad_template (element_class,
+ gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&vorbis_parse_src_factory));
- gst_element_class_add_pad_template (element_class,
+ gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&vorbis_parse_sink_factory));
- gst_element_class_set_details_simple (element_class,
+ gst_element_class_set_details_simple (gstelement_class,
"VorbisParse", "Codec/Parser/Audio",
"parse raw vorbis streams",
"Thomas Vander Stichele <thomas at apestaart dot org>");
-}
-
-static void
-gst_vorbis_parse_class_init (GstVorbisParseClass * klass)
-{
- GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
-
- gstelement_class->change_state = vorbis_parse_change_state;
klass->parse_packet = GST_DEBUG_FUNCPTR (vorbis_parse_parse_packet);
}
static void
-gst_vorbis_parse_init (GstVorbisParse * parse, GstVorbisParseClass * g_class)
+gst_vorbis_parse_init (GstVorbisParse * parse)
{
parse->sinkpad =
gst_pad_new_from_static_template (&vorbis_parse_sink_factory, "sink");
GstCaps *caps;
GstBuffer *outbuf, *outbuf1, *outbuf2, *outbuf3;
ogg_packet packet;
+ gsize size;
/* get the headers into the caps, passing them to vorbis as we go */
- caps = gst_caps_make_writable (gst_pad_get_caps (parse->srcpad));
+ caps = gst_caps_make_writable (gst_pad_get_caps (parse->srcpad, NULL));
vorbis_parse_set_header_on_caps (parse, caps);
GST_DEBUG_OBJECT (parse, "here are the caps: %" GST_PTR_FORMAT, caps);
gst_pad_set_caps (parse->srcpad, caps);
gst_caps_unref (caps);
outbuf = GST_BUFFER_CAST (parse->streamheader->data);
- packet.packet = GST_BUFFER_DATA (outbuf);
- packet.bytes = GST_BUFFER_SIZE (outbuf);
+ packet.packet = gst_buffer_map (outbuf, &size, NULL, GST_MAP_READ);
+ packet.bytes = size;
packet.granulepos = GST_BUFFER_OFFSET_END (outbuf);
packet.packetno = 1;
packet.e_o_s = 0;
packet.b_o_s = 1;
vorbis_synthesis_headerin (&parse->vi, &parse->vc, &packet);
+ gst_buffer_unmap (outbuf, packet.packet, size);
parse->sample_rate = parse->vi.rate;
outbuf1 = outbuf;
outbuf = GST_BUFFER_CAST (parse->streamheader->next->data);
- packet.packet = GST_BUFFER_DATA (outbuf);
- packet.bytes = GST_BUFFER_SIZE (outbuf);
+ packet.packet = gst_buffer_map (outbuf, &size, NULL, GST_MAP_READ);
+ packet.bytes = size;
packet.granulepos = GST_BUFFER_OFFSET_END (outbuf);
packet.packetno = 2;
packet.e_o_s = 0;
packet.b_o_s = 0;
vorbis_synthesis_headerin (&parse->vi, &parse->vc, &packet);
+ gst_buffer_unmap (outbuf, packet.packet, size);
outbuf2 = outbuf;
outbuf = GST_BUFFER_CAST (parse->streamheader->next->next->data);
- packet.packet = GST_BUFFER_DATA (outbuf);
- packet.bytes = GST_BUFFER_SIZE (outbuf);
+ packet.packet = gst_buffer_map (outbuf, &size, NULL, GST_MAP_READ);
+ packet.bytes = size;
packet.granulepos = GST_BUFFER_OFFSET_END (outbuf);
packet.packetno = 3;
packet.e_o_s = 0;
packet.b_o_s = 0;
vorbis_synthesis_headerin (&parse->vi, &parse->vc, &packet);
+ gst_buffer_unmap (outbuf, packet.packet, size);
outbuf3 = outbuf;
/* first process queued events */
vorbis_parse_drain_event_queue (parse);
/* push out buffers, ignoring return value... */
- outbuf1 = gst_buffer_make_metadata_writable (outbuf1);
- gst_buffer_set_caps (outbuf1, GST_PAD_CAPS (parse->srcpad));
gst_pad_push (parse->srcpad, outbuf1);
- outbuf2 = gst_buffer_make_metadata_writable (outbuf2);
- gst_buffer_set_caps (outbuf2, GST_PAD_CAPS (parse->srcpad));
gst_pad_push (parse->srcpad, outbuf2);
- outbuf3 = gst_buffer_make_metadata_writable (outbuf3);
- gst_buffer_set_caps (outbuf3, GST_PAD_CAPS (parse->srcpad));
gst_pad_push (parse->srcpad, outbuf3);
g_list_free (parse->streamheader);
GST_BUFFER_TIMESTAMP (buf) =
GST_BUFFER_OFFSET (buf) - GST_BUFFER_DURATION (buf);
- gst_buffer_set_caps (buf, GST_PAD_CAPS (parse->srcpad));
-
return gst_pad_push (parse->srcpad, buf);
}
GstFlowReturn ret = GST_FLOW_OK;
long blocksize;
ogg_packet packet;
+ gsize size;
- buf = gst_buffer_make_metadata_writable (buf);
+ buf = gst_buffer_make_writable (buf);
- packet.packet = GST_BUFFER_DATA (buf);
- packet.bytes = GST_BUFFER_SIZE (buf);
+ packet.packet = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
+ packet.bytes = size;
packet.granulepos = GST_BUFFER_OFFSET_END (buf);
packet.packetno = parse->packetno + parse->buffer_queue->length;
packet.e_o_s = 0;
blocksize = vorbis_packet_blocksize (&parse->vi, &packet);
+ gst_buffer_unmap (buf, packet.packet, size);
/* temporarily store the sample count in OFFSET -- we overwrite this later */
{
GstFlowReturn ret;
guint8 *data;
- guint size;
+ gsize size;
gboolean have_header;
- data = GST_BUFFER_DATA (buf);
- size = GST_BUFFER_SIZE (buf);
-
parse->packetno++;
have_header = FALSE;
+ data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
if (size >= 1) {
if (data[0] >= 0x01 && data[0] <= 0x05)
have_header = TRUE;
}
+ gst_buffer_unmap (buf, data, size);
if (have_header) {
if (!parse->streamheader_sent) {
break;
}
- ret = parent_class->change_state (element, transition);
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_READY:
static GstFlowReturn gst_vorbis_tag_parse_packet (GstVorbisParse * parse,
GstBuffer * buffer);
-#define _do_init(type) \
- G_STMT_START{ \
- static const GInterfaceInfo tag_setter_info = { \
- NULL, \
- NULL, \
- NULL \
- }; \
- g_type_add_interface_static (type, GST_TYPE_TAG_SETTER, \
- &tag_setter_info); \
- }G_STMT_END
-
-GST_BOILERPLATE_FULL (GstVorbisTag, gst_vorbis_tag, GstVorbisParse,
- GST_TYPE_VORBIS_PARSE, _do_init);
-
+#define gst_vorbis_tag_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstVorbisTag, gst_vorbis_tag,
+ GST_TYPE_VORBIS_PARSE, G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL));
static void
-gst_vorbis_tag_base_init (gpointer g_class)
+gst_vorbis_tag_class_init (GstVorbisTagClass * klass)
{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+ GstVorbisParseClass *vorbisparse_class = GST_VORBIS_PARSE_CLASS (klass);
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
gst_element_class_set_details_simple (element_class,
"VorbisTag", "Formatter/Metadata",
"Retags vorbis streams", "James Livingston <doclivingston@gmail.com>");
-}
-
-static void
-gst_vorbis_tag_class_init (GstVorbisTagClass * klass)
-{
- GstVorbisParseClass *vorbisparse_class = GST_VORBIS_PARSE_CLASS (klass);
vorbisparse_class->parse_packet = gst_vorbis_tag_parse_packet;
}
static void
-gst_vorbis_tag_init (GstVorbisTag * tagger, GstVorbisTagClass * g_class)
+gst_vorbis_tag_init (GstVorbisTag * tagger)
{
/* nothing to do */
}
GstVorbisTag *tagger;
gchar *encoder = NULL;
GstBuffer *new_buf;
+ guint8 *data;
+ gsize size;
+ gboolean do_parse = FALSE;
+ data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
/* just pass everything except the comments packet */
- if (GST_BUFFER_SIZE (buffer) >= 1 && GST_BUFFER_DATA (buffer)[0] != 0x03) {
+ if (size >= 1 && data[0] != 0x03)
+ do_parse = TRUE;
+ gst_buffer_unmap (buffer, data, size);
+
+ if (do_parse) {
return GST_VORBIS_PARSE_CLASS (parent_class)->parse_packet (parse, buffer);
}
new_buf =
gst_tag_list_to_vorbiscomment_buffer (new_tags, (guint8 *) "\003vorbis",
7, encoder);
- gst_buffer_copy_metadata (new_buf, buffer, GST_BUFFER_COPY_TIMESTAMPS);
+ gst_buffer_copy_into (new_buf, buffer, GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
gst_tag_list_free (new_tags);
g_free (encoder);
nodist_libgstapp_@GST_MAJORMINOR@_la_SOURCES = \
$(built_sources)
-libgstapp_@GST_MAJORMINOR@_la_SOURCES = gstappsrc.c gstappbuffer.c gstappsink.c
+libgstapp_@GST_MAJORMINOR@_la_SOURCES = gstappsrc.c gstappsink.c
libgstapp_@GST_MAJORMINOR@_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) \
$(GST_BASE_CFLAGS) $(GST_CFLAGS)
libgstapp_@GST_MAJORMINOR@_la_LIBADD = $(GST_BASE_LIBS)
libgstapp_@GST_MAJORMINOR@includedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/app
libgstapp_@GST_MAJORMINOR@include_HEADERS = \
gstappsrc.h \
- gstappbuffer.h \
gstappsink.h
CLEANFILES = $(BUILT_SOURCES)
+++ /dev/null
-/* GStreamer
- * Copyright (C) 2007 David Schleef <ds@schleef.org>
- *
- * 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/gst.h>
-#include <gst/base/gstpushsrc.h>
-
-#include <string.h>
-
-#include "gstappbuffer.h"
-
-static void gst_app_buffer_init (GstAppBuffer * buffer, gpointer g_class);
-static void gst_app_buffer_class_init (gpointer g_class, gpointer class_data);
-static void gst_app_buffer_finalize (GstAppBuffer * buffer);
-
-static GstBufferClass *parent_class;
-
-GType
-gst_app_buffer_get_type (void)
-{
- static volatile gsize app_buffer_type = 0;
-
- if (g_once_init_enter (&app_buffer_type)) {
- static const GTypeInfo app_buffer_info = {
- sizeof (GstBufferClass),
- NULL,
- NULL,
- gst_app_buffer_class_init,
- NULL,
- NULL,
- sizeof (GstAppBuffer),
- 0,
- (GInstanceInitFunc) gst_app_buffer_init,
- NULL
- };
- GType tmp = g_type_register_static (GST_TYPE_BUFFER, "GstAppBuffer",
- &app_buffer_info, 0);
- g_once_init_leave (&app_buffer_type, tmp);
- }
-
- return (GType) app_buffer_type;
-}
-
-static void
-gst_app_buffer_init (GstAppBuffer * buffer, gpointer g_class)
-{
-
-}
-
-static void
-gst_app_buffer_class_init (gpointer g_class, gpointer class_data)
-{
- GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
-
- mini_object_class->finalize =
- (GstMiniObjectFinalizeFunction) gst_app_buffer_finalize;
-
- parent_class = g_type_class_peek_parent (g_class);
-}
-
-static void
-gst_app_buffer_finalize (GstAppBuffer * buffer)
-{
- g_return_if_fail (buffer != NULL);
- g_return_if_fail (GST_IS_APP_BUFFER (buffer));
-
- if (buffer->finalize) {
- buffer->finalize (buffer->priv);
- }
-
- GST_MINI_OBJECT_CLASS (parent_class)->finalize (GST_MINI_OBJECT (buffer));
-}
-
-GstBuffer *
-gst_app_buffer_new (void *data, int length,
- GstAppBufferFinalizeFunc finalize, void *priv)
-{
- GstAppBuffer *buffer;
-
- buffer = (GstAppBuffer *) gst_mini_object_new (GST_TYPE_APP_BUFFER);
-
- GST_BUFFER_DATA (buffer) = data;
- GST_BUFFER_SIZE (buffer) = length;
-
- buffer->finalize = finalize;
- buffer->priv = priv;
-
- return GST_BUFFER (buffer);
-}
+++ /dev/null
-/* GStreamer
- * Copyright (C) 2007 David Schleef <ds@schleef.org>
- *
- * 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_APP_BUFFER_H_
-#define _GST_APP_BUFFER_H_
-
-#include <gst/gst.h>
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_APP_BUFFER \
- (gst_app_buffer_get_type())
-#define GST_APP_BUFFER(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_APP_BUFFER,GstAppBuffer))
-#define GST_APP_BUFFER_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_APP_BUFFER,GstAppBufferClass))
-#define GST_IS_APP_BUFFER(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_APP_BUFFER))
-#define GST_IS_APP_BUFFER_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_APP_BUFFER))
-
-typedef struct _GstAppBuffer GstAppBuffer;
-typedef struct _GstAppBufferClass GstAppBufferClass;
-typedef void (*GstAppBufferFinalizeFunc) (void *priv);
-
-struct _GstAppBuffer
-{
- GstBuffer buffer;
-
- /*< private >*/
- GstAppBufferFinalizeFunc finalize;
- void *priv;
-};
-
-struct _GstAppBufferClass
-{
- GstBufferClass buffer_class;
-};
-
-GType gst_app_buffer_get_type(void);
-
-GstBuffer *gst_app_buffer_new (void *data, int length,
- GstAppBufferFinalizeFunc finalize, void *priv);
-
-G_END_DECLS
-
-#endif
-
GstBuffer * buffer);
static GstFlowReturn gst_app_sink_render_list (GstBaseSink * psink,
GstBufferList * list);
-static GstCaps *gst_app_sink_getcaps (GstBaseSink * psink);
+static GstCaps *gst_app_sink_getcaps (GstBaseSink * psink, GstCaps * filter);
static GstMiniObject *gst_app_sink_pull_object (GstAppSink * appsink);
static guint gst_app_sink_signals[LAST_SIGNAL] = { 0 };
-static void
-_do_init (GType filesrc_type)
-{
- static const GInterfaceInfo urihandler_info = {
- gst_app_sink_uri_handler_init,
- NULL,
- NULL
- };
- g_type_add_interface_static (filesrc_type, GST_TYPE_URI_HANDLER,
- &urihandler_info);
-}
-
-GST_BOILERPLATE_FULL (GstAppSink, gst_app_sink, GstBaseSink, GST_TYPE_BASE_SINK,
- _do_init);
+#define gst_app_sink_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstAppSink, gst_app_sink, GST_TYPE_BASE_SINK,
+ G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER,
+ gst_app_sink_uri_handler_init));
/* Can't use glib-genmarshal for this, as it doesn't know how to handle
* GstMiniObject-based types, which are a new fundamental type */
}
static void
-gst_app_sink_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- GST_DEBUG_CATEGORY_INIT (app_sink_debug, "appsink", 0, "appsink element");
-
- gst_element_class_set_details_simple (element_class, "AppSink",
- "Generic/Sink", "Allow the application to get access to raw buffer",
- "David Schleef <ds@schleef.org>, Wim Taymans <wim.taymans@gmail.com>");
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&gst_app_sink_template));
-}
-
-static void
gst_app_sink_class_init (GstAppSinkClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
+ GstElementClass *element_class = (GstElementClass *) klass;
GstBaseSinkClass *basesink_class = (GstBaseSinkClass *) klass;
+ GST_DEBUG_CATEGORY_INIT (app_sink_debug, "appsink", 0, "appsink element");
+
gobject_class->dispose = gst_app_sink_dispose;
gobject_class->finalize = gst_app_sink_finalize;
pull_buffer_list), NULL, NULL, gst_app_marshal_BUFFER__VOID,
GST_TYPE_BUFFER_LIST, 0, G_TYPE_NONE);
+ gst_element_class_set_details_simple (element_class, "AppSink",
+ "Generic/Sink", "Allow the application to get access to raw buffer",
+ "David Schleef <ds@schleef.org>, Wim Taymans <wim.taymans@gmail.com>");
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_app_sink_template));
+
basesink_class->unlock = gst_app_sink_unlock_start;
basesink_class->unlock_stop = gst_app_sink_unlock_stop;
basesink_class->start = gst_app_sink_start;
}
static void
-gst_app_sink_init (GstAppSink * appsink, GstAppSinkClass * klass)
+gst_app_sink_init (GstAppSink * appsink)
{
GstAppSinkPrivate *priv;
static GstFlowReturn
gst_app_sink_render_list (GstBaseSink * sink, GstBufferList * list)
{
- GstBufferListIterator *it;
GstFlowReturn flow;
GstAppSink *appsink;
- GstBuffer *group;
+ GstBuffer *buffer;
+ guint i, len;
appsink = GST_APP_SINK_CAST (sink);
* then and push them one-by-one */
GST_INFO_OBJECT (sink, "chaining each group in list as a merged buffer");
- it = gst_buffer_list_iterate (list);
+ len = gst_buffer_list_len (list);
- if (gst_buffer_list_iterator_next_group (it)) {
- do {
- group = gst_buffer_list_iterator_merge_group (it);
- if (group == NULL) {
- group = gst_buffer_new ();
- GST_DEBUG_OBJECT (sink, "chaining empty group");
- } else {
- GST_DEBUG_OBJECT (sink, "chaining group");
- }
- flow = gst_app_sink_render (sink, group);
- gst_buffer_unref (group);
- } while (flow == GST_FLOW_OK && gst_buffer_list_iterator_next_group (it));
- } else {
- GST_DEBUG_OBJECT (sink, "chaining empty group");
- group = gst_buffer_new ();
- flow = gst_app_sink_render (sink, group);
- gst_buffer_unref (group);
+ flow = GST_FLOW_OK;
+ for (i = 0; i < len; i++) {
+ buffer = gst_buffer_list_get (list, i);
+ flow = gst_app_sink_render (sink, buffer);
+ if (flow != GST_FLOW_OK)
+ break;
}
- gst_buffer_list_iterator_free (it);
-
return flow;
}
static GstCaps *
-gst_app_sink_getcaps (GstBaseSink * psink)
+gst_app_sink_getcaps (GstBaseSink * psink, GstCaps * filter)
{
GstCaps *caps;
GstAppSink *appsink = GST_APP_SINK_CAST (psink);
GstAppSinkPrivate *priv = appsink->priv;
GST_OBJECT_LOCK (appsink);
- if ((caps = priv->caps))
- gst_caps_ref (caps);
+ if ((caps = priv->caps)) {
+ if (filter)
+ caps = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+ else
+ gst_caps_ref (caps);
+ }
GST_DEBUG_OBJECT (appsink, "got caps %" GST_PTR_FORMAT, caps);
GST_OBJECT_UNLOCK (appsink);
static gboolean gst_app_src_unlock_stop (GstBaseSrc * bsrc);
static gboolean gst_app_src_do_seek (GstBaseSrc * src, GstSegment * segment);
static gboolean gst_app_src_is_seekable (GstBaseSrc * src);
-static gboolean gst_app_src_check_get_range (GstBaseSrc * src);
static gboolean gst_app_src_do_get_size (GstBaseSrc * src, guint64 * size);
static gboolean gst_app_src_query (GstBaseSrc * src, GstQuery * query);
static guint gst_app_src_signals[LAST_SIGNAL] = { 0 };
-static void
-_do_init (GType filesrc_type)
-{
- static const GInterfaceInfo urihandler_info = {
- gst_app_src_uri_handler_init,
- NULL,
- NULL
- };
- g_type_add_interface_static (filesrc_type, GST_TYPE_URI_HANDLER,
- &urihandler_info);
-}
-
-GST_BOILERPLATE_FULL (GstAppSrc, gst_app_src, GstBaseSrc, GST_TYPE_BASE_SRC,
- _do_init);
-
-static void
-gst_app_src_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- GST_DEBUG_CATEGORY_INIT (app_src_debug, "appsrc", 0, "appsrc element");
-
- gst_element_class_set_details_simple (element_class, "AppSrc",
- "Generic/Source", "Allow the application to feed buffers to a pipeline",
- "David Schleef <ds@schleef.org>, Wim Taymans <wim.taymans@gmail.com>");
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&gst_app_src_template));
-}
+#define gst_app_src_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstAppSrc, gst_app_src, GST_TYPE_BASE_SRC,
+ G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER, gst_app_src_uri_handler_init));
static void
gst_app_src_class_init (GstAppSrcClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
+ GstElementClass *element_class = (GstElementClass *) klass;
GstBaseSrcClass *basesrc_class = (GstBaseSrcClass *) klass;
+ GST_DEBUG_CATEGORY_INIT (app_src_debug, "appsrc", 0, "appsrc element");
+
gobject_class->dispose = gst_app_src_dispose;
gobject_class->finalize = gst_app_src_finalize;
end_of_stream), NULL, NULL, __gst_app_marshal_ENUM__VOID,
GST_TYPE_FLOW_RETURN, 0, G_TYPE_NONE);
+ gst_element_class_set_details_simple (element_class, "AppSrc",
+ "Generic/Source", "Allow the application to feed buffers to a pipeline",
+ "David Schleef <ds@schleef.org>, Wim Taymans <wim.taymans@gmail.com>");
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_app_src_template));
+
basesrc_class->create = gst_app_src_create;
basesrc_class->start = gst_app_src_start;
basesrc_class->stop = gst_app_src_stop;
basesrc_class->unlock_stop = gst_app_src_unlock_stop;
basesrc_class->do_seek = gst_app_src_do_seek;
basesrc_class->is_seekable = gst_app_src_is_seekable;
- basesrc_class->check_get_range = gst_app_src_check_get_range;
basesrc_class->get_size = gst_app_src_do_get_size;
basesrc_class->get_size = gst_app_src_do_get_size;
basesrc_class->query = gst_app_src_query;
}
static void
-gst_app_src_init (GstAppSrc * appsrc, GstAppSrcClass * klass)
+gst_app_src_init (GstAppSrc * appsrc)
{
GstAppSrcPrivate *priv;
}
static gboolean
-gst_app_src_check_get_range (GstBaseSrc * src)
-{
- GstAppSrc *appsrc = GST_APP_SRC_CAST (src);
- GstAppSrcPrivate *priv = appsrc->priv;
- gboolean res = FALSE;
-
- switch (priv->stream_type) {
- case GST_APP_STREAM_TYPE_STREAM:
- case GST_APP_STREAM_TYPE_SEEKABLE:
- break;
- case GST_APP_STREAM_TYPE_RANDOM_ACCESS:
- res = TRUE;
- break;
- }
- return res;
-}
-
-static gboolean
gst_app_src_do_get_size (GstBaseSrc * src, guint64 * size)
{
GstAppSrc *appsrc = GST_APP_SRC_CAST (src);
gst_query_set_latency (query, live, min, max);
break;
}
+ case GST_QUERY_SCHEDULING:
+ {
+ gboolean pull_mode = FALSE;
+
+ switch (priv->stream_type) {
+ case GST_APP_STREAM_TYPE_STREAM:
+ case GST_APP_STREAM_TYPE_SEEKABLE:
+ break;
+ case GST_APP_STREAM_TYPE_RANDOM_ACCESS:
+ pull_mode = TRUE;
+ break;
+ }
+ gst_query_set_scheduling (query, pull_mode, TRUE, FALSE, 1, -1, 1);
+ res = TRUE;
+ break;
+ }
default:
res = GST_BASE_SRC_CLASS (parent_class)->query (src, query);
break;
gint64 desired_position;
gboolean res = FALSE;
- desired_position = segment->last_stop;
+ desired_position = segment->position;
GST_DEBUG_OBJECT (appsrc, "seeking to %" G_GINT64_FORMAT ", format %s",
desired_position, gst_format_get_name (segment->format));
GST_DEBUG_OBJECT (appsrc,
"Size changed from %" G_GINT64_FORMAT " to %" G_GINT64_FORMAT,
bsrc->segment.duration, priv->size);
- gst_segment_set_duration (&bsrc->segment, GST_FORMAT_BYTES, priv->size);
+ bsrc->segment.duration = priv->size;
GST_OBJECT_UNLOCK (appsrc);
gst_element_post_message (GST_ELEMENT (appsrc),
guint buf_size;
*buf = g_queue_pop_head (priv->queue);
- buf_size = GST_BUFFER_SIZE (*buf);
+ buf_size = gst_buffer_get_size (*buf);
GST_DEBUG_OBJECT (appsrc, "we have buffer %p of size %u", *buf, buf_size);
/* only update the offset when in random_access mode */
if (priv->stream_type == GST_APP_STREAM_TYPE_RANDOM_ACCESS)
priv->offset += buf_size;
- if (caps) {
- *buf = gst_buffer_make_metadata_writable (*buf);
- gst_buffer_set_caps (*buf, caps);
- }
/* signal that we removed an item */
g_cond_broadcast (priv->cond);
if (!steal_ref)
gst_buffer_ref (buffer);
g_queue_push_tail (priv->queue, buffer);
- priv->queued_bytes += GST_BUFFER_SIZE (buffer);
+ priv->queued_bytes += gst_buffer_get_size (buffer);
g_cond_broadcast (priv->cond);
g_mutex_unlock (priv->mutex);
int width = 0;
int channels = 0;
- const GstCaps *caps = NULL;
+ GstCaps *caps;
GstStructure *structure;
/* get caps of pad */
- caps = GST_PAD_CAPS (pad);
+ caps = gst_pad_get_current_caps (pad);
- if (caps == NULL) {
- /* ERROR: could not get caps of pad */
- g_warning ("gstaudio: could not get caps of pad %s:%s\n",
- GST_DEBUG_PAD_NAME (pad));
- return 0;
- }
+ if (caps == NULL)
+ goto no_caps;
structure = gst_caps_get_structure (caps, 0);
gst_structure_get_int (structure, "width", &width);
gst_structure_get_int (structure, "channels", &channels);
+ gst_caps_unref (caps);
+
return (width / 8) * channels;
+
+ /* ERRORS */
+no_caps:
+ {
+ /* ERROR: could not get caps of pad */
+ g_warning ("gstaudio: could not get caps of pad %s:%s\n",
+ GST_DEBUG_PAD_NAME (pad));
+ return 0;
+ }
}
/**
/* FIXME: this function assumes the buffer size to be a whole multiple
* of the frame byte size
*/
- return GST_BUFFER_SIZE (buf) / frame_byte_size;
+ return gst_buffer_get_size (buf) / frame_byte_size;
}
/**
int width = 0;
int channels = 0;
int rate = 0;
-
- GstClockTime length;
-
- const GstCaps *caps = NULL;
+ GstCaps *caps;
GstStructure *structure;
g_assert (GST_IS_BUFFER (buf));
+
/* get caps of pad */
- caps = GST_PAD_CAPS (pad);
- if (caps == NULL) {
+ caps = gst_pad_get_current_caps (pad);
+ if (caps == NULL)
+ goto no_caps;
+
+ structure = gst_caps_get_structure (caps, 0);
+ bytes = gst_buffer_get_size (buf);
+ gst_structure_get_int (structure, "width", &width);
+ gst_structure_get_int (structure, "channels", &channels);
+ gst_structure_get_int (structure, "rate", &rate);
+ gst_caps_unref (caps);
+
+ g_assert (bytes != 0);
+ g_assert (width != 0);
+ g_assert (channels != 0);
+ g_assert (rate != 0);
+
+ return (bytes * 8 * GST_SECOND) / (rate * channels * width);
+
+ /* ERRORS */
+no_caps:
+ {
/* ERROR: could not get caps of pad */
g_warning ("gstaudio: could not get caps of pad %s:%s\n",
GST_DEBUG_PAD_NAME (pad));
- length = GST_CLOCK_TIME_NONE;
- } else {
- structure = gst_caps_get_structure (caps, 0);
- bytes = GST_BUFFER_SIZE (buf);
- gst_structure_get_int (structure, "width", &width);
- gst_structure_get_int (structure, "channels", &channels);
- gst_structure_get_int (structure, "rate", &rate);
-
- g_assert (bytes != 0);
- g_assert (width != 0);
- g_assert (channels != 0);
- g_assert (rate != 0);
- length = (bytes * 8 * GST_SECOND) / (rate * channels * width);
+ return GST_CLOCK_TIME_NONE;
}
- return length;
}
/**
gboolean
gst_audio_is_buffer_framed (GstPad * pad, GstBuffer * buf)
{
- if (GST_BUFFER_SIZE (buf) % gst_audio_frame_byte_size (pad) == 0)
+ if (gst_buffer_get_size (buf) % gst_audio_frame_byte_size (pad) == 0)
return TRUE;
else
return FALSE;
GstBuffer *ret;
GstClockTime timestamp = GST_CLOCK_TIME_NONE, duration = GST_CLOCK_TIME_NONE;
guint64 offset = GST_BUFFER_OFFSET_NONE, offset_end = GST_BUFFER_OFFSET_NONE;
- guint8 *data;
- guint size;
-
+ gsize trim, size;
gboolean change_duration = TRUE, change_offset = TRUE, change_offset_end =
TRUE;
* Calculate the missing values for the calculations,
* they won't be changed later though. */
- data = GST_BUFFER_DATA (buffer);
- size = GST_BUFFER_SIZE (buffer);
+ trim = 0;
+ size = gst_buffer_get_size (buffer);
timestamp = GST_BUFFER_TIMESTAMP (buffer);
+ GST_DEBUG ("timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp));
if (GST_BUFFER_DURATION_IS_VALID (buffer)) {
duration = GST_BUFFER_DURATION (buffer);
} else {
if (segment->format == GST_FORMAT_TIME) {
/* Handle clipping for GST_FORMAT_TIME */
- gint64 start, stop, cstart, cstop, diff;
+ guint64 start, stop, cstart, cstop, diff;
start = timestamp;
stop = timestamp + duration;
diff = gst_util_uint64_scale (diff, rate, GST_SECOND);
if (change_offset)
offset += diff;
- data += diff * frame_size;
+ trim += diff * frame_size;
size -= diff * frame_size;
}
}
} else {
/* Handle clipping for GST_FORMAT_DEFAULT */
- gint64 start, stop, cstart, cstop, diff;
+ guint64 start, stop, cstart, cstop, diff;
g_return_val_if_fail (GST_BUFFER_OFFSET_IS_VALID (buffer), buffer);
if (change_duration)
duration -= gst_util_uint64_scale (diff, GST_SECOND, rate);
- data += diff * frame_size;
+ trim += diff * frame_size;
size -= diff * frame_size;
}
}
}
- /* Get a metadata writable buffer and apply all changes */
- ret = gst_buffer_make_metadata_writable (buffer);
+ /* Get a writable buffer and apply all changes */
+ GST_DEBUG ("trim %" G_GSIZE_FORMAT " size %" G_GSIZE_FORMAT, trim, size);
+ ret = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, trim, size);
+ gst_buffer_unref (buffer);
+ GST_DEBUG ("timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp));
GST_BUFFER_TIMESTAMP (ret) = timestamp;
- GST_BUFFER_SIZE (ret) = size;
- GST_BUFFER_DATA (ret) = data;
if (change_duration)
GST_BUFFER_DURATION (ret) = duration;
* #GstAudioFilter will parse the input format for you (with error checking)
* before calling your setup function. Also, elements deriving from
* #GstAudioFilter may use gst_audio_filter_class_add_pad_templates() from
- * their base_init function to easily configure the set of caps/formats that
+ * their class_init function to easily configure the set of caps/formats that
* the element is able to handle.
*
* Derived classes should override the #GstAudioFilterClass.setup() and
static gboolean gst_audio_filter_set_caps (GstBaseTransform * btrans,
GstCaps * incaps, GstCaps * outcaps);
static gboolean gst_audio_filter_get_unit_size (GstBaseTransform * btrans,
- GstCaps * caps, guint * size);
+ GstCaps * caps, gsize * size);
#define do_init G_STMT_START { \
GST_DEBUG_CATEGORY_INIT (audiofilter_dbg, "audiofilter", 0, "audiofilter"); \
static gboolean
gst_audio_filter_get_unit_size (GstBaseTransform * btrans, GstCaps * caps,
- guint * size)
+ gsize * size)
{
GstStructure *structure;
gboolean ret = TRUE;
* Convenience function to add pad templates to this element class, with
* @allowed_caps as the caps that can be handled.
*
- * This function is usually used from within a GObject base_init function.
+ * This function is usually used from within a GObject class_init function.
*
* Since: 0.10.12
*/
void
gst_audio_filter_class_add_pad_templates (GstAudioFilterClass * klass,
- const GstCaps * allowed_caps)
+ GstCaps * allowed_caps)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
GstPadTemplate *pad_template;
g_return_if_fail (GST_IS_CAPS (allowed_caps));
pad_template = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
- gst_caps_copy (allowed_caps));
+ allowed_caps);
gst_element_class_add_pad_template (element_class, pad_template);
- gst_object_unref (pad_template);
pad_template = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
- gst_caps_copy (allowed_caps));
+ allowed_caps);
gst_element_class_add_pad_template (element_class, pad_template);
- gst_object_unref (pad_template);
}
GType gst_audio_filter_get_type (void);
void gst_audio_filter_class_add_pad_templates (GstAudioFilterClass * klass,
- const GstCaps * allowed_caps);
+ GstCaps * allowed_caps);
G_END_DECLS
/* set latency to one more segment as we need some headroom */
spec->seglatency = spec->segtotal + 1;
- buf->data = gst_buffer_new_and_alloc (spec->segtotal * spec->segsize);
- memset (GST_BUFFER_DATA (buf->data), 0, GST_BUFFER_SIZE (buf->data));
+ buf->size = spec->segtotal * spec->segsize;
+ buf->memory = g_malloc0 (buf->size);
return TRUE;
csink = GST_AUDIO_SINK_GET_CLASS (sink);
/* free the buffer */
- gst_buffer_unref (buf->data);
- buf->data = NULL;
+ g_free (buf->memory);
+ buf->memory = NULL;
if (csink->unprepare)
result = csink->unprepare (sink);
ARG_0,
};
-#define _do_init(bla) \
+#define _do_init \
GST_DEBUG_CATEGORY_INIT (gst_audio_sink_debug, "audiosink", 0, "audiosink element");
-
-GST_BOILERPLATE_FULL (GstAudioSink, gst_audio_sink, GstBaseAudioSink,
+#define gst_audio_sink_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstAudioSink, gst_audio_sink,
GST_TYPE_BASE_AUDIO_SINK, _do_init);
static GstRingBuffer *gst_audio_sink_create_ringbuffer (GstBaseAudioSink *
sink);
static void
-gst_audio_sink_base_init (gpointer g_class)
-{
-}
-
-static void
gst_audio_sink_class_init (GstAudioSinkClass * klass)
{
GstBaseAudioSinkClass *gstbaseaudiosink_class;
}
static void
-gst_audio_sink_init (GstAudioSink * audiosink, GstAudioSinkClass * g_class)
+gst_audio_sink_init (GstAudioSink * audiosink)
{
}
if (!result)
goto could_not_open;
- buf->data = gst_buffer_new_and_alloc (spec->segtotal * spec->segsize);
- memset (GST_BUFFER_DATA (buf->data), 0, GST_BUFFER_SIZE (buf->data));
+ buf->size = spec->segtotal * spec->segsize;
+ buf->memory = g_malloc0 (buf->size);
abuf = GST_AUDIORING_BUFFER (buf);
abuf->running = TRUE;
GST_OBJECT_LOCK (buf);
/* free the buffer */
- gst_buffer_unref (buf->data);
- buf->data = NULL;
+ g_free (buf->memory);
+ buf->memory = NULL;
if (csrc->unprepare)
result = csrc->unprepare (src);
ARG_0,
};
-#define _do_init(bla) \
+#define _do_init \
GST_DEBUG_CATEGORY_INIT (gst_audio_src_debug, "audiosrc", 0, "audiosrc element");
-
-GST_BOILERPLATE_FULL (GstAudioSrc, gst_audio_src, GstBaseAudioSrc,
+#define gst_audio_src_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstAudioSrc, gst_audio_src,
GST_TYPE_BASE_AUDIO_SRC, _do_init);
static GstRingBuffer *gst_audio_src_create_ringbuffer (GstBaseAudioSrc * src);
static void
-gst_audio_src_base_init (gpointer g_class)
-{
-}
-
-static void
gst_audio_src_class_init (GstAudioSrcClass * klass)
{
GstBaseAudioSrcClass *gstbaseaudiosrc_class;
}
static void
-gst_audio_src_init (GstAudioSrc * audiosrc, GstAudioSrcClass * g_class)
+gst_audio_src_init (GstAudioSrc * audiosrc)
{
}
GstClockTime eos_time;
- gboolean do_time_offset;
/* number of microseconds we alow timestamps or clock slaving to drift
* before resyncing */
guint64 drift_tolerance;
}
-#define _do_init(bla) \
+#define _do_init \
GST_DEBUG_CATEGORY_INIT (gst_base_audio_sink_debug, "baseaudiosink", 0, "baseaudiosink element");
-
-GST_BOILERPLATE_FULL (GstBaseAudioSink, gst_base_audio_sink, GstBaseSink,
+#define gst_base_audio_sink_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstBaseAudioSink, gst_base_audio_sink,
GST_TYPE_BASE_SINK, _do_init);
static void gst_base_audio_sink_dispose (GObject * object);
static void gst_base_audio_sink_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
+#if 0
static GstStateChangeReturn gst_base_audio_sink_async_play (GstBaseSink *
basesink);
+#endif
static GstStateChangeReturn gst_base_audio_sink_change_state (GstElement *
element, GstStateChange transition);
static gboolean gst_base_audio_sink_activate_pull (GstBaseSink * basesink,
/* static guint gst_base_audio_sink_signals[LAST_SIGNAL] = { 0 }; */
static void
-gst_base_audio_sink_base_init (gpointer g_class)
-{
-}
-
-static void
gst_base_audio_sink_class_init (GstBaseAudioSinkClass * klass)
{
GObjectClass *gobject_class;
GST_DEBUG_FUNCPTR (gst_base_audio_sink_get_times);
gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_base_audio_sink_setcaps);
gstbasesink_class->fixate = GST_DEBUG_FUNCPTR (gst_base_audio_sink_fixate);
+#if 0
gstbasesink_class->async_play =
GST_DEBUG_FUNCPTR (gst_base_audio_sink_async_play);
+#endif
gstbasesink_class->activate_pull =
GST_DEBUG_FUNCPTR (gst_base_audio_sink_activate_pull);
}
static void
-gst_base_audio_sink_init (GstBaseAudioSink * baseaudiosink,
- GstBaseAudioSinkClass * g_class)
+gst_base_audio_sink_init (GstBaseAudioSink * baseaudiosink)
{
- GstPluginFeature *feature;
GstBaseSink *basesink;
baseaudiosink->priv = GST_BASE_AUDIO_SINK_GET_PRIVATE (baseaudiosink);
/* install some custom pad_query functions */
gst_pad_set_query_function (GST_BASE_SINK_PAD (baseaudiosink),
GST_DEBUG_FUNCPTR (gst_base_audio_sink_query_pad));
-
- baseaudiosink->priv->do_time_offset = TRUE;
-
- /* check the factory, pulsesink < 0.10.17 does the timestamp offset itself so
- * we should not do ourselves */
- feature =
- GST_PLUGIN_FEATURE_CAST (GST_ELEMENT_CLASS (g_class)->elementfactory);
- GST_DEBUG ("created from factory %p", feature);
-
- /* HACK for old pulsesink that did the time_offset themselves */
- if (feature) {
- if (strcmp (gst_plugin_feature_get_name (feature), "pulsesink") == 0) {
- if (!gst_plugin_feature_check_version (feature, 0, 10, 17)) {
- /* we're dealing with an old pulsesink, we need to disable time corection */
- GST_DEBUG ("disable time offset");
- baseaudiosink->priv->do_time_offset = FALSE;
- }
- }
- }
}
static void
GST_DEBUG_OBJECT (sink, "release old ringbuffer");
- /* get current time, updates the last_time */
+ /* get current time, updates the last_time. When the subclass has a clock that
+ * restarts from 0 when a new format is negotiated, it will call
+ * gst_audio_clock_reset() which will use this last_time to create an offset
+ * so that time from the clock keeps on increasing monotonically. */
now = gst_clock_get_time (sink->provided_clock);
GST_DEBUG_OBJECT (sink, "time was %" GST_TIME_FORMAT, GST_TIME_ARGS (now));
/* now wait till we played everything */
gst_base_audio_sink_drain (sink);
break;
- case GST_EVENT_NEWSEGMENT:
- {
- gdouble rate;
-
- /* we only need the rate */
- gst_event_parse_new_segment_full (event, NULL, &rate, NULL, NULL,
- NULL, NULL, NULL);
-
- GST_DEBUG_OBJECT (sink, "new segment rate of %f", rate);
- break;
- }
default:
break;
}
G_GINT64_FORMAT, align, maxdrift);
} else {
/* calculate sample diff in seconds for error message */
- gint64 diff_s = gst_util_uint64_scale_int (diff, GST_SECOND,
- ringbuf->spec.rate);
+ gint64 diff_s =
+ gst_util_uint64_scale_int (diff, GST_SECOND, ringbuf->spec.rate);
/* timestamps drifted apart from previous samples too much, we need to
* resync. We log this as an element warning. */
GST_WARNING_OBJECT (sink,
GstBaseAudioSinkClass *bclass;
GstBaseAudioSink *sink;
GstRingBuffer *ringbuf;
- gint64 diff, align, ctime, cstop;
+ gint64 diff, align;
+ guint64 ctime, cstop;
+ gsize offset;
guint8 *data;
- guint size;
+ gsize size;
guint samples, written;
gint bps;
gint accum;
bps = ringbuf->spec.bytes_per_sample;
- size = GST_BUFFER_SIZE (buf);
+ size = gst_buffer_get_size (buf);
if (G_UNLIKELY (size % bps) != 0)
goto wrong_size;
GST_TIME_FORMAT ", samples %u", GST_TIME_ARGS (time), in_offset,
GST_TIME_ARGS (bsink->segment.start), samples);
- data = GST_BUFFER_DATA (buf);
+ offset = 0;
/* if not valid timestamp or we can't clip or sync, try to play
* sample ASAP */
render_stop = render_start + samples;
GST_DEBUG_OBJECT (sink,
"Buffer of size %u has no time. Using render_start=%" G_GUINT64_FORMAT,
- GST_BUFFER_SIZE (buf), render_start);
+ size, render_start);
/* we don't have a start so we don't know stop either */
stop = -1;
goto no_sync;
GST_DEBUG_OBJECT (sink, "clipping start to %" GST_TIME_FORMAT " %"
G_GUINT64_FORMAT " samples", GST_TIME_ARGS (ctime), diff);
samples -= diff;
- data += diff * bps;
+ offset += diff * bps;
time = ctime;
}
diff = stop - cstop;
GST_TIME_ARGS (render_start), GST_TIME_ARGS (render_stop));
/* bring to position in the ringbuffer */
- if (sink->priv->do_time_offset) {
- time_offset =
- GST_AUDIO_CLOCK_CAST (sink->provided_clock)->abidata.ABI.time_offset;
- GST_DEBUG_OBJECT (sink,
- "time offset %" GST_TIME_FORMAT, GST_TIME_ARGS (time_offset));
- if (render_start > time_offset)
- render_start -= time_offset;
- else
- render_start = 0;
- if (render_stop > time_offset)
- render_stop -= time_offset;
- else
- render_stop = 0;
- }
+ time_offset =
+ GST_AUDIO_CLOCK_CAST (sink->provided_clock)->abidata.ABI.time_offset;
+ GST_DEBUG_OBJECT (sink,
+ "time offset %" GST_TIME_FORMAT, GST_TIME_ARGS (time_offset));
+ if (render_start > time_offset)
+ render_start -= time_offset;
+ else
+ render_start = 0;
+ if (render_stop > time_offset)
+ render_stop -= time_offset;
+ else
+ render_stop = 0;
/* and bring the time to the rate corrected offset in the buffer */
render_start = gst_util_uint64_scale_int (render_start,
/* we need to accumulate over different runs for when we get interrupted */
accum = 0;
align_next = TRUE;
+ data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
do {
written =
- gst_ring_buffer_commit_full (ringbuf, &sample_offset, data, samples,
- out_samples, &accum);
+ gst_ring_buffer_commit_full (ringbuf, &sample_offset, data + offset,
+ samples, out_samples, &accum);
GST_DEBUG_OBJECT (sink, "wrote %u of %u", written, samples);
/* if we wrote all, we're done */
break;
samples -= written;
- data += written * bps;
+ offset += written * bps;
} while (TRUE);
+ gst_buffer_unmap (buf, data, size);
if (align_next)
sink->next_sample = sample_offset;
{
GST_DEBUG_OBJECT (sink, "preroll got interrupted: %d (%s)", ret,
gst_flow_get_name (ret));
+ gst_buffer_unmap (buf, data, size);
goto done;
}
sync_latency_failed:
GstBaseAudioSink *sink;
GstBuffer *buf;
GstFlowReturn ret;
+ gsize size;
basesink = GST_BASE_SINK (user_data);
sink = GST_BASE_AUDIO_SINK (user_data);
GST_LOG_OBJECT (basesink, "pulling %d bytes offset %" G_GUINT64_FORMAT
" to fill audio buffer", len, basesink->offset);
ret =
- gst_pad_pull_range (basesink->sinkpad, basesink->segment.last_stop, len,
+ gst_pad_pull_range (basesink->sinkpad, basesink->segment.position, len,
&buf);
if (ret != GST_FLOW_OK) {
goto error;
}
- GST_PAD_PREROLL_LOCK (basesink->sinkpad);
+ GST_BASE_SINK_PREROLL_LOCK (basesink);
if (basesink->flushing)
goto flushing;
if (ret != GST_FLOW_OK)
goto preroll_error;
- if (len != GST_BUFFER_SIZE (buf)) {
+ size = gst_buffer_get_size (buf);
+
+ if (len != size) {
GST_INFO_OBJECT (basesink,
- "got different size than requested from sink pad: %u != %u", len,
- GST_BUFFER_SIZE (buf));
- len = MIN (GST_BUFFER_SIZE (buf), len);
+ "got different size than requested from sink pad: %u != %u", len, size);
+ len = MIN (size, len);
}
- basesink->segment.last_stop += len;
+ basesink->segment.position += len;
- memcpy (data, GST_BUFFER_DATA (buf), len);
- GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
+ gst_buffer_extract (buf, 0, data, len);
+ GST_BASE_SINK_PREROLL_UNLOCK (basesink);
GST_PAD_STREAM_UNLOCK (basesink->sinkpad);
{
GST_DEBUG_OBJECT (sink, "we are flushing");
gst_ring_buffer_pause (rbuf);
- GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
+ GST_BASE_SINK_PREROLL_UNLOCK (basesink);
GST_PAD_STREAM_UNLOCK (basesink->sinkpad);
return;
}
{
GST_DEBUG_OBJECT (sink, "error %s", gst_flow_get_name (ret));
gst_ring_buffer_pause (rbuf);
- GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
+ GST_BASE_SINK_PREROLL_UNLOCK (basesink);
GST_PAD_STREAM_UNLOCK (basesink->sinkpad);
return;
}
return ret;
}
+#if 0
/* should be called with the LOCK */
static GstStateChangeReturn
gst_base_audio_sink_async_play (GstBaseSink * basesink)
return GST_STATE_CHANGE_SUCCESS;
}
+#endif
static GstStateChangeReturn
gst_base_audio_sink_change_state (GstElement * element,
#endif /* ENABLE_NLS */
}
-GST_BOILERPLATE_FULL (GstBaseAudioSrc, gst_base_audio_src, GstPushSrc,
- GST_TYPE_PUSH_SRC, _do_init);
+#define gst_base_audio_src_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstBaseAudioSrc, gst_base_audio_src, GST_TYPE_PUSH_SRC,
+ _do_init (g_define_type_id));
static void gst_base_audio_src_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static GstFlowReturn gst_base_audio_src_create (GstBaseSrc * bsrc,
guint64 offset, guint length, GstBuffer ** buf);
-static gboolean gst_base_audio_src_check_get_range (GstBaseSrc * bsrc);
static gboolean gst_base_audio_src_event (GstBaseSrc * bsrc, GstEvent * event);
static void gst_base_audio_src_get_times (GstBaseSrc * bsrc,
/* static guint gst_base_audio_src_signals[LAST_SIGNAL] = { 0 }; */
static void
-gst_base_audio_src_base_init (gpointer g_class)
-{
-}
-
-static void
gst_base_audio_src_class_init (GstBaseAudioSrcClass * klass)
{
GObjectClass *gobject_class;
gstbasesrc_class->get_times =
GST_DEBUG_FUNCPTR (gst_base_audio_src_get_times);
gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_base_audio_src_create);
- gstbasesrc_class->check_get_range =
- GST_DEBUG_FUNCPTR (gst_base_audio_src_check_get_range);
gstbasesrc_class->fixate = GST_DEBUG_FUNCPTR (gst_base_audio_src_fixate);
/* ref class from a thread-safe context to work around missing bit of
}
static void
-gst_base_audio_src_init (GstBaseAudioSrc * baseaudiosrc,
- GstBaseAudioSrcClass * g_class)
+gst_base_audio_src_init (GstBaseAudioSrc * baseaudiosrc)
{
baseaudiosrc->priv = GST_BASE_AUDIO_SRC_GET_PRIVATE (baseaudiosrc);
return result;
}
-static gboolean
-gst_base_audio_src_check_get_range (GstBaseSrc * bsrc)
-{
- /* we allow limited pull base operation of which the details
- * will eventually exposed in an as of yet non-existing query.
- * Basically pulling can be done on any number of bytes as long
- * as the offset is -1 or sequentially increasing. */
- return TRUE;
-}
-
/**
* gst_base_audio_src_set_provide_clock:
* @src: a #GstBaseAudioSrc
spec->latency_time = src->latency_time;
GST_OBJECT_LOCK (src);
- if (!gst_ring_buffer_parse_caps (spec, caps))
- {
+ if (!gst_ring_buffer_parse_caps (spec, caps)) {
GST_OBJECT_UNLOCK (src);
goto parse_error;
}
res = TRUE;
break;
}
+ case GST_QUERY_SCHEDULING:
+ {
+ /* we allow limited pull base operation of which the details
+ * will eventually exposed in an as of yet non-existing query.
+ * Basically pulling can be done on any number of bytes as long
+ * as the offset is -1 or sequentially increasing. */
+ gst_query_set_scheduling (query, TRUE, FALSE, TRUE, 1, -1, 1);
+
+ res = TRUE;
+ break;
+ }
default:
res = GST_BASE_SRC_CLASS (parent_class)->query (bsrc, query);
break;
{
GstBaseAudioSrc *src = GST_BASE_AUDIO_SRC (bsrc);
GstBuffer *buf;
- guchar *data;
+ guchar *data, *ptr;
guint samples, total_samples;
guint64 sample;
gint bps;
/* FIXME, using a bufferpool would be nice here */
buf = gst_buffer_new_and_alloc (length);
- data = GST_BUFFER_DATA (buf);
-
+ data = ptr = gst_buffer_map (buf, NULL, NULL, GST_MAP_WRITE);
do {
- read = gst_ring_buffer_read (ringbuffer, sample, data, samples);
+ read = gst_ring_buffer_read (ringbuffer, sample, ptr, samples);
GST_DEBUG_OBJECT (src, "read %u of %u", read, samples);
/* if we read all, we're done */
if (read == samples)
/* read next samples */
sample += read;
samples -= read;
- data += read * bps;
+ ptr += read * bps;
} while (TRUE);
+ gst_buffer_unmap (buf, data, length);
/* mark discontinuity if needed */
if (G_UNLIKELY (sample != src->next_sample) && src->next_sample != -1) {
gint inr, outr;
gboolean reverse;
- g_return_val_if_fail (buf->data != NULL, -1);
+ g_return_val_if_fail (buf->memory != NULL, -1);
g_return_val_if_fail (data != NULL, -1);
- dest = GST_BUFFER_DATA (buf->data);
+ dest = buf->memory;
segsize = buf->spec.segsize;
segtotal = buf->spec.segtotal;
bps = buf->spec.bytes_per_sample;
guint to_read;
g_return_val_if_fail (GST_IS_RING_BUFFER (buf), -1);
- g_return_val_if_fail (buf->data != NULL, -1);
+ g_return_val_if_fail (buf->memory != NULL, -1);
g_return_val_if_fail (data != NULL, -1);
- dest = GST_BUFFER_DATA (buf->data);
+ dest = buf->memory;
segsize = buf->spec.segsize;
segtotal = buf->spec.segtotal;
bps = buf->spec.bytes_per_sample;
return FALSE;
}
- g_return_val_if_fail (buf->data != NULL, FALSE);
+ g_return_val_if_fail (buf->memory != NULL, FALSE);
g_return_val_if_fail (segment != NULL, FALSE);
g_return_val_if_fail (readptr != NULL, FALSE);
g_return_val_if_fail (len != NULL, FALSE);
- data = GST_BUFFER_DATA (buf->data);
+ data = buf->memory;
/* get the position of the pointer */
segdone = g_atomic_int_get (&buf->segdone);
g_return_if_fail (GST_IS_RING_BUFFER (buf));
/* no data means it's already cleared */
- if (G_UNLIKELY (buf->data == NULL))
+ if (G_UNLIKELY (buf->memory == NULL))
return;
/* no empty_seg means it's not opened */
segment %= buf->spec.segtotal;
- data = GST_BUFFER_DATA (buf->data);
+ data = buf->memory;
data += segment * buf->spec.segsize;
GST_LOG ("clear segment %d @%p", segment, data);
GCond *cond;
gboolean open;
gboolean acquired;
- GstBuffer *data;
+ guint8 *memory;
+ gsize size;
GstRingBufferSpec spec;
GstRingBufferSegState *segstate;
gint samples_per_seg;
/* make order chosen in the end more determinable */
if (rank_a == rank_b) {
- const gchar *name_a = GST_PLUGIN_FEATURE_NAME (GST_PLUGIN_FEATURE (a));
- const gchar *name_b = GST_PLUGIN_FEATURE_NAME (GST_PLUGIN_FEATURE (b));
+ const gchar *name_a = GST_OBJECT_NAME (GST_PLUGIN_FEATURE (a));
+ const gchar *name_b = GST_OBJECT_NAME (GST_PLUGIN_FEATURE (b));
return g_ascii_strcasecmp (name_a, name_b);
}
ARG_TOC_BIAS
};
+static void gst_cdda_base_src_uri_handler_init (gpointer g_iface,
+ gpointer iface_data);
static void gst_cdda_base_src_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_cdda_base_src_set_property (GObject * object, guint prop_id,
GstEvent * event);
static gboolean gst_cdda_base_src_do_seek (GstBaseSrc * basesrc,
GstSegment * segment);
-static void gst_cdda_base_src_setup_interfaces (GType type);
static gboolean gst_cdda_base_src_start (GstBaseSrc * basesrc);
static gboolean gst_cdda_base_src_stop (GstBaseSrc * basesrc);
static GstFlowReturn gst_cdda_base_src_create (GstPushSrc * pushsrc,
static void gst_cdda_base_src_set_index (GstElement * src, GstIndex * index);
static GstIndex *gst_cdda_base_src_get_index (GstElement * src);
-GST_BOILERPLATE_FULL (GstCddaBaseSrc, gst_cdda_base_src, GstPushSrc,
- GST_TYPE_PUSH_SRC, gst_cdda_base_src_setup_interfaces);
+#define gst_cdda_base_src_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstCddaBaseSrc, gst_cdda_base_src, GST_TYPE_PUSH_SRC,
+ G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER,
+ gst_cdda_base_src_uri_handler_init));
#define SRC_CAPS \
"audio/x-raw-int, " \
}
static void
-gst_cdda_base_src_base_init (gpointer g_class)
+gst_cdda_base_src_class_init (GstCddaBaseSrcClass * klass)
{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+ GstElementClass *element_class;
+ GstPushSrcClass *pushsrc_class;
+ GstBaseSrcClass *basesrc_class;
+ GObjectClass *gobject_class;
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&gst_cdda_base_src_src_template));
+ gobject_class = (GObjectClass *) klass;
+ element_class = (GstElementClass *) klass;
+ basesrc_class = (GstBaseSrcClass *) klass;
+ pushsrc_class = (GstPushSrcClass *) klass;
+
+ GST_DEBUG_CATEGORY_INIT (gst_cdda_base_src_debug, "cddabasesrc", 0,
+ "CDDA Base Source");
/* our very own formats */
track_format = gst_format_register ("track", "CD track");
gst_tag_register (GST_TAG_CDDA_TRACK_TAGS, GST_TAG_FLAG_META, GST_TYPE_TAG_LIST, "track-tags", "CDDA taglist for one track", gst_tag_merge_use_first); ///////////// FIXME: right function??? ///////
#endif
- GST_DEBUG_CATEGORY_INIT (gst_cdda_base_src_debug, "cddabasesrc", 0,
- "CDDA Base Source");
-}
-
-static void
-gst_cdda_base_src_class_init (GstCddaBaseSrcClass * klass)
-{
- GstElementClass *element_class;
- GstPushSrcClass *pushsrc_class;
- GstBaseSrcClass *basesrc_class;
- GObjectClass *gobject_class;
-
- gobject_class = (GObjectClass *) klass;
- element_class = (GstElementClass *) klass;
- basesrc_class = (GstBaseSrcClass *) klass;
- pushsrc_class = (GstPushSrcClass *) klass;
-
gobject_class->set_property = gst_cdda_base_src_set_property;
gobject_class->get_property = gst_cdda_base_src_get_property;
gobject_class->finalize = gst_cdda_base_src_finalize;
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
#endif
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_cdda_base_src_src_template));
+
element_class->set_index = GST_DEBUG_FUNCPTR (gst_cdda_base_src_set_index);
element_class->get_index = GST_DEBUG_FUNCPTR (gst_cdda_base_src_get_index);
}
static void
-gst_cdda_base_src_init (GstCddaBaseSrc * src, GstCddaBaseSrcClass * klass)
+gst_cdda_base_src_init (GstCddaBaseSrc * src)
{
gst_pad_set_query_type_function (GST_BASE_SRC_PAD (src),
GST_DEBUG_FUNCPTR (gst_cdda_base_src_get_query_types));
iface->get_protocols = gst_cdda_base_src_uri_get_protocols;
}
-static void
-gst_cdda_base_src_setup_interfaces (GType type)
-{
- static const GInterfaceInfo urihandler_info = {
- gst_cdda_base_src_uri_handler_init,
- NULL,
- NULL,
- };
-
- g_type_add_interface_static (type, GST_TYPE_URI_HANDLER, &urihandler_info);
-}
-
/**
* gst_cdda_base_src_add_track:
* @src: a #GstCddaBaseSrc
basesrc = GST_BASE_SRC (src);
format = GST_FORMAT_TIME;
- if (gst_pad_query_duration (GST_BASE_SRC_PAD (src), &format, &duration)) {
- gst_segment_set_duration (&basesrc->segment, GST_FORMAT_TIME, duration);
- } else {
- gst_segment_set_duration (&basesrc->segment, GST_FORMAT_TIME, -1);
+ if (!gst_pad_query_duration (GST_BASE_SRC_PAD (src), &format, &duration)) {
duration = GST_CLOCK_TIME_NONE;
}
+ basesrc->segment.duration = duration;
gst_element_post_message (GST_ELEMENT (src),
gst_message_new_duration (GST_OBJECT (src), GST_FORMAT_TIME, -1));
return GST_FLOW_ERROR;
}
- if (GST_BUFFER_CAPS (buf) == NULL) {
- gst_buffer_set_caps (buf, GST_PAD_CAPS (GST_BASE_SRC_PAD (src)));
- }
-
format = GST_FORMAT_TIME;
if (gst_pad_query_position (GST_BASE_SRC_PAD (src), &format, &qry_position)) {
gint64 next_ts = 0;
/* fallback duration: 4 bytes per sample, 44100 samples per second */
if (duration == GST_CLOCK_TIME_NONE) {
- duration = gst_util_uint64_scale_int (GST_BUFFER_SIZE (buf) >> 2,
+ duration = gst_util_uint64_scale_int (gst_buffer_get_size (buf) >> 2,
GST_SECOND, 44100);
}
structure = gst_structure_new (GST_NAVIGATION_QUERY_NAME,
"type", G_TYPE_STRING, "commands", NULL);
- query = gst_query_new_application (GST_QUERY_CUSTOM, structure);
+ query = gst_query_new_custom (GST_QUERY_CUSTOM, structure);
return query;
}
}
va_end (ap);
- structure = gst_query_get_structure (query);
+ structure = gst_query_writable_structure (query);
gst_structure_set_value (structure, "commands", &list);
g_value_unset (&list);
for (i = 0; i < n_cmds; i++) {
gst_query_list_add_command (&list, cmds[i]);
}
- structure = gst_query_get_structure (query);
+ structure = gst_query_writable_structure (query);
gst_structure_set_value (structure, "commands", &list);
g_value_unset (&list);
gboolean
gst_navigation_query_parse_commands_length (GstQuery * query, guint * n_cmds)
{
- GstStructure *structure;
+ const GstStructure *structure;
const GValue *list;
g_return_val_if_fail (GST_NAVIGATION_QUERY_HAS_TYPE (query, COMMANDS), FALSE);
gst_navigation_query_parse_commands_nth (GstQuery * query, guint nth,
GstNavigationCommand * cmd)
{
- GstStructure *structure;
+ const GstStructure *structure;
const GValue *list;
g_return_val_if_fail (GST_NAVIGATION_QUERY_HAS_TYPE (query, COMMANDS), FALSE);
structure = gst_structure_new (GST_NAVIGATION_QUERY_NAME,
"type", G_TYPE_STRING, "angles", NULL);
- query = gst_query_new_application (GST_QUERY_CUSTOM, structure);
+ query = gst_query_new_custom (GST_QUERY_CUSTOM, structure);
return query;
}
g_return_if_fail (GST_NAVIGATION_QUERY_HAS_TYPE (query, ANGLES));
- structure = gst_query_get_structure (query);
+ structure = gst_query_writable_structure (query);
gst_structure_set (structure,
"angle", G_TYPE_UINT, cur_angle, "angles", G_TYPE_UINT, n_angles, NULL);
}
gst_navigation_query_parse_angles (GstQuery * query, guint * cur_angle,
guint * n_angles)
{
- GstStructure *structure;
+ const GstStructure *structure;
gboolean ret = TRUE;
g_return_val_if_fail (GST_NAVIGATION_QUERY_HAS_TYPE (query, ANGLES), FALSE);
#include "gstnetbuffer.h"
-static void gst_netbuffer_finalize (GstNetBuffer * nbuf);
-static GstNetBuffer *gst_netbuffer_copy (GstNetBuffer * nbuf);
-
-static GstBufferClass *parent_class;
-
-G_DEFINE_TYPE (GstNetBuffer, gst_netbuffer, GST_TYPE_BUFFER);
-
-static void
-gst_netbuffer_class_init (GstNetBufferClass * netbuffer_class)
-{
- GstMiniObjectClass *mo_class = GST_MINI_OBJECT_CLASS (netbuffer_class);
-
- parent_class = g_type_class_peek_parent (netbuffer_class);
-
- mo_class->copy = (GstMiniObjectCopyFunction) gst_netbuffer_copy;
- mo_class->finalize = (GstMiniObjectFinalizeFunction) gst_netbuffer_finalize;
-}
-
static void
-gst_netbuffer_init (GstNetBuffer * instance)
+meta_net_address_copy (GstBuffer * copybuf, GstMetaNetAddress * meta,
+ GstBuffer * buffer, gsize offset, gsize size)
{
-}
+ GstMetaNetAddress *naddr;
-static void
-gst_netbuffer_finalize (GstNetBuffer * nbuf)
-{
- GST_MINI_OBJECT_CLASS (parent_class)->finalize (GST_MINI_OBJECT (nbuf));
+ naddr = gst_buffer_add_meta_net_address (copybuf);
+ memcpy (&naddr->naddr, &meta->naddr, sizeof (meta->naddr));
}
-static GstNetBuffer *
-gst_netbuffer_copy (GstNetBuffer * nbuf)
+const GstMetaInfo *
+gst_meta_net_address_get_info (void)
{
- GstNetBuffer *copy;
-
- copy = gst_netbuffer_new ();
-
- /* we simply copy everything from our parent */
- GST_BUFFER_DATA (copy) =
- g_memdup (GST_BUFFER_DATA (nbuf), GST_BUFFER_SIZE (nbuf));
- /* make sure it gets freed (even if the parent is subclassed, we return a
- normal buffer) */
- GST_BUFFER_MALLOCDATA (copy) = GST_BUFFER_DATA (copy);
- GST_BUFFER_SIZE (copy) = GST_BUFFER_SIZE (nbuf);
-
- memcpy (©->to, &nbuf->to, sizeof (nbuf->to));
- memcpy (©->from, &nbuf->from, sizeof (nbuf->from));
-
- /* copy metadata */
- gst_buffer_copy_metadata (GST_BUFFER_CAST (copy),
- GST_BUFFER_CAST (nbuf), GST_BUFFER_COPY_ALL);
-
- return copy;
-}
-
-/**
- * gst_netbuffer_new:
- *
- * Create a new network buffer.
- *
- * Returns: a new #GstNetBuffer.
- */
-GstNetBuffer *
-gst_netbuffer_new (void)
-{
- GstNetBuffer *buf;
-
- buf = (GstNetBuffer *) gst_mini_object_new (GST_TYPE_NETBUFFER);
-
- return buf;
+ static const GstMetaInfo *meta_info = NULL;
+
+ if (meta_info == NULL) {
+ meta_info = gst_meta_register ("GstMetaNetAddress", "GstMetaNetAddress",
+ sizeof (GstMetaNetAddress),
+ (GstMetaInitFunction) NULL,
+ (GstMetaFreeFunction) NULL,
+ (GstMetaCopyFunction) meta_net_address_copy,
+ (GstMetaTransformFunction) NULL);
+ }
+ return meta_info;
}
/**
G_BEGIN_DECLS
+#if 0
typedef struct _GstNetBuffer GstNetBuffer;
typedef struct _GstNetBufferClass GstNetBufferClass;
+#endif
typedef struct _GstNetAddress GstNetAddress;
+#if 0
#define GST_TYPE_NETBUFFER (gst_netbuffer_get_type())
#define GST_IS_NETBUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_NETBUFFER))
#define GST_IS_NETBUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_NETBUFFER))
#define GST_NETBUFFER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_NETBUFFER, GstNetBufferClass))
#define GST_NETBUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_NETBUFFER, GstNetBuffer))
#define GST_NETBUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_NETBUFFER, GstNetBufferClass))
+#endif
/**
* GstNetType:
/**
* GstNetAddress:
*
- * An opaque network address as used in #GstNetBuffer.
+ * An opaque network address as used in #GstMetaNetAddress.
*/
struct _GstNetAddress {
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
};
+typedef struct _GstMetaNetAddress GstMetaNetAddress;
+
/**
- * GstNetBuffer:
- * @buffer: the parent #GstBuffer
- * @from: the address where this buffer came from.
- * @to: the address where this buffer should go to.
+ * GstMetaNetAddress:
*
- * buffer for use in network sources and sinks.
- * It contains the source or destination address of the buffer.
+ * Buffer metadata for network addresses.
*/
-struct _GstNetBuffer {
- GstBuffer buffer;
-
- GstNetAddress from;
- GstNetAddress to;
+struct _GstMetaNetAddress {
+ GstMeta meta;
- /*< private >*/
- gpointer _gst_reserved[GST_PADDING];
-};
-
-struct _GstNetBufferClass {
- GstBufferClass buffer_class;
-
- /*< private >*/
- gpointer _gst_reserved[GST_PADDING];
+ GstNetAddress naddr;
};
-/* creating buffers */
-GType gst_netbuffer_get_type (void);
+const GstMetaInfo *gst_meta_net_address_get_info (void);
+#define GST_META_NET_ADDRESS_INFO (gst_meta_net_address_get_info())
-GstNetBuffer* gst_netbuffer_new (void);
+#define gst_buffer_get_meta_net_address(b) \
+ ((GstMetaNetAddress*)gst_buffer_get_meta((b),GST_META_NET_ADDRESS_INFO))
+#define gst_buffer_add_meta_net_address(b) \
+ ((GstMetaNetAddress*)gst_buffer_add_meta((b),GST_META_NET_ADDRESS_INFO,NULL))
/* address operations */
void gst_netaddress_set_ip4_address (GstNetAddress *naddr, guint32 address, guint16 port);
struct _GstEncodingProfile
{
- GstMiniObject parent;
+ GObject parent;
/*< public > */
gchar *name;
static volatile gsize g_define_type_id__volatile = 0;
if (g_once_init_enter (&g_define_type_id__volatile)) {
- GType g_define_type_id =
- g_type_register_static_simple (GST_TYPE_MINI_OBJECT,
+ GType g_define_type_id = g_type_register_static_simple (G_TYPE_OBJECT,
g_intern_static_string ("GstEncodingProfile"),
sizeof (GstEncodingProfileClass),
(GClassInitFunc) gst_encoding_profile_class_intern_init,
}
static void
-gst_encoding_profile_finalize (GstEncodingProfile * prof)
+gst_encoding_profile_finalize (GObject * object)
{
+ GstEncodingProfile *prof = (GstEncodingProfile *) object;
if (prof->name)
g_free (prof->name);
if (prof->format)
}
static void
-gst_encoding_profile_class_init (GstMiniObjectClass * klass)
+gst_encoding_profile_class_init (GObjectClass * klass)
{
- klass->finalize =
- (GstMiniObjectFinalizeFunction) gst_encoding_profile_finalize;
+ klass->finalize = gst_encoding_profile_finalize;
}
/**
*
* Since: 0.10.32
*
- * Returns: the #GstCaps corresponding to the media format used in the profile.
+ * Returns: (transfer full): the #GstCaps corresponding to the media format used
+ * in the profile. Unref after usage.
*/
-const GstCaps *
+GstCaps *
gst_encoding_profile_get_format (GstEncodingProfile * profile)
{
- return profile->format;
+ return (profile->format ? gst_caps_ref (profile->format) : NULL);
}
/**
*
* Since: 0.10.32
*
- * Returns: The restriction #GstCaps to apply before the encoder
+ * Returns: (transfer full): The restriction #GstCaps to apply before the encoder
* that will be used in the profile. The fields present in restriction caps are
* properties of the raw stream (that is before encoding), such as height and
* width for video and depth and sampling rate for audio. Does not apply to
* #GstEncodingContainerProfile (since there is no corresponding raw stream).
- * Can be %NULL.
+ * Can be %NULL. Unref after usage.
*/
-const GstCaps *
+GstCaps *
gst_encoding_profile_get_restriction (GstEncodingProfile * profile)
{
- return profile->restriction;
+ return (profile->restriction ? gst_caps_ref (profile->restriction) : NULL);
}
/**
}
static void
-gst_encoding_container_profile_finalize (GstEncodingContainerProfile * prof)
+gst_encoding_container_profile_finalize (GObject * object)
{
- g_list_foreach (prof->encodingprofiles, (GFunc) gst_mini_object_unref, NULL);
+ GstEncodingContainerProfile *prof = (GstEncodingContainerProfile *) object;
+
+ g_list_foreach (prof->encodingprofiles, (GFunc) g_object_unref, NULL);
g_list_free (prof->encodingprofiles);
- GST_MINI_OBJECT_CLASS (gst_encoding_container_profile_parent_class)->finalize
- ((GstMiniObject *) prof);
+ G_OBJECT_CLASS (gst_encoding_container_profile_parent_class)->finalize
+ ((GObject *) prof);
}
static void
-gst_encoding_container_profile_class_init (GstMiniObjectClass * klass)
+gst_encoding_container_profile_class_init (GObjectClass * klass)
{
- klass->finalize =
- (GstMiniObjectFinalizeFunction) gst_encoding_container_profile_finalize;
+ klass->finalize = gst_encoding_container_profile_finalize;
}
const GList *
}
static void
-gst_encoding_video_profile_class_init (GstMiniObjectClass * klass)
+gst_encoding_video_profile_class_init (GObjectClass * klass)
{
}
}
static void
-gst_encoding_audio_profile_class_init (GstMiniObjectClass * klass)
+gst_encoding_audio_profile_class_init (GObjectClass * klass)
{
}
{
GstEncodingProfile *prof;
- prof = (GstEncodingProfile *) gst_mini_object_new (objtype);
+ prof = (GstEncodingProfile *) g_object_new (objtype, NULL);
if (name)
prof->name = g_strdup (name);
*
* Since: 0.10.32
*
- * Returns: The full caps the given @profile can consume. Call gst_caps_unref()
- * when you are done with the caps.
+ * Returns: (transfer full): The full caps the given @profile can consume. Call
+ * gst_caps_unref() when you are done with the caps.
*/
GstCaps *
gst_encoding_profile_get_input_caps (GstEncodingProfile * profile)
GstStructure *st, *outst;
GQuark out_name;
guint i, len;
- const GstCaps *fcaps;
+ GstCaps *fcaps;
if (GST_IS_ENCODING_CONTAINER_PROFILE (profile)) {
GstCaps *res = gst_caps_new_empty ();
/* fast-path */
if ((profile->restriction == NULL) || gst_caps_is_any (profile->restriction))
- return gst_caps_copy (fcaps);
+ return gst_caps_ref (fcaps);
/* Combine the format with the restriction caps */
outst = gst_caps_get_structure (fcaps, 0);
profile = combo_search (profilename);
if (profile)
- gst_value_take_mini_object (dest_value, (GstMiniObject *) profile);
+ g_value_take_object (dest_value, (GObject *) profile);
}
static gboolean
profile = combo_search (s);
if (profile) {
- gst_value_take_mini_object (value, (GstMiniObject *) profile);
+ g_value_take_object (value, (GObject *) profile);
return TRUE;
}
#define GST_IS_ENCODING_PROFILE(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ENCODING_PROFILE))
typedef struct _GstEncodingProfile GstEncodingProfile;
-typedef GstMiniObjectClass GstEncodingProfileClass;
+typedef GObjectClass GstEncodingProfileClass;
GType gst_encoding_profile_get_type (void);
*
* Since: 0.10.32
*/
-#define gst_encoding_profile_unref(profile) (gst_mini_object_unref ((GstMiniObject*) profile))
+#define gst_encoding_profile_unref(profile) (g_object_unref ((GObject*) profile))
/**
* gst_encoding_profile_ref:
*
* Since: 0.10.32
*/
-#define gst_encoding_profile_ref(profile) (gst_mini_object_ref ((GstMiniObject*) profile))
+#define gst_encoding_profile_ref(profile) (g_object_ref ((GObject*) profile))
const gchar * gst_encoding_profile_get_name(GstEncodingProfile *profile);
const gchar * gst_encoding_profile_get_description(GstEncodingProfile *profile);
-const GstCaps * gst_encoding_profile_get_format(GstEncodingProfile *profile);
+GstCaps * gst_encoding_profile_get_format(GstEncodingProfile *profile);
const gchar * gst_encoding_profile_get_preset(GstEncodingProfile *profile);
guint gst_encoding_profile_get_presence(GstEncodingProfile *profile);
-const GstCaps * gst_encoding_profile_get_restriction(GstEncodingProfile *profile);
+GstCaps * gst_encoding_profile_get_restriction(GstEncodingProfile *profile);
void gst_encoding_profile_set_name(GstEncodingProfile *profile, const gchar *name);
void gst_encoding_profile_set_description(GstEncodingProfile *profile, const gchar *description);
struct _GstEncodingTarget
{
- GstMiniObject parent;
+ GObject parent;
gchar *name;
gchar *category;
gchar *keyfile;
};
-G_DEFINE_TYPE (GstEncodingTarget, gst_encoding_target, GST_TYPE_MINI_OBJECT);
+G_DEFINE_TYPE (GstEncodingTarget, gst_encoding_target, G_TYPE_OBJECT);
static void
gst_encoding_target_init (GstEncodingTarget * target)
}
static void
-gst_encoding_target_finalize (GstEncodingTarget * target)
+gst_encoding_target_finalize (GObject * object)
{
+ GstEncodingTarget *target = (GstEncodingTarget *) object;
+
GST_DEBUG ("Finalizing");
if (target->name)
if (target->description)
g_free (target->description);
- g_list_foreach (target->profiles, (GFunc) gst_mini_object_unref, NULL);
+ g_list_foreach (target->profiles, (GFunc) g_object_unref, NULL);
g_list_free (target->profiles);
}
static void
-gst_encoding_target_class_init (GstMiniObjectClass * klass)
+gst_encoding_target_class_init (GObjectClass * klass)
{
- klass->finalize =
- (GstMiniObjectFinalizeFunction) gst_encoding_target_finalize;
+ klass->finalize = gst_encoding_target_finalize;
}
/**
if (!validate_name (category))
goto invalid_category;
- res = (GstEncodingTarget *) gst_mini_object_new (GST_TYPE_ENCODING_TARGET);
+ res = (GstEncodingTarget *) g_object_new (GST_TYPE_ENCODING_TARGET, NULL);
res->name = g_strdup (name);
res->category = g_strdup (category);
res->description = g_strdup (description);
/* Try from local profiles */
tldir =
- g_build_filename (g_get_home_dir (), ".gstreamer-" GST_MAJORMINOR,
+ g_build_filename (g_get_user_data_dir (), "gstreamer-" GST_MAJORMINOR,
GST_ENCODING_TARGET_DIRECTORY, NULL);
target = gst_encoding_target_subload (tldir, category, lfilename, error);
g_free (tldir);
lfilename = g_strdup_printf ("%s" GST_ENCODING_TARGET_SUFFIX, target->name);
filename =
- g_build_filename (g_get_home_dir (), ".gstreamer-" GST_MAJORMINOR,
+ g_build_filename (g_get_user_data_dir (), "gstreamer-" GST_MAJORMINOR,
GST_ENCODING_TARGET_DIRECTORY, target->category, lfilename, NULL);
g_free (lfilename);
gchar *topdir;
/* First try user-local categories */
- topdir = g_build_filename (g_get_home_dir (), ".gstreamer-" GST_MAJORMINOR,
+ topdir =
+ g_build_filename (g_get_user_data_dir (), "gstreamer-" GST_MAJORMINOR,
GST_ENCODING_TARGET_DIRECTORY, NULL);
res = get_categories (topdir);
g_free (topdir);
gchar *topdir;
/* Get user-locals */
- topdir = g_build_filename (g_get_home_dir (), ".gstreamer-" GST_MAJORMINOR,
+ topdir =
+ g_build_filename (g_get_user_data_dir (), "gstreamer-" GST_MAJORMINOR,
GST_ENCODING_TARGET_DIRECTORY, NULL);
res = get_all_targets (topdir, categoryname);
g_free (topdir);
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ENCODING_TARGET))
typedef struct _GstEncodingTarget GstEncodingTarget;
-typedef GstMiniObjectClass GstEncodingTargetClass;
+typedef GObjectClass GstEncodingTargetClass;
GType gst_encoding_target_get_type (void);
* Since: 0.10.32
*/
#define gst_encoding_target_unref(target) \
- (gst_mini_object_unref ((GstMiniObject*) target))
+ (g_object_unref ((GObject*) target))
/**
* gst_encoding_target_ref:
* Since: 0.10.32
*/
#define gst_encoding_target_ref(target) \
- (gst_mini_object_ref ((GstMiniObject*) target))
+ (g_object_ref ((GObject*) target))
GstEncodingTarget *
gst_encoding_target_new (const gchar *name, const gchar *category,
/* Per-stream information */
G_DEFINE_TYPE (GstDiscovererStreamInfo, gst_discoverer_stream_info,
- GST_TYPE_MINI_OBJECT);
+ G_TYPE_OBJECT);
static void
gst_discoverer_stream_info_init (GstDiscovererStreamInfo * info)
}
static void
-gst_discoverer_stream_info_finalize (GstDiscovererStreamInfo * info)
+gst_discoverer_stream_info_finalize (GObject * object)
{
+ GstDiscovererStreamInfo *info = (GstDiscovererStreamInfo *) object;
+
if (info->next)
- gst_mini_object_unref ((GstMiniObject *) info->next);
+ g_object_unref ((GObject *) info->next);
if (info->caps)
gst_caps_unref (info->caps);
gst_structure_free (info->misc);
}
-static GstDiscovererStreamInfo *
-gst_discoverer_stream_info_copy (GstDiscovererStreamInfo * info)
-{
- return gst_discoverer_info_copy_int (info, NULL);
-}
-
static void
-gst_discoverer_stream_info_class_init (GstMiniObjectClass * klass)
+gst_discoverer_stream_info_class_init (GObjectClass * klass)
{
- klass->finalize =
- (GstMiniObjectFinalizeFunction) gst_discoverer_stream_info_finalize;
- klass->copy = (GstMiniObjectCopyFunction) gst_discoverer_stream_info_copy;
+ klass->finalize = gst_discoverer_stream_info_finalize;
}
static GstDiscovererStreamInfo *
gst_discoverer_stream_info_new (void)
{
return (GstDiscovererStreamInfo *)
- gst_mini_object_new (GST_TYPE_DISCOVERER_STREAM_INFO);
+ g_object_new (GST_TYPE_DISCOVERER_STREAM_INFO, NULL);
}
static GstDiscovererStreamInfo *
gst_discoverer_container_info_new (void)
{
return (GstDiscovererContainerInfo *)
- gst_mini_object_new (GST_TYPE_DISCOVERER_CONTAINER_INFO);
+ g_object_new (GST_TYPE_DISCOVERER_CONTAINER_INFO, NULL);
}
static void
-gst_discoverer_container_info_finalize (GstDiscovererContainerInfo * info)
+gst_discoverer_container_info_finalize (GObject * object)
{
+ GstDiscovererContainerInfo *info = (GstDiscovererContainerInfo *) object;
GList *tmp;
for (tmp = ((GstDiscovererContainerInfo *) info)->streams; tmp;
tmp = tmp->next)
- gst_mini_object_unref ((GstMiniObject *) tmp->data);
+ g_object_unref ((GObject *) tmp->data);
gst_discoverer_stream_info_list_free (info->streams);
- gst_discoverer_stream_info_finalize ((GstDiscovererStreamInfo *) info);
+ gst_discoverer_stream_info_finalize ((GObject *) info);
}
static void
-gst_discoverer_container_info_class_init (GstMiniObjectClass * klass)
+gst_discoverer_container_info_class_init (GObjectClass * klass)
{
- klass->finalize =
- (GstMiniObjectFinalizeFunction) gst_discoverer_container_info_finalize;
+ klass->finalize = gst_discoverer_container_info_finalize;
}
static GstDiscovererContainerInfo *
gst_discoverer_audio_info_new (void)
{
return (GstDiscovererAudioInfo *)
- gst_mini_object_new (GST_TYPE_DISCOVERER_AUDIO_INFO);
+ g_object_new (GST_TYPE_DISCOVERER_AUDIO_INFO, NULL);
}
static GstDiscovererAudioInfo *
GST_TYPE_DISCOVERER_STREAM_INFO);
static void
-gst_discoverer_video_info_class_init (GstMiniObjectClass * klass)
+gst_discoverer_video_info_class_init (GObjectClass * klass)
{
/* Nothing to initialize */
}
gst_discoverer_video_info_new (void)
{
return (GstDiscovererVideoInfo *)
- gst_mini_object_new (GST_TYPE_DISCOVERER_VIDEO_INFO);
+ g_object_new (GST_TYPE_DISCOVERER_VIDEO_INFO, NULL);
}
static GstDiscovererVideoInfo *
}
/* Global stream information */
-G_DEFINE_TYPE (GstDiscovererInfo, gst_discoverer_info, GST_TYPE_MINI_OBJECT);
+G_DEFINE_TYPE (GstDiscovererInfo, gst_discoverer_info, G_TYPE_OBJECT);
static void
gst_discoverer_info_init (GstDiscovererInfo * info)
}
static void
-gst_discoverer_info_finalize (GstDiscovererInfo * info)
+gst_discoverer_info_finalize (GObject * object)
{
+ GstDiscovererInfo *info = (GstDiscovererInfo *) object;
g_free (info->uri);
if (info->stream_info)
- gst_mini_object_unref ((GstMiniObject *) info->stream_info);
+ g_object_unref ((GObject *) info->stream_info);
if (info->misc)
gst_structure_free (info->misc);
static GstDiscovererInfo *
gst_discoverer_info_new (void)
{
- return (GstDiscovererInfo *) gst_mini_object_new (GST_TYPE_DISCOVERER_INFO);
+ return (GstDiscovererInfo *) g_object_new (GST_TYPE_DISCOVERER_INFO, NULL);
}
GstDiscovererInfo *
}
static void
-gst_discoverer_info_class_init (GstMiniObjectClass * klass)
+gst_discoverer_info_class_init (GObjectClass * klass)
{
- klass->finalize =
- (GstMiniObjectFinalizeFunction) gst_discoverer_info_finalize;
- klass->copy = (GstMiniObjectCopyFunction) gst_discoverer_info_copy;
+ klass->finalize = gst_discoverer_info_finalize;
}
/**
g_object_set (ps->sink, "silent", TRUE, NULL);
g_object_set (ps->queue, "max-size-buffers", 1, "silent", TRUE, NULL);
- caps = gst_pad_get_caps_reffed (pad);
+ caps = gst_pad_get_caps (pad, NULL);
if (gst_caps_can_intersect (caps, subs_caps)) {
/* Subtitle streams are sparse and don't provide any information - don't
if (!caps) {
GST_WARNING ("Couldn't get negotiated caps from %s:%s",
GST_DEBUG_PAD_NAME (ps->pad));
- caps = gst_pad_get_caps (ps->pad);
+ caps = gst_pad_get_caps (ps->pad, NULL);
}
if (caps) {
GST_DEBUG ("Got caps %" GST_PTR_FORMAT, caps);
return parent;
else
return (GstDiscovererStreamInfo *)
- gst_mini_object_new (GST_TYPE_DISCOVERER_STREAM_INFO);
+ g_object_new (GST_TYPE_DISCOVERER_STREAM_INFO, NULL);
}
gst_structure_id_get (st, _CAPS_QUARK, GST_TYPE_CAPS, &caps, NULL);
info = (GstDiscovererAudioInfo *) parent;
else {
info = (GstDiscovererAudioInfo *)
- gst_mini_object_new (GST_TYPE_DISCOVERER_AUDIO_INFO);
+ g_object_new (GST_TYPE_DISCOVERER_AUDIO_INFO, NULL);
info->parent.caps = caps;
}
info = (GstDiscovererVideoInfo *) parent;
else {
info = (GstDiscovererVideoInfo *)
- gst_mini_object_new (GST_TYPE_DISCOVERER_VIDEO_INFO);
+ g_object_new (GST_TYPE_DISCOVERER_VIDEO_INFO, NULL);
info->parent.caps = caps;
}
info = parent;
else {
info = (GstDiscovererStreamInfo *)
- gst_mini_object_new (GST_TYPE_DISCOVERER_STREAM_INFO);
+ g_object_new (GST_TYPE_DISCOVERER_STREAM_INFO, NULL);
info->caps = caps;
}
GST_DEBUG ("next is a list of %d entries", len);
cont = (GstDiscovererContainerInfo *)
- gst_mini_object_new (GST_TYPE_DISCOVERER_CONTAINER_INFO);
+ g_object_new (GST_TYPE_DISCOVERER_CONTAINER_INFO, NULL);
cont->parent.caps = caps;
res = (GstDiscovererStreamInfo *) cont;
case GST_MESSAGE_ELEMENT:
{
- GQuark sttype = gst_structure_get_name_id (msg->structure);
+ GQuark sttype;
+ const GstStructure *structure;
+
+ structure = gst_message_get_structure (msg);
+ sttype = gst_structure_get_name_id (structure);
GST_DEBUG_OBJECT (GST_MESSAGE_SRC (msg),
- "structure %" GST_PTR_FORMAT, msg->structure);
+ "structure %" GST_PTR_FORMAT, structure);
if (sttype == _MISSING_PLUGIN_QUARK) {
GST_DEBUG_OBJECT (GST_MESSAGE_SRC (msg),
"Setting result to MISSING_PLUGINS");
dc->priv->current_info->result = GST_DISCOVERER_MISSING_PLUGINS;
- dc->priv->current_info->misc = gst_structure_copy (msg->structure);
+ dc->priv->current_info->misc = gst_structure_copy (structure);
} else if (sttype == _STREAM_TOPOLOGY_QUARK) {
- dc->priv->current_topology = gst_structure_copy (msg->structure);
+ dc->priv->current_topology = gst_structure_copy (structure);
}
}
break;
/* Pop URI off the pending URI list */
dc->priv->current_info =
- (GstDiscovererInfo *) gst_mini_object_new (GST_TYPE_DISCOVERER_INFO);
+ (GstDiscovererInfo *) g_object_new (GST_TYPE_DISCOVERER_INFO, NULL);
dc->priv->current_info->uri = (gchar *) dc->priv->pending_uris->data;
dc->priv->pending_uris =
g_list_delete_link (dc->priv->pending_uris, dc->priv->pending_uris);
#define GST_IS_DISCOVERER_STREAM_INFO(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DISCOVERER_STREAM_INFO))
typedef struct _GstDiscovererStreamInfo GstDiscovererStreamInfo;
-typedef GstMiniObjectClass GstDiscovererStreamInfoClass;
+typedef GObjectClass GstDiscovererStreamInfoClass;
GType gst_discoverer_stream_info_get_type (void);
/**
*
* Since: 0.10.31
*/
-#define gst_discoverer_stream_info_ref(info) ((GstDiscovererStreamInfo*) gst_mini_object_ref((GstMiniObject*) info))
-#define gst_discoverer_stream_info_unref(info) (gst_mini_object_unref((GstMiniObject*) info))
+#define gst_discoverer_stream_info_ref(info) ((GstDiscovererStreamInfo*) g_object_ref((GObject*) info))
+#define gst_discoverer_stream_info_unref(info) (g_object_unref((GObject*) info))
GstDiscovererStreamInfo* gst_discoverer_stream_info_get_previous(GstDiscovererStreamInfo* info);
GstDiscovererStreamInfo* gst_discoverer_stream_info_get_next(GstDiscovererStreamInfo* info);
#define GST_IS_DISCOVERER_CONTAINER_INFO(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DISCOVERER_CONTAINER_INFO))
typedef struct _GstDiscovererContainerInfo GstDiscovererContainerInfo;
-typedef GstMiniObjectClass GstDiscovererContainerInfoClass;
+typedef GObjectClass GstDiscovererContainerInfoClass;
GType gst_discoverer_container_info_get_type (void);
#define GST_IS_DISCOVERER_AUDIO_INFO(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DISCOVERER_AUDIO_INFO))
typedef struct _GstDiscovererAudioInfo GstDiscovererAudioInfo;
-typedef GstMiniObjectClass GstDiscovererAudioInfoClass;
+typedef GObjectClass GstDiscovererAudioInfoClass;
GType gst_discoverer_audio_info_get_type (void);
#define GST_IS_DISCOVERER_VIDEO_INFO(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DISCOVERER_VIDEO_INFO))
typedef struct _GstDiscovererVideoInfo GstDiscovererVideoInfo;
-typedef GstMiniObjectClass GstDiscovererVideoInfoClass;
+typedef GObjectClass GstDiscovererVideoInfoClass;
GType gst_discoverer_video_info_get_type (void);
guint gst_discoverer_video_info_get_width(const GstDiscovererVideoInfo* info);
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DISCOVERER_INFO, GstDiscovererInfo))
#define GST_IS_DISCOVERER_INFO(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DISCOVERER_INFO))
-typedef GstMiniObjectClass GstDiscovererInfoClass;
+typedef GObjectClass GstDiscovererInfoClass;
GType gst_discoverer_info_get_type (void);
-#define gst_discoverer_info_unref(info) (gst_mini_object_unref((GstMiniObject*)info))
-#define gst_discoverer_info_ref(info) (gst_mini_object_ref((GstMiniObject*)info))
+#define gst_discoverer_info_unref(info) (g_object_unref((GObject*)info))
+#define gst_discoverer_info_ref(info) (g_object_ref((Gbject*)info))
GstDiscovererInfo* gst_discoverer_info_copy (GstDiscovererInfo * ptr);
GString *str = NULL;
gchar *detail = NULL;
gchar *desc;
+ const GstStructure *structure;
g_return_val_if_fail (gst_is_missing_plugin_message (msg), NULL);
- GST_LOG ("Parsing missing-plugin message: %" GST_PTR_FORMAT, msg->structure);
+ structure = gst_message_get_structure (msg);
+ GST_LOG ("Parsing missing-plugin message: %" GST_PTR_FORMAT, structure);
- missing_type = missing_structure_get_type (msg->structure);
+ missing_type = missing_structure_get_type (structure);
if (missing_type == GST_MISSING_TYPE_UNKNOWN) {
GST_WARNING ("couldn't parse 'type' field");
goto error;
}
- type = gst_structure_get_string (msg->structure, "type");
+ type = gst_structure_get_string (structure, "type");
g_assert (type != NULL); /* validity already checked above */
/* FIXME: use gst_installer_detail_new() here too */
case GST_MISSING_TYPE_URISOURCE:
case GST_MISSING_TYPE_URISINK:
case GST_MISSING_TYPE_ELEMENT:
- if (!missing_structure_get_string_detail (msg->structure, &detail))
+ if (!missing_structure_get_string_detail (structure, &detail))
goto error;
break;
case GST_MISSING_TYPE_DECODER:
case GST_MISSING_TYPE_ENCODER:{
GstCaps *caps = NULL;
- if (!missing_structure_get_caps_detail (msg->structure, &caps))
+ if (!missing_structure_get_caps_detail (structure, &caps))
goto error;
detail = gst_caps_to_string (caps);
GstMissingType missing_type;
const gchar *desc;
gchar *ret = NULL;
+ const GstStructure *structure;
g_return_val_if_fail (gst_is_missing_plugin_message (msg), NULL);
- GST_LOG ("Parsing missing-plugin message: %" GST_PTR_FORMAT, msg->structure);
+ structure = gst_message_get_structure (msg);
+ GST_LOG ("Parsing missing-plugin message: %" GST_PTR_FORMAT, structure);
- desc = gst_structure_get_string (msg->structure, "name");
+ desc = gst_structure_get_string (structure, "name");
if (desc != NULL && *desc != '\0') {
ret = g_strdup (desc);
goto done;
}
/* fallback #1 */
- missing_type = missing_structure_get_type (msg->structure);
+ missing_type = missing_structure_get_type (structure);
switch (missing_type) {
case GST_MISSING_TYPE_URISOURCE:
case GST_MISSING_TYPE_ELEMENT:{
gchar *detail = NULL;
- if (missing_structure_get_string_detail (msg->structure, &detail)) {
+ if (missing_structure_get_string_detail (structure, &detail)) {
if (missing_type == GST_MISSING_TYPE_URISOURCE)
ret = gst_pb_utils_get_source_description (detail);
else if (missing_type == GST_MISSING_TYPE_URISINK)
case GST_MISSING_TYPE_ENCODER:{
GstCaps *caps = NULL;
- if (missing_structure_get_caps_detail (msg->structure, &caps)) {
+ if (missing_structure_get_caps_detail (structure, &caps)) {
if (missing_type == GST_MISSING_TYPE_DECODER)
ret = gst_pb_utils_get_decoder_description (caps);
else
gboolean
gst_is_missing_plugin_message (GstMessage * msg)
{
+ const GstStructure *structure;
+
g_return_val_if_fail (msg != NULL, FALSE);
g_return_val_if_fail (GST_IS_MESSAGE (msg), FALSE);
- if (GST_MESSAGE_TYPE (msg) != GST_MESSAGE_ELEMENT || msg->structure == NULL)
+ structure = gst_message_get_structure (msg);
+ if (GST_MESSAGE_TYPE (msg) != GST_MESSAGE_ELEMENT || structure == NULL)
return FALSE;
- return gst_structure_has_name (msg->structure, "missing-plugin");
+ return gst_structure_has_name (structure, "missing-plugin");
}
/* takes ownership of the description */
*/
struct _GstDiscovererStreamInfo {
- GstMiniObject parent;
+ GObject parent;
GstDiscovererStreamInfo *previous; /* NULL for starting points */
GstDiscovererStreamInfo *next; /* NULL for containers */
};
struct _GstDiscovererInfo {
- GstMiniObject parent;
+ GObject parent;
gchar *uri;
GstDiscovererResult result;
if (palette) {
GstBuffer *copy;
guint num_colors;
+ gsize size;
if (strf != NULL)
num_colors = strf->num_colors;
else
num_colors = 256;
- if (GST_BUFFER_SIZE (palette) >= (num_colors * 4)) {
+ size = gst_buffer_get_size (palette);
+
+ if (size >= (num_colors * 4)) {
/* palette is always at least 256*4 bytes */
- copy =
- gst_buffer_new_and_alloc (MAX (GST_BUFFER_SIZE (palette), 256 * 4));
- memcpy (GST_BUFFER_DATA (copy), GST_BUFFER_DATA (palette),
- GST_BUFFER_SIZE (palette));
+ copy = gst_buffer_new_and_alloc (MAX (size, 256 * 4));
+ gst_buffer_copy_into (copy, palette, GST_BUFFER_COPY_MEMORY, 0, size);
#if (G_BYTE_ORDER == G_BIG_ENDIAN)
{
guint16 valid_bits_per_sample;
guint32 channel_mask;
guint32 subformat_guid[4];
- const guint8 *data;
+ guint8 *data;
+ gsize size;
channels_max = 8;
/* should be at least 22 bytes */
- if (strf_data == NULL || GST_BUFFER_SIZE (strf_data) < 22) {
+ size = gst_buffer_get_size (strf_data);
+
+ if (strf_data == NULL || size < 22) {
GST_WARNING ("WAVE_FORMAT_EXTENSIBLE data size is %d (expected: 22)",
- (strf_data) ? GST_BUFFER_SIZE (strf_data) : -1);
+ (strf_data) ? size : -1);
return NULL;
}
- data = GST_BUFFER_DATA (strf_data);
-
+ data = gst_buffer_map (strf_data, &size, NULL, GST_MAP_READ);
valid_bits_per_sample = GST_READ_UINT16_LE (data);
channel_mask = GST_READ_UINT32_LE (data + 2);
subformat_guid[0] = GST_READ_UINT32_LE (data + 6);
subformat_guid[1] = GST_READ_UINT32_LE (data + 10);
subformat_guid[2] = GST_READ_UINT32_LE (data + 14);
subformat_guid[3] = GST_READ_UINT32_LE (data + 18);
+ gst_buffer_unmap (strf_data, data, size);
GST_DEBUG ("valid bps = %u", valid_bits_per_sample);
GST_DEBUG ("channel mask = 0x%08x", channel_mask);
{
GstBuffer *buf;
GstFlowReturn res;
+ guint8 *data;
guint size;
guint64 offset = *_offset;
+ gsize bsize;
g_return_val_if_fail (element != NULL, GST_FLOW_ERROR);
g_return_val_if_fail (pad != NULL, GST_FLOW_ERROR);
size = 8;
if ((res = gst_pad_pull_range (pad, offset, size, &buf)) != GST_FLOW_OK)
return res;
- else if (GST_BUFFER_SIZE (buf) < size)
+ else if (gst_buffer_get_size (buf) < size)
goto too_small;
- *tag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf));
- size = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf) + 4);
+ data = gst_buffer_map (buf, &bsize, NULL, GST_MAP_READ);
+ *tag = GST_READ_UINT32_LE (data);
+ size = GST_READ_UINT32_LE (data + 4);
+ gst_buffer_unmap (buf, data, bsize);
gst_buffer_unref (buf);
GST_DEBUG_OBJECT (element, "fourcc=%" GST_FOURCC_FORMAT ", size=%u",
if ((res = gst_pad_pull_range (pad, offset + 8, size, &buf)) != GST_FLOW_OK)
return res;
- else if (GST_BUFFER_SIZE (buf) < size)
+ else if (gst_buffer_get_size (buf) < size)
goto too_small;
*_chunk_data = buf;
{
/* short read, we return UNEXPECTED to mark the EOS case */
GST_DEBUG_OBJECT (element, "not enough data (available=%u, needed=%u)",
- GST_BUFFER_SIZE (buf), size);
+ gst_buffer_get_size (buf), size);
gst_buffer_unref (buf);
return GST_FLOW_UNEXPECTED;
}
{
guint size, bufsize;
guint32 fourcc;
- guint8 *data;
+ guint8 *data, *ptr;
+ gsize bsize;
guint offset = *_offset;
g_return_val_if_fail (element != NULL, FALSE);
*chunk_data = NULL;
*_fourcc = 0;
- bufsize = GST_BUFFER_SIZE (buf);
+ bufsize = gst_buffer_get_size (buf);
if (bufsize == offset)
goto end_offset;
goto too_small;
/* read header */
- data = GST_BUFFER_DATA (buf) + offset;
- fourcc = GST_READ_UINT32_LE (data);
- size = GST_READ_UINT32_LE (data + 4);
+ data = ptr = gst_buffer_map (buf, &bsize, NULL, GST_MAP_READ);
+ ptr += offset;
+ fourcc = GST_READ_UINT32_LE (ptr);
+ size = GST_READ_UINT32_LE (ptr + 4);
+ gst_buffer_unmap (buf, data, bsize);
GST_DEBUG_OBJECT (element, "fourcc=%" GST_FOURCC_FORMAT ", size=%u",
GST_FOURCC_ARGS (fourcc), size);
}
if (size)
- *chunk_data = gst_buffer_create_sub (buf, offset + 8, size);
+ *chunk_data =
+ gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, offset + 8, size);
else
*chunk_data = NULL;
{
guint8 *data;
guint32 tag;
+ gsize size;
g_return_val_if_fail (buf != NULL, FALSE);
g_return_val_if_fail (doctype != NULL, FALSE);
- if (GST_BUFFER_SIZE (buf) < 12)
+ data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
+ if (size < 12)
goto too_small;
- data = GST_BUFFER_DATA (buf);
tag = GST_READ_UINT32_LE (data);
if (tag != GST_RIFF_TAG_RIFF && tag != GST_RIFF_TAG_AVF0)
goto not_riff;
*doctype = GST_READ_UINT32_LE (data + 8);
+ gst_buffer_unmap (buf, data, size);
gst_buffer_unref (buf);
{
GST_ELEMENT_ERROR (element, STREAM, WRONG_TYPE, (NULL),
("Not enough data to parse RIFF header (%d available, %d needed)",
- GST_BUFFER_SIZE (buf), 12));
+ size, 12));
+ gst_buffer_unmap (buf, data, size);
gst_buffer_unref (buf);
return FALSE;
}
GST_ELEMENT_ERROR (element, STREAM, WRONG_TYPE, (NULL),
("Stream is no RIFF stream: %" GST_FOURCC_FORMAT,
GST_FOURCC_ARGS (tag)));
+ gst_buffer_unmap (buf, data, size);
gst_buffer_unref (buf);
return FALSE;
}
GstBuffer * buf, gst_riff_strh ** _strh)
{
gst_riff_strh *strh;
+ guint8 *data;
+ gsize size;
g_return_val_if_fail (buf != NULL, FALSE);
g_return_val_if_fail (_strh != NULL, FALSE);
- if (GST_BUFFER_SIZE (buf) < sizeof (gst_riff_strh))
+ data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
+ if (size < sizeof (gst_riff_strh))
goto too_small;
- strh = g_memdup (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
+ strh = g_memdup (data, size);
+ gst_buffer_unmap (buf, data, size);
+
gst_buffer_unref (buf);
#if (G_BYTE_ORDER == G_BIG_ENDIAN)
{
GST_ERROR_OBJECT (element,
"Too small strh (%d available, %d needed)",
- GST_BUFFER_SIZE (buf), (int) sizeof (gst_riff_strh));
+ size, (int) sizeof (gst_riff_strh));
+ gst_buffer_unmap (buf, data, size);
gst_buffer_unref (buf);
return FALSE;
}
GstBuffer * buf, gst_riff_strf_vids ** _strf, GstBuffer ** data)
{
gst_riff_strf_vids *strf;
+ guint8 *bdata;
+ gsize size;
g_return_val_if_fail (buf != NULL, FALSE);
g_return_val_if_fail (_strf != NULL, FALSE);
g_return_val_if_fail (data != NULL, FALSE);
- if (GST_BUFFER_SIZE (buf) < sizeof (gst_riff_strf_vids))
+ bdata = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
+ if (size < sizeof (gst_riff_strf_vids))
goto too_small;
- strf = g_memdup (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
+ strf = g_memdup (bdata, size);
+ gst_buffer_unmap (buf, bdata, size);
#if (G_BYTE_ORDER == G_BIG_ENDIAN)
strf->size = GUINT32_FROM_LE (strf->size);
/* size checking */
*data = NULL;
- if (strf->size > GST_BUFFER_SIZE (buf)) {
+ if (strf->size > size) {
GST_WARNING_OBJECT (element,
"strf_vids header gave %d bytes data, only %d available",
- strf->size, GST_BUFFER_SIZE (buf));
- strf->size = GST_BUFFER_SIZE (buf);
+ strf->size, size);
+ strf->size = size;
}
- if (sizeof (gst_riff_strf_vids) < GST_BUFFER_SIZE (buf)) {
- *data = gst_buffer_create_sub (buf, sizeof (gst_riff_strf_vids),
- GST_BUFFER_SIZE (buf) - sizeof (gst_riff_strf_vids));
+ if (sizeof (gst_riff_strf_vids) < size) {
+ *data =
+ gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
+ sizeof (gst_riff_strf_vids), size - sizeof (gst_riff_strf_vids));
}
+ gst_buffer_unref (buf);
/* debug */
GST_INFO_OBJECT (element, "strf tag found in context vids:");
GST_INFO_OBJECT (element, " num_colors %d", strf->num_colors);
GST_INFO_OBJECT (element, " imp_colors %d", strf->imp_colors);
if (*data)
- GST_INFO_OBJECT (element, " %d bytes extradata", GST_BUFFER_SIZE (*data));
-
- gst_buffer_unref (buf);
+ GST_INFO_OBJECT (element, " %d bytes extradata",
+ gst_buffer_get_size (*data));
*_strf = strf;
{
GST_ERROR_OBJECT (element,
"Too small strf_vids (%d available, %d needed)",
- GST_BUFFER_SIZE (buf), (int) sizeof (gst_riff_strf_vids));
+ size, (int) sizeof (gst_riff_strf_vids));
+ gst_buffer_unmap (buf, data, size);
gst_buffer_unref (buf);
return FALSE;
}
GstBuffer * buf, gst_riff_strf_auds ** _strf, GstBuffer ** data)
{
gst_riff_strf_auds *strf;
- guint bufsize;
+ gsize bsize;
+ guint8 *bdata;
g_return_val_if_fail (buf != NULL, FALSE);
g_return_val_if_fail (_strf != NULL, FALSE);
g_return_val_if_fail (data != NULL, FALSE);
- bufsize = GST_BUFFER_SIZE (buf);
-
- if (bufsize < sizeof (gst_riff_strf_auds))
+ bdata = gst_buffer_map (buf, &bsize, NULL, GST_MAP_READ);
+ if (bsize < sizeof (gst_riff_strf_auds))
goto too_small;
- strf = g_memdup (GST_BUFFER_DATA (buf), bufsize);
+ strf = g_memdup (bdata, bsize);
#if (G_BYTE_ORDER == G_BIG_ENDIAN)
strf->format = GUINT16_FROM_LE (strf->format);
/* size checking */
*data = NULL;
- if (bufsize > sizeof (gst_riff_strf_auds) + 2) {
+ if (bsize > sizeof (gst_riff_strf_auds) + 2) {
gint len;
- len = GST_READ_UINT16_LE (&GST_BUFFER_DATA (buf)[16]);
- if (len + 2 + sizeof (gst_riff_strf_auds) > bufsize) {
+ len = GST_READ_UINT16_LE (&data[16]);
+ if (len + 2 + sizeof (gst_riff_strf_auds) > bsize) {
GST_WARNING_OBJECT (element,
"Extradata indicated %d bytes, but only %" G_GSSIZE_FORMAT
- " available", len, bufsize - 2 - sizeof (gst_riff_strf_auds));
- len = bufsize - 2 - sizeof (gst_riff_strf_auds);
+ " available", len, bsize - 2 - sizeof (gst_riff_strf_auds));
+ len = bsize - 2 - sizeof (gst_riff_strf_auds);
}
if (len)
- *data = gst_buffer_create_sub (buf, sizeof (gst_riff_strf_auds) + 2, len);
+ *data = gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL,
+ sizeof (gst_riff_strf_auds) + 2, len);
}
/* debug */
GST_INFO_OBJECT (element, " blockalign %d", strf->blockalign);
GST_INFO_OBJECT (element, " size %d", strf->size);
if (*data)
- GST_INFO_OBJECT (element, " %d bytes extradata", GST_BUFFER_SIZE (*data));
+ GST_INFO_OBJECT (element, " %d bytes extradata",
+ gst_buffer_get_size (*data));
+ gst_buffer_unmap (buf, bdata, bsize);
gst_buffer_unref (buf);
*_strf = strf;
{
GST_ERROR_OBJECT (element,
"Too small strf_auds (%d available, %" G_GSSIZE_FORMAT " needed)",
- bufsize, sizeof (gst_riff_strf_auds));
+ bsize, sizeof (gst_riff_strf_auds));
+ gst_buffer_unmap (buf, bdata, bsize);
gst_buffer_unref (buf);
return FALSE;
}
GstBuffer * buf, gst_riff_strf_iavs ** _strf, GstBuffer ** data)
{
gst_riff_strf_iavs *strf;
+ gsize bsize;
+ guint8 *bdata;
g_return_val_if_fail (buf != NULL, FALSE);
g_return_val_if_fail (_strf != NULL, FALSE);
g_return_val_if_fail (data != NULL, FALSE);
- if (GST_BUFFER_SIZE (buf) < sizeof (gst_riff_strf_iavs))
+ bdata = gst_buffer_map (buf, &bsize, NULL, GST_MAP_READ);
+ if (bsize < sizeof (gst_riff_strf_iavs))
goto too_small;
- strf = g_memdup (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
+ strf = g_memdup (bdata, bsize);
+ gst_buffer_unmap (buf, bdata, bsize);
+
gst_buffer_unref (buf);
#if (G_BYTE_ORDER == G_BIG_ENDIAN)
{
GST_ERROR_OBJECT (element,
"Too small strf_iavs (%d available, %" G_GSSIZE_FORMAT " needed)",
- GST_BUFFER_SIZE (buf), sizeof (gst_riff_strf_iavs));
+ bsize, sizeof (gst_riff_strf_iavs));
+ gst_buffer_unmap (buf, bdata, bsize);
gst_buffer_unref (buf);
return FALSE;
}
gst_riff_parse_info (GstElement * element,
GstBuffer * buf, GstTagList ** _taglist)
{
- guint8 *data;
- guint size, tsize;
+ guint8 *data, *ptr;
+ gsize size, left;
+ guint tsize;
guint32 tag;
const gchar *type;
GstTagList *taglist;
*_taglist = NULL;
return;
}
- data = GST_BUFFER_DATA (buf);
- size = GST_BUFFER_SIZE (buf);
+ data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
+
taglist = gst_tag_list_new ();
- while (size > 8) {
- tag = GST_READ_UINT32_LE (data);
- tsize = GST_READ_UINT32_LE (data + 4);
- size -= 8;
- data += 8;
+ ptr = data;
+ left = size;
+
+ while (left > 8) {
+ tag = GST_READ_UINT32_LE (ptr);
+ tsize = GST_READ_UINT32_LE (ptr + 4);
+ left -= 8;
+ ptr += 8;
GST_DEBUG ("tag %" GST_FOURCC_FORMAT ", size %u",
GST_FOURCC_ARGS (tag), tsize);
- if (tsize > size) {
+ if (tsize > left) {
GST_WARNING_OBJECT (element,
- "Tagsize %d is larger than available data %d", tsize, size);
- tsize = size;
+ "Tagsize %d is larger than available data %d", tsize, left);
+ tsize = left;
}
/* find out the type of metadata */
break;
}
- if (type != NULL && data[0] != '\0') {
+ if (type != NULL && ptr[0] != '\0') {
static const gchar *env_vars[] = { "GST_AVI_TAG_ENCODING",
"GST_RIFF_TAG_ENCODING", "GST_TAG_ENCODING", NULL
};
gchar *val;
- val = gst_tag_freeform_string_to_utf8 ((gchar *) data, tsize, env_vars);
+ val = gst_tag_freeform_string_to_utf8 ((gchar *) ptr, tsize, env_vars);
if (val) {
gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, type, val, NULL);
if (tsize & 1) {
tsize++;
- if (tsize > size)
- tsize = size;
+ if (tsize > left)
+ tsize = left;
}
- data += tsize;
- size -= tsize;
+ ptr += tsize;
+ left -= tsize;
}
if (!gst_tag_list_is_empty (taglist)) {
*_taglist = NULL;
gst_tag_list_free (taglist);
}
+ gst_buffer_unmap (buf, data, size);
return;
}
static gboolean gst_base_rtp_payload_audio_handle_event (GstPad * pad,
GstEvent * event);
-GST_BOILERPLATE (GstBaseRTPAudioPayload, gst_base_rtp_audio_payload,
- GstBaseRTPPayload, GST_TYPE_BASE_RTP_PAYLOAD);
-
-static void
-gst_base_rtp_audio_payload_base_init (gpointer klass)
-{
-}
+#define gst_base_rtp_audio_payload_parent_class parent_class
+G_DEFINE_TYPE (GstBaseRTPAudioPayload, gst_base_rtp_audio_payload,
+ GST_TYPE_BASE_RTP_PAYLOAD);
static void
gst_base_rtp_audio_payload_class_init (GstBaseRTPAudioPayloadClass * klass)
}
static void
-gst_base_rtp_audio_payload_init (GstBaseRTPAudioPayload * payload,
- GstBaseRTPAudioPayloadClass * klass)
+gst_base_rtp_audio_payload_init (GstBaseRTPAudioPayload * payload)
{
payload->priv = GST_BASE_RTP_AUDIO_PAYLOAD_GET_PRIVATE (payload);
{
GstBaseRTPPayload *basepayload;
GstBaseRTPAudioPayloadPrivate *priv;
+ GstRTPBuffer rtp;
basepayload = GST_BASE_RTP_PAYLOAD_CAST (payload);
priv = payload->priv;
/* set payload type */
- gst_rtp_buffer_set_payload_type (buffer, basepayload->pt);
+ gst_rtp_buffer_map (buffer, GST_MAP_WRITE, &rtp);
+ gst_rtp_buffer_set_payload_type (&rtp, basepayload->pt);
/* set marker bit for disconts */
if (priv->discont) {
GST_DEBUG_OBJECT (payload, "Setting marker and DISCONT");
- gst_rtp_buffer_set_marker (buffer, TRUE);
+ gst_rtp_buffer_set_marker (&rtp, TRUE);
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
priv->discont = FALSE;
}
+ gst_rtp_buffer_unmap (&rtp);
+
GST_BUFFER_TIMESTAMP (buffer) = timestamp;
/* get the offset in RTP time */
GstBuffer *outbuf;
guint8 *payload;
GstFlowReturn ret;
+ GstRTPBuffer rtp;
basepayload = GST_BASE_RTP_PAYLOAD (baseaudiopayload);
outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0);
/* copy payload */
- payload = gst_rtp_buffer_get_payload (outbuf);
+ gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+ payload = gst_rtp_buffer_get_payload (&rtp);
memcpy (payload, data, payload_len);
+ gst_rtp_buffer_unmap (&rtp);
/* set metadata */
gst_base_rtp_audio_payload_set_meta (baseaudiopayload, outbuf, payload_len,
priv = baseaudiopayload->priv;
basepayload = GST_BASE_RTP_PAYLOAD (baseaudiopayload);
- payload_len = GST_BUFFER_SIZE (buffer);
+ payload_len = gst_buffer_get_size (buffer);
GST_DEBUG_OBJECT (baseaudiopayload, "Pushing %d bytes ts %" GST_TIME_FORMAT,
payload_len, GST_TIME_ARGS (timestamp));
if (priv->buffer_list) {
GstBufferList *list;
- GstBufferListIterator *it;
+ guint i, len;
list = gst_buffer_list_new ();
- it = gst_buffer_list_iterate (list);
+ len = gst_buffer_list_len (list);
- /* add both buffers to the buffer list */
- gst_buffer_list_iterator_add_group (it);
- gst_buffer_list_iterator_add (it, outbuf);
- gst_buffer_list_iterator_add (it, buffer);
-
- gst_buffer_list_iterator_free (it);
+ for (i = 0; i < len; i++) {
+ /* FIXME */
+ g_warning ("bufferlist not implemented");
+ gst_buffer_list_add (list, outbuf);
+ gst_buffer_list_add (list, buffer);
+ }
GST_DEBUG_OBJECT (baseaudiopayload, "Pushing list %p", list);
ret = gst_basertppayload_push_list (basepayload, list);
} else {
+ GstRTPBuffer rtp;
+
/* copy payload */
- payload = gst_rtp_buffer_get_payload (outbuf);
- memcpy (payload, GST_BUFFER_DATA (buffer), payload_len);
+ gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+ payload = gst_rtp_buffer_get_payload (&rtp);
+ gst_buffer_extract (buffer, 0, payload, payload_len);
+ gst_rtp_buffer_unmap (&rtp);
+
gst_buffer_unref (buffer);
GST_DEBUG_OBJECT (baseaudiopayload, "Pushing buffer %p", outbuf);
gst_base_rtp_audio_payload_push_buffer (baseaudiopayload, buffer,
timestamp);
} else {
+ GstRTPBuffer rtp;
+
/* create buffer to hold the payload */
outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0);
/* copy payload */
- payload = gst_rtp_buffer_get_payload (outbuf);
+ gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+ payload = gst_rtp_buffer_get_payload (&rtp);
gst_adapter_copy (adapter, payload, 0, payload_len);
gst_adapter_flush (adapter, payload_len);
+ gst_rtp_buffer_unmap (&rtp);
/* set metadata */
gst_base_rtp_audio_payload_set_meta (baseaudiopayload, outbuf, payload_len,
"Calculated min_payload_len %u and max_payload_len %u",
min_payload_len, max_payload_len);
- size = GST_BUFFER_SIZE (buffer);
+ size = gst_buffer_get_size (buffer);
/* shortcut, we don't need to use the adapter when the packet can be pushed
* through directly. */
#include "gstbasertpdepayload.h"
-#ifdef GST_DISABLE_DEPRECATED
-#define QUEUE_LOCK_INIT(base) (g_static_rec_mutex_init(&base->queuelock))
-#define QUEUE_LOCK_FREE(base) (g_static_rec_mutex_free(&base->queuelock))
-#define QUEUE_LOCK(base) (g_static_rec_mutex_lock(&base->queuelock))
-#define QUEUE_UNLOCK(base) (g_static_rec_mutex_unlock(&base->queuelock))
-#else
-/* otherwise it's already been defined in the header (FIXME 0.11)*/
-#endif
-
GST_DEBUG_CATEGORY_STATIC (basertpdepayload_debug);
#define GST_CAT_DEFAULT (basertpdepayload_debug)
LAST_SIGNAL
};
-#define DEFAULT_QUEUE_DELAY 0
-
enum
{
PROP_0,
- PROP_QUEUE_DELAY,
PROP_LAST
};
static gboolean gst_base_rtp_depayload_handle_event (GstBaseRTPDepayload *
filter, GstEvent * event);
-GST_BOILERPLATE (GstBaseRTPDepayload, gst_base_rtp_depayload, GstElement,
- GST_TYPE_ELEMENT);
+static GstElementClass *parent_class = NULL;
+static void gst_base_rtp_depayload_class_init (GstBaseRTPDepayloadClass *
+ klass);
+static void gst_base_rtp_depayload_init (GstBaseRTPDepayload * basertppayload,
+ GstBaseRTPDepayloadClass * klass);
-static void
-gst_base_rtp_depayload_base_init (gpointer klass)
+GType
+gst_base_rtp_depayload_get_type (void)
{
- /*GstElementClass *element_class = GST_ELEMENT_CLASS (klass); */
+ static GType base_rtp_depayload_type = 0;
+
+ if (g_once_init_enter ((gsize *) & base_rtp_depayload_type)) {
+ static const GTypeInfo base_rtp_depayload_info = {
+ sizeof (GstBaseRTPDepayloadClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) gst_base_rtp_depayload_class_init,
+ NULL,
+ NULL,
+ sizeof (GstBaseRTPDepayload),
+ 0,
+ (GInstanceInitFunc) gst_base_rtp_depayload_init,
+ };
+
+ g_once_init_leave ((gsize *) & base_rtp_depayload_type,
+ g_type_register_static (GST_TYPE_ELEMENT, "GstBaseRTPDepayload",
+ &base_rtp_depayload_info, G_TYPE_FLAG_ABSTRACT));
+ }
+ return base_rtp_depayload_type;
}
static void
gobject_class->set_property = gst_base_rtp_depayload_set_property;
gobject_class->get_property = gst_base_rtp_depayload_get_property;
- /**
- * GstBaseRTPDepayload::queue-delay
- *
- * Control the amount of packets to buffer.
- *
- * Deprecated: Use a jitterbuffer or RTP session manager to delay packet
- * playback. This property has no effect anymore since 0.10.15.
- */
-#ifndef GST_REMOVE_DEPRECATED
- g_object_class_install_property (gobject_class, PROP_QUEUE_DELAY,
- g_param_spec_uint ("queue-delay", "Queue Delay",
- "Amount of ms to queue/buffer, deprecated", 0, G_MAXUINT,
- DEFAULT_QUEUE_DELAY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-#endif
-
gstelement_class->change_state = gst_base_rtp_depayload_change_state;
klass->set_gst_timestamp = gst_base_rtp_depayload_set_gst_timestamp;
gst_pad_use_fixed_caps (filter->srcpad);
gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
- filter->queue = g_queue_new ();
- filter->queue_delay = DEFAULT_QUEUE_DELAY;
-
gst_segment_init (&filter->segment, GST_FORMAT_UNDEFINED);
}
static void
gst_base_rtp_depayload_finalize (GObject * object)
{
- GstBaseRTPDepayload *filter = GST_BASE_RTP_DEPAYLOAD (object);
-
- g_queue_free (filter->queue);
-
G_OBJECT_CLASS (parent_class)->finalize (object);
}
guint32 rtptime;
gboolean discont;
gint gap;
+ GstRTPBuffer rtp;
filter = GST_BASE_RTP_DEPAYLOAD (GST_OBJECT_PARENT (pad));
priv = filter->priv;
priv->timestamp = timestamp;
priv->duration = GST_BUFFER_DURATION (in);
- seqnum = gst_rtp_buffer_get_seq (in);
- rtptime = gst_rtp_buffer_get_timestamp (in);
+ gst_rtp_buffer_map (in, GST_MAP_READ, &rtp);
+ seqnum = gst_rtp_buffer_get_seq (&rtp);
+ rtptime = gst_rtp_buffer_get_timestamp (&rtp);
+ gst_rtp_buffer_unmap (&rtp);
+
discont = FALSE;
GST_LOG_OBJECT (filter, "discont %d, seqnum %u, rtptime %u, timestamp %"
/* we detected a seqnum discont but the buffer was not flagged with a discont,
* set the discont flag so that the subclass can throw away old data. */
priv->discont = TRUE;
- in = gst_buffer_make_metadata_writable (in);
+ in = gst_buffer_make_writable (in);
GST_BUFFER_FLAG_SET (in, GST_BUFFER_FLAG_DISCONT);
}
not_negotiated:
{
/* this is not fatal but should be filtered earlier */
- if (GST_BUFFER_CAPS (in) == NULL) {
- GST_ELEMENT_ERROR (filter, CORE, NEGOTIATION,
- ("No RTP format was negotiated."),
- ("Input buffers need to have RTP caps set on them. This is usually "
- "achieved by setting the 'caps' property of the upstream source "
- "element (often udpsrc or appsrc), or by putting a capsfilter "
- "element before the depayloader and setting the 'caps' property "
- "on that. Also see http://cgit.freedesktop.org/gstreamer/"
- "gst-plugins-good/tree/gst/rtp/README"));
- } else {
- GST_ELEMENT_ERROR (filter, CORE, NEGOTIATION,
- ("No RTP format was negotiated."),
- ("RTP caps on input buffer were rejected, most likely because they "
- "were incomplete or contained wrong values. Check the debug log "
- "for more information."));
- }
+ GST_ELEMENT_ERROR (filter, CORE, NEGOTIATION,
+ ("No RTP format was negotiated."),
+ ("Input buffers need to have RTP caps set on them. This is usually "
+ "achieved by setting the 'caps' property of the upstream source "
+ "element (often udpsrc or appsrc), or by putting a capsfilter "
+ "element before the depayloader and setting the 'caps' property "
+ "on that. Also see http://cgit.freedesktop.org/gstreamer/"
+ "gst-plugins-good/tree/gst/rtp/README"));
gst_buffer_unref (in);
return GST_FLOW_NOT_NEGOTIATED;
}
filter->need_newsegment = TRUE;
filter->priv->next_seqnum = -1;
break;
- case GST_EVENT_NEWSEGMENT:
+ case GST_EVENT_SEGMENT:
{
- gboolean update;
- gdouble rate;
- GstFormat fmt;
- gint64 start, stop, position;
-
- gst_event_parse_new_segment (event, &update, &rate, &fmt, &start, &stop,
- &position);
-
- gst_segment_set_newsegment (&filter->segment, update, rate, fmt,
- start, stop, position);
-
+ gst_event_copy_segment (event, &filter->segment);
/* don't pass the event downstream, we generate our own segment including
* the NTP time and other things we receive in caps */
forward = FALSE;
GstEvent *event;
GstClockTime stop;
GstBaseRTPDepayloadPrivate *priv;
+ GstSegment segment;
priv = filter->priv;
else
stop = -1;
- event = gst_event_new_new_segment_full (update, priv->play_speed,
- priv->play_scale, GST_FORMAT_TIME, position, stop,
- position + priv->npt_start);
+ gst_segment_init (&segment, GST_FORMAT_TIME);
+ segment.rate = priv->play_speed;
+ segment.applied_rate = priv->play_scale;
+ segment.start = 0;
+ segment.stop = stop;
+ segment.time = priv->npt_start;
+ segment.position = position;
+
+ event = gst_event_new_segment (&segment);
return event;
}
{
GstBaseRTPDepayload *depayload;
GstBaseRTPDepayloadClass *bclass;
- GstCaps *caps;
gboolean do_ts;
gboolean rtptime;
} HeaderData;
-static GstBufferListItem
-set_headers (GstBuffer ** buffer, guint group, guint idx, HeaderData * data)
+static gboolean
+set_headers (GstBuffer ** buffer, guint idx, HeaderData * data)
{
GstBaseRTPDepayload *depayload = data->depayload;
- *buffer = gst_buffer_make_metadata_writable (*buffer);
- gst_buffer_set_caps (*buffer, data->caps);
+ *buffer = gst_buffer_make_writable (*buffer);
/* set the timestamp if we must and can */
if (data->bclass->set_gst_timestamp && data->do_ts)
depayload->priv->discont = FALSE;
}
- return GST_BUFFER_LIST_SKIP_GROUP;
+ return TRUE;
}
static GstFlowReturn
HeaderData data;
data.depayload = filter;
- data.caps = GST_PAD_CAPS (filter->srcpad);
data.rtptime = rtptime;
data.do_ts = do_ts;
data.bclass = GST_BASE_RTP_DEPAYLOAD_GET_CLASS (filter);
gst_buffer_list_foreach (*blist, (GstBufferListFunc) set_headers, &data);
} else {
GstBuffer **buf = obj;
- set_headers (buf, 0, 0, &data);
+ set_headers (buf, 0, &data);
}
/* if this is the first buffer send a NEWSEGMENT */
filter = GST_BASE_RTP_DEPAYLOAD (object);
switch (prop_id) {
- case PROP_QUEUE_DELAY:
- filter->queue_delay = g_value_get_uint (value);
- break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
filter = GST_BASE_RTP_DEPAYLOAD (object);
switch (prop_id) {
- case PROP_QUEUE_DELAY:
- g_value_set_uint (value, filter->queue_delay);
- break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
#define GST_BASE_RTP_DEPAYLOAD_SINKPAD(depayload) (GST_BASE_RTP_DEPAYLOAD (depayload)->sinkpad)
#define GST_BASE_RTP_DEPAYLOAD_SRCPAD(depayload) (GST_BASE_RTP_DEPAYLOAD (depayload)->srcpad)
-#ifndef GST_DISABLE_DEPRECATED
-/* this was presumably never meant to be public API, or should at least
- * have been prefixed if it was. Don't use. (FIXME: remove in 0.11) */
-#define QUEUE_LOCK_INIT(base) (g_static_rec_mutex_init(&base->queuelock))
-#define QUEUE_LOCK_FREE(base) (g_static_rec_mutex_free(&base->queuelock))
-#define QUEUE_LOCK(base) (g_static_rec_mutex_lock(&base->queuelock))
-#define QUEUE_UNLOCK(base) (g_static_rec_mutex_unlock(&base->queuelock))
-#endif
-
typedef struct _GstBaseRTPDepayload GstBaseRTPDepayload;
typedef struct _GstBaseRTPDepayloadClass GstBaseRTPDepayloadClass;
typedef struct _GstBaseRTPDepayloadPrivate GstBaseRTPDepayloadPrivate;
GstPad *sinkpad, *srcpad;
-#ifndef GST_REMOVE_DEPRECATED
- /* lock to protect the queue, deprecated */
- GStaticRecMutex queuelock;
-
- /* deprecated */
- gboolean thread_running;
- /* the releaser thread, deprecated */
- GThread *thread;
-#endif
-
/* this attribute must be set by the child */
guint clock_rate;
-#ifndef GST_REMOVE_DEPRECATED
- /* this value can be modified by the child if needed, deprecated */
- guint queue_delay;
-#endif
-
- /* we will queue up to RTP_QUEUEDELAY ms of packets,
- * reordering them if necessary
- * dropping any packets that are more than
- * RTP_QUEUEDELAY ms late, deprecated */
- GQueue *queue;
-
GstSegment segment;
gboolean need_newsegment;
/* virtuals, inform the subclass of the caps. */
gboolean (*set_caps) (GstBaseRTPDepayload *filter, GstCaps *caps);
- /* non-pure function, default implementation in base class
- * this does buffering, reordering and dropping, deprecated */
- GstFlowReturn (*add_to_queue) (GstBaseRTPDepayload *filter, GstBuffer *in);
-
/* pure virtual function, child must use this to process incoming
* rtp packets. If the child returns a buffer without a valid timestamp,
* the timestamp of @in will be applied to the result buffer and the
static void gst_basertppayload_finalize (GObject * object);
static gboolean gst_basertppayload_sink_setcaps (GstPad * pad, GstCaps * caps);
-static GstCaps *gst_basertppayload_sink_getcaps (GstPad * pad);
+static GstCaps *gst_basertppayload_sink_getcaps (GstPad * pad,
+ GstCaps * filter);
static gboolean gst_basertppayload_event (GstPad * pad, GstEvent * event);
static GstFlowReturn gst_basertppayload_chain (GstPad * pad,
GstBuffer * buffer);
{
static GType basertppayload_type = 0;
- if (!basertppayload_type) {
+ if (g_once_init_enter ((gsize *) & basertppayload_type)) {
static const GTypeInfo basertppayload_info = {
sizeof (GstBaseRTPPayloadClass),
(GBaseInitFunc) gst_basertppayload_base_init,
(GInstanceInitFunc) gst_basertppayload_init,
};
- basertppayload_type =
+ g_once_init_leave ((gsize *) & basertppayload_type,
g_type_register_static (GST_TYPE_ELEMENT, "GstBaseRTPPayload",
- &basertppayload_info, G_TYPE_FLAG_ABSTRACT);
+ &basertppayload_info, G_TYPE_FLAG_ABSTRACT));
}
return basertppayload_type;
}
}
static GstCaps *
-gst_basertppayload_sink_getcaps (GstPad * pad)
+gst_basertppayload_sink_getcaps (GstPad * pad, GstCaps * filter)
{
GstBaseRTPPayload *basertppayload;
GstBaseRTPPayloadClass *basertppayload_class;
basertppayload_class = GST_BASE_RTP_PAYLOAD_GET_CLASS (basertppayload);
if (basertppayload_class->get_caps)
- caps = basertppayload_class->get_caps (basertppayload, pad);
+ caps = basertppayload_class->get_caps (basertppayload, pad, filter);
if (!caps) {
caps = GST_PAD_TEMPLATE_CAPS (GST_PAD_PAD_TEMPLATE (pad));
"using pad template %p with caps %p %" GST_PTR_FORMAT,
GST_PAD_PAD_TEMPLATE (pad), caps, caps);
- caps = gst_caps_ref (caps);
+ if (filter)
+ caps = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+ else
+ caps = gst_caps_ref (caps);
}
gst_object_unref (basertppayload);
res = gst_pad_event_default (pad, event);
gst_segment_init (&basertppayload->segment, GST_FORMAT_UNDEFINED);
break;
- case GST_EVENT_NEWSEGMENT:
+ case GST_EVENT_SEGMENT:
{
- gboolean update;
- gdouble rate, arate;
- GstFormat fmt;
- gint64 start, stop, position;
GstSegment *segment;
segment = &basertppayload->segment;
-
- gst_event_parse_new_segment_full (event, &update, &rate, &arate, &fmt,
- &start, &stop, &position);
- gst_segment_set_newsegment_full (segment, update, rate, arate, fmt, start,
- stop, position);
+ gst_event_copy_segment (event, segment);
GST_DEBUG_OBJECT (basertppayload,
- "configured NEWSEGMENT update %d, rate %lf, applied rate %lf, "
- "format %d, "
- "%" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %"
- G_GINT64_FORMAT ", accum %" G_GINT64_FORMAT, update, rate, arate,
- segment->format, segment->start, segment->stop, segment->time,
- segment->accum);
+ "configured SEGMENT %" GST_SEGMENT_FORMAT, segment);
/* fallthrough */
}
default:
payload->abidata.ABI.ptime = 0;
/* the peer caps can override some of the defaults */
- peercaps = gst_pad_peer_get_caps (payload->srcpad);
+ peercaps = gst_pad_peer_get_caps (payload->srcpad, srccaps);
if (peercaps == NULL) {
/* no peer caps, just add the other properties */
gst_caps_set_simple (srccaps,
gint pt;
guint max_ptime, ptime;
- /* peer provides caps we can use to fixate, intersect. This always returns a
- * writable caps. */
- temp = gst_caps_intersect (srccaps, peercaps);
+ /* peer provides caps we can use to fixate. They are already intersected
+ * with our srccaps, just make them writable */
+ temp = gst_caps_make_writable (peercaps);
gst_caps_unref (srccaps);
- gst_caps_unref (peercaps);
if (gst_caps_is_empty (temp)) {
gst_caps_unref (temp);
guint32 ssrc;
guint16 seqnum;
guint8 pt;
- GstCaps *caps;
GstClockTime timestamp;
guint64 offset;
guint32 rtptime;
} HeaderData;
-static GstBufferListItem
-find_timestamp (GstBuffer ** buffer, guint group, guint idx, HeaderData * data)
+static gboolean
+find_timestamp (GstBuffer ** buffer, guint idx, HeaderData * data)
{
data->timestamp = GST_BUFFER_TIMESTAMP (*buffer);
data->offset = GST_BUFFER_OFFSET (*buffer);
/* stop when we find a timestamp. We take whatever offset is associated with
* the timestamp (if any) to do perfect timestamps when we need to. */
if (data->timestamp != -1)
- return GST_BUFFER_LIST_END;
+ return FALSE;
else
- return GST_BUFFER_LIST_CONTINUE;
+ return TRUE;
}
-static GstBufferListItem
+static gboolean
set_headers (GstBuffer ** buffer, guint group, guint idx, HeaderData * data)
{
- gst_rtp_buffer_set_ssrc (*buffer, data->ssrc);
- gst_rtp_buffer_set_payload_type (*buffer, data->pt);
- gst_rtp_buffer_set_seq (*buffer, data->seqnum);
- gst_rtp_buffer_set_timestamp (*buffer, data->rtptime);
- gst_buffer_set_caps (*buffer, data->caps);
+ GstRTPBuffer rtp;
+
+ gst_rtp_buffer_map (*buffer, GST_MAP_WRITE, &rtp);
+ gst_rtp_buffer_set_ssrc (&rtp, data->ssrc);
+ gst_rtp_buffer_set_payload_type (&rtp, data->pt);
+ gst_rtp_buffer_set_seq (&rtp, data->seqnum);
+ gst_rtp_buffer_set_timestamp (&rtp, data->rtptime);
+ gst_rtp_buffer_unmap (&rtp);
+
/* increment the seqnum for each buffer */
data->seqnum++;
- return GST_BUFFER_LIST_SKIP_GROUP;
+ return TRUE;
}
/* Updates the SSRC, payload type, seqnum and timestamp of the RTP buffer
data.seqnum = payload->seqnum;
data.ssrc = payload->current_ssrc;
data.pt = payload->pt;
- data.caps = GST_PAD_CAPS (payload->srcpad);
/* find the first buffer with a timestamp */
if (is_list) {
GST_LOG_OBJECT (payload,
"Preparing to push packet with size %d, seq=%d, rtptime=%u, timestamp %"
GST_TIME_FORMAT, (is_list) ? -1 :
- GST_BUFFER_SIZE (GST_BUFFER (obj)), payload->seqnum, data.rtptime,
+ gst_buffer_get_size (GST_BUFFER (obj)), payload->seqnum, data.rtptime,
GST_TIME_ARGS (data.timestamp));
if (g_atomic_int_compare_and_exchange (&payload->
GstFlowReturn (*handle_buffer) (GstBaseRTPPayload *payload,
GstBuffer *buffer);
gboolean (*handle_event) (GstPad * pad, GstEvent * event);
- GstCaps * (*get_caps) (GstBaseRTPPayload *payload, GstPad * pad);
+ GstCaps * (*get_caps) (GstBaseRTPPayload *payload, GstPad * pad, GstCaps * filter);
/*< private >*/
gpointer _gst_reserved[GST_PADDING-2];
g_return_val_if_fail (len > 0, NULL);
result = gst_buffer_new ();
-
- GST_BUFFER_MALLOCDATA (result) = data;
- GST_BUFFER_DATA (result) = data;
- GST_BUFFER_SIZE (result) = len;
+ gst_buffer_take_memory (result,
+ gst_memory_new_wrapped (0, data, g_free, len, 0, len));
return result;
}
gboolean
gst_rtcp_buffer_validate (GstBuffer * buffer)
{
+ gboolean res;
guint8 *data;
- guint len;
+ gsize len;
g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
- data = GST_BUFFER_DATA (buffer);
- len = GST_BUFFER_SIZE (buffer);
+ data = gst_buffer_map (buffer, &len, NULL, GST_MAP_READ);
+ res = gst_rtcp_buffer_validate_data (data, len);
+ gst_buffer_unmap (buffer, data, len);
- return gst_rtcp_buffer_validate_data (data, len);
+ return res;
}
/**
g_return_val_if_fail (mtu > 0, NULL);
result = gst_buffer_new ();
- GST_BUFFER_MALLOCDATA (result) = g_malloc0 (mtu);
- GST_BUFFER_DATA (result) = GST_BUFFER_MALLOCDATA (result);
- GST_BUFFER_SIZE (result) = mtu;
+ gst_buffer_take_memory (result,
+ gst_memory_new_wrapped (0, g_malloc0 (mtu), g_free, mtu, 0, mtu));
return result;
}
/**
- * gst_rtcp_buffer_end:
+ * gst_rtcp_buffer_map:
* @buffer: a buffer with an RTCP packet
+ * @flags: flags for the mapping
+ * @rtcp: resulting #GstRTCPBuffer
*
- * Finish @buffer after being constructured. This function is usually called
- * after gst_rtcp_buffer_new() and after adding the RTCP items to the new buffer.
+ * Open @buffer for reading or writing, depending on @flags. The resulting RTCP
+ * buffer state is stored in @rtcp.
+ */
+gboolean
+gst_rtcp_buffer_map (GstBuffer * buffer, GstMapFlags flags,
+ GstRTCPBuffer * rtcp)
+{
+ g_return_val_if_fail (rtcp != NULL, FALSE);
+ g_return_val_if_fail (rtcp->buffer == NULL, FALSE);
+ g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
+
+ rtcp->buffer = buffer;
+ rtcp->flags = flags;
+ rtcp->data = gst_buffer_map (buffer, &rtcp->size, &rtcp->maxsize, flags);
+
+ return TRUE;
+}
+
+/**
+ * gst_rtcp_buffer_unmap:
+ * @buffer: a buffer with an RTCP packet
+ *
+ * Finish @rtcp after being constructured. This function is usually called
+ * after gst_rtcp_buffer_map() and after adding the RTCP items to the new buffer.
*
* The function adjusts the size of @buffer with the total length of all the
* added packets.
*/
-void
-gst_rtcp_buffer_end (GstBuffer * buffer)
+gboolean
+gst_rtcp_buffer_unmap (GstRTCPBuffer * rtcp)
{
+ gboolean res;
GstRTCPPacket packet;
- g_return_if_fail (GST_IS_BUFFER (buffer));
+ g_return_val_if_fail (rtcp != NULL, FALSE);
+ g_return_val_if_fail (GST_IS_BUFFER (rtcp->buffer), FALSE);
/* move to the first free space */
- if (gst_rtcp_buffer_get_first_packet (buffer, &packet))
+ if (gst_rtcp_buffer_get_first_packet (rtcp, &packet))
while (gst_rtcp_packet_move_to_next (&packet));
/* shrink size */
- GST_BUFFER_SIZE (buffer) = packet.offset;
+ res = gst_buffer_unmap (rtcp->buffer, rtcp->data, packet.offset);
+ rtcp->buffer = NULL;
+
+ return res;
}
/**
* Returns: the number of RTCP packets in @buffer.
*/
guint
-gst_rtcp_buffer_get_packet_count (GstBuffer * buffer)
+gst_rtcp_buffer_get_packet_count (GstRTCPBuffer * rtcp)
{
GstRTCPPacket packet;
guint count;
- g_return_val_if_fail (GST_IS_BUFFER (buffer), 0);
+ g_return_val_if_fail (rtcp != NULL, 0);
+ g_return_val_if_fail (GST_IS_BUFFER (rtcp->buffer), 0);
count = 0;
- if (gst_rtcp_buffer_get_first_packet (buffer, &packet)) {
+ if (gst_rtcp_buffer_get_first_packet (rtcp, &packet)) {
do {
count++;
} while (gst_rtcp_packet_move_to_next (&packet));
guint offset;
g_return_val_if_fail (packet != NULL, FALSE);
- g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE);
- data = GST_BUFFER_DATA (packet->buffer);
- size = GST_BUFFER_SIZE (packet->buffer);
+ data = packet->rtcp->data;
+ size = packet->rtcp->size;
offset = packet->offset;
* Returns: TRUE if the packet existed in @buffer.
*/
gboolean
-gst_rtcp_buffer_get_first_packet (GstBuffer * buffer, GstRTCPPacket * packet)
+gst_rtcp_buffer_get_first_packet (GstRTCPBuffer * rtcp, GstRTCPPacket * packet)
{
- g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
+ g_return_val_if_fail (rtcp != NULL, FALSE);
+ g_return_val_if_fail (GST_IS_BUFFER (rtcp->buffer), FALSE);
g_return_val_if_fail (packet != NULL, FALSE);
/* init to 0 */
- packet->buffer = buffer;
+ packet->rtcp = rtcp;
packet->offset = 0;
packet->type = GST_RTCP_TYPE_INVALID;
{
g_return_val_if_fail (packet != NULL, FALSE);
g_return_val_if_fail (packet->type != GST_RTCP_TYPE_INVALID, FALSE);
- g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE);
/* if we have a padding or invalid packet, it must be the last,
* return FALSE */
* if the max mtu is exceeded for the buffer.
*/
gboolean
-gst_rtcp_buffer_add_packet (GstBuffer * buffer, GstRTCPType type,
+gst_rtcp_buffer_add_packet (GstRTCPBuffer * rtcp, GstRTCPType type,
GstRTCPPacket * packet)
{
guint len, size;
guint8 *data;
gboolean result;
- g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
+ g_return_val_if_fail (rtcp != NULL, FALSE);
+ g_return_val_if_fail (GST_IS_BUFFER (rtcp->buffer), FALSE);
g_return_val_if_fail (type != GST_RTCP_TYPE_INVALID, FALSE);
g_return_val_if_fail (packet != NULL, FALSE);
/* find free space */
- if (gst_rtcp_buffer_get_first_packet (buffer, packet))
+ if (gst_rtcp_buffer_get_first_packet (rtcp, packet))
while (gst_rtcp_packet_move_to_next (packet));
- size = GST_BUFFER_SIZE (buffer);
+ size = rtcp->size;
/* packet->offset is now pointing to the next free offset in the buffer to
* start a compount packet. Next we figure out if we have enough free space in
if (packet->offset + len >= size)
goto no_space;
- data = GST_BUFFER_DATA (buffer) + packet->offset;
+ data = rtcp->data + packet->offset;
data[0] = (GST_RTCP_VERSION << 6);
data[1] = type;
offset = packet->offset + (packet->length << 2) + 4;
/* Overwrite this packet with the rest of the data */
- memmove (GST_BUFFER_DATA (packet->buffer) + packet->offset,
- GST_BUFFER_DATA (packet->buffer) + offset,
- GST_BUFFER_SIZE (packet->buffer) - offset);
+ memmove (packet->rtcp->data + packet->offset,
+ packet->rtcp->data + offset, packet->rtcp->size - offset);
/* try to read next header */
ret = read_packet_header (packet);
g_return_if_fail (packet != NULL);
g_return_if_fail (packet->type == GST_RTCP_TYPE_SR);
- g_return_if_fail (GST_IS_BUFFER (packet->buffer));
- data = GST_BUFFER_DATA (packet->buffer);
+ data = packet->rtcp->data;
/* skip header */
data += packet->offset + 4;
g_return_if_fail (packet != NULL);
g_return_if_fail (packet->type == GST_RTCP_TYPE_SR);
- g_return_if_fail (GST_IS_BUFFER (packet->buffer));
- data = GST_BUFFER_DATA (packet->buffer);
+ data = packet->rtcp->data;
/* skip header */
data += packet->offset + 4;
g_return_val_if_fail (packet != NULL, 0);
g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RR, 0);
- g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0);
- data = GST_BUFFER_DATA (packet->buffer);
+ data = packet->rtcp->data;
/* skip header */
data += packet->offset + 4;
g_return_if_fail (packet != NULL);
g_return_if_fail (packet->type == GST_RTCP_TYPE_RR);
- g_return_if_fail (GST_IS_BUFFER (packet->buffer));
- data = GST_BUFFER_DATA (packet->buffer);
+ data = packet->rtcp->data;
/* skip header */
data += packet->offset + 4;
g_return_val_if_fail (packet != NULL, 0);
g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RR ||
packet->type == GST_RTCP_TYPE_SR, 0);
- g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0);
return packet->count;
}
g_return_if_fail (packet != NULL);
g_return_if_fail (packet->type == GST_RTCP_TYPE_RR ||
packet->type == GST_RTCP_TYPE_SR);
- g_return_if_fail (GST_IS_BUFFER (packet->buffer));
- data = GST_BUFFER_DATA (packet->buffer);
+ data = packet->rtcp->data;
/* skip header */
data += packet->offset + 4;
g_return_val_if_fail (packet != NULL, FALSE);
g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RR ||
packet->type == GST_RTCP_TYPE_SR, FALSE);
- g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE);
if (packet->count >= GST_RTCP_MAX_RB_COUNT)
goto no_space;
- data = GST_BUFFER_DATA (packet->buffer);
- size = GST_BUFFER_SIZE (packet->buffer);
+ data = packet->rtcp->data;
+ size = packet->rtcp->size;
/* skip header */
offset = packet->offset + 4;
g_return_if_fail (packet != NULL);
g_return_if_fail (packet->type == GST_RTCP_TYPE_RR ||
packet->type == GST_RTCP_TYPE_SR);
- g_return_if_fail (GST_IS_BUFFER (packet->buffer));
g_warning ("not implemented");
}
{
g_return_val_if_fail (packet != NULL, 0);
g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, 0);
- g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0);
return packet->count;
}
{
g_return_val_if_fail (packet != NULL, FALSE);
g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, FALSE);
- g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE);
packet->item_offset = 4;
packet->item_count = 0;
g_return_val_if_fail (packet != NULL, FALSE);
g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, FALSE);
- g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE);
/* if we are at the last item, we are done */
if (packet->item_count == packet->count)
return FALSE;
/* move to SDES */
- data = GST_BUFFER_DATA (packet->buffer);
+ data = packet->rtcp->data;
data += packet->offset;
/* move to item */
offset = packet->item_offset;
g_return_val_if_fail (packet != NULL, 0);
g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, 0);
- g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0);
/* move to SDES */
- data = GST_BUFFER_DATA (packet->buffer);
+ data = packet->rtcp->data;
data += packet->offset;
/* move to item */
data += packet->item_offset;
g_return_val_if_fail (packet != NULL, FALSE);
g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, FALSE);
- g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE);
/* move to SDES */
- data = GST_BUFFER_DATA (packet->buffer);
+ data = packet->rtcp->data;
data += packet->offset;
/* move to item */
offset = packet->item_offset;
g_return_val_if_fail (packet != NULL, FALSE);
g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, FALSE);
- g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE);
/* move to SDES */
- data = GST_BUFFER_DATA (packet->buffer);
+ data = packet->rtcp->data;
data += packet->offset;
/* move to item */
offset = packet->item_offset;
g_return_val_if_fail (packet != NULL, FALSE);
g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, FALSE);
- g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE);
/* move to SDES */
- bdata = GST_BUFFER_DATA (packet->buffer);
+ bdata = packet->rtcp->data;
bdata += packet->offset;
/* move to item */
offset = packet->item_offset;
g_return_val_if_fail (packet != NULL, FALSE);
g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, FALSE);
- g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE);
if (!gst_rtcp_packet_sdes_get_entry (packet, type, &tlen, &tdata))
return FALSE;
g_return_val_if_fail (packet != NULL, FALSE);
g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, FALSE);
- g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE);
/* increment item count when possible */
if (packet->count >= GST_RTCP_MAX_SDES_ITEM_COUNT)
gst_rtcp_packet_sdes_next_item (packet);
/* move to SDES */
- data = GST_BUFFER_DATA (packet->buffer);
- size = GST_BUFFER_SIZE (packet->buffer);
+ data = packet->rtcp->data;
+ size = packet->rtcp->size;
data += packet->offset;
/* move to current item */
offset = packet->item_offset;
g_return_val_if_fail (packet != NULL, FALSE);
g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, FALSE);
- g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE);
/* move to SDES */
- bdata = GST_BUFFER_DATA (packet->buffer);
- size = GST_BUFFER_SIZE (packet->buffer);
+ bdata = packet->rtcp->data;
+ size = packet->rtcp->size;
bdata += packet->offset;
/* move to item */
offset = packet->item_offset;
g_return_val_if_fail (packet != NULL, 0);
g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, 0);
- g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0);
/* get amount of sources and check that we don't read too much */
sc = packet->count;
offset += packet->offset;
/* check if the packet is valid */
- if (offset + 4 > GST_BUFFER_SIZE (packet->buffer))
+ if (offset + 4 > packet->rtcp->size)
return 0;
- data = GST_BUFFER_DATA (packet->buffer);
+ data = packet->rtcp->data;
data += offset;
ssrc = GST_READ_UINT32_BE (data);
g_return_val_if_fail (packet != NULL, FALSE);
g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, FALSE);
- g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE);
if (packet->count >= GST_RTCP_MAX_BYE_SSRC_COUNT)
goto no_space;
- data = GST_BUFFER_DATA (packet->buffer);
- size = GST_BUFFER_SIZE (packet->buffer);
+ data = packet->rtcp->data;
+ size = packet->rtcp->size;
/* skip header */
offset = packet->offset + 4;
g_return_val_if_fail (packet != NULL, FALSE);
g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, FALSE);
- g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE);
res = TRUE;
for (i = 0; i < len && res; i++) {
offset += packet->offset;
/* check if the packet is valid */
- if (offset + 1 > GST_BUFFER_SIZE (packet->buffer))
+ if (offset + 1 > packet->rtcp->size)
return 0;
return offset;
g_return_val_if_fail (packet != NULL, 0);
g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, 0);
- g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0);
roffset = get_reason_offset (packet);
if (roffset == 0)
return 0;
- data = GST_BUFFER_DATA (packet->buffer);
+ data = packet->rtcp->data;
return data[roffset];
}
g_return_val_if_fail (packet != NULL, NULL);
g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, NULL);
- g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), NULL);
roffset = get_reason_offset (packet);
if (roffset == 0)
return NULL;
- data = GST_BUFFER_DATA (packet->buffer);
+ data = packet->rtcp->data;
/* get length of reason string */
len = data[roffset];
roffset += 1;
/* check if enough data to copy */
- if (roffset + len > GST_BUFFER_SIZE (packet->buffer))
+ if (roffset + len > packet->rtcp->size)
return NULL;
return g_strndup ((gconstpointer) (data + roffset), len);
g_return_val_if_fail (packet != NULL, FALSE);
g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, FALSE);
- g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE);
if (reason == NULL)
return TRUE;
if (roffset == 0)
goto no_space;
- data = GST_BUFFER_DATA (packet->buffer);
- size = GST_BUFFER_SIZE (packet->buffer);
+ data = packet->rtcp->data;
+ size = packet->rtcp->size;
/* we have 1 byte length and we need to pad to 4 bytes */
padded = ((len + 1) + 3) & ~3;
g_return_val_if_fail (packet != NULL, 0);
g_return_val_if_fail ((packet->type == GST_RTCP_TYPE_RTPFB ||
packet->type == GST_RTCP_TYPE_PSFB), 0);
- g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0);
- data = GST_BUFFER_DATA (packet->buffer);
+ data = packet->rtcp->data;
/* skip header */
data += packet->offset + 4;
g_return_if_fail (packet != NULL);
g_return_if_fail (packet->type == GST_RTCP_TYPE_RTPFB ||
packet->type == GST_RTCP_TYPE_PSFB);
- g_return_if_fail (GST_IS_BUFFER (packet->buffer));
- data = GST_BUFFER_DATA (packet->buffer);
+ data = packet->rtcp->data;
/* skip header */
data += packet->offset + 4;
g_return_val_if_fail (packet != NULL, 0);
g_return_val_if_fail ((packet->type == GST_RTCP_TYPE_RTPFB ||
packet->type == GST_RTCP_TYPE_PSFB), 0);
- g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0);
- data = GST_BUFFER_DATA (packet->buffer);
+ data = packet->rtcp->data;
/* skip header and sender ssrc */
data += packet->offset + 8;
g_return_if_fail (packet != NULL);
g_return_if_fail (packet->type == GST_RTCP_TYPE_RTPFB ||
packet->type == GST_RTCP_TYPE_PSFB);
- g_return_if_fail (GST_IS_BUFFER (packet->buffer));
- data = GST_BUFFER_DATA (packet->buffer);
+ data = packet->rtcp->data;
/* skip header and sender ssrc */
data += packet->offset + 8;
g_return_if_fail (packet != NULL);
g_return_if_fail (packet->type == GST_RTCP_TYPE_RTPFB ||
packet->type == GST_RTCP_TYPE_PSFB);
- g_return_if_fail (GST_IS_BUFFER (packet->buffer));
- data = GST_BUFFER_DATA (packet->buffer);
+ data = packet->rtcp->data;
data[packet->offset] = (data[packet->offset] & 0xe0) | type;
packet->count = type;
g_return_val_if_fail (packet != NULL, 0);
g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RTPFB ||
packet->type == GST_RTCP_TYPE_PSFB, 0);
- g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0);
- data = GST_BUFFER_DATA (packet->buffer) + packet->offset + 2;
+ data = packet->rtcp->data + packet->offset + 2;
return GST_READ_UINT16_BE (data) - 2;
}
g_return_val_if_fail (packet != NULL, FALSE);
g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RTPFB ||
packet->type == GST_RTCP_TYPE_PSFB, FALSE);
- g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE);
- if (GST_BUFFER_SIZE (packet->buffer) < packet->offset + ((wordlen + 3) * 4))
+ if (packet->rtcp->size < packet->offset + ((wordlen + 3) * 4))
return FALSE;
- data = GST_BUFFER_DATA (packet->buffer) + packet->offset + 2;
+ data = packet->rtcp->data + packet->offset + 2;
wordlen += 2;
GST_WRITE_UINT16_BE (data, wordlen);
g_return_val_if_fail (packet != NULL, NULL);
g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RTPFB ||
packet->type == GST_RTCP_TYPE_PSFB, NULL);
- g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), NULL);
- data = GST_BUFFER_DATA (packet->buffer) + packet->offset;
+ data = packet->rtcp->data + packet->offset;
if (GST_READ_UINT16_BE (data + 2) <= 2)
return NULL;
*/
#define GST_RTCP_VALID_VALUE ((GST_RTCP_VERSION << 14) | GST_RTCP_TYPE_SR)
+typedef struct _GstRTCPBuffer GstRTCPBuffer;
typedef struct _GstRTCPPacket GstRTCPPacket;
+struct _GstRTCPBuffer
+{
+ GstBuffer *buffer;
+
+ GstMapFlags flags;
+ guint8 *data;
+ gsize size;
+ gsize maxsize;
+};
+
/**
* GstRTCPPacket:
* @buffer: pointer to RTCP buffer
*/
struct _GstRTCPPacket
{
- GstBuffer *buffer;
- guint offset;
+ GstRTCPBuffer *rtcp;
+ guint offset;
/*< private >*/
gboolean padding; /* padding field of current packet */
gboolean gst_rtcp_buffer_validate (GstBuffer *buffer);
GstBuffer* gst_rtcp_buffer_new (guint mtu);
-void gst_rtcp_buffer_end (GstBuffer *buffer);
+
+gboolean gst_rtcp_buffer_map (GstBuffer *buffer, GstMapFlags flags, GstRTCPBuffer *rtcp);
+gboolean gst_rtcp_buffer_unmap (GstRTCPBuffer *rtcp);
/* adding/retrieving packets */
-guint gst_rtcp_buffer_get_packet_count (GstBuffer *buffer);
-gboolean gst_rtcp_buffer_get_first_packet (GstBuffer *buffer, GstRTCPPacket *packet);
+guint gst_rtcp_buffer_get_packet_count (GstRTCPBuffer *rtcp);
+gboolean gst_rtcp_buffer_get_first_packet (GstRTCPBuffer *rtcp, GstRTCPPacket *packet);
gboolean gst_rtcp_packet_move_to_next (GstRTCPPacket *packet);
-gboolean gst_rtcp_buffer_add_packet (GstBuffer *buffer, GstRTCPType type,
+gboolean gst_rtcp_buffer_add_packet (GstRTCPBuffer *rtcp, GstRTCPType type,
GstRTCPPacket *packet);
gboolean gst_rtcp_packet_remove (GstRTCPPacket *packet);
{
guint len;
guint8 *data;
+ GstMemory *mem;
g_return_if_fail (csrc_count <= 15);
g_return_if_fail (GST_IS_BUFFER (buffer));
len = GST_RTP_HEADER_LEN + csrc_count * sizeof (guint32)
+ payload_len + pad_len;
- data = g_malloc (len);
- GST_BUFFER_MALLOCDATA (buffer) = data;
- GST_BUFFER_DATA (buffer) = data;
- GST_BUFFER_SIZE (buffer) = len;
+ mem = gst_memory_new_alloc (len, 0);
+ data = gst_memory_map (mem, NULL, NULL, GST_MAP_WRITE);
/* fill in defaults */
GST_RTP_HEADER_VERSION (data) = GST_RTP_VERSION;
GST_RTP_HEADER_PADDING (data) = FALSE;
GST_RTP_HEADER_SEQ (data) = 0;
GST_RTP_HEADER_TIMESTAMP (data) = 0;
GST_RTP_HEADER_SSRC (data) = 0;
+ gst_memory_unmap (mem, data, len);
+
+ gst_buffer_take_memory (buffer, mem);
}
/**
* Returns: A newly allocated buffer with @data and of size @len.
*/
GstBuffer *
-gst_rtp_buffer_new_take_data (gpointer data, guint len)
+gst_rtp_buffer_new_take_data (gpointer data, gsize len)
{
GstBuffer *result;
g_return_val_if_fail (len > 0, NULL);
result = gst_buffer_new ();
-
- GST_BUFFER_MALLOCDATA (result) = data;
- GST_BUFFER_DATA (result) = data;
- GST_BUFFER_SIZE (result) = len;
+ gst_buffer_take_memory (result,
+ gst_memory_new_wrapped (0, data, g_free, len, 0, len));
return result;
}
* Returns: A newly allocated buffer with a copy of @data and of size @len.
*/
GstBuffer *
-gst_rtp_buffer_new_copy_data (gpointer data, guint len)
+gst_rtp_buffer_new_copy_data (gpointer data, gsize len)
{
return gst_rtp_buffer_new_take_data (g_memdup (data, len), len);
}
/**
* gst_rtp_buffer_new_allocate_len:
- * @packet_len: the total length of the packet
+ * @rtp_len: the total length of the packet
* @pad_len: the amount of padding
* @csrc_count: the number of CSRC entries
*
* Returns: TRUE if the data points to a valid RTP packet.
*/
gboolean
-gst_rtp_buffer_validate_data (guint8 * data, guint len)
+gst_rtp_buffer_validate_data (guint8 * data, gsize len)
{
return validate_data (data, len, NULL, 0);
}
gboolean
gst_rtp_buffer_validate (GstBuffer * buffer)
{
+ gboolean res;
guint8 *data;
- guint len;
+ gsize len;
g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
- data = GST_BUFFER_DATA (buffer);
- len = GST_BUFFER_SIZE (buffer);
+ data = gst_buffer_map (buffer, &len, NULL, GST_MAP_READ);
+ res = validate_data (data, len, NULL, 0);
+ gst_buffer_unmap (buffer, data, len);
- return validate_data (data, len, NULL, 0);
+ return res;
}
-/**
- * gst_rtp_buffer_list_validate:
- * @list: the buffer list to validate
- *
- * Check if all RTP packets in the @list are valid using validate_data().
- * Use this function to validate an list before using the other functions in
- * this module.
- *
- * Returns: TRUE if @list consists only of valid RTP packets.
- *
- * Since: 0.10.24
- */
gboolean
-gst_rtp_buffer_list_validate (GstBufferList * list)
+gst_rtp_buffer_map (GstBuffer * buffer, GstMapFlags flags, GstRTPBuffer * rtp)
{
- guint16 prev_seqnum = 0;
- GstBufferListIterator *it;
- guint i = 0;
-
- g_return_val_if_fail (GST_IS_BUFFER_LIST (list), FALSE);
-
- it = gst_buffer_list_iterate (list);
- g_return_val_if_fail (it != NULL, FALSE);
-
- /* iterate through all the RTP packets in the list */
- while (gst_buffer_list_iterator_next_group (it)) {
- GstBuffer *rtpbuf;
- GstBuffer *paybuf;
- guint8 *packet_header;
- guint8 *packet_payload;
- guint payload_size;
- guint packet_size;
- guint j, n_buffers;
-
- /* each group should consists of at least 1 buffer: The first buffer always
- * contains the complete RTP header. Next buffers contain the payload */
- n_buffers = gst_buffer_list_iterator_n_buffers (it);
- if (n_buffers < 1)
- goto invalid_list;
-
- /* get the RTP header (and if n_buffers == 1 also the payload) */
- rtpbuf = gst_buffer_list_iterator_next (it);
- packet_header = GST_BUFFER_DATA (rtpbuf);
- if (packet_header == NULL)
- goto invalid_list;
-
- /* check the sequence number */
- if (G_UNLIKELY (i == 0)) {
- prev_seqnum = g_ntohs (GST_RTP_HEADER_SEQ (packet_header));
- i++;
- } else {
- if (++prev_seqnum != g_ntohs (GST_RTP_HEADER_SEQ (packet_header)))
- goto invalid_list;
- }
+ guint8 *data;
+ gsize size, maxsize;
- packet_size = GST_BUFFER_SIZE (rtpbuf);
- packet_payload = NULL;
- payload_size = 0;
+ g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
+ g_return_val_if_fail (rtp != NULL, FALSE);
+ g_return_val_if_fail (rtp->buffer == NULL, FALSE);
- /* get the payload buffers */
- for (j = 1; j < n_buffers; j++) {
- /* get the payload */
- paybuf = gst_buffer_list_iterator_next (it);
+ data = gst_buffer_map (buffer, &size, &maxsize, flags);
+ if (data == NULL)
+ return FALSE;
- if ((packet_payload = GST_BUFFER_DATA (paybuf)) == NULL)
- goto invalid_list;
+ rtp->buffer = buffer;
+ rtp->flags = flags;
+ rtp->data = data;
+ rtp->size = size;
+ rtp->maxsize = maxsize;
- if ((payload_size = GST_BUFFER_SIZE (paybuf)) == 0)
- goto invalid_list;
+ return TRUE;
+}
- /* the size of the RTP packet within the current group */
- packet_size += payload_size;
- }
+gboolean
+gst_rtp_buffer_unmap (GstRTPBuffer * rtp)
+{
+ g_return_val_if_fail (rtp != NULL, FALSE);
+ g_return_val_if_fail (rtp->buffer != NULL, FALSE);
- /* validate packet */
- if (!validate_data (packet_header, packet_size, packet_payload,
- payload_size)) {
- goto invalid_list;
- }
- }
+ gst_buffer_unmap (rtp->buffer, rtp->data, rtp->size);
- gst_buffer_list_iterator_free (it);
+ rtp->buffer = NULL;
return TRUE;
-
- /* ERRORS */
-invalid_list:
- {
- gst_buffer_list_iterator_free (it);
- return FALSE;
- }
}
+
/**
* gst_rtp_buffer_set_packet_len:
- * @buffer: the buffer
+ * @rtp: the RTP packet
* @len: the new packet length
*
- * Set the total @buffer size to @len. The data in the buffer will be made
- * larger if needed. Any padding will be removed from the packet.
+ * Set the total @rtp size to @len. The data in the buffer will be made
+ * larger if needed. Any padding will be removed from the packet.
*/
void
-gst_rtp_buffer_set_packet_len (GstBuffer * buffer, guint len)
+gst_rtp_buffer_set_packet_len (GstRTPBuffer * rtp, guint len)
{
guint oldlen;
guint8 *data;
- oldlen = GST_BUFFER_SIZE (buffer);
- data = GST_BUFFER_DATA (buffer);
+ oldlen = rtp->size;
+ data = rtp->data;
- if (oldlen < len) {
- data = g_realloc (GST_BUFFER_MALLOCDATA (buffer), len);
- GST_BUFFER_MALLOCDATA (buffer) = data;
- GST_BUFFER_DATA (buffer) = data;
+ if (rtp->maxsize <= len) {
+ /* FIXME, realloc bigger space */
+ g_warning ("not implemented");
}
- GST_BUFFER_SIZE (buffer) = len;
+
+ gst_buffer_set_size (rtp->buffer, len);
+ rtp->size = len;
/* remove any padding */
GST_RTP_HEADER_PADDING (data) = FALSE;
/**
* gst_rtp_buffer_get_packet_len:
- * @buffer: the buffer
+ * @rtp: the RTP packet
*
* Return the total length of the packet in @buffer.
*
* Returns: The total length of the packet in @buffer.
*/
guint
-gst_rtp_buffer_get_packet_len (GstBuffer * buffer)
+gst_rtp_buffer_get_packet_len (GstRTPBuffer * rtp)
{
- return GST_BUFFER_SIZE (buffer);
+ return gst_buffer_get_size (rtp->buffer);
}
/**
* gst_rtp_buffer_get_header_len:
- * @buffer: the buffer
+ * @rtp: the RTP packet
*
* Return the total length of the header in @buffer. This include the length of
* the fixed header, the CSRC list and the extension header.
* Returns: The total length of the header in @buffer.
*/
guint
-gst_rtp_buffer_get_header_len (GstBuffer * buffer)
+gst_rtp_buffer_get_header_len (GstRTPBuffer * rtp)
{
guint len;
guint8 *data;
- data = GST_BUFFER_DATA (buffer);
+ data = rtp->data;
len = GST_RTP_HEADER_LEN + GST_RTP_HEADER_CSRC_SIZE (data);
if (GST_RTP_HEADER_EXTENSION (data))
/**
* gst_rtp_buffer_get_version:
- * @buffer: the buffer
+ * @rtp: the RTP packet
*
* Get the version number of the RTP packet in @buffer.
*
* Returns: The version of @buffer.
*/
guint8
-gst_rtp_buffer_get_version (GstBuffer * buffer)
+gst_rtp_buffer_get_version (GstRTPBuffer * rtp)
{
- return GST_RTP_HEADER_VERSION (GST_BUFFER_DATA (buffer));
+ return GST_RTP_HEADER_VERSION (rtp->data);
}
/**
* gst_rtp_buffer_set_version:
- * @buffer: the buffer
+ * @rtp: the RTP packet
* @version: the new version
*
* Set the version of the RTP packet in @buffer to @version.
*/
void
-gst_rtp_buffer_set_version (GstBuffer * buffer, guint8 version)
+gst_rtp_buffer_set_version (GstRTPBuffer * rtp, guint8 version)
{
g_return_if_fail (version < 0x04);
- GST_RTP_HEADER_VERSION (GST_BUFFER_DATA (buffer)) = version;
+ GST_RTP_HEADER_VERSION (rtp->data) = version;
}
/**
* gst_rtp_buffer_get_padding:
- * @buffer: the buffer
+ * @rtp: the RTP packet
*
* Check if the padding bit is set on the RTP packet in @buffer.
*
* Returns: TRUE if @buffer has the padding bit set.
*/
gboolean
-gst_rtp_buffer_get_padding (GstBuffer * buffer)
+gst_rtp_buffer_get_padding (GstRTPBuffer * rtp)
{
- return GST_RTP_HEADER_PADDING (GST_BUFFER_DATA (buffer));
+ return GST_RTP_HEADER_PADDING (rtp->data);
}
/**
* Set the padding bit on the RTP packet in @buffer to @padding.
*/
void
-gst_rtp_buffer_set_padding (GstBuffer * buffer, gboolean padding)
+gst_rtp_buffer_set_padding (GstRTPBuffer * rtp, gboolean padding)
{
- GST_RTP_HEADER_PADDING (GST_BUFFER_DATA (buffer)) = padding;
+ GST_RTP_HEADER_PADDING (rtp->data) = padding;
}
/**
* gst_rtp_buffer_pad_to:
- * @buffer: the buffer
+ * @rtp: the RTP packet
* @len: the new amount of padding
*
* Set the amount of padding in the RTP packet in @buffer to
* NOTE: This function does not work correctly.
*/
void
-gst_rtp_buffer_pad_to (GstBuffer * buffer, guint len)
+gst_rtp_buffer_pad_to (GstRTPBuffer * rtp, guint len)
{
guint8 *data;
- data = GST_BUFFER_DATA (buffer);
+ data = rtp->data;
if (len > 0)
GST_RTP_HEADER_PADDING (data) = TRUE;
/**
* gst_rtp_buffer_get_extension:
- * @buffer: the buffer
+ * @rtp: the RTP packet
*
* Check if the extension bit is set on the RTP packet in @buffer.
*
* Returns: TRUE if @buffer has the extension bit set.
*/
gboolean
-gst_rtp_buffer_get_extension (GstBuffer * buffer)
+gst_rtp_buffer_get_extension (GstRTPBuffer * rtp)
{
- return GST_RTP_HEADER_EXTENSION (GST_BUFFER_DATA (buffer));
+ return GST_RTP_HEADER_EXTENSION (rtp->data);
}
/**
* gst_rtp_buffer_set_extension:
- * @buffer: the buffer
+ * @rtp: the RTP packet
* @extension: the new extension
*
* Set the extension bit on the RTP packet in @buffer to @extension.
*/
void
-gst_rtp_buffer_set_extension (GstBuffer * buffer, gboolean extension)
+gst_rtp_buffer_set_extension (GstRTPBuffer * rtp, gboolean extension)
{
- GST_RTP_HEADER_EXTENSION (GST_BUFFER_DATA (buffer)) = extension;
+ GST_RTP_HEADER_EXTENSION (rtp->data) = extension;
}
/**
* gst_rtp_buffer_get_extension_data:
- * @buffer: the buffer
+ * @rtp: the RTP packet
* @bits: location for result bits
* @data: location for data
* @wordlen: location for length of @data in 32 bits words
* Since: 0.10.15
*/
gboolean
-gst_rtp_buffer_get_extension_data (GstBuffer * buffer, guint16 * bits,
+gst_rtp_buffer_get_extension_data (GstRTPBuffer * rtp, guint16 * bits,
gpointer * data, guint * wordlen)
{
guint len;
guint8 *pdata;
- pdata = GST_BUFFER_DATA (buffer);
+ pdata = rtp->data;
if (!GST_RTP_HEADER_EXTENSION (pdata))
return FALSE;
/**
* gst_rtp_buffer_set_extension_data:
- * @buffer: the buffer
+ * @rtp: the RTP packet
* @bits: the bits specific for the extension
* @length: the length that counts the number of 32-bit words in
* the extension, excluding the extension header ( therefore zero is a valid length)
* Since: 0.10.18
*/
gboolean
-gst_rtp_buffer_set_extension_data (GstBuffer * buffer, guint16 bits,
+gst_rtp_buffer_set_extension_data (GstRTPBuffer * rtp, guint16 bits,
guint16 length)
{
guint32 min_size = 0;
guint8 *data;
- data = GST_BUFFER_DATA (buffer);
+ data = rtp->data;
/* check if the buffer is big enough to hold the extension */
min_size =
GST_RTP_HEADER_LEN + GST_RTP_HEADER_CSRC_SIZE (data) + 4 +
length * sizeof (guint32);
- if (G_UNLIKELY (min_size > GST_BUFFER_SIZE (buffer)))
+ if (G_UNLIKELY (min_size > rtp->size))
goto too_small;
/* now we can set the extension bit */
- gst_rtp_buffer_set_extension (buffer, TRUE);
+ GST_RTP_HEADER_EXTENSION (rtp->data) = TRUE;
data += GST_RTP_HEADER_LEN + GST_RTP_HEADER_CSRC_SIZE (data);
GST_WRITE_UINT16_BE (data, bits);
too_small:
{
g_warning
- ("rtp buffer too small: need more than %d bytes but only have %d bytes",
- min_size, GST_BUFFER_SIZE (buffer));
+ ("rtp buffer too small: need more than %d bytes but only have %"
+ G_GSIZE_FORMAT " bytes", min_size, rtp->size);
return FALSE;
}
}
/**
* gst_rtp_buffer_get_ssrc:
- * @buffer: the buffer
+ * @rtp: the RTP packet
*
* Get the SSRC of the RTP packet in @buffer.
*
* Returns: the SSRC of @buffer in host order.
*/
guint32
-gst_rtp_buffer_get_ssrc (GstBuffer * buffer)
-{
- return g_ntohl (GST_RTP_HEADER_SSRC (GST_BUFFER_DATA (buffer)));
-}
-
-/**
- * gst_rtp_buffer_list_get_ssrc:
- * @list: the buffer list
- *
- * Get the SSRC of the first RTP packet in @list.
- * All RTP packets within @list have the same SSRC.
- *
- * Returns: the SSRC of @list in host order.
- *
- * Since: 0.10.24
- */
-guint32
-gst_rtp_buffer_list_get_ssrc (GstBufferList * list)
+gst_rtp_buffer_get_ssrc (GstRTPBuffer * rtp)
{
- GstBuffer *buffer;
-
- buffer = gst_buffer_list_get (list, 0, 0);
- g_return_val_if_fail (buffer != NULL, 0);
-
- return g_ntohl (GST_RTP_HEADER_SSRC (GST_BUFFER_DATA (buffer)));
+ return g_ntohl (GST_RTP_HEADER_SSRC (rtp->data));
}
/**
* gst_rtp_buffer_set_ssrc:
- * @buffer: the buffer
+ * @rtp: the RTP packet
* @ssrc: the new SSRC
*
* Set the SSRC on the RTP packet in @buffer to @ssrc.
*/
void
-gst_rtp_buffer_set_ssrc (GstBuffer * buffer, guint32 ssrc)
-{
- GST_RTP_HEADER_SSRC (GST_BUFFER_DATA (buffer)) = g_htonl (ssrc);
-}
-
-static GstBufferListItem
-set_ssrc_header (GstBuffer ** buffer, guint group, guint idx, guint32 * ssrc)
-{
- GST_RTP_HEADER_SSRC (GST_BUFFER_DATA (*buffer)) = g_htonl (*ssrc);
- return GST_BUFFER_LIST_SKIP_GROUP;
-}
-
-/**
- * gst_rtp_buffer_list_set_ssrc:
- * @list: the buffer list
- * @ssrc: the new SSRC
- *
- * Set the SSRC on each RTP packet in @list to @ssrc.
- *
- * Since: 0.10.24
- */
-void
-gst_rtp_buffer_list_set_ssrc (GstBufferList * list, guint32 ssrc)
+gst_rtp_buffer_set_ssrc (GstRTPBuffer * rtp, guint32 ssrc)
{
- gst_buffer_list_foreach (list, (GstBufferListFunc) set_ssrc_header, &ssrc);
+ GST_RTP_HEADER_SSRC (rtp->data) = g_htonl (ssrc);
}
/**
* gst_rtp_buffer_get_csrc_count:
- * @buffer: the buffer
+ * @rtp: the RTP packet
*
* Get the CSRC count of the RTP packet in @buffer.
*
* Returns: the CSRC count of @buffer.
*/
guint8
-gst_rtp_buffer_get_csrc_count (GstBuffer * buffer)
+gst_rtp_buffer_get_csrc_count (GstRTPBuffer * rtp)
{
- return GST_RTP_HEADER_CSRC_COUNT (GST_BUFFER_DATA (buffer));
+ return GST_RTP_HEADER_CSRC_COUNT (rtp->data);
}
/**
* gst_rtp_buffer_get_csrc:
- * @buffer: the buffer
+ * @rtp: the RTP packet
* @idx: the index of the CSRC to get
*
* Get the CSRC at index @idx in @buffer.
* Returns: the CSRC at index @idx in host order.
*/
guint32
-gst_rtp_buffer_get_csrc (GstBuffer * buffer, guint8 idx)
+gst_rtp_buffer_get_csrc (GstRTPBuffer * rtp, guint8 idx)
{
guint8 *data;
- data = GST_BUFFER_DATA (buffer);
+ data = rtp->data;
g_return_val_if_fail (idx < GST_RTP_HEADER_CSRC_COUNT (data), 0);
/**
* gst_rtp_buffer_set_csrc:
- * @buffer: the buffer
+ * @rtp: the RTP packet
* @idx: the CSRC index to set
* @csrc: the CSRC in host order to set at @idx
*
* Modify the CSRC at index @idx in @buffer to @csrc.
*/
void
-gst_rtp_buffer_set_csrc (GstBuffer * buffer, guint8 idx, guint32 csrc)
+gst_rtp_buffer_set_csrc (GstRTPBuffer * rtp, guint8 idx, guint32 csrc)
{
guint8 *data;
- data = GST_BUFFER_DATA (buffer);
+ data = rtp->data;
g_return_if_fail (idx < GST_RTP_HEADER_CSRC_COUNT (data));
/**
* gst_rtp_buffer_get_marker:
- * @buffer: the buffer
+ * @rtp: the RTP packet
*
* Check if the marker bit is set on the RTP packet in @buffer.
*
* Returns: TRUE if @buffer has the marker bit set.
*/
gboolean
-gst_rtp_buffer_get_marker (GstBuffer * buffer)
+gst_rtp_buffer_get_marker (GstRTPBuffer * rtp)
{
- return GST_RTP_HEADER_MARKER (GST_BUFFER_DATA (buffer));
+ return GST_RTP_HEADER_MARKER (rtp->data);
}
/**
* gst_rtp_buffer_set_marker:
- * @buffer: the buffer
+ * @rtp: the RTP packet
* @marker: the new marker
*
* Set the marker bit on the RTP packet in @buffer to @marker.
*/
void
-gst_rtp_buffer_set_marker (GstBuffer * buffer, gboolean marker)
+gst_rtp_buffer_set_marker (GstRTPBuffer * rtp, gboolean marker)
{
- GST_RTP_HEADER_MARKER (GST_BUFFER_DATA (buffer)) = marker;
+ GST_RTP_HEADER_MARKER (rtp->data) = marker;
}
/**
* gst_rtp_buffer_get_payload_type:
- * @buffer: the buffer
+ * @rtp: the RTP packet
*
* Get the payload type of the RTP packet in @buffer.
*
* Returns: The payload type.
*/
guint8
-gst_rtp_buffer_get_payload_type (GstBuffer * buffer)
-{
- return GST_RTP_HEADER_PAYLOAD_TYPE (GST_BUFFER_DATA (buffer));
-}
-
-/**
- * gst_rtp_buffer_list_get_payload_type:
- * @list: the buffer list
- *
- * Get the payload type of the first RTP packet in @list.
- * All packets in @list should have the same payload type.
- *
- * Returns: The payload type.
- *
- * Since: 0.10.24
- */
-guint8
-gst_rtp_buffer_list_get_payload_type (GstBufferList * list)
+gst_rtp_buffer_get_payload_type (GstRTPBuffer * rtp)
{
- GstBuffer *buffer;
-
- buffer = gst_buffer_list_get (list, 0, 0);
- g_return_val_if_fail (buffer != NULL, 0);
-
- return GST_RTP_HEADER_PAYLOAD_TYPE (GST_BUFFER_DATA (buffer));
+ return GST_RTP_HEADER_PAYLOAD_TYPE (rtp->data);
}
/**
* gst_rtp_buffer_set_payload_type:
- * @buffer: the buffer
+ * @rtp: the RTP packet
* @payload_type: the new type
*
* Set the payload type of the RTP packet in @buffer to @payload_type.
*/
void
-gst_rtp_buffer_set_payload_type (GstBuffer * buffer, guint8 payload_type)
+gst_rtp_buffer_set_payload_type (GstRTPBuffer * rtp, guint8 payload_type)
{
g_return_if_fail (payload_type < 0x80);
- GST_RTP_HEADER_PAYLOAD_TYPE (GST_BUFFER_DATA (buffer)) = payload_type;
-}
-
-static GstBufferListItem
-set_pt_header (GstBuffer ** buffer, guint group, guint idx, guint8 * pt)
-{
- GST_RTP_HEADER_PAYLOAD_TYPE (GST_BUFFER_DATA (*buffer)) = *pt;
- return GST_BUFFER_LIST_SKIP_GROUP;
-}
-
-/**
- * gst_rtp_buffer_list_set_payload_type:
- * @list: the buffer list
- * @payload_type: the new type
- *
- * Set the payload type of each RTP packet in @list to @payload_type.
- *
- * Since: 0.10.24
- */
-void
-gst_rtp_buffer_list_set_payload_type (GstBufferList * list, guint8 payload_type)
-{
- g_return_if_fail (payload_type < 0x80);
-
- gst_buffer_list_foreach (list, (GstBufferListFunc) set_pt_header,
- &payload_type);
+ GST_RTP_HEADER_PAYLOAD_TYPE (rtp->data) = payload_type;
}
/**
* gst_rtp_buffer_get_seq:
- * @buffer: the buffer
+ * @rtp: the RTP packet
*
* Get the sequence number of the RTP packet in @buffer.
*
* Returns: The sequence number in host order.
*/
guint16
-gst_rtp_buffer_get_seq (GstBuffer * buffer)
+gst_rtp_buffer_get_seq (GstRTPBuffer * rtp)
{
- return g_ntohs (GST_RTP_HEADER_SEQ (GST_BUFFER_DATA (buffer)));
+ return g_ntohs (GST_RTP_HEADER_SEQ (rtp->data));
}
/**
* gst_rtp_buffer_set_seq:
- * @buffer: the buffer
+ * @rtp: the RTP packet
* @seq: the new sequence number
*
* Set the sequence number of the RTP packet in @buffer to @seq.
*/
void
-gst_rtp_buffer_set_seq (GstBuffer * buffer, guint16 seq)
+gst_rtp_buffer_set_seq (GstRTPBuffer * rtp, guint16 seq)
{
- GST_RTP_HEADER_SEQ (GST_BUFFER_DATA (buffer)) = g_htons (seq);
-}
-
-static GstBufferListItem
-set_seq_header (GstBuffer ** buffer, guint group, guint idx, guint16 * seq)
-{
- GST_RTP_HEADER_SEQ (GST_BUFFER_DATA (*buffer)) = g_htons (*seq);
- (*seq)++;
- return GST_BUFFER_LIST_SKIP_GROUP;
-}
-
-/**
- * gst_rtp_buffer_list_set_seq:
- * @list: the buffer list
- * @seq: the new sequence number
- *
- * Set the sequence number of each RTP packet in @list to @seq.
- *
- * Returns: The seq number of the last packet in the list + 1.
- *
- * Since: 0.10.24
- */
-guint16
-gst_rtp_buffer_list_set_seq (GstBufferList * list, guint16 seq)
-{
- gst_buffer_list_foreach (list, (GstBufferListFunc) set_seq_header, &seq);
- return seq;
+ GST_RTP_HEADER_SEQ (rtp->data) = g_htons (seq);
}
/**
- * gst_rtp_buffer_list_get_seq:
- * @list: the buffer list
- *
- * Get the sequence number of the first RTP packet in @list.
- * All packets within @list have the same sequence number.
- *
- * Returns: The seq number
- *
- * Since: 0.10.24
- */
-guint16
-gst_rtp_buffer_list_get_seq (GstBufferList * list)
-{
- GstBuffer *buffer;
-
- buffer = gst_buffer_list_get (list, 0, 0);
- g_return_val_if_fail (buffer != NULL, 0);
-
- return g_ntohl (GST_RTP_HEADER_SEQ (GST_BUFFER_DATA (buffer)));
-}
-
-
-/**
* gst_rtp_buffer_get_timestamp:
- * @buffer: the buffer
+ * @rtp: the RTP packet
*
* Get the timestamp of the RTP packet in @buffer.
*
* Returns: The timestamp in host order.
*/
guint32
-gst_rtp_buffer_get_timestamp (GstBuffer * buffer)
-{
- return g_ntohl (GST_RTP_HEADER_TIMESTAMP (GST_BUFFER_DATA (buffer)));
-}
-
-/**
- * gst_rtp_buffer_list_get_timestamp:
- * @list: the buffer list
- *
- * Get the timestamp of the first RTP packet in @list.
- * All packets within @list have the same timestamp.
- *
- * Returns: The timestamp in host order.
- *
- * Since: 0.10.24
- */
-guint32
-gst_rtp_buffer_list_get_timestamp (GstBufferList * list)
+gst_rtp_buffer_get_timestamp (GstRTPBuffer * rtp)
{
- GstBuffer *buffer;
-
- buffer = gst_buffer_list_get (list, 0, 0);
- g_return_val_if_fail (buffer != NULL, 0);
-
- return g_ntohl (GST_RTP_HEADER_TIMESTAMP (GST_BUFFER_DATA (buffer)));
+ return g_ntohl (GST_RTP_HEADER_TIMESTAMP (rtp->data));
}
/**
* gst_rtp_buffer_set_timestamp:
- * @buffer: the buffer
+ * @rtp: the RTP packet
* @timestamp: the new timestamp
*
* Set the timestamp of the RTP packet in @buffer to @timestamp.
*/
void
-gst_rtp_buffer_set_timestamp (GstBuffer * buffer, guint32 timestamp)
-{
- GST_RTP_HEADER_TIMESTAMP (GST_BUFFER_DATA (buffer)) = g_htonl (timestamp);
-}
-
-
-static GstBufferListItem
-set_timestamp_header (GstBuffer ** buffer, guint group, guint idx,
- guint32 * timestamp)
+gst_rtp_buffer_set_timestamp (GstRTPBuffer * rtp, guint32 timestamp)
{
- GST_RTP_HEADER_TIMESTAMP (GST_BUFFER_DATA (*buffer)) = g_htonl (*timestamp);
- return GST_BUFFER_LIST_SKIP_GROUP;
+ GST_RTP_HEADER_TIMESTAMP (rtp->data) = g_htonl (timestamp);
}
-/**
- * gst_rtp_buffer_list_set_timestamp:
- * @list: the buffer list
- * @timestamp: the new timestamp
- *
- * Set the timestamp of each RTP packet in @list to @timestamp.
- *
- * Since: 0.10.24
- */
-void
-gst_rtp_buffer_list_set_timestamp (GstBufferList * list, guint32 timestamp)
-{
- gst_buffer_list_foreach (list, (GstBufferListFunc) set_timestamp_header,
- ×tamp);
-}
/**
* gst_rtp_buffer_get_payload_subbuffer:
- * @buffer: the buffer
+ * @rtp: the RTP packet
* @offset: the offset in the payload
* @len: the length in the payload
*
* Since: 0.10.10
*/
GstBuffer *
-gst_rtp_buffer_get_payload_subbuffer (GstBuffer * buffer, guint offset,
+gst_rtp_buffer_get_payload_subbuffer (GstRTPBuffer * rtp, guint offset,
guint len)
{
guint poffset, plen;
- plen = gst_rtp_buffer_get_payload_len (buffer);
+ plen = gst_rtp_buffer_get_payload_len (rtp);
/* we can't go past the length */
if (G_UNLIKELY (offset >= plen))
goto wrong_offset;
/* apply offset */
- poffset = gst_rtp_buffer_get_header_len (buffer) + offset;
+ poffset = gst_rtp_buffer_get_header_len (rtp) + offset;
plen -= offset;
/* see if we need to shrink the buffer based on @len */
if (len != -1 && len < plen)
plen = len;
- return gst_buffer_create_sub (buffer, poffset, plen);
+ return gst_buffer_copy_region (rtp->buffer, GST_BUFFER_COPY_ALL, poffset,
+ plen);
/* ERRORS */
wrong_offset:
/**
* gst_rtp_buffer_get_payload_buffer:
- * @buffer: the buffer
+ * @rtp: the RTP packet
*
* Create a buffer of the payload of the RTP packet in @buffer. This function
* will internally create a subbuffer of @buffer so that a memcpy can be
* Returns: A new buffer with the data of the payload.
*/
GstBuffer *
-gst_rtp_buffer_get_payload_buffer (GstBuffer * buffer)
+gst_rtp_buffer_get_payload_buffer (GstRTPBuffer * rtp)
{
- return gst_rtp_buffer_get_payload_subbuffer (buffer, 0, -1);
+ return gst_rtp_buffer_get_payload_subbuffer (rtp, 0, -1);
}
/**
* gst_rtp_buffer_get_payload_len:
- * @buffer: the buffer
+ * @rtp: the RTP packet
*
* Get the length of the payload of the RTP packet in @buffer.
*
* Returns: The length of the payload in @buffer.
*/
guint
-gst_rtp_buffer_get_payload_len (GstBuffer * buffer)
+gst_rtp_buffer_get_payload_len (GstRTPBuffer * rtp)
{
guint len, size;
guint8 *data;
- size = GST_BUFFER_SIZE (buffer);
- data = GST_BUFFER_DATA (buffer);
+ size = rtp->size;
+ data = rtp->data;
- len = size - gst_rtp_buffer_get_header_len (buffer);
+ len = size - gst_rtp_buffer_get_header_len (rtp);
if (GST_RTP_HEADER_PADDING (data))
len -= data[size - 1];
}
/**
- * gst_rtp_buffer_list_get_payload_len:
- * @list: the buffer list
- *
- * Get the length of the payload of the RTP packet in @list.
- *
- * Returns: The length of the payload in @list.
- *
- * Since: 0.10.24
- */
-guint
-gst_rtp_buffer_list_get_payload_len (GstBufferList * list)
-{
- guint len;
- GstBufferListIterator *it;
-
- it = gst_buffer_list_iterate (list);
- len = 0;
-
- while (gst_buffer_list_iterator_next_group (it)) {
- guint i;
- GstBuffer *buf;
-
- i = 0;
- while ((buf = gst_buffer_list_iterator_next (it))) {
- /* skip the RTP header */
- if (!i++)
- continue;
- /* take the size of the current buffer */
- len += GST_BUFFER_SIZE (buf);
- }
- }
-
- gst_buffer_list_iterator_free (it);
-
- return len;
-}
-
-/**
* gst_rtp_buffer_get_payload:
- * @buffer: the buffer
+ * @rtp: the RTP packet
*
* Get a pointer to the payload data in @buffer. This pointer is valid as long
* as a reference to @buffer is held.
* Returns: A pointer to the payload data in @buffer.
*/
gpointer
-gst_rtp_buffer_get_payload (GstBuffer * buffer)
+gst_rtp_buffer_get_payload (GstRTPBuffer * rtp)
{
- return GST_BUFFER_DATA (buffer) + gst_rtp_buffer_get_header_len (buffer);
+ return rtp->data + gst_rtp_buffer_get_header_len (rtp);
}
/**
/**
* gst_rtp_buffer_get_extension_onebyte_header:
- * @buffer: the buffer
+ * @rtp: the RTP packet
* @id: The ID of the header extension to be read (between 1 and 14).
* @nth: Read the nth extension packet with the requested ID
* @data: location for data
*/
gboolean
-gst_rtp_buffer_get_extension_onebyte_header (GstBuffer * buffer, guint8 id,
+gst_rtp_buffer_get_extension_onebyte_header (GstRTPBuffer * rtp, guint8 id,
guint nth, gpointer * data, guint * size)
{
guint16 bits;
g_return_val_if_fail (id > 0 && id < 15, FALSE);
- if (!gst_rtp_buffer_get_extension_data (buffer, &bits, (gpointer) & pdata,
+ if (!gst_rtp_buffer_get_extension_data (rtp, &bits, (gpointer) & pdata,
&wordlen))
return FALSE;
/**
* gst_rtp_buffer_get_extension_twobytes_header:
- * @buffer: the buffer
+ * @rtp: the RTP packet
* @appbits: Application specific bits
* @id: The ID of the header extension to be read (between 1 and 14).
* @nth: Read the nth extension packet with the requested ID
*/
gboolean
-gst_rtp_buffer_get_extension_twobytes_header (GstBuffer * buffer,
+gst_rtp_buffer_get_extension_twobytes_header (GstRTPBuffer * rtp,
guint8 * appbits, guint8 id, guint nth, gpointer * data, guint * size)
{
guint16 bits;
gulong offset = 0;
guint count = 0;
- if (!gst_rtp_buffer_get_extension_data (buffer, &bits, (gpointer) & pdata,
+ if (!gst_rtp_buffer_get_extension_data (rtp, &bits, (gpointer) & pdata,
&wordlen))
return FALSE;
/**
* gst_rtp_buffer_add_extension_onebyte_header:
- * @buffer: the buffer
+ * @rtp: the RTP packet
* @id: The ID of the header extension (between 1 and 14).
* @data: location for data
* @size: the size of the data in bytes
*/
gboolean
-gst_rtp_buffer_add_extension_onebyte_header (GstBuffer * buffer, guint8 id,
+gst_rtp_buffer_add_extension_onebyte_header (GstRTPBuffer * rtp, guint8 id,
gpointer data, guint size)
{
guint16 bits;
g_return_val_if_fail (id > 0 && id < 15, FALSE);
g_return_val_if_fail (size >= 1 && size <= 16, FALSE);
- g_return_val_if_fail (gst_buffer_is_writable (buffer), FALSE);
+ g_return_val_if_fail (gst_buffer_is_writable (rtp->buffer), FALSE);
- has_bit = gst_rtp_buffer_get_extension_data (buffer, &bits,
+ has_bit = gst_rtp_buffer_get_extension_data (rtp, &bits,
(gpointer) & pdata, &wordlen);
if (has_bit) {
return FALSE;
nextext = pdata + offset;
- offset = nextext - GST_BUFFER_DATA (buffer);
+ offset = nextext - rtp->data;
/* Don't add extra header if there isn't enough space */
- if (GST_BUFFER_SIZE (buffer) < offset + size + 1)
+ if (rtp->size < offset + size + 1)
return FALSE;
nextext[0] = (id << 4) | (0x0F & (size - 1));
wordlen = extlen / 4;
}
- gst_rtp_buffer_set_extension_data (buffer, 0xBEDE, wordlen);
+ gst_rtp_buffer_set_extension_data (rtp, 0xBEDE, wordlen);
} else {
wordlen = (size + 1) / 4 + (((size + 1) % 4) ? 1 : 0);
- gst_rtp_buffer_set_extension_data (buffer, 0xBEDE, wordlen);
+ gst_rtp_buffer_set_extension_data (rtp, 0xBEDE, wordlen);
- gst_rtp_buffer_get_extension_data (buffer, &bits,
+ gst_rtp_buffer_get_extension_data (rtp, &bits,
(gpointer) & pdata, &wordlen);
pdata[0] = (id << 4) | (0x0F & (size - 1));
/**
* gst_rtp_buffer_add_extension_twobytes_header:
- * @buffer: the buffer
+ * @rtp: the RTP packet
* @appbits: Application specific bits
* @id: The ID of the header extension
* @data: location for data
*/
gboolean
-gst_rtp_buffer_add_extension_twobytes_header (GstBuffer * buffer,
+gst_rtp_buffer_add_extension_twobytes_header (GstRTPBuffer * rtp,
guint8 appbits, guint8 id, gpointer data, guint size)
{
guint16 bits;
g_return_val_if_fail ((appbits & 0xF0) == 0, FALSE);
g_return_val_if_fail (size < 256, FALSE);
- g_return_val_if_fail (gst_buffer_is_writable (buffer), FALSE);
+ g_return_val_if_fail (gst_buffer_is_writable (rtp->buffer), FALSE);
- has_bit = gst_rtp_buffer_get_extension_data (buffer, &bits,
+ has_bit = gst_rtp_buffer_get_extension_data (rtp, &bits,
(gpointer) & pdata, &wordlen);
if (has_bit) {
nextext = pdata + offset;
- offset = nextext - GST_BUFFER_DATA (buffer);
+ offset = nextext - rtp->data;
/* Don't add extra header if there isn't enough space */
- if (GST_BUFFER_SIZE (buffer) < offset + size + 2)
+ if (rtp->size < offset + size + 2)
return FALSE;
nextext[0] = id;
wordlen = extlen / 4;
}
- gst_rtp_buffer_set_extension_data (buffer, (0x100 << 4) | (appbits & 0x0F),
+ gst_rtp_buffer_set_extension_data (rtp, (0x100 << 4) | (appbits & 0x0F),
wordlen);
} else {
wordlen = (size + 2) / 4 + (((size + 2) % 4) ? 1 : 0);
- gst_rtp_buffer_set_extension_data (buffer, (0x100 << 4) | (appbits & 0x0F),
+ gst_rtp_buffer_set_extension_data (rtp, (0x100 << 4) | (appbits & 0x0F),
wordlen);
- gst_rtp_buffer_get_extension_data (buffer, &bits,
+ gst_rtp_buffer_get_extension_data (rtp, &bits,
(gpointer) & pdata, &wordlen);
pdata[0] = id;
return TRUE;
}
-
-/**
- * gst_rtp_buffer_list_get_extension_onebyte_header:
- * @bufferlist: the bufferlist
- * @group_idx: The index of the group in the #GstBufferList
- * @id: The ID of the header extension to be read (between 1 and 14).
- * @nth: Read the nth extension packet with the requested ID
- * @data: location for data
- * @size: the size of the data in bytes
- *
- * Parses RFC 5285 style header extensions with a one byte header. It will
- * return the nth extension with the requested id.
- *
- * Returns: TRUE if @buffer had the requested header extension
- *
- * Since: 0.10.31
- */
-
-gboolean
-gst_rtp_buffer_list_get_extension_onebyte_header (GstBufferList * bufferlist,
- guint group_idx, guint8 id, guint nth, gpointer * data, guint * size)
-{
- GstBuffer *buffer;
-
- buffer = gst_buffer_list_get (bufferlist, group_idx, 0);
-
- if (!buffer)
- return FALSE;
-
- return gst_rtp_buffer_get_extension_onebyte_header (buffer, id, nth, data,
- size);
-}
-
-
-/**
- * gst_rtp_buffer_list_get_extension_twobytes_header:
- * @bufferlist: the bufferlist
- * @group_idx: The index of the group in the #GstBufferList
- * @appbits: Application specific bits
- * @id: The ID of the header extension to be read (between 1 and 14).
- * @nth: Read the nth extension packet with the requested ID
- * @data: location for data
- * @size: the size of the data in bytes
- *
- * Parses RFC 5285 style header extensions with a two bytes header. It will
- * return the nth extension with the requested id.
- *
- * Returns: TRUE if @buffer had the requested header extension
- *
- * Since: 0.10.31
- */
-
-gboolean
-gst_rtp_buffer_list_get_extension_twobytes_header (GstBufferList * bufferlist,
- guint group_idx, guint8 * appbits, guint8 id, guint nth,
- gpointer * data, guint * size)
-{
- GstBuffer *buffer;
-
- buffer = gst_buffer_list_get (bufferlist, group_idx, 0);
-
- if (!buffer)
- return FALSE;
-
- return gst_rtp_buffer_get_extension_twobytes_header (buffer, appbits, id,
- nth, data, size);
-}
-
-/**
- * gst_rtp_buffer_list_add_extension_onebyte_header:
- * @it: a #GstBufferListIterator pointing right after the #GstBuffer where
- * the header extension should be added
- * @id: The ID of the header extension (between 1 and 14).
- * @data: location for data
- * @size: the size of the data in bytes
- *
- * Adds a RFC 5285 header extension with a one byte header to the end of the
- * RTP header. If there is already a RFC 5285 header extension with a one byte
- * header, the new extension will be appended.
- * It will not work if there is already a header extension that does not follow
- * the mecanism described in RFC 5285 or if there is a header extension with
- * a two bytes header as described in RFC 5285. In that case, use
- * gst_rtp_buffer_list_add_extension_twobytes_header()
- *
- * This function will not modify the data section of the RTP buffer, only
- * the header.
- *
- * Returns: %TRUE if header extension could be added
- *
- * Since: 0.10.31
- */
-
-gboolean
-gst_rtp_buffer_list_add_extension_onebyte_header (GstBufferListIterator * it,
- guint8 id, gpointer data, guint size)
-{
- GstBuffer *buffer;
- guint16 bits;
- guint8 *pdata;
- guint wordlen;
- gboolean retval;
- guint endoffset = 0;
-
- g_return_val_if_fail (gst_buffer_list_iterator_n_buffers (it) == 1, FALSE);
- g_return_val_if_fail (id > 0 && id < 15, FALSE);
- g_return_val_if_fail (size >= 1 && size <= 16, FALSE);
-
- buffer = gst_buffer_list_iterator_steal (it);
-
- if (GST_RTP_HEADER_EXTENSION (GST_BUFFER_DATA (buffer))) {
- gst_rtp_buffer_get_extension_data (buffer, &bits, (gpointer) & pdata,
- &wordlen);
-
- if (bits != 0xBEDE)
- return FALSE;
-
- endoffset = get_onebyte_header_end_offset (pdata, wordlen);
- if (endoffset == 0)
- return FALSE;
- endoffset += pdata - GST_BUFFER_DATA (buffer);
- } else {
- endoffset = GST_BUFFER_SIZE (buffer) + 4;
- }
-
- if (endoffset + size + 1 > GST_BUFFER_SIZE (buffer)) {
- guint newsize;
- GstBuffer *newbuffer;
-
- newsize = endoffset + size + 1;
- if (newsize % 4)
- newsize += 4 - (newsize % 4);
- newbuffer = gst_buffer_new_and_alloc (newsize);
- memcpy (GST_BUFFER_DATA (newbuffer), GST_BUFFER_DATA (buffer),
- GST_BUFFER_SIZE (buffer));
- gst_buffer_copy_metadata (newbuffer, buffer, GST_BUFFER_COPY_ALL);
- gst_buffer_unref (buffer);
- buffer = newbuffer;
- } else {
- buffer = gst_buffer_make_writable (buffer);
- }
-
- retval = gst_rtp_buffer_add_extension_onebyte_header (buffer, id, data, size);
-
- gst_buffer_list_iterator_take (it, buffer);
-
- return retval;
-}
-
-/**
- * gst_rtp_buffer_list_add_extension_twobytes_header:
- * @it: a #GstBufferListIterator pointing right after the #GstBuffer where
- * the header extension should be added
- * @appbits: Application specific bits
- * @id: The ID of the header extension
- * @data: location for data
- * @size: the size of the data in bytes
- *
- * Adds a RFC 5285 header extension with a two bytes header to the end of the
- * RTP header. If there is already a RFC 5285 header extension with a two bytes
- * header, the new extension will be appended.
- * It will not work if there is already a header extension that does not follow
- * the mecanism described in RFC 5285 or if there is a header extension with
- * a one byte header as described in RFC 5285. In that case, use
- * gst_rtp_buffer_add_extension_onebyte_header()
- *
- * This function will not modify the data section of the RTP buffer, only
- * the header.
- *
- * Returns: %TRUE if header extension could be added
- *
- * Since: 0.10.31
- */
-
-gboolean
-gst_rtp_buffer_list_add_extension_twobytes_header (GstBufferListIterator * it,
- guint8 appbits, guint8 id, gpointer data, guint size)
-{
- GstBuffer *buffer;
- guint16 bits;
- guint8 *pdata;
- guint wordlen;
- gboolean retval;
- guint endoffset;
-
- g_return_val_if_fail ((appbits & 0xF0) == 0, FALSE);
- g_return_val_if_fail (size < 256, FALSE);
- g_return_val_if_fail (gst_buffer_list_iterator_n_buffers (it) == 1, FALSE);
-
- buffer = gst_buffer_list_iterator_steal (it);
-
- if (GST_RTP_HEADER_EXTENSION (GST_BUFFER_DATA (buffer))) {
- gst_rtp_buffer_get_extension_data (buffer, &bits, (gpointer) & pdata,
- &wordlen);
-
- if (bits != ((0x100 << 4) | (appbits & 0x0f)))
- return FALSE;
-
- endoffset = get_twobytes_header_end_offset (pdata, wordlen);
- if (endoffset == 0)
- return FALSE;
- endoffset += pdata - GST_BUFFER_DATA (buffer);
- } else {
- endoffset = GST_BUFFER_SIZE (buffer) + 4;
- }
-
- if (endoffset + size + 2 > GST_BUFFER_SIZE (buffer)) {
- guint newsize;
- GstBuffer *newbuffer;
-
- newsize = endoffset + size + 2;
- if (newsize % 4)
- newsize += 4 - newsize % 4;
- newbuffer = gst_buffer_new_and_alloc (newsize);
- memcpy (GST_BUFFER_DATA (newbuffer), GST_BUFFER_DATA (buffer),
- GST_BUFFER_SIZE (buffer));
- gst_buffer_copy_metadata (newbuffer, buffer, GST_BUFFER_COPY_ALL);
- gst_buffer_unref (buffer);
- buffer = newbuffer;
- } else {
- buffer = gst_buffer_make_writable (buffer);
- }
-
- retval = gst_rtp_buffer_add_extension_twobytes_header (buffer, appbits, id,
- data, size);
-
- gst_buffer_list_iterator_take (it, buffer);
-
- return retval;
-}
-
-/**
- * gst_rtp_buffer_list_from_buffer:
- * @buffer: a #GstBuffer containing a RTP packet
- *
- * Splits a #GstBuffer into a #GstBufferList containing separate
- * buffers for the header and data sections.
- *
- * Returns: a #GstBufferList
- */
-
-GstBufferList *
-gst_rtp_buffer_list_from_buffer (GstBuffer * buffer)
-{
- GstBufferList *bufferlist;
- GstBuffer *sub;
- GstBufferListIterator *it;
- guint8 *payload;
-
- bufferlist = gst_buffer_list_new ();
-
- it = gst_buffer_list_iterate (bufferlist);
- gst_buffer_list_iterator_add_group (it);
-
- payload = gst_rtp_buffer_get_payload (buffer);
- sub = gst_buffer_create_sub (buffer, 0, payload - GST_BUFFER_DATA (buffer));
- gst_buffer_list_iterator_add (it, sub);
-
- sub = gst_rtp_buffer_get_payload_buffer (buffer);
- gst_buffer_list_iterator_add (it, sub);
-
- gst_buffer_list_iterator_free (it);
-
- return bufferlist;
-}
*/
#define GST_RTP_VERSION 2
+
+typedef struct _GstRTPBuffer GstRTPBuffer;
+
+/**
+ * GstRTPBuffer:
+ * @buffer: pointer to RTP buffer
+ *
+ * Data structure that points to an RTP packet.
+ * The size of the structure is made public to allow stack allocations.
+ */
+struct _GstRTPBuffer
+{
+ GstBuffer *buffer;
+ GstMapFlags flags;
+ guint8 *data;
+ gsize size;
+ gsize maxsize;
+};
+
/* creating buffers */
-void gst_rtp_buffer_allocate_data (GstBuffer *buffer, guint payload_len,
+void gst_rtp_buffer_allocate_data (GstBuffer *buffer, guint payload_len,
guint8 pad_len, guint8 csrc_count);
-GstBuffer* gst_rtp_buffer_new_take_data (gpointer data, guint len);
-GstBuffer* gst_rtp_buffer_new_copy_data (gpointer data, guint len);
+GstBuffer* gst_rtp_buffer_new_take_data (gpointer data, gsize len);
+GstBuffer* gst_rtp_buffer_new_copy_data (gpointer data, gsize len);
GstBuffer* gst_rtp_buffer_new_allocate (guint payload_len, guint8 pad_len, guint8 csrc_count);
GstBuffer* gst_rtp_buffer_new_allocate_len (guint packet_len, guint8 pad_len, guint8 csrc_count);
-GstBufferList* gst_rtp_buffer_list_from_buffer (GstBuffer * buffer);
-
-
guint gst_rtp_buffer_calc_header_len (guint8 csrc_count);
guint gst_rtp_buffer_calc_packet_len (guint payload_len, guint8 pad_len, guint8 csrc_count);
guint gst_rtp_buffer_calc_payload_len (guint packet_len, guint8 pad_len, guint8 csrc_count);
-gboolean gst_rtp_buffer_validate_data (guint8 *data, guint len);
+gboolean gst_rtp_buffer_validate_data (guint8 *data, gsize len);
gboolean gst_rtp_buffer_validate (GstBuffer *buffer);
-gboolean gst_rtp_buffer_list_validate (GstBufferList *list);
-void gst_rtp_buffer_set_packet_len (GstBuffer *buffer, guint len);
-guint gst_rtp_buffer_get_packet_len (GstBuffer *buffer);
-guint gst_rtp_buffer_get_header_len (GstBuffer *buffer);
+gboolean gst_rtp_buffer_map (GstBuffer *buffer, GstMapFlags flags, GstRTPBuffer *rtp);
+gboolean gst_rtp_buffer_unmap (GstRTPBuffer *rtp);
+
+void gst_rtp_buffer_set_packet_len (GstRTPBuffer *rtp, guint len);
+guint gst_rtp_buffer_get_packet_len (GstRTPBuffer *rtp);
+
+guint gst_rtp_buffer_get_header_len (GstRTPBuffer *rtp);
-guint8 gst_rtp_buffer_get_version (GstBuffer *buffer);
-void gst_rtp_buffer_set_version (GstBuffer *buffer, guint8 version);
+guint8 gst_rtp_buffer_get_version (GstRTPBuffer *rtp);
+void gst_rtp_buffer_set_version (GstRTPBuffer *rtp, guint8 version);
-gboolean gst_rtp_buffer_get_padding (GstBuffer *buffer);
-void gst_rtp_buffer_set_padding (GstBuffer *buffer, gboolean padding);
-void gst_rtp_buffer_pad_to (GstBuffer *buffer, guint len);
+gboolean gst_rtp_buffer_get_padding (GstRTPBuffer *rtp);
+void gst_rtp_buffer_set_padding (GstRTPBuffer *rtp, gboolean padding);
+void gst_rtp_buffer_pad_to (GstRTPBuffer *rtp, guint len);
-gboolean gst_rtp_buffer_get_extension (GstBuffer *buffer);
-void gst_rtp_buffer_set_extension (GstBuffer *buffer, gboolean extension);
-gboolean gst_rtp_buffer_get_extension_data (GstBuffer *buffer, guint16 *bits,
+gboolean gst_rtp_buffer_get_extension (GstRTPBuffer *rtp);
+void gst_rtp_buffer_set_extension (GstRTPBuffer *rtp, gboolean extension);
+gboolean gst_rtp_buffer_get_extension_data (GstRTPBuffer *rtp, guint16 *bits,
gpointer *data, guint *wordlen);
-gboolean gst_rtp_buffer_set_extension_data (GstBuffer *buffer, guint16 bits, guint16 length);
+gboolean gst_rtp_buffer_set_extension_data (GstRTPBuffer *rtp, guint16 bits, guint16 length);
-guint32 gst_rtp_buffer_get_ssrc (GstBuffer *buffer);
-guint32 gst_rtp_buffer_list_get_ssrc (GstBufferList *list);
-void gst_rtp_buffer_set_ssrc (GstBuffer *buffer, guint32 ssrc);
-void gst_rtp_buffer_list_set_ssrc (GstBufferList *list, guint32 ssrc);
+guint32 gst_rtp_buffer_get_ssrc (GstRTPBuffer *rtp);
+void gst_rtp_buffer_set_ssrc (GstRTPBuffer *rtp, guint32 ssrc);
-guint8 gst_rtp_buffer_get_csrc_count (GstBuffer *buffer);
-guint32 gst_rtp_buffer_get_csrc (GstBuffer *buffer, guint8 idx);
-void gst_rtp_buffer_set_csrc (GstBuffer *buffer, guint8 idx, guint32 csrc);
+guint8 gst_rtp_buffer_get_csrc_count (GstRTPBuffer *rtp);
+guint32 gst_rtp_buffer_get_csrc (GstRTPBuffer *rtp, guint8 idx);
+void gst_rtp_buffer_set_csrc (GstRTPBuffer *rtp, guint8 idx, guint32 csrc);
-gboolean gst_rtp_buffer_get_marker (GstBuffer *buffer);
-void gst_rtp_buffer_set_marker (GstBuffer *buffer, gboolean marker);
+gboolean gst_rtp_buffer_get_marker (GstRTPBuffer *rtp);
+void gst_rtp_buffer_set_marker (GstRTPBuffer *rtp, gboolean marker);
-guint8 gst_rtp_buffer_get_payload_type (GstBuffer *buffer);
-guint8 gst_rtp_buffer_list_get_payload_type (GstBufferList *list);
-void gst_rtp_buffer_set_payload_type (GstBuffer *buffer, guint8 payload_type);
-void gst_rtp_buffer_list_set_payload_type (GstBufferList *list, guint8 payload_type);
+guint8 gst_rtp_buffer_get_payload_type (GstRTPBuffer *rtp);
+void gst_rtp_buffer_set_payload_type (GstRTPBuffer *rtp, guint8 payload_type);
-guint16 gst_rtp_buffer_get_seq (GstBuffer *buffer);
-guint16 gst_rtp_buffer_list_get_seq (GstBufferList *list);
-void gst_rtp_buffer_set_seq (GstBuffer *buffer, guint16 seq);
-guint16 gst_rtp_buffer_list_set_seq (GstBufferList *list, guint16 seq);
+guint16 gst_rtp_buffer_get_seq (GstRTPBuffer *rtp);
+void gst_rtp_buffer_set_seq (GstRTPBuffer *rtp, guint16 seq);
-guint32 gst_rtp_buffer_get_timestamp (GstBuffer *buffer);
-guint32 gst_rtp_buffer_list_get_timestamp (GstBufferList *list);
-void gst_rtp_buffer_set_timestamp (GstBuffer *buffer, guint32 timestamp);
-void gst_rtp_buffer_list_set_timestamp (GstBufferList *list, guint32 timestamp);
+guint32 gst_rtp_buffer_get_timestamp (GstRTPBuffer *rtp);
+void gst_rtp_buffer_set_timestamp (GstRTPBuffer *rtp, guint32 timestamp);
-GstBuffer* gst_rtp_buffer_get_payload_buffer (GstBuffer *buffer);
-GstBuffer* gst_rtp_buffer_get_payload_subbuffer (GstBuffer *buffer, guint offset, guint len);
+GstBuffer* gst_rtp_buffer_get_payload_buffer (GstRTPBuffer *rtp);
+GstBuffer* gst_rtp_buffer_get_payload_subbuffer (GstRTPBuffer *rtp, guint offset, guint len);
-guint gst_rtp_buffer_get_payload_len (GstBuffer *buffer);
-guint gst_rtp_buffer_list_get_payload_len (GstBufferList *list);
-gpointer gst_rtp_buffer_get_payload (GstBuffer *buffer);
+guint gst_rtp_buffer_get_payload_len (GstRTPBuffer *rtp);
+gpointer gst_rtp_buffer_get_payload (GstRTPBuffer *rtp);
/* some helpers */
guint32 gst_rtp_buffer_default_clock_rate (guint8 payload_type);
gint gst_rtp_buffer_compare_seqnum (guint16 seqnum1, guint16 seqnum2);
guint64 gst_rtp_buffer_ext_timestamp (guint64 *exttimestamp, guint32 timestamp);
-gboolean gst_rtp_buffer_get_extension_onebyte_header (GstBuffer * buffer,
- guint8 id,
- guint nth,
- gpointer * data,
- guint * size);
-gboolean gst_rtp_buffer_get_extension_twobytes_header (GstBuffer * buffer,
+gboolean gst_rtp_buffer_get_extension_onebyte_header (GstRTPBuffer *rtp,
+ guint8 id,
+ guint nth,
+ gpointer * data,
+ guint * size);
+gboolean gst_rtp_buffer_get_extension_twobytes_header (GstRTPBuffer *rtp,
guint8 * appbits,
guint8 id,
guint nth,
gpointer * data,
guint * size);
-gboolean gst_rtp_buffer_add_extension_onebyte_header (GstBuffer * buffer,
- guint8 id,
- gpointer data,
- guint size);
-gboolean gst_rtp_buffer_add_extension_twobytes_header (GstBuffer * buffer,
+gboolean gst_rtp_buffer_add_extension_onebyte_header (GstRTPBuffer *rtp,
+ guint8 id,
+ gpointer data,
+ guint size);
+gboolean gst_rtp_buffer_add_extension_twobytes_header (GstRTPBuffer *rtp,
guint8 appbits,
guint8 id,
gpointer data,
guint size);
-gboolean gst_rtp_buffer_list_get_extension_onebyte_header (GstBufferList * bufferlist,
- guint group_idx,
- guint8 id,
- guint nth,
- gpointer * data,
- guint * size);
-gboolean gst_rtp_buffer_list_get_extension_twobytes_header (GstBufferList * bufferlist,
- guint group_idx,
- guint8 * appbits,
- guint8 id,
- guint nth,
- gpointer * data,
- guint * size);
-
-gboolean gst_rtp_buffer_list_add_extension_onebyte_header (GstBufferListIterator * it,
- guint8 id,
- gpointer data,
- guint size);
-gboolean gst_rtp_buffer_list_add_extension_twobytes_header (GstBufferListIterator * it,
- guint8 appbits,
- guint8 id,
- gpointer data,
- guint size);
-
G_END_DECLS
struct _GstExifReader
{
GstTagList *taglist;
- const GstBuffer *buffer;
+ GstBuffer *buffer;
guint32 base_offset;
gint byte_order;
/* GstExifReader functions */
static void
gst_exif_reader_init (GstExifReader * reader, gint byte_order,
- const GstBuffer * buf, guint32 base_offset)
+ GstBuffer * buf, guint32 base_offset)
{
ensure_exif_tags ();
const GstTagList * taglist, const GstExifTagMatch * exiftag)
{
const GValue *value;
- const guint8 *data = NULL;
- gint size = 0;
+ guint8 *data = NULL;
+ gsize size = 0;
gint tag_size = gst_tag_list_get_tag_size (taglist, exiftag->gst_tag);
+ GstBuffer *buf = NULL;
if (tag_size != 1) {
GST_WARNING ("Only the first item in the taglist will be serialized");
break;
default:
if (G_VALUE_TYPE (value) == GST_TYPE_BUFFER) {
- GstBuffer *buf = gst_value_get_buffer (value);
-
- data = GST_BUFFER_DATA (buf);
- size = GST_BUFFER_SIZE (buf);
+ buf = gst_value_get_buffer (value);
+ data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
} else {
GST_WARNING ("Conversion from %s to raw data not supported",
G_VALUE_TYPE_NAME (value));
break;
}
- if (size == 0)
- return;
+ if (size > 0)
+ write_exif_undefined_tag (writer, exiftag->exif_tag, data, size);
- write_exif_undefined_tag (writer, exiftag->exif_tag, data, size);
+ if (buf)
+ gst_buffer_unmap (buf, data, size);
}
static void
guint32 real_offset;
if (count > 4) {
+ guint8 *data;
+ gsize size;
+
if (offset < reader->base_offset) {
GST_WARNING ("Offset is smaller (%u) than base offset (%u)", offset,
reader->base_offset);
}
real_offset = offset - reader->base_offset;
- if (real_offset >= GST_BUFFER_SIZE (reader->buffer)) {
+
+ data = gst_buffer_map (reader->buffer, &size, NULL, GST_MAP_READ);
+ if (real_offset >= size) {
GST_WARNING ("Invalid offset %u for buffer of size %u, not adding tag %s",
- real_offset, GST_BUFFER_SIZE (reader->buffer), tag->gst_tag);
+ real_offset, size, tag->gst_tag);
+ gst_buffer_unmap (reader->buffer, data, size);
return;
}
- str =
- g_strndup ((gchar *) (GST_BUFFER_DATA (reader->buffer) + real_offset),
- count);
+ str = g_strndup ((gchar *) (data + real_offset), count);
+ gst_buffer_unmap (reader->buffer, data, size);
} else {
str = g_strndup ((gchar *) offset_as_data, count);
}
guint32 real_offset;
if (count > 4) {
+ guint8 *bdata;
+ gsize bsize;
+
if (offset < reader->base_offset) {
GST_WARNING ("Offset is smaller (%u) than base offset (%u)", offset,
reader->base_offset);
}
real_offset = offset - reader->base_offset;
- if (real_offset >= GST_BUFFER_SIZE (reader->buffer)) {
+
+ bdata = gst_buffer_map (reader->buffer, &bsize, NULL, GST_MAP_READ);
+
+ if (real_offset >= bsize) {
GST_WARNING ("Invalid offset %u for buffer of size %u, not adding tag %s",
- real_offset, GST_BUFFER_SIZE (reader->buffer), tag->gst_tag);
+ real_offset, bsize, tag->gst_tag);
+ gst_buffer_unmap (reader->buffer, bdata, bsize);
return;
}
/* +1 because it could be a string without the \0 */
data = malloc (sizeof (guint8) * count + 1);
- memcpy (data, GST_BUFFER_DATA (reader->buffer) + real_offset, count);
+ memcpy (data, bdata + real_offset, count);
data[count] = 0;
+
+ gst_buffer_unmap (reader->buffer, bdata, bsize);
} else {
data = malloc (sizeof (guint8) * count + 1);
memcpy (data, (guint8 *) offset_as_data, count);
GstBuffer *buf;
buf = gst_buffer_new ();
- GST_BUFFER_DATA (buf) = data;
- GST_BUFFER_MALLOCDATA (buf) = data;
- GST_BUFFER_SIZE (buf) = count;
+ gst_buffer_take_memory (buf,
+ gst_memory_new_wrapped (0, data, g_free, count, 0, count));
data = NULL;
gst_tag_list_add (reader->taglist, GST_TAG_MERGE_APPEND, tag->gst_tag,
guint32 real_offset;
gint32 frac_n = 0;
gint32 frac_d = 0;
+ guint8 *data;
+ gsize size;
if (count > 1) {
GST_WARNING ("Rationals with multiple entries are not supported");
}
real_offset = offset - exif_reader->base_offset;
- if (real_offset >= GST_BUFFER_SIZE (exif_reader->buffer)) {
- GST_WARNING ("Invalid offset %u for buffer of size %u",
- real_offset, GST_BUFFER_SIZE (exif_reader->buffer));
- return FALSE;
+
+ data = gst_buffer_map (exif_reader->buffer, &size, NULL, GST_MAP_READ);
+
+ if (real_offset >= size) {
+ GST_WARNING ("Invalid offset %u for buffer of size %u", real_offset, size);
+ goto reader_fail;
}
- gst_byte_reader_init_from_buffer (&data_reader, exif_reader->buffer);
+ gst_byte_reader_init (&data_reader, data, size);
if (!gst_byte_reader_set_pos (&data_reader, real_offset))
goto reader_fail;
if (_frac_d)
*_frac_d = frac_d;
+ gst_buffer_unmap (exif_reader->buffer, data, size);
+
return TRUE;
reader_fail:
GST_WARNING ("Failed to read from byte reader. (Buffer too short?)");
+ gst_buffer_unmap (exif_reader->buffer, data, size);
return FALSE;
}
}
if (inner_ifd) {
+ guint8 *data;
+ gsize size;
+
GST_DEBUG ("Adding inner ifd: %x", tag_map[i].exif_tag);
gst_exif_writer_write_tag_header (&writer, tag_map[i].exif_tag,
EXIF_TYPE_LONG, 1,
gst_byte_writer_get_size (&writer.datawriter), FALSE);
- gst_byte_writer_put_data (&writer.datawriter,
- GST_BUFFER_DATA (inner_ifd), GST_BUFFER_SIZE (inner_ifd));
+
+ data = gst_buffer_map (inner_ifd, &size, NULL, GST_MAP_READ);
+ gst_byte_writer_put_data (&writer.datawriter, data, size);
+ gst_buffer_unmap (inner_ifd, data, size);
gst_buffer_unref (inner_ifd);
}
continue;
GstByteReader reader;
guint16 entries = 0;
guint16 i;
+ guint8 *data;
+ gsize size;
g_return_val_if_fail (exif_reader->byte_order == G_LITTLE_ENDIAN
|| exif_reader->byte_order == G_BIG_ENDIAN, FALSE);
- gst_byte_reader_init_from_buffer (&reader, exif_reader->buffer);
- if (!gst_byte_reader_set_pos (&reader, buf_offset)) {
- GST_WARNING ("Buffer offset invalid when parsing exif ifd");
- return FALSE;
- }
+ data = gst_buffer_map (exif_reader->buffer, &size, NULL, GST_MAP_READ);
+
+ gst_byte_reader_init (&reader, data, size);
+ if (!gst_byte_reader_set_pos (&reader, buf_offset))
+ goto invalid_offset;
/* read the IFD entries number */
if (exif_reader->byte_order == G_LITTLE_ENDIAN) {
}
}
}
+ gst_buffer_unmap (exif_reader->buffer, data, size);
return TRUE;
+invalid_offset:
+ {
+ GST_WARNING ("Buffer offset invalid when parsing exif ifd");
+ gst_buffer_unmap (exif_reader->buffer, data, size);
+ return FALSE;
+ }
read_error:
{
GST_WARNING ("Failed to parse the exif ifd");
+ gst_buffer_unmap (exif_reader->buffer, data, size);
return FALSE;
}
}
{
GstBuffer *ifd;
GstByteWriter writer;
- guint size;
+ gsize size;
+ guint8 *data;
ifd = gst_tag_list_to_exif_buffer (taglist, G_BYTE_ORDER, 8);
if (ifd == NULL) {
GST_WARNING ("Failed to create exif buffer");
return NULL;
}
- size = TIFF_HEADER_SIZE + GST_BUFFER_SIZE (ifd);
+
+ data = gst_buffer_map (ifd, &size, NULL, GST_MAP_READ);
+
+ size += TIFF_HEADER_SIZE;
/* TODO what is the correct endianness here? */
gst_byte_writer_init_with_size (&writer, size, FALSE);
gst_byte_writer_put_uint16_be (&writer, 42);
gst_byte_writer_put_uint32_be (&writer, 8);
}
- if (!gst_byte_writer_put_data (&writer, GST_BUFFER_DATA (ifd),
- GST_BUFFER_SIZE (ifd))) {
+ if (!gst_byte_writer_put_data (&writer, data, size)) {
GST_WARNING ("Byte writer size mismatch");
/* reaching here is a programming error because we should have a buffer
* large enough */
g_assert_not_reached ();
+ gst_buffer_unmap (ifd, data, size);
gst_buffer_unref (ifd);
gst_byte_writer_reset (&writer);
return NULL;
}
+ gst_buffer_unmap (ifd, data, size);
gst_buffer_unref (ifd);
+
return gst_byte_writer_reset_and_get_buffer (&writer);
}
* Since: 0.10.30
*/
GstTagList *
-gst_tag_list_from_exif_buffer (const GstBuffer * buffer, gint byte_order,
+gst_tag_list_from_exif_buffer (GstBuffer * buffer, gint byte_order,
guint32 base_offset)
{
GstExifReader reader;
* Since: 0.10.30
*/
GstTagList *
-gst_tag_list_from_exif_buffer_with_tiff_header (const GstBuffer * buffer)
+gst_tag_list_from_exif_buffer_with_tiff_header (GstBuffer * buffer)
{
GstByteReader reader;
guint16 fortytwo = 42;
guint32 offset;
GstTagList *taglist = NULL;
GstBuffer *subbuffer;
+ guint8 *data, *sdata;
+ gsize size, ssize;
+
+ data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
- GST_LOG ("Parsing exif tags with tiff header of size %u",
- GST_BUFFER_SIZE (buffer));
+ GST_LOG ("Parsing exif tags with tiff header of size %u", size);
- gst_byte_reader_init_from_buffer (&reader, buffer);
+ gst_byte_reader_init (&reader, data, size);
GST_LOG ("Parsing the tiff header");
if (!gst_byte_reader_get_uint16_be (&reader, &endianness)) {
if (!gst_byte_reader_get_uint16_be (&reader, &fortytwo) ||
!gst_byte_reader_get_uint32_be (&reader, &offset))
goto byte_reader_fail;
- } else {
- GST_WARNING ("Invalid endianness number %u", endianness);
- return NULL;
- }
+ } else
+ goto invalid_endianness;
- if (fortytwo != 42) {
- GST_WARNING ("Invalid magic number %u, should be 42", fortytwo);
- return NULL;
- }
+ if (fortytwo != 42)
+ goto invalid_magic;
- subbuffer = gst_buffer_new_and_alloc (GST_BUFFER_SIZE (buffer) -
- (TIFF_HEADER_SIZE - 2));
- memcpy (GST_BUFFER_DATA (subbuffer),
- GST_BUFFER_DATA (buffer) + TIFF_HEADER_SIZE,
- GST_BUFFER_SIZE (buffer) - TIFF_HEADER_SIZE);
+ subbuffer = gst_buffer_new_and_alloc (size - (TIFF_HEADER_SIZE - 2));
+
+ sdata = gst_buffer_map (subbuffer, &ssize, NULL, GST_MAP_WRITE);
+ memcpy (sdata, data + TIFF_HEADER_SIZE, size - TIFF_HEADER_SIZE);
+ gst_buffer_unmap (subbuffer, sdata, ssize);
taglist = gst_tag_list_from_exif_buffer (subbuffer,
endianness == TIFF_LITTLE_ENDIAN ? G_LITTLE_ENDIAN : G_BIG_ENDIAN, 8);
gst_buffer_unref (subbuffer);
+
+done:
+ gst_buffer_unmap (buffer, data, size);
+
return taglist;
byte_reader_fail:
{
GST_WARNING ("Failed to read values from buffer");
- return NULL;
+ goto done;
+ }
+invalid_endianness:
+ {
+ GST_WARNING ("Invalid endianness number %u", endianness);
+ goto done;
+ }
+invalid_magic:
+ {
+ GST_WARNING ("Invalid magic number %u, should be 42", fortytwo);
+ goto done;
}
}
gdouble degrees;
gdouble minutes;
gdouble seconds;
+ guint8 *data = NULL;
+ gsize size = 0;
GST_LOG ("Starting to parse %s tag in exif 0x%x", exiftag->gst_tag,
exiftag->exif_tag);
return ret;
}
+ data = gst_buffer_map (exif_reader->buffer, &size, NULL, GST_MAP_READ);
+
/* now parse the fractions */
- gst_byte_reader_init_from_buffer (&fractions_reader, exif_reader->buffer);
+ gst_byte_reader_init (&fractions_reader, data, size);
+
if (!gst_byte_reader_set_pos (&fractions_reader,
next_tagdata.offset - exif_reader->base_offset))
goto reader_fail;
!gst_byte_reader_get_uint32_be (&fractions_reader, &seconds_d))
goto reader_fail;
}
+ gst_buffer_unmap (exif_reader->buffer, data, size);
GST_DEBUG ("Read degrees fraction for tag %s: %u/%u %u/%u %u/%u",
exiftag->gst_tag, degrees_n, degrees_d, minutes_n, minutes_d,
reader_fail:
GST_WARNING ("Failed to read fields from buffer (too short?)");
+ if (data)
+ gst_buffer_unmap (exif_reader->buffer, data, size);
return ret;
}
GstTagDemuxState state;
GstBuffer *collect;
+ gsize collect_size;
GstCaps *src_caps;
GstTagList *event_tags;
GstSegment segment;
gboolean need_newseg;
- gboolean newseg_update;
GList *pending_events;
};
static GstFlowReturn gst_tag_demux_read_range (GstTagDemux * tagdemux,
guint64 offset, guint length, GstBuffer ** buffer);
-static gboolean gst_tag_demux_src_checkgetrange (GstPad * srcpad);
static GstFlowReturn gst_tag_demux_src_getrange (GstPad * srcpad,
guint64 offset, guint length, GstBuffer ** buffer);
tagdemux->priv->send_tag_event = FALSE;
gst_buffer_replace (buffer_p, NULL);
+ tagdemux->priv->collect_size = 0;
gst_caps_replace (caps_p, NULL);
gst_tag_demux_remove_srcpad (tagdemux);
gst_segment_init (&tagdemux->priv->segment, GST_FORMAT_UNDEFINED);
tagdemux->priv->need_newseg = TRUE;
- tagdemux->priv->newseg_update = FALSE;
g_list_foreach (tagdemux->priv->pending_events,
(GFunc) gst_mini_object_unref, NULL);
GST_DEBUG_FUNCPTR (gst_tag_demux_srcpad_event));
gst_pad_set_activatepull_function (tagdemux->priv->srcpad,
GST_DEBUG_FUNCPTR (gst_tag_demux_src_activate_pull));
- gst_pad_set_checkgetrange_function (tagdemux->priv->srcpad,
- GST_DEBUG_FUNCPTR (gst_tag_demux_src_checkgetrange));
gst_pad_set_getrange_function (tagdemux->priv->srcpad,
GST_DEBUG_FUNCPTR (gst_tag_demux_src_getrange));
* also return TRUE and set *buf_ref to NULL if the buffer was before
* the start of the data */
static gboolean
-gst_tag_demux_trim_buffer (GstTagDemux * tagdemux, GstBuffer ** buf_ref)
+gst_tag_demux_trim_buffer (GstTagDemux * tagdemux, GstBuffer ** buf_ref,
+ gsize * buf_size)
{
GstBuffer *buf = *buf_ref;
guint trim_start = 0;
- guint out_size = GST_BUFFER_SIZE (buf);
- guint64 out_offset = GST_BUFFER_OFFSET (buf);
+ guint out_size, bsize;
+ guint64 out_offset, boffset;
gboolean need_sub = FALSE;
+ bsize = out_size = gst_buffer_get_size (buf);
+ boffset = out_offset = GST_BUFFER_OFFSET (buf);
+
/* Adjust offset and length */
if (!GST_BUFFER_OFFSET_IS_VALID (buf)) {
/* Can't change anything without an offset */
+ *buf_size = bsize;
return TRUE;
}
}
if (need_sub == TRUE) {
- if (out_size != GST_BUFFER_SIZE (buf) || !gst_buffer_is_writable (buf)) {
+ if (out_size != bsize || !gst_buffer_is_writable (buf)) {
GstBuffer *sub;
GST_DEBUG_OBJECT (tagdemux, "Sub-buffering to trim size %d offset %"
G_GINT64_FORMAT " to %d offset %" G_GINT64_FORMAT,
- GST_BUFFER_SIZE (buf), GST_BUFFER_OFFSET (buf), out_size, out_offset);
+ bsize, boffset, out_size, out_offset);
- sub = gst_buffer_create_sub (buf, trim_start, out_size);
+ sub =
+ gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, trim_start,
+ out_size);
g_return_val_if_fail (sub != NULL, FALSE);
gst_buffer_unref (buf);
*buf_ref = buf = sub;
+ *buf_size = out_size;
} else {
GST_DEBUG_OBJECT (tagdemux, "Adjusting buffer from size %d offset %"
G_GINT64_FORMAT " to %d offset %" G_GINT64_FORMAT,
- GST_BUFFER_SIZE (buf), GST_BUFFER_OFFSET (buf), out_size, out_offset);
+ bsize, boffset, out_size, out_offset);
}
GST_BUFFER_OFFSET (buf) = out_offset;
GST_BUFFER_OFFSET_END (buf) = out_offset + out_size;
- gst_buffer_set_caps (buf, tagdemux->priv->src_caps);
}
return TRUE;
guint tagsize = 0;
guint available;
- g_assert (gst_buffer_is_metadata_writable (collect));
+ g_assert (gst_buffer_is_writable (collect));
klass = GST_TAG_DEMUX_CLASS (G_OBJECT_GET_CLASS (demux));
g_assert (klass->identify_tag != NULL);
g_assert (klass->parse_tag != NULL);
- available = GST_BUFFER_SIZE (collect);
+ available = gst_buffer_get_size (collect);
if (available < klass->min_start_size) {
GST_DEBUG_OBJECT (demux, "Only %u bytes available, but %u needed "
return; /* wait for more data */
}
- saved_size = GST_BUFFER_SIZE (collect);
- GST_BUFFER_SIZE (collect) = tagsize;
+ saved_size = gst_buffer_get_size (collect);
+ gst_buffer_set_size (collect, tagsize);
newsize = tagsize;
parse_ret = klass->parse_tag (demux, collect, TRUE, &newsize, &tags);
- GST_BUFFER_SIZE (collect) = saved_size;
+ gst_buffer_set_size (collect, saved_size);
switch (parse_ret) {
case GST_TAG_DEMUX_RESULT_OK:
gst_tag_demux_chain (GstPad * pad, GstBuffer * buf)
{
GstTagDemux *demux;
+ gsize size;
demux = GST_TAG_DEMUX (GST_PAD_PARENT (pad));
- /* Update our segment last_stop info */
+ size = gst_buffer_get_size (buf);
+
+ /* Update our segment position info */
if (demux->priv->segment.format == GST_FORMAT_BYTES) {
if (GST_BUFFER_OFFSET_IS_VALID (buf))
- demux->priv->segment.last_stop = GST_BUFFER_OFFSET (buf);
- demux->priv->segment.last_stop += GST_BUFFER_SIZE (buf);
+ demux->priv->segment.position = GST_BUFFER_OFFSET (buf);
+ demux->priv->segment.position += size;
} else if (demux->priv->segment.format == GST_FORMAT_TIME) {
if (GST_BUFFER_TIMESTAMP_IS_VALID (buf))
- demux->priv->segment.last_stop = GST_BUFFER_TIMESTAMP (buf);
+ demux->priv->segment.position = GST_BUFFER_TIMESTAMP (buf);
if (GST_BUFFER_DURATION_IS_VALID (buf))
- demux->priv->segment.last_stop += GST_BUFFER_DURATION (buf);
+ demux->priv->segment.position += GST_BUFFER_DURATION (buf);
}
if (demux->priv->collect == NULL) {
} else {
demux->priv->collect = gst_buffer_join (demux->priv->collect, buf);
}
+ demux->priv->collect_size += size;
buf = NULL;
switch (demux->priv->state) {
case GST_TAG_DEMUX_READ_START_TAG:
- demux->priv->collect =
- gst_buffer_make_metadata_writable (demux->priv->collect);
+ demux->priv->collect = gst_buffer_make_writable (demux->priv->collect);
gst_tag_demux_chain_parse_tag (demux, demux->priv->collect);
if (demux->priv->state != GST_TAG_DEMUX_TYPEFINDING)
break;
case GST_TAG_DEMUX_TYPEFINDING:{
GstTypeFindProbability probability = 0;
GstBuffer *typefind_buf = NULL;
+ gsize typefind_size;
GstCaps *caps;
- if (GST_BUFFER_SIZE (demux->priv->collect) <
+ if (demux->priv->collect_size <
TYPE_FIND_MIN_SIZE + demux->priv->strip_start)
break; /* Go get more data first */
GST_DEBUG_OBJECT (demux, "Typefinding with size %d",
- GST_BUFFER_SIZE (demux->priv->collect));
+ demux->priv->collect_size);
/* Trim the buffer and adjust offset for typefinding */
typefind_buf = demux->priv->collect;
gst_buffer_ref (typefind_buf);
- if (!gst_tag_demux_trim_buffer (demux, &typefind_buf))
+ if (!gst_tag_demux_trim_buffer (demux, &typefind_buf, &typefind_size))
return GST_FLOW_UNEXPECTED;
if (typefind_buf == NULL)
typefind_buf, &probability);
if (caps == NULL) {
- if (GST_BUFFER_SIZE (typefind_buf) < TYPE_FIND_MAX_SIZE) {
+ if (typefind_size < TYPE_FIND_MAX_SIZE) {
/* Just break for more data */
gst_buffer_unref (typefind_buf);
return GST_FLOW_OK;
gst_buffer_unref (typefind_buf);
gst_buffer_unref (demux->priv->collect);
demux->priv->collect = NULL;
+ demux->priv->collect_size = 0;
return GST_FLOW_ERROR;
}
gst_buffer_unref (typefind_buf);
}
case GST_TAG_DEMUX_STREAMING:{
GstBuffer *outbuf = NULL;
+ gsize outbuf_size;
/* Trim the buffer and adjust offset */
if (demux->priv->collect) {
outbuf = demux->priv->collect;
demux->priv->collect = NULL;
- if (!gst_tag_demux_trim_buffer (demux, &outbuf))
+ demux->priv->collect_size = 0;
+ if (!gst_tag_demux_trim_buffer (demux, &outbuf, &outbuf_size))
return GST_FLOW_UNEXPECTED;
}
if (outbuf) {
demux->priv->send_tag_event = FALSE;
}
- /* Ensure the caps are set correctly */
- outbuf = gst_buffer_make_metadata_writable (outbuf);
- gst_buffer_set_caps (outbuf, GST_PAD_CAPS (demux->priv->srcpad));
-
GST_LOG_OBJECT (demux, "Pushing buffer %p", outbuf);
return gst_pad_push (demux->priv->srcpad, outbuf);
}
ret = gst_pad_event_default (pad, event);
break;
- case GST_EVENT_NEWSEGMENT:{
- gboolean update;
- gdouble rate, arate;
- GstFormat format;
- gint64 start, stop, position;
-
- gst_event_parse_new_segment_full (event, &update, &rate, &arate,
- &format, &start, &stop, &position);
+ case GST_EVENT_SEGMENT:
+ {
+ gst_event_copy_segment (event, &demux->priv->segment);
- gst_segment_set_newsegment_full (&demux->priv->segment, update, rate,
- arate, format, start, stop, position);
- demux->priv->newseg_update = update;
demux->priv->need_newseg = TRUE;
gst_event_unref (event);
ret = TRUE;
gboolean res = FALSE;
guint64 offset;
guint tagsize;
+ gsize bsize;
klass = GST_TAG_DEMUX_CLASS (G_OBJECT_GET_CLASS (demux));
goto done;
}
- if (GST_BUFFER_SIZE (buffer) < klass->min_end_size) {
+ bsize = gst_buffer_get_size (buffer);
+
+ if (bsize < klass->min_end_size) {
GST_DEBUG_OBJECT (demux, "Only managed to read %u bytes from file "
- "(required: %u bytes)", GST_BUFFER_SIZE (buffer), klass->min_end_size);
+ "(required: %u bytes)", bsize, klass->min_end_size);
goto done;
}
g_assert (tagsize >= klass->min_end_size);
/* Get buffer that's exactly the requested size */
- if (GST_BUFFER_SIZE (buffer) != tagsize) {
+ if (bsize != tagsize) {
gst_buffer_unref (buffer);
buffer = NULL;
goto done;
}
- if (GST_BUFFER_SIZE (buffer) < tagsize) {
+ bsize = gst_buffer_get_size (buffer);
+
+ if (bsize < tagsize) {
GST_DEBUG_OBJECT (demux, "Only managed to read %u bytes from file",
- GST_BUFFER_SIZE (buffer));
+ bsize);
goto done;
}
}
GST_BUFFER_OFFSET (buffer) = offset;
- saved_size = GST_BUFFER_SIZE (buffer);
- GST_BUFFER_SIZE (buffer) = tagsize;
+ saved_size = bsize;
+ gst_buffer_set_size (buffer, tagsize);
newsize = tagsize;
parse_ret = klass->parse_tag (demux, buffer, FALSE, &newsize, &new_tags);
- GST_BUFFER_SIZE (buffer) = saved_size;
+ gst_buffer_set_size (buffer, saved_size);
switch (parse_ret) {
case GST_TAG_DEMUX_RESULT_OK:
gboolean have_tag;
gboolean res = FALSE;
guint req, tagsize;
+ gsize bsize;
klass = GST_TAG_DEMUX_CLASS (G_OBJECT_GET_CLASS (demux));
goto done;
}
- if (GST_BUFFER_SIZE (buffer) < klass->min_start_size) {
+ bsize = gst_buffer_get_size (buffer);
+
+ if (bsize < klass->min_start_size) {
GST_DEBUG_OBJECT (demux, "Only managed to read %u bytes from file - "
- "no tag in this file", GST_BUFFER_SIZE (buffer));
+ "no tag in this file", bsize);
goto done;
}
/* Now pull the entire tag */
g_assert (tagsize >= klass->min_start_size);
- if (GST_BUFFER_SIZE (buffer) < tagsize) {
+ if (bsize < tagsize) {
gst_buffer_unref (buffer);
buffer = NULL;
goto done;
}
- if (GST_BUFFER_SIZE (buffer) < tagsize) {
+ bsize = gst_buffer_get_size (buffer);
+
+ if (bsize < tagsize) {
GST_DEBUG_OBJECT (demux, "Only managed to read %u bytes from file",
- GST_BUFFER_SIZE (buffer));
+ bsize);
GST_ELEMENT_ERROR (demux, STREAM, DECODE,
(_("Failed to read tag: not enough data")), (NULL));
goto done;
}
}
- saved_size = GST_BUFFER_SIZE (buffer);
- GST_BUFFER_SIZE (buffer) = tagsize;
+ saved_size = bsize;
+ gst_buffer_set_size (buffer, tagsize);
newsize = tagsize;
parse_ret = klass->parse_tag (demux, buffer, TRUE, &newsize, &new_tags);
- GST_BUFFER_SIZE (buffer) = saved_size;
+ gst_buffer_set_size (buffer, saved_size);
switch (parse_ret) {
case GST_TAG_DEMUX_RESULT_OK:
gboolean e_tag_ok, s_tag_ok;
gboolean ret = FALSE;
GstCaps *caps = NULL;
+ GstQuery *query;
+ gboolean pull_mode;
demux = GST_TAG_DEMUX (GST_PAD_PARENT (sinkpad));
klass = GST_TAG_DEMUX_CLASS (G_OBJECT_GET_CLASS (demux));
* collect buffers, read the start tag and output a buffer to end
* preroll.
*/
- if (!gst_pad_check_pull_range (sinkpad) ||
- !gst_pad_activate_pull (sinkpad, TRUE)) {
- GST_DEBUG_OBJECT (demux, "No pull mode. Changing to push, but won't be "
- "able to read end tags");
- demux->priv->state = GST_TAG_DEMUX_READ_START_TAG;
- return gst_pad_activate_push (sinkpad, TRUE);
+ query = gst_query_new_scheduling ();
+
+ if (!gst_pad_peer_query (sinkpad, query)) {
+ gst_query_unref (query);
+ goto activate_push;
}
+ gst_query_parse_scheduling (query, &pull_mode, NULL, NULL, NULL, NULL, NULL);
+ gst_query_unref (query);
+
+ if (!pull_mode)
+ goto activate_push;
+
+ if (!gst_pad_activate_pull (sinkpad, TRUE))
+ goto activate_push;
+
/* Look for tags at start and end of file */
GST_DEBUG_OBJECT (demux, "Activated pull mode. Looking for tags");
if (!gst_tag_demux_get_upstream_size (demux))
gst_caps_unref (caps);
return ret;
+
+activate_push:
+ {
+ GST_DEBUG_OBJECT (demux, "No pull mode. Changing to push, but won't be "
+ "able to read end tags");
+ demux->priv->state = GST_TAG_DEMUX_READ_START_TAG;
+ return gst_pad_activate_push (sinkpad, TRUE);
+ }
}
static gboolean
return gst_pad_activate_pull (demux->priv->sinkpad, active);
}
-static gboolean
-gst_tag_demux_src_checkgetrange (GstPad * srcpad)
-{
- GstTagDemux *demux = GST_TAG_DEMUX (GST_PAD_PARENT (srcpad));
-
- return gst_pad_check_pull_range (demux->priv->sinkpad);
-}
-
static GstFlowReturn
gst_tag_demux_read_range (GstTagDemux * demux,
guint64 offset, guint length, GstBuffer ** buffer)
GstFlowReturn ret;
guint64 in_offset;
guint in_length;
+ gsize size;
g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
ret = gst_pad_pull_range (demux->priv->sinkpad, in_offset, in_length, buffer);
if (ret == GST_FLOW_OK && *buffer) {
- if (!gst_tag_demux_trim_buffer (demux, buffer))
+ if (!gst_tag_demux_trim_buffer (demux, buffer, &size))
goto read_beyond_end;
/* this should only happen in streaming mode */
g_assert (*buffer != NULL);
-
- gst_buffer_set_caps (*buffer, demux->priv->src_caps);
}
return ret;
GstEvent *event;
gint64 start, stop, position;
GstSegment *seg = &tagdemux->priv->segment;
+ GstSegment newseg;
if (seg->format == GST_FORMAT_UNDEFINED) {
GST_LOG_OBJECT (tagdemux,
"No new segment received before first buffer. Using default");
- gst_segment_set_newsegment (seg, FALSE, 1.0,
- GST_FORMAT_BYTES, tagdemux->priv->strip_start, -1,
- tagdemux->priv->strip_start);
+ gst_segment_init (seg, GST_FORMAT_BYTES);
+ seg->start = tagdemux->priv->strip_start;
+ seg->time = tagdemux->priv->strip_start;
}
/* Can't adjust segments in non-BYTES formats */
if (tagdemux->priv->segment.format != GST_FORMAT_BYTES) {
- event = gst_event_new_new_segment_full (tagdemux->priv->newseg_update,
- seg->rate, seg->applied_rate, seg->format, seg->start,
- seg->stop, seg->time);
+ event = gst_event_new_segment (seg);
return gst_pad_push_event (tagdemux->priv->srcpad, event);
}
}
}
- GST_DEBUG_OBJECT (tagdemux,
- "Sending new segment update %d, rate %g, format %d, "
- "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT ", position %"
- G_GINT64_FORMAT, tagdemux->priv->newseg_update, seg->rate, seg->format,
- start, stop, position);
+ GST_DEBUG_OBJECT (tagdemux, "Sending segment %" GST_SEGMENT_FORMAT, seg);
+
+ gst_segment_copy_into (seg, &newseg);
+ newseg.start = start;
+ newseg.stop = stop;
+ newseg.position = position;
+ event = gst_event_new_segment (&newseg);
- event = gst_event_new_new_segment_full (tagdemux->priv->newseg_update,
- seg->rate, seg->applied_rate, seg->format, start, stop, position);
return gst_pad_push_event (tagdemux->priv->srcpad, event);
}
}
/**
- * gst_tag_list_from_vorbiscomment_buffer:
- * @buffer: buffer to convert
+ * gst_tag_list_from_vorbiscomment:
+ * @data: data to convert
+ * @size: size of @data
* @id_data: identification data at start of stream
* @id_data_length: length of identification data
* @vendor_string: pointer to a string that should take the vendor string
* given vorbiscomment buffer or NULL on error.
*/
GstTagList *
-gst_tag_list_from_vorbiscomment_buffer (const GstBuffer * buffer,
+gst_tag_list_from_vorbiscomment (const guint8 * data, gsize size,
const guint8 * id_data, const guint id_data_length, gchar ** vendor_string)
{
#define ADVANCE(x) G_STMT_START{ \
gchar *cur, *value;
guint cur_size;
guint iterations;
- guint8 *data;
- guint size, value_len;
+ guint value_len;
GstTagList *list;
- g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
+ g_return_val_if_fail (data != NULL, NULL);
g_return_val_if_fail (id_data != NULL || id_data_length == 0, NULL);
- data = GST_BUFFER_DATA (buffer);
- size = GST_BUFFER_SIZE (buffer);
list = gst_tag_list_new ();
if (size < 11 || size <= id_data_length + 4)
#undef ADVANCE
}
+/**
+ * gst_tag_list_from_vorbiscomment_buffer:
+ * @buffer: buffer to convert
+ * @id_data: identification data at start of stream
+ * @id_data_length: length of identification data
+ * @vendor_string: pointer to a string that should take the vendor string
+ * of this vorbis comment or NULL if you don't need it.
+ *
+ * Creates a new tag list that contains the information parsed out of a
+ * vorbiscomment packet.
+ *
+ * Returns: A new #GstTagList with all tags that could be extracted from the
+ * given vorbiscomment buffer or NULL on error.
+ */
+GstTagList *
+gst_tag_list_from_vorbiscomment_buffer (GstBuffer * buffer,
+ const guint8 * id_data, const guint id_data_length, gchar ** vendor_string)
+{
+ GstTagList *res;
+ guint8 *data;
+ gsize size;
+
+ data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
+ res =
+ gst_tag_list_from_vorbiscomment (data, size, id_data, id_data_length,
+ vendor_string);
+ gst_buffer_unmap (buffer, data, size);
+
+ return res;
+}
+
typedef struct
{
guint count;
gst_tag_to_metadata_block_picture (const gchar * tag,
const GValue * image_value)
{
+#if 0
gchar *comment_data, *data_result;
const gchar *mime_type;
guint mime_type_len;
GstStructure *mime_struct;
GstBuffer *buffer;
+#endif
GList *l = NULL;
+#if 0
+ guint8 *data;
+ gsize size;
GstByteWriter writer;
GstTagImageType image_type = GST_TAG_IMAGE_TYPE_NONE;
gint width = 0, height = 0;
guint8 *metadata_block;
guint metadata_block_len;
+#endif
g_return_val_if_fail (image_value != NULL, NULL);
+ /* FIXME, no more buffer caps */
+ g_assert_not_reached ();
+
+#if 0
buffer = gst_value_get_buffer (image_value);
g_return_val_if_fail (gst_caps_is_fixed (buffer->caps), NULL);
mime_struct = gst_caps_get_structure (buffer->caps, 0);
&image_type, "width", G_TYPE_INT, &width, "height", G_TYPE_INT, &height,
NULL);
- metadata_block_len = 32 + mime_type_len + GST_BUFFER_SIZE (buffer);
+ metadata_block_len = 32 + mime_type_len + gst_buffer_get_size (buffer);
gst_byte_writer_init_with_size (&writer, metadata_block_len, TRUE);
if (image_type == GST_TAG_IMAGE_TYPE_NONE
gst_byte_writer_put_uint32_be_unchecked (&writer, 0);
/* for indexed formats the number of colors */
gst_byte_writer_put_uint32_be_unchecked (&writer, 0);
- gst_byte_writer_put_uint32_be_unchecked (&writer, GST_BUFFER_SIZE (buffer));
- gst_byte_writer_put_data_unchecked (&writer, GST_BUFFER_DATA (buffer),
- GST_BUFFER_SIZE (buffer));
+
+ data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
+ gst_byte_writer_put_uint32_be_unchecked (&writer, size);
+ gst_byte_writer_put_data_unchecked (&writer, data, size);
+ gst_buffer_unmap (buffer, data, size);
+
g_assert (gst_byte_writer_get_pos (&writer) == metadata_block_len);
metadata_block = gst_byte_writer_reset_and_get_data (&writer);
g_free (comment_data);
l = g_list_append (l, data_result);
+#endif
return l;
}
const gchar * vendor_string)
{
GstBuffer *buffer;
- guint8 *data;
+ guint8 *data, *odata;
guint i;
GList *l;
MyForEach my_data = { 0, 0, NULL };
required_size = id_data_length + 4 + vendor_len + 4 + 1;
gst_tag_list_foreach ((GstTagList *) list, write_one_tag, &my_data);
required_size += 4 * my_data.count + my_data.data_count;
+
buffer = gst_buffer_new_and_alloc (required_size);
- data = GST_BUFFER_DATA (buffer);
+ odata = data = gst_buffer_map (buffer, NULL, NULL, GST_MAP_WRITE);
if (id_data_length > 0) {
memcpy (data, id_data, id_data_length);
data += id_data_length;
g_list_foreach (my_data.entries, (GFunc) g_free, NULL);
g_list_free (my_data.entries);
*data = 1;
+ gst_buffer_unmap (buffer, odata, required_size);
return buffer;
}
* Since: 0.10.29
*/
GstTagList *
-gst_tag_list_from_xmp_buffer (const GstBuffer * buffer)
+gst_tag_list_from_xmp_buffer (GstBuffer * buffer)
{
GstTagList *list = NULL;
- const gchar *xps, *xp1, *xp2, *xpe, *ns, *ne;
- guint len, max_ft_len;
+ gchar *xps, *xp1, *xp2, *xpe, *ns, *ne;
+ gsize len, max_ft_len;
gboolean in_tag;
gchar *part, *pp;
guint i;
XmpTag *context_tag = NULL;
GstXmpNamespaceMap ns_map[] = {
- {"dc", NULL},
- {"exif", NULL},
- {"tiff", NULL},
- {"xap", NULL},
- {"photoshop", NULL},
- {"Iptc4xmpCore", NULL},
- {"Iptc4xmpExt", NULL},
+ {"dc", NULL}
+ ,
+ {"exif", NULL}
+ ,
+ {"tiff", NULL}
+ ,
+ {"xap", NULL}
+ ,
+ {"photoshop", NULL}
+ ,
+ {"Iptc4xmpCore", NULL}
+ ,
+ {"Iptc4xmpExt", NULL}
+ ,
{NULL, NULL}
};
xmp_tags_initialize ();
g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
- g_return_val_if_fail (GST_BUFFER_SIZE (buffer) > 0, NULL);
GST_LOG ("Starting xmp parsing");
- xps = (const gchar *) GST_BUFFER_DATA (buffer);
- len = GST_BUFFER_SIZE (buffer);
+ xps = gst_buffer_map (buffer, &len, NULL, GST_MAP_READ);
+ g_return_val_if_fail (len > 0, NULL);
+
xpe = &xps[len + 1];
/* check header and footer */
}
g_free (part);
+ gst_buffer_unmap (buffer, xps, len);
+
return list;
/* Errors */
XmpSerializationData serialization_data;
GString *data;
guint i;
+ gsize bsize;
+ gpointer bdata;
serialization_data.data = g_string_sized_new (4096);
serialization_data.schemas = schemas;
g_string_append_printf (data, "<?xpacket end=\"%c\"?>\n",
(read_only ? 'r' : 'w'));
+ bsize = data->len + 1;
+ bdata = g_string_free (data, FALSE);
+
buffer = gst_buffer_new ();
- GST_BUFFER_SIZE (buffer) = data->len + 1;
- GST_BUFFER_DATA (buffer) = (guint8 *) g_string_free (data, FALSE);
- GST_BUFFER_MALLOCDATA (buffer) = GST_BUFFER_DATA (buffer);
+ gst_buffer_take_memory (buffer,
+ gst_memory_new_wrapped (0, bdata, g_free, bsize, 0, bsize));
return buffer;
}
const gchar * tag);
/* functions to convert GstBuffers with vorbiscomment contents to GstTagLists and back */
-GstTagList * gst_tag_list_from_vorbiscomment_buffer (const GstBuffer * buffer,
+GstTagList * gst_tag_list_from_vorbiscomment (const guint8 * data,
+ gsize size,
+ const guint8 * id_data,
+ const guint id_data_length,
+ gchar ** vendor_string);
+GstTagList * gst_tag_list_from_vorbiscomment_buffer (GstBuffer * buffer,
const guint8 * id_data,
const guint id_data_length,
gchar ** vendor_string);
guint id3_picture_type);
/* functions to convert GstBuffers with xmp packets contents to GstTagLists and back */
-GstTagList * gst_tag_list_from_xmp_buffer (const GstBuffer * buffer);
+GstTagList * gst_tag_list_from_xmp_buffer (GstBuffer * buffer);
GstBuffer * gst_tag_list_to_xmp_buffer (const GstTagList * list,
gboolean read_only);
GstBuffer * gst_tag_list_to_xmp_buffer_full (const GstTagList * list,
GstBuffer * gst_tag_list_to_exif_buffer_with_tiff_header (const GstTagList * taglist);
-GstTagList * gst_tag_list_from_exif_buffer (const GstBuffer * buffer,
+GstTagList * gst_tag_list_from_exif_buffer (GstBuffer * buffer,
gint byte_order,
guint32 base_offset);
GstTagList * gst_tag_list_from_exif_buffer_with_tiff_header (
- const GstBuffer * buffer);
+ GstBuffer * buffer);
/* other tag-related functions */
guint image_data_len, GstTagImageType image_type)
{
const gchar *name;
-
GstBuffer *image;
-
GstCaps *caps;
+ guint8 *data;
g_return_val_if_fail (image_data != NULL, NULL);
g_return_val_if_fail (image_data_len > 0, NULL);
GST_DEBUG ("image data len: %u bytes", image_data_len);
/* allocate space for a NUL terminator for an uri too */
- image = gst_buffer_try_new_and_alloc (image_data_len + 1);
- if (image == NULL) {
- GST_WARNING ("failed to allocate buffer of %d for image", image_data_len);
- return NULL;
- }
+ image = gst_buffer_new_and_alloc (image_data_len + 1);
+ if (image == NULL)
+ goto alloc_failed;
- memcpy (GST_BUFFER_DATA (image), image_data, image_data_len);
- GST_BUFFER_DATA (image)[image_data_len] = '\0';
+ data = gst_buffer_map (image, NULL, NULL, GST_MAP_WRITE);
+ memcpy (data, image_data, image_data_len);
+ data[image_data_len] = '\0';
+ gst_buffer_unmap (image, data, image_data_len + 1);
/* Find GStreamer media type, can't trust declared type */
caps = gst_type_find_helper_for_buffer (NULL, image, NULL);
* to keep the original size of the image
*/
if (!g_str_equal (name, "text/uri-list"))
- GST_BUFFER_SIZE (image) = image_data_len;
+ gst_buffer_set_size (image, image_data_len);
if (image_type != GST_TAG_IMAGE_TYPE_NONE) {
GST_LOG ("Setting image type: %d", image_type);
image_type, NULL);
}
- gst_buffer_set_caps (image, caps);
+ g_warning ("extra image data can't be set");
gst_caps_unref (caps);
+
return image;
/* ERRORS */
gst_caps_unref (caps);
return NULL;
}
+alloc_failed:
+ {
+ GST_WARNING ("failed to allocate buffer of %d for image", image_data_len);
+ gst_buffer_unref (image);
+ return NULL;
+ }
+
}
CLEANFILES = $(BUILT_SOURCES)
libgstvideo_@GST_MAJORMINOR@_la_SOURCES = \
- video.c gstvideosink.c gstvideofilter.c convertframe.c
+ video.c gstvideosink.c gstvideofilter.c convertframe.c gstmetavideo.c
nodist_libgstvideo_@GST_MAJORMINOR@_la_SOURCES = $(BUILT_SOURCES)
libgstvideo_@GST_MAJORMINOR@includedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/video
libgstvideo_@GST_MAJORMINOR@include_HEADERS = \
- video.h gstvideosink.h gstvideofilter.h
+ video.h gstvideosink.h gstvideofilter.h gstmetavideo.h
nodist_libgstvideo_@GST_MAJORMINOR@include_HEADERS = $(built_headers)
libgstvideo_@GST_MAJORMINOR@_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
/**
* gst_video_convert_frame:
* @buf: a #GstBuffer
+ * @from_caps: the #GstCaps to convert from
* @to_caps: the #GstCaps to convert to
* @timeout: the maximum amount of time allowed for the processing.
* @error: pointer to a #GError. Can be %NULL.
*
*/
GstBuffer *
-gst_video_convert_frame (GstBuffer * buf, const GstCaps * to_caps,
- GstClockTime timeout, GError ** error)
+gst_video_convert_frame (GstBuffer * buf, GstCaps * from_caps,
+ const GstCaps * to_caps, GstClockTime timeout, GError ** error)
{
GstMessage *msg;
GstBuffer *result = NULL;
GError *err = NULL;
GstBus *bus;
- GstCaps *from_caps, *to_caps_copy = NULL;
+ GstCaps *to_caps_copy = NULL;
GstFlowReturn ret;
GstElement *pipeline, *src, *sink;
guint i, n;
g_return_val_if_fail (buf != NULL, NULL);
g_return_val_if_fail (to_caps != NULL, NULL);
- g_return_val_if_fail (GST_BUFFER_CAPS (buf) != NULL, NULL);
-
- from_caps = GST_BUFFER_CAPS (buf);
+ g_return_val_if_fail (from_caps != NULL, NULL);
to_caps_copy = gst_caps_new_empty ();
n = gst_caps_get_size (to_caps);
/* feed buffer in appsrc */
GST_DEBUG ("feeding buffer %p, size %u, caps %" GST_PTR_FORMAT,
- buf, GST_BUFFER_SIZE (buf), from_caps);
+ buf, gst_buffer_get_size (buf), from_caps);
g_signal_emit_by_name (src, "push-buffer", buf, &ret);
/* now see what happens. We either got an error somewhere or the pipeline
*
*/
void
-gst_video_convert_frame_async (GstBuffer * buf, const GstCaps * to_caps,
- GstClockTime timeout, GstVideoConvertFrameCallback callback,
- gpointer user_data, GDestroyNotify destroy_notify)
+gst_video_convert_frame_async (GstBuffer * buf, GstCaps * from_caps,
+ const GstCaps * to_caps, GstClockTime timeout,
+ GstVideoConvertFrameCallback callback, gpointer user_data,
+ GDestroyNotify destroy_notify)
{
GMainContext *context = NULL;
GError *error = NULL;
GstBus *bus;
- GstCaps *from_caps, *to_caps_copy = NULL;
+ GstCaps *to_caps_copy = NULL;
GstElement *pipeline, *src, *sink;
guint i, n;
GSource *source;
g_return_if_fail (buf != NULL);
g_return_if_fail (to_caps != NULL);
- g_return_if_fail (GST_BUFFER_CAPS (buf) != NULL);
+ g_return_if_fail (from_caps != NULL);
g_return_if_fail (callback != NULL);
context = g_main_context_get_thread_default ();
if (!context)
context = g_main_context_default ();
- from_caps = GST_BUFFER_CAPS (buf);
-
to_caps_copy = gst_caps_new_empty ();
n = gst_caps_get_size (to_caps);
for (i = 0; i < n; i++) {
--- /dev/null
+/* GStreamer
+ * Copyright (C) <2011> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * 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.
+ */
+
+#include "gstmetavideo.h"
+
+/* video metadata */
+const GstMetaInfo *
+gst_meta_video_get_info (void)
+{
+ static const GstMetaInfo *meta_video_info = NULL;
+
+ if (meta_video_info == NULL) {
+ meta_video_info = gst_meta_register (GST_META_API_VIDEO, "GstMetaVideo",
+ sizeof (GstMetaVideo),
+ (GstMetaInitFunction) NULL,
+ (GstMetaFreeFunction) NULL,
+ (GstMetaCopyFunction) NULL, (GstMetaTransformFunction) NULL);
+ }
+ return meta_video_info;
+}
+
+
+GstMetaVideo *
+gst_buffer_add_meta_video (GstBuffer * buffer, GstMetaVideoFlags flags,
+ GstVideoFormat format, guint width, guint height)
+{
+ GstMetaVideo *meta;
+ guint i;
+ GstMetaVideoPlane plane[GST_VIDEO_MAX_PLANES];
+
+ for (i = 0; i < GST_VIDEO_MAX_PLANES; i++) {
+ gint offset;
+
+ offset = gst_video_format_get_component_offset (format, i, width, height);
+ /* end when the offset is 0 for something else that the first component */
+ if (i > 0 && offset == 0)
+ break;
+
+ plane[i].offset = offset;
+ plane[i].stride = gst_video_format_get_row_stride (format, i, width);
+ }
+
+ meta = gst_buffer_add_meta_video_full (buffer, flags, format, width, height,
+ i, plane);
+
+ return meta;
+}
+
+GstMetaVideo *
+gst_buffer_add_meta_video_full (GstBuffer * buffer, GstMetaVideoFlags flags,
+ GstVideoFormat format, guint width, guint height,
+ guint n_planes, GstMetaVideoPlane plane[GST_VIDEO_MAX_PLANES])
+{
+ GstMetaVideo *meta;
+ guint i;
+
+ meta =
+ (GstMetaVideo *) gst_buffer_add_meta (buffer, GST_META_INFO_VIDEO, NULL);
+
+ meta->flags = flags;
+ meta->format = format;
+ meta->width = width;
+ meta->height = height;
+
+ meta->n_planes = n_planes;
+ for (i = 0; i < n_planes; i++)
+ meta->plane[i] = plane[i];
+
+ return meta;
+}
+
+static GstMemory *
+find_mem_for_offset (GstBuffer * buffer, guint * offset, GstMapFlags flags)
+{
+ guint n, i;
+ GstMemory *res = NULL;
+
+ n = gst_buffer_n_memory (buffer);
+ for (i = 0; i < n; i++) {
+ GstMemory *mem = NULL;
+ gsize size;
+
+ mem = gst_buffer_peek_memory (buffer, i, flags);
+ size = gst_memory_get_sizes (mem, NULL);
+
+ if (*offset < size) {
+ res = mem;
+ break;
+ }
+ *offset -= size;
+ }
+ return res;
+}
+
+gpointer
+gst_meta_video_map (GstMetaVideo * meta, guint plane, gint * stride,
+ GstMapFlags flags)
+{
+ guint offset;
+ gboolean write;
+ GstBuffer *buffer;
+ GstMemory *mem;
+ guint8 *base;
+
+ g_return_val_if_fail (meta != NULL, NULL);
+ g_return_val_if_fail (plane < meta->n_planes, NULL);
+ g_return_val_if_fail (stride != NULL, NULL);
+
+ buffer = meta->buffer;
+ g_return_val_if_fail (buffer != NULL, NULL);
+
+ write = (flags & GST_MAP_WRITE) != 0;
+ g_return_val_if_fail (write && !gst_buffer_is_writable (buffer), NULL);
+
+ offset = meta->plane[plane].offset;
+ *stride = meta->plane[plane].stride;
+ /* find the memory block for this plane, this is the memory block containing
+ * the plane offset */
+ mem = find_mem_for_offset (buffer, &offset, flags);
+
+ /* move to the right offset inside the block */
+ base = gst_memory_map (mem, NULL, NULL, flags);
+
+ return base + offset;
+}
+
+gboolean
+gst_meta_video_unmap (GstMetaVideo * meta, guint plane, gpointer data)
+{
+ guint offset;
+ GstBuffer *buffer;
+ GstMemory *mem;
+ guint8 *base;
+
+ g_return_val_if_fail (meta != NULL, FALSE);
+ g_return_val_if_fail (plane < meta->n_planes, FALSE);
+
+ buffer = meta->buffer;
+ g_return_val_if_fail (buffer != NULL, FALSE);
+
+ offset = meta->plane[plane].offset;
+ mem = find_mem_for_offset (buffer, &offset, GST_MAP_READ);
+ base = data;
+
+ gst_memory_unmap (mem, base - offset, -1);
+
+ return TRUE;
+}
--- /dev/null
+/* GStreamer
+ * Copyright (C) <2011> Wim Taymans <wim.taymans@gmail.com>
+ *
+ * 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_META_VIDEO_H__
+#define __GST_META_VIDEO_H__
+
+#include <gst/gst.h>
+
+#include <gst/video/video.h>
+
+G_BEGIN_DECLS
+
+#define GST_META_API_VIDEO "GstMetaVideo"
+#define GST_META_INFO_VIDEO (gst_meta_video_get_info())
+
+#define GST_VIDEO_MAX_PLANES 4
+
+typedef struct _GstMetaVideo GstMetaVideo;
+typedef struct _GstMetaVideoPlane GstMetaVideoPlane;
+
+/**
+ * GstMetaVideoFlags:
+ * @GST_META_VIDEO_FLAG_NONE: no flags
+ * @GST_META_VIDEO_FLAG_INTERLACED:
+ * @GST_META_VIDEO_FLAG_TTF:
+ * @GST_META_VIDEO_FLAG_RFF:
+ * @GST_META_VIDEO_FLAG_ONEFIELD:
+ * @GST_META_VIDEO_FLAG_TELECINE:
+ * @GST_META_VIDEO_FLAG_PROGRESSIVE:
+ *
+ * Extra video flags
+ */
+typedef enum {
+ GST_META_VIDEO_FLAG_NONE = 0,
+ GST_META_VIDEO_FLAG_INTERLACED = (1 << 0),
+ GST_META_VIDEO_FLAG_TTF = (1 << 1),
+ GST_META_VIDEO_FLAG_RFF = (1 << 2),
+ GST_META_VIDEO_FLAG_ONEFIELD = (1 << 3),
+ GST_META_VIDEO_FLAG_TELECINE = (1 << 4),
+ GST_META_VIDEO_FLAG_PROGRESSIVE = (1 << 5)
+} GstMetaVideoFlags;
+
+/**
+ * GstMetaVideoPlane:
+ * @offset: offset of the first pixel in the buffer memory region
+ * @stride: stride of the image lines. Can be negative when the image is
+ * upside-down
+ *
+ * Information for one video plane.
+ */
+struct _GstMetaVideoPlane {
+ gsize offset;
+ gint stride;
+};
+
+/**
+ * GstMetaVideo:
+ * @meta: parent #GstMeta
+ * @flags: additional video flags
+ * @n_planes: the number of planes in the image
+ * @plane: array of #GstMetaVideoPlane
+ * @map: map the memory of a plane
+ * @unmap: unmap the memory of a plane
+ *
+ * Extra buffer metadata describing image properties
+ */
+struct _GstMetaVideo {
+ GstMeta meta;
+
+ GstMetaVideoFlags flags;
+
+ GstBuffer *buffer;
+
+ GstVideoFormat format;
+ guint width;
+ guint height;
+
+ guint n_planes;
+ GstMetaVideoPlane plane[GST_VIDEO_MAX_PLANES];
+
+ gpointer (*map) (GstMetaVideo *meta, guint plane, gint *stride,
+ GstMapFlags flags);
+ gboolean (*unmap) (GstMetaVideo *meta, guint plane, gpointer data);
+};
+
+const GstMetaInfo * gst_meta_video_get_info (void);
+
+#define gst_buffer_get_meta_video(b) ((GstMetaVideo*)gst_buffer_get_meta((b),GST_META_INFO_VIDEO))
+GstMetaVideo * gst_buffer_add_meta_video (GstBuffer *buffer, GstMetaVideoFlags flags,
+ GstVideoFormat format, guint width, guint height);
+GstMetaVideo * gst_buffer_add_meta_video_full (GstBuffer *buffer, GstMetaVideoFlags flags,
+ GstVideoFormat format, guint width, guint height,
+ guint n_planes, GstMetaVideoPlane plane[GST_VIDEO_MAX_PLANES]);
+
+gpointer gst_meta_video_map (GstMetaVideo *meta, guint plane, gint *stride,
+ GstMapFlags flags);
+gboolean gst_meta_video_unmap (GstMetaVideo *meta, guint plane, gpointer data);
+
+
+G_END_DECLS
+
+#endif /* __GST_META_VIDEO_H__ */
static gboolean
gst_video_filter_get_unit_size (GstBaseTransform * btrans, GstCaps * caps,
- guint * size)
+ gsize * size)
{
GstVideoFormat fmt;
gint width, height;
{
const GValue *fps;
gchar *fps_string;
-
- const GstCaps *caps = NULL;
+ GstCaps *caps = NULL;
GstStructure *structure;
/* get pad caps */
- caps = GST_PAD_CAPS (pad);
- if (caps == NULL) {
+ caps = gst_pad_get_current_caps (pad);
+ if (caps == NULL)
+ goto no_caps;
+
+ structure = gst_caps_get_structure (caps, 0);
+ if ((fps = gst_structure_get_value (structure, "framerate")) == NULL)
+ goto no_framerate;
+
+ if (!GST_VALUE_HOLDS_FRACTION (fps))
+ goto no_fraction;
+
+ fps_string = gst_value_serialize (fps);
+ GST_DEBUG ("Framerate request on pad %s:%s: %s",
+ GST_DEBUG_PAD_NAME (pad), fps_string);
+ g_free (fps_string);
+
+ gst_caps_unref (caps);
+
+ return fps;
+
+ /* ERRORS */
+no_caps:
+ {
g_warning ("gstvideo: failed to get caps of pad %s:%s",
GST_DEBUG_PAD_NAME (pad));
return NULL;
}
-
- structure = gst_caps_get_structure (caps, 0);
- if ((fps = gst_structure_get_value (structure, "framerate")) == NULL) {
+no_framerate:
+ {
g_warning ("gstvideo: failed to get framerate property of pad %s:%s",
GST_DEBUG_PAD_NAME (pad));
+ gst_caps_unref (caps);
return NULL;
}
- if (!GST_VALUE_HOLDS_FRACTION (fps)) {
+no_fraction:
+ {
g_warning
("gstvideo: framerate property of pad %s:%s is not of type Fraction",
GST_DEBUG_PAD_NAME (pad));
+ gst_caps_unref (caps);
return NULL;
}
-
- fps_string = gst_value_serialize (fps);
- GST_DEBUG ("Framerate request on pad %s:%s: %s",
- GST_DEBUG_PAD_NAME (pad), fps_string);
- g_free (fps_string);
-
- return fps;
}
/**
gboolean
gst_video_get_size (GstPad * pad, gint * width, gint * height)
{
- const GstCaps *caps = NULL;
+ GstCaps *caps = NULL;
GstStructure *structure;
gboolean ret;
g_return_val_if_fail (width != NULL, FALSE);
g_return_val_if_fail (height != NULL, FALSE);
- caps = GST_PAD_CAPS (pad);
-
- if (caps == NULL) {
- g_warning ("gstvideo: failed to get caps of pad %s:%s",
- GST_DEBUG_PAD_NAME (pad));
- return FALSE;
- }
+ caps = gst_pad_get_current_caps (pad);
+ if (caps == NULL)
+ goto no_caps;
structure = gst_caps_get_structure (caps, 0);
ret = gst_structure_get_int (structure, "width", width);
ret &= gst_structure_get_int (structure, "height", height);
+ gst_caps_unref (caps);
- if (!ret) {
- g_warning ("gstvideo: failed to get size properties on pad %s:%s",
- GST_DEBUG_PAD_NAME (pad));
- return FALSE;
- }
+ if (!ret)
+ goto no_size;
GST_DEBUG ("size request on pad %s:%s: %dx%d",
GST_DEBUG_PAD_NAME (pad), width ? *width : -1, height ? *height : -1);
return TRUE;
+
+ /* ERROR */
+no_caps:
+ {
+ g_warning ("gstvideo: failed to get caps of pad %s:%s",
+ GST_DEBUG_PAD_NAME (pad));
+ return FALSE;
+ }
+no_size:
+ {
+ g_warning ("gstvideo: failed to get size properties on pad %s:%s",
+ GST_DEBUG_PAD_NAME (pad));
+ return FALSE;
+ }
}
/**
GstEvent *gst_video_event_new_still_frame (gboolean in_still);
gboolean gst_video_event_parse_still_frame (GstEvent *event, gboolean *in_still);
-GstBuffer *gst_video_convert_frame(GstBuffer *buf, const GstCaps *to_caps,
+GstBuffer *gst_video_convert_frame(GstBuffer *buf, GstCaps *from_caps, const GstCaps *to_caps,
GstClockTime timeout, GError **error);
typedef void (*GstVideoConvertFrameCallback) (GstBuffer *buf, GError *error, gpointer user_data);
-void gst_video_convert_frame_async(GstBuffer *buf, const GstCaps *to_caps,
+void gst_video_convert_frame_async(GstBuffer *buf, GstCaps *from_caps, const GstCaps *to_caps,
GstClockTime timeout, GstVideoConvertFrameCallback callback,
gpointer user_data, GDestroyNotify destroy_notify);
GST_STATIC_CAPS (CAPS)
);
-GST_BOILERPLATE (GstAdder, gst_adder, GstElement, GST_TYPE_ELEMENT);
+#define gst_adder_parent_class parent_class
+G_DEFINE_TYPE (GstAdder, gst_adder, GST_TYPE_ELEMENT);
static void gst_adder_dispose (GObject * object);
static void gst_adder_set_property (GObject * object, guint prop_id,
static gboolean gst_adder_sink_event (GstPad * pad, GstEvent * event);
static GstPad *gst_adder_request_new_pad (GstElement * element,
- GstPadTemplate * temp, const gchar * unused);
+ GstPadTemplate * temp, const gchar * unused, const GstCaps * caps);
static void gst_adder_release_pad (GstElement * element, GstPad * pad);
static GstStateChangeReturn gst_adder_change_state (GstElement * element,
* if we have filtercaps set, use those to constrain the target caps.
*/
static GstCaps *
-gst_adder_sink_getcaps (GstPad * pad)
+gst_adder_sink_getcaps (GstPad * pad, GstCaps * filter)
{
GstAdder *adder;
GstCaps *result, *peercaps, *sinkcaps, *filter_caps;
GST_OBJECT_LOCK (adder);
/* take filter */
- if ((filter_caps = adder->filter_caps))
- gst_caps_ref (filter_caps);
+ if ((filter_caps = adder->filter_caps)) {
+ if (filter)
+ filter_caps =
+ gst_caps_intersect_full (filter, filter_caps,
+ GST_CAPS_INTERSECT_FIRST);
+ else
+ gst_caps_ref (filter_caps);
+ } else {
+ filter_caps = gst_caps_ref (filter);
+ }
GST_OBJECT_UNLOCK (adder);
+ if (filter_caps && gst_caps_is_empty (filter_caps)) {
+ GST_WARNING_OBJECT (pad, "Empty filter caps");
+ return filter_caps;
+ }
+
/* get the downstream possible caps */
- peercaps = gst_pad_peer_get_caps (adder->srcpad);
+ peercaps = gst_pad_peer_get_caps (adder->srcpad, filter_caps);
+
+ /* get the allowed caps on this sinkpad */
+ sinkcaps = gst_pad_get_current_caps (pad);
+ if (sinkcaps == NULL) {
+ sinkcaps = gst_pad_get_pad_template_caps (pad);
+ if (!sinkcaps)
+ sinkcaps = gst_caps_new_any ();
+ }
- /* get the allowed caps on this sinkpad, we use the fixed caps function so
- * that it does not call recursively in this function. */
- sinkcaps = gst_pad_get_fixed_caps_func (pad);
if (peercaps) {
- /* restrict with filter-caps if any */
- if (filter_caps) {
- GST_DEBUG_OBJECT (adder, "filtering peer caps");
- result = gst_caps_intersect (peercaps, filter_caps);
- gst_caps_unref (peercaps);
- peercaps = result;
- }
/* if the peer has caps, intersect */
GST_DEBUG_OBJECT (adder, "intersecting peer and template caps");
- result = gst_caps_intersect (peercaps, sinkcaps);
+ result =
+ gst_caps_intersect_full (peercaps, sinkcaps, GST_CAPS_INTERSECT_FIRST);
gst_caps_unref (peercaps);
gst_caps_unref (sinkcaps);
} else {
/* restrict with filter-caps if any */
if (filter_caps) {
GST_DEBUG_OBJECT (adder, "no peer caps, using filtered sinkcaps");
- result = gst_caps_intersect (sinkcaps, filter_caps);
+ result =
+ gst_caps_intersect_full (filter_caps, sinkcaps,
+ GST_CAPS_INTERSECT_FIRST);
gst_caps_unref (sinkcaps);
} else {
GST_DEBUG_OBJECT (adder, "no peer caps, using sinkcaps");
return result;
}
+typedef struct
+{
+ GstPad *pad;
+ GstCaps *caps;
+} IterData;
+
+static void
+setcapsfunc (const GValue * item, IterData * data)
+{
+ GstPad *otherpad = g_value_get_object (item);
+
+ if (otherpad != data->pad)
+ gst_pad_set_caps (data->pad, data->caps);
+}
+
/* the first caps we receive on any of the sinkpads will define the caps for all
* the other sinkpads because we can only mix streams with the same caps.
*/
gst_adder_setcaps (GstPad * pad, GstCaps * caps)
{
GstAdder *adder;
- GList *pads;
GstStructure *structure;
const char *media_type;
+ GstIterator *it;
+ GstIteratorResult ires;
+ IterData idata;
+ gboolean done;
adder = GST_ADDER (GST_PAD_PARENT (pad));
GST_LOG_OBJECT (adder, "setting caps on pad %p,%s to %" GST_PTR_FORMAT, pad,
GST_PAD_NAME (pad), caps);
+ it = gst_element_iterate_pads (GST_ELEMENT_CAST (adder));
+
/* FIXME, see if the other pads can accept the format. Also lock the
* format on the other pads to this new format. */
- GST_OBJECT_LOCK (adder);
- pads = GST_ELEMENT (adder)->pads;
- while (pads) {
- GstPad *otherpad = GST_PAD (pads->data);
+ idata.caps = caps;
+ idata.pad = pad;
- if (otherpad != pad) {
- gst_caps_replace (&GST_PAD_CAPS (otherpad), caps);
+ done = FALSE;
+ while (!done) {
+ ires = gst_iterator_foreach (it, (GstIteratorForeachFunction) setcapsfunc,
+ &idata);
+
+ switch (ires) {
+ case GST_ITERATOR_RESYNC:
+ gst_iterator_resync (it);
+ break;
+ default:
+ done = TRUE;
+ break;
}
- pads = g_list_next (pads);
}
- GST_OBJECT_UNLOCK (adder);
/* parse caps now */
structure = gst_caps_get_structure (caps, 0);
GstFormat format;
GstIterator *it;
gboolean done;
+ GValue item = { 0, };
/* parse format */
gst_query_parse_duration (query, &format, NULL);
while (!done) {
GstIteratorResult ires;
- gpointer item;
-
ires = gst_iterator_next (it, &item);
switch (ires) {
case GST_ITERATOR_DONE:
break;
case GST_ITERATOR_OK:
{
- GstPad *pad = GST_PAD_CAST (item);
-
+ GstPad *pad = g_value_get_object (&item);
gint64 duration;
/* ask sink peer for duration */
else if (duration > max)
max = duration;
}
- gst_object_unref (pad);
+ g_value_reset (&item);
break;
}
case GST_ITERATOR_RESYNC:
break;
}
}
+ g_value_unset (&item);
gst_iterator_free (it);
if (res) {
gboolean res;
GstIterator *it;
gboolean done;
+ GValue item = { 0, };
res = TRUE;
done = FALSE;
while (!done) {
GstIteratorResult ires;
- gpointer item;
-
ires = gst_iterator_next (it, &item);
switch (ires) {
case GST_ITERATOR_DONE:
break;
case GST_ITERATOR_OK:
{
- GstPad *pad = GST_PAD_CAST (item);
+ GstPad *pad = g_value_get_object (&item);
GstQuery *peerquery;
GstClockTime min_cur, max_cur;
gboolean live_cur;
}
gst_query_unref (peerquery);
- gst_object_unref (pad);
+ g_value_reset (&item);
break;
}
case GST_ITERATOR_RESYNC:
break;
}
}
+ g_value_unset (&item);
gst_iterator_free (it);
if (res) {
switch (format) {
case GST_FORMAT_TIME:
/* FIXME, bring to stream time, might be tricky */
- gst_query_set_position (query, format, adder->timestamp);
+ gst_query_set_position (query, format, adder->segment.position);
res = TRUE;
break;
case GST_FORMAT_DEFAULT:
} EventData;
static gboolean
-forward_event_func (GstPad * pad, GValue * ret, EventData * data)
+forward_event_func (const GValue * val, GValue * ret, EventData * data)
{
+ GstPad *pad = g_value_get_object (val);
GstEvent *event = data->event;
gst_event_ref (event);
GST_LOG_OBJECT (pad, "Sent event %p (%s).",
event, GST_EVENT_TYPE_NAME (event));
}
- gst_object_unref (pad);
/* continue on other pads, even if one failed */
return TRUE;
g_value_set_boolean (&vret, FALSE);
it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (adder));
while (TRUE) {
- ires = gst_iterator_fold (it, (GstIteratorFoldFunction) forward_event_func,
+ ires =
+ gst_iterator_fold (it, (GstIteratorFoldFunction) forward_event_func,
&vret, &data);
switch (ires) {
case GST_ITERATOR_RESYNC:
case GST_EVENT_SEEK:
{
GstSeekFlags flags;
+ gdouble rate;
GstSeekType curtype, endtype;
gint64 cur, end;
gboolean flush;
/* parse the seek parameters */
- gst_event_parse_seek (event, &adder->segment_rate, NULL, &flags, &curtype,
+ gst_event_parse_seek (event, &rate, NULL, &flags, &curtype,
&cur, &endtype, &end);
if ((curtype != GST_SEEK_TYPE_NONE) && (curtype != GST_SEEK_TYPE_SET)) {
* segment. After we have the lock, no collect function is running and no
* new collect function will be called for as long as we're flushing. */
GST_OBJECT_LOCK (adder->collect);
+ adder->segment.rate = rate;
if (curtype == GST_SEEK_TYPE_SET)
- adder->segment_start = cur;
+ adder->segment.start = cur;
else
- adder->segment_start = 0;
+ adder->segment.start = 0;
if (endtype == GST_SEEK_TYPE_SET)
- adder->segment_end = end;
+ adder->segment.stop = end;
else
- adder->segment_end = GST_CLOCK_TIME_NONE;
+ adder->segment.stop = GST_CLOCK_TIME_NONE;
/* make sure we push a new segment, to inform about new basetime
* see FIXME in gst_adder_collected() */
adder->segment_pending = TRUE;
}
static void
-gst_adder_base_init (gpointer g_class)
-{
- GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&gst_adder_src_template));
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&gst_adder_sink_template));
- gst_element_class_set_details_simple (gstelement_class, "Adder",
- "Generic/Audio",
- "Add N audio channels together",
- "Thomas Vander Stichele <thomas at apestaart dot org>");
-}
-
-static void
gst_adder_class_init (GstAdderClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
"object.", GST_TYPE_CAPS,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_adder_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_adder_sink_template));
+ gst_element_class_set_details_simple (gstelement_class, "Adder",
+ "Generic/Audio",
+ "Add N audio channels together",
+ "Thomas Vander Stichele <thomas at apestaart dot org>");
+
gstelement_class->request_new_pad =
GST_DEBUG_FUNCPTR (gst_adder_request_new_pad);
gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_adder_release_pad);
}
static void
-gst_adder_init (GstAdder * adder, GstAdderClass * klass)
+gst_adder_init (GstAdder * adder)
{
GstPadTemplate *template;
static GstPad *
gst_adder_request_new_pad (GstElement * element, GstPadTemplate * templ,
- const gchar * unused)
+ const gchar * unused, const GstCaps * caps)
{
gchar *name;
GstAdder *adder;
GST_LOG_OBJECT (adder, "channel %p: preparing output buffer of %d bytes",
collect_data, outsize);
- /* make data and metadata writable, can simply return the inbuf when we
- * are the only one referencing this buffer. If this is the last (and
- * only) GAP buffer, it will automatically copy the GAP flag. */
- outbuf = gst_buffer_make_writable (inbuf);
- outdata = GST_BUFFER_DATA (outbuf);
- gst_buffer_set_caps (outbuf, GST_PAD_CAPS (adder->srcpad));
+
+ outdata = gst_buffer_map (outbuf, NULL, NULL, GST_MAP_WRITE);
} else {
if (!is_gap) {
/* we had a previous output buffer, mix this non-GAP buffer */
guint8 *indata;
- guint insize;
+ gsize insize;
- indata = GST_BUFFER_DATA (inbuf);
- insize = GST_BUFFER_SIZE (inbuf);
+ indata = gst_buffer_map (inbuf, &insize, NULL, GST_MAP_READ);
/* all buffers should have outsize, there are no short buffers because we
* asked for the max size above */
/* further buffers, need to add them */
adder->func ((gpointer) outdata, (gpointer) indata,
insize / adder->sample_size);
+ gst_buffer_unmap (inbuf, indata, insize);
} else {
/* skip gap buffer */
GST_LOG_OBJECT (adder, "channel %p: skipping GAP buffer", collect_data);
gst_buffer_unref (inbuf);
}
}
+ if (outbuf)
+ gst_buffer_unmap (outbuf, outdata, outsize);
if (outbuf == NULL) {
/* no output buffer, reuse one of the GAP buffers then if we have one */
* event. We also adjust offset & timestamp acordingly.
* This basically ignores all newsegments sent by upstream.
*/
- event = gst_event_new_new_segment_full (FALSE, adder->segment_rate,
- 1.0, GST_FORMAT_TIME, adder->segment_start, adder->segment_end,
- adder->segment_start);
- if (adder->segment_rate > 0.0) {
- adder->timestamp = adder->segment_start;
+ event = gst_event_new_segment (&adder->segment);
+
+ if (adder->segment.rate > 0.0) {
+ adder->segment.position = adder->segment.start;
} else {
- adder->timestamp = adder->segment_end;
+ adder->segment.position = adder->segment.stop;
}
- adder->offset = gst_util_uint64_scale (adder->timestamp,
+ adder->offset = gst_util_uint64_scale (adder->segment.position,
adder->rate, GST_SECOND);
GST_INFO_OBJECT (adder, "seg_start %" G_GUINT64_FORMAT ", seg_end %"
- G_GUINT64_FORMAT, adder->segment_start, adder->segment_end);
+ G_GUINT64_FORMAT, adder->segment.start, adder->segment.stop);
GST_INFO_OBJECT (adder, "timestamp %" G_GINT64_FORMAT ",new offset %"
- G_GINT64_FORMAT, adder->timestamp, adder->offset);
+ G_GINT64_FORMAT, adder->segment.position, adder->offset);
if (event) {
if (!gst_pad_push_event (adder->srcpad, event)) {
} else {
GST_WARNING_OBJECT (adder->srcpad, "Creating new segment event for "
"start:%" G_GINT64_FORMAT " end:%" G_GINT64_FORMAT " failed",
- adder->segment_start, adder->segment_end);
+ adder->segment.start, adder->segment.stop);
}
}
/* for the next timestamp, use the sample counter, which will
* never accumulate rounding errors */
- if (adder->segment_rate > 0.0) {
+ if (adder->segment.rate > 0.0) {
next_offset = adder->offset + outsize / adder->bps;
} else {
next_offset = adder->offset - outsize / adder->bps;
/* set timestamps on the output buffer */
- if (adder->segment_rate > 0.0) {
- GST_BUFFER_TIMESTAMP (outbuf) = adder->timestamp;
+ if (adder->segment.rate > 0.0) {
+ GST_BUFFER_TIMESTAMP (outbuf) = adder->segment.position;
GST_BUFFER_OFFSET (outbuf) = adder->offset;
GST_BUFFER_OFFSET_END (outbuf) = next_offset;
- GST_BUFFER_DURATION (outbuf) = next_timestamp - adder->timestamp;
+ GST_BUFFER_DURATION (outbuf) = next_timestamp - adder->segment.position;
} else {
GST_BUFFER_TIMESTAMP (outbuf) = next_timestamp;
GST_BUFFER_OFFSET (outbuf) = next_offset;
GST_BUFFER_OFFSET_END (outbuf) = adder->offset;
- GST_BUFFER_DURATION (outbuf) = adder->timestamp - next_timestamp;
+ GST_BUFFER_DURATION (outbuf) = adder->segment.position - next_timestamp;
}
adder->offset = next_offset;
- adder->timestamp = next_timestamp;
+ adder->segment.position = next_timestamp;
/* send it out */
GST_LOG_OBJECT (adder, "pushing outbuf %p, timestamp %" GST_TIME_FORMAT
case GST_STATE_CHANGE_NULL_TO_READY:
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
- adder->timestamp = 0;
+ adder->segment.position = 0;
adder->offset = 0;
adder->flush_stop_pending = FALSE;
adder->segment_pending = TRUE;
- adder->segment_start = 0;
- adder->segment_end = GST_CLOCK_TIME_NONE;
- adder->segment_rate = 1.0;
- gst_segment_init (&adder->segment, GST_FORMAT_UNDEFINED);
+ gst_segment_init (&adder->segment, GST_FORMAT_TIME);
gst_collect_pads_start (adder->collect);
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
GstAdderFunction func;
/* counters to keep track of timestamps */
- gint64 timestamp;
gint64 offset;
/* sink event handling */
GstPadEventFunction collect_event;
GstSegment segment;
gboolean segment_pending;
- guint64 segment_start, segment_end;
- gdouble segment_rate;
/* src event handling */
gboolean flush_stop_pending;
/* gstreamer functions */
static gboolean gst_audio_convert_get_unit_size (GstBaseTransform * base,
- GstCaps * caps, guint * size);
+ GstCaps * caps, gsize * size);
static GstCaps *gst_audio_convert_transform_caps (GstBaseTransform * base,
- GstPadDirection direction, GstCaps * caps);
+ GstPadDirection direction, GstCaps * caps, GstCaps * filter);
static void gst_audio_convert_fixate_caps (GstBaseTransform * base,
GstPadDirection direction, GstCaps * caps, GstCaps * othercaps);
static gboolean gst_audio_convert_set_caps (GstBaseTransform * base,
ARG_NOISE_SHAPING,
};
-#define DEBUG_INIT(bla) \
+#define DEBUG_INIT \
GST_DEBUG_CATEGORY_INIT (audio_convert_debug, "audioconvert", 0, "audio conversion element"); \
GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE");
-
-GST_BOILERPLATE_FULL (GstAudioConvert, gst_audio_convert, GstBaseTransform,
+#define gst_audio_convert_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstAudioConvert, gst_audio_convert,
GST_TYPE_BASE_TRANSFORM, DEBUG_INIT);
/*** GSTREAMER PROTOTYPES *****************************************************/
/*** TYPE FUNCTIONS ***********************************************************/
-
-static void
-gst_audio_convert_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_audio_convert_src_template));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&gst_audio_convert_sink_template));
- gst_element_class_set_details_simple (element_class,
- "Audio converter", "Filter/Converter/Audio",
- "Convert audio to different formats", "Benjamin Otte <otte@gnome.org>");
-}
-
static void
gst_audio_convert_class_init (GstAudioConvertClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
GstBaseTransformClass *basetransform_class = GST_BASE_TRANSFORM_CLASS (klass);
gobject_class->dispose = gst_audio_convert_dispose;
GST_TYPE_AUDIO_CONVERT_NOISE_SHAPING, NOISE_SHAPING_NONE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_audio_convert_src_template));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_audio_convert_sink_template));
+ gst_element_class_set_details_simple (element_class,
+ "Audio converter", "Filter/Converter/Audio",
+ "Convert audio to different formats", "Benjamin Otte <otte@gnome.org>");
+
basetransform_class->get_unit_size =
GST_DEBUG_FUNCPTR (gst_audio_convert_get_unit_size);
basetransform_class->transform_caps =
}
static void
-gst_audio_convert_init (GstAudioConvert * this, GstAudioConvertClass * g_class)
+gst_audio_convert_init (GstAudioConvert * this)
{
this->dither = DITHER_TPDF;
this->ns = NOISE_SHAPING_NONE;
/* BaseTransform vmethods */
static gboolean
gst_audio_convert_get_unit_size (GstBaseTransform * base, GstCaps * caps,
- guint * size)
+ gsize * size)
{
AudioConvertFmt fmt = { 0 };
*/
static GstCaps *
gst_audio_convert_transform_caps (GstBaseTransform * base,
- GstPadDirection direction, GstCaps * caps)
+ GstPadDirection direction, GstCaps * caps, GstCaps * filter)
{
GstCaps *ret;
GstStructure *s, *structure;
GST_DEBUG_OBJECT (base, "Caps transformed to %" GST_PTR_FORMAT, ret);
+ if (filter) {
+ GstCaps *intersection;
+
+ GST_DEBUG_OBJECT (base, "Using filter caps %" GST_PTR_FORMAT, filter);
+ intersection =
+ gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST);
+ gst_caps_unref (ret);
+ ret = intersection;
+ GST_DEBUG_OBJECT (base, "Intersection %" GST_PTR_FORMAT, ret);
+ }
+
return ret;
}
gst_audio_convert_transform (GstBaseTransform * base, GstBuffer * inbuf,
GstBuffer * outbuf)
{
+ GstFlowReturn ret;
GstAudioConvert *this = GST_AUDIO_CONVERT (base);
+ gsize srcsize, dstsize;
gint insize, outsize;
gint samples;
gpointer src, dst;
- GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, base, "converting audio from %"
- GST_PTR_FORMAT " to %" GST_PTR_FORMAT, GST_BUFFER_CAPS (inbuf),
- GST_BUFFER_CAPS (outbuf));
-
/* get amount of samples to convert. */
- samples = GST_BUFFER_SIZE (inbuf) / this->ctx.in.unit_size;
+ samples = gst_buffer_get_size (inbuf) / this->ctx.in.unit_size;
/* get in/output sizes, to see if the buffers we got are of correct
* sizes */
if (insize == 0 || outsize == 0)
return GST_FLOW_OK;
+ /* get src and dst data */
+ src = gst_buffer_map (inbuf, &srcsize, NULL, GST_MAP_READ);
+ dst = gst_buffer_map (outbuf, &dstsize, NULL, GST_MAP_WRITE);
+
/* check in and outsize */
- if (GST_BUFFER_SIZE (inbuf) < insize)
+ if (srcsize < insize)
goto wrong_size;
- if (GST_BUFFER_SIZE (outbuf) < outsize)
+ if (dstsize < outsize)
goto wrong_size;
- /* get src and dst data */
- src = GST_BUFFER_DATA (inbuf);
- dst = GST_BUFFER_DATA (outbuf);
-
/* and convert the samples */
if (!GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP)) {
if (!audio_convert_convert (&this->ctx, src, dst,
/* Create silence buffer */
gst_audio_convert_create_silence_buffer (this, dst, outsize);
}
+ ret = GST_FLOW_OK;
- GST_BUFFER_SIZE (outbuf) = outsize;
+done:
+ gst_buffer_unmap (outbuf, dst, outsize);
+ gst_buffer_unmap (inbuf, src, srcsize);
- return GST_FLOW_OK;
+ return ret;
/* ERRORS */
error:
GST_ELEMENT_ERROR (this, STREAM, FORMAT,
(NULL),
("input/output buffers are of wrong size in: %d < %d or out: %d < %d",
- GST_BUFFER_SIZE (inbuf), insize, GST_BUFFER_SIZE (outbuf),
- outsize));
- return GST_FLOW_ERROR;
+ srcsize, insize, dstsize, outsize));
+ ret = GST_FLOW_ERROR;
+ goto done;
}
convert_error:
{
GST_ELEMENT_ERROR (this, STREAM, FORMAT,
(NULL), ("error while converting"));
- return GST_FLOW_ERROR;
+ ret = GST_FLOW_ERROR;
+ goto done;
}
}
GST_AUDIO_FLOAT_PAD_TEMPLATE_CAPS)
);
-static void gst_audio_rate_base_init (gpointer g_class);
-static void gst_audio_rate_class_init (GstAudioRateClass * klass);
-static void gst_audio_rate_init (GstAudioRate * audiorate);
static gboolean gst_audio_rate_sink_event (GstPad * pad, GstEvent * event);
static gboolean gst_audio_rate_src_event (GstPad * pad, GstEvent * event);
static GstFlowReturn gst_audio_rate_chain (GstPad * pad, GstBuffer * buf);
static GstStateChangeReturn gst_audio_rate_change_state (GstElement * element,
GstStateChange transition);
-static GstElementClass *parent_class = NULL;
-
/*static guint gst_audio_rate_signals[LAST_SIGNAL] = { 0 }; */
static GParamSpec *pspec_drop = NULL;
static GParamSpec *pspec_add = NULL;
-static GType
-gst_audio_rate_get_type (void)
-{
- static GType audio_rate_type = 0;
-
- if (!audio_rate_type) {
- static const GTypeInfo audio_rate_info = {
- sizeof (GstAudioRateClass),
- gst_audio_rate_base_init,
- NULL,
- (GClassInitFunc) gst_audio_rate_class_init,
- NULL,
- NULL,
- sizeof (GstAudioRate),
- 0,
- (GInstanceInitFunc) gst_audio_rate_init,
- };
-
- audio_rate_type = g_type_register_static (GST_TYPE_ELEMENT,
- "GstAudioRate", &audio_rate_info, 0);
- }
-
- return audio_rate_type;
-}
-
-static void
-gst_audio_rate_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_set_details_simple (element_class,
- "Audio rate adjuster", "Filter/Effect/Audio",
- "Drops/duplicates/adjusts timestamps on audio samples to make a perfect stream",
- "Wim Taymans <wim@fluendo.com>");
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&gst_audio_rate_sink_template));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&gst_audio_rate_src_template));
-}
+#define gst_audio_rate_parent_class parent_class
+G_DEFINE_TYPE (GstAudioRate, gst_audio_rate, GST_TYPE_ELEMENT);
static void
gst_audio_rate_class_init (GstAudioRateClass * klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
- parent_class = g_type_class_peek_parent (klass);
-
object_class->set_property = gst_audio_rate_set_property;
object_class->get_property = gst_audio_rate_get_property;
"Don't produce buffers before the first one we receive",
DEFAULT_SKIP_TO_FIRST, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ gst_element_class_set_details_simple (element_class,
+ "Audio rate adjuster", "Filter/Effect/Audio",
+ "Drops/duplicates/adjusts timestamps on audio samples to make a perfect stream",
+ "Wim Taymans <wim@fluendo.com>");
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_audio_rate_sink_template));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_audio_rate_src_template));
+
element_class->change_state = gst_audio_rate_change_state;
}
gst_audio_rate_reset (audiorate);
res = gst_pad_push_event (audiorate->srcpad, event);
break;
- case GST_EVENT_NEWSEGMENT:
+ case GST_EVENT_SEGMENT:
{
- GstFormat format;
- gdouble rate, arate;
- gint64 start, stop, time;
- gboolean update;
-
- gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
- &start, &stop, &time);
+ gst_event_copy_segment (event, &audiorate->sink_segment);
GST_DEBUG_OBJECT (audiorate, "handle NEWSEGMENT");
+#if 0
/* FIXME: bad things will likely happen if rate < 0 ... */
if (!update) {
/* a new segment starts. We need to figure out what will be the next
* sample offset. We mark the offsets as invalid so that the _chain
* function will perform this calculation. */
gst_audio_rate_fill_to_time (audiorate, audiorate->src_segment.stop);
+#endif
audiorate->next_offset = -1;
audiorate->next_ts = -1;
+#if 0
} else {
gst_audio_rate_fill_to_time (audiorate, audiorate->src_segment.start);
}
-
- /* we accept all formats */
- gst_segment_set_newsegment_full (&audiorate->sink_segment, update, rate,
- arate, format, start, stop, time);
+#endif
GST_DEBUG_OBJECT (audiorate, "updated segment: %" GST_SEGMENT_FORMAT,
&audiorate->sink_segment);
- if (format == GST_FORMAT_TIME) {
+ if (audiorate->sink_segment.format == GST_FORMAT_TIME) {
/* TIME formats can be copied to src and forwarded */
res = gst_pad_push_event (audiorate->srcpad, event);
- memcpy (&audiorate->src_segment, &audiorate->sink_segment,
- sizeof (GstSegment));
+ gst_segment_copy_into (&audiorate->sink_segment,
+ &audiorate->src_segment);
} else {
/* other formats will be handled in the _chain function */
gst_event_unref (event);
static gboolean
gst_audio_rate_convert (GstAudioRate * audiorate,
- GstFormat src_fmt, gint64 src_val, GstFormat dest_fmt, gint64 * dest_val)
+ GstFormat src_fmt, guint64 src_val, GstFormat dest_fmt, guint64 * dest_val)
{
if (src_fmt == dest_fmt) {
*dest_val = src_val;
dst_fmt, &audiorate->src_segment.field);
audiorate->sink_segment.rate = audiorate->src_segment.rate;
- audiorate->sink_segment.abs_rate = audiorate->src_segment.abs_rate;
audiorate->sink_segment.flags = audiorate->src_segment.flags;
audiorate->sink_segment.applied_rate = audiorate->src_segment.applied_rate;
CONVERT_VAL (start);
CONVERT_VAL (stop);
CONVERT_VAL (time);
- CONVERT_VAL (accum);
- CONVERT_VAL (last_stop);
+ CONVERT_VAL (base);
+ CONVERT_VAL (position);
#undef CONVERT_VAL
return TRUE;
in_time = audiorate->next_ts;
}
- in_size = GST_BUFFER_SIZE (buf);
+ in_size = gst_buffer_get_size (buf);
in_samples = in_size / audiorate->bytes_per_sample;
/* calculate the buffer offset */
while (fillsamples > 0) {
guint64 cursamples = MIN (fillsamples, audiorate->rate);
+ guint8 *data;
fillsamples -= cursamples;
fillsize = cursamples * audiorate->bytes_per_sample;
fill = gst_buffer_new_and_alloc (fillsize);
+
+ data = gst_buffer_map (fill, NULL, NULL, GST_MAP_WRITE);
/* FIXME, 0 might not be the silence byte for the negotiated format. */
- memset (GST_BUFFER_DATA (fill), 0, fillsize);
+ memset (data, 0, fillsize);
+ gst_buffer_unmap (fill, data, fillsize);
GST_DEBUG_OBJECT (audiorate, "inserting %" G_GUINT64_FORMAT " samples",
cursamples);
GST_BUFFER_FLAG_SET (fill, GST_BUFFER_FLAG_DISCONT);
audiorate->discont = FALSE;
}
- gst_buffer_set_caps (fill, GST_PAD_CAPS (audiorate->srcpad));
ret = gst_pad_push (audiorate->srcpad, fill);
if (ret != GST_FLOW_OK)
truncsize = truncsamples * audiorate->bytes_per_sample;
leftsize = in_size - truncsize;
- trunc = gst_buffer_create_sub (buf, truncsize, leftsize);
+ trunc =
+ gst_buffer_copy_region (buf, GST_BUFFER_COPY_ALL, truncsize,
+ leftsize);
gst_buffer_unref (buf);
buf = trunc;
- gst_buffer_set_caps (buf, GST_PAD_CAPS (audiorate->srcpad));
-
audiorate->drop += truncsamples;
GST_DEBUG_OBJECT (audiorate, "truncating %" G_GUINT64_FORMAT " samples",
truncsamples);
}
send:
- if (GST_BUFFER_SIZE (buf) == 0)
+ if (gst_buffer_get_size (buf) == 0)
goto beach;
/* Now calculate parameters for whichever buffer (either the original
if (audiorate->discont) {
/* we need to output a discont buffer, do so now */
GST_DEBUG_OBJECT (audiorate, "marking DISCONT on output buffer");
- buf = gst_buffer_make_metadata_writable (buf);
+ buf = gst_buffer_make_writable (buf);
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
audiorate->discont = FALSE;
} else if (GST_BUFFER_IS_DISCONT (buf)) {
/* else we make everything continuous so we can safely remove the DISCONT
* flag from the buffer if there was one */
GST_DEBUG_OBJECT (audiorate, "removing DISCONT from buffer");
- buf = gst_buffer_make_metadata_writable (buf);
+ buf = gst_buffer_make_writable (buf);
GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
}
/* set last_stop on segment */
- gst_segment_set_last_stop (&audiorate->src_segment, GST_FORMAT_TIME,
- GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf));
+ audiorate->src_segment.position =
+ GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf);
ret = gst_pad_push (audiorate->srcpad, buf);
buf = NULL;
break;
}
- if (parent_class->change_state)
- return parent_class->change_state (element, transition);
-
- return GST_STATE_CHANGE_SUCCESS;
+ return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
}
static gboolean
GstElementClass parent_class;
};
+GType gst_audio_rate_get_type (void);
+
G_END_DECLS
#endif /* __GST_AUDIO_RATE_H__ */
enum
{
PROP_0,
- PROP_QUALITY,
- PROP_FILTER_LENGTH
+ PROP_QUALITY
};
#define SUPPORTED_CAPS \
/* vmethods */
static gboolean gst_audio_resample_get_unit_size (GstBaseTransform * base,
- GstCaps * caps, guint * size);
+ GstCaps * caps, gsize * size);
static GstCaps *gst_audio_resample_transform_caps (GstBaseTransform * base,
- GstPadDirection direction, GstCaps * caps);
+ GstPadDirection direction, GstCaps * caps, GstCaps * filter);
static void gst_audio_resample_fixate_caps (GstBaseTransform * base,
GstPadDirection direction, GstCaps * caps, GstCaps * othercaps);
static gboolean gst_audio_resample_transform_size (GstBaseTransform * trans,
- GstPadDirection direction, GstCaps * incaps, guint insize,
- GstCaps * outcaps, guint * outsize);
+ GstPadDirection direction, GstCaps * incaps, gsize insize,
+ GstCaps * outcaps, gsize * outsize);
static gboolean gst_audio_resample_set_caps (GstBaseTransform * base,
GstCaps * incaps, GstCaps * outcaps);
static GstFlowReturn gst_audio_resample_transform (GstBaseTransform * base,
static gboolean gst_audio_resample_query (GstPad * pad, GstQuery * query);
static const GstQueryType *gst_audio_resample_query_type (GstPad * pad);
-GST_BOILERPLATE (GstAudioResample, gst_audio_resample, GstBaseTransform,
- GST_TYPE_BASE_TRANSFORM);
-
-static void
-gst_audio_resample_base_init (gpointer g_class)
-{
- GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&gst_audio_resample_src_template));
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&gst_audio_resample_sink_template));
-
- gst_element_class_set_details_simple (gstelement_class, "Audio resampler",
- "Filter/Converter/Audio", "Resamples audio",
- "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
-}
+#define gst_audio_resample_parent_class parent_class
+G_DEFINE_TYPE (GstAudioResample, gst_audio_resample, GST_TYPE_BASE_TRANSFORM);
static void
gst_audio_resample_class_init (GstAudioResampleClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
+ GstElementClass *gstelement_class = (GstElementClass *) klass;
gobject_class->set_property = gst_audio_resample_set_property;
gobject_class->get_property = gst_audio_resample_get_property;
SPEEX_RESAMPLER_QUALITY_DEFAULT,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
- /* FIXME 0.11: Remove this property, it's just for compatibility
- * with old audioresample
- */
- /**
- * GstAudioResample:filter-length:
- *
- * Length of the resample filter
- *
- * Deprectated: Use #GstAudioResample:quality property instead
- */
- g_object_class_install_property (gobject_class, PROP_FILTER_LENGTH,
- g_param_spec_int ("filter-length", "Filter length",
- "Length of the resample filter", 0, G_MAXINT, 64,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_audio_resample_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_audio_resample_sink_template));
+
+ gst_element_class_set_details_simple (gstelement_class, "Audio resampler",
+ "Filter/Converter/Audio", "Resamples audio",
+ "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
GST_BASE_TRANSFORM_CLASS (klass)->start =
GST_DEBUG_FUNCPTR (gst_audio_resample_start);
}
static void
-gst_audio_resample_init (GstAudioResample * resample,
- GstAudioResampleClass * klass)
+gst_audio_resample_init (GstAudioResample * resample)
{
GstBaseTransform *trans = GST_BASE_TRANSFORM (resample);
static gboolean
gst_audio_resample_get_unit_size (GstBaseTransform * base, GstCaps * caps,
- guint * size)
+ gsize * size)
{
gint width, channels;
GstStructure *structure;
static GstCaps *
gst_audio_resample_transform_caps (GstBaseTransform * base,
- GstPadDirection direction, GstCaps * caps)
+ GstPadDirection direction, GstCaps * caps, GstCaps * filter)
{
const GValue *val;
GstStructure *s;
gst_caps_append_structure (res, s);
}
+ if (filter) {
+ GstCaps *intersection;
+
+ intersection =
+ gst_caps_intersect_full (filter, res, GST_CAPS_INTERSECT_FIRST);
+ gst_caps_unref (res);
+ res = intersection;
+ }
+
return res;
}
static gboolean
gst_audio_resample_transform_size (GstBaseTransform * base,
- GstPadDirection direction, GstCaps * caps, guint size, GstCaps * othercaps,
- guint * othersize)
+ GstPadDirection direction, GstCaps * caps, gsize size, GstCaps * othercaps,
+ gsize * othersize)
{
gboolean ret = TRUE;
guint32 ratio_den, ratio_num;
guint out_len, out_processed;
gint err;
guint num, den;
+ guint8 *data;
g_assert (resample->state != NULL);
if (out_len == 0)
return;
- res =
- gst_pad_alloc_buffer_and_set_caps (GST_BASE_TRANSFORM_SRC_PAD (resample),
- GST_BUFFER_OFFSET_NONE, outsize,
- GST_PAD_CAPS (GST_BASE_TRANSFORM_SRC_PAD (resample)), &outbuf);
- if (G_UNLIKELY (res != GST_FLOW_OK)) {
- GST_WARNING_OBJECT (resample, "failed allocating buffer of %d bytes",
- outsize);
- return;
- }
+ outbuf = gst_buffer_new_and_alloc (outsize);
+
+ data = gst_buffer_map (outbuf, NULL, NULL, GST_MAP_WRITE);
if (resample->funcs->width != resample->width) {
/* need to convert data format; allocate workspace */
/* convert output format */
gst_audio_resample_convert_buffer (resample, resample->tmp_out,
- GST_BUFFER_DATA (outbuf), out_processed, TRUE);
+ data, out_processed, TRUE);
} else {
/* don't need to convert data format; process */
err = resample->funcs->process (resample->state, NULL, &in_processed,
- GST_BUFFER_DATA (outbuf), &out_processed);
+ data, &out_processed);
}
/* If we wrote more than allocated something is really wrong now
* and we should better abort immediately */
g_assert (out_len >= out_processed);
+ outsize = out_processed * resample->channels * (resample->width / 8);
+ gst_buffer_unmap (outbuf, data, outsize);
+
if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS)) {
GST_WARNING_OBJECT (resample, "Failed to process drain: %s",
resample->funcs->strerror (err));
return;
}
- GST_BUFFER_SIZE (outbuf) =
- out_processed * resample->channels * (resample->width / 8);
-
GST_LOG_OBJECT (resample,
"Pushing drain buffer of %u bytes with timestamp %" GST_TIME_FORMAT
" duration %" GST_TIME_FORMAT " offset %" G_GUINT64_FORMAT " offset_end %"
- G_GUINT64_FORMAT, GST_BUFFER_SIZE (outbuf),
+ G_GUINT64_FORMAT, outsize,
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)), GST_BUFFER_OFFSET (outbuf),
GST_BUFFER_OFFSET_END (outbuf));
resample->samples_out = 0;
resample->need_discont = TRUE;
break;
- case GST_EVENT_NEWSEGMENT:
+ case GST_EVENT_SEGMENT:
if (resample->state) {
guint latency = resample->funcs->get_input_latency (resample->state);
gst_audio_resample_push_drain (resample, latency);
break;
}
- return parent_class->event (base, event);
+ return GST_BASE_TRANSFORM_CLASS (parent_class)->event (base, event);
}
static gboolean
gst_audio_resample_process (GstAudioResample * resample, GstBuffer * inbuf,
GstBuffer * outbuf)
{
+ gsize in_size, out_size;
+ guint8 *in_data, *out_data;
guint32 in_len, in_processed;
guint32 out_len, out_processed;
guint filt_len = resample->funcs->get_filt_len (resample->state);
- in_len = GST_BUFFER_SIZE (inbuf) / resample->channels;
- out_len = GST_BUFFER_SIZE (outbuf) / resample->channels;
+ in_data = gst_buffer_map (inbuf, &in_size, NULL, GST_MAP_READ);
+ out_data = gst_buffer_map (outbuf, &out_size, NULL, GST_MAP_WRITE);
+
+ in_len = in_size / resample->channels;
+ out_len = out_size / resample->channels;
in_len /= (resample->width / 8);
out_len /= (resample->width / 8);
else
out_processed = 0;
- memset (GST_BUFFER_DATA (outbuf), 0, GST_BUFFER_SIZE (outbuf));
+ memset (out_data, 0, out_size);
GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
resample->num_gap_samples += in_len;
in_processed = in_len;
&resample->tmp_out_size, out_len * resample->channels *
(resample->funcs->width / 8))) {
GST_ERROR_OBJECT (resample, "failed to allocate workspace");
+ gst_buffer_unmap (inbuf, in_data, in_size);
+ gst_buffer_unmap (outbuf, out_data, out_size);
return GST_FLOW_ERROR;
}
/* convert input */
- gst_audio_resample_convert_buffer (resample, GST_BUFFER_DATA (inbuf),
+ gst_audio_resample_convert_buffer (resample, in_data,
resample->tmp_in, in_len, FALSE);
/* process */
/* convert output */
gst_audio_resample_convert_buffer (resample, resample->tmp_out,
- GST_BUFFER_DATA (outbuf), out_processed, TRUE);
+ out_data, out_processed, TRUE);
} else {
/* no format conversion required; process */
err = resample->funcs->process (resample->state,
- GST_BUFFER_DATA (inbuf), &in_processed,
- GST_BUFFER_DATA (outbuf), &out_processed);
+ in_data, &in_processed, out_data, &out_processed);
}
if (G_UNLIKELY (err != RESAMPLER_ERR_SUCCESS)) {
GST_ERROR_OBJECT (resample, "Failed to convert data: %s",
resample->funcs->strerror (err));
+ gst_buffer_unmap (inbuf, in_data, in_size);
+ gst_buffer_unmap (outbuf, out_data, out_size);
return GST_FLOW_ERROR;
}
}
resample->samples_out += out_processed;
resample->samples_in += in_len;
- GST_BUFFER_SIZE (outbuf) =
- out_processed * resample->channels * (resample->width / 8);
+ out_size = out_processed * resample->channels * (resample->width / 8);
+ gst_buffer_unmap (inbuf, in_data, in_size);
+ gst_buffer_unmap (outbuf, out_data, out_size);
GST_LOG_OBJECT (resample,
"Converted to buffer of %" G_GUINT32_FORMAT
" samples (%u bytes) with timestamp %" GST_TIME_FORMAT ", duration %"
GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT ", offset_end %"
- G_GUINT64_FORMAT, out_processed, GST_BUFFER_SIZE (outbuf),
+ G_GUINT64_FORMAT, out_processed, out_size,
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)),
GST_BUFFER_OFFSET (outbuf), GST_BUFFER_OFFSET_END (outbuf));
GstBuffer * outbuf)
{
GstAudioResample *resample = GST_AUDIO_RESAMPLE (base);
- gulong size;
GstFlowReturn ret;
if (resample->state == NULL) {
gst_audio_resample_get_funcs (resample->width, resample->fp);
}
- size = GST_BUFFER_SIZE (inbuf);
-
GST_LOG_OBJECT (resample, "transforming buffer of %ld bytes, ts %"
GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT ", offset %"
G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT,
- size, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)),
+ gst_buffer_get_size (inbuf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)),
GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf)),
GST_BUFFER_OFFSET (inbuf), GST_BUFFER_OFFSET_END (inbuf));
resample->quality, resample->fp);
GST_BASE_TRANSFORM_UNLOCK (resample);
break;
- case PROP_FILTER_LENGTH:{
- gint filter_length = g_value_get_int (value);
-
- GST_BASE_TRANSFORM_LOCK (resample);
- if (filter_length <= 8)
- resample->quality = 0;
- else if (filter_length <= 16)
- resample->quality = 1;
- else if (filter_length <= 32)
- resample->quality = 2;
- else if (filter_length <= 48)
- resample->quality = 3;
- else if (filter_length <= 64)
- resample->quality = 4;
- else if (filter_length <= 80)
- resample->quality = 5;
- else if (filter_length <= 96)
- resample->quality = 6;
- else if (filter_length <= 128)
- resample->quality = 7;
- else if (filter_length <= 160)
- resample->quality = 8;
- else if (filter_length <= 192)
- resample->quality = 9;
- else
- resample->quality = 10;
-
- GST_DEBUG_OBJECT (resample, "new quality %d", resample->quality);
-
- gst_audio_resample_update_state (resample, resample->width,
- resample->channels, resample->inrate, resample->outrate,
- resample->quality, resample->fp);
- GST_BASE_TRANSFORM_UNLOCK (resample);
- break;
- }
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
case PROP_QUALITY:
g_value_set_int (value, resample->quality);
break;
- case PROP_FILTER_LENGTH:
- switch (resample->quality) {
- case 0:
- g_value_set_int (value, 8);
- break;
- case 1:
- g_value_set_int (value, 16);
- break;
- case 2:
- g_value_set_int (value, 32);
- break;
- case 3:
- g_value_set_int (value, 48);
- break;
- case 4:
- g_value_set_int (value, 64);
- break;
- case 5:
- g_value_set_int (value, 80);
- break;
- case 6:
- g_value_set_int (value, 96);
- break;
- case 7:
- g_value_set_int (value, 128);
- break;
- case 8:
- g_value_set_int (value, 160);
- break;
- case 9:
- g_value_set_int (value, 192);
- break;
- case 10:
- g_value_set_int (value, 256);
- break;
- }
- break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
"rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]")
);
-
-GST_BOILERPLATE (GstAudioTestSrc, gst_audio_test_src, GstBaseSrc,
- GST_TYPE_BASE_SRC);
+#define gst_audio_test_src_parent_class parent_class
+G_DEFINE_TYPE (GstAudioTestSrc, gst_audio_test_src, GST_TYPE_BASE_SRC);
#define GST_TYPE_AUDIO_TEST_SRC_WAVE (gst_audiostestsrc_wave_get_type())
static GType
static void gst_audio_test_src_src_fixate (GstPad * pad, GstCaps * caps);
static gboolean gst_audio_test_src_is_seekable (GstBaseSrc * basesrc);
-static gboolean gst_audio_test_src_check_get_range (GstBaseSrc * basesrc);
static gboolean gst_audio_test_src_do_seek (GstBaseSrc * basesrc,
GstSegment * segment);
static gboolean gst_audio_test_src_query (GstBaseSrc * basesrc,
static GstFlowReturn gst_audio_test_src_create (GstBaseSrc * basesrc,
guint64 offset, guint length, GstBuffer ** buffer);
-
-static void
-gst_audio_test_src_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_audio_test_src_src_template));
- gst_element_class_set_details_simple (element_class,
- "Audio test source", "Source/Audio",
- "Creates audio test signals of given frequency and volume",
- "Stefan Kost <ensonic@users.sf.net>");
-}
-
static void
gst_audio_test_src_class_init (GstAudioTestSrcClass * klass)
{
GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
GstBaseSrcClass *gstbasesrc_class;
gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
gstbasesrc_class = (GstBaseSrcClass *) klass;
gobject_class->set_property = gst_audio_test_src_set_property;
"Can activate in pull mode", DEFAULT_CAN_ACTIVATE_PULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_audio_test_src_src_template));
+ gst_element_class_set_details_simple (gstelement_class,
+ "Audio test source", "Source/Audio",
+ "Creates audio test signals of given frequency and volume",
+ "Stefan Kost <ensonic@users.sf.net>");
+
gstbasesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_audio_test_src_setcaps);
gstbasesrc_class->is_seekable =
GST_DEBUG_FUNCPTR (gst_audio_test_src_is_seekable);
- gstbasesrc_class->check_get_range =
- GST_DEBUG_FUNCPTR (gst_audio_test_src_check_get_range);
gstbasesrc_class->do_seek = GST_DEBUG_FUNCPTR (gst_audio_test_src_do_seek);
gstbasesrc_class->query = GST_DEBUG_FUNCPTR (gst_audio_test_src_query);
gstbasesrc_class->get_times =
}
static void
-gst_audio_test_src_init (GstAudioTestSrc * src, GstAudioTestSrcClass * g_class)
+gst_audio_test_src_init (GstAudioTestSrc * src)
{
GstPad *pad = GST_BASE_SRC_PAD (src);
res = TRUE;
break;
}
+ case GST_QUERY_SCHEDULING:
+ {
+ /* if we can operate in pull mode */
+ gst_query_set_scheduling (query, src->can_activate_pull, TRUE, FALSE, 1,
+ -1, 1);
+ res = TRUE;
+ break;
+ }
default:
res = GST_BASE_SRC_CLASS (parent_class)->query (basesrc, query);
break;
GST_DEBUG_OBJECT (src, "seeking %" GST_SEGMENT_FORMAT, segment);
- time = segment->last_stop;
+ time = segment->position;
src->reverse = (segment->rate < 0.0);
/* now move to the time indicated */
return TRUE;
}
-static gboolean
-gst_audio_test_src_check_get_range (GstBaseSrc * basesrc)
-{
- GstAudioTestSrc *src;
-
- src = GST_AUDIO_TEST_SRC (basesrc);
-
- /* if we can operate in pull mode */
- return src->can_activate_pull;
-}
-
static GstFlowReturn
gst_audio_test_src_create (GstBaseSrc * basesrc, guint64 offset,
guint length, GstBuffer ** buffer)
{
- GstFlowReturn res;
GstAudioTestSrc *src;
GstBuffer *buf;
GstClockTime next_time;
gint64 next_sample, next_byte;
gint bytes, samples;
GstElementClass *eclass;
+ guint8 *data;
src = GST_AUDIO_TEST_SRC (basesrc);
bytes = src->generate_samples_per_buffer * src->sample_size * src->channels;
- if ((res = gst_pad_alloc_buffer (basesrc->srcpad, src->next_sample,
- bytes, GST_PAD_CAPS (basesrc->srcpad), &buf)) != GST_FLOW_OK) {
- return res;
- }
+ buf = gst_buffer_new_and_alloc (bytes);
next_byte = src->next_byte + (src->reverse ? (-bytes) : bytes);
next_time = gst_util_uint64_scale_int (next_sample, GST_SECOND,
src->generate_samples_per_buffer,
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
- src->process (src, GST_BUFFER_DATA (buf));
+ data = gst_buffer_map (buf, NULL, NULL, GST_MAP_WRITE);
+ src->process (src, data);
+ gst_buffer_unmap (buf, data, bytes);
if (G_UNLIKELY ((src->wave == GST_AUDIO_TEST_SRC_WAVE_SILENCE)
|| (src->volume == 0.0))) {
* to %GST_STATE_PAUSED or higher.
*/
g_object_class_install_property (gobject_klass, PROP_PROFILE,
- gst_param_spec_mini_object ("profile", "Profile",
+ g_param_spec_object ("profile", "Profile",
"The GstEncodingProfile to use", GST_TYPE_ENCODING_PROFILE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gstelement_klass->change_state =
GST_DEBUG_FUNCPTR (gst_encode_bin_change_state);
- gstelement_klass->request_new_pad_full =
+ gstelement_klass->request_new_pad =
GST_DEBUG_FUNCPTR (gst_encode_bin_request_new_pad);
gstelement_klass->release_pad =
GST_DEBUG_FUNCPTR (gst_encode_bin_release_pad);
switch (prop_id) {
case PROP_PROFILE:
gst_encode_bin_set_profile (ebin,
- (GstEncodingProfile *) gst_value_get_mini_object (value));
+ (GstEncodingProfile *) g_value_get_object (value));
break;
case PROP_QUEUE_BUFFERS_MAX:
ebin->queue_buffers_max = g_value_get_uint (value);
switch (prop_id) {
case PROP_PROFILE:
- gst_value_set_mini_object (value, (GstMiniObject *) ebin->profile);
+ g_value_set_object (value, (GObject *) ebin->profile);
break;
case PROP_QUEUE_BUFFERS_MAX:
g_value_set_uint (value, ebin->queue_buffers_max);
{
GstElement *res = NULL;
- GST_DEBUG ("Creating element from factory %s",
- GST_PLUGIN_FEATURE_NAME (factory));
+ GST_DEBUG ("Creating element from factory %s", GST_OBJECT_NAME (factory));
res = gst_element_factory_create (factory, name);
if (preset && GST_IS_PRESET (res) &&
!gst_preset_load_preset (GST_PRESET (res), preset)) {
GST_WARNING ("Couldn't set preset [%s] on element [%s]",
- preset, GST_PLUGIN_FEATURE_NAME (factory));
+ preset, GST_OBJECT_NAME (factory));
gst_object_unref (res);
res = NULL;
}
static GstPad *
local_element_request_pad (GstElement * element, GstPadTemplate * templ,
- const gchar * name)
+ const gchar * name, const GstCaps * caps)
{
GstPad *newpad = NULL;
GstElementClass *oclass;
oclass = GST_ELEMENT_GET_CLASS (element);
if (oclass->request_new_pad)
- newpad = (oclass->request_new_pad) (element, templ, name);
+ newpad = (oclass->request_new_pad) (element, templ, name, caps);
if (newpad)
gst_object_ref (newpad);
/* FIXME : Improve algorithm for finding compatible muxer sink pad */
static inline GstPad *
get_compatible_muxer_sink_pad (GstEncodeBin * ebin, GstElement * encoder,
- const GstCaps * sinkcaps)
+ GstCaps * sinkcaps)
{
GstPad *sinkpad;
GstPadTemplate *srctempl = NULL;
gst_object_unref (srcpad);
sinktempl = gst_element_get_compatible_pad_template (ebin->muxer, srctempl);
+ gst_object_unref (srctempl);
} else {
srctempl =
gst_pad_template_new ("whatever", GST_PAD_SRC, GST_PAD_ALWAYS,
- gst_caps_copy (sinkcaps));
+ sinkcaps);
g_assert (srctempl != NULL);
sinktempl = gst_element_get_compatible_pad_template (ebin->muxer, srctempl);
g_object_unref (srctempl);
_has_class (GstElement * element, const gchar * classname)
{
GstElementClass *klass;
+ const gchar *value;
klass = GST_ELEMENT_GET_CLASS (element);
+ value = gst_element_class_get_metadata (klass, GST_ELEMENT_METADATA_KLASS);
- return strstr (klass->details.klass, classname) != NULL;
+ return strstr (value, classname) != NULL;
}
/* FIXME : Add handling of streams that don't need encoding */
/* Element we will link to the encoder */
GstElement *last = NULL;
GList *tmp, *tosync = NULL;
- const GstCaps *format;
- const GstCaps *restriction;
+ GstCaps *format, *restriction;
const gchar *missing_element_name;
format = gst_encoding_profile_get_format (sprof);
/* Path 1 : Already-encoded data */
sinkpad =
- local_element_request_pad (sgroup->combiner, NULL, "passthroughsink");
+ local_element_request_pad (sgroup->combiner, NULL, "passthroughsink",
+ NULL);
if (G_UNLIKELY (sinkpad == NULL))
goto no_combiner_sinkpad;
/* Check if stream format is compatible */
srcpad = gst_element_get_static_pad (sgroup->smartencoder, "src");
- tmpcaps = gst_pad_get_caps (srcpad);
+ tmpcaps = gst_pad_get_caps (srcpad, NULL);
if (!gst_caps_can_intersect (tmpcaps, format)) {
GST_DEBUG ("We don't have a smart encoder for the stream format");
gst_object_unref (sgroup->smartencoder);
g_object_unref (srcpad);
}
- srcpad = local_element_request_pad (sgroup->splitter, NULL, "passthroughsrc");
+ srcpad =
+ local_element_request_pad (sgroup->splitter, NULL, "passthroughsrc",
+ NULL);
if (G_UNLIKELY (srcpad == NULL))
goto no_splitter_srcpad;
gst_bin_add ((GstBin *) ebin, sgroup->encoder);
tosync = g_list_append (tosync, sgroup->encoder);
- sinkpad = local_element_request_pad (sgroup->combiner, NULL, "encodingsink");
+ sinkpad =
+ local_element_request_pad (sgroup->combiner, NULL, "encodingsink", NULL);
if (G_UNLIKELY (sinkpad == NULL))
goto no_combiner_sinkpad;
srcpad = gst_element_get_static_pad (sgroup->encoder, "src");
/* Link to stream splitter */
sinkpad = gst_element_get_static_pad (last, "sink");
- srcpad = local_element_request_pad (sgroup->splitter, NULL, "encodingsrc");
+ srcpad =
+ local_element_request_pad (sgroup->splitter, NULL, "encodingsrc", NULL);
if (G_UNLIKELY (srcpad == NULL))
goto no_splitter_srcpad;
if (G_UNLIKELY (fast_pad_link (srcpad, sinkpad) != GST_PAD_LINK_OK))
ebin->streams = g_list_prepend (ebin->streams, sgroup);
+ if (format)
+ gst_caps_unref (format);
+ if (restriction)
+ gst_caps_unref (restriction);
+
return sgroup;
splitter_encoding_failure:
cleanup:
/* FIXME : Actually properly cleanup everything */
+ if (format)
+ gst_caps_unref (format);
+ if (restriction)
+ gst_caps_unref (restriction);
g_slice_free (StreamGroup, sgroup);
return NULL;
}
formatterfact = (GstElementFactory *) tmpfmtr->data;
GST_DEBUG_OBJECT (ebin, "Trying formatter %s",
- GST_PLUGIN_FEATURE_NAME (formatterfact));
+ GST_OBJECT_NAME (formatterfact));
if ((formatter =
_create_element_and_set_preset (formatterfact, preset, NULL)))
muxerfact = (GstElementFactory *) tmpmux->data;
- GST_DEBUG ("Trying muxer %s", GST_PLUGIN_FEATURE_NAME (muxerfact));
+ GST_DEBUG ("Trying muxer %s", GST_OBJECT_NAME (muxerfact));
/* See if the muxer can sink all of our stream profile caps */
for (tmp = profiles; tmp; tmp = tmp->next) {
}
static void
-release_pads (GstPad * pad, GstElement * elt)
+release_pads (const GValue * item, GstElement * elt)
{
+ GstPad *pad = g_value_get_object (item);
GstPad *peer = NULL;
GST_DEBUG_OBJECT (elt, "Releasing pad %s:%s", GST_DEBUG_PAD_NAME (pad));
/* Release it from the object */
gst_element_release_request_pad (elt, pad);
-
- /* And remove the reference added by the iterator */
- gst_object_unref (pad);
}
static void inline
GstIteratorResult itret = GST_ITERATOR_OK;
while (itret == GST_ITERATOR_OK || itret == GST_ITERATOR_RESYNC) {
- itret = gst_iterator_foreach (it, (GFunc) release_pads, sgroup->combiner);
+ itret =
+ gst_iterator_foreach (it, (GstIteratorForeachFunction) release_pads,
+ sgroup->combiner);
gst_iterator_resync (it);
}
gst_iterator_free (it);
GstIterator *it = gst_element_iterate_src_pads (sgroup->splitter);
GstIteratorResult itret = GST_ITERATOR_OK;
while (itret == GST_ITERATOR_OK || itret == GST_ITERATOR_RESYNC) {
- itret = gst_iterator_foreach (it, (GFunc) release_pads, sgroup->splitter);
+ itret =
+ gst_iterator_foreach (it, (GstIteratorForeachFunction) release_pads,
+ sgroup->splitter);
gst_iterator_resync (it);
}
gst_iterator_free (it);
static GstFlowReturn gst_smart_encoder_chain (GstPad * pad, GstBuffer * buf);
static gboolean smart_encoder_sink_event (GstPad * pad, GstEvent * event);
-static GstCaps *smart_encoder_sink_getcaps (GstPad * pad);
+static GstCaps *smart_encoder_sink_getcaps (GstPad * pad, GstCaps * filter);
static GstStateChangeReturn
gst_smart_encoder_change_state (GstElement * element,
GstStateChange transition);
static GstFlowReturn
gst_smart_encoder_push_pending_gop (GstSmartEncoder * smart_encoder)
{
- gint64 cstart, cstop;
+ guint64 cstart, cstop;
GList *tmp;
GstFlowReturn res = GST_FLOW_OK;
case GST_EVENT_FLUSH_STOP:
smart_encoder_reset (smart_encoder);
break;
- case GST_EVENT_NEWSEGMENT:
+ case GST_EVENT_SEGMENT:
{
- GstFormat format;
- gdouble rate, arate;
- gint64 start, stop, time;
- gboolean update;
-
- gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
- &start, &stop, &time);
- GST_DEBUG_OBJECT (smart_encoder,
- "newsegment: update %d, rate %g, arate %g, start %" GST_TIME_FORMAT
- ", stop %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT,
- update, rate, arate, GST_TIME_ARGS (start), GST_TIME_ARGS (stop),
- GST_TIME_ARGS (time));
- if (format != GST_FORMAT_TIME)
+ gst_event_copy_segment (event, smart_encoder->segment);
+
+ GST_DEBUG_OBJECT (smart_encoder, "segment: %" GST_SEGMENT_FORMAT,
+ smart_encoder->segment);
+ if (smart_encoder->segment->format != GST_FORMAT_TIME)
GST_ERROR
("smart_encoder can not handle streams not specified in GST_FORMAT_TIME");
- /* now configure the values */
- gst_segment_set_newsegment_full (smart_encoder->segment, update,
- rate, arate, format, start, stop, time);
-
/* And keep a copy for further usage */
if (smart_encoder->newsegment)
gst_event_unref (smart_encoder->newsegment);
}
static GstCaps *
-smart_encoder_sink_getcaps (GstPad * pad)
+smart_encoder_sink_getcaps (GstPad * pad, GstCaps * filter)
{
GstCaps *peer, *tmpl, *res;
GstSmartEncoder *smart_encoder = GST_SMART_ENCODER (gst_pad_get_parent (pad));
- /* Try getting it from downstream */
- peer = gst_pad_peer_get_caps_reffed (smart_encoder->srcpad);
-
/* Use computed caps */
if (smart_encoder->available_caps)
tmpl = gst_caps_ref (smart_encoder->available_caps);
else
tmpl = gst_static_pad_template_get_caps (&src_template);
+ /* Try getting it from downstream */
+ peer = gst_pad_peer_get_caps (smart_encoder->srcpad, tmpl);
+
if (peer == NULL) {
res = tmpl;
} else {
- res = gst_caps_intersect (peer, tmpl);
- gst_caps_unref (peer);
+ res = peer;
gst_caps_unref (tmpl);
}
setup_recoder_pipeline (GstSmartEncoder * smart_encoder)
{
GstPad *tmppad;
+ GstCaps *caps;
/* Fast path */
if (G_UNLIKELY (smart_encoder->encoder))
GST_DEBUG ("Creating internal decoder and encoder");
/* Create decoder/encoder */
- smart_encoder->decoder = get_decoder (GST_PAD_CAPS (smart_encoder->sinkpad));
+ caps = gst_pad_get_current_caps (smart_encoder->sinkpad);
+ smart_encoder->decoder = get_decoder (caps);
if (G_UNLIKELY (smart_encoder->decoder == NULL))
goto no_decoder;
+ gst_caps_unref (caps);
gst_element_set_bus (smart_encoder->decoder, GST_ELEMENT_BUS (smart_encoder));
- smart_encoder->encoder = get_encoder (GST_PAD_CAPS (smart_encoder->sinkpad));
+ caps = gst_pad_get_current_caps (smart_encoder->sinkpad);
+ smart_encoder->encoder = get_encoder (caps);
if (G_UNLIKELY (smart_encoder->encoder == NULL))
goto no_encoder;
+ gst_caps_unref (caps);
gst_element_set_bus (smart_encoder->encoder, GST_ELEMENT_BUS (smart_encoder));
GST_DEBUG ("Creating internal pads");
smart_encoder->internal_srcpad = gst_pad_new ("internal_src", GST_PAD_SRC);
g_object_set_qdata ((GObject *) smart_encoder->internal_srcpad,
INTERNAL_ELEMENT, smart_encoder);
- gst_pad_set_caps (smart_encoder->internal_srcpad,
- GST_PAD_CAPS (smart_encoder->sinkpad));
gst_pad_set_active (smart_encoder->internal_srcpad, TRUE);
/* Sink pad which will get the buffers from the encoder.
smart_encoder->internal_sinkpad = gst_pad_new ("internal_sink", GST_PAD_SINK);
g_object_set_qdata ((GObject *) smart_encoder->internal_sinkpad,
INTERNAL_ELEMENT, smart_encoder);
- gst_pad_set_caps (smart_encoder->internal_sinkpad,
- GST_PAD_CAPS (smart_encoder->sinkpad));
gst_pad_set_chain_function (smart_encoder->internal_sinkpad, internal_chain);
gst_pad_set_active (smart_encoder->internal_sinkpad, TRUE);
no_decoder:
{
- GST_WARNING ("Couldn't find a decoder for %" GST_PTR_FORMAT,
- GST_PAD_CAPS (smart_encoder->sinkpad));
+ GST_WARNING ("Couldn't find a decoder for %" GST_PTR_FORMAT, caps);
+ gst_caps_unref (caps);
return FALSE;
}
no_encoder:
{
- GST_WARNING ("Couldn't find an encoder for %" GST_PTR_FORMAT,
- GST_PAD_CAPS (smart_encoder->sinkpad));
+ GST_WARNING ("Couldn't find an encoder for %" GST_PTR_FORMAT, caps);
+ gst_caps_unref (caps);
return FALSE;
}
static void gst_stream_combiner_dispose (GObject * object);
static GstPad *gst_stream_combiner_request_new_pad (GstElement * element,
- GstPadTemplate * templ, const gchar * name);
+ GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
static void gst_stream_combiner_release_pad (GstElement * element,
GstPad * pad);
}
static GstCaps *
-gst_stream_combiner_sink_getcaps (GstPad * pad)
+gst_stream_combiner_sink_getcaps (GstPad * pad, GstCaps * filter)
{
GstStreamCombiner *stream_combiner =
(GstStreamCombiner *) GST_PAD_PARENT (pad);
- return gst_pad_peer_get_caps_reffed (stream_combiner->srcpad);
+ return gst_pad_peer_get_caps (stream_combiner->srcpad, filter);
}
static gboolean
static GstPad *
gst_stream_combiner_request_new_pad (GstElement * element,
- GstPadTemplate * templ, const gchar * name)
+ GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
{
GstStreamCombiner *stream_combiner = (GstStreamCombiner *) element;
GstPad *sinkpad;
static void gst_stream_splitter_dispose (GObject * object);
static GstPad *gst_stream_splitter_request_new_pad (GstElement * element,
- GstPadTemplate * templ, const gchar * name);
+ GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
static void gst_stream_splitter_release_pad (GstElement * element,
GstPad * pad);
}
static GstCaps *
-gst_stream_splitter_sink_getcaps (GstPad * pad)
+gst_stream_splitter_sink_getcaps (GstPad * pad, GstCaps * filter)
{
GstStreamSplitter *stream_splitter =
(GstStreamSplitter *) GST_PAD_PARENT (pad);
resync:
if (G_UNLIKELY (stream_splitter->srcpads == NULL)) {
- res = gst_caps_new_any ();
+ res = (filter ? gst_caps_ref (filter) : gst_caps_new_any ());
goto beach;
}
STREAMS_UNLOCK (stream_splitter);
if (res)
- gst_caps_merge (res, gst_pad_peer_get_caps_reffed (srcpad));
+ gst_caps_merge (res, gst_pad_peer_get_caps (srcpad, filter));
else
- res = gst_pad_peer_get_caps (srcpad);
+ res = gst_pad_peer_get_caps (srcpad, filter);
STREAMS_LOCK (stream_splitter);
if (G_UNLIKELY (cookie != stream_splitter->cookie)) {
GstCaps *peercaps;
STREAMS_UNLOCK (stream_splitter);
- peercaps = gst_pad_peer_get_caps_reffed (srcpad);
+ peercaps = gst_pad_peer_get_caps (srcpad, NULL);
if (peercaps) {
res = gst_caps_can_intersect (caps, peercaps);
gst_caps_unref (peercaps);
static GstPad *
gst_stream_splitter_request_new_pad (GstElement * element,
- GstPadTemplate * templ, const gchar * name)
+ GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
{
GstStreamSplitter *stream_splitter = (GstStreamSplitter *) element;
GstPad *srcpad;
/*
* Read a palette from a caps.
*/
-
static void
gst_ffmpeg_get_palette (const GstCaps * caps, AVCodecContext * context)
{
/* do we have a palette? */
if ((palette_v = gst_structure_get_value (str, "palette_data")) && context) {
- const GstBuffer *palette;
+ GstBuffer *palette;
palette = gst_value_get_buffer (palette_v);
- if (palette && GST_BUFFER_SIZE (palette) >= 256 * 4) {
+ if (palette && gst_buffer_get_size (palette) >= 256 * 4) {
if (context->palctrl)
av_free (context->palctrl);
context->palctrl = av_malloc (sizeof (AVPaletteControl));
context->palctrl->palette_changed = 1;
- memcpy (context->palctrl->palette, GST_BUFFER_DATA (palette),
+ gst_buffer_extract (palette, 0, context->palctrl->palette,
AVPALETTE_SIZE);
}
}
{
if (context->palctrl) {
GstBuffer *palette = gst_buffer_new_and_alloc (256 * 4);
+ guint8 *data;
+ gsize size;
+
+ data = gst_buffer_map (palette, &size, NULL, GST_MAP_WRITE);
+ memcpy (data, context->palctrl->palette, AVPALETTE_SIZE);
+ gst_buffer_unmap (palette, data, size);
- memcpy (GST_BUFFER_DATA (palette), context->palctrl->palette,
- AVPALETTE_SIZE);
gst_caps_set_simple (caps, "palette_data", GST_TYPE_BUFFER, palette, NULL);
gst_buffer_unref (palette);
}
static gboolean gst_ffmpegcsp_set_caps (GstBaseTransform * btrans,
GstCaps * incaps, GstCaps * outcaps);
static gboolean gst_ffmpegcsp_get_unit_size (GstBaseTransform * btrans,
- GstCaps * caps, guint * size);
+ GstCaps * caps, gsize * size);
static GstFlowReturn gst_ffmpegcsp_transform (GstBaseTransform * btrans,
GstBuffer * inbuf, GstBuffer * outbuf);
return caps;
}
-
-static gboolean
-gst_ffmpegcsp_structure_is_alpha (GstStructure * s)
-{
- GQuark name;
-
- name = gst_structure_get_name_id (s);
-
- if (name == _QRAWRGB) {
- return gst_structure_id_has_field (s, _QALPHAMASK);
- } else if (name == _QRAWYUV) {
- guint32 fourcc;
-
- if (!gst_structure_get_fourcc (s, "format", &fourcc))
- return FALSE;
-
- return (fourcc == GST_MAKE_FOURCC ('A', 'Y', 'U', 'V'));
- }
-
- return FALSE;
-}
-
/* The caps can be transformed into any other caps with format info removed.
* However, we should prefer passthrough, so if passthrough is possible,
* put it first in the list. */
static GstCaps *
gst_ffmpegcsp_transform_caps (GstBaseTransform * btrans,
- GstPadDirection direction, GstCaps * caps)
+ GstPadDirection direction, GstCaps * caps, GstCaps * filter)
{
GstCaps *template;
GstCaps *tmp, *tmp2;
GstCaps *result;
- GstStructure *s;
- GstCaps *alpha, *non_alpha;
template = gst_static_pad_template_get_caps (&gst_ffmpegcsp_src_template);
result = gst_caps_copy (caps);
gst_caps_unref (tmp);
tmp = tmp2;
- /* Now move alpha formats to the beginning if caps is an alpha format
- * or at the end if caps is no alpha format */
- alpha = gst_caps_new_empty ();
- non_alpha = gst_caps_new_empty ();
-
- while ((s = gst_caps_steal_structure (tmp, 0))) {
- if (gst_ffmpegcsp_structure_is_alpha (s))
- gst_caps_append_structure (alpha, s);
- else
- gst_caps_append_structure (non_alpha, s);
- }
-
- s = gst_caps_get_structure (caps, 0);
- gst_caps_unref (tmp);
-
- if (gst_ffmpegcsp_structure_is_alpha (s)) {
- gst_caps_append (alpha, non_alpha);
- tmp = alpha;
- } else {
- gst_caps_append (non_alpha, alpha);
- tmp = non_alpha;
+ if (filter) {
+ tmp2 = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
+ gst_caps_unref (tmp);
+ tmp = tmp2;
}
- gst_caps_append (result, tmp);
-
GST_DEBUG_OBJECT (btrans, "transformed %" GST_PTR_FORMAT " into %"
GST_PTR_FORMAT, caps, result);
}
}
-GST_BOILERPLATE (GstFFMpegCsp, gst_ffmpegcsp, GstVideoFilter,
- GST_TYPE_VIDEO_FILTER);
-
-static void
-gst_ffmpegcsp_base_init (gpointer klass)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&gst_ffmpegcsp_src_template));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&gst_ffmpegcsp_sink_template));
-
- gst_element_class_set_details_simple (element_class,
- "FFMPEG Colorspace converter", "Filter/Converter/Video",
- "Converts video from one colorspace to another",
- "GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>");
-
- _QRAWRGB = g_quark_from_string ("video/x-raw-rgb");
- _QRAWYUV = g_quark_from_string ("video/x-raw-yuv");
- _QALPHAMASK = g_quark_from_string ("alpha_mask");
-}
+#define gst_ffmpegcsp_parent_class parent_class
+G_DEFINE_TYPE (GstFFMpegCsp, gst_ffmpegcsp, GST_TYPE_VIDEO_FILTER);
static void
gst_ffmpegcsp_finalize (GObject * obj)
gst_ffmpegcsp_class_init (GstFFMpegCspClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
+ GstElementClass *gstelement_class = (GstElementClass *) klass;
GstBaseTransformClass *gstbasetransform_class =
(GstBaseTransformClass *) klass;
+ _QRAWRGB = g_quark_from_string ("video/x-raw-rgb");
+ _QRAWYUV = g_quark_from_string ("video/x-raw-yuv");
+ _QALPHAMASK = g_quark_from_string ("alpha_mask");
+
gobject_class->finalize = gst_ffmpegcsp_finalize;
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_ffmpegcsp_src_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_ffmpegcsp_sink_template));
+
+ gst_element_class_set_details_simple (gstelement_class,
+ "FFMPEG Colorspace converter", "Filter/Converter/Video",
+ "Converts video from one colorspace to another",
+ "GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>");
+
gstbasetransform_class->transform_caps =
GST_DEBUG_FUNCPTR (gst_ffmpegcsp_transform_caps);
gstbasetransform_class->set_caps = GST_DEBUG_FUNCPTR (gst_ffmpegcsp_set_caps);
}
static void
-gst_ffmpegcsp_init (GstFFMpegCsp * space, GstFFMpegCspClass * klass)
+gst_ffmpegcsp_init (GstFFMpegCsp * space)
{
space->from_pixfmt = space->to_pixfmt = PIX_FMT_NB;
space->palette = NULL;
static gboolean
gst_ffmpegcsp_get_unit_size (GstBaseTransform * btrans, GstCaps * caps,
- guint * size)
+ gsize * size)
{
GstStructure *structure = NULL;
AVCodecContext *ctx = NULL;
{
GstFFMpegCsp *space;
gint result;
+ guint8 *indata, *outdata;
+ gsize insize, outsize;
space = GST_FFMPEGCSP (btrans);
goto unknown_format;
/* fill from with source data */
+ indata = gst_buffer_map (inbuf, &insize, NULL, GST_MAP_READ);
gst_ffmpegcsp_avpicture_fill (&space->from_frame,
- GST_BUFFER_DATA (inbuf), space->from_pixfmt, space->width, space->height,
+ indata, space->from_pixfmt, space->width, space->height,
space->interlaced);
/* fill optional palette */
space->from_frame.data[1] = (uint8_t *) space->palette->palette;
/* fill target frame */
+ outdata = gst_buffer_map (outbuf, &outsize, NULL, GST_MAP_WRITE);
gst_ffmpegcsp_avpicture_fill (&space->to_frame,
- GST_BUFFER_DATA (outbuf), space->to_pixfmt, space->width, space->height,
+ outdata, space->to_pixfmt, space->width, space->height,
space->interlaced);
/* and convert */
result = img_convert (&space->to_frame, space->to_pixfmt,
&space->from_frame, space->from_pixfmt, space->width, space->height);
+ gst_buffer_unmap (outbuf, outdata, outsize);
+ gst_buffer_unmap (inbuf, indata, insize);
+
if (result == -1)
goto not_supported;
GST_DEBUG_CATEGORY_STATIC (gst_gdp_depay_debug);
#define GST_CAT_DEFAULT gst_gdp_depay_debug
-#define _do_init(x) \
+#define _do_init \
GST_DEBUG_CATEGORY_INIT (gst_gdp_depay_debug, "gdpdepay", 0, \
"GDP depayloader");
-
-GST_BOILERPLATE_FULL (GstGDPDepay, gst_gdp_depay, GstElement,
+#define gst_gdp_depay_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstGDPDepay, gst_gdp_depay,
GST_TYPE_ELEMENT, _do_init);
static gboolean gst_gdp_depay_sink_event (GstPad * pad, GstEvent * event);
static void gst_gdp_depay_finalize (GObject * object);
static void
-gst_gdp_depay_base_init (gpointer g_class)
+gst_gdp_depay_class_init (GstGDPDepayClass * klass)
{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
- gst_element_class_set_details_simple (element_class,
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+
+ gst_element_class_set_details_simple (gstelement_class,
"GDP Depayloader", "GDP/Depayloader",
"Depayloads GStreamer Data Protocol buffers",
"Thomas Vander Stichele <thomas at apestaart dot org>");
- gst_element_class_add_pad_template (element_class,
+ gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&gdp_depay_sink_template));
- gst_element_class_add_pad_template (element_class,
+ gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&gdp_depay_src_template));
-}
-
-static void
-gst_gdp_depay_class_init (GstGDPDepayClass * klass)
-{
- GObjectClass *gobject_class;
- GstElementClass *gstelement_class;
-
- gobject_class = (GObjectClass *) klass;
- gstelement_class = (GstElementClass *) klass;
gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_gdp_depay_change_state);
}
static void
-gst_gdp_depay_init (GstGDPDepay * gdpdepay, GstGDPDepayClass * g_class)
+gst_gdp_depay_init (GstGDPDepay * gdpdepay)
{
gdpdepay->sinkpad =
gst_pad_new_from_static_template (&gdp_depay_sink_template, "sink");
/* after EOS, we don't expect to output anything anymore */
res = gst_pad_push_event (this->srcpad, event);
break;
- case GST_EVENT_NEWSEGMENT:
+ case GST_EVENT_SEGMENT:
case GST_EVENT_TAG:
case GST_EVENT_BUFFERSIZE:
default:
goto wrong_type;
}
- if (this->payload_length
- && (!gst_dp_validate_payload (GST_DP_HEADER_LENGTH, this->header,
- gst_adapter_peek (this->adapter, this->payload_length)))) {
- goto payload_validate_error;
+ if (this->payload_length) {
+ const guint8 *data;
+ gboolean res;
+
+ data = gst_adapter_map (this->adapter, this->payload_length);
+ res = gst_dp_validate_payload (GST_DP_HEADER_LENGTH, this->header,
+ data);
+ gst_adapter_unmap (this->adapter, 0);
+
+ if (!res)
+ goto payload_validate_error;
}
break;
}
case GST_GDP_DEPAY_STATE_BUFFER:
{
-
/* if we receive a buffer without caps first, we error out */
if (!this->caps)
goto no_caps;
if (this->payload_length > 0) {
guint8 *payload;
- payload = gst_adapter_take (this->adapter, this->payload_length);
- memcpy (GST_BUFFER_DATA (buf), payload, this->payload_length);
- g_free (payload);
+ payload = gst_buffer_map (buf, NULL, NULL, GST_MAP_WRITE);
+ gst_adapter_copy (this->adapter, payload, 0, this->payload_length);
+ gst_buffer_unmap (buf, payload, this->payload_length);
+
+ gst_adapter_flush (this->adapter, this->payload_length);
}
/* set caps and push */
- gst_buffer_set_caps (buf, this->caps);
GST_LOG_OBJECT (this, "deserialized buffer %p, pushing, timestamp %"
GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT
", offset %" G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT
- ", size %d, flags 0x%x",
+ ", size %" G_GSIZE_FORMAT ", flags 0x%x",
buf,
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
GST_TIME_ARGS (GST_BUFFER_DURATION (buf)),
GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET_END (buf),
- GST_BUFFER_SIZE (buf), GST_BUFFER_FLAGS (buf));
+ gst_buffer_get_size (buf), GST_BUFFER_FLAGS (buf));
ret = gst_pad_push (this->srcpad, buf);
if (ret != GST_FLOW_OK)
goto push_error;
PROP_VERSION,
};
-#define _do_init(x) \
+#define _do_init \
GST_DEBUG_CATEGORY_INIT (gst_gdp_pay_debug, "gdppay", 0, \
"GDP payloader");
-
-GST_BOILERPLATE_FULL (GstGDPPay, gst_gdp_pay, GstElement,
- GST_TYPE_ELEMENT, _do_init);
+#define gst_gdp_pay_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstGDPPay, gst_gdp_pay, GST_TYPE_ELEMENT, _do_init);
static void gst_gdp_pay_reset (GstGDPPay * this);
static GstFlowReturn gst_gdp_pay_chain (GstPad * pad, GstBuffer * buffer);
-
static gboolean gst_gdp_pay_src_event (GstPad * pad, GstEvent * event);
-
static gboolean gst_gdp_pay_sink_event (GstPad * pad, GstEvent * event);
static GstStateChangeReturn gst_gdp_pay_change_state (GstElement *
static void gst_gdp_pay_finalize (GObject * gobject);
static void
-gst_gdp_pay_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_set_details_simple (element_class,
- "GDP Payloader", "GDP/Payloader",
- "Payloads GStreamer Data Protocol buffers",
- "Thomas Vander Stichele <thomas at apestaart dot org>");
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&gdp_pay_sink_template));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&gdp_pay_src_template));
-}
-
-static void
gst_gdp_pay_class_init (GstGDPPayClass * klass)
{
GObjectClass *gobject_class;
-
GstElementClass *gstelement_class;
gobject_class = (GObjectClass *) klass;
GST_TYPE_DP_VERSION, DEFAULT_VERSION,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ gst_element_class_set_details_simple (gstelement_class,
+ "GDP Payloader", "GDP/Payloader",
+ "Payloads GStreamer Data Protocol buffers",
+ "Thomas Vander Stichele <thomas at apestaart dot org>");
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gdp_pay_sink_template));
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gdp_pay_src_template));
+
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_gdp_pay_change_state);
}
static void
-gst_gdp_pay_init (GstGDPPay * gdppay, GstGDPPayClass * g_class)
+gst_gdp_pay_init (GstGDPPay * gdppay)
{
gdppay->sinkpad =
gst_pad_new_from_static_template (&gdp_pay_sink_template, "sink");
gst_gdp_stamp_buffer (GstGDPPay * this, GstBuffer * buffer)
{
GST_BUFFER_OFFSET (buffer) = this->offset;
- GST_BUFFER_OFFSET_END (buffer) = this->offset + GST_BUFFER_SIZE (buffer);
+ GST_BUFFER_OFFSET_END (buffer) = this->offset + gst_buffer_get_size (buffer);
this->offset = GST_BUFFER_OFFSET_END (buffer);
}
+#if 0
static GstBuffer *
gst_gdp_buffer_from_caps (GstGDPPay * this, GstCaps * caps)
{
GstBuffer *headerbuf;
-
GstBuffer *payloadbuf;
-
guint8 *header, *payload;
-
- guint len;
+ guint len, plen;
if (!this->packetizer->packet_from_caps (caps, this->header_flag, &len,
&header, &payload))
GST_LOG_OBJECT (this, "creating GDP header and payload buffer from caps");
headerbuf = gst_buffer_new ();
- gst_buffer_set_data (headerbuf, header, len);
- GST_BUFFER_MALLOCDATA (headerbuf) = header;
+ gst_buffer_take_memory (headerbuf,
+ gst_memory_new_wrapped (0, header, g_free, len, 0, len));
payloadbuf = gst_buffer_new ();
- gst_buffer_set_data (payloadbuf, payload,
- gst_dp_header_payload_length (header));
- GST_BUFFER_MALLOCDATA (payloadbuf) = payload;
+ plen = gst_dp_header_payload_length (header);
+ gst_buffer_take_memory (payloadbuf,
+ gst_memory_new_wrapped (0, payload, g_free, plen, 0, plen));
return gst_buffer_join (headerbuf, payloadbuf);
return NULL;
}
}
+#endif
static GstBuffer *
gst_gdp_pay_buffer_from_buffer (GstGDPPay * this, GstBuffer * buffer)
{
GstBuffer *headerbuf;
-
guint8 *header;
-
guint len;
if (!this->packetizer->header_from_buffer (buffer, this->header_flag, &len,
GST_LOG_OBJECT (this, "creating GDP header and payload buffer from buffer");
headerbuf = gst_buffer_new ();
- gst_buffer_set_data (headerbuf, header, len);
- GST_BUFFER_MALLOCDATA (headerbuf) = header;
+ gst_buffer_take_memory (headerbuf,
+ gst_memory_new_wrapped (0, header, g_free, len, 0, len));
/* we do not want to lose the ref on the incoming buffer */
gst_buffer_ref (buffer);
gst_gdp_buffer_from_event (GstGDPPay * this, GstEvent * event)
{
GstBuffer *headerbuf;
-
GstBuffer *payloadbuf;
-
guint8 *header, *payload;
-
- guint len;
-
+ guint len, plen;
gboolean ret;
ret =
GST_LOG_OBJECT (this, "creating GDP header and payload buffer from event");
headerbuf = gst_buffer_new ();
- gst_buffer_set_data (headerbuf, header, len);
- GST_BUFFER_MALLOCDATA (headerbuf) = header;
+ gst_buffer_take_memory (headerbuf,
+ gst_memory_new_wrapped (0, header, g_free, len, 0, len));
payloadbuf = gst_buffer_new ();
- gst_buffer_set_data (payloadbuf, payload,
- gst_dp_header_payload_length (header));
- GST_BUFFER_MALLOCDATA (payloadbuf) = payload;
+ plen = gst_dp_header_payload_length (header);
+ if (plen && payload != NULL) {
+ gst_buffer_take_memory (payloadbuf,
+ gst_memory_new_wrapped (0, payload, g_free, plen, 0, plen));
+ }
return gst_buffer_join (headerbuf, payloadbuf);
gst_gdp_pay_reset_streamheader (GstGDPPay * this)
{
GstCaps *caps;
-
/* We use copies of these to avoid circular refcounts */
GstBuffer *new_segment_buf, *caps_buf, *tag_buf;
-
GstStructure *structure;
-
GstFlowReturn r = GST_FLOW_OK;
-
gboolean version_one_zero = TRUE;
GValue array = { 0 };
GST_DEBUG_OBJECT (this, "1.0, appending copy of new segment buffer %p",
this->new_segment_buf);
new_segment_buf = gst_buffer_copy (this->new_segment_buf);
- gst_buffer_set_caps (new_segment_buf, NULL);
g_value_init (&value, GST_TYPE_BUFFER);
gst_value_set_buffer (&value, new_segment_buf);
gst_value_array_append_value (&array, &value);
tag_buf = this->tag_buf;
this->tag_buf = NULL;
- gst_buffer_set_caps (tag_buf, NULL);
g_value_init (&value, GST_TYPE_BUFFER);
gst_value_set_buffer (&value, tag_buf);
gst_value_array_append_value (&array, &value);
gst_gdp_stamp_buffer (this, this->caps_buf);
GST_DEBUG_OBJECT (this, "appending copy of caps buffer %p", this->caps_buf);
caps_buf = gst_buffer_copy (this->caps_buf);
- gst_buffer_set_caps (caps_buf, NULL);
g_value_init (&value, GST_TYPE_BUFFER);
gst_value_set_buffer (&value, caps_buf);
gst_value_array_append_value (&array, &value);
GST_DEBUG_OBJECT (this, "Setting caps on src pad %" GST_PTR_FORMAT, caps);
gst_pad_set_caps (this->srcpad, caps);
- this->caps_buf = gst_buffer_make_metadata_writable (this->caps_buf);
- gst_buffer_set_caps (this->caps_buf, caps);
- this->new_segment_buf =
- gst_buffer_make_metadata_writable (this->new_segment_buf);
- gst_buffer_set_caps (this->new_segment_buf, caps);
/* if these are our first ever buffers, send out new_segment first */
if (!this->sent_streamheader) {
- GstEvent *event =
- gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_BYTES, 0, -1, 0);
+ GstEvent *event;
+ GstSegment segment;
+
+ gst_segment_init (&segment, GST_FORMAT_BYTES);
+ event = gst_event_new_segment (&segment);
+
GST_DEBUG_OBJECT (this, "Sending out new_segment event %p", event);
if (!gst_pad_push_event (this->srcpad, event)) {
GST_WARNING_OBJECT (this, "pushing new segment failed");
goto done;
}
if (this->tag_buf) {
- gst_buffer_set_caps (this->tag_buf, caps);
GST_DEBUG_OBJECT (this, "Pushing GDP tag buffer %p", this->tag_buf);
/* we stored these bufs with refcount 1, so make sure we keep a ref */
r = gst_pad_push (this->srcpad, gst_buffer_ref (this->tag_buf));
this->queue = g_list_delete_link (this->queue, this->queue);
/* set caps and push */
- gst_buffer_set_caps (buffer, caps);
r = gst_pad_push (this->srcpad, buffer);
if (r != GST_FLOW_OK) {
GST_WARNING_OBJECT (this, "pushing queued GDP buffer returned %d", r);
if (this->sent_streamheader) {
GST_LOG_OBJECT (this, "Pushing GDP buffer %p, caps %" GST_PTR_FORMAT,
buffer, this->caps);
- gst_buffer_set_caps (buffer, GST_PAD_CAPS (this->srcpad));
return gst_pad_push (this->srcpad, buffer);
}
gst_gdp_pay_chain (GstPad * pad, GstBuffer * buffer)
{
GstGDPPay *this;
-
+#if 0
GstCaps *caps;
-
+#endif
GstBuffer *outbuffer;
-
GstFlowReturn ret;
this = GST_GDP_PAY (gst_pad_get_parent (pad));
* fake one in that case */
if (!this->new_segment_buf) {
GstEvent *event;
+ GstSegment segment;
GST_WARNING_OBJECT (this,
"did not receive new-segment before first buffer");
- event = gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_BYTES, 0, -1, 0);
+ gst_segment_init (&segment, GST_FORMAT_BYTES);
+ event = gst_event_new_segment (&segment);
outbuffer = gst_gdp_buffer_from_event (this, event);
gst_event_unref (event);
this->new_segment_buf = outbuffer;
}
}
-
+#if 0
/* make sure we've received caps before */
caps = gst_buffer_get_caps (buffer);
if (!this->caps && !caps)
if (caps)
gst_caps_unref (caps);
+#endif
/* create a GDP header packet,
* then create a GST buffer of the header packet and the buffer contents */
return ret;
/* ERRORS */
+#if 0
no_caps:
{
/* when returning a fatal error as a GstFlowReturn we must post an error
ret = GST_FLOW_ERROR;
goto done;
}
+#endif
no_buffer:
{
GST_ELEMENT_ERROR (this, STREAM, ENCODE, (NULL),
gst_gdp_pay_sink_event (GstPad * pad, GstEvent * event)
{
GstBuffer *outbuffer;
-
GstGDPPay *this = GST_GDP_PAY (gst_pad_get_parent (pad));
-
GstFlowReturn flowret;
-
gboolean ret = TRUE;
GST_DEBUG_OBJECT (this, "received event %p of type %s (%d)",
/* if we got a new segment or tag event, we should put it on our streamheader,
* and not send it on */
switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_NEWSEGMENT:
+ case GST_EVENT_SEGMENT:
GST_DEBUG_OBJECT (this, "Storing in caps buffer %p as new_segment_buf",
outbuffer);
gst_gdp_pay_src_event (GstPad * pad, GstEvent * event)
{
GstGDPPay *this;
-
gboolean res = TRUE;
this = GST_GDP_PAY (gst_pad_get_parent (pad));
gst_gdp_pay_change_state (GstElement * element, GstStateChange transition)
{
GstStateChangeReturn ret;
-
GstGDPPay *this = GST_GDP_PAY (element);
switch (transition) {
get_our_ghost_pad (GstDecodeBin * decode_bin, GstPad * pad)
{
GstIterator *pad_it = NULL;
+ GValue item = { 0, };
GstPad *db_pad = NULL;
gboolean done = FALSE;
pad_it = gst_element_iterate_src_pads (GST_ELEMENT (decode_bin));
while (!done) {
db_pad = NULL;
- switch (gst_iterator_next (pad_it, (gpointer) & db_pad)) {
- case GST_ITERATOR_OK:
+ switch (gst_iterator_next (pad_it, &item)) {
+ case GST_ITERATOR_OK:{
+ db_pad = g_value_get_object (&item);
GST_DEBUG_OBJECT (decode_bin, "looking at pad %s:%s",
GST_DEBUG_PAD_NAME (db_pad));
if (GST_IS_GHOST_PAD (db_pad)) {
}
}
/* Not the right one */
- gst_object_unref (db_pad);
+ g_value_reset (&item);
break;
+ }
case GST_ITERATOR_RESYNC:
gst_iterator_resync (pad_it);
break;
break;
}
}
+ g_value_unset (&item);
gst_iterator_free (pad_it);
return db_pad;
{
GstIterator *iter;
gboolean done = FALSE;
- gpointer item;
+ GValue item = { 0, };
GstElement *elem = GST_ELEMENT (GST_OBJECT_PARENT (pad));
while (GST_OBJECT_PARENT (elem) &&
GstPad *ghostpad;
GstPad *peer;
- pad = GST_PAD (item);
+ pad = g_value_get_object (&item);
GST_DEBUG_OBJECT (decode_bin, "inspecting internal pad %s:%s",
GST_DEBUG_PAD_NAME (pad));
gst_element_remove_pad (GST_ELEMENT (decode_bin), ghostpad);
gst_object_unref (ghostpad);
+ g_value_reset (&item);
continue;
} else {
GST_DEBUG_OBJECT (decode_bin, "not one of our ghostpads");
}
gst_object_unref (peer);
}
- gst_object_unref (item);
+ g_value_reset (&item);
}
break;
case GST_ITERATOR_RESYNC:
}
}
GST_DEBUG_OBJECT (decode_bin, "removing %s", GST_ELEMENT_NAME (elem));
-
+ g_value_unset (&item);
gst_iterator_free (iter);
no_iter:
/* see if any more pending dynamic connections exist */
more = gst_decode_bin_is_dynamic (decode_bin);
- caps = gst_pad_get_caps (pad);
+ caps = gst_pad_get_caps (pad, NULL);
close_pad_link (element, pad, caps, decode_bin, more);
if (caps)
gst_caps_unref (caps);
GST_OBJECT_NAME (pad));
/* continue autoplugging on the pads */
- caps = gst_pad_get_caps (pad);
+ caps = gst_pad_get_caps (pad, NULL);
close_pad_link (element, pad, caps, decode_bin, more);
if (caps)
gst_caps_unref (caps);
{
GstIterator *pad_it = NULL;
gboolean done = FALSE;
+ GstPad *pad = NULL;
+ GValue item = { 0, };
pad_it = gst_element_iterate_src_pads (element);
while (!done) {
- GstPad *pad = NULL;
-
- switch (gst_iterator_next (pad_it, (gpointer) & pad)) {
+ switch (gst_iterator_next (pad_it, &item)) {
case GST_ITERATOR_OK:
+ pad = g_value_get_object (&item);
g_signal_handlers_disconnect_by_func (pad, (gpointer) unlinked,
decode_bin);
- gst_object_unref (pad);
+ g_value_reset (&item);
break;
case GST_ITERATOR_RESYNC:
gst_iterator_resync (pad_it);
break;
}
}
+ g_value_unset (&item);
gst_iterator_free (pad_it);
}
GstIterator *elem_it = NULL, *gpad_it = NULL;
GstPad *typefind_pad = NULL;
gboolean done = FALSE;
+ GstElement *element = NULL;
+ GstPad *pad = NULL;
+ GValue item = { 0, };
g_return_if_fail (GST_IS_DECODE_BIN (decode_bin));
elem_it = gst_bin_iterate_elements (GST_BIN (decode_bin));
while (!done) {
- GstElement *element = NULL;
-
- switch (gst_iterator_next (elem_it, (gpointer) & element)) {
+ switch (gst_iterator_next (elem_it, &item)) {
case GST_ITERATOR_OK:
+ element = g_value_get_object (&item);
if (element != decode_bin->typefind && element != decode_bin->fakesink) {
GST_DEBUG_OBJECT (element, "removing autoplugged element");
disconnect_unlinked_signals (decode_bin, element);
gst_element_set_state (element, GST_STATE_NULL);
gst_bin_remove (GST_BIN (decode_bin), element);
}
- gst_object_unref (element);
+ g_value_reset (&item);
break;
case GST_ITERATOR_RESYNC:
gst_iterator_resync (elem_it);
break;
}
}
+ g_value_unset (&item);
gst_iterator_free (elem_it);
done = FALSE;
gpad_it = gst_element_iterate_pads (GST_ELEMENT (decode_bin));
while (!done) {
- GstPad *pad = NULL;
-
- switch (gst_iterator_next (gpad_it, (gpointer) & pad)) {
+ switch (gst_iterator_next (gpad_it, &item)) {
case GST_ITERATOR_OK:
+ pad = g_value_get_object (&item);
GST_DEBUG_OBJECT (pad, "inspecting pad %s:%s",
GST_DEBUG_PAD_NAME (pad));
if (GST_IS_GHOST_PAD (pad) && GST_PAD_IS_SRC (pad)) {
GST_DEBUG_OBJECT (pad, "removing ghost pad");
gst_element_remove_pad (GST_ELEMENT (decode_bin), pad);
}
- gst_object_unref (pad);
+ g_value_reset (&item);
break;
case GST_ITERATOR_RESYNC:
gst_iterator_resync (gpad_it);
break;
}
}
+ g_value_unset (&item);
gst_iterator_free (gpad_it);
if (GST_IS_PAD (typefind_pad)) {
/* first check the pad caps, if this is set, we are positively sure it is
* fixed and exactly what the element will produce. */
- GST_OBJECT_LOCK (pad);
- if ((caps = GST_PAD_CAPS (pad)))
- gst_caps_ref (caps);
- GST_OBJECT_UNLOCK (pad);
+ caps = gst_pad_get_current_caps (pad);
/* then use the getcaps function if we don't have caps. These caps might not
* be fixed in some cases, in which case analyze_new_pad will set up a
* notify::caps signal to continue autoplugging. */
if (caps == NULL)
- caps = gst_pad_get_caps_reffed (pad);
+ caps = gst_pad_get_caps (pad, NULL);
return caps;
}
GstDecodeBin *dbin;
GstPad *srcpad, *sinkpad;
GstIterator *it = NULL;
+ GValue item = { 0, };
dbin = group->dbin;
it = gst_pad_iterate_internal_links (sinkpad);
- if (!it || (gst_iterator_next (it, (gpointer) & srcpad)) != GST_ITERATOR_OK
- || srcpad == NULL) {
+ if (!it || (gst_iterator_next (it, &item)) != GST_ITERATOR_OK
+ || ((srcpad = g_value_dup_object (&item)) == NULL)) {
GST_ERROR_OBJECT (dbin,
"Couldn't get srcpad from multiqueue for sinkpad %" GST_PTR_FORMAT,
sinkpad);
goto error;
}
-
CHAIN_MUTEX_LOCK (group->parent);
group->reqpads = g_list_prepend (group->reqpads, gst_object_ref (sinkpad));
CHAIN_MUTEX_UNLOCK (group->parent);
beach:
+ g_value_unset (&item);
if (it)
gst_iterator_free (it);
gst_object_unref (sinkpad);
GstPad *pad, *peer;
gboolean done = FALSE;
GstCaps *caps = NULL;
+ GValue item = { 0, };
it = gst_element_iterate_src_pads (src);
while (!done) {
- switch (gst_iterator_next (it, (gpointer) & pad)) {
+ switch (gst_iterator_next (it, &item)) {
case GST_ITERATOR_OK:
+ pad = g_value_get_object (&item);
peer = gst_pad_get_peer (pad);
if (peer) {
parent = gst_pad_get_parent_element (peer);
gst_object_unref (parent);
gst_object_unref (peer);
}
- gst_object_unref (pad);
+ g_value_reset (&item);
break;
case GST_ITERATOR_RESYNC:
gst_iterator_resync (it);
break;
}
}
-
+ g_value_unset (&item);
gst_iterator_free (it);
return caps;
pad->blocked = FALSE;
pad->exposed = FALSE;
pad->drained = FALSE;
- gst_object_ref (pad);
- gst_object_sink (pad);
+ gst_object_ref_sink (pad);
}
static void
{
GstIterator *it;
GstPad *pad = NULL;
- gpointer point;
+ GValue item = { 0, };
it = gst_element_iterate_sink_pads (element);
- if ((gst_iterator_next (it, &point)) == GST_ITERATOR_OK)
- pad = (GstPad *) point;
-
+ if ((gst_iterator_next (it, &item)) == GST_ITERATOR_OK)
+ pad = g_value_dup_object (&item);
+ g_value_unset (&item);
gst_iterator_free (it);
return pad;
GST_DEBUG ("play base: new decoded pad. Last: %d", last);
/* first see if this pad has interesting caps */
- caps = gst_pad_get_caps (pad);
+ caps = gst_pad_get_caps (pad, NULL);
if (caps == NULL || gst_caps_is_empty (caps) || gst_caps_is_any (caps))
goto no_type;
guint i, num_raw = 0;
gboolean res = FALSE;
- caps = gst_pad_get_caps (pad);
+ caps = gst_pad_get_caps (pad, NULL);
if (caps == NULL)
return FALSE;
GstIterator *pads_iter;
gboolean done = FALSE;
gboolean res = TRUE;
+ GValue item = { 0, };
*have_out = FALSE;
*is_raw = FALSE;
while (!done) {
GstPad *pad = NULL;
- switch (gst_iterator_next (pads_iter, (gpointer) & pad)) {
+ switch (gst_iterator_next (pads_iter, &item)) {
case GST_ITERATOR_ERROR:
res = FALSE;
/* FALLTROUGH */
gst_iterator_resync (pads_iter);
break;
case GST_ITERATOR_OK:
+ pad = g_value_get_object (&item);
/* we now officially have an ouput pad */
*have_out = TRUE;
/* if FALSE, this pad has no caps and we continue with the next pad. */
if (!has_all_raw_caps (pad, is_raw)) {
- gst_object_unref (pad);
+ g_value_reset (&item);
break;
}
play_base_bin, FALSE);
}
- gst_object_unref (pad);
+ g_value_reset (&item);
break;
}
}
+ g_value_unset (&item);
gst_iterator_free (pads_iter);
if (!*have_out) {
0.0, VOLUME_MAX_DOUBLE, 1.0,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_klass, ARG_FRAME,
- gst_param_spec_mini_object ("frame", "Frame",
+ g_param_spec_boxed ("frame", "Frame",
"The last frame (NULL = no video available)", GST_TYPE_BUFFER,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_klass, ARG_FONT_DESC,
}
play_bin->video_sink = g_value_get_object (value);
if (play_bin->video_sink != NULL) {
- gst_object_ref (play_bin->video_sink);
- gst_object_sink (GST_OBJECT_CAST (play_bin->video_sink));
+ gst_object_ref_sink (play_bin->video_sink);
}
/* when changing the videosink, we just remove the
* video pipeline from the cache so that it will be
}
play_bin->audio_sink = g_value_get_object (value);
if (play_bin->audio_sink != NULL) {
- gst_object_ref (play_bin->audio_sink);
- gst_object_sink (GST_OBJECT_CAST (play_bin->audio_sink));
+ gst_object_ref_sink (play_bin->audio_sink);
}
g_hash_table_remove (play_bin->cache, "abin");
break;
/* Take ownership */
if (pending_visualisation) {
- gst_object_ref (pending_visualisation);
- gst_object_sink (pending_visualisation);
+ gst_object_ref_sink (pending_visualisation);
}
/* Do we already have a visualisation change pending ? */
{
GstPlayBin *play_bin = GST_PLAY_BIN (data);
+#if 0
/* applications need to know the buffer caps,
* make sure they are always set on the frame */
if (GST_BUFFER_CAPS (frame) == NULL) {
gst_object_unref (pad);
}
}
+#endif
gst_buffer_replace (&play_bin->frame, frame);
}
GstCaps *caps;
/* could not link this stream */
- caps = gst_pad_get_caps (srcpad);
+ caps = gst_pad_get_caps (srcpad, NULL);
capsstr = gst_caps_to_string (caps);
g_warning ("could not link %s: %d", capsstr, linkres);
GST_DEBUG_OBJECT (play_bin,
GstCaps *caps;
/* could not link this stream */
- caps = gst_pad_get_caps (subtitle_pad);
+ caps = gst_pad_get_caps (subtitle_pad, NULL);
GST_WARNING_OBJECT (play_bin, "subtitle link failed when adding sink, "
"caps = %" GST_PTR_FORMAT ", reason %d", caps, linkres);
gst_caps_unref (caps);
guint size, i;
GstPlayBaseBin *playbasebin = GST_PLAY_BASE_BIN (playbin);
guint connection_speed = playbasebin->connection_speed;
+ const GstStructure *structure;
GST_DEBUG_OBJECT (playbin, "redirect message: %" GST_PTR_FORMAT, msg);
GST_DEBUG_OBJECT (playbin, "connection speed: %u", connection_speed);
- if (connection_speed == 0 || msg->structure == NULL)
+ structure = gst_message_get_structure (msg);
+ if (connection_speed == 0 || structure == NULL)
return msg;
- locations_list = gst_structure_get_value (msg->structure, "locations");
+ locations_list = gst_structure_get_value (structure, "locations");
if (locations_list == NULL)
return msg;
static void
gst_play_bin_handle_message (GstBin * bin, GstMessage * msg)
{
- if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ELEMENT && msg->structure != NULL
- && gst_structure_has_name (msg->structure, "redirect")) {
+ const GstStructure *structure;
+
+ structure = gst_message_get_structure (msg);
+ if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ELEMENT && structure != NULL
+ && gst_structure_has_name (structure, "redirect")) {
msg = gst_play_bin_handle_redirect_message (GST_PLAY_BIN (bin), msg);
}
* The #GstCaps on the buffer will describe the format of the buffer.
*/
g_object_class_install_property (gobject_klass, PROP_FRAME,
- gst_param_spec_mini_object ("frame", "Frame",
+ g_param_spec_boxed ("frame", "Frame",
"The last frame (NULL = no video available)",
GST_TYPE_BUFFER, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_klass, PROP_FONT_DESC,
{
GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
GstPad *sinkpad;
+ GValue item = { 0, };
- if (it && gst_iterator_next (it, (gpointer) & sinkpad) == GST_ITERATOR_OK
- && sinkpad) {
+ if (it && gst_iterator_next (it, &item) == GST_ITERATOR_OK
+ && ((sinkpad = g_value_get_object (&item)) != NULL)) {
GstEvent *event;
event =
GST_DEBUG_OBJECT (suburidecodebin, "Seeking to the beginning failed!");
}
- gst_object_unref (sinkpad);
+ g_value_unset (&item);
}
if (it)
{
GstIterator *it = gst_element_iterate_src_pads (suburidecodebin);
gboolean done = FALSE;
+ GValue item = { 0, };
GST_DEBUG_OBJECT (suburidecodebin, "Blocking suburidecodebin: %d", block);
while (!done) {
GstPad *sinkpad;
- switch (gst_iterator_next (it, (gpointer) & sinkpad)) {
+ switch (gst_iterator_next (it, &item)) {
case GST_ITERATOR_OK:
+ sinkpad = g_value_get_object (&item);
gst_pad_set_blocked_async (sinkpad, block, _suburidecodebin_blocked_cb,
NULL);
- gst_object_unref (sinkpad);
+ g_value_reset (&item);
break;
case GST_ITERATOR_DONE:
done = TRUE;
break;
}
}
+ g_value_unset (&item);
gst_iterator_free (it);
}
GstMessage *new_msg;
GstIterator *it;
gboolean done = FALSE;
+ GValue item = { 0, };
gst_message_parse_error (msg, &err, &debug);
new_msg = gst_message_new_warning (msg->src, err, debug);
GstPad *p = NULL;
GstIteratorResult res;
- res = gst_iterator_next (it, (gpointer) & p);
+ res = gst_iterator_next (it, &item);
switch (res) {
case GST_ITERATOR_DONE:
done = TRUE;
break;
case GST_ITERATOR_OK:
+ p = g_value_get_object (&item);
pad_removed_cb (NULL, p, group);
- gst_object_unref (p);
+ g_value_reset (&item);
break;
case GST_ITERATOR_RESYNC:
break;
}
}
+ g_value_unset (&item);
if (it)
gst_iterator_free (it);
}
if (GST_IS_EVENT (object)
- && GST_EVENT_TYPE (GST_EVENT_CAST (object)) == GST_EVENT_NEWSEGMENT) {
+ && GST_EVENT_TYPE (GST_EVENT_CAST (object)) == GST_EVENT_SEGMENT) {
/* push the event first, then send the delayed one */
gst_event_ref (GST_EVENT_CAST (object));
gst_pad_send_event (pad, GST_EVENT_CAST (object));
playbin = group->playbin;
- caps = gst_pad_get_caps_reffed (pad);
+ caps = gst_pad_get_caps (pad, NULL);
s = gst_caps_get_structure (caps, 0);
name = gst_structure_get_name (s);
if (GST_STATE (sink) < GST_STATE_READY)
gst_element_set_state (sink, GST_STATE_READY);
- sinkcaps = gst_pad_get_caps_reffed (sinkpad);
+ sinkcaps = gst_pad_get_caps (sinkpad, NULL);
if (!gst_caps_is_any (sinkcaps))
ret = !gst_pad_accept_caps (sinkpad, caps);
gst_caps_unref (sinkcaps);
if (GST_STATE (sink) < GST_STATE_READY)
gst_element_set_state (sink, GST_STATE_READY);
- sinkcaps = gst_pad_get_caps_reffed (sinkpad);
+ sinkcaps = gst_pad_get_caps (sinkpad, NULL);
if (!gst_caps_is_any (sinkcaps))
ret = !gst_pad_accept_caps (sinkpad, caps);
gst_caps_unref (sinkcaps);
if (GST_STATE (sink) < GST_STATE_READY)
gst_element_set_state (sink, GST_STATE_READY);
- sinkcaps = gst_pad_get_caps_reffed (sinkpad);
+ sinkcaps = gst_pad_get_caps (sinkpad, NULL);
if (!gst_caps_is_any (sinkcaps))
ret = !gst_pad_accept_caps (sinkpad, caps);
gst_caps_unref (sinkcaps);
GST_DEBUG_OBJECT (playbin, "select group %p for %s:%s, %" GST_PTR_FORMAT,
group, GST_DEBUG_PAD_NAME (pad), caps);
- GST_DEBUG_OBJECT (playbin, "checking factory %s",
- GST_PLUGIN_FEATURE_NAME (factory));
+ GST_DEBUG_OBJECT (playbin, "checking factory %s", GST_OBJECT_NAME (factory));
/* if it's not a sink, we just make decodebin try it */
if (!gst_element_factory_list_is_type (factory,
GValue * value, GParamSpec * spec);
static GstPad *gst_play_sink_request_new_pad (GstElement * element,
- GstPadTemplate * templ, const gchar * name);
+ GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
static void gst_play_sink_release_request_pad (GstElement * element,
GstPad * pad);
static gboolean gst_play_sink_send_event (GstElement * element,
* Since: 0.10.30
*/
g_object_class_install_property (gobject_klass, PROP_FRAME,
- gst_param_spec_mini_object ("frame", "Frame",
+ g_param_spec_boxed ("frame", "Frame",
"The last frame (NULL = no video available)",
GST_TYPE_BUFFER, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
/**
} FindPropertyHelper;
static gint
-find_property (GstElement * element, FindPropertyHelper * helper)
+find_property (const GValue * item, FindPropertyHelper * helper)
{
+ GstElement *element = g_value_get_object (item);
if (helper->need_sink && !element_is_sink (element)) {
- gst_object_unref (element);
return 1;
}
if (!element_has_property (element, helper->prop_name, helper->prop_type)) {
- gst_object_unref (element);
return 1;
}
if (element_has_property (obj, name, expected_type)) {
result = obj;
} else if (GST_IS_BIN (obj)) {
+ gboolean found;
+ GValue item = { 0, };
FindPropertyHelper helper = { name, expected_type, TRUE };
it = gst_bin_iterate_recurse (GST_BIN_CAST (obj));
- result = gst_iterator_find_custom (it,
- (GCompareFunc) find_property, &helper);
+ found = gst_iterator_find_custom (it,
+ (GCompareFunc) find_property, &item, &helper);
gst_iterator_free (it);
+ if (found)
+ result = g_value_get_object (&item);
/* we don't need the extra ref */
- if (result)
- gst_object_unref (result);
+ g_value_unset (&item);
}
return result;
}
GstIterator *it;
if (GST_IS_BIN (obj)) {
+ gboolean found;
+ GValue item = { 0, };
FindPropertyHelper helper = { name, expected_type, FALSE };
it = gst_bin_iterate_recurse (GST_BIN_CAST (obj));
- result = gst_iterator_find_custom (it,
- (GCompareFunc) find_property, &helper);
+ found = gst_iterator_find_custom (it,
+ (GCompareFunc) find_property, &item, &helper);
gst_iterator_free (it);
+ if (found)
+ result = g_value_dup_object (&item);
+ g_value_unset (&item);
} else {
if (element_has_property (obj, name, expected_type)) {
result = obj;
goto no_chain;
if (!playsink->video_sinkpad_stream_synchronizer) {
+ GValue item = { 0, };
GstIterator *it;
playsink->video_sinkpad_stream_synchronizer =
it = gst_pad_iterate_internal_links
(playsink->video_sinkpad_stream_synchronizer);
g_assert (it);
- gst_iterator_next (it,
- (gpointer *) & playsink->video_srcpad_stream_synchronizer);
+ gst_iterator_next (it, &item);
+ playsink->video_srcpad_stream_synchronizer = g_value_dup_object (&item);
+ g_value_unset (&item);
g_assert (playsink->video_srcpad_stream_synchronizer);
gst_iterator_free (it);
}
}
if (!playsink->audio_sinkpad_stream_synchronizer) {
+ GValue item = { 0, };
GstIterator *it;
playsink->audio_sinkpad_stream_synchronizer =
it = gst_pad_iterate_internal_links
(playsink->audio_sinkpad_stream_synchronizer);
g_assert (it);
- gst_iterator_next (it,
- (gpointer *) & playsink->audio_srcpad_stream_synchronizer);
+ gst_iterator_next (it, &item);
+ playsink->audio_srcpad_stream_synchronizer = g_value_dup_object (&item);
+ g_value_unset (&item);
g_assert (playsink->audio_srcpad_stream_synchronizer);
gst_iterator_free (it);
}
add_chain (GST_PLAY_CHAIN (playsink->textchain), TRUE);
if (!playsink->text_sinkpad_stream_synchronizer) {
+ GValue item = { 0, };
+
playsink->text_sinkpad_stream_synchronizer =
gst_element_get_request_pad (GST_ELEMENT_CAST
(playsink->stream_synchronizer), "sink_%d");
it = gst_pad_iterate_internal_links
(playsink->text_sinkpad_stream_synchronizer);
g_assert (it);
- gst_iterator_next (it,
- (gpointer *) & playsink->text_srcpad_stream_synchronizer);
+ gst_iterator_next (it, &item);
+ playsink->text_srcpad_stream_synchronizer = g_value_dup_object (&item);
+ g_value_unset (&item);
g_assert (playsink->text_srcpad_stream_synchronizer);
gst_iterator_free (it);
GstBuffer *temp;
GError *err = NULL;
- temp = gst_video_convert_frame (result, caps, 25 * GST_SECOND, &err);
+ /* FIXME, need to get the input buffer caps */
+ temp = gst_video_convert_frame (result, NULL, caps, 25 * GST_SECOND, &err);
gst_buffer_unref (result);
if (temp == NULL && err) {
/* I'm really uncertain whether we should make playsink post an error
if (!caps) {
guint i, n;
- caps = gst_pad_get_caps_reffed (peer);
+ caps = gst_pad_get_caps (peer, NULL);
n = gst_caps_get_size (caps);
for (i = 0; i < n; i++) {
static GstPad *
gst_play_sink_request_new_pad (GstElement * element, GstPadTemplate * templ,
- const gchar * name)
+ const gchar * name, const GstCaps * caps)
{
GstPlaySink *psink;
GstPad *pad;
}
static void
-distribute_running_time (GstElement * element, const GstSegment * segment)
-{
- GstEvent *event;
- GstPad *pad;
-
- pad = gst_element_get_static_pad (element, "sink");
-
- if (segment->accum) {
- event = gst_event_new_new_segment_full (FALSE, segment->rate,
- segment->applied_rate, segment->format, 0, segment->accum, 0);
- gst_pad_push_event (pad, event);
- }
-
- event = gst_event_new_new_segment_full (FALSE, segment->rate,
- segment->applied_rate, segment->format,
- segment->start, segment->stop, segment->time);
- gst_pad_push_event (pad, event);
-
- gst_object_unref (pad);
-}
-
-static void
pad_blocked_cb (GstPad * pad, gboolean blocked, GstPlaySinkAudioConvert * self)
{
GstPad *peer;
peer = gst_pad_get_peer (self->sinkpad);
caps = gst_pad_get_negotiated_caps (peer);
if (!caps)
- caps = gst_pad_get_caps_reffed (peer);
+ caps = gst_pad_get_caps (peer, NULL);
gst_object_unref (peer);
raw = is_raw_caps (caps);
} else {
gst_bin_add (bin, self->conv);
gst_element_sync_state_with_parent (self->conv);
- distribute_running_time (self->conv, &self->segment);
prev = head = self->conv;
}
} else {
gst_bin_add (bin, self->resample);
gst_element_sync_state_with_parent (self->resample);
- distribute_running_time (self->resample, &self->segment);
if (prev) {
if (!gst_element_link_pads_full (prev, "src", self->resample, "sink",
GST_PAD_LINK_CHECK_TEMPLATE_CAPS))
if (self->use_volume && self->volume) {
gst_bin_add (bin, gst_object_ref (self->volume));
gst_element_sync_state_with_parent (self->volume);
- distribute_running_time (self->volume, &self->segment);
if (prev) {
if (!gst_element_link_pads_full (prev, "src", self->volume, "sink",
GST_PAD_LINK_CHECK_TEMPLATE_CAPS))
ret = gst_proxy_pad_event_default (pad, gst_event_ref (event));
- if (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT) {
- gboolean update;
- gdouble rate, applied_rate;
- GstFormat format;
- gint64 start, stop, position;
-
+ if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) {
GST_PLAY_SINK_AUDIO_CONVERT_LOCK (self);
- gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
- &format, &start, &stop, &position);
-
GST_DEBUG_OBJECT (self, "Segment before %" GST_SEGMENT_FORMAT,
&self->segment);
- gst_segment_set_newsegment_full (&self->segment, update, rate, applied_rate,
- format, start, stop, position);
+ gst_event_copy_segment (event, &self->segment);
GST_DEBUG_OBJECT (self, "Segment after %" GST_SEGMENT_FORMAT,
&self->segment);
GST_PLAY_SINK_AUDIO_CONVERT_UNLOCK (self);
}
static GstCaps *
-gst_play_sink_audio_convert_getcaps (GstPad * pad)
+gst_play_sink_audio_convert_getcaps (GstPad * pad, GstCaps * filter)
{
GstPlaySinkAudioConvert *self =
GST_PLAY_SINK_AUDIO_CONVERT (gst_pad_get_parent (pad));
peer = gst_pad_get_peer (otherpad);
if (peer) {
- ret = gst_pad_get_caps_reffed (peer);
+ ret = gst_pad_get_caps (peer, filter);
gst_object_unref (peer);
} else {
- ret = gst_caps_new_any ();
+ ret = (filter ? gst_caps_ref (filter) : gst_caps_new_any ());
}
gst_object_unref (otherpad);
}
static void
-distribute_running_time (GstElement * element, const GstSegment * segment)
-{
- GstEvent *event;
- GstPad *pad;
-
- pad = gst_element_get_static_pad (element, "sink");
-
- if (segment->accum) {
- event = gst_event_new_new_segment_full (FALSE, segment->rate,
- segment->applied_rate, segment->format, 0, segment->accum, 0);
- gst_pad_push_event (pad, event);
- }
-
- event = gst_event_new_new_segment_full (FALSE, segment->rate,
- segment->applied_rate, segment->format,
- segment->start, segment->stop, segment->time);
- gst_pad_push_event (pad, event);
-
- gst_object_unref (pad);
-}
-
-static void
pad_blocked_cb (GstPad * pad, gboolean blocked, GstPlaySinkVideoConvert * self)
{
GstPad *peer;
peer = gst_pad_get_peer (self->sinkpad);
caps = gst_pad_get_negotiated_caps (peer);
if (!caps)
- caps = gst_pad_get_caps_reffed (peer);
+ caps = gst_pad_get_caps (peer, NULL);
gst_object_unref (peer);
raw = is_raw_caps (caps);
} else {
gst_bin_add (bin, self->conv);
gst_element_sync_state_with_parent (self->conv);
- distribute_running_time (self->conv, &self->segment);
prev = head = self->conv;
}
g_object_set (self->scale, "add-borders", TRUE, NULL);
gst_bin_add (bin, self->scale);
gst_element_sync_state_with_parent (self->scale);
- distribute_running_time (self->scale, &self->segment);
if (prev) {
if (!gst_element_link_pads_full (prev, "src", self->scale, "sink",
GST_PAD_LINK_CHECK_TEMPLATE_CAPS))
ret = gst_proxy_pad_event_default (pad, gst_event_ref (event));
- if (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT) {
- gboolean update;
- gdouble rate, applied_rate;
- GstFormat format;
- gint64 start, stop, position;
+ if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) {
GST_PLAY_SINK_VIDEO_CONVERT_LOCK (self);
- gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
- &format, &start, &stop, &position);
-
GST_DEBUG_OBJECT (self, "Segment before %" GST_SEGMENT_FORMAT,
&self->segment);
- gst_segment_set_newsegment_full (&self->segment, update, rate, applied_rate,
- format, start, stop, position);
+ gst_event_copy_segment (event, &self->segment);
GST_DEBUG_OBJECT (self, "Segment after %" GST_SEGMENT_FORMAT,
&self->segment);
GST_PLAY_SINK_VIDEO_CONVERT_UNLOCK (self);
}
static GstCaps *
-gst_play_sink_video_convert_getcaps (GstPad * pad)
+gst_play_sink_video_convert_getcaps (GstPad * pad, GstCaps * filter)
{
GstPlaySinkVideoConvert *self =
GST_PLAY_SINK_VIDEO_CONVERT (gst_pad_get_parent (pad));
peer = gst_pad_get_peer (otherpad);
if (peer) {
- ret = gst_pad_get_caps_reffed (peer);
+ ret = gst_pad_get_caps (peer, filter);
gst_object_unref (peer);
} else {
- ret = gst_caps_new_any ();
+ ret = (filter ? gst_caps_ref (filter) : gst_caps_new_any ());
}
gst_object_unref (otherpad);
static void gst_selector_pad_reset (GstSelectorPad * pad);
static gboolean gst_selector_pad_event (GstPad * pad, GstEvent * event);
-static GstCaps *gst_selector_pad_getcaps (GstPad * pad);
+static GstCaps *gst_selector_pad_getcaps (GstPad * pad, GstCaps * filter);
static GstFlowReturn gst_selector_pad_chain (GstPad * pad, GstBuffer * buf);
-static GstFlowReturn gst_selector_pad_bufferalloc (GstPad * pad,
- guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
enum
{
case GST_EVENT_FLUSH_STOP:
gst_selector_pad_reset (selpad);
break;
- case GST_EVENT_NEWSEGMENT:
+ case GST_EVENT_SEGMENT:
{
- gboolean update;
- GstFormat format;
- gdouble rate, arate;
- gint64 start, stop, time;
-
- gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
- &start, &stop, &time);
-
- GST_DEBUG_OBJECT (selpad,
- "configured NEWSEGMENT update %d, rate %lf, applied rate %lf, "
- "format %d, "
- "%" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %"
- G_GINT64_FORMAT, update, rate, arate, format, start, stop, time);
-
- gst_segment_set_newsegment_full (&selpad->segment, update,
- rate, arate, format, start, stop, time);
+ gst_event_copy_segment (event, &selpad->segment);
+
+ GST_DEBUG_OBJECT (selpad, "configured SEGMENT %" GST_SEGMENT_FORMAT,
+ &selpad->segment);
/* if we are not going to forward the segment, mark the segment as
* pending */
if (!forward)
}
static GstCaps *
-gst_selector_pad_getcaps (GstPad * pad)
+gst_selector_pad_getcaps (GstPad * pad, GstCaps * filter)
{
GstStreamSelector *sel;
GstCaps *caps;
sel = GST_STREAM_SELECTOR (gst_pad_get_parent (pad));
GST_DEBUG_OBJECT (sel, "Getting caps of srcpad peer");
- caps = gst_pad_peer_get_caps (sel->srcpad);
+ caps = gst_pad_peer_get_caps (sel->srcpad, filter);
if (caps == NULL)
- caps = gst_caps_new_any ();
+ caps = (filter ? gst_caps_ref (filter) : gst_caps_new_any ());
gst_object_unref (sel);
}
static GstFlowReturn
-gst_selector_pad_bufferalloc (GstPad * pad, guint64 offset,
- guint size, GstCaps * caps, GstBuffer ** buf)
-{
- GstStreamSelector *sel;
- GstFlowReturn result;
- GstPad *active_sinkpad;
-
- sel = GST_STREAM_SELECTOR (gst_pad_get_parent (pad));
-
- active_sinkpad = gst_stream_selector_activate_sinkpad (sel, pad);
-
- /* Fallback allocation for buffers from pads except the selected one */
- if (pad != active_sinkpad) {
- GST_DEBUG_OBJECT (sel,
- "Pad %s:%s is not selected. Performing fallback allocation",
- GST_DEBUG_PAD_NAME (pad));
-
- *buf = NULL;
- result = GST_FLOW_OK;
- } else {
- result = gst_pad_alloc_buffer (sel->srcpad, offset, size, caps, buf);
-
- /* FIXME: HACK. If buffer alloc returns not-linked, perform a fallback
- * allocation. This should NOT be necessary, because playbin should
- * properly block the source pad from running until it's finished hooking
- * everything up, but playbin needs refactoring first. */
- if (result == GST_FLOW_NOT_LINKED) {
- GST_DEBUG_OBJECT (sel,
- "No peer pad yet - performing fallback allocation for pad %s:%s",
- GST_DEBUG_PAD_NAME (pad));
-
- *buf = NULL;
- result = GST_FLOW_OK;
- }
- }
-
- gst_object_unref (sel);
-
- return result;
-}
-
-static GstFlowReturn
gst_selector_pad_chain (GstPad * pad, GstBuffer * buf)
{
GstStreamSelector *sel;
if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
GST_DEBUG_OBJECT (sel, "received timestamp %" GST_TIME_FORMAT,
GST_TIME_ARGS (timestamp));
- gst_segment_set_last_stop (seg, seg->format, timestamp);
+ seg->position = timestamp;
}
/* Ignore buffers from pads except the selected one */
/* if we have a pending segment, push it out now */
if (selpad->segment_pending) {
- gst_pad_push_event (sel->srcpad, gst_event_new_new_segment_full (FALSE,
- seg->rate, seg->applied_rate, seg->format, seg->start, seg->stop,
- seg->time));
-
+ gst_pad_push_event (sel->srcpad, gst_event_new_segment (seg));
selpad->segment_pending = FALSE;
}
guint prop_id, GValue * value, GParamSpec * pspec);
static GstPad *gst_stream_selector_request_new_pad (GstElement * element,
- GstPadTemplate * templ, const gchar * unused);
+ GstPadTemplate * templ, const gchar * unused, const GstCaps * caps);
static void gst_stream_selector_release_pad (GstElement * element,
GstPad * pad);
static GstIterator *gst_stream_selector_pad_iterate_linked_pads (GstPad * pad);
-static GstCaps *gst_stream_selector_getcaps (GstPad * pad);
+static GstCaps *gst_stream_selector_getcaps (GstPad * pad, GstCaps * filter);
static GstElementClass *parent_class = NULL;
}
static GstCaps *
-gst_stream_selector_getcaps (GstPad * pad)
+gst_stream_selector_getcaps (GstPad * pad, GstCaps * filter)
{
GstPad *otherpad;
GstObject *parent;
if (!otherpad) {
GST_DEBUG_OBJECT (parent,
"Pad %s:%s not linked, returning ANY", GST_DEBUG_PAD_NAME (pad));
- caps = gst_caps_new_any ();
+ caps = (filter ? gst_caps_ref (filter) : gst_caps_new_any ());
} else {
GST_DEBUG_OBJECT (parent,
"Pad %s:%s is linked (to %s:%s), returning peer caps",
GST_DEBUG_PAD_NAME (pad), GST_DEBUG_PAD_NAME (otherpad));
/* if the peer has caps, use those. If the pad is not linked, this function
* returns NULL and we return ANY */
- if (!(caps = gst_pad_peer_get_caps (otherpad)))
- caps = gst_caps_new_any ();
+ if (!(caps = gst_pad_peer_get_caps (otherpad, filter)))
+ caps = (filter ? gst_caps_ref (filter) : gst_caps_new_any ());
gst_object_unref (otherpad);
}
gst_stream_selector_pad_iterate_linked_pads (GstPad * pad)
{
GstStreamSelector *sel = GST_STREAM_SELECTOR (gst_pad_get_parent (pad));
+ GValue value = { 0, };
GstPad *otherpad;
- GstIterator *ret;
+ GstIterator *ret = NULL;
otherpad = gst_stream_selector_get_linked_pad (pad, TRUE);
- ret =
- gst_iterator_new_single (GST_TYPE_PAD, otherpad,
- (GstCopyFunction) gst_object_ref, (GFreeFunc) gst_object_unref);
-
- if (otherpad)
+ if (otherpad) {
+ g_value_init (&value, GST_TYPE_PAD);
+ g_value_set_object (&value, otherpad);
+ ret = gst_iterator_new_single (GST_TYPE_PAD, &value);
+ g_value_unset (&value);
gst_object_unref (otherpad);
+ }
gst_object_unref (sel);
return ret;
static GstPad *
gst_stream_selector_request_new_pad (GstElement * element,
- GstPadTemplate * templ, const gchar * unused)
+ GstPadTemplate * templ, const gchar * unused, const GstCaps * caps)
{
GstStreamSelector *sel;
gchar *name = NULL;
GST_DEBUG_FUNCPTR (gst_selector_pad_chain));
gst_pad_set_iterate_internal_links_function (sinkpad,
GST_DEBUG_FUNCPTR (gst_stream_selector_pad_iterate_linked_pads));
- gst_pad_set_bufferalloc_function (sinkpad,
- GST_DEBUG_FUNCPTR (gst_selector_pad_bufferalloc));
gst_pad_set_active (sinkpad, TRUE);
gst_element_add_pad (GST_ELEMENT (sel), sinkpad);
static const gboolean passthrough = TRUE;
-GST_BOILERPLATE (GstStreamSynchronizer, gst_stream_synchronizer,
- GstElement, GST_TYPE_ELEMENT);
+#define gst_stream_synchronizer_parent_class parent_class
+G_DEFINE_TYPE (GstStreamSynchronizer, gst_stream_synchronizer,
+ GST_TYPE_ELEMENT);
typedef struct
{
opad = gst_stream_get_other_pad_from_pad (pad);
if (opad) {
- it = gst_iterator_new_single (GST_TYPE_PAD, opad,
- (GstCopyFunction) gst_object_ref, (GFreeFunc) gst_object_unref);
+ GValue value = { 0, };
+
+ g_value_init (&value, GST_TYPE_PAD);
+ g_value_set_object (&value, opad);
+ it = gst_iterator_new_single (GST_TYPE_PAD, &value);
+ g_value_unset (&value);
gst_object_unref (opad);
}
}
static GstCaps *
-gst_stream_synchronizer_getcaps (GstPad * pad)
+gst_stream_synchronizer_getcaps (GstPad * pad, GstCaps * filter)
{
GstPad *opad;
GstCaps *ret = NULL;
opad = gst_stream_get_other_pad_from_pad (pad);
if (opad) {
- ret = gst_pad_peer_get_caps (opad);
+ ret = gst_pad_peer_get_caps (opad, filter);
gst_object_unref (opad);
}
if (ret == NULL)
- ret = gst_caps_new_any ();
+ ret = (filter ? gst_caps_ref (filter) : gst_caps_new_any ());
GST_LOG_OBJECT (pad, "Returning caps: %" GST_PTR_FORMAT, ret);
goto skip_adjustments;
GST_LOG_OBJECT (pad, "Handling event %s: %" GST_PTR_FORMAT,
- GST_EVENT_TYPE_NAME (event), event->structure);
+ GST_EVENT_TYPE_NAME (event), event);
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_QOS:{
gint64 running_time_diff;
GstStream *stream;
- gst_event_parse_qos (event, &proportion, &diff, ×tamp);
+ gst_event_parse_qos (event, NULL, &proportion, &diff, ×tamp);
gst_event_unref (event);
GST_STREAM_SYNCHRONIZER_LOCK (self);
goto out;
}
- event = gst_event_new_qos (proportion, diff, timestamp);
+ event =
+ gst_event_new_qos (GST_QOS_TYPE_UNDERFLOW, proportion, diff,
+ timestamp);
break;
}
default:
goto skip_adjustments;
GST_LOG_OBJECT (pad, "Handling event %s: %" GST_PTR_FORMAT,
- GST_EVENT_TYPE_NAME (event), event->structure);
+ GST_EVENT_TYPE_NAME (event), event);
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_SINK_MESSAGE:{
GstMessage *message;
gst_event_parse_sink_message (event, &message);
- if (message->structure
- && gst_structure_has_name (message->structure,
- "playbin2-stream-changed")) {
+ if (gst_message_has_name (message, "playbin2-stream-changed")) {
GstStream *stream;
GST_STREAM_SYNCHRONIZER_LOCK (self);
break;
}
if (all_wait) {
- gint64 last_stop = 0;
+ gint64 position = 0;
GST_DEBUG_OBJECT (self, "All streams have changed -- unblocking");
for (l = self->streams; l; l = l->next) {
GstStream *ostream = l->data;
gint64 stop_running_time;
- gint64 last_stop_running_time;
+ gint64 position_running_time;
ostream->wait = FALSE;
stop_running_time =
gst_segment_to_running_time (&ostream->segment,
GST_FORMAT_TIME, ostream->segment.stop);
- last_stop_running_time =
+ position_running_time =
gst_segment_to_running_time (&ostream->segment,
- GST_FORMAT_TIME, ostream->segment.last_stop);
- last_stop =
- MAX (last_stop, MAX (stop_running_time,
- last_stop_running_time));
+ GST_FORMAT_TIME, ostream->segment.position);
+ position =
+ MAX (position, MAX (stop_running_time,
+ position_running_time));
}
- last_stop = MAX (0, last_stop);
- self->group_start_time = MAX (self->group_start_time, last_stop);
+ position = MAX (0, position);
+ self->group_start_time = MAX (self->group_start_time, position);
GST_DEBUG_OBJECT (self, "New group start time: %" GST_TIME_FORMAT,
GST_TIME_ARGS (self->group_start_time));
gst_message_unref (message);
break;
}
- case GST_EVENT_NEWSEGMENT:{
+ case GST_EVENT_SEGMENT:{
GstStream *stream;
- gboolean update;
- gdouble rate, applied_rate;
- GstFormat format;
- gint64 start, stop, position;
+ GstSegment segment;
- gst_event_parse_new_segment_full (event,
- &update, &rate, &applied_rate, &format, &start, &stop, &position);
+ gst_event_copy_segment (event, &segment);
GST_STREAM_SYNCHRONIZER_LOCK (self);
stream = gst_pad_get_element_private (pad);
goto done;
}
- if (stream && format == GST_FORMAT_TIME) {
+ if (stream && segment.format == GST_FORMAT_TIME) {
if (stream->new_stream) {
- gint64 last_stop_running_time = 0;
+ gint64 position_running_time = 0;
gint64 stop_running_time = 0;
if (stream->segment.format == GST_FORMAT_TIME) {
- last_stop_running_time =
+ position_running_time =
gst_segment_to_running_time (&stream->segment, GST_FORMAT_TIME,
- stream->segment.last_stop);
- last_stop_running_time = MAX (last_stop_running_time, 0);
+ stream->segment.position);
+ position_running_time = MAX (position_running_time, 0);
stop_running_time =
gst_segment_to_running_time (&stream->segment, GST_FORMAT_TIME,
stream->segment.stop);
- stop_running_time = MAX (last_stop_running_time, 0);
+ stop_running_time = MAX (position_running_time, 0);
- if (stop_running_time != last_stop_running_time) {
+ if (stop_running_time != position_running_time) {
GST_WARNING_OBJECT (pad,
- "Gap between last_stop and segment stop: %" GST_TIME_FORMAT
+ "Gap between position and segment stop: %" GST_TIME_FORMAT
" != %" GST_TIME_FORMAT, GST_TIME_ARGS (stop_running_time),
- GST_TIME_ARGS (last_stop_running_time));
+ GST_TIME_ARGS (position_running_time));
}
- if (stop_running_time < last_stop_running_time) {
+ if (stop_running_time < position_running_time) {
GST_DEBUG_OBJECT (pad, "Updating stop position");
+ stream->segment.stop = stream->segment.position;
gst_pad_push_event (stream->srcpad,
- gst_event_new_new_segment_full (TRUE, stream->segment.rate,
- stream->segment.applied_rate, GST_FORMAT_TIME,
- stream->segment.start, stream->segment.last_stop,
- stream->segment.time));
- gst_segment_set_newsegment_full (&stream->segment, TRUE,
- stream->segment.rate, stream->segment.applied_rate,
- GST_FORMAT_TIME, stream->segment.start,
- stream->segment.last_stop, stream->segment.time);
+ gst_event_new_segment (&stream->segment));
}
- stop_running_time = MAX (stop_running_time, last_stop_running_time);
+ stop_running_time = MAX (stop_running_time, position_running_time);
GST_DEBUG_OBJECT (pad,
"Stop running time of last group: %" GST_TIME_FORMAT,
GST_TIME_ARGS (stop_running_time));
GST_DEBUG_OBJECT (pad,
"Advancing running time for other streams by: %"
GST_TIME_FORMAT, GST_TIME_ARGS (diff));
- gst_pad_push_event (stream->srcpad,
- gst_event_new_new_segment_full (FALSE, 1.0, 1.0,
- GST_FORMAT_TIME, 0, diff, 0));
- gst_segment_set_newsegment_full (&stream->segment, FALSE, 1.0, 1.0,
- GST_FORMAT_TIME, 0, diff, 0);
+
+ segment.base += diff;
}
}
GST_DEBUG_OBJECT (pad, "Segment was: %" GST_SEGMENT_FORMAT,
&stream->segment);
- gst_segment_set_newsegment_full (&stream->segment, update, rate,
- applied_rate, format, start, stop, position);
+ gst_segment_copy_into (&segment, &stream->segment);
GST_DEBUG_OBJECT (pad, "Segment now is: %" GST_SEGMENT_FORMAT,
&stream->segment);
GST_DEBUG_OBJECT (pad, "Stream start running time: %" GST_TIME_FORMAT,
- GST_TIME_ARGS (stream->segment.accum));
- stream->running_time_diff = stream->segment.accum;
+ GST_TIME_ARGS (stream->segment.base));
+ stream->running_time_diff = stream->segment.base;
} else if (stream) {
GST_WARNING_OBJECT (pad, "Non-TIME segment: %s",
- gst_format_get_name (format));
+ gst_format_get_name (segment.format));
gst_segment_init (&stream->segment, GST_FORMAT_UNDEFINED);
}
GST_STREAM_SYNCHRONIZER_UNLOCK (self);
}
static GstFlowReturn
-gst_stream_synchronizer_sink_bufferalloc (GstPad * pad, guint64 offset,
- guint size, GstCaps * caps, GstBuffer ** buf)
-{
- GstPad *opad;
- GstFlowReturn ret = GST_FLOW_ERROR;
-
- GST_LOG_OBJECT (pad, "Allocating buffer: size=%u", size);
-
- opad = gst_stream_get_other_pad_from_pad (pad);
- if (opad) {
- ret = gst_pad_alloc_buffer (opad, offset, size, caps, buf);
- gst_object_unref (opad);
- }
-
- GST_LOG_OBJECT (pad, "Allocation: %s", gst_flow_get_name (ret));
-
- return ret;
-}
-
-static GstFlowReturn
gst_stream_synchronizer_sink_chain (GstPad * pad, GstBuffer * buffer)
{
GstStreamSynchronizer *self =
GST_LOG_OBJECT (pad, "Handling buffer %p: size=%u, timestamp=%"
GST_TIME_FORMAT " duration=%" GST_TIME_FORMAT
" offset=%" G_GUINT64_FORMAT " offset_end=%" G_GUINT64_FORMAT,
- buffer, GST_BUFFER_SIZE (buffer),
+ buffer, gst_buffer_get_size (buffer),
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)),
GST_BUFFER_OFFSET (buffer), GST_BUFFER_OFFSET_END (buffer));
stream->seen_data = TRUE;
if (stream && stream->drop_discont) {
- buffer = gst_buffer_make_metadata_writable (buffer);
+ buffer = gst_buffer_make_writable (buffer);
GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DISCONT);
stream->drop_discont = FALSE;
}
&& GST_CLOCK_TIME_IS_VALID (timestamp)) {
GST_LOG_OBJECT (pad,
"Updating last-stop from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
- GST_TIME_ARGS (stream->segment.last_stop), GST_TIME_ARGS (timestamp));
- gst_segment_set_last_stop (&stream->segment, GST_FORMAT_TIME, timestamp);
+ GST_TIME_ARGS (stream->segment.position), GST_TIME_ARGS (timestamp));
+ stream->segment.position = timestamp;
}
GST_STREAM_SYNCHRONIZER_UNLOCK (self);
&& GST_CLOCK_TIME_IS_VALID (timestamp_end)) {
GST_LOG_OBJECT (pad,
"Updating last-stop from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
- GST_TIME_ARGS (stream->segment.last_stop),
+ GST_TIME_ARGS (stream->segment.position),
GST_TIME_ARGS (timestamp_end));
- gst_segment_set_last_stop (&stream->segment, GST_FORMAT_TIME,
- timestamp_end);
+ stream->segment.position = timestamp_end;
}
/* Advance EOS streams if necessary. For non-EOS
* streams the demuxers should already do this! */
for (l = self->streams; l; l = l->next) {
GstStream *ostream = l->data;
- gint64 last_stop;
+ gint64 position;
if (!ostream->is_eos || ostream->segment.format != GST_FORMAT_TIME)
continue;
- if (ostream->segment.last_stop != -1)
- last_stop = ostream->segment.last_stop;
+ if (ostream->segment.position != -1)
+ position = ostream->segment.position;
else
- last_stop = ostream->segment.start;
+ position = ostream->segment.start;
/* Is there a 1 second lag? */
- if (last_stop != -1 && last_stop + GST_SECOND < timestamp_end) {
+ if (position != -1 && position + GST_SECOND < timestamp_end) {
gint64 new_start, new_stop;
new_start = timestamp_end - GST_SECOND;
GST_DEBUG_OBJECT (ostream->sinkpad,
"Advancing stream %u from %" GST_TIME_FORMAT " to %"
- GST_TIME_FORMAT, ostream->stream_number, GST_TIME_ARGS (last_stop),
+ GST_TIME_FORMAT, ostream->stream_number, GST_TIME_ARGS (position),
GST_TIME_ARGS (new_start));
+ ostream->segment.start = new_start;
+ ostream->segment.stop = new_stop;
+ ostream->segment.time = new_start;
+ ostream->segment.position = new_start;
+
gst_pad_push_event (ostream->srcpad,
- gst_event_new_new_segment_full (TRUE, ostream->segment.rate,
- ostream->segment.applied_rate, ostream->segment.format,
- new_start, new_stop, new_start));
- gst_segment_set_newsegment_full (&ostream->segment, TRUE,
- ostream->segment.rate, ostream->segment.applied_rate,
- ostream->segment.format, new_start, new_stop, new_start);
- gst_segment_set_last_stop (&ostream->segment, GST_FORMAT_TIME,
- new_start);
+ gst_event_new_segment (&ostream->segment));
}
}
GST_STREAM_SYNCHRONIZER_UNLOCK (self);
/* GstElement vfuncs */
static GstPad *
gst_stream_synchronizer_request_new_pad (GstElement * element,
- GstPadTemplate * temp, const gchar * name)
+ GstPadTemplate * temp, const gchar * name, const GstCaps * caps)
{
GstStreamSynchronizer *self = GST_STREAM_SYNCHRONIZER (element);
GstStream *stream;
GST_DEBUG_FUNCPTR (gst_stream_synchronizer_sink_event));
gst_pad_set_chain_function (stream->sinkpad,
GST_DEBUG_FUNCPTR (gst_stream_synchronizer_sink_chain));
- gst_pad_set_bufferalloc_function (stream->sinkpad,
- GST_DEBUG_FUNCPTR (gst_stream_synchronizer_sink_bufferalloc));
tmp = g_strdup_printf ("src_%d", self->current_stream_number);
stream->srcpad = gst_pad_new_from_static_template (&srctemplate, tmp);
if (stream->segment.format == GST_FORMAT_TIME) {
gint64 stop_running_time;
- gint64 last_stop_running_time;
+ gint64 position_running_time;
stop_running_time =
gst_segment_to_running_time (&stream->segment, GST_FORMAT_TIME,
stream->segment.stop);
- last_stop_running_time =
+ position_running_time =
gst_segment_to_running_time (&stream->segment, GST_FORMAT_TIME,
- stream->segment.last_stop);
- stop_running_time = MAX (stop_running_time, last_stop_running_time);
+ stream->segment.position);
+ stop_running_time = MAX (stop_running_time, position_running_time);
GST_DEBUG_OBJECT (stream->sinkpad,
"Stop running time was: %" GST_TIME_FORMAT,
/* GObject type initialization */
static void
-gst_stream_synchronizer_init (GstStreamSynchronizer * self,
- GstStreamSynchronizerClass * klass)
+gst_stream_synchronizer_init (GstStreamSynchronizer * self)
{
self->lock = g_mutex_new ();
self->stream_finish_cond = g_cond_new ();
}
static void
-gst_stream_synchronizer_base_init (gpointer g_class)
-{
- GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&srctemplate));
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&sinktemplate));
-
- gst_element_class_set_details_simple (gstelement_class,
- "Stream Synchronizer", "Generic",
- "Synchronizes a group of streams to have equal durations and starting points",
- "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
-}
-
-static void
gst_stream_synchronizer_class_init (GstStreamSynchronizerClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
gobject_class->finalize = gst_stream_synchronizer_finalize;
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&srctemplate));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&sinktemplate));
+
+ gst_element_class_set_details_simple (element_class,
+ "Stream Synchronizer", "Generic",
+ "Synchronizes a group of streams to have equal durations and starting points",
+ "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+
element_class->change_state =
GST_DEBUG_FUNCPTR (gst_stream_synchronizer_change_state);
element_class->request_new_pad =
PROP_SUBTITLE_ENCODING
};
-GST_BOILERPLATE (GstSubtitleOverlay, gst_subtitle_overlay, GstBin,
- GST_TYPE_BIN);
+#define gst_subtitle_overlay_parent_class parent_class
+G_DEFINE_TYPE (GstSubtitleOverlay, gst_subtitle_overlay, GST_TYPE_BIN);
static void _pad_blocked_cb (GstPad * pad, gboolean blocked,
gpointer user_data);
gst_message_new_async_start (GST_OBJECT_CAST (self), FALSE);
GST_DEBUG_OBJECT (self, "Posting async-start");
- parent_class->handle_message (GST_BIN_CAST (self), msg);
+ GST_BIN_CLASS (parent_class)->handle_message (GST_BIN_CAST (self), msg);
self->do_async = TRUE;
}
}
GstMessage *msg = gst_message_new_async_done (GST_OBJECT_CAST (self));
GST_DEBUG_OBJECT (self, "Posting async-done");
- parent_class->handle_message (GST_BIN_CAST (self), msg);
+ GST_BIN_CLASS (parent_class)->handle_message (GST_BIN_CAST (self), msg);
self->do_async = FALSE;
}
}
}
static void
-_generate_update_newsegment_event (GstSegment * segment, GstEvent ** event1,
- GstEvent ** event2)
+_generate_update_segment_event (GstSegment * segment, GstEvent ** event1)
{
GstEvent *event;
+ GstStructure *structure;
- *event1 = NULL;
- *event2 = NULL;
-
- event = gst_event_new_new_segment_full (FALSE, segment->rate,
- segment->applied_rate, segment->format, 0, segment->accum, 0);
- gst_structure_id_set (event->structure, _subtitle_overlay_event_marker_id,
+ event = gst_event_new_segment (segment);
+ structure = gst_event_writable_structure (event);
+ gst_structure_id_set (structure, _subtitle_overlay_event_marker_id,
G_TYPE_BOOLEAN, TRUE, NULL);
*event1 = event;
-
- event = gst_event_new_new_segment_full (FALSE, segment->rate,
- segment->applied_rate, segment->format,
- segment->start, segment->stop, segment->time);
- gst_structure_id_set (event->structure, _subtitle_overlay_event_marker_id,
- G_TYPE_BOOLEAN, TRUE, NULL);
- *event2 = event;
}
static gboolean
/* Send segment to the identity. This is dropped because identity
* is not linked downstream yet */
if (self->video_segment.format != GST_FORMAT_UNDEFINED) {
- GstEvent *event1, *event2;
+ GstEvent *event1;
- _generate_update_newsegment_event (&self->video_segment, &event1, &event2);
+ _generate_update_segment_event (&self->video_segment, &event1);
GST_DEBUG_OBJECT (self,
- "Pushing video accumulate newsegment event: %" GST_PTR_FORMAT,
- event1->structure);
- GST_DEBUG_OBJECT (self,
- "Pushing video update newsegment event: %" GST_PTR_FORMAT,
- event2->structure);
+ "Pushing video segment event: %" GST_PTR_FORMAT, event1);
gst_pad_send_event (sink, event1);
- gst_pad_send_event (sink, event2);
}
/* Link sink ghostpads to identity */
if (peer) {
subcaps = gst_pad_get_negotiated_caps (peer);
if (!subcaps) {
- subcaps = gst_pad_get_caps_reffed (peer);
+ subcaps = gst_pad_get_caps (peer, NULL);
if (!gst_caps_is_fixed (subcaps)) {
gst_caps_unref (subcaps);
subcaps = NULL;
video_caps = gst_pad_get_negotiated_caps (video_peer);
if (!video_caps) {
- video_caps = gst_pad_get_caps_reffed (video_peer);
+ video_caps = gst_pad_get_caps (video_peer, NULL);
if (!gst_caps_is_fixed (video_caps)) {
gst_caps_unref (video_caps);
video_caps = NULL;
/* Send segments to the parser/overlay if necessary. These are not sent
* outside this element because of the proxy pad event function */
if (self->video_segment.format != GST_FORMAT_UNDEFINED) {
- GstEvent *event1, *event2;
+ GstEvent *event1;
sink = gst_element_get_static_pad (self->pre_colorspace, "sink");
if (G_UNLIKELY (!sink)) {
continue;
}
- _generate_update_newsegment_event (&self->video_segment, &event1,
- &event2);
- GST_DEBUG_OBJECT (self,
- "Pushing video accumulate newsegment event: %" GST_PTR_FORMAT,
- event1->structure);
+ _generate_update_segment_event (&self->video_segment, &event1);
GST_DEBUG_OBJECT (self,
- "Pushing video update newsegment event: %" GST_PTR_FORMAT,
- event2->structure);
+ "Pushing video segment event: %" GST_PTR_FORMAT, event1);
gst_pad_send_event (sink, event1);
- gst_pad_send_event (sink, event2);
gst_object_unref (sink);
}
if (self->subtitle_segment.format != GST_FORMAT_UNDEFINED) {
- GstEvent *event1, *event2;
+ GstEvent *event1;
sink = gst_element_get_static_pad (element, "sink");
if (G_UNLIKELY (!sink)) {
continue;
}
- _generate_update_newsegment_event (&self->subtitle_segment, &event1,
- &event2);
- GST_DEBUG_OBJECT (self,
- "Pushing subtitle accumulate newsegment event: %" GST_PTR_FORMAT,
- event1->structure);
+ _generate_update_segment_event (&self->subtitle_segment, &event1);
GST_DEBUG_OBJECT (self,
- "Pushing subtitle update newsegment event: %" GST_PTR_FORMAT,
- event2->structure);
+ "Pushing subtitle segment event: %" GST_PTR_FORMAT, event1);
gst_pad_send_event (sink, event1);
- gst_pad_send_event (sink, event2);
gst_object_unref (sink);
}
/* Send segments to the renderer if necessary. These are not sent
* outside this element because of the proxy pad event handler */
if (self->video_segment.format != GST_FORMAT_UNDEFINED) {
- GstEvent *event1, *event2;
+ GstEvent *event1;
sink = gst_element_get_static_pad (self->pre_colorspace, "sink");
if (G_UNLIKELY (!sink)) {
continue;
}
- _generate_update_newsegment_event (&self->video_segment, &event1,
- &event2);
+ _generate_update_segment_event (&self->video_segment, &event1);
GST_DEBUG_OBJECT (self,
- "Pushing video accumulate newsegment event: %" GST_PTR_FORMAT,
- event1->structure);
- GST_DEBUG_OBJECT (self,
- "Pushing video update newsegment event: %" GST_PTR_FORMAT,
- event2->structure);
+ "Pushing video segment event: %" GST_PTR_FORMAT, event1);
gst_pad_send_event (sink, event1);
- gst_pad_send_event (sink, event2);
gst_object_unref (sink);
}
if (self->subtitle_segment.format != GST_FORMAT_UNDEFINED) {
- GstEvent *event1, *event2;
+ GstEvent *event1;
sink = _get_sub_pad (element);
if (G_UNLIKELY (!sink)) {
continue;
}
- _generate_update_newsegment_event (&self->subtitle_segment, &event1,
- &event2);
- GST_DEBUG_OBJECT (self,
- "Pushing subtitle accumulate newsegment event: %" GST_PTR_FORMAT,
- event1->structure);
+ _generate_update_segment_event (&self->subtitle_segment, &event1);
GST_DEBUG_OBJECT (self,
- "Pushing subtitle update newsegment event: %" GST_PTR_FORMAT,
- event2->structure);
+ "Pushing subtitle segment event: %" GST_PTR_FORMAT, event1);
gst_pad_send_event (sink, event1);
- gst_pad_send_event (sink, event2);
gst_object_unref (sink);
}
}
static void
-gst_subtitle_overlay_base_init (gpointer g_class)
-{
- GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&srctemplate));
-
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&video_sinktemplate));
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&subtitle_sinktemplate));
-
- gst_element_class_set_details_simple (gstelement_class, "Subtitle Overlay",
- "Video/Overlay/Subtitle",
- "Overlays a video stream with subtitles",
- "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
-}
-
-static void
gst_subtitle_overlay_class_init (GstSubtitleOverlayClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
"ISO-8859-15 will be assumed.", NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&srctemplate));
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&video_sinktemplate));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&subtitle_sinktemplate));
+
+ gst_element_class_set_details_simple (element_class, "Subtitle Overlay",
+ "Video/Overlay/Subtitle",
+ "Overlays a video stream with subtitles",
+ "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+
element_class->change_state =
GST_DEBUG_FUNCPTR (gst_subtitle_overlay_change_state);
s = gst_event_get_structure (event);
if (s && gst_structure_id_has_field (s, _subtitle_overlay_event_marker_id)) {
GST_DEBUG_OBJECT (ghostpad, "Dropping event with marker: %" GST_PTR_FORMAT,
- event->structure);
+ event);
gst_event_unref (event);
event = NULL;
ret = TRUE;
ret = gst_proxy_pad_event_default (pad, gst_event_ref (event));
- if (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT) {
- gboolean update;
- gdouble rate, applied_rate;
- GstFormat format;
- gint64 start, stop, position;
+ if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) {
- GST_DEBUG_OBJECT (pad, "Newsegment event: %" GST_PTR_FORMAT,
- event->structure);
- gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
- &format, &start, &stop, &position);
+ GST_DEBUG_OBJECT (pad, "segment event: %" GST_PTR_FORMAT, event);
+ gst_event_copy_segment (event, &self->video_segment);
- if (format != GST_FORMAT_TIME) {
+ if (self->video_segment.format != GST_FORMAT_TIME) {
GST_ERROR_OBJECT (pad, "Newsegment event in non-time format: %s",
- gst_format_get_name (format));
+ gst_format_get_name (self->video_segment.format));
gst_object_unref (event);
gst_object_unref (self);
return FALSE;
}
-
- GST_DEBUG_OBJECT (pad, "Old video segment: %" GST_SEGMENT_FORMAT,
- &self->video_segment);
- gst_segment_set_newsegment_full (&self->video_segment, update, rate,
- applied_rate, format, start, stop, position);
- GST_DEBUG_OBJECT (pad, "New video segment: %" GST_SEGMENT_FORMAT,
- &self->video_segment);
}
gst_event_unref (event);
}
static GstCaps *
-gst_subtitle_overlay_subtitle_sink_getcaps (GstPad * pad)
+gst_subtitle_overlay_subtitle_sink_getcaps (GstPad * pad, GstCaps * filter)
{
GstSubtitleOverlay *self = GST_SUBTITLE_OVERLAY (gst_pad_get_parent (pad));
GstCaps *ret;
g_mutex_lock (self->factories_lock);
if (G_UNLIKELY (!gst_subtitle_overlay_update_factory_list (self)))
ret = GST_CAPS_NONE;
+ else if (filter)
+ ret =
+ gst_caps_intersect_full (filter, self->factory_caps,
+ GST_CAPS_INTERSECT_FIRST);
else
ret = gst_caps_ref (self->factory_caps);
g_mutex_unlock (self->factories_lock);
static gboolean
gst_subtitle_overlay_subtitle_sink_acceptcaps (GstPad * pad, GstCaps * caps)
{
- GstCaps *othercaps = gst_subtitle_overlay_subtitle_sink_getcaps (pad);
+ GstCaps *othercaps = gst_subtitle_overlay_subtitle_sink_getcaps (pad, NULL);
gboolean ret = gst_caps_can_intersect (caps, othercaps);
gst_caps_unref (othercaps);
caps = gst_pad_get_negotiated_caps (peer);
if (!caps) {
- caps = gst_pad_get_caps_reffed (peer);
+ caps = gst_pad_get_caps (peer, NULL);
if (!gst_caps_is_fixed (caps)) {
gst_caps_unref (caps);
caps = NULL;
{
GstSubtitleOverlay *self = GST_SUBTITLE_OVERLAY (gst_pad_get_parent (pad));
gboolean ret;
- GstFormat format;
if (GST_EVENT_TYPE (event) == GST_EVENT_CUSTOM_DOWNSTREAM_OOB &&
- event->structure
- && strcmp (gst_structure_get_name (event->structure),
- "subtitleoverlay-flush-subtitle") == 0) {
+ gst_event_has_name (event, "subtitleoverlay-flush-subtitle")) {
GST_DEBUG_OBJECT (pad, "Custom subtitle flush event");
GST_SUBTITLE_OVERLAY_LOCK (self);
self->subtitle_flush = TRUE;
event = NULL;
ret = TRUE;
goto out;
- } else if (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT) {
- gst_event_parse_new_segment_full (event, NULL, NULL, NULL,
- &format, NULL, NULL, NULL);
- if (self->subtitle_segment.format != GST_FORMAT_UNDEFINED &&
- self->subtitle_segment.format != format) {
- GST_DEBUG_OBJECT (pad, "Subtitle segment format changed: %s -> %s",
- gst_format_get_name (self->subtitle_segment.format),
- gst_format_get_name (format));
- gst_segment_init (&self->subtitle_segment, GST_FORMAT_UNDEFINED);
- }
}
switch (GST_EVENT_TYPE (event)) {
gst_segment_init (&self->subtitle_segment, GST_FORMAT_UNDEFINED);
/* fall through */
case GST_EVENT_FLUSH_START:
- case GST_EVENT_NEWSEGMENT:
+ case GST_EVENT_SEGMENT:
case GST_EVENT_EOS:
+ {
+ GstStructure *structure;
+
/* Add our event marker to make sure no events from here go ever outside
* the element, they're only interesting for our internal elements */
- event =
- GST_EVENT_CAST (gst_mini_object_make_writable (GST_MINI_OBJECT_CAST
- (event)));
- if (!event->structure) {
- event->structure =
- gst_structure_id_empty_new (_subtitle_overlay_event_marker_id);
- gst_structure_set_parent_refcount (event->structure,
- &event->mini_object.refcount);
- }
- gst_structure_id_set (event->structure, _subtitle_overlay_event_marker_id,
+ event = GST_EVENT_CAST (gst_event_make_writable (event));
+ structure = gst_event_writable_structure (event);
+
+ gst_structure_id_set (structure, _subtitle_overlay_event_marker_id,
G_TYPE_BOOLEAN, TRUE, NULL);
break;
+ }
default:
break;
}
ret = gst_proxy_pad_event_default (pad, gst_event_ref (event));
- if (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT) {
- gboolean update;
- gdouble rate, applied_rate;
- gint64 start, stop, position;
-
- GST_DEBUG_OBJECT (pad, "Newsegment event: %" GST_PTR_FORMAT,
- event->structure);
- gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
- &format, &start, &stop, &position);
-
- GST_DEBUG_OBJECT (pad, "Old subtitle segment: %" GST_SEGMENT_FORMAT,
- &self->subtitle_segment);
- if (self->subtitle_segment.format != format) {
- GST_DEBUG_OBJECT (pad, "Subtitle segment format changed: %s -> %s",
- gst_format_get_name (self->subtitle_segment.format),
- gst_format_get_name (format));
- gst_segment_init (&self->subtitle_segment, format);
- }
-
- gst_segment_set_newsegment_full (&self->subtitle_segment, update, rate,
- applied_rate, format, start, stop, position);
+ if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) {
+ GST_DEBUG_OBJECT (pad, "segment event: %" GST_PTR_FORMAT, event);
+ gst_event_copy_segment (event, &self->subtitle_segment);
GST_DEBUG_OBJECT (pad, "New subtitle segment: %" GST_SEGMENT_FORMAT,
&self->subtitle_segment);
}
}
static void
-gst_subtitle_overlay_init (GstSubtitleOverlay * self,
- GstSubtitleOverlayClass * klass)
+gst_subtitle_overlay_init (GstSubtitleOverlay * self)
{
GstPadTemplate *templ;
GstPad *proxypad = NULL;
GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
(self->video_sinkpad)));
self->video_block_pad = proxypad;
+
gst_element_add_pad (GST_ELEMENT_CAST (self), self->video_sinkpad);
templ = gst_static_pad_template_get (&subtitle_sinktemplate);
GST_DEBUG_FUNCPTR (gst_subtitle_overlay_subtitle_sink_getcaps));
gst_pad_set_acceptcaps_function (self->subtitle_sinkpad,
GST_DEBUG_FUNCPTR (gst_subtitle_overlay_subtitle_sink_acceptcaps));
- gst_pad_set_bufferalloc_function (self->subtitle_sinkpad, NULL);
proxypad =
GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD
static guint gst_uri_decode_bin_signals[LAST_SIGNAL] = { 0 };
GType gst_uri_decode_bin_get_type (void);
-GST_BOILERPLATE (GstURIDecodeBin, gst_uri_decode_bin, GstBin, GST_TYPE_BIN);
+#define gst_uri_decode_bin_parent_class parent_class
+G_DEFINE_TYPE (GstURIDecodeBin, gst_uri_decode_bin, GST_TYPE_BIN);
static void remove_decoders (GstURIDecodeBin * bin, gboolean force);
static void gst_uri_decode_bin_set_property (GObject * object, guint prop_id,
static GstStateChangeReturn gst_uri_decode_bin_change_state (GstElement *
element, GstStateChange transition);
-static void
-gst_uri_decode_bin_base_init (gpointer g_class)
-{
- GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&srctemplate));
- gst_element_class_set_details_simple (gstelement_class,
- "URI Decoder", "Generic/Bin/Decoder",
- "Autoplug and decode an URI to raw media",
- "Wim Taymans <wim.taymans@gmail.com>");
-}
-
static gboolean
_gst_boolean_accumulator (GSignalInvocationHint * ihint,
GValue * return_accu, const GValue * handler_return, gpointer dummy)
G_SIGNAL_RUN_LAST, 0, NULL, NULL,
gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&srctemplate));
+ gst_element_class_set_details_simple (gstelement_class,
+ "URI Decoder", "Generic/Bin/Decoder",
+ "Autoplug and decode an URI to raw media",
+ "Wim Taymans <wim.taymans@gmail.com>");
+
gstelement_class->query = GST_DEBUG_FUNCPTR (gst_uri_decode_bin_query);
gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_uri_decode_bin_change_state);
}
static void
-gst_uri_decode_bin_init (GstURIDecodeBin * dec, GstURIDecodeBinClass * klass)
+gst_uri_decode_bin_init (GstURIDecodeBin * dec)
{
/* first filter out the interesting element factories */
dec->factories_lock = g_mutex_new ();
dbin->async_pending = TRUE;
message = gst_message_new_async_start (GST_OBJECT_CAST (dbin), FALSE);
- parent_class->handle_message (GST_BIN_CAST (dbin), message);
+ GST_BIN_CLASS (parent_class)->handle_message (GST_BIN_CAST (dbin), message);
}
static void
if (dbin->async_pending) {
GST_DEBUG_OBJECT (dbin, "posting ASYNC_DONE");
message = gst_message_new_async_done (GST_OBJECT_CAST (dbin));
- parent_class->handle_message (GST_BIN_CAST (dbin), message);
+ GST_BIN_CLASS (parent_class)->handle_message (GST_BIN_CAST (dbin), message);
dbin->async_pending = FALSE;
}
gint capssize;
gboolean res = FALSE;
- caps = gst_pad_get_caps_reffed (pad);
+ caps = gst_pad_get_caps (pad, NULL);
if (caps == NULL)
return FALSE;
gboolean res = TRUE;
GstCaps *rawcaps;
GstPad *pad;
+ GValue item = { 0, };
*have_out = FALSE;
*is_raw = FALSE;
pads_iter = gst_element_iterate_src_pads (decoder->source);
while (!done) {
- switch (gst_iterator_next (pads_iter, (gpointer) & pad)) {
+ switch (gst_iterator_next (pads_iter, &item)) {
case GST_ITERATOR_ERROR:
res = FALSE;
/* FALLTROUGH */
gst_iterator_resync (pads_iter);
break;
case GST_ITERATOR_OK:
+ pad = g_value_get_object (&item);
/* we now officially have an ouput pad */
*have_out = TRUE;
/* if FALSE, this pad has no caps and we continue with the next pad. */
if (!has_all_raw_caps (pad, rawcaps, is_raw)) {
- gst_object_unref (pad);
+ g_value_reset (&item);
break;
}
}
expose_decoded_pad (outelem, pad, decoder);
}
- gst_object_unref (pad);
+ g_value_reset (&item);
break;
}
}
+ g_value_unset (&item);
gst_iterator_free (pads_iter);
gst_caps_unref (rawcaps);
{
post_missing_plugin_error (GST_ELEMENT_CAST (decoder), "queue2");
- gst_object_unref (pad);
+ g_value_unset (&item);
gst_iterator_free (pads_iter);
gst_caps_unref (rawcaps);
GList *l_good = NULL, *l_neutral = NULL, *l_bad = NULL;
GValue new_list = { 0, };
guint size, i;
+ const GstStructure *structure;
GST_DEBUG_OBJECT (dec, "redirect message: %" GST_PTR_FORMAT, msg);
GST_DEBUG_OBJECT (dec, "connection speed: %u", dec->connection_speed);
- if (dec->connection_speed == 0 || msg->structure == NULL)
+ structure = gst_message_get_structure (msg);
+ if (dec->connection_speed == 0 || structure == NULL)
return msg;
- locations_list = gst_structure_get_value (msg->structure, "locations");
+ locations_list = gst_structure_get_value (structure, "locations");
if (locations_list == NULL)
return msg;
static void
handle_message (GstBin * bin, GstMessage * msg)
{
- if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ELEMENT && msg->structure != NULL
- && gst_structure_has_name (msg->structure, "redirect")) {
+ if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ELEMENT
+ && gst_message_has_name (msg, "redirect")) {
/* sort redirect messages based on the connection speed. This simplifies
* the user of this element as it can in most cases just pick the first item
* of the sorted list as a good redirection candidate. It can of course
}
static gboolean
-decoder_query_duration_fold (GstPad * item, GValue * ret, QueryFold * fold)
+decoder_query_duration_fold (const GValue * item, GValue * ret,
+ QueryFold * fold)
{
- if (gst_pad_query (item, fold->query)) {
+ GstPad *pad = g_value_get_object (item);
+
+ if (gst_pad_query (pad, fold->query)) {
gint64 duration;
g_value_set_boolean (ret, TRUE);
if (duration > fold->max)
fold->max = duration;
}
- gst_object_unref (item);
return TRUE;
}
}
static gboolean
-decoder_query_position_fold (GstPad * item, GValue * ret, QueryFold * fold)
+decoder_query_position_fold (const GValue * item, GValue * ret,
+ QueryFold * fold)
{
- if (gst_pad_query (item, fold->query)) {
+ GstPad *pad = g_value_get_object (item);
+
+ if (gst_pad_query (pad, fold->query)) {
gint64 position;
g_value_set_boolean (ret, TRUE);
fold->max = position;
}
- gst_object_unref (item);
return TRUE;
}
}
static gboolean
-decoder_query_latency_fold (GstPad * item, GValue * ret, QueryFold * fold)
+decoder_query_latency_fold (const GValue * item, GValue * ret, QueryFold * fold)
{
- if (gst_pad_query (item, fold->query)) {
+ GstPad *pad = g_value_get_object (item);
+
+ if (gst_pad_query (pad, fold->query)) {
GstClockTime min, max;
gboolean live;
fold->live = live;
}
- gst_object_unref (item);
return TRUE;
}
/* we are seekable if all srcpads are seekable */
static gboolean
-decoder_query_seeking_fold (GstPad * item, GValue * ret, QueryFold * fold)
+decoder_query_seeking_fold (const GValue * item, GValue * ret, QueryFold * fold)
{
- if (gst_pad_query (item, fold->query)) {
+ GstPad *pad = g_value_get_object (item);
+
+ if (gst_pad_query (pad, fold->query)) {
gboolean seekable;
g_value_set_boolean (ret, TRUE);
if (fold->seekable == TRUE)
fold->seekable = seekable;
}
- gst_object_unref (item);
return TRUE;
}
/* generic fold, return first valid result */
static gboolean
-decoder_query_generic_fold (GstPad * item, GValue * ret, QueryFold * fold)
+decoder_query_generic_fold (const GValue * item, GValue * ret, QueryFold * fold)
{
+ GstPad *pad = g_value_get_object (item);
gboolean res;
- if ((res = gst_pad_query (item, fold->query))) {
+ if ((res = gst_pad_query (pad, fold->query))) {
g_value_set_boolean (ret, TRUE);
GST_DEBUG_OBJECT (item, "answered query %p", fold->query);
}
- gst_object_unref (item);
-
/* and stop as soon as we have a valid result */
return !res;
}
GST_STATIC_CAPS ("text/x-pango-markup")
);
-GST_BOILERPLATE (GstSsaParse, gst_ssa_parse, GstElement, GST_TYPE_ELEMENT);
+#define gst_ssa_parse_parent_class parent_class
+G_DEFINE_TYPE (GstSsaParse, gst_ssa_parse, GST_TYPE_ELEMENT);
static GstStateChangeReturn gst_ssa_parse_change_state (GstElement *
element, GstStateChange transition);
static GstFlowReturn gst_ssa_parse_chain (GstPad * sinkpad, GstBuffer * buf);
static void
-gst_ssa_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_templ));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&src_templ));
- gst_element_class_set_details_simple (element_class,
- "SSA Subtitle Parser", "Codec/Parser/Subtitle",
- "Parses SSA subtitle streams",
- "Tim-Philipp Müller <tim centricular net>");
-
- GST_DEBUG_CATEGORY_INIT (ssa_parse_debug, "ssaparse", 0,
- "SSA subtitle parser");
-}
-
-static void
gst_ssa_parse_dispose (GObject * object)
{
GstSsaParse *parse = GST_SSA_PARSE (object);
}
static void
-gst_ssa_parse_init (GstSsaParse * parse, GstSsaParseClass * klass)
+gst_ssa_parse_init (GstSsaParse * parse)
{
parse->sinkpad = gst_pad_new_from_static_template (&sink_templ, "sink");
gst_pad_set_setcaps_function (parse->sinkpad,
object_class->dispose = gst_ssa_parse_dispose;
+ 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,
+ "SSA Subtitle Parser", "Codec/Parser/Subtitle",
+ "Parses SSA subtitle streams",
+ "Tim-Philipp Müller <tim centricular net>");
+
+ GST_DEBUG_CATEGORY_INIT (ssa_parse_debug, "ssaparse", 0,
+ "SSA subtitle parser");
+
element_class->change_state = GST_DEBUG_FUNCPTR (gst_ssa_parse_change_state);
}
GstStructure *s;
const guchar bom_utf8[] = { 0xEF, 0xBB, 0xBF };
GstBuffer *priv;
- gchar *data;
- guint size;
+ gchar *data, *ptr;
+ gsize size, left;
s = gst_caps_get_structure (caps, 0);
val = gst_structure_get_value (s, "codec_data");
parse->framed = TRUE;
parse->send_tags = TRUE;
- priv = (GstBuffer *) gst_value_get_mini_object (val);
+ priv = (GstBuffer *) g_value_get_boxed (val);
g_return_val_if_fail (priv != NULL, FALSE);
gst_buffer_ref (priv);
- data = (gchar *) GST_BUFFER_DATA (priv);
- size = GST_BUFFER_SIZE (priv);
+ data = gst_buffer_map (priv, &size, NULL, GST_MAP_READ);
+
+ ptr = data;
+ left = size;
+
/* skip UTF-8 BOM */
- if (size >= 3 && memcmp (data, bom_utf8, 3) == 0) {
- data += 3;
- size -= 3;
+ if (left >= 3 && memcmp (ptr, bom_utf8, 3) == 0) {
+ ptr += 3;
+ left -= 3;
}
if (!strstr (data, "[Script Info]")) {
return FALSE;
}
- if (!g_utf8_validate (data, size, NULL)) {
+ if (!g_utf8_validate (ptr, left, NULL)) {
GST_WARNING_OBJECT (parse, "Init section is not valid UTF-8");
gst_buffer_unref (priv);
return FALSE;
}
/* FIXME: parse initial section */
- parse->ini = g_strndup (data, size);
+ parse->ini = g_strndup (ptr, left);
GST_LOG_OBJECT (parse, "Init section:\n%s", parse->ini);
+ gst_buffer_unmap (priv, data, size);
gst_buffer_unref (priv);
return TRUE;
/* allocate enough for a terminating NUL, but don't include it in buf size */
buf = gst_buffer_new_and_alloc (len + 1);
- memcpy (GST_BUFFER_DATA (buf), escaped, len + 1);
- GST_BUFFER_SIZE (buf) = len;
+ gst_buffer_fill (buf, 0, escaped, len + 1);
+ gst_buffer_set_size (buf, len);
g_free (escaped);
GST_BUFFER_TIMESTAMP (buf) = start;
GST_BUFFER_DURATION (buf) = duration;
- gst_buffer_set_caps (buf, GST_PAD_CAPS (parse->srcpad));
-
GST_LOG_OBJECT (parse, "Pushing buffer with timestamp %" GST_TIME_FORMAT
" and duration %" GST_TIME_FORMAT, GST_TIME_ARGS (start),
GST_TIME_ARGS (duration));
GstSsaParse *parse = GST_SSA_PARSE (GST_PAD_PARENT (sinkpad));
GstClockTime ts;
gchar *txt;
+ gchar *data;
+ gsize size;
if (G_UNLIKELY (!parse->framed))
goto not_framed;
}
/* make double-sure it's 0-terminated and all */
- txt = g_strndup ((gchar *) GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
+ data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
+ txt = g_strndup (data, size);
+ gst_buffer_unmap (buf, data, size);
+
if (txt == NULL)
goto empty_text;
ret = gst_ssa_parse_push_line (parse, txt, ts, GST_BUFFER_DURATION (buf));
if (ret != GST_FLOW_OK && GST_CLOCK_TIME_IS_VALID (ts)) {
+ GstSegment segment;
+
/* just advance time without sending anything */
- gst_pad_push_event (parse->srcpad,
- gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, ts, -1, ts));
+ gst_segment_init (&segment, GST_FORMAT_TIME);
+ segment.start = ts;
+ segment.time = ts;
+ gst_pad_push_event (parse->srcpad, gst_event_new_segment (&segment));
ret = GST_FLOW_OK;
}
break;
}
- ret = parent_class->change_state (element, transition);
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
if (ret == GST_STATE_CHANGE_FAILURE)
return ret;
GST_STATIC_CAPS ("text/plain; text/x-pango-markup")
);
-static void gst_sub_parse_base_init (GstSubParseClass * klass);
-static void gst_sub_parse_class_init (GstSubParseClass * klass);
-static void gst_sub_parse_init (GstSubParse * subparse);
static gboolean gst_sub_parse_src_event (GstPad * pad, GstEvent * event);
static gboolean gst_sub_parse_src_query (GstPad * pad, GstQuery * query);
static GstFlowReturn gst_sub_parse_chain (GstPad * sinkpad, GstBuffer * buf);
-static GstElementClass *parent_class = NULL;
-
-GType
-gst_sub_parse_get_type (void)
-{
- static GType sub_parse_type = 0;
-
- if (!sub_parse_type) {
- static const GTypeInfo sub_parse_info = {
- sizeof (GstSubParseClass),
- (GBaseInitFunc) gst_sub_parse_base_init,
- NULL,
- (GClassInitFunc) gst_sub_parse_class_init,
- NULL,
- NULL,
- sizeof (GstSubParse),
- 0,
- (GInstanceInitFunc) gst_sub_parse_init,
- };
-
- sub_parse_type = g_type_register_static (GST_TYPE_ELEMENT,
- "GstSubParse", &sub_parse_info, 0);
- }
-
- return sub_parse_type;
-}
-
-static void
-gst_sub_parse_base_init (GstSubParseClass * klass)
-{
- 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,
- "Subtitle parser", "Codec/Parser/Subtitle",
- "Parses subtitle (.sub) files into text streams",
- "Gustavo J. A. M. Carneiro <gjc@inescporto.pt>, "
- "GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>");
-}
+#define gst_sub_parse_parent_class parent_class
+G_DEFINE_TYPE (GstSubParse, gst_sub_parse, GST_TYPE_ELEMENT);
static void
gst_sub_parse_dispose (GObject * object)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
- parent_class = g_type_class_peek_parent (klass);
-
object_class->dispose = gst_sub_parse_dispose;
object_class->set_property = gst_sub_parse_set_property;
object_class->get_property = gst_sub_parse_get_property;
+ 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,
+ "Subtitle parser", "Codec/Parser/Subtitle",
+ "Parses subtitle (.sub) files into text streams",
+ "Gustavo J. A. M. Carneiro <gjc@inescporto.pt>, "
+ "GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>");
+
element_class->change_state = gst_sub_parse_change_state;
g_object_class_install_property (object_class, PROP_ENCODING,
ret = gst_pad_peer_query (self->sinkpad, query);
} else {
ret = TRUE;
- gst_query_set_position (query, GST_FORMAT_TIME,
- self->segment.last_stop);
+ gst_query_set_position (query, GST_FORMAT_TIME, self->segment.position);
}
}
case GST_QUERY_SEEKING:
case GST_EVENT_SEEK:
{
GstFormat format;
+ GstSeekFlags flags;
GstSeekType start_type, stop_type;
gint64 start, stop;
gdouble rate;
gboolean update;
- gst_event_parse_seek (event, &rate, &format, &self->segment_flags,
+ gst_event_parse_seek (event, &rate, &format, &flags,
&start_type, &start, &stop_type, &stop);
if (format != GST_FORMAT_TIME) {
/* Convert that seek to a seeking in bytes at position 0,
FIXME: could use an index */
ret = gst_pad_push_event (self->sinkpad,
- gst_event_new_seek (rate, GST_FORMAT_BYTES, self->segment_flags,
+ gst_event_new_seek (rate, GST_FORMAT_BYTES, flags,
GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, 0));
if (ret) {
/* Apply the seek to our segment */
- gst_segment_set_seek (&self->segment, rate, format, self->segment_flags,
+ gst_segment_do_seek (&self->segment, rate, format, flags,
start_type, start, stop_type, stop, &update);
GST_DEBUG_OBJECT (self, "segment after seek: %" GST_SEGMENT_FORMAT,
const gchar *line_split;
gchar *line_chunk;
guint start_frame, end_frame;
- gint64 clip_start = 0, clip_stop = 0;
+ guint64 clip_start = 0, clip_stop = 0;
gboolean in_seg = FALSE;
GString *markup;
gchar *ret;
case 2:
{
/* No need to parse that text if it's out of segment */
- gint64 clip_start = 0, clip_stop = 0;
+ guint64 clip_start = 0, clip_stop = 0;
gboolean in_seg = FALSE;
/* Check our segment start/stop */
case 1:
{
/* No need to parse that text if it's out of segment */
- gint64 clip_start = 0, clip_stop = 0;
+ guint64 clip_start = 0, clip_stop = 0;
gboolean in_seg = FALSE;
/* Check our segment start/stop */
return NULL;
case 1:
{ /* No need to parse that text if it's out of segment */
- gint64 clip_start = 0, clip_stop = 0;
+ guint64 clip_start = 0, clip_stop = 0;
gboolean in_seg = FALSE;
/* Check our segment start/stop */
return NULL;
case 1:
{
- gint64 clip_start = 0, clip_stop = 0;
+ guint64 clip_start = 0, clip_stop = 0;
gboolean in_seg;
gchar *ret;
gboolean discont;
gsize consumed;
gchar *input = NULL;
+ const guint8 *data;
+ gsize avail;
discont = GST_BUFFER_IS_DISCONT (buf);
* subtitles which are discontinuous by nature. */
}
- self->offset = GST_BUFFER_OFFSET (buf) + GST_BUFFER_SIZE (buf);
+ self->offset = GST_BUFFER_OFFSET (buf) + gst_buffer_get_size (buf);
self->next_offset = self->offset;
gst_adapter_push (self->adapter, buf);
- input =
- convert_encoding (self, (const gchar *) gst_adapter_peek (self->adapter,
- gst_adapter_available (self->adapter)),
- (gsize) gst_adapter_available (self->adapter), &consumed);
+ avail = gst_adapter_available (self->adapter);
+ data = gst_adapter_map (self->adapter, avail),
+ input = convert_encoding (self, (const gchar *) data, avail, &consumed);
if (input && consumed > 0) {
self->textbuf = g_string_append (self->textbuf, input);
- gst_adapter_flush (self->adapter, consumed);
+ gst_adapter_unmap (self->adapter, consumed);
+ } else {
+ gst_adapter_unmap (self->adapter, 0);
}
g_free (input);
{
GstFlowReturn ret = GST_FLOW_OK;
GstCaps *caps = NULL;
- gchar *line, *subtitle;
+ gchar *line, *subtitle, *data;
+ gsize size;
if (self->first_buffer) {
- self->detected_encoding =
- detect_encoding ((gchar *) GST_BUFFER_DATA (buf),
- GST_BUFFER_SIZE (buf));
+ data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
+ self->detected_encoding = detect_encoding (data, size);
+ gst_buffer_unmap (buf, data, size);
self->first_buffer = FALSE;
self->state.fps_n = self->fps_n;
self->state.fps_d = self->fps_d;
guint subtitle_len = strlen (subtitle);
/* +1 for terminating NUL character */
- ret = gst_pad_alloc_buffer_and_set_caps (self->srcpad,
- GST_BUFFER_OFFSET_NONE, subtitle_len + 1,
- GST_PAD_CAPS (self->srcpad), &buf);
-
- if (ret == GST_FLOW_OK) {
- /* copy terminating NUL character as well */
- memcpy (GST_BUFFER_DATA (buf), subtitle, subtitle_len + 1);
- GST_BUFFER_SIZE (buf) = subtitle_len;
- GST_BUFFER_TIMESTAMP (buf) = self->state.start_time;
- GST_BUFFER_DURATION (buf) = self->state.duration;
-
- /* in some cases (e.g. tmplayer) we can only determine the duration
- * of a text chunk from the timestamp of the next text chunk; in those
- * cases, we probably want to limit the duration to something
- * reasonable, so we don't end up showing some text for e.g. 40 seconds
- * just because nothing else is being said during that time */
- if (self->state.max_duration > 0 && GST_BUFFER_DURATION_IS_VALID (buf)) {
- if (GST_BUFFER_DURATION (buf) > self->state.max_duration)
- GST_BUFFER_DURATION (buf) = self->state.max_duration;
- }
+ buf = gst_buffer_new_and_alloc (subtitle_len + 1);
+
+ /* copy terminating NUL character as well */
+ gst_buffer_fill (buf, 0, subtitle, subtitle_len + 1);
+ gst_buffer_set_size (buf, subtitle_len);
+
+ GST_BUFFER_TIMESTAMP (buf) = self->state.start_time;
+ GST_BUFFER_DURATION (buf) = self->state.duration;
+
+ /* in some cases (e.g. tmplayer) we can only determine the duration
+ * of a text chunk from the timestamp of the next text chunk; in those
+ * cases, we probably want to limit the duration to something
+ * reasonable, so we don't end up showing some text for e.g. 40 seconds
+ * just because nothing else is being said during that time */
+ if (self->state.max_duration > 0 && GST_BUFFER_DURATION_IS_VALID (buf)) {
+ if (GST_BUFFER_DURATION (buf) > self->state.max_duration)
+ GST_BUFFER_DURATION (buf) = self->state.max_duration;
+ }
- gst_segment_set_last_stop (&self->segment, GST_FORMAT_TIME,
- self->state.start_time);
+ self->segment.position = self->state.start_time;
- GST_DEBUG_OBJECT (self, "Sending text '%s', %" GST_TIME_FORMAT " + %"
- GST_TIME_FORMAT, subtitle, GST_TIME_ARGS (self->state.start_time),
- GST_TIME_ARGS (self->state.duration));
+ GST_DEBUG_OBJECT (self, "Sending text '%s', %" GST_TIME_FORMAT " + %"
+ GST_TIME_FORMAT, subtitle, GST_TIME_ARGS (self->state.start_time),
+ GST_TIME_ARGS (self->state.duration));
- ret = gst_pad_push (self->srcpad, buf);
- }
+ ret = gst_pad_push (self->srcpad, buf);
/* move this forward (the tmplayer parser needs this) */
if (self->state.duration != GST_CLOCK_TIME_NONE)
GST_LOG_OBJECT (self, "pushing newsegment event with %" GST_SEGMENT_FORMAT,
&self->segment);
- gst_pad_push_event (self->srcpad, gst_event_new_new_segment (FALSE,
- self->segment.rate, self->segment.format,
- self->segment.last_stop, self->segment.stop, self->segment.time));
+ gst_pad_push_event (self->srcpad, gst_event_new_segment (&self->segment));
self->need_segment = FALSE;
}
self->parser_type == GST_SUB_PARSE_FORMAT_TMPLAYER ||
self->parser_type == GST_SUB_PARSE_FORMAT_MPL2 ||
self->parser_type == GST_SUB_PARSE_FORMAT_QTTEXT) {
+ gchar term_chars[] = { '\n', '\n', '\0' };
GstBuffer *buf = gst_buffer_new_and_alloc (2 + 1);
GST_DEBUG ("EOS. Pushing remaining text (if any)");
- GST_BUFFER_DATA (buf)[0] = '\n';
- GST_BUFFER_DATA (buf)[1] = '\n';
- GST_BUFFER_DATA (buf)[2] = '\0'; /* play it safe */
- GST_BUFFER_SIZE (buf) = 2;
+ gst_buffer_fill (buf, 0, term_chars, 3);
+ gst_buffer_set_size (buf, 2);
+
GST_BUFFER_OFFSET (buf) = self->offset;
gst_sub_parse_chain (pad, buf);
}
ret = gst_pad_event_default (pad, event);
break;
}
- case GST_EVENT_NEWSEGMENT:
+ case GST_EVENT_SEGMENT:
{
- GstFormat format;
- gdouble rate;
- gint64 start, stop, time;
- gboolean update;
-
- gst_event_parse_new_segment (event, &update, &rate, &format, &start,
- &stop, &time);
-
- GST_DEBUG_OBJECT (self, "newsegment (%s)", gst_format_get_name (format));
-
- if (format == GST_FORMAT_TIME) {
- gst_segment_set_newsegment (&self->segment, update, rate, format,
- start, stop, time);
- } else {
- /* if not time format, we'll either start with a 0 timestamp anyway or
- * it's following a seek in which case we'll have saved the requested
- * seek segment and don't want to overwrite it (remember that on a seek
- * we always just seek back to the start in BYTES format and just throw
- * away all text that's before the requested position; if the subtitles
- * come from an upstream demuxer, it won't be able to handle our BYTES
- * seek request and instead send us a newsegment from the seek request
- * it received via its video pads instead, so all is fine then too) */
- }
-
+ gst_event_copy_segment (event, &self->segment);
+ GST_DEBUG_OBJECT (self, "newsegment (%s)",
+ gst_format_get_name (self->segment.format));
+
+ /* if not time format, we'll either start with a 0 timestamp anyway or
+ * it's following a seek in which case we'll have saved the requested
+ * seek segment and don't want to overwrite it (remember that on a seek
+ * we always just seek back to the start in BYTES format and just throw
+ * away all text that's before the requested position; if the subtitles
+ * come from an upstream demuxer, it won't be able to handle our BYTES
+ * seek request and instead send us a newsegment from the seek request
+ * it received via its video pads instead, so all is fine then too) */
ret = TRUE;
gst_event_unref (event);
break;
break;
}
- ret = parent_class->change_state (element, transition);
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
if (ret == GST_STATE_CHANGE_FAILURE)
return ret;
/* Segment */
GstSegment segment;
- GstSeekFlags segment_flags;
gboolean need_segment;
gboolean flushing;
/* this is really arbitrarily chosen */
-#define DEFAULT_PROTOCOL GST_TCP_PROTOCOL_NONE
#define DEFAULT_MODE 1
#define DEFAULT_BUFFERS_MAX -1
#define DEFAULT_BUFFERS_SOFT_MAX -1
enum
{
PROP_0,
- PROP_PROTOCOL,
PROP_MODE,
PROP_BUFFERS_QUEUED,
PROP_BYTES_QUEUED,
static void gst_multi_fd_sink_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
-GST_BOILERPLATE (GstMultiFdSink, gst_multi_fd_sink, GstBaseSink,
- GST_TYPE_BASE_SINK);
+#define gst_multi_fd_sink_parent_class parent_class
+G_DEFINE_TYPE (GstMultiFdSink, gst_multi_fd_sink, GST_TYPE_BASE_SINK);
static guint gst_multi_fd_sink_signals[LAST_SIGNAL] = { 0 };
static void
-gst_multi_fd_sink_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 (&sinktemplate));
-
- gst_element_class_set_details_simple (element_class,
- "Multi filedescriptor sink", "Sink/Network",
- "Send data to multiple filedescriptors",
- "Thomas Vander Stichele <thomas at apestaart dot org>, "
- "Wim Taymans <wim@fluendo.com>");
-}
-
-static void
gst_multi_fd_sink_class_init (GstMultiFdSinkClass * klass)
{
GObjectClass *gobject_class;
gobject_class->get_property = gst_multi_fd_sink_get_property;
gobject_class->finalize = gst_multi_fd_sink_finalize;
- g_object_class_install_property (gobject_class, PROP_PROTOCOL,
- g_param_spec_enum ("protocol", "Protocol", "The protocol to wrap data in"
- ". GDP protocol here is deprecated. Please use gdppay element.",
- GST_TYPE_TCP_PROTOCOL, DEFAULT_PROTOCOL,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
/**
* GstMultiFdSink::mode
*
client_fd_removed), NULL, NULL, gst_tcp_marshal_VOID__INT,
G_TYPE_NONE, 1, G_TYPE_INT);
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&sinktemplate));
+
+ gst_element_class_set_details_simple (gstelement_class,
+ "Multi filedescriptor sink", "Sink/Network",
+ "Send data to multiple filedescriptors",
+ "Thomas Vander Stichele <thomas at apestaart dot org>, "
+ "Wim Taymans <wim@fluendo.com>");
+
gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_multi_fd_sink_change_state);
}
static void
-gst_multi_fd_sink_init (GstMultiFdSink * this, GstMultiFdSinkClass * klass)
+gst_multi_fd_sink_init (GstMultiFdSink * this)
{
GST_OBJECT_FLAG_UNSET (this, GST_MULTI_FD_SINK_OPEN);
- this->protocol = DEFAULT_PROTOCOL;
this->mode = DEFAULT_MODE;
CLIENTS_LOCK_INIT (this);
}
}
-/* Queue raw data for this client, creating a new buffer.
- * This takes ownership of the data by
- * setting it as GST_BUFFER_MALLOCDATA() on the created buffer so
- * be sure to pass g_free()-able @data.
- */
-static gboolean
-gst_multi_fd_sink_client_queue_data (GstMultiFdSink * sink,
- GstTCPClient * client, gchar * data, gint len)
-{
- GstBuffer *buf;
-
- buf = gst_buffer_new ();
- GST_BUFFER_DATA (buf) = (guint8 *) data;
- GST_BUFFER_MALLOCDATA (buf) = (guint8 *) data;
- GST_BUFFER_SIZE (buf) = len;
-
- GST_LOG_OBJECT (sink, "[fd %5d] queueing data of length %d",
- client->fd.fd, len);
-
- client->sending = g_slist_append (client->sending, buf);
-
- return TRUE;
-}
-
-/* GDP-encode given caps and queue them for sending */
-static gboolean
-gst_multi_fd_sink_client_queue_caps (GstMultiFdSink * sink,
- GstTCPClient * client, const GstCaps * caps)
-{
- guint8 *header;
- guint8 *payload;
- guint length;
- gchar *string;
-
- g_return_val_if_fail (caps != NULL, FALSE);
-
- string = gst_caps_to_string (caps);
- GST_DEBUG_OBJECT (sink, "[fd %5d] Queueing caps %s through GDP",
- client->fd.fd, string);
- g_free (string);
-
- if (!gst_dp_packet_from_caps (caps, sink->header_flags, &length, &header,
- &payload)) {
- GST_DEBUG_OBJECT (sink, "Could not create GDP packet from caps");
- return FALSE;
- }
- gst_multi_fd_sink_client_queue_data (sink, client, (gchar *) header, length);
-
- length = gst_dp_header_payload_length (header);
- gst_multi_fd_sink_client_queue_data (sink, client, (gchar *) payload, length);
-
- return TRUE;
-}
-
static gboolean
is_sync_frame (GstMultiFdSink * sink, GstBuffer * buffer)
{
gboolean send_streamheader = FALSE;
GstStructure *s;
+#if 0
/* before we queue the buffer, we check if we need to queue streamheader
* buffers (because it's a new client, or because they changed) */
caps = gst_buffer_get_caps (buffer); /* cleaned up after streamheader */
+#else
+ caps = NULL;
+#endif
if (!client->caps) {
GST_DEBUG_OBJECT (sink,
"[fd %5d] no previous caps for this client, send streamheader",
buffer = g_value_peek_pointer (bufval);
GST_DEBUG_OBJECT (sink,
"[fd %5d] queueing streamheader buffer of length %d",
- client->fd.fd, GST_BUFFER_SIZE (buffer));
+ client->fd.fd, gst_buffer_get_size (buffer));
gst_buffer_ref (buffer);
- if (sink->protocol == GST_TCP_PROTOCOL_GDP) {
- guint8 *header;
- guint len;
-
- if (!gst_dp_header_from_buffer (buffer, sink->header_flags, &len,
- &header)) {
- GST_DEBUG_OBJECT (sink,
- "[fd %5d] could not create header, removing client",
- client->fd.fd);
- return FALSE;
- }
- gst_multi_fd_sink_client_queue_data (sink, client, (gchar *) header,
- len);
- }
-
client->sending = g_slist_append (client->sending, buffer);
}
}
gst_caps_unref (caps);
caps = NULL;
- /* now we can send the buffer, possibly sending a GDP header first */
- if (sink->protocol == GST_TCP_PROTOCOL_GDP) {
- guint8 *header;
- guint len;
-
- if (!gst_dp_header_from_buffer (buffer, sink->header_flags, &len, &header)) {
- GST_DEBUG_OBJECT (sink,
- "[fd %5d] could not create header, removing client", client->fd.fd);
- return FALSE;
- }
- gst_multi_fd_sink_client_queue_data (sink, client, (gchar *) header, len);
- }
GST_LOG_OBJECT (sink, "[fd %5d] queueing buffer of length %d",
- client->fd.fd, GST_BUFFER_SIZE (buffer));
+ client->fd.fd, gst_buffer_get_size (buffer));
gst_buffer_ref (buffer);
client->sending = g_slist_append (client->sending, buffer);
for (i = 0; i < len; i++) {
buf = g_array_index (sink->bufqueue, GstBuffer *, i);
- acc += GST_BUFFER_SIZE (buf);
+ acc += gst_buffer_get_size (buf);
if (acc > max)
return i + 1;
}
buf = g_array_index (sink->bufqueue, GstBuffer *, i);
- bytes += GST_BUFFER_SIZE (buf);
+ bytes += gst_buffer_get_size (buf);
/* take timestamp and save for the base first timestamp */
if ((time = GST_BUFFER_TIMESTAMP (buf)) != -1) {
{
int fd = client->fd.fd;
gboolean more;
- gboolean res;
gboolean flushing;
GstClockTime now;
GTimeVal nowtv;
flushing = client->status == GST_CLIENT_STATUS_FLUSHING;
- /* when using GDP, first check if we have queued caps yet */
- if (sink->protocol == GST_TCP_PROTOCOL_GDP) {
- /* don't need to do anything when the client is flushing */
- if (!client->caps_sent && !flushing) {
- GstPad *peer;
- GstCaps *caps;
-
- peer = gst_pad_get_peer (GST_BASE_SINK_PAD (sink));
- if (!peer) {
- GST_WARNING_OBJECT (sink, "pad has no peer");
- return FALSE;
- }
- gst_object_unref (peer);
-
- caps = gst_pad_get_negotiated_caps (GST_BASE_SINK_PAD (sink));
- if (!caps) {
- GST_WARNING_OBJECT (sink, "pad caps not yet negotiated");
- return FALSE;
- }
-
- /* queue caps for sending */
- res = gst_multi_fd_sink_client_queue_caps (sink, client, caps);
-
- gst_caps_unref (caps);
-
- if (!res) {
- GST_DEBUG_OBJECT (sink, "Failed queueing caps, removing client");
- return FALSE;
- }
- client->caps_sent = TRUE;
- }
- }
-
more = TRUE;
do {
gint maxsize;
if (client->sending) {
ssize_t wrote;
GstBuffer *head;
+ guint8 *data;
+ gsize size;
/* pick first buffer from list */
head = GST_BUFFER (client->sending->data);
- maxsize = GST_BUFFER_SIZE (head) - client->bufoffset;
+
+ data = gst_buffer_map (head, &size, NULL, GST_MAP_READ);
+ maxsize = size - client->bufoffset;
/* try to write the complete buffer */
#ifdef MSG_NOSIGNAL
#define FLAGS 0
#endif
if (client->is_socket) {
- wrote =
- send (fd, GST_BUFFER_DATA (head) + client->bufoffset, maxsize,
- FLAGS);
+ wrote = send (fd, data + client->bufoffset, maxsize, FLAGS);
} else {
- wrote = write (fd, GST_BUFFER_DATA (head) + client->bufoffset, maxsize);
+ wrote = write (fd, data + client->bufoffset, maxsize);
}
+ gst_buffer_unmap (head, data, size);
if (wrote < 0) {
/* hmm error.. */
{
GstMultiFdSink *sink;
gboolean in_caps;
+#if 0
GstCaps *bufcaps, *padcaps;
+#endif
sink = GST_MULTI_FD_SINK (bsink);
g_return_val_if_fail (GST_OBJECT_FLAG_IS_SET (sink, GST_MULTI_FD_SINK_OPEN),
GST_FLOW_WRONG_STATE);
+#if 0
/* since we check every buffer for streamheader caps, we need to make
* sure every buffer has caps set */
bufcaps = gst_buffer_get_caps (buf);
/* make sure we have caps on the pad */
if (!padcaps && !bufcaps)
goto no_caps;
+#endif
/* get IN_CAPS first, code below might mess with the flags */
in_caps = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
+#if 0
/* stamp the buffer with previous caps if no caps set */
if (!bufcaps) {
- if (!gst_buffer_is_metadata_writable (buf)) {
+ if (!gst_buffer_is_writable (buf)) {
/* metadata is not writable, copy will be made and original buffer
* will be unreffed so we need to ref so that we don't lose the
* buffer in the render method. */
gst_buffer_ref (buf);
/* the new buffer is ours only, we keep it out of the scope of this
* function */
- buf = gst_buffer_make_metadata_writable (buf);
+ buf = gst_buffer_make_writable (buf);
} else {
/* else the metadata is writable, we ref because we keep the buffer
* out of the scope of this method */
/* since we keep this buffer out of the scope of this method */
gst_buffer_ref (buf);
}
+#endif
GST_LOG_OBJECT (sink, "received buffer %p, in_caps: %s, offset %"
G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT
if (in_caps) {
GST_DEBUG_OBJECT (sink,
"appending IN_CAPS buffer with length %d to streamheader",
- GST_BUFFER_SIZE (buf));
+ gst_buffer_get_size (buf));
sink->streamheader = g_slist_append (sink->streamheader, buf);
} else {
/* queue the buffer, this is a regular data buffer. */
gst_multi_fd_sink_queue_buffer (sink, buf);
- sink->bytes_to_serve += GST_BUFFER_SIZE (buf);
+ sink->bytes_to_serve += gst_buffer_get_size (buf);
}
return GST_FLOW_OK;
/* ERRORS */
+#if 0
no_caps:
{
GST_ELEMENT_ERROR (sink, CORE, NEGOTIATION, (NULL),
("Received first buffer without caps set"));
return GST_FLOW_NOT_NEGOTIATED;
}
+#endif
}
static void
multifdsink = GST_MULTI_FD_SINK (object);
switch (prop_id) {
- case PROP_PROTOCOL:
- multifdsink->protocol = g_value_get_enum (value);
- break;
case PROP_MODE:
multifdsink->mode = g_value_get_enum (value);
break;
multifdsink = GST_MULTI_FD_SINK (object);
switch (prop_id) {
- case PROP_PROTOCOL:
- g_value_set_enum (value, multifdsink->protocol);
- break;
case PROP_MODE:
g_value_set_enum (value, multifdsink->mode);
break;
gboolean discont;
- GstTCPProtocol protocol;
-
gboolean caps_sent;
gboolean new_connection;
GSList *streamheader; /* GSList of GstBuffers to use as streamheader */
gboolean previous_buffer_in_caps;
- GstTCPProtocol protocol;
guint mtu;
gint qos_dscp;
gboolean handle_read;
int ret;
ssize_t bytes_read;
int readsize;
+ guint8 *data;
*buf = NULL;
*buf = gst_buffer_new_and_alloc (readsize);
- bytes_read = read (socket, GST_BUFFER_DATA (*buf), readsize);
+ data = gst_buffer_map (*buf, NULL, NULL, GST_MAP_WRITE);
+ bytes_read = read (socket, data, readsize);
+ gst_buffer_unmap (*buf, data, bytes_read);
if (bytes_read < 0)
goto read_error;
/* but mom, you promised to give me readsize bytes! */
goto short_read;
- GST_LOG_OBJECT (this, "returning buffer of size %d", GST_BUFFER_SIZE (*buf));
+ GST_LOG_OBJECT (this, "returning buffer of size %d", bytes_read);
return GST_FLOW_OK;
/* ERRORS */
{
GstFlowReturn ret;
guint8 *header = NULL;
+ guint8 *data;
+ gsize size;
GST_LOG_OBJECT (this, "Reading %d bytes for buffer packet header",
GST_DP_HEADER_LENGTH);
g_free (header);
- ret = gst_tcp_socket_read (this, socket, GST_BUFFER_DATA (*buf),
- GST_BUFFER_SIZE (*buf), fdset);
+ data = gst_buffer_map (*buf, &size, NULL, GST_MAP_WRITE);
+ ret = gst_tcp_socket_read (this, socket, data, size, fdset);
+ gst_buffer_unmap (*buf, data, size);
if (ret != GST_FLOW_OK)
goto data_read_error;
return GST_FLOW_ERROR;
}
}
-
-/* write a GDP header to the socket. Return false if fails. */
-gboolean
-gst_tcp_gdp_write_buffer (GstElement * this, int socket, GstBuffer * buffer,
- gboolean fatal, const gchar * host, int port)
-{
- guint length;
- guint8 *header;
- size_t wrote;
-
- if (!gst_dp_header_from_buffer (buffer, 0, &length, &header))
- goto create_error;
-
- GST_LOG_OBJECT (this, "writing %d bytes for GDP buffer header", length);
- wrote = gst_tcp_socket_write (socket, header, length);
- g_free (header);
-
- if (wrote != length)
- goto write_error;
-
- return TRUE;
-
- /* ERRORS */
-create_error:
- {
- if (fatal)
- GST_ELEMENT_ERROR (this, CORE, TOO_LAZY, (NULL),
- ("Could not create GDP header from buffer"));
- return FALSE;
- }
-write_error:
- {
- if (fatal)
- GST_ELEMENT_ERROR (this, RESOURCE, WRITE,
- (_("Error while sending data to \"%s:%d\"."), host, port),
- ("Only %" G_GSIZE_FORMAT " of %u bytes written: %s",
- wrote, GST_BUFFER_SIZE (buffer), g_strerror (errno)));
- return FALSE;
- }
-}
-
-/* write GDP header and payload to the given socket for the given caps.
- * Return false if fails. */
-gboolean
-gst_tcp_gdp_write_caps (GstElement * this, int socket, const GstCaps * caps,
- gboolean fatal, const char *host, int port)
-{
- guint length;
- guint8 *header;
- guint8 *payload;
- size_t wrote;
-
- if (!gst_dp_packet_from_caps (caps, 0, &length, &header, &payload))
- goto create_error;
-
- GST_LOG_OBJECT (this, "writing %d bytes for GDP caps header", length);
- wrote = gst_tcp_socket_write (socket, header, length);
- if (wrote != length)
- goto write_header_error;
-
- length = gst_dp_header_payload_length (header);
- g_free (header);
-
- GST_LOG_OBJECT (this, "writing %d bytes for GDP caps payload", length);
- wrote = gst_tcp_socket_write (socket, payload, length);
- g_free (payload);
-
- if (wrote != length)
- goto write_payload_error;
-
- return TRUE;
-
- /* ERRORS */
-create_error:
- {
- if (fatal)
- GST_ELEMENT_ERROR (this, CORE, TOO_LAZY, (NULL),
- ("Could not create GDP packet from caps"));
- return FALSE;
- }
-write_header_error:
- {
- g_free (header);
- g_free (payload);
- if (fatal)
- GST_ELEMENT_ERROR (this, RESOURCE, WRITE,
- (_("Error while sending gdp header data to \"%s:%d\"."), host, port),
- ("Only %" G_GSIZE_FORMAT " of %u bytes written: %s",
- wrote, length, g_strerror (errno)));
- return FALSE;
- }
-write_payload_error:
- {
- if (fatal)
- GST_ELEMENT_ERROR (this, RESOURCE, WRITE,
- (_("Error while sending gdp payload data to \"%s:%d\"."), host, port),
- ("Only %" G_GSIZE_FORMAT " of %u bytes written: %s",
- wrote, length, g_strerror (errno)));
- return FALSE;
- }
-}
G_BEGIN_DECLS
-/**
- * GstTCPProtocol:
- * @GST_TCP_PROTOCOL_NONE: Raw data transmission
- * @GST_TCP_PROTOCOL_GDP: #GstBuffers are wrapped and sent/received using the
- * GDP protocol.
- *
- * This enum is provided by the tcp/multifd elements to configure the format of
- * data transmission/reception.
- *
- * The GDP protocol wraps data buffers in a header that also carries format
- * information and timestamps. The None value indicates the data is
- * sent/received as-is. In that case, format information and timestamping
- * must be transmitted separately, or implicit in the bytestream itself.
- */
-typedef enum
-{
- GST_TCP_PROTOCOL_NONE,
- GST_TCP_PROTOCOL_GDP
-} GstTCPProtocol;
-
gchar * gst_tcp_host_to_ip (GstElement *element, const gchar *host);
gint gst_tcp_socket_write (int socket, const void *buf, size_t count);
GstFlowReturn gst_tcp_gdp_read_buffer (GstElement * this, int socket, GstPoll * fdset, GstBuffer **buf);
GstFlowReturn gst_tcp_gdp_read_caps (GstElement * this, int socket, GstPoll * fdset, GstCaps **caps);
-GstEvent * gst_tcp_gdp_read_event (GstElement *elem, int socket, GstPoll * fdset);
-
-gboolean gst_tcp_gdp_write_buffer (GstElement *elem, int socket, GstBuffer *buffer, gboolean fatal, const gchar *host, int port);
-gboolean gst_tcp_gdp_write_event (GstElement *elem, int socket, GstEvent *event, gboolean fatal, const gchar *host, int port);
-gboolean gst_tcp_gdp_write_caps (GstElement *elem, int socket, const GstCaps *caps, gboolean fatal, const gchar *host, int port);
-
G_END_DECLS
#endif /* __GST_TCP_HELP_H__ */
{
ARG_0,
ARG_HOST,
- ARG_PORT,
- ARG_PROTOCOL
- /* FILL ME */
+ ARG_PORT
};
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
-static void gst_tcp_client_sink_base_init (gpointer g_class);
-static void gst_tcp_client_sink_class_init (GstTCPClientSink * klass);
-static void gst_tcp_client_sink_init (GstTCPClientSink * tcpclientsink);
static void gst_tcp_client_sink_finalize (GObject * gobject);
static gboolean gst_tcp_client_sink_setcaps (GstBaseSink * bsink,
GValue * value, GParamSpec * pspec);
-static GstElementClass *parent_class = NULL;
-
/*static guint gst_tcp_client_sink_signals[LAST_SIGNAL] = { 0 }; */
-GType
-gst_tcp_client_sink_get_type (void)
-{
- static GType tcpclientsink_type = 0;
-
-
- if (!tcpclientsink_type) {
- static const GTypeInfo tcpclientsink_info = {
- sizeof (GstTCPClientSinkClass),
- gst_tcp_client_sink_base_init,
- NULL,
- (GClassInitFunc) gst_tcp_client_sink_class_init,
- NULL,
- NULL,
- sizeof (GstTCPClientSink),
- 0,
- (GInstanceInitFunc) gst_tcp_client_sink_init,
- NULL
- };
-
- tcpclientsink_type =
- g_type_register_static (GST_TYPE_BASE_SINK, "GstTCPClientSink",
- &tcpclientsink_info, 0);
- }
- return tcpclientsink_type;
-}
+#define gst_tcp_client_sink_parent_class parent_class
+G_DEFINE_TYPE (GstTCPClientSink, gst_tcp_client_sink, GST_TYPE_BASE_SINK);
static void
-gst_tcp_client_sink_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 (&sinktemplate));
-
- gst_element_class_set_details_simple (element_class,
- "TCP client sink", "Sink/Network",
- "Send data as a client over the network via TCP",
- "Thomas Vander Stichele <thomas at apestaart dot org>");
-}
-
-static void
-gst_tcp_client_sink_class_init (GstTCPClientSink * klass)
+gst_tcp_client_sink_class_init (GstTCPClientSinkClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
g_param_spec_int ("port", "Port", "The port to send the packets to",
0, TCP_HIGHEST_PORT, TCP_DEFAULT_PORT,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, ARG_PROTOCOL,
- g_param_spec_enum ("protocol", "Protocol", "The protocol to wrap data in",
- GST_TYPE_TCP_PROTOCOL, GST_TCP_PROTOCOL_NONE,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&sinktemplate));
+
+ gst_element_class_set_details_simple (gstelement_class,
+ "TCP client sink", "Sink/Network",
+ "Send data as a client over the network via TCP",
+ "Thomas Vander Stichele <thomas at apestaart dot org>");
gstelement_class->change_state = gst_tcp_client_sink_change_state;
this->port = TCP_DEFAULT_PORT;
this->sock_fd.fd = -1;
- this->protocol = GST_TCP_PROTOCOL_NONE;
GST_OBJECT_FLAG_UNSET (this, GST_TCP_CLIENT_SINK_OPEN);
}
sink = GST_TCP_CLIENT_SINK (bsink);
- /* write the buffer header if we have one */
- switch (sink->protocol) {
- case GST_TCP_PROTOCOL_NONE:
- break;
-
- case GST_TCP_PROTOCOL_GDP:
- /* if we haven't send caps yet, send them first */
- if (!sink->caps_sent) {
- const GstCaps *caps;
- gchar *string;
-
- caps = GST_PAD_CAPS (GST_PAD_PEER (GST_BASE_SINK_PAD (bsink)));
- string = gst_caps_to_string (caps);
- GST_DEBUG_OBJECT (sink, "Sending caps %s through GDP", string);
- g_free (string);
-
- if (!gst_tcp_gdp_write_caps (GST_ELEMENT (sink), sink->sock_fd.fd,
- caps, TRUE, sink->host, sink->port))
- goto gdp_write_error;
-
- sink->caps_sent = TRUE;
- }
- break;
- default:
- g_warning ("Unhandled protocol type");
- break;
- }
-
return TRUE;
-
- /* ERRORS */
-gdp_write_error:
- {
- return FALSE;
- }
}
static GstFlowReturn
{
size_t wrote = 0;
GstTCPClientSink *sink;
- gint size;
+ guint8 *data;
+ gsize size;
sink = GST_TCP_CLIENT_SINK (bsink);
g_return_val_if_fail (GST_OBJECT_FLAG_IS_SET (sink, GST_TCP_CLIENT_SINK_OPEN),
GST_FLOW_WRONG_STATE);
- size = GST_BUFFER_SIZE (buf);
-
- GST_LOG_OBJECT (sink, "writing %d bytes for buffer data", size);
-
- /* write the buffer header if we have one */
- switch (sink->protocol) {
- case GST_TCP_PROTOCOL_NONE:
- break;
- case GST_TCP_PROTOCOL_GDP:
- GST_LOG_OBJECT (sink, "Sending buffer header through GDP");
- if (!gst_tcp_gdp_write_buffer (GST_ELEMENT (sink), sink->sock_fd.fd, buf,
- TRUE, sink->host, sink->port))
- goto gdp_write_error;
- break;
- default:
- break;
- }
+ data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
+ GST_LOG_OBJECT (sink, "writing %" G_GSIZE_FORMAT " bytes for buffer data",
+ size);
/* write buffer data */
- wrote = gst_tcp_socket_write (sink->sock_fd.fd, GST_BUFFER_DATA (buf), size);
+ wrote = gst_tcp_socket_write (sink->sock_fd.fd, data, size);
+ gst_buffer_unmap (buf, data, size);
if (wrote < size)
goto write_error;
return GST_FLOW_OK;
/* ERRORS */
-gdp_write_error:
- {
- return FALSE;
- }
write_error:
{
GST_ELEMENT_ERROR (sink, RESOURCE, WRITE,
(_("Error while sending data to \"%s:%d\"."), sink->host, sink->port),
- ("Only %" G_GSIZE_FORMAT " of %u bytes written: %s",
- wrote, GST_BUFFER_SIZE (buf), g_strerror (errno)));
+ ("Only %" G_GSIZE_FORMAT " of %" G_GSIZE_FORMAT " bytes written: %s",
+ wrote, size, g_strerror (errno)));
return GST_FLOW_ERROR;
}
}
case ARG_PORT:
tcpclientsink->port = g_value_get_int (value);
break;
- case ARG_PROTOCOL:
- tcpclientsink->protocol = g_value_get_enum (value);
- break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
case ARG_PORT:
g_value_set_int (value, tcpclientsink->port);
break;
- case ARG_PROTOCOL:
- g_value_set_enum (value, tcpclientsink->protocol);
- break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
GstPollFD sock_fd;
size_t data_written; /* how much bytes have we written ? */
- GstTCPProtocol protocol; /* used with the protocol enum */
gboolean caps_sent; /* whether or not we sent caps already */
};
{
PROP_0,
PROP_HOST,
- PROP_PORT,
- PROP_PROTOCOL
+ PROP_PORT
};
-
-GST_BOILERPLATE (GstTCPClientSrc, gst_tcp_client_src, GstPushSrc,
- GST_TYPE_PUSH_SRC);
+#define gst_tcp_client_src_parent_class parent_class
+G_DEFINE_TYPE (GstTCPClientSrc, gst_tcp_client_src, GST_TYPE_PUSH_SRC);
static void gst_tcp_client_src_finalize (GObject * gobject);
-static GstCaps *gst_tcp_client_src_getcaps (GstBaseSrc * psrc);
+static GstCaps *gst_tcp_client_src_getcaps (GstBaseSrc * psrc,
+ GstCaps * filter);
static GstFlowReturn gst_tcp_client_src_create (GstPushSrc * psrc,
GstBuffer ** outbuf);
static void gst_tcp_client_src_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
-
-static void
-gst_tcp_client_src_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 (&srctemplate));
-
- gst_element_class_set_details_simple (element_class,
- "TCP client source", "Source/Network",
- "Receive data as a client over the network via TCP",
- "Thomas Vander Stichele <thomas at apestaart dot org>");
-}
-
static void
gst_tcp_client_src_class_init (GstTCPClientSrcClass * klass)
{
GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
GstBaseSrcClass *gstbasesrc_class;
GstPushSrcClass *gstpush_src_class;
gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
gstbasesrc_class = (GstBaseSrcClass *) klass;
gstpush_src_class = (GstPushSrcClass *) klass;
g_param_spec_int ("port", "Port", "The port to receive packets from", 0,
TCP_HIGHEST_PORT, TCP_DEFAULT_PORT,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, PROP_PROTOCOL,
- g_param_spec_enum ("protocol", "Protocol", "The protocol to wrap data in",
- GST_TYPE_TCP_PROTOCOL, GST_TCP_PROTOCOL_NONE,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&srctemplate));
+
+ gst_element_class_set_details_simple (gstelement_class,
+ "TCP client source", "Source/Network",
+ "Receive data as a client over the network via TCP",
+ "Thomas Vander Stichele <thomas at apestaart dot org>");
gstbasesrc_class->get_caps = gst_tcp_client_src_getcaps;
gstbasesrc_class->start = gst_tcp_client_src_start;
}
static void
-gst_tcp_client_src_init (GstTCPClientSrc * this, GstTCPClientSrcClass * g_class)
+gst_tcp_client_src_init (GstTCPClientSrc * this)
{
this->port = TCP_DEFAULT_PORT;
this->host = g_strdup (TCP_DEFAULT_HOST);
this->sock_fd.fd = -1;
- this->protocol = GST_TCP_PROTOCOL_NONE;
this->caps = NULL;
GST_OBJECT_FLAG_UNSET (this, GST_TCP_CLIENT_SRC_OPEN);
}
static GstCaps *
-gst_tcp_client_src_getcaps (GstBaseSrc * bsrc)
+gst_tcp_client_src_getcaps (GstBaseSrc * bsrc, GstCaps * filter)
{
GstTCPClientSrc *src;
GstCaps *caps = NULL;
src = GST_TCP_CLIENT_SRC (bsrc);
if (!GST_OBJECT_FLAG_IS_SET (src, GST_TCP_CLIENT_SRC_OPEN))
- caps = gst_caps_new_any ();
+ caps = (filter ? gst_caps_ref (filter) : gst_caps_new_any ());
+ else if (src->caps && filter)
+ caps =
+ gst_caps_intersect_full (filter, src->caps, GST_CAPS_INTERSECT_FIRST);
else if (src->caps)
caps = gst_caps_copy (src->caps);
else
- caps = gst_caps_new_any ();
+ caps = (filter ? gst_caps_ref (filter) : gst_caps_new_any ());
+
GST_DEBUG_OBJECT (src, "returning caps %" GST_PTR_FORMAT, caps);
g_assert (GST_IS_CAPS (caps));
return caps;
GST_LOG_OBJECT (src, "asked for a buffer");
- /* read the buffer header if we're using a protocol */
- switch (src->protocol) {
- case GST_TCP_PROTOCOL_NONE:
- ret = gst_tcp_read_buffer (GST_ELEMENT (src), src->sock_fd.fd,
- src->fdset, outbuf);
- break;
-
- case GST_TCP_PROTOCOL_GDP:
- /* get the caps if we're using GDP */
- if (!src->caps_received) {
- GstCaps *caps;
-
- GST_DEBUG_OBJECT (src, "getting caps through GDP");
- ret = gst_tcp_gdp_read_caps (GST_ELEMENT (src), src->sock_fd.fd,
- src->fdset, &caps);
-
- if (ret != GST_FLOW_OK)
- goto no_caps;
-
- src->caps_received = TRUE;
- src->caps = caps;
- }
-
- ret = gst_tcp_gdp_read_buffer (GST_ELEMENT (src), src->sock_fd.fd,
- src->fdset, outbuf);
- break;
- default:
- /* need to assert as buf == NULL */
- g_assert ("Unhandled protocol type");
- break;
- }
+ /* read the buffer header */
+ ret = gst_tcp_read_buffer (GST_ELEMENT (src), src->sock_fd.fd,
+ src->fdset, outbuf);
if (ret == GST_FLOW_OK) {
GST_LOG_OBJECT (src,
"Returning buffer from _get of size %d, ts %"
GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT
", offset %" G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT,
- GST_BUFFER_SIZE (*outbuf),
+ gst_buffer_get_size (*outbuf),
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (*outbuf)),
GST_TIME_ARGS (GST_BUFFER_DURATION (*outbuf)),
GST_BUFFER_OFFSET (*outbuf), GST_BUFFER_OFFSET_END (*outbuf));
-
- gst_buffer_set_caps (*outbuf, src->caps);
}
return ret;
GST_DEBUG_OBJECT (src, "connection to closed, cannot read data");
return GST_FLOW_WRONG_STATE;
}
-no_caps:
- {
- GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
- ("Could not read caps through GDP"));
- return ret;
- }
}
static void
case PROP_PORT:
tcpclientsrc->port = g_value_get_int (value);
break;
- case PROP_PROTOCOL:
- tcpclientsrc->protocol = g_value_get_enum (value);
- break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
case PROP_PORT:
g_value_set_int (value, tcpclientsrc->port);
break;
- case PROP_PROTOCOL:
- g_value_set_enum (value, tcpclientsrc->protocol);
- break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
GstPollFD sock_fd;
GstPoll *fdset;
- GstTCPProtocol protocol; /* protocol used for reading data */
gboolean caps_received; /* if we have received caps yet */
GstCaps *caps;
};
static void gst_tcp_server_sink_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
-
-GST_BOILERPLATE (GstTCPServerSink, gst_tcp_server_sink, GstMultiFdSink,
- GST_TYPE_MULTI_FD_SINK);
-
-
-static void
-gst_tcp_server_sink_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_set_details_simple (element_class,
- "TCP server sink", "Sink/Network",
- "Send data as a server over the network via TCP",
- "Thomas Vander Stichele <thomas at apestaart dot org>");
-}
+#define gst_tcp_server_sink_parent_class parent_class
+G_DEFINE_TYPE (GstTCPServerSink, gst_tcp_server_sink, GST_TYPE_MULTI_FD_SINK);
static void
gst_tcp_server_sink_class_init (GstTCPServerSinkClass * klass)
{
GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
GstMultiFdSinkClass *gstmultifdsink_class;
gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
gstmultifdsink_class = (GstMultiFdSinkClass *) klass;
gobject_class->set_property = gst_tcp_server_sink_set_property;
0, TCP_HIGHEST_PORT, TCP_DEFAULT_PORT,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ gst_element_class_set_details_simple (gstelement_class,
+ "TCP server sink", "Sink/Network",
+ "Send data as a server over the network via TCP",
+ "Thomas Vander Stichele <thomas at apestaart dot org>");
+
gstmultifdsink_class->init = gst_tcp_server_sink_init_send;
gstmultifdsink_class->wait = gst_tcp_server_sink_handle_wait;
gstmultifdsink_class->close = gst_tcp_server_sink_close;
}
static void
-gst_tcp_server_sink_init (GstTCPServerSink * this,
- GstTCPServerSinkClass * klass)
+gst_tcp_server_sink_init (GstTCPServerSink * this)
{
this->server_port = TCP_DEFAULT_PORT;
/* should support as minimum 576 for IPV4 and 1500 for IPV6 */
{
PROP_0,
PROP_HOST,
- PROP_PORT,
- PROP_PROTOCOL
+ PROP_PORT
};
-
-GST_BOILERPLATE (GstTCPServerSrc, gst_tcp_server_src, GstPushSrc,
- GST_TYPE_PUSH_SRC);
+#define gst_tcp_server_src_parent_class parent_class
+G_DEFINE_TYPE (GstTCPServerSrc, gst_tcp_server_src, GST_TYPE_PUSH_SRC);
static void gst_tcp_server_src_finalize (GObject * gobject);
static void gst_tcp_server_src_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
-
-static void
-gst_tcp_server_src_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 (&srctemplate));
-
- gst_element_class_set_details_simple (element_class,
- "TCP server source", "Source/Network",
- "Receive data as a server over the network via TCP",
- "Thomas Vander Stichele <thomas at apestaart dot org>");
-}
-
static void
gst_tcp_server_src_class_init (GstTCPServerSrcClass * klass)
{
GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
GstBaseSrcClass *gstbasesrc_class;
GstPushSrcClass *gstpush_src_class;
gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
gstbasesrc_class = (GstBaseSrcClass *) klass;
gstpush_src_class = (GstPushSrcClass *) klass;
g_param_spec_int ("port", "Port", "The port to listen to",
0, TCP_HIGHEST_PORT, TCP_DEFAULT_PORT,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, PROP_PROTOCOL,
- g_param_spec_enum ("protocol", "Protocol", "The protocol to wrap data in",
- GST_TYPE_TCP_PROTOCOL, GST_TCP_PROTOCOL_NONE,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&srctemplate));
+
+ gst_element_class_set_details_simple (gstelement_class,
+ "TCP server source", "Source/Network",
+ "Receive data as a server over the network via TCP",
+ "Thomas Vander Stichele <thomas at apestaart dot org>");
gstbasesrc_class->start = gst_tcp_server_src_start;
gstbasesrc_class->stop = gst_tcp_server_src_stop;
}
static void
-gst_tcp_server_src_init (GstTCPServerSrc * src, GstTCPServerSrcClass * g_class)
+gst_tcp_server_src_init (GstTCPServerSrc * src)
{
src->server_port = TCP_DEFAULT_PORT;
src->host = g_strdup (TCP_DEFAULT_HOST);
src->server_sock_fd.fd = -1;
src->client_sock_fd.fd = -1;
- src->protocol = GST_TCP_PROTOCOL_NONE;
GST_OBJECT_FLAG_UNSET (src, GST_TCP_SERVER_SRC_OPEN);
}
GST_LOG_OBJECT (src, "asked for a buffer");
- switch (src->protocol) {
- case GST_TCP_PROTOCOL_NONE:
- ret = gst_tcp_read_buffer (GST_ELEMENT (src), src->client_sock_fd.fd,
- src->fdset, outbuf);
- break;
-
- case GST_TCP_PROTOCOL_GDP:
- if (!src->caps_received) {
- GstCaps *caps;
- gchar *string;
-
- ret = gst_tcp_gdp_read_caps (GST_ELEMENT (src), src->client_sock_fd.fd,
- src->fdset, &caps);
-
- if (ret == GST_FLOW_WRONG_STATE)
- goto gdp_cancelled;
-
- if (ret != GST_FLOW_OK)
- goto gdp_caps_read_error;
-
- src->caps_received = TRUE;
- string = gst_caps_to_string (caps);
- GST_DEBUG_OBJECT (src, "Received caps through GDP: %s", string);
- g_free (string);
-
- gst_pad_set_caps (GST_BASE_SRC_PAD (psrc), caps);
- }
-
- ret = gst_tcp_gdp_read_buffer (GST_ELEMENT (src), src->client_sock_fd.fd,
- src->fdset, outbuf);
-
- if (ret == GST_FLOW_OK)
- gst_buffer_set_caps (*outbuf, GST_PAD_CAPS (GST_BASE_SRC_PAD (src)));
-
- break;
-
- default:
- /* need to assert as buf == NULL */
- g_assert ("Unhandled protocol type");
- break;
- }
+ ret = gst_tcp_read_buffer (GST_ELEMENT (src), src->client_sock_fd.fd,
+ src->fdset, outbuf);
if (ret == GST_FLOW_OK) {
GST_LOG_OBJECT (src,
"Returning buffer from _get of size %d, ts %"
GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT
", offset %" G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT,
- GST_BUFFER_SIZE (*outbuf),
+ gst_buffer_get_size (*outbuf),
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (*outbuf)),
GST_TIME_ARGS (GST_BUFFER_DURATION (*outbuf)),
GST_BUFFER_OFFSET (*outbuf), GST_BUFFER_OFFSET_END (*outbuf));
("Could not accept client on server socket: %s", g_strerror (errno)));
return GST_FLOW_ERROR;
}
-gdp_cancelled:
- {
- GST_DEBUG_OBJECT (src, "reading gdp canceled");
- return GST_FLOW_WRONG_STATE;
- }
-gdp_caps_read_error:
- {
- /* if we did not get canceled, report an error */
- if (ret != GST_FLOW_WRONG_STATE) {
- GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
- ("Could not read caps through GDP"));
- }
- return ret;
- }
}
static void
case PROP_PORT:
tcpserversrc->server_port = g_value_get_int (value);
break;
- case PROP_PROTOCOL:
- tcpserversrc->protocol = g_value_get_enum (value);
- break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
case PROP_PORT:
g_value_set_int (value, tcpserversrc->server_port);
break;
- case PROP_PROTOCOL:
- g_value_set_enum (value, tcpserversrc->protocol);
- break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
GstPoll *fdset;
- GstTCPProtocol protocol; /* protocol used for reading data */
gboolean caps_received; /* if we have received caps yet */
};
utf8_type_find_have_valid_utf8_at_offset (GstTypeFind * tf, guint64 offset,
GstTypeFindProbability * prob)
{
- guint8 *data;
+ const guint8 *data;
/* randomly decided values */
guint min_size = 16; /* minimum size */
static void
uri_type_find (GstTypeFind * tf, gpointer unused)
{
- guint8 *data = gst_type_find_peek (tf, 0, BUFFER_SIZE);
+ const guint8 *data = gst_type_find_peek (tf, 0, BUFFER_SIZE);
guint pos = 0;
guint offset = 0;
gboolean strict)
{
gboolean got_xmldec;
- guint8 *data;
+ const guint8 *data;
guint offset = 0;
guint pos = 0;
static gboolean
sdp_check_header (GstTypeFind * tf)
{
- guint8 *data;
+ const guint8 *data;
data = gst_type_find_peek (tf, 0, 5);
if (!data)
static void
html_type_find (GstTypeFind * tf, gpointer unused)
{
- gchar *d, *data;
+ const gchar *d, *data;
- data = (gchar *) gst_type_find_peek (tf, 0, 16);
+ data = (const gchar *) gst_type_find_peek (tf, 0, 16);
if (!data)
return;
} else if (xml_check_first_element (tf, "html", 4, FALSE)) {
gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, HTML_CAPS);
} else if ((d = memchr (data, '<', 16))) {
- data = (gchar *) gst_type_find_peek (tf, d - data, 6);
+ data = (const gchar *) gst_type_find_peek (tf, d - data, 6);
if (data && g_ascii_strncasecmp (data, "<html>", 6) == 0) {
gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, HTML_CAPS);
}
static void
mid_type_find (GstTypeFind * tf, gpointer unused)
{
- guint8 *data = gst_type_find_peek (tf, 0, 4);
+ const guint8 *data = gst_type_find_peek (tf, 0, 4);
/* http://jedi.ks.uiuc.edu/~johns/links/music/midifile.html */
if (data && data[0] == 'M' && data[1] == 'T' && data[2] == 'h'
static void
mxmf_type_find (GstTypeFind * tf, gpointer unused)
{
- guint8 *data = NULL;
+ const guint8 *data = NULL;
/* Search FileId "XMF_" 4 bytes */
data = gst_type_find_peek (tf, 0, 4);
static void
flx_type_find (GstTypeFind * tf, gpointer unused)
{
- guint8 *data = gst_type_find_peek (tf, 0, 134);
+ const guint8 *data = gst_type_find_peek (tf, 0, 134);
if (data) {
/* check magic and the frame type of the first frame */
static void
id3v2_type_find (GstTypeFind * tf, gpointer unused)
{
- guint8 *data = gst_type_find_peek (tf, 0, 10);
+ const guint8 *data = gst_type_find_peek (tf, 0, 10);
if (data && memcmp (data, "ID3", 3) == 0 &&
data[3] != 0xFF && data[4] != 0xFF &&
static void
id3v1_type_find (GstTypeFind * tf, gpointer unused)
{
- guint8 *data = gst_type_find_peek (tf, -128, 3);
+ const guint8 *data = gst_type_find_peek (tf, -128, 3);
if (data && memcmp (data, "TAG", 3) == 0) {
gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, ID3_CAPS);
static void
apetag_type_find (GstTypeFind * tf, gpointer unused)
{
- guint8 *data;
+ const guint8 *data;
/* APEv1/2 at start of file */
data = gst_type_find_peek (tf, 0, 8);
static void
tta_type_find (GstTypeFind * tf, gpointer unused)
{
- guint8 *data = gst_type_find_peek (tf, 0, 3);
+ const guint8 *data = gst_type_find_peek (tf, 0, 3);
if (data) {
if (memcmp (data, "TTA", 3) == 0) {
mp3_type_find_at_offset (GstTypeFind * tf, guint64 start_off,
guint * found_layer, GstTypeFindProbability * found_prob)
{
- guint8 *data = NULL;
- guint8 *data_end = NULL;
+ const guint8 *data = NULL;
+ const guint8 *data_end = NULL;
guint size;
guint64 skipped;
gint last_free_offset = -1;
data_end = data + size;
}
if (*data == 0xFF) {
- guint8 *head_data = NULL;
+ const guint8 *head_data = NULL;
guint layer = 0, bitrate, samplerate, channels;
guint found = 0; /* number of valid headers found */
guint64 offset = skipped;
mp3_type_find (GstTypeFind * tf, gpointer unused)
{
GstTypeFindProbability prob, mid_prob;
- guint8 *data;
+ const guint8 *data;
guint layer, mid_layer;
guint64 length;
static void
musepack_type_find (GstTypeFind * tf, gpointer unused)
{
- guint8 *data = gst_type_find_peek (tf, 0, 4);
+ const guint8 *data = gst_type_find_peek (tf, 0, 4);
GstTypeFindProbability prop = GST_TYPE_FIND_MINIMUM;
gint streamversion = -1;
{
guint64 offset;
guint32 blocksize;
- guint8 *data;
+ const guint8 *data;
data = gst_type_find_peek (tf, 0, 32);
if (!data)
static void
postscript_type_find (GstTypeFind * tf, gpointer unused)
{
- guint8 *data = gst_type_find_peek (tf, 0, 3);
+ const guint8 *data = gst_type_find_peek (tf, 0, 3);
if (!data)
return;
static void
multipart_type_find (GstTypeFind * tf, gpointer unused)
{
- guint8 *data;
- guint8 *x;
+ const guint8 *data;
+ const guint8 *x;
#define MULTIPART_MAX_BOUNDARY_OFFSET 16
data = gst_type_find_peek (tf, 0, MULTIPART_MAX_BOUNDARY_OFFSET);
}
static gboolean
-mpeg_sys_is_valid_pes (GstTypeFind * tf, guint8 * data, guint len,
+mpeg_sys_is_valid_pes (GstTypeFind * tf, const guint8 * data, guint len,
guint * pack_size)
{
guint pes_packet_len;
}
static gboolean
-mpeg_sys_is_valid_sys (GstTypeFind * tf, guint8 * data, guint len,
+mpeg_sys_is_valid_sys (GstTypeFind * tf, const guint8 * data, guint len,
guint * pack_size)
{
guint sys_hdr_len;
static void
mpeg_sys_type_find (GstTypeFind * tf, gpointer unused)
{
- guint8 *data, *data0, *first_sync, *end;
+ const guint8 *data, *data0, *first_sync, *end;
gint mpegversion = 0;
guint pack_headers = 0;
guint pes_headers = 0;
{
/* We always enter this function having found at least one header already */
gint found = 1;
- guint8 *data = NULL;
+ const guint8 *data = NULL;
GST_LOG ("looking for mpeg-ts packets of size %u", packet_size);
while (found < GST_MPEGTS_TYPEFIND_MAX_HEADERS) {
/* TS packet sizes to test: normal, DVHS packet size and
* FEC with 16 or 20 byte codes packet size. */
const gint pack_sizes[] = { 188, 192, 204, 208 };
-
- guint8 *data = NULL;
+ const guint8 *data = NULL;
guint size = 0;
guint64 skipped = 0;
static void
aiff_type_find (GstTypeFind * tf, gpointer unused)
{
- guint8 *data = gst_type_find_peek (tf, 0, 4);
+ const guint8 *data = gst_type_find_peek (tf, 0, 4);
if (data && memcmp (data, "FORM", 4) == 0) {
data += 8;
static void
svx_type_find (GstTypeFind * tf, gpointer unused)
{
- guint8 *data = gst_type_find_peek (tf, 0, 4);
+ const guint8 *data = gst_type_find_peek (tf, 0, 4);
if (data && memcmp (data, "FORM", 4) == 0) {
data += 8;
static void
shn_type_find (GstTypeFind * tf, gpointer unused)
{
- guint8 *data = gst_type_find_peek (tf, 0, 4);
+ const guint8 *data = gst_type_find_peek (tf, 0, 4);
if (data && memcmp (data, "ajkg", 4) == 0) {
gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, SHN_CAPS);
static void
ape_type_find (GstTypeFind * tf, gpointer unused)
{
- guint8 *data = gst_type_find_peek (tf, 0, 4);
+ const guint8 *data = gst_type_find_peek (tf, 0, 4);
if (data && memcmp (data, "MAC ", 4) == 0) {
gst_type_find_suggest (tf, GST_TYPE_FIND_LIKELY + 10, APE_CAPS);
static void
m4a_type_find (GstTypeFind * tf, gpointer unused)
{
- guint8 *data = gst_type_find_peek (tf, 4, 8);
+ const guint8 *data = gst_type_find_peek (tf, 4, 8);
if (data && (memcmp (data, "ftypM4A ", 8) == 0)) {
gst_type_find_suggest (tf, GST_TYPE_FIND_MAXIMUM, M4A_CAPS);
const gchar *profile;
guint32 ftyp_size = 0;
gint offset = 0;
- guint8 *data = NULL;
+ const guint8 *data = NULL;
if ((data = gst_type_find_peek (tf, 0, 12)) == NULL) {
return;
static void
jp2_type_find (GstTypeFind * tf, gpointer unused)
{
- guint8 *data;
+ const guint8 *data;
data = gst_type_find_peek (tf, 0, 24);
if (!data)
static void
qt_type_find (GstTypeFind * tf, gpointer unused)
{
- guint8 *data;
+ const guint8 *data;
guint tip = 0;
guint64 offset = 0;
guint64 size;
}
}
if (size == 1) {
- guint8 *sizedata;
+ const guint8 *sizedata;
sizedata = gst_type_find_peek (tf, offset + 8, 8);
if (sizedata == NULL)
static void
mod_type_find (GstTypeFind * tf, gpointer unused)
{
- guint8 *data;
+ const guint8 *data;
/* MOD */
if ((data = gst_type_find_peek (tf, 1080, 4)) != NULL) {
}
/* DSM */
if (memcmp (data, "RIFF", 4) == 0) {
- guint8 *data2 = gst_type_find_peek (tf, 8, 4);
+ const guint8 *data2 = gst_type_find_peek (tf, 8, 4);
if (data2) {
if (memcmp (data2, "DSMF", 4) == 0) {
}
/* FAM */
if (memcmp (data, "FAM\xFE", 4) == 0) {
- guint8 *data2 = gst_type_find_peek (tf, 44, 3);
+ const guint8 *data2 = gst_type_find_peek (tf, 44, 3);
if (data2) {
if (memcmp (data2, "compare", 3) == 0) {
}
/* GDM */
if (memcmp (data, "GDM\xFE", 4) == 0) {
- guint8 *data2 = gst_type_find_peek (tf, 71, 4);
+ const guint8 *data2 = gst_type_find_peek (tf, 71, 4);
if (data2) {
if (memcmp (data2, "GMFS", 4) == 0) {
if ((data = gst_type_find_peek (tf, 20, 8)) != NULL) {
if (g_ascii_strncasecmp ((gchar *) data, "!Scream!", 8) == 0 ||
g_ascii_strncasecmp ((gchar *) data, "BMOD2STM", 8) == 0) {
- guint8 *id, *stmtype;
+ const guint8 *id, *stmtype;
if ((id = gst_type_find_peek (tf, 28, 1)) == NULL)
return;
static void
swf_type_find (GstTypeFind * tf, gpointer unused)
{
- guint8 *data = gst_type_find_peek (tf, 0, 4);
+ const guint8 *data = gst_type_find_peek (tf, 0, 4);
if (data && (data[0] == 'F' || data[0] == 'C') &&
data[1] == 'W' && data[2] == 'S') {
static void
tiff_type_find (GstTypeFind * tf, gpointer ununsed)
{
- guint8 *data = gst_type_find_peek (tf, 0, 8);
+ const guint8 *data = gst_type_find_peek (tf, 0, 8);
guint8 le_header[4] = { 0x49, 0x49, 0x2A, 0x00 };
guint8 be_header[4] = { 0x4D, 0x4D, 0x00, 0x2A };
static void
sds_type_find (GstTypeFind * tf, gpointer ununsed)
{
- guint8 *data = gst_type_find_peek (tf, 0, 4);
+ const guint8 *data = gst_type_find_peek (tf, 0, 4);
guint8 mask[4] = { 0xFF, 0xFF, 0x80, 0xFF };
guint8 match[4] = { 0xF0, 0x7E, 0, 0x01 };
gint x;
static void
ircam_type_find (GstTypeFind * tf, gpointer ununsed)
{
- guint8 *data = gst_type_find_peek (tf, 0, 4);
+ const guint8 *data = gst_type_find_peek (tf, 0, 4);
guint8 mask[4] = { 0xFF, 0xFF, 0xF8, 0xFF };
guint8 match[4] = { 0x64, 0xA3, 0x00, 0x00 };
gint x;
ebml_check_header (GstTypeFind * tf, const gchar * doctype, int doctype_len)
{
/* 4 bytes for EBML ID, 1 byte for header length identifier */
- guint8 *data = gst_type_find_peek (tf, 0, 4 + 1);
+ const guint8 *data = gst_type_find_peek (tf, 0, 4 + 1);
gint len_mask = 0x80, size = 1, n = 1, total;
if (!data)
static void
dv_type_find (GstTypeFind * tf, gpointer private)
{
- guint8 *data;
+ const guint8 *data;
data = gst_type_find_peek (tf, 0, 5);
static void
ogganx_type_find (GstTypeFind * tf, gpointer private)
{
- guint8 *data = gst_type_find_peek (tf, 0, 4);
+ const guint8 *data = gst_type_find_peek (tf, 0, 4);
if ((data != NULL) && (memcmp (data, "OggS", 4) == 0)) {
static void
vorbis_type_find (GstTypeFind * tf, gpointer private)
{
- guint8 *data = gst_type_find_peek (tf, 0, 30);
+ const guint8 *data = gst_type_find_peek (tf, 0, 30);
if (data) {
guint blocksize_0;
static void
theora_type_find (GstTypeFind * tf, gpointer private)
{
- guint8 *data = gst_type_find_peek (tf, 0, 7); //42);
+ const guint8 *data = gst_type_find_peek (tf, 0, 7); //42);
if (data) {
if (data[0] != 0x80)
static void
kate_type_find (GstTypeFind * tf, gpointer private)
{
- guint8 *data = gst_type_find_peek (tf, 0, 64);
+ const guint8 *data = gst_type_find_peek (tf, 0, 64);
gchar category[16] = { 0, };
if (G_UNLIKELY (data == NULL))
static void
ogmvideo_type_find (GstTypeFind * tf, gpointer private)
{
- guint8 *data = gst_type_find_peek (tf, 0, 9);
+ const guint8 *data = gst_type_find_peek (tf, 0, 9);
if (data) {
if (memcmp (data, "\001video\000\000\000", 9) != 0)
static void
ogmaudio_type_find (GstTypeFind * tf, gpointer private)
{
- guint8 *data = gst_type_find_peek (tf, 0, 9);
+ const guint8 *data = gst_type_find_peek (tf, 0, 9);
if (data) {
if (memcmp (data, "\001audio\000\000\000", 9) != 0)
static void
ogmtext_type_find (GstTypeFind * tf, gpointer private)
{
- guint8 *data = gst_type_find_peek (tf, 0, 9);
+ const guint8 *data = gst_type_find_peek (tf, 0, 9);
if (data) {
if (memcmp (data, "\001text\000\000\000\000", 9) != 0)
static void
speex_type_find (GstTypeFind * tf, gpointer private)
{
- guint8 *data = gst_type_find_peek (tf, 0, 80);
+ const guint8 *data = gst_type_find_peek (tf, 0, 80);
if (data) {
/* 8 byte string "Speex "
static void
celt_type_find (GstTypeFind * tf, gpointer private)
{
- guint8 *data = gst_type_find_peek (tf, 0, 8);
+ const guint8 *data = gst_type_find_peek (tf, 0, 8);
if (data) {
/* 8 byte string "CELT " */
static void
oggskel_type_find (GstTypeFind * tf, gpointer private)
{
- guint8 *data = gst_type_find_peek (tf, 0, 12);
+ const guint8 *data = gst_type_find_peek (tf, 0, 12);
if (data) {
/* 8 byte string "fishead\0" for the ogg skeleton stream */
cmml_type_find (GstTypeFind * tf, gpointer private)
{
/* Header is 12 bytes minimum (though we don't check the minor version */
- guint8 *data = gst_type_find_peek (tf, 0, 12);
+ const guint8 *data = gst_type_find_peek (tf, 0, 12);
if (data) {
static void
tar_type_find (GstTypeFind * tf, gpointer unused)
{
- guint8 *data = gst_type_find_peek (tf, 257, 8);
+ const guint8 *data = gst_type_find_peek (tf, 257, 8);
/* of course we are not certain, but we don't want other typefind funcs
* to detect formats of files within the tar archive, e.g. mp3s */
static void
ar_type_find (GstTypeFind * tf, gpointer unused)
{
- guint8 *data = gst_type_find_peek (tf, 0, 24);
+ const guint8 *data = gst_type_find_peek (tf, 0, 24);
if (data && memcmp (data, "!<arch>", 7) == 0) {
gint i;
static void
au_type_find (GstTypeFind * tf, gpointer unused)
{
- guint8 *data = gst_type_find_peek (tf, 0, 4);
+ const guint8 *data = gst_type_find_peek (tf, 0, 4);
if (data) {
if (memcmp (data, ".snd", 4) == 0 || memcmp (data, "dns.", 4) == 0) {
static void
nuv_type_find (GstTypeFind * tf, gpointer unused)
{
- guint8 *data = gst_type_find_peek (tf, 0, 11);
+ const guint8 *data = gst_type_find_peek (tf, 0, 11);
if (data) {
if (memcmp (data, "MythTVVideo", 11) == 0
static void
paris_type_find (GstTypeFind * tf, gpointer unused)
{
- guint8 *data = gst_type_find_peek (tf, 0, 4);
+ const guint8 *data = gst_type_find_peek (tf, 0, 4);
if (data) {
if (memcmp (data, " paf", 4) == 0 || memcmp (data, "fap ", 4) == 0) {
static void
ilbc_type_find (GstTypeFind * tf, gpointer unused)
{
- guint8 *data = gst_type_find_peek (tf, 0, 8);
+ const guint8 *data = gst_type_find_peek (tf, 0, 8);
if (data) {
if (memcmp (data, "#!iLBC30", 8) == 0 || memcmp (data, "#!iLBC20", 8) == 0) {
static void
msdos_type_find (GstTypeFind * tf, gpointer unused)
{
- guint8 *data = gst_type_find_peek (tf, 0, 64);
+ const guint8 *data = gst_type_find_peek (tf, 0, 64);
if (data && data[0] == 'M' && data[1] == 'Z' &&
GST_READ_UINT16_LE (data + 8) == 4) {
0xcf, 0x11, 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c
};
- guint8 *data;
+ const guint8 *data;
data = gst_type_find_peek (tf, 0, 2 + 2 + 4 + 2 + 2 + 16);
if (data && data[0] == 0x24 && data[1] == 0x48 &&
static void
dirac_type_find (GstTypeFind * tf, gpointer unused)
{
- guint8 *data = gst_type_find_peek (tf, 0, 8);
+ const guint8 *data = gst_type_find_peek (tf, 0, 8);
if (data) {
if (memcmp (data, "BBCD", 4) == 0 || memcmp (data, "KW-DIRAC", 8) == 0) {
static const guint8 vivo_marker[] = { 'V', 'e', 'r', 's', 'i', 'o', 'n',
':', 'V', 'i', 'v', 'o', '/'
};
- guint8 *data;
+ const guint8 *data;
guint hdr_len, pos;
data = gst_type_find_peek (tf, 0, 1024);
gchar *mimetype;
gsize length = 16384;
guint64 tf_length;
- guint8 *data;
+ const guint8 *data;
gchar *tmp;
if ((tf_length = gst_type_find_get_length (find)) > 0)
static void
windows_icon_typefind (GstTypeFind * find, gpointer user_data)
{
- guint8 *data;
+ const guint8 *data;
gint64 datalen;
guint16 type, nimages;
gint32 size, offset;
start_with_type_find (GstTypeFind * tf, gpointer private)
{
GstTypeFindData *start_with = (GstTypeFindData *) private;
- guint8 *data;
+ const guint8 *data;
GST_LOG ("trying to find mime type %s with the first %u bytes of data",
gst_structure_get_name (gst_caps_get_structure (start_with->caps, 0)),
riff_type_find (GstTypeFind * tf, gpointer private)
{
GstTypeFindData *riff_data = (GstTypeFindData *) private;
- guint8 *data = gst_type_find_peek (tf, 0, 12);
+ const guint8 *data = gst_type_find_peek (tf, 0, 12);
if (data && (memcmp (data, "RIFF", 4) == 0 || memcmp (data, "AVF0", 4) == 0)) {
data += 8;
static GParamSpec *pspec_drop = NULL;
static GParamSpec *pspec_duplicate = NULL;
-GST_BOILERPLATE (GstVideoRate, gst_video_rate, GstElement, GST_TYPE_ELEMENT);
-
-static void
-gst_video_rate_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_set_details_simple (element_class,
- "Video rate adjuster", "Filter/Effect/Video",
- "Drops/duplicates/adjusts timestamps on video frames to make a perfect stream",
- "Wim Taymans <wim@fluendo.com>");
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&gst_video_rate_sink_template));
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&gst_video_rate_src_template));
-}
+#define gst_video_rate_parent_class parent_class
+G_DEFINE_TYPE (GstVideoRate, gst_video_rate, GST_TYPE_ELEMENT);
static void
gst_video_rate_class_init (GstVideoRateClass * klass)
"Don't produce buffers before the first one we receive",
DEFAULT_SKIP_TO_FIRST, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ gst_element_class_set_details_simple (element_class,
+ "Video rate adjuster", "Filter/Effect/Video",
+ "Drops/duplicates/adjusts timestamps on video frames to make a perfect stream",
+ "Wim Taymans <wim@fluendo.com>");
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_video_rate_sink_template));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_video_rate_src_template));
+
/**
* GstVideoRate:drop-only:
*
/* return the caps that can be used on out_pad given in_caps on in_pad */
static gboolean
gst_video_rate_transformcaps (GstPad * in_pad, GstCaps * in_caps,
- GstPad * out_pad, GstCaps ** out_caps)
+ GstPad * out_pad, GstCaps ** out_caps, GstCaps * filter)
{
- GstCaps *intersect;
- const GstCaps *in_templ;
+ GstCaps *intersect, *in_templ;
gint i;
GSList *extra_structures = NULL;
GSList *iter;
in_templ = gst_pad_get_pad_template_caps (in_pad);
- intersect = gst_caps_intersect (in_caps, in_templ);
+ intersect =
+ gst_caps_intersect_full (in_caps, in_templ, GST_CAPS_INTERSECT_FIRST);
+ gst_caps_unref (in_templ);
/* all possible framerates are allowed */
for (i = 0; i < gst_caps_get_size (intersect); i++) {
}
g_slist_free (extra_structures);
+ if (filter) {
+ GstCaps *tmp;
+
+ tmp = gst_caps_intersect_full (filter, intersect, GST_CAPS_INTERSECT_FIRST);
+ gst_caps_unref (intersect);
+ intersect = tmp;
+ }
+
*out_caps = intersect;
return TRUE;
}
static GstCaps *
-gst_video_rate_getcaps (GstPad * pad)
+gst_video_rate_getcaps (GstPad * pad, GstCaps * filter)
{
GstVideoRate *videorate;
GstPad *otherpad;
videorate->srcpad;
/* we can do what the peer can */
- caps = gst_pad_peer_get_caps (otherpad);
+ caps = gst_pad_peer_get_caps (otherpad, filter);
if (caps) {
- GstCaps *transform;
+ GstCaps *transform, *intersect;
- gst_video_rate_transformcaps (otherpad, caps, pad, &transform);
- gst_caps_unref (caps);
- caps = transform;
+ gst_video_rate_transformcaps (otherpad, caps, pad, &transform, filter);
+
+ /* Now prefer the downstream caps if possible */
+ intersect =
+ gst_caps_intersect_full (caps, transform, GST_CAPS_INTERSECT_FIRST);
+ if (!gst_caps_is_empty (intersect)) {
+ gst_caps_append (intersect, transform);
+ gst_caps_unref (caps);
+ caps = intersect;
+ } else {
+ gst_caps_unref (intersect);
+ caps = transform;
+ }
} else {
/* no peer, our padtemplate is enough then */
- caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
+ caps = gst_pad_get_pad_template_caps (pad);
+ if (filter) {
+ GstCaps *intersection;
+ intersection =
+ gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+ gst_caps_unref (caps);
+ caps = intersection;
+ }
}
return caps;
ret = TRUE;
} else {
- GstCaps *peercaps;
GstCaps *transform = NULL;
ret = FALSE;
/* see how we can transform the input caps */
- if (!gst_video_rate_transformcaps (pad, caps, otherpad, &transform))
+ if (!gst_video_rate_transformcaps (pad, caps, otherpad, &transform, NULL))
goto no_transform;
- /* see what the peer can do */
- peercaps = gst_pad_get_caps (opeer);
-
- GST_DEBUG_OBJECT (opeer, "icaps %" GST_PTR_FORMAT, peercaps);
GST_DEBUG_OBJECT (videorate, "transform %" GST_PTR_FORMAT, transform);
- /* filter against our possibilities */
- caps = gst_caps_intersect (peercaps, transform);
- gst_caps_unref (peercaps);
- gst_caps_unref (transform);
+ /* see what the peer can do */
+ caps = gst_pad_get_caps (opeer, transform);
- GST_DEBUG_OBJECT (videorate, "intersect %" GST_PTR_FORMAT, caps);
+ GST_DEBUG_OBJECT (opeer, "icaps %" GST_PTR_FORMAT, caps);
/* could turn up empty, due to e.g. colorspace etc */
if (gst_caps_get_size (caps) == 0) {
}
/* take first possibility */
+ caps = gst_caps_make_writable (caps);
gst_caps_truncate (caps);
structure = gst_caps_get_structure (caps, 0);
}
static void
-gst_video_rate_init (GstVideoRate * videorate, GstVideoRateClass * klass)
+gst_video_rate_init (GstVideoRate * videorate)
{
videorate->sinkpad =
gst_pad_new_from_static_template (&gst_video_rate_sink_template, "sink");
goto eos_before_buffers;
/* make sure we can write to the metadata */
- outbuf = gst_buffer_make_metadata_writable
- (gst_buffer_ref (videorate->prevbuf));
+ outbuf = gst_buffer_make_writable (gst_buffer_ref (videorate->prevbuf));
GST_BUFFER_OFFSET (outbuf) = videorate->out;
GST_BUFFER_OFFSET_END (outbuf) = videorate->out + 1;
if (videorate->to_rate_numerator) {
/* interpolate next expected timestamp in the segment */
videorate->next_ts =
- videorate->segment.accum + videorate->segment.start +
+ videorate->segment.base + videorate->segment.start +
videorate->base_ts + gst_util_uint64_scale (videorate->out_frame_count,
videorate->to_rate_denominator * GST_SECOND,
videorate->to_rate_numerator);
/* We do not need to update time in VFR (variable frame rate) mode */
if (!videorate->drop_only) {
/* adapt for looping, bring back to time in current segment. */
- GST_BUFFER_TIMESTAMP (outbuf) = push_ts - videorate->segment.accum;
+ GST_BUFFER_TIMESTAMP (outbuf) = push_ts - videorate->segment.base;
}
- gst_buffer_set_caps (outbuf, GST_PAD_CAPS (videorate->srcpad));
GST_LOG_OBJECT (videorate,
"old is best, dup, pushing buffer outgoing ts %" GST_TIME_FORMAT,
videorate = GST_VIDEO_RATE (gst_pad_get_parent (pad));
switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_NEWSEGMENT:
+ case GST_EVENT_SEGMENT:
{
- gint64 start, stop, time;
- gdouble rate, arate;
- gboolean update;
- GstFormat format;
+ const GstSegment *segment;
- gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
- &start, &stop, &time);
+ gst_event_parse_segment (event, &segment);
- if (format != GST_FORMAT_TIME)
+ if (segment->format != GST_FORMAT_TIME)
goto format_error;
GST_DEBUG_OBJECT (videorate, "handle NEWSEGMENT");
/* close up the previous segment, if appropriate */
- if (!update && videorate->prevbuf) {
+ if (videorate->prevbuf) {
gint count = 0;
GstFlowReturn res;
* regardless, prevent going loopy in strange cases */
while (res == GST_FLOW_OK && count <= MAGIC_LIMIT &&
((GST_CLOCK_TIME_IS_VALID (videorate->segment.stop) &&
- videorate->next_ts - videorate->segment.accum
+ videorate->next_ts - videorate->segment.base
< videorate->segment.stop)
|| count < 1)) {
res = gst_video_rate_flush_prev (videorate, count > 0);
}
/* We just want to update the accumulated stream_time */
- gst_segment_set_newsegment_full (&videorate->segment, update, rate, arate,
- format, start, stop, time);
+ gst_segment_copy_into (segment, &videorate->segment);
GST_DEBUG_OBJECT (videorate, "updated segment: %" GST_SEGMENT_FORMAT,
&videorate->segment);
* or only send out the stored buffer if there is no specific stop.
* regardless, prevent going loopy in strange cases */
while (res == GST_FLOW_OK && count <= MAGIC_LIMIT &&
- ((videorate->next_ts - videorate->segment.accum <
+ ((videorate->next_ts - videorate->segment.base <
videorate->segment.stop)
|| count < 1)) {
res = gst_video_rate_flush_prev (videorate, count > 0);
videorate->next_ts + GST_BUFFER_DURATION (videorate->prevbuf);
while (res == GST_FLOW_OK && count <= MAGIC_LIMIT &&
- ((videorate->next_ts - videorate->segment.accum < end_ts)
+ ((videorate->next_ts - videorate->segment.base < end_ts)
|| count < 1)) {
res = gst_video_rate_flush_prev (videorate, count > 0);
count++;
/* the input time is the time in the segment + all previously accumulated
* segments */
- intime = in_ts + videorate->segment.accum;
+ intime = in_ts + videorate->segment.base;
/* we need to have two buffers to compare */
if (videorate->prevbuf == NULL) {
videorate->base_ts = in_ts - videorate->segment.start;
videorate->out_frame_count = 0;
} else {
- videorate->next_ts =
- videorate->segment.start + videorate->segment.accum;
+ videorate->next_ts = videorate->segment.start + videorate->segment.base;
}
}
} else {
break;
}
- ret = parent_class->change_state (element, transition);
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_READY:
gst_video_scale_src_template_factory (void)
{
return gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
- gst_caps_ref (gst_video_scale_get_capslist ()));
+ gst_video_scale_get_capslist ());
}
static GstPadTemplate *
gst_video_scale_sink_template_factory (void)
{
return gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
- gst_caps_ref (gst_video_scale_get_capslist ()));
+ gst_video_scale_get_capslist ());
}
/* base transform vmethods */
static GstCaps *gst_video_scale_transform_caps (GstBaseTransform * trans,
- GstPadDirection direction, GstCaps * caps);
+ GstPadDirection direction, GstCaps * caps, GstCaps * filter);
static gboolean gst_video_scale_set_caps (GstBaseTransform * trans,
GstCaps * in, GstCaps * out);
static gboolean gst_video_scale_get_unit_size (GstBaseTransform * trans,
- GstCaps * caps, guint * size);
+ GstCaps * caps, gsize * size);
static GstFlowReturn gst_video_scale_transform (GstBaseTransform * trans,
GstBuffer * in, GstBuffer * out);
static void gst_video_scale_fixate_caps (GstBaseTransform * base,
static void gst_video_scale_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
-GST_BOILERPLATE (GstVideoScale, gst_video_scale, GstVideoFilter,
- GST_TYPE_VIDEO_FILTER);
-
-static void
-gst_video_scale_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_set_details_simple (element_class,
- "Video scaler", "Filter/Converter/Video/Scaler",
- "Resizes video", "Wim Taymans <wim.taymans@chello.be>");
-
- gst_element_class_add_pad_template (element_class,
- gst_video_scale_sink_template_factory ());
- gst_element_class_add_pad_template (element_class,
- gst_video_scale_src_template_factory ());
-}
+#define gst_video_scale_parent_class parent_class
+G_DEFINE_TYPE (GstVideoScale, gst_video_scale, GST_TYPE_VIDEO_FILTER);
static void
gst_video_scale_class_init (GstVideoScaleClass * klass)
{
GObjectClass *gobject_class = (GObjectClass *) klass;
+ GstElementClass *element_class = (GstElementClass *) klass;
GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
gobject_class->finalize = (GObjectFinalizeFunc) gst_video_scale_finalize;
DEFAULT_PROP_ADD_BORDERS,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ gst_element_class_set_details_simple (element_class,
+ "Video scaler", "Filter/Converter/Video/Scaler",
+ "Resizes video", "Wim Taymans <wim.taymans@chello.be>");
+
+ gst_element_class_add_pad_template (element_class,
+ gst_video_scale_sink_template_factory ());
+ gst_element_class_add_pad_template (element_class,
+ gst_video_scale_src_template_factory ());
+
trans_class->transform_caps =
GST_DEBUG_FUNCPTR (gst_video_scale_transform_caps);
trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_video_scale_set_caps);
}
static void
-gst_video_scale_init (GstVideoScale * videoscale, GstVideoScaleClass * klass)
+gst_video_scale_init (GstVideoScale * videoscale)
{
videoscale->tmp_buf = NULL;
videoscale->method = DEFAULT_PROP_METHOD;
static GstCaps *
gst_video_scale_transform_caps (GstBaseTransform * trans,
- GstPadDirection direction, GstCaps * caps)
+ GstPadDirection direction, GstCaps * caps, GstCaps * filter)
{
GstCaps *ret;
GstStructure *structure;
(direction == GST_PAD_SINK) ? "sink" : "src");
ret = gst_caps_copy (caps);
- structure = gst_structure_copy (gst_caps_get_structure (ret, 0));
+ structure = gst_caps_get_structure (ret, 0);
gst_structure_set (structure,
"width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
gst_structure_set (structure, "pixel-aspect-ratio", GST_TYPE_FRACTION_RANGE,
1, G_MAXINT, G_MAXINT, 1, NULL);
}
- gst_caps_append_structure (ret, structure);
+
+ 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);
static gboolean
gst_video_scale_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
- guint * size)
+ gsize * size)
{
GstVideoFormat format;
gint width, height;
gint method;
const guint8 *black = _get_black_for_format (videoscale->format);
gboolean add_borders;
+ guint8 *in_data, *out_data;
+ gsize in_size, out_size;
GST_OBJECT_LOCK (videoscale);
method = videoscale->method;
method = GST_VIDEO_SCALE_BILINEAR;
}
+ in_data = gst_buffer_map (in, &in_size, NULL, GST_MAP_READ);
+ out_data = gst_buffer_map (out, &out_size, NULL, GST_MAP_WRITE);
+
gst_video_scale_setup_vs_image (&src, videoscale->format, 0,
- videoscale->from_width, videoscale->from_height, 0, 0,
- GST_BUFFER_DATA (in));
+ videoscale->from_width, videoscale->from_height, 0, 0, in_data);
gst_video_scale_setup_vs_image (&dest, videoscale->format, 0,
videoscale->to_width, videoscale->to_height, videoscale->borders_w,
- videoscale->borders_h, GST_BUFFER_DATA (out));
+ videoscale->borders_h, out_data);
if (videoscale->format == GST_VIDEO_FORMAT_I420
|| videoscale->format == GST_VIDEO_FORMAT_YV12
|| videoscale->format == GST_VIDEO_FORMAT_Y42B
|| videoscale->format == GST_VIDEO_FORMAT_Y41B) {
gst_video_scale_setup_vs_image (&src_u, videoscale->format, 1,
- videoscale->from_width, videoscale->from_height, 0, 0,
- GST_BUFFER_DATA (in));
+ videoscale->from_width, videoscale->from_height, 0, 0, in_data);
gst_video_scale_setup_vs_image (&src_v, videoscale->format, 2,
- videoscale->from_width, videoscale->from_height, 0, 0,
- GST_BUFFER_DATA (in));
+ videoscale->from_width, videoscale->from_height, 0, 0, in_data);
gst_video_scale_setup_vs_image (&dest_u, videoscale->format, 1,
videoscale->to_width, videoscale->to_height, videoscale->borders_w,
- videoscale->borders_h, GST_BUFFER_DATA (out));
+ videoscale->borders_h, out_data);
gst_video_scale_setup_vs_image (&dest_v, videoscale->format, 2,
videoscale->to_width, videoscale->to_height, videoscale->borders_w,
- videoscale->borders_h, GST_BUFFER_DATA (out));
+ videoscale->borders_h, out_data);
}
switch (videoscale->format) {
}
GST_LOG_OBJECT (videoscale, "pushing buffer of %d bytes",
- GST_BUFFER_SIZE (out));
+ gst_buffer_get_size (out));
+
+done:
+ gst_buffer_unmap (in, in_data, in_size);
+ gst_buffer_unmap (out, out_data, out_size);
return ret;
GST_ELEMENT_ERROR (videoscale, STREAM, NOT_IMPLEMENTED, (NULL),
("Unsupported format %d for scaling method %d",
videoscale->format, method));
- return GST_FLOW_ERROR;
+ ret = GST_FLOW_ERROR;
+ goto done;
}
unknown_mode:
{
GST_ELEMENT_ERROR (videoscale, STREAM, NOT_IMPLEMENTED, (NULL),
("Unknown scaling method %d", videoscale->method));
- return GST_FLOW_ERROR;
+ ret = GST_FLOW_ERROR;
+ goto done;
}
}
};
-GST_BOILERPLATE (GstVideoTestSrc, gst_video_test_src, GstPushSrc,
- GST_TYPE_PUSH_SRC);
-
+#define gst_video_test_src_parent_class parent_class
+G_DEFINE_TYPE (GstVideoTestSrc, gst_video_test_src, GST_TYPE_PUSH_SRC);
static void gst_video_test_src_set_pattern (GstVideoTestSrc * videotestsrc,
int pattern_type);
static void gst_video_test_src_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
-static GstCaps *gst_video_test_src_getcaps (GstBaseSrc * bsrc);
+static GstCaps *gst_video_test_src_getcaps (GstBaseSrc * bsrc,
+ GstCaps * filter);
static gboolean gst_video_test_src_setcaps (GstBaseSrc * bsrc, GstCaps * caps);
static void gst_video_test_src_src_fixate (GstPad * pad, GstCaps * caps);
static GstFlowReturn gst_video_test_src_create (GstPushSrc * psrc,
GstBuffer ** buffer);
static gboolean gst_video_test_src_start (GstBaseSrc * basesrc);
+static gboolean gst_video_test_src_stop (GstBaseSrc * basesrc);
#define GST_TYPE_VIDEO_TEST_SRC_PATTERN (gst_video_test_src_pattern_get_type ())
static GType
}
static void
-gst_video_test_src_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_set_details_simple (element_class,
- "Video test source", "Source/Video",
- "Creates a test video stream", "David A. Schleef <ds@schleef.org>");
-
- gst_element_class_add_pad_template (element_class,
- gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
- gst_video_test_src_getcaps (NULL)));
-}
-
-static void
gst_video_test_src_class_init (GstVideoTestSrcClass * klass)
{
GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
GstBaseSrcClass *gstbasesrc_class;
GstPushSrcClass *gstpushsrc_class;
+ GstCaps *templ_caps;
gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
gstbasesrc_class = (GstBaseSrcClass *) klass;
gstpushsrc_class = (GstPushSrcClass *) klass;
G_MININT32, G_MAXINT32, DEFAULT_HORIZONTAL_SPEED,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ gst_element_class_set_details_simple (gstelement_class,
+ "Video test source", "Source/Video",
+ "Creates a test video stream", "David A. Schleef <ds@schleef.org>");
+
+ templ_caps = gst_video_test_src_getcaps (NULL, NULL);
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, templ_caps));
+ gst_caps_unref (templ_caps);
+
gstbasesrc_class->get_caps = gst_video_test_src_getcaps;
gstbasesrc_class->set_caps = gst_video_test_src_setcaps;
gstbasesrc_class->is_seekable = gst_video_test_src_is_seekable;
gstbasesrc_class->query = gst_video_test_src_query;
gstbasesrc_class->get_times = gst_video_test_src_get_times;
gstbasesrc_class->start = gst_video_test_src_start;
+ gstbasesrc_class->stop = gst_video_test_src_stop;
gstpushsrc_class->create = gst_video_test_src_create;
}
static void
-gst_video_test_src_init (GstVideoTestSrc * src, GstVideoTestSrcClass * g_class)
+gst_video_test_src_init (GstVideoTestSrc * src)
{
GstPad *pad = GST_BASE_SRC_PAD (src);
/* threadsafe because this gets called as the plugin is loaded */
static GstCaps *
-gst_video_test_src_getcaps (GstBaseSrc * bsrc)
+gst_video_test_src_getcaps (GstBaseSrc * bsrc, GstCaps * filter)
{
static GstCaps *capslist = NULL;
capslist = caps;
}
- return gst_caps_copy (capslist);
+ if (filter)
+ return gst_caps_intersect_full (filter, capslist, GST_CAPS_INTERSECT_FIRST);
+ else
+ return gst_caps_ref (capslist);
}
static gboolean
struct fourcc_list_struct *fourcc;
GstVideoTestSrc *videotestsrc;
GstVideoTestSrcColorSpec color_spec;
+ GstQuery *query;
+ GstBufferPool *pool;
+ guint size, min, max, prefix, alignment;
videotestsrc = GST_VIDEO_TEST_SRC (bsrc);
res = gst_video_test_src_parse_caps (caps, &width, &height,
&rate_numerator, &rate_denominator, &fourcc, &color_spec);
- if (res) {
- /* looks ok here */
- videotestsrc->fourcc = fourcc;
- videotestsrc->width = width;
- videotestsrc->height = height;
- videotestsrc->rate_numerator = rate_numerator;
- videotestsrc->rate_denominator = rate_denominator;
- videotestsrc->bpp = videotestsrc->fourcc->bitspp;
- videotestsrc->color_spec = color_spec;
-
- GST_DEBUG_OBJECT (videotestsrc, "size %dx%d, %d/%d fps",
- videotestsrc->width, videotestsrc->height,
- videotestsrc->rate_numerator, videotestsrc->rate_denominator);
+ if (!res)
+ goto parse_failed;
+
+ /* looks ok here */
+ videotestsrc->fourcc = fourcc;
+ videotestsrc->width = width;
+ videotestsrc->height = height;
+ videotestsrc->rate_numerator = rate_numerator;
+ videotestsrc->rate_denominator = rate_denominator;
+ videotestsrc->bpp = videotestsrc->fourcc->bitspp;
+ videotestsrc->color_spec = color_spec;
+
+ GST_DEBUG_OBJECT (videotestsrc, "size %dx%d, %d/%d fps",
+ videotestsrc->width, videotestsrc->height,
+ videotestsrc->rate_numerator, videotestsrc->rate_denominator);
+
+ /* find a pool for the negotiated caps now */
+ query = gst_query_new_allocation (caps, TRUE);
+
+ if (gst_pad_peer_query (bsrc->srcpad, query)) {
+ /* we got configuration from our peer, parse them */
+ gst_query_parse_allocation_params (query, &size, &min, &max, &prefix,
+ &alignment, &pool);
+ } else {
+ size = gst_video_test_src_get_size (videotestsrc, width, height);
+ min = max = 0;
+ prefix = 0;
+ alignment = 1;
+ pool = NULL;
+ }
+
+ 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, caps, size, min, max, prefix, 0,
+ alignment);
+ gst_buffer_pool_set_config (pool, config);
}
+
+ if (videotestsrc->pool)
+ gst_object_unref (videotestsrc->pool);
+ videotestsrc->pool = pool;
+
+ /* and activate */
+ gst_buffer_pool_set_active (pool, TRUE);
+
return res;
+
+ /* ERRORS */
+parse_failed:
+ {
+ GST_DEBUG_OBJECT (bsrc, "failed to parse caps");
+ return FALSE;
+ }
}
static gboolean
static gboolean
gst_video_test_src_do_seek (GstBaseSrc * bsrc, GstSegment * segment)
{
- GstClockTime time;
+ GstClockTime position;
GstVideoTestSrc *src;
src = GST_VIDEO_TEST_SRC (bsrc);
segment->time = segment->start;
- time = segment->last_stop;
+ position = segment->position;
- /* now move to the time indicated */
+ /* now move to the position indicated */
if (src->rate_numerator) {
- src->n_frames = gst_util_uint64_scale (time,
+ src->n_frames = gst_util_uint64_scale (position,
src->rate_numerator, src->rate_denominator * GST_SECOND);
} else {
src->n_frames = 0;
src->running_time = 0;
}
- g_assert (src->running_time <= time);
+ g_assert (src->running_time <= position);
return TRUE;
}
gst_video_test_src_create (GstPushSrc * psrc, GstBuffer ** buffer)
{
GstVideoTestSrc *src;
- gulong newsize, size;
+ gsize size;
GstBuffer *outbuf = NULL;
GstFlowReturn res;
GstClockTime next_time;
+ guint8 *data;
src = GST_VIDEO_TEST_SRC (psrc);
- if (G_UNLIKELY (src->fourcc == NULL))
+ if (G_UNLIKELY (src->pool == NULL))
goto not_negotiated;
/* 0 framerate and we are at the second frame, eos */
if (G_UNLIKELY (src->rate_numerator == 0 && src->n_frames == 1))
goto eos;
- newsize = gst_video_test_src_get_size (src, src->width, src->height);
-
- g_return_val_if_fail (newsize > 0, GST_FLOW_ERROR);
-
GST_LOG_OBJECT (src,
- "creating buffer of %lu bytes with %dx%d image for frame %d", newsize,
- src->width, src->height, (gint) src->n_frames);
-
- if (src->peer_alloc) {
- res =
- gst_pad_alloc_buffer_and_set_caps (GST_BASE_SRC_PAD (psrc),
- GST_BUFFER_OFFSET_NONE, newsize, GST_PAD_CAPS (GST_BASE_SRC_PAD (psrc)),
- &outbuf);
- if (res != GST_FLOW_OK)
- goto no_buffer;
-
- /* the buffer could have renegotiated, we need to discard any buffers of the
- * wrong size. */
- size = GST_BUFFER_SIZE (outbuf);
- newsize = gst_video_test_src_get_size (src, src->width, src->height);
-
- if (size != newsize) {
- gst_buffer_unref (outbuf);
- outbuf = NULL;
- }
- }
+ "creating buffer from pool for frame %d", (gint) src->n_frames);
- if (outbuf == NULL) {
- outbuf = gst_buffer_new_and_alloc (newsize);
- gst_buffer_set_caps (outbuf, GST_PAD_CAPS (GST_BASE_SRC_PAD (psrc)));
- }
+ res = gst_buffer_pool_acquire_buffer (src->pool, &outbuf, NULL);
+ if (res != GST_FLOW_OK)
+ goto no_buffer;
- memset (GST_BUFFER_DATA (outbuf), 0, GST_BUFFER_SIZE (outbuf));
+ data = gst_buffer_map (outbuf, &size, NULL, GST_MAP_WRITE);
+ memset (data, 0, size);
src->tmpline_u8 = g_malloc (src->width + 8);
src->tmpline = g_malloc ((src->width + 8) * 4);
src->tmpline2 = g_malloc ((src->width + 8) * 4);
- src->make_image (src, (void *) GST_BUFFER_DATA (outbuf),
- src->width, src->height);
+ src->make_image (src, (void *) data, src->width, src->height);
+ gst_buffer_unmap (outbuf, data, size);
g_free (src->tmpline);
g_free (src->tmpline2);
}
static gboolean
+gst_video_test_src_stop (GstBaseSrc * basesrc)
+{
+ GstVideoTestSrc *src = GST_VIDEO_TEST_SRC (basesrc);
+
+ /* deactivate */
+
+ if (src->pool) {
+ gst_buffer_pool_set_active (src->pool, FALSE);
+ gst_object_unref (src->pool);
+ }
+ src->pool = NULL;
+
+ return TRUE;
+}
+
+static gboolean
plugin_init (GstPlugin * plugin)
{
gst_videotestsrc_orc_init ();
gint rate_numerator;
gint rate_denominator;
+ /* the bufferpool */
+ GstBufferPool *pool;
+
/* private */
gint64 timestamp_offset; /* base offset */
GstClockTime running_time; /* total running time */
static void gst_volume_interface_init (GstImplementsInterfaceClass * klass);
static void gst_volume_mixer_init (GstMixerClass * iface);
-#define _init_interfaces(type) \
- { \
- static const GInterfaceInfo voliface_info = { \
- (GInterfaceInitFunc) gst_volume_interface_init, \
- NULL, \
- NULL \
- }; \
- static const GInterfaceInfo volmixer_info = { \
- (GInterfaceInitFunc) gst_volume_mixer_init, \
- NULL, \
- NULL \
- }; \
- static const GInterfaceInfo svol_info = { \
- NULL, \
- NULL, \
- NULL \
- }; \
- \
- g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE, \
- &voliface_info); \
- g_type_add_interface_static (type, GST_TYPE_MIXER, &volmixer_info); \
- g_type_add_interface_static (type, GST_TYPE_STREAM_VOLUME, &svol_info); \
- }
-
-GST_BOILERPLATE_FULL (GstVolume, gst_volume, GstAudioFilter,
- GST_TYPE_AUDIO_FILTER, _init_interfaces);
+#define gst_volume_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstVolume, gst_volume,
+ GST_TYPE_AUDIO_FILTER, G_IMPLEMENT_INTERFACE (GST_TYPE_IMPLEMENTS_INTERFACE,
+ gst_volume_interface_init);
+ G_IMPLEMENT_INTERFACE (GST_TYPE_MIXER, gst_volume_mixer_init);
+ G_IMPLEMENT_INTERFACE (GST_TYPE_STREAM_VOLUME, NULL));
static void volume_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
}
static void
-gst_volume_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
- GstAudioFilterClass *filter_class = GST_AUDIO_FILTER_CLASS (g_class);
- GstCaps *caps;
-
- gst_element_class_set_details_simple (element_class, "Volume",
- "Filter/Effect/Audio",
- "Set volume on audio/raw streams", "Andy Wingo <wingo@pobox.com>");
-
- caps = gst_caps_from_string (ALLOWED_CAPS);
- gst_audio_filter_class_add_pad_templates (filter_class, caps);
- gst_caps_unref (caps);
-}
-
-static void
gst_volume_class_init (GstVolumeClass * klass)
{
GObjectClass *gobject_class;
+ GstElementClass *element_class;
GstBaseTransformClass *trans_class;
GstAudioFilterClass *filter_class;
+ GstCaps *caps;
gobject_class = (GObjectClass *) klass;
+ element_class = (GstElementClass *) klass;
trans_class = (GstBaseTransformClass *) klass;
filter_class = (GstAudioFilterClass *) (klass);
0.0, VOLUME_MAX_DOUBLE, DEFAULT_PROP_VOLUME,
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+ gst_element_class_set_details_simple (element_class, "Volume",
+ "Filter/Effect/Audio",
+ "Set volume on audio/raw streams", "Andy Wingo <wingo@pobox.com>");
+
+ caps = gst_caps_from_string (ALLOWED_CAPS);
+ gst_audio_filter_class_add_pad_templates (filter_class, caps);
+ gst_caps_unref (caps);
+
trans_class->before_transform = GST_DEBUG_FUNCPTR (volume_before_transform);
trans_class->transform_ip = GST_DEBUG_FUNCPTR (volume_transform_ip);
trans_class->stop = GST_DEBUG_FUNCPTR (volume_stop);
}
static void
-gst_volume_init (GstVolume * self, GstVolumeClass * g_class)
+gst_volume_init (GstVolume * self)
{
GstMixerTrack *track = NULL;
{
GstVolume *self = GST_VOLUME (base);
guint8 *data;
- guint size;
+ gsize size;
GstControlSource *mute_csource, *volume_csource;
if (G_UNLIKELY (!self->negotiated))
GST_BUFFER_FLAG_IS_SET (outbuf, GST_BUFFER_FLAG_GAP))
return GST_FLOW_OK;
- data = GST_BUFFER_DATA (outbuf);
- size = GST_BUFFER_SIZE (outbuf);
+ data = gst_buffer_map (outbuf, &size, NULL, GST_MAP_READWRITE);
mute_csource = gst_object_get_control_source (G_OBJECT (self), "mute");
volume_csource = gst_object_get_control_source (G_OBJECT (self), "volume");
} else if (self->current_volume != 1.0) {
self->process (self, data, size);
}
+ gst_buffer_unmap (outbuf, data, size);
return GST_FLOW_OK;
GST_ELEMENT_ERROR (self, CORE, FAILED,
("Failed to get values from controller"), (NULL));
+ gst_buffer_unmap (outbuf, data, size);
return GST_FLOW_ERROR;
}
}
static void gst_v4lelement_init_interfaces (GType type);
-GST_BOILERPLATE_FULL (GstV4lElement, gst_v4lelement, GstPushSrc,
- GST_TYPE_PUSH_SRC, gst_v4lelement_init_interfaces);
+#define gst_v4lelement_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstV4lElement, gst_v4lelement,
+ GST_TYPE_PUSH_SRC, gst_v4lelement_init_interfaces (g_define_type_id));
static void gst_v4lelement_dispose (GObject * object);
static void gst_v4lelement_set_property (GObject * object,
GST_TYPE_PROPERTY_PROBE, &v4l_propertyprobe_info);
}
-
-static void
-gst_v4lelement_base_init (gpointer g_class)
-{
- GstV4lElementClass *klass = GST_V4LELEMENT_CLASS (g_class);
-
- klass->devices = NULL;
-
- GST_DEBUG_CATEGORY_INIT (v4lelement_debug, "v4lelement", 0,
- "V4L Base Class debug");
-}
-
static void
gst_v4lelement_class_init (GstV4lElementClass * klass)
{
gobject_class = (GObjectClass *) klass;
element_class = GST_ELEMENT_CLASS (klass);
+ GST_DEBUG_CATEGORY_INIT (v4lelement_debug, "v4lelement", 0,
+ "V4L Base Class debug");
+
gobject_class->set_property = gst_v4lelement_set_property;
gobject_class->get_property = gst_v4lelement_get_property;
gobject_class->dispose = gst_v4lelement_dispose;
g_param_spec_flags ("flags", "Flags", "Device type flags",
GST_TYPE_V4L_DEVICE_FLAGS, 0,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-
}
-
static void
-gst_v4lelement_init (GstV4lElement * v4lelement, GstV4lElementClass * klass)
+gst_v4lelement_init (GstV4lElement * v4lelement)
{
/* some default values */
v4lelement->video_fd = -1;
0};
if (!GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lmjpegsrc))) {
- return gst_caps_copy (gst_pad_get_pad_template_caps (pad));
+ return gst_pad_get_pad_template_caps (pad);
}
g_value_init (&fps, GST_TYPE_FRACTION);
PROP_TIMESTAMP_OFFSET
};
-
-GST_BOILERPLATE (GstV4lSrc, gst_v4lsrc, GstV4lElement, GST_TYPE_V4LELEMENT);
+#define gst_v4lsrc_parent_class parent_class
+G_DEFINE_TYPE (GstV4lSrc, gst_v4lsrc, GST_TYPE_V4LELEMENT);
static GstStaticPadTemplate v4l_src_template = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
static gboolean gst_v4lsrc_start (GstBaseSrc * src);
static gboolean gst_v4lsrc_stop (GstBaseSrc * src);
static gboolean gst_v4lsrc_set_caps (GstBaseSrc * src, GstCaps * caps);
-static GstCaps *gst_v4lsrc_get_caps (GstBaseSrc * src);
+static GstCaps *gst_v4lsrc_get_caps (GstBaseSrc * src, GstCaps * filter);
static GstFlowReturn gst_v4lsrc_create (GstPushSrc * src, GstBuffer ** out);
static gboolean gst_v4lsrc_query (GstBaseSrc * bsrc, GstQuery * query);
static void gst_v4lsrc_fixate (GstBaseSrc * bsrc, GstCaps * caps);
static void gst_v4lsrc_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec);
-
-static void
-gst_v4lsrc_base_init (gpointer g_class)
-{
- GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_set_details_simple (gstelement_class,
- "Video (video4linux/raw) Source", "Source/Video",
- "Reads raw frames from a video4linux device",
- "GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>");
-
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&v4l_src_template));
-}
-
static void
gst_v4lsrc_class_init (GstV4lSrcClass * klass)
{
GObjectClass *gobject_class;
+ GstElementClass *element_class;
GstBaseSrcClass *basesrc_class;
GstPushSrcClass *pushsrc_class;
gobject_class = (GObjectClass *) klass;
+ element_class = (GstElementClass *) klass;
basesrc_class = (GstBaseSrcClass *) klass;
pushsrc_class = (GstPushSrcClass *) klass;
+ GST_DEBUG_CATEGORY_INIT (v4lsrc_debug, "v4lsrc", 0, "V4L source element");
+
gobject_class->set_property = gst_v4lsrc_set_property;
gobject_class->get_property = gst_v4lsrc_get_property;
G_MININT64, G_MAXINT64, 0,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- GST_DEBUG_CATEGORY_INIT (v4lsrc_debug, "v4lsrc", 0, "V4L source element");
+ gst_element_class_set_details_simple (element_class,
+ "Video (video4linux/raw) Source", "Source/Video",
+ "Reads raw frames from a video4linux device",
+ "GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>");
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&v4l_src_template));
basesrc_class->get_caps = gst_v4lsrc_get_caps;
basesrc_class->set_caps = gst_v4lsrc_set_caps;
}
static void
-gst_v4lsrc_init (GstV4lSrc * v4lsrc, GstV4lSrcClass * klass)
+gst_v4lsrc_init (GstV4lSrc * v4lsrc)
{
v4lsrc->buffer_size = 0;
}
static GstCaps *
-gst_v4lsrc_get_caps (GstBaseSrc * src)
+gst_v4lsrc_get_caps (GstBaseSrc * src, GstCaps * filter)
{
GstCaps *list;
GstV4lSrc *v4lsrc = GST_V4LSRC (src);
GList *item;
if (!GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lsrc))) {
- return gst_v4lsrc_get_any_caps ();
+ GstCaps *caps, *intersection;
+
+ caps = gst_v4lsrc_get_any_caps ();
+ if (filter) {
+ intersection =
+ gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+ gst_caps_unref (caps);
+ caps = intersection;
+ }
+ return caps;
}
if (!v4lsrc->autoprobe) {
+ GstCaps *caps, *intersection;
+
/* FIXME: query current caps and return those, with _any appended */
- return gst_v4lsrc_get_any_caps ();
+ caps = gst_v4lsrc_get_any_caps ();
+ if (filter) {
+ intersection =
+ gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+ gst_caps_unref (caps);
+ caps = intersection;
+ }
+ return caps;
}
if (!v4lsrc->colorspaces) {
gst_caps_append (list, one);
}
+ if (filter) {
+ GstCaps *intersection;
+
+ intersection =
+ gst_caps_intersect_full (filter, list, GST_CAPS_INTERSECT_FIRST);
+ gst_caps_unref (list);
+ list = intersection;
+ }
+
return list;
}
}
}
-#define GST_TYPE_V4LSRC_BUFFER (gst_v4lsrc_buffer_get_type())
-#define GST_IS_V4LSRC_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4LSRC_BUFFER))
-#define GST_V4LSRC_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4LSRC_BUFFER, GstV4lSrcBuffer))
-
-typedef struct _GstV4lSrcBuffer
+typedef struct _GstMetaV4lSrc
{
- GstBuffer buffer;
+ GstMeta meta;
GstV4lSrc *v4lsrc;
-
gint num;
-} GstV4lSrcBuffer;
-
-static void gst_v4lsrc_buffer_class_init (gpointer g_class,
- gpointer class_data);
-static void gst_v4lsrc_buffer_init (GTypeInstance * instance, gpointer g_class);
-static void gst_v4lsrc_buffer_finalize (GstV4lSrcBuffer * v4lsrc_buffer);
+} GstMetaV4lSrc;
-static GstBufferClass *v4lbuffer_parent_class = NULL;
-
-static GType
-gst_v4lsrc_buffer_get_type (void)
-{
- static GType _gst_v4lsrc_buffer_type;
-
- if (G_UNLIKELY (_gst_v4lsrc_buffer_type == 0)) {
- static const GTypeInfo v4lsrc_buffer_info = {
- sizeof (GstBufferClass),
- NULL,
- NULL,
- gst_v4lsrc_buffer_class_init,
- NULL,
- NULL,
- sizeof (GstV4lSrcBuffer),
- 0,
- gst_v4lsrc_buffer_init,
- NULL
- };
- _gst_v4lsrc_buffer_type = g_type_register_static (GST_TYPE_BUFFER,
- "GstV4lSrcBuffer", &v4lsrc_buffer_info, 0);
- }
- return _gst_v4lsrc_buffer_type;
-}
+#define GST_META_V4LSRC_GET(buf) ((GstMetaV4lSrc *)gst_buffer_get_meta(buf,gst_meta_v4lsrc_get_info()))
+#define GST_META_V4LSRC_ADD(buf) ((GstMetaV4lSrc *)gst_buffer_add_meta(buf,gst_meta_v4lsrc_get_info(), NULL))
static void
-gst_v4lsrc_buffer_class_init (gpointer g_class, gpointer class_data)
+meta_v4lsrc_free (GstMetaV4lSrc * meta, GstBuffer * buffer)
{
- GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
-
- v4lbuffer_parent_class = g_type_class_peek_parent (g_class);
-
- mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
- gst_v4lsrc_buffer_finalize;
-}
-
-static void
-gst_v4lsrc_buffer_init (GTypeInstance * instance, gpointer g_class)
-{
-
-}
-
-static void
-gst_v4lsrc_buffer_finalize (GstV4lSrcBuffer * v4lsrc_buffer)
-{
- GstMiniObjectClass *miniobject_class;
GstV4lSrc *v4lsrc;
gint num;
- v4lsrc = v4lsrc_buffer->v4lsrc;
- num = v4lsrc_buffer->num;
+ v4lsrc = meta->v4lsrc;
+ num = meta->num;
- GST_LOG_OBJECT (v4lsrc, "freeing buffer %p for frame %d", v4lsrc_buffer, num);
+ GST_LOG_OBJECT (v4lsrc, "freeing buffer %p for frame %d", buffer, num);
/* only requeue if we still have an mmap buffer */
if (GST_V4LELEMENT (v4lsrc)->buffer) {
}
gst_object_unref (v4lsrc);
+}
- miniobject_class = (GstMiniObjectClass *) v4lbuffer_parent_class;
- miniobject_class->finalize (GST_MINI_OBJECT_CAST (v4lsrc_buffer));
+static const GstMetaInfo *
+gst_meta_v4lsrc_get_info (void)
+{
+ static const GstMetaInfo *meta_v4lsrc_info = NULL;
+
+ if (meta_v4lsrc_info == NULL) {
+ meta_v4lsrc_info = gst_meta_register ("GstMetaV4lSrc", "GstMetaV4lSrc",
+ sizeof (GstMetaV4lSrc),
+ (GstMetaInitFunction) NULL,
+ (GstMetaFreeFunction) meta_v4lsrc_free,
+ (GstMetaCopyFunction) NULL, (GstMetaTransformFunction) NULL);
+ }
+ return meta_v4lsrc_info;
}
+
/* Create a V4lSrc buffer from our mmap'd data area */
GstBuffer *
gst_v4lsrc_buffer_new (GstV4lSrc * v4lsrc, gint num)
{
+ GstMetaV4lSrc *meta;
GstClockTime duration, timestamp, latency;
GstBuffer *buf;
GstClock *clock;
if (!(gst_v4lsrc_get_fps (v4lsrc, &fps_n, &fps_d)))
return NULL;
- buf = (GstBuffer *) gst_mini_object_new (GST_TYPE_V4LSRC_BUFFER);
+ buf = gst_buffer_new ();
+
+ /* attach private metadata with the frame num and v4lsrc element */
+ meta = GST_META_V4LSRC_ADD (buf);
+ meta->num = num;
+ meta->v4lsrc = gst_object_ref (v4lsrc);
- GST_V4LSRC_BUFFER (buf)->num = num;
- GST_V4LSRC_BUFFER (buf)->v4lsrc = gst_object_ref (v4lsrc);
+ gst_buffer_take_memory (buf,
+ gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
+ gst_v4lsrc_get_buffer (v4lsrc, num), NULL, v4lsrc->buffer_size,
+ 0, v4lsrc->buffer_size));
- GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_READONLY);
- GST_BUFFER_DATA (buf) = gst_v4lsrc_get_buffer (v4lsrc, num);
- GST_BUFFER_SIZE (buf) = v4lsrc->buffer_size;
GST_BUFFER_OFFSET (buf) = v4lsrc->offset++;
GST_BUFFER_OFFSET_END (buf) = v4lsrc->offset;
plugin_LTLIBRARIES = libgstximagesink.la
-libgstximagesink_la_SOURCES = ximagesink.c ximage.c
+libgstximagesink_la_SOURCES = ximagesink.c ximage.c ximagepool.c
libgstximagesink_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(X_CFLAGS)
libgstximagesink_la_LIBADD = \
$(top_builddir)/gst-libs/gst/interfaces/libgstinterfaces-$(GST_MAJORMINOR).la \
libgstximagesink_la_DEPENDENCIES = $(top_builddir)/gst-libs/gst/video/libgstvideo-$(GST_MAJORMINOR).la
libgstximagesink_la_LIBTOOLFLAGS = --tag=disable-static
-noinst_HEADERS = ximagesink.h
+noinst_HEADERS = ximagesink.h ximagepool.h
* Boston, MA 02111-1307, USA.
*/
-
-
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "ximagesink.h"
+GST_DEBUG_CATEGORY (gst_debug_ximagepool);
GST_DEBUG_CATEGORY (gst_debug_ximagesink);
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE);
static gboolean
plugin_init (GstPlugin * plugin)
GST_DEBUG_CATEGORY_INIT (gst_debug_ximagesink, "ximagesink", 0,
"ximagesink element");
+ GST_DEBUG_CATEGORY_INIT (gst_debug_ximagepool, "ximagepool", 0,
+ "ximagepool object");
+
+ GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE");
return TRUE;
}
--- /dev/null
+/* GStreamer
+ * Copyright (C) <2005> Julien Moutte <julien@moutte.net>
+ *
+ * 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
+
+/* Object header */
+#include "ximagesink.h"
+
+/* Debugging category */
+#include <gst/gstinfo.h>
+
+GST_DEBUG_CATEGORY_EXTERN (gst_debug_ximagepool);
+#define GST_CAT_DEFAULT gst_debug_ximagepool
+
+static void gst_meta_ximage_free (GstMetaXImage * meta, GstBuffer * buffer);
+
+/* ximage metadata */
+const GstMetaInfo *
+gst_meta_ximage_get_info (void)
+{
+ static const GstMetaInfo *meta_ximage_info = NULL;
+
+ if (meta_ximage_info == NULL) {
+ meta_ximage_info = gst_meta_register ("GstMetaXImage", "GstMetaXImage",
+ sizeof (GstMetaXImage),
+ (GstMetaInitFunction) NULL,
+ (GstMetaFreeFunction) gst_meta_ximage_free,
+ (GstMetaCopyFunction) NULL, (GstMetaTransformFunction) NULL);
+ }
+ return meta_ximage_info;
+}
+
+/* X11 stuff */
+static gboolean error_caught = FALSE;
+
+static int
+gst_ximagesink_handle_xerror (Display * display, XErrorEvent * xevent)
+{
+ char error_msg[1024];
+
+ XGetErrorText (display, xevent->error_code, error_msg, 1024);
+ GST_DEBUG ("ximagesink triggered an XError. error: %s", error_msg);
+ error_caught = TRUE;
+ return 0;
+}
+
+GstMetaXImage *
+gst_buffer_add_meta_ximage (GstBuffer * buffer, GstXImageSink * ximagesink,
+ gint width, gint height)
+{
+ int (*handler) (Display *, XErrorEvent *);
+ gboolean success = FALSE;
+ GstXContext *xcontext;
+ GstMetaXImage *meta;
+
+ xcontext = ximagesink->xcontext;
+
+ meta =
+ (GstMetaXImage *) gst_buffer_add_meta (buffer, GST_META_INFO_XIMAGE,
+ NULL);
+#ifdef HAVE_XSHM
+ meta->SHMInfo.shmaddr = ((void *) -1);
+ meta->SHMInfo.shmid = -1;
+#endif
+ meta->width = width;
+ meta->height = height;
+ meta->sink = gst_object_ref (ximagesink);
+
+ GST_DEBUG_OBJECT (ximagesink, "creating image %p (%dx%d)", buffer,
+ meta->width, meta->height);
+
+ g_mutex_lock (ximagesink->x_lock);
+
+ /* Setting an error handler to catch failure */
+ error_caught = FALSE;
+ handler = XSetErrorHandler (gst_ximagesink_handle_xerror);
+
+#ifdef HAVE_XSHM
+ if (xcontext->use_xshm) {
+ meta->ximage = XShmCreateImage (xcontext->disp,
+ xcontext->visual,
+ xcontext->depth,
+ ZPixmap, NULL, &meta->SHMInfo, meta->width, meta->height);
+ if (!meta->ximage || error_caught) {
+ g_mutex_unlock (ximagesink->x_lock);
+
+ /* Reset error flag */
+ error_caught = FALSE;
+
+ /* Push a warning */
+ GST_ELEMENT_WARNING (ximagesink, RESOURCE, WRITE,
+ ("Failed to create output image buffer of %dx%d pixels",
+ meta->width, meta->height),
+ ("could not XShmCreateImage a %dx%d image",
+ meta->width, meta->height));
+
+ /* Retry without XShm */
+ ximagesink->xcontext->use_xshm = FALSE;
+
+ /* Hold X mutex again to try without XShm */
+ g_mutex_lock (ximagesink->x_lock);
+
+ goto no_xshm;
+ }
+
+ /* we have to use the returned bytes_per_line for our shm size */
+ meta->size = meta->ximage->bytes_per_line * meta->ximage->height;
+ GST_LOG_OBJECT (ximagesink,
+ "XShm image size is %" G_GSIZE_FORMAT ", width %d, stride %d",
+ meta->size, meta->width, meta->ximage->bytes_per_line);
+
+ /* get shared memory */
+ meta->SHMInfo.shmid = shmget (IPC_PRIVATE, meta->size, IPC_CREAT | 0777);
+ if (meta->SHMInfo.shmid == -1)
+ goto shmget_failed;
+
+ /* attach */
+ meta->SHMInfo.shmaddr = shmat (meta->SHMInfo.shmid, NULL, 0);
+ if (meta->SHMInfo.shmaddr == ((void *) -1))
+ goto shmat_failed;
+
+ /* now we can set up the image data */
+ meta->ximage->data = meta->SHMInfo.shmaddr;
+ meta->SHMInfo.readOnly = FALSE;
+
+ if (XShmAttach (xcontext->disp, &meta->SHMInfo) == 0)
+ goto xattach_failed;
+
+ XSync (xcontext->disp, FALSE);
+
+ /* Now that everyone has attached, we can delete the shared memory segment.
+ * This way, it will be deleted as soon as we detach later, and not
+ * leaked if we crash. */
+ shmctl (meta->SHMInfo.shmid, IPC_RMID, NULL);
+
+ GST_DEBUG_OBJECT (ximagesink, "XServer ShmAttached to 0x%x, id 0x%lx",
+ meta->SHMInfo.shmid, meta->SHMInfo.shmseg);
+ } else
+ no_xshm:
+#endif /* HAVE_XSHM */
+ {
+ guint allocsize;
+
+ meta->ximage = XCreateImage (xcontext->disp,
+ xcontext->visual,
+ xcontext->depth,
+ ZPixmap, 0, NULL, meta->width, meta->height, xcontext->bpp, 0);
+ if (!meta->ximage || error_caught)
+ goto create_failed;
+
+ /* upstream will assume that rowstrides are multiples of 4, but this
+ * doesn't always seem to be the case with XCreateImage() */
+ if ((meta->ximage->bytes_per_line % 4) != 0) {
+ GST_WARNING_OBJECT (ximagesink, "returned stride not a multiple of 4 as "
+ "usually assumed");
+ }
+
+ /* we have to use the returned bytes_per_line for our image size */
+ meta->size = meta->ximage->bytes_per_line * meta->ximage->height;
+
+ /* alloc a bit more for unexpected strides to avoid crashes upstream.
+ * FIXME: if we get an unrounded stride, the image will be displayed
+ * distorted, since all upstream elements assume a rounded stride */
+ allocsize =
+ GST_ROUND_UP_4 (meta->ximage->bytes_per_line) * meta->ximage->height;
+
+ meta->ximage->data = g_malloc (allocsize);
+ GST_LOG_OBJECT (ximagesink,
+ "non-XShm image size is %" G_GSIZE_FORMAT " (alloced: %u), width %d, "
+ "stride %d", meta->size, allocsize, meta->width,
+ meta->ximage->bytes_per_line);
+
+ XSync (xcontext->disp, FALSE);
+ }
+
+ /* Reset error handler */
+ error_caught = FALSE;
+ XSetErrorHandler (handler);
+
+ gst_buffer_take_memory (buffer,
+ gst_memory_new_wrapped (GST_MEMORY_FLAG_NO_SHARE, meta->ximage->data,
+ NULL, meta->size, 0, meta->size));
+
+ g_mutex_unlock (ximagesink->x_lock);
+
+ success = TRUE;
+
+beach:
+ if (!success)
+ meta = NULL;
+
+ return meta;
+
+ /* ERRORS */
+create_failed:
+ {
+ g_mutex_unlock (ximagesink->x_lock);
+ /* Reset error handler */
+ error_caught = FALSE;
+ XSetErrorHandler (handler);
+ /* Push an error */
+ GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE,
+ ("Failed to create output image buffer of %dx%d pixels",
+ meta->width, meta->height),
+ ("could not XShmCreateImage a %dx%d image", meta->width, meta->height));
+ goto beach;
+ }
+shmget_failed:
+ {
+ g_mutex_unlock (ximagesink->x_lock);
+ GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE,
+ ("Failed to create output image buffer of %dx%d pixels",
+ meta->width, meta->height),
+ ("could not get shared memory of %" G_GSIZE_FORMAT " bytes",
+ meta->size));
+ goto beach;
+ }
+shmat_failed:
+ {
+ g_mutex_unlock (ximagesink->x_lock);
+ GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE,
+ ("Failed to create output image buffer of %dx%d pixels",
+ meta->width, meta->height),
+ ("Failed to shmat: %s", g_strerror (errno)));
+ /* Clean up the shared memory segment */
+ shmctl (meta->SHMInfo.shmid, IPC_RMID, NULL);
+ goto beach;
+ }
+xattach_failed:
+ {
+ /* Clean up the shared memory segment */
+ shmctl (meta->SHMInfo.shmid, IPC_RMID, NULL);
+ g_mutex_unlock (ximagesink->x_lock);
+
+ GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE,
+ ("Failed to create output image buffer of %dx%d pixels",
+ meta->width, meta->height), ("Failed to XShmAttach"));
+ goto beach;
+ }
+}
+
+static void
+gst_meta_ximage_free (GstMetaXImage * meta, GstBuffer * buffer)
+{
+ GstXImageSink *ximagesink;
+
+ ximagesink = meta->sink;
+
+ GST_DEBUG_OBJECT (ximagesink, "free meta on buffer %p", buffer);
+
+ /* Hold the object lock to ensure the XContext doesn't disappear */
+ GST_OBJECT_LOCK (ximagesink);
+ /* We might have some buffers destroyed after changing state to NULL */
+ if (ximagesink->xcontext == NULL) {
+ GST_DEBUG_OBJECT (ximagesink, "Destroying XImage after XContext");
+#ifdef HAVE_XSHM
+ /* Need to free the shared memory segment even if the x context
+ * was already cleaned up */
+ if (meta->SHMInfo.shmaddr != ((void *) -1)) {
+ shmdt (meta->SHMInfo.shmaddr);
+ }
+#endif
+ goto beach;
+ }
+
+ g_mutex_lock (ximagesink->x_lock);
+
+#ifdef HAVE_XSHM
+ if (ximagesink->xcontext->use_xshm) {
+ if (meta->SHMInfo.shmaddr != ((void *) -1)) {
+ GST_DEBUG_OBJECT (ximagesink, "XServer ShmDetaching from 0x%x id 0x%lx",
+ meta->SHMInfo.shmid, meta->SHMInfo.shmseg);
+ XShmDetach (ximagesink->xcontext->disp, &meta->SHMInfo);
+ XSync (ximagesink->xcontext->disp, FALSE);
+ shmdt (meta->SHMInfo.shmaddr);
+ meta->SHMInfo.shmaddr = (void *) -1;
+ }
+ if (meta->ximage)
+ XDestroyImage (meta->ximage);
+ } else
+#endif /* HAVE_XSHM */
+ {
+ if (meta->ximage) {
+ XDestroyImage (meta->ximage);
+ }
+ }
+
+ XSync (ximagesink->xcontext->disp, FALSE);
+
+ g_mutex_unlock (ximagesink->x_lock);
+
+beach:
+ GST_OBJECT_UNLOCK (ximagesink);
+
+ gst_object_unref (meta->sink);
+}
+
+GstBuffer *
+gst_ximage_buffer_new (GstXImageSink * ximagesink, gint width, gint height)
+{
+ GstBuffer *buffer;
+ GstMetaXImage *meta;
+
+ buffer = gst_buffer_new ();
+ meta = gst_buffer_add_meta_ximage (buffer, ximagesink, width, height);
+ if (meta == NULL) {
+ gst_buffer_unref (buffer);
+ buffer = NULL;
+ }
+ return buffer;
+}
+
+#ifdef HAVE_XSHM
+/* This function checks that it is actually really possible to create an image
+ using XShm */
+gboolean
+gst_ximagesink_check_xshm_calls (GstXImageSink * ximagesink,
+ GstXContext * xcontext)
+{
+ XImage *ximage;
+ XShmSegmentInfo SHMInfo;
+ size_t size;
+ int (*handler) (Display *, XErrorEvent *);
+ gboolean result = FALSE;
+ gboolean did_attach = FALSE;
+
+ g_return_val_if_fail (xcontext != NULL, FALSE);
+
+ /* Sync to ensure any older errors are already processed */
+ XSync (xcontext->disp, FALSE);
+
+ /* Set defaults so we don't free these later unnecessarily */
+ SHMInfo.shmaddr = ((void *) -1);
+ SHMInfo.shmid = -1;
+
+ /* Setting an error handler to catch failure */
+ error_caught = FALSE;
+ handler = XSetErrorHandler (gst_ximagesink_handle_xerror);
+
+ /* Trying to create a 1x1 ximage */
+ GST_DEBUG ("XShmCreateImage of 1x1");
+
+ ximage = XShmCreateImage (xcontext->disp, xcontext->visual,
+ xcontext->depth, ZPixmap, NULL, &SHMInfo, 1, 1);
+
+ /* Might cause an error, sync to ensure it is noticed */
+ XSync (xcontext->disp, FALSE);
+ if (!ximage || error_caught) {
+ GST_WARNING ("could not XShmCreateImage a 1x1 image");
+ goto beach;
+ }
+ size = ximage->height * ximage->bytes_per_line;
+
+ SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777);
+ if (SHMInfo.shmid == -1) {
+ GST_WARNING ("could not get shared memory of %" G_GSIZE_FORMAT " bytes",
+ size);
+ goto beach;
+ }
+
+ SHMInfo.shmaddr = shmat (SHMInfo.shmid, NULL, 0);
+ if (SHMInfo.shmaddr == ((void *) -1)) {
+ GST_WARNING ("Failed to shmat: %s", g_strerror (errno));
+ /* Clean up the shared memory segment */
+ shmctl (SHMInfo.shmid, IPC_RMID, NULL);
+ goto beach;
+ }
+
+ ximage->data = SHMInfo.shmaddr;
+ SHMInfo.readOnly = FALSE;
+
+ if (XShmAttach (xcontext->disp, &SHMInfo) == 0) {
+ GST_WARNING ("Failed to XShmAttach");
+ /* Clean up the shared memory segment */
+ shmctl (SHMInfo.shmid, IPC_RMID, NULL);
+ goto beach;
+ }
+
+ /* Sync to ensure we see any errors we caused */
+ XSync (xcontext->disp, FALSE);
+
+ /* Delete the shared memory segment as soon as everyone is attached.
+ * This way, it will be deleted as soon as we detach later, and not
+ * leaked if we crash. */
+ shmctl (SHMInfo.shmid, IPC_RMID, NULL);
+
+ if (!error_caught) {
+ GST_DEBUG ("XServer ShmAttached to 0x%x, id 0x%lx", SHMInfo.shmid,
+ SHMInfo.shmseg);
+
+ did_attach = TRUE;
+ /* store whether we succeeded in result */
+ result = TRUE;
+ } else {
+ GST_WARNING ("MIT-SHM extension check failed at XShmAttach. "
+ "Not using shared memory.");
+ }
+
+beach:
+ /* Sync to ensure we swallow any errors we caused and reset error_caught */
+ XSync (xcontext->disp, FALSE);
+
+ error_caught = FALSE;
+ XSetErrorHandler (handler);
+
+ if (did_attach) {
+ GST_DEBUG ("XServer ShmDetaching from 0x%x id 0x%lx",
+ SHMInfo.shmid, SHMInfo.shmseg);
+ XShmDetach (xcontext->disp, &SHMInfo);
+ XSync (xcontext->disp, FALSE);
+ }
+ if (SHMInfo.shmaddr != ((void *) -1))
+ shmdt (SHMInfo.shmaddr);
+ if (ximage)
+ XDestroyImage (ximage);
+ return result;
+}
+#endif /* HAVE_XSHM */
+
+/* bufferpool */
+static void gst_ximage_buffer_pool_finalize (GObject * object);
+
+#define GST_XIMAGE_BUFFER_POOL_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_XIMAGE_BUFFER_POOL, GstXImageBufferPoolPrivate))
+
+struct _GstXImageBufferPoolPrivate
+{
+ GstCaps *caps;
+ gint width, height;
+};
+
+G_DEFINE_TYPE (GstXImageBufferPool, gst_ximage_buffer_pool,
+ GST_TYPE_BUFFER_POOL);
+
+static gboolean
+ximage_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config)
+{
+ GstXImageBufferPool *xpool = GST_XIMAGE_BUFFER_POOL_CAST (pool);
+ GstXImageBufferPoolPrivate *priv = xpool->priv;
+ GstStructure *structure;
+ gint width, height;
+ const GstCaps *caps;
+
+ if (!gst_buffer_pool_config_get (config, &caps, NULL, NULL, NULL, NULL,
+ NULL, NULL))
+ goto wrong_config;
+
+ if (caps == NULL)
+ goto no_caps;
+
+ /* now parse the caps from the config */
+ structure = gst_caps_get_structure (caps, 0);
+
+ if (!gst_structure_get_int (structure, "width", &width) ||
+ !gst_structure_get_int (structure, "height", &height))
+ goto wrong_caps;
+
+ GST_LOG_OBJECT (pool, "%dx%d, caps %" GST_PTR_FORMAT, width, height, caps);
+
+ /* keep track of the width and height and caps */
+ if (priv->caps)
+ gst_caps_unref (priv->caps);
+ priv->caps = gst_caps_copy (caps);
+ priv->width = width;
+ priv->height = height;
+
+ return TRUE;
+
+ /* ERRORS */
+wrong_config:
+ {
+ GST_WARNING_OBJECT (pool, "invalid config");
+ return FALSE;
+ }
+no_caps:
+ {
+ GST_WARNING_OBJECT (pool, "no caps in config");
+ return FALSE;
+ }
+wrong_caps:
+ {
+ GST_WARNING_OBJECT (pool,
+ "failed getting geometry from caps %" GST_PTR_FORMAT, caps);
+ return FALSE;
+ }
+}
+
+/* This function handles GstXImageBuffer creation depending on XShm availability */
+static GstFlowReturn
+ximage_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer,
+ GstBufferPoolParams * params)
+{
+ GstXImageBufferPool *xpool = GST_XIMAGE_BUFFER_POOL_CAST (pool);
+ GstXImageBufferPoolPrivate *priv = xpool->priv;
+ GstBuffer *ximage;
+
+ ximage = gst_ximage_buffer_new (xpool->sink, priv->width, priv->height);
+ if (ximage == NULL)
+ goto no_buffer;
+
+ *buffer = ximage;
+
+ return GST_FLOW_OK;
+
+ /* ERROR */
+no_buffer:
+ {
+ GST_WARNING_OBJECT (pool, "can't create image");
+ return GST_FLOW_ERROR;
+ }
+}
+
+static void
+ximage_buffer_pool_free (GstBufferPool * pool, GstBuffer * buffer)
+{
+ gst_buffer_unref (buffer);
+}
+
+GstBufferPool *
+gst_ximage_buffer_pool_new (GstXImageSink * ximagesink)
+{
+ GstXImageBufferPool *pool;
+
+ g_return_val_if_fail (GST_IS_XIMAGESINK (ximagesink), NULL);
+
+ pool = g_object_new (GST_TYPE_XIMAGE_BUFFER_POOL, NULL);
+ pool->sink = gst_object_ref (ximagesink);
+
+ GST_LOG_OBJECT (pool, "new XImage buffer pool %p", pool);
+
+ return GST_BUFFER_POOL_CAST (pool);
+}
+
+static void
+gst_ximage_buffer_pool_class_init (GstXImageBufferPoolClass * klass)
+{
+ GObjectClass *gobject_class = (GObjectClass *) klass;
+ GstBufferPoolClass *gstbufferpool_class = (GstBufferPoolClass *) klass;
+
+ g_type_class_add_private (klass, sizeof (GstXImageBufferPoolPrivate));
+
+ gobject_class->finalize = gst_ximage_buffer_pool_finalize;
+
+ gstbufferpool_class->set_config = ximage_buffer_pool_set_config;
+ gstbufferpool_class->alloc_buffer = ximage_buffer_pool_alloc;
+ gstbufferpool_class->free_buffer = ximage_buffer_pool_free;
+}
+
+static void
+gst_ximage_buffer_pool_init (GstXImageBufferPool * pool)
+{
+ pool->priv = GST_XIMAGE_BUFFER_POOL_GET_PRIVATE (pool);
+}
+
+static void
+gst_ximage_buffer_pool_finalize (GObject * object)
+{
+ GstXImageBufferPool *pool = GST_XIMAGE_BUFFER_POOL_CAST (object);
+ GstXImageBufferPoolPrivate *priv = pool->priv;
+
+ GST_LOG_OBJECT (pool, "finalize XImage buffer pool %p", pool);
+
+ if (priv->caps)
+ gst_caps_unref (priv->caps);
+ gst_object_unref (pool->sink);
+
+ G_OBJECT_CLASS (gst_ximage_buffer_pool_parent_class)->finalize (object);
+}
--- /dev/null
+/* GStreamer
+ * Copyright (C) <2005> Julien Moutte <julien@moutte.net>
+ *
+ * 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_XIMAGEPOOL_H__
+#define __GST_XIMAGEPOOL_H__
+
+#ifdef HAVE_XSHM
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#endif /* HAVE_XSHM */
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#ifdef HAVE_XSHM
+#include <X11/extensions/XShm.h>
+#endif /* HAVE_XSHM */
+
+#include <string.h>
+#include <math.h>
+
+
+G_BEGIN_DECLS
+
+typedef struct _GstMetaXImage GstMetaXImage;
+
+typedef struct _GstXImageBufferPool GstXImageBufferPool;
+typedef struct _GstXImageBufferPoolClass GstXImageBufferPoolClass;
+typedef struct _GstXImageBufferPoolPrivate GstXImageBufferPoolPrivate;
+
+#include "ximagesink.h"
+
+const GstMetaInfo * gst_meta_ximage_get_info (void);
+#define GST_META_INFO_XIMAGE (gst_meta_ximage_get_info())
+
+#define gst_buffer_get_meta_ximage(b) ((GstMetaXImage*)gst_buffer_get_meta((b),GST_META_INFO_XIMAGE))
+GstMetaXImage * gst_buffer_add_meta_ximage (GstBuffer *buffer, GstXImageSink * ximagesink,
+ gint width, gint height);
+
+/**
+ * GstMetaXImage:
+ * @simagesink: a reference to the our #GstXImageSink
+ * @ximage: the XImage of this buffer
+ * @width: the width in pixels of XImage @ximage
+ * @height: the height in pixels of XImage @ximage
+ * @size: the size in bytes of XImage @ximage
+ *
+ * Subclass of #GstMeta containing additional information about an XImage.
+ */
+struct _GstMetaXImage
+{
+ GstMeta meta;
+
+ /* Reference to the ximagesink we belong to */
+ GstXImageSink *sink;
+
+ XImage *ximage;
+
+#ifdef HAVE_XSHM
+ XShmSegmentInfo SHMInfo;
+#endif /* HAVE_XSHM */
+
+ gint width, height;
+ size_t size;
+};
+
+GstBuffer * gst_ximage_buffer_new (GstXImageSink *ximagesink, gint width, gint height);
+
+/* buffer pool functions */
+#define GST_TYPE_XIMAGE_BUFFER_POOL (gst_ximage_buffer_pool_get_type())
+#define GST_IS_XIMAGE_BUFFER_POOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_XIMAGE_BUFFER_POOL))
+#define GST_XIMAGE_BUFFER_POOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_XIMAGE_BUFFER_POOL, GstXImageBufferPool))
+#define GST_XIMAGE_BUFFER_POOL_CAST(obj) ((GstXImageBufferPool*)(obj))
+
+struct _GstXImageBufferPool
+{
+ GstBufferPool bufferpool;
+
+ GstXImageSink *sink;
+
+ GstXImageBufferPoolPrivate *priv;
+};
+
+struct _GstXImageBufferPoolClass
+{
+ GstBufferPoolClass parent_class;
+};
+
+GType gst_ximage_buffer_pool_get_type (void);
+
+GstBufferPool * gst_ximage_buffer_pool_new (GstXImageSink * ximagesink);
+
+gboolean gst_ximagesink_check_xshm_calls (GstXImageSink * ximagesink,
+ GstXContext * xcontext);
+
+G_END_DECLS
+
+#endif /* __GST_XIMAGEPOOL_H__ */
#include <gst/interfaces/navigation.h>
#include <gst/interfaces/xoverlay.h>
+#include <gst/video/gstmetavideo.h>
+
/* Object header */
#include "ximagesink.h"
#define MWM_HINTS_DECORATIONS (1L << 1)
static void gst_ximagesink_reset (GstXImageSink * ximagesink);
-static void gst_ximagesink_ximage_destroy (GstXImageSink * ximagesink,
- GstXImageBuffer * ximage);
static void gst_ximagesink_xwindow_update_geometry (GstXImageSink * ximagesink);
static void gst_ximagesink_expose (GstXOverlay * overlay);
PROP_WINDOW_HEIGHT
};
-static GstVideoSinkClass *parent_class = NULL;
-
/* ============================================================= */
/* */
-/* Private Methods */
+/* Public Methods */
/* */
/* ============================================================= */
-/* ximage buffers */
-
-static GstBufferClass *ximage_buffer_parent_class = NULL;
-
-#define GST_TYPE_XIMAGE_BUFFER (gst_ximage_buffer_get_type())
-
-#define GST_IS_XIMAGE_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_XIMAGE_BUFFER))
-#define GST_XIMAGE_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_XIMAGE_BUFFER, GstXImageBuffer))
-#define GST_XIMAGE_BUFFER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_XIMAGE_BUFFER, GstXImageBufferClass))
-
-/* So some words about GstMiniObject, this is pretty messy...
- GstMiniObject does not use the standard finalizing of GObjects, you are
- supposed to call gst_buffer_unref that's going to call gst_mini_objec_unref
- which will handle its own refcount system and call gst_mini_object_free.
- gst_mini_object_free will call the class finalize method which is not the
- one from GObject, after calling this finalize method it will free the object
- instance for you if the refcount is still 0 so you should not chain up */
-static void
-gst_ximage_buffer_finalize (GstXImageBuffer * ximage)
-{
- GstXImageSink *ximagesink = NULL;
- gboolean recycled = FALSE;
- gboolean running;
-
- g_return_if_fail (ximage != NULL);
-
- ximagesink = ximage->ximagesink;
- if (G_UNLIKELY (ximagesink == NULL)) {
- GST_WARNING_OBJECT (ximagesink, "no sink found");
- goto beach;
- }
-
- GST_OBJECT_LOCK (ximagesink);
- running = ximagesink->running;
- GST_OBJECT_UNLOCK (ximagesink);
-
- if (running == FALSE) {
- /* If the sink is shutting down, need to clear the image */
- GST_DEBUG_OBJECT (ximagesink,
- "destroy image %p because the sink is shutting down", ximage);
- gst_ximagesink_ximage_destroy (ximagesink, ximage);
- } else if ((ximage->width != GST_VIDEO_SINK_WIDTH (ximagesink)) ||
- (ximage->height != GST_VIDEO_SINK_HEIGHT (ximagesink))) {
- /* If our geometry changed we can't reuse that image. */
- GST_DEBUG_OBJECT (ximagesink,
- "destroy image %p as its size changed %dx%d vs current %dx%d",
- ximage, ximage->width, ximage->height,
- GST_VIDEO_SINK_WIDTH (ximagesink), GST_VIDEO_SINK_HEIGHT (ximagesink));
- gst_ximagesink_ximage_destroy (ximagesink, ximage);
- } else {
- /* In that case we can reuse the image and add it to our image pool. */
- GST_LOG_OBJECT (ximagesink, "recycling image %p in pool", ximage);
- /* need to increment the refcount again to recycle */
- gst_buffer_ref (GST_BUFFER_CAST (ximage));
- g_mutex_lock (ximagesink->pool_lock);
- ximagesink->buffer_pool = g_slist_prepend (ximagesink->buffer_pool, ximage);
- g_mutex_unlock (ximagesink->pool_lock);
- recycled = TRUE;
- }
-
- if (!recycled)
- GST_MINI_OBJECT_CLASS (ximage_buffer_parent_class)->finalize
- (GST_MINI_OBJECT (ximage));
-
-beach:
- return;
-}
-
-static void
-gst_ximage_buffer_free (GstXImageBuffer * ximage)
-{
- /* make sure it is not recycled */
- ximage->width = -1;
- ximage->height = -1;
- gst_buffer_unref (GST_BUFFER_CAST (ximage));
-}
-
-static void
-gst_ximage_buffer_init (GstXImageBuffer * ximage_buffer, gpointer g_class)
-{
-#ifdef HAVE_XSHM
- ximage_buffer->SHMInfo.shmaddr = ((void *) -1);
- ximage_buffer->SHMInfo.shmid = -1;
-#endif
-}
-
-static void
-gst_ximage_buffer_class_init (gpointer g_class, gpointer class_data)
-{
- GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
-
- ximage_buffer_parent_class = g_type_class_peek_parent (g_class);
-
- mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
- gst_ximage_buffer_finalize;
-}
+/* =========================================== */
+/* */
+/* Object typing & Creation */
+/* */
+/* =========================================== */
+static void gst_ximagesink_interface_init (GstImplementsInterfaceClass * klass);
+static void gst_ximagesink_navigation_init (GstNavigationInterface * klass);
+static void gst_ximagesink_xoverlay_init (GstXOverlayClass * klass);
+#define gst_ximagesink_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstXImageSink, gst_ximagesink, GST_TYPE_VIDEO_SINK,
+ G_IMPLEMENT_INTERFACE (GST_TYPE_IMPLEMENTS_INTERFACE,
+ gst_ximagesink_interface_init);
+ G_IMPLEMENT_INTERFACE (GST_TYPE_NAVIGATION, gst_ximagesink_navigation_init);
+ G_IMPLEMENT_INTERFACE (GST_TYPE_X_OVERLAY, gst_ximagesink_xoverlay_init));
-static GType
-gst_ximage_buffer_get_type (void)
-{
- static GType _gst_ximage_buffer_type;
-
- if (G_UNLIKELY (_gst_ximage_buffer_type == 0)) {
- static const GTypeInfo ximage_buffer_info = {
- sizeof (GstBufferClass),
- NULL,
- NULL,
- gst_ximage_buffer_class_init,
- NULL,
- NULL,
- sizeof (GstXImageBuffer),
- 0,
- (GInstanceInitFunc) gst_ximage_buffer_init,
- NULL
- };
- _gst_ximage_buffer_type = g_type_register_static (GST_TYPE_BUFFER,
- "GstXImageBuffer", &ximage_buffer_info, 0);
- }
- return _gst_ximage_buffer_type;
-}
+/* ============================================================= */
+/* */
+/* Private Methods */
+/* */
+/* ============================================================= */
/* X11 stuff */
-static gboolean error_caught = FALSE;
-
-static int
-gst_ximagesink_handle_xerror (Display * display, XErrorEvent * xevent)
-{
- char error_msg[1024];
-
- XGetErrorText (display, xevent->error_code, error_msg, 1024);
- GST_DEBUG ("ximagesink triggered an XError. error: %s", error_msg);
- error_caught = TRUE;
- return 0;
-}
-
-#ifdef HAVE_XSHM /* Check that XShm calls actually work */
-
-static gboolean
-gst_ximagesink_check_xshm_calls (GstXImageSink * ximagesink,
- GstXContext * xcontext)
-{
- XImage *ximage;
- XShmSegmentInfo SHMInfo;
- size_t size;
- int (*handler) (Display *, XErrorEvent *);
- gboolean result = FALSE;
- gboolean did_attach = FALSE;
-
- g_return_val_if_fail (xcontext != NULL, FALSE);
-
- /* Sync to ensure any older errors are already processed */
- XSync (xcontext->disp, FALSE);
-
- /* Set defaults so we don't free these later unnecessarily */
- SHMInfo.shmaddr = ((void *) -1);
- SHMInfo.shmid = -1;
-
- /* Setting an error handler to catch failure */
- error_caught = FALSE;
- handler = XSetErrorHandler (gst_ximagesink_handle_xerror);
-
- /* Trying to create a 1x1 ximage */
- GST_DEBUG ("XShmCreateImage of 1x1");
-
- ximage = XShmCreateImage (xcontext->disp, xcontext->visual,
- xcontext->depth, ZPixmap, NULL, &SHMInfo, 1, 1);
-
- /* Might cause an error, sync to ensure it is noticed */
- XSync (xcontext->disp, FALSE);
- if (!ximage || error_caught) {
- GST_WARNING ("could not XShmCreateImage a 1x1 image");
- goto beach;
- }
- size = ximage->height * ximage->bytes_per_line;
-
- SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777);
- if (SHMInfo.shmid == -1) {
- GST_WARNING ("could not get shared memory of %" G_GSIZE_FORMAT " bytes",
- size);
- goto beach;
- }
-
- SHMInfo.shmaddr = shmat (SHMInfo.shmid, NULL, 0);
- if (SHMInfo.shmaddr == ((void *) -1)) {
- GST_WARNING ("Failed to shmat: %s", g_strerror (errno));
- /* Clean up shm seg */
- shmctl (SHMInfo.shmid, IPC_RMID, NULL);
- goto beach;
- }
-
- ximage->data = SHMInfo.shmaddr;
- SHMInfo.readOnly = FALSE;
-
- if (XShmAttach (xcontext->disp, &SHMInfo) == 0) {
- GST_WARNING ("Failed to XShmAttach");
- /* Clean up shm seg */
- shmctl (SHMInfo.shmid, IPC_RMID, NULL);
- goto beach;
- }
-
- /* Sync to ensure we see any errors we caused */
- XSync (xcontext->disp, FALSE);
-
- /* Delete the shared memory segment as soon as everyone is attached.
- * This way, it will be deleted as soon as we detach later, and not
- * leaked if we crash. */
- shmctl (SHMInfo.shmid, IPC_RMID, NULL);
-
- if (!error_caught) {
- did_attach = TRUE;
- /* store whether we succeeded in result */
- result = TRUE;
- }
-
-beach:
- /* Sync to ensure we swallow any errors we caused and reset error_caught */
- XSync (xcontext->disp, FALSE);
- error_caught = FALSE;
- XSetErrorHandler (handler);
-
- if (did_attach) {
- XShmDetach (xcontext->disp, &SHMInfo);
- XSync (xcontext->disp, FALSE);
- }
- if (SHMInfo.shmaddr != ((void *) -1))
- shmdt (SHMInfo.shmaddr);
- if (ximage)
- XDestroyImage (ximage);
- return result;
-}
-#endif /* HAVE_XSHM */
-
-/* This function handles GstXImageBuffer creation depending on XShm availability */
-static GstXImageBuffer *
-gst_ximagesink_ximage_new (GstXImageSink * ximagesink, GstCaps * caps)
-{
- GstXImageBuffer *ximage = NULL;
- GstStructure *structure = NULL;
- gboolean succeeded = FALSE;
- int (*handler) (Display *, XErrorEvent *);
-
- g_return_val_if_fail (GST_IS_XIMAGESINK (ximagesink), NULL);
-
- ximage = (GstXImageBuffer *) gst_mini_object_new (GST_TYPE_XIMAGE_BUFFER);
-
- structure = gst_caps_get_structure (caps, 0);
-
- if (!gst_structure_get_int (structure, "width", &ximage->width) ||
- !gst_structure_get_int (structure, "height", &ximage->height)) {
- GST_WARNING ("failed getting geometry from caps %" GST_PTR_FORMAT, caps);
- }
-
- GST_DEBUG_OBJECT (ximagesink, "creating image %p (%dx%d)", ximage,
- ximage->width, ximage->height);
-
- g_mutex_lock (ximagesink->x_lock);
-
- /* Setting an error handler to catch failure */
- error_caught = FALSE;
- handler = XSetErrorHandler (gst_ximagesink_handle_xerror);
-
-#ifdef HAVE_XSHM
- if (ximagesink->xcontext->use_xshm) {
- ximage->ximage = XShmCreateImage (ximagesink->xcontext->disp,
- ximagesink->xcontext->visual,
- ximagesink->xcontext->depth,
- ZPixmap, NULL, &ximage->SHMInfo, ximage->width, ximage->height);
- if (!ximage->ximage || error_caught) {
- g_mutex_unlock (ximagesink->x_lock);
-
- /* Reset error flag */
- error_caught = FALSE;
-
- /* Push a warning */
- GST_ELEMENT_WARNING (ximagesink, RESOURCE, WRITE,
- ("Failed to create output image buffer of %dx%d pixels",
- ximage->width, ximage->height),
- ("could not XShmCreateImage a %dx%d image",
- ximage->width, ximage->height));
-
- /* Retry without XShm */
- ximagesink->xcontext->use_xshm = FALSE;
-
- /* Hold X mutex again to try without XShm */
- g_mutex_lock (ximagesink->x_lock);
- goto no_xshm;
- }
-
- /* we have to use the returned bytes_per_line for our shm size */
- ximage->size = ximage->ximage->bytes_per_line * ximage->ximage->height;
- GST_LOG_OBJECT (ximagesink,
- "XShm image size is %" G_GSIZE_FORMAT ", width %d, stride %d",
- ximage->size, ximage->width, ximage->ximage->bytes_per_line);
-
- ximage->SHMInfo.shmid = shmget (IPC_PRIVATE, ximage->size,
- IPC_CREAT | 0777);
- if (ximage->SHMInfo.shmid == -1) {
- g_mutex_unlock (ximagesink->x_lock);
- GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE,
- ("Failed to create output image buffer of %dx%d pixels",
- ximage->width, ximage->height),
- ("could not get shared memory of %" G_GSIZE_FORMAT " bytes",
- ximage->size));
- goto beach;
- }
-
- ximage->SHMInfo.shmaddr = shmat (ximage->SHMInfo.shmid, NULL, 0);
- if (ximage->SHMInfo.shmaddr == ((void *) -1)) {
- g_mutex_unlock (ximagesink->x_lock);
- GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE,
- ("Failed to create output image buffer of %dx%d pixels",
- ximage->width, ximage->height),
- ("Failed to shmat: %s", g_strerror (errno)));
- /* Clean up the shared memory segment */
- shmctl (ximage->SHMInfo.shmid, IPC_RMID, NULL);
- goto beach;
- }
-
- ximage->ximage->data = ximage->SHMInfo.shmaddr;
- ximage->SHMInfo.readOnly = FALSE;
-
- if (XShmAttach (ximagesink->xcontext->disp, &ximage->SHMInfo) == 0) {
- /* Clean up shm seg */
- shmctl (ximage->SHMInfo.shmid, IPC_RMID, NULL);
-
- g_mutex_unlock (ximagesink->x_lock);
- GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE,
- ("Failed to create output image buffer of %dx%d pixels",
- ximage->width, ximage->height), ("Failed to XShmAttach"));
- goto beach;
- }
-
- XSync (ximagesink->xcontext->disp, FALSE);
-
- /* Now that everyone has attached, we can delete the shared memory segment.
- * This way, it will be deleted as soon as we detach later, and not
- * leaked if we crash. */
- shmctl (ximage->SHMInfo.shmid, IPC_RMID, NULL);
-
- } else
- no_xshm:
-#endif /* HAVE_XSHM */
- {
- guint allocsize;
-
- ximage->ximage = XCreateImage (ximagesink->xcontext->disp,
- ximagesink->xcontext->visual,
- ximagesink->xcontext->depth,
- ZPixmap, 0, NULL,
- ximage->width, ximage->height, ximagesink->xcontext->bpp, 0);
- if (!ximage->ximage || error_caught) {
- g_mutex_unlock (ximagesink->x_lock);
- /* Reset error handler */
- error_caught = FALSE;
- XSetErrorHandler (handler);
- /* Push an error */
- GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE,
- ("Failed to create output image buffer of %dx%d pixels",
- ximage->width, ximage->height),
- ("could not XCreateImage a %dx%d image",
- ximage->width, ximage->height));
- goto beach;
- }
-
- /* upstream will assume that rowstrides are multiples of 4, but this
- * doesn't always seem to be the case with XCreateImage() */
- if ((ximage->ximage->bytes_per_line % 4) != 0) {
- GST_WARNING_OBJECT (ximagesink, "returned stride not a multiple of 4 as "
- "usually assumed");
- }
-
- /* we have to use the returned bytes_per_line for our image size */
- ximage->size = ximage->ximage->bytes_per_line * ximage->ximage->height;
-
- /* alloc a bit more for unexpected strides to avoid crashes upstream.
- * FIXME: if we get an unrounded stride, the image will be displayed
- * distorted, since all upstream elements assume a rounded stride */
- allocsize =
- GST_ROUND_UP_4 (ximage->ximage->bytes_per_line) *
- ximage->ximage->height;
- ximage->ximage->data = g_malloc (allocsize);
- GST_LOG_OBJECT (ximagesink,
- "non-XShm image size is %" G_GSIZE_FORMAT " (alloced: %u), width %d, "
- "stride %d", ximage->size, allocsize, ximage->width,
- ximage->ximage->bytes_per_line);
-
- XSync (ximagesink->xcontext->disp, FALSE);
- }
-
- /* Reset error handler */
- error_caught = FALSE;
- XSetErrorHandler (handler);
-
- succeeded = TRUE;
-
- GST_BUFFER_DATA (ximage) = (guchar *) ximage->ximage->data;
- GST_BUFFER_SIZE (ximage) = ximage->size;
-
- /* Keep a ref to our sink */
- ximage->ximagesink = gst_object_ref (ximagesink);
-
- g_mutex_unlock (ximagesink->x_lock);
-beach:
- if (!succeeded) {
- gst_ximage_buffer_free (ximage);
- ximage = NULL;
- }
-
- return ximage;
-}
-
-/* This function destroys a GstXImageBuffer handling XShm availability */
-static void
-gst_ximagesink_ximage_destroy (GstXImageSink * ximagesink,
- GstXImageBuffer * ximage)
-{
- g_return_if_fail (ximage != NULL);
- g_return_if_fail (GST_IS_XIMAGESINK (ximagesink));
-
- /* Hold the object lock to ensure the XContext doesn't disappear */
- GST_OBJECT_LOCK (ximagesink);
-
- /* If the destroyed image is the current one we destroy our reference too */
- if (ximagesink->cur_image == ximage) {
- ximagesink->cur_image = NULL;
- }
-
- /* We might have some buffers destroyed after changing state to NULL */
- if (!ximagesink->xcontext) {
- GST_DEBUG_OBJECT (ximagesink, "Destroying XImage after XContext");
-#ifdef HAVE_XSHM
- if (ximage->SHMInfo.shmaddr != ((void *) -1)) {
- shmdt (ximage->SHMInfo.shmaddr);
- }
-#endif
- goto beach;
- }
-
- g_mutex_lock (ximagesink->x_lock);
-
-#ifdef HAVE_XSHM
- if (ximagesink->xcontext->use_xshm) {
- if (ximage->SHMInfo.shmaddr != ((void *) -1)) {
- XShmDetach (ximagesink->xcontext->disp, &ximage->SHMInfo);
- XSync (ximagesink->xcontext->disp, 0);
- shmdt (ximage->SHMInfo.shmaddr);
- }
- if (ximage->ximage)
- XDestroyImage (ximage->ximage);
-
- } else
-#endif /* HAVE_XSHM */
- {
- if (ximage->ximage) {
- XDestroyImage (ximage->ximage);
- }
- }
-
- XSync (ximagesink->xcontext->disp, FALSE);
-
- g_mutex_unlock (ximagesink->x_lock);
-
-beach:
- GST_OBJECT_UNLOCK (ximagesink);
-
- if (ximage->ximagesink) {
- /* Release the ref to our sink */
- ximage->ximagesink = NULL;
- gst_object_unref (ximagesink);
- }
-
- return;
-}
-
/* We are called with the x_lock taken */
static void
gst_ximagesink_xwindow_draw_borders (GstXImageSink * ximagesink,
/* This function puts a GstXImageBuffer on a GstXImageSink's window */
static gboolean
-gst_ximagesink_ximage_put (GstXImageSink * ximagesink, GstXImageBuffer * ximage)
+gst_ximagesink_ximage_put (GstXImageSink * ximagesink, GstBuffer * ximage)
{
+ GstMetaXImage *meta;
GstVideoRectangle src, dst, result;
gboolean draw_border = FALSE;
- g_return_val_if_fail (GST_IS_XIMAGESINK (ximagesink), FALSE);
-
/* We take the flow_lock. If expose is in there we don't want to run
concurrently from the data flow thread */
g_mutex_lock (ximagesink->flow_lock);
if (ximage && ximagesink->cur_image != ximage) {
if (ximagesink->cur_image) {
GST_LOG_OBJECT (ximagesink, "unreffing %p", ximagesink->cur_image);
- gst_buffer_unref (GST_BUFFER_CAST (ximagesink->cur_image));
+ gst_buffer_unref (ximagesink->cur_image);
}
GST_LOG_OBJECT (ximagesink, "reffing %p as our current image", ximage);
- ximagesink->cur_image =
- GST_XIMAGE_BUFFER (gst_buffer_ref (GST_BUFFER_CAST (ximage)));
+ ximagesink->cur_image = gst_buffer_ref (ximage);
}
/* Expose sends a NULL image, we take the latest frame */
}
}
- src.w = ximage->width;
- src.h = ximage->height;
+ meta = gst_buffer_get_meta_ximage (ximage);
+
+ src.w = meta->width;
+ src.h = meta->height;
dst.w = ximagesink->xwindow->width;
dst.h = ximagesink->xwindow->height;
ximage, 0, 0, result.x, result.y, result.w, result.h,
ximagesink->xwindow->width, ximagesink->xwindow->height);
XShmPutImage (ximagesink->xcontext->disp, ximagesink->xwindow->win,
- ximagesink->xwindow->gc, ximage->ximage, 0, 0, result.x, result.y,
+ ximagesink->xwindow->gc, meta->ximage, 0, 0, result.x, result.y,
result.w, result.h, FALSE);
} else
#endif /* HAVE_XSHM */
ximage, 0, 0, result.x, result.y, result.w, result.h,
ximagesink->xwindow->width, ximagesink->xwindow->height);
XPutImage (ximagesink->xcontext->disp, ximagesink->xwindow->win,
- ximagesink->xwindow->gc, ximage->ximage, 0, 0, result.x, result.y,
+ ximagesink->xwindow->gc, meta->ximage, 0, 0, result.x, result.y,
result.w, result.h);
}
g_mutex_lock (ximagesink->x_lock);
- hints_atom = XInternAtom (ximagesink->xcontext->disp, "_MOTIF_WM_HINTS", 1);
+ hints_atom = XInternAtom (ximagesink->xcontext->disp, "_MOTIF_WM_HINTS",
+ True);
if (hints_atom == None) {
g_mutex_unlock (ximagesink->x_lock);
return FALSE;
xwindow->win = XCreateSimpleWindow (ximagesink->xcontext->disp,
ximagesink->xcontext->root,
- 0, 0, xwindow->width, xwindow->height, 0, 0, ximagesink->xcontext->black);
+ 0, 0, width, height, 0, 0, ximagesink->xcontext->black);
/* We have to do that to prevent X from redrawing the background on
ConfigureNotify. This takes away flickering of video when resizing. */
gst_ximagesink_xwindow_update_geometry (GstXImageSink * ximagesink)
{
XWindowAttributes attr;
+ gboolean reconfigure;
g_return_if_fail (GST_IS_XIMAGESINK (ximagesink));
XGetWindowAttributes (ximagesink->xcontext->disp,
ximagesink->xwindow->win, &attr);
+ /* Check if we would suggest a different width/height now */
+ reconfigure = (ximagesink->xwindow->width != attr.width)
+ || (ximagesink->xwindow->height != attr.height);
ximagesink->xwindow->width = attr.width;
ximagesink->xwindow->height = attr.height;
g_mutex_unlock (ximagesink->x_lock);
+
+ if (reconfigure)
+ gst_pad_push_event (GST_BASE_SINK (ximagesink)->sinkpad,
+ gst_event_new_reconfigure ());
}
static void
g_mutex_unlock (ximagesink->x_lock);
gst_navigation_send_key_event (GST_NAVIGATION (ximagesink),
e.type == KeyPress ? "key-press" : "key-release", key_str);
-
} else {
gst_navigation_send_key_event (GST_NAVIGATION (ximagesink),
e.type == KeyPress ? "key-press" : "key-release", "unknown");
g_mutex_lock (ximagesink->x_lock);
}
+ /* Handle Expose */
while (XCheckWindowEvent (ximagesink->xcontext->disp,
ximagesink->xwindow->win, ExposureMask | StructureNotifyMask, &e)) {
switch (e.type) {
g_mutex_unlock (ximagesink->x_lock);
g_free (xcontext->par);
g_free (xcontext);
- GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE,
+ GST_ELEMENT_ERROR (ximagesink, RESOURCE, SETTINGS,
("Could not get supported pixmap formats"), (NULL));
return NULL;
}
xcontext->use_xshm = TRUE;
GST_DEBUG ("ximagesink is using XShm extension");
} else
-#endif
+#endif /* HAVE_XSHM */
{
xcontext->use_xshm = FALSE;
GST_DEBUG ("ximagesink is not using XShm extension");
g_free (xcontext);
}
-static void
-gst_ximagesink_bufferpool_clear (GstXImageSink * ximagesink)
-{
-
- g_mutex_lock (ximagesink->pool_lock);
-
- while (ximagesink->buffer_pool) {
- GstXImageBuffer *ximage = ximagesink->buffer_pool->data;
-
- ximagesink->buffer_pool = g_slist_delete_link (ximagesink->buffer_pool,
- ximagesink->buffer_pool);
- gst_ximage_buffer_free (ximage);
- }
-
- g_mutex_unlock (ximagesink->pool_lock);
-}
-
/* Element stuff */
static GstCaps *
-gst_ximagesink_getcaps (GstBaseSink * bsink)
+gst_ximagesink_getcaps (GstBaseSink * bsink, GstCaps * filter)
{
GstXImageSink *ximagesink;
GstCaps *caps;
ximagesink = GST_XIMAGESINK (bsink);
- if (ximagesink->xcontext)
- return gst_caps_ref (ximagesink->xcontext->caps);
+ g_mutex_lock (ximagesink->x_lock);
+ if (ximagesink->xcontext) {
+ GstCaps *caps;
- /* get a template copy and add the pixel aspect ratio */
- caps =
- gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SINK
- (ximagesink)->sinkpad));
- for (i = 0; i < gst_caps_get_size (caps); ++i) {
- GstStructure *structure = gst_caps_get_structure (caps, i);
+ caps = gst_caps_ref (ximagesink->xcontext->caps);
- if (ximagesink->par) {
+ if (filter) {
+ GstCaps *intersection;
+
+ intersection =
+ gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+ gst_caps_unref (caps);
+ caps = intersection;
+ }
+
+ if (ximagesink->xwindow && ximagesink->xwindow->width) {
+ GstStructure *s0, *s1;
+
+ caps = gst_caps_make_writable (caps);
+
+ /* There can only be a single structure because the xcontext
+ * caps only have a single structure */
+ s0 = gst_caps_get_structure (caps, 0);
+ s1 = gst_structure_copy (gst_caps_get_structure (caps, 0));
+
+ gst_structure_set (s0, "width", G_TYPE_INT, ximagesink->xwindow->width,
+ "height", G_TYPE_INT, ximagesink->xwindow->height, NULL);
+ gst_caps_append_structure (caps, s1);
+
+ /* This will not change the order but will remove the
+ * fixed width/height caps again if not possible
+ * upstream */
+ if (filter) {
+ GstCaps *intersection;
+
+ intersection =
+ gst_caps_intersect_full (caps, filter, GST_CAPS_INTERSECT_FIRST);
+ gst_caps_unref (caps);
+ caps = intersection;
+ }
+ }
+
+ g_mutex_unlock (ximagesink->x_lock);
+ return caps;
+ }
+ g_mutex_unlock (ximagesink->x_lock);
+
+ /* get a template copy and add the pixel aspect ratio */
+ caps = gst_pad_get_pad_template_caps (GST_BASE_SINK (ximagesink)->sinkpad);
+ if (ximagesink->par) {
+ caps = gst_caps_make_writable (caps);
+ for (i = 0; i < gst_caps_get_size (caps); ++i) {
+ GstStructure *structure = gst_caps_get_structure (caps, i);
int nom, den;
nom = gst_value_get_fraction_numerator (ximagesink->par);
}
}
+ if (filter) {
+ GstCaps *intersection;
+
+ intersection =
+ gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+ gst_caps_unref (caps);
+ caps = intersection;
+ }
+
return caps;
}
gst_ximagesink_setcaps (GstBaseSink * bsink, GstCaps * caps)
{
GstXImageSink *ximagesink;
- gboolean ret = TRUE;
GstStructure *structure;
+ GstBufferPool *newpool, *oldpool;
+ gboolean ret = TRUE;
const GValue *par;
gint new_width, new_height;
const GValue *fps;
ret &= gst_structure_get_int (structure, "height", &new_height);
fps = gst_structure_get_value (structure, "framerate");
ret &= (fps != NULL);
+
if (!ret)
return FALSE;
/* Creating our window and our image */
if (GST_VIDEO_SINK_WIDTH (ximagesink) <= 0 ||
- GST_VIDEO_SINK_HEIGHT (ximagesink) <= 0) {
- GST_ELEMENT_ERROR (ximagesink, CORE, NEGOTIATION, (NULL),
- ("Invalid image size."));
- return FALSE;
- }
+ GST_VIDEO_SINK_HEIGHT (ximagesink) <= 0)
+ goto invalid_size;
g_mutex_lock (ximagesink->flow_lock);
if (!ximagesink->xwindow) {
}
/* Remember to draw borders for next frame */
ximagesink->draw_border = TRUE;
- g_mutex_unlock (ximagesink->flow_lock);
- /* If our ximage has changed we destroy it, next chain iteration will create
- a new one */
- if ((ximagesink->ximage) &&
- ((GST_VIDEO_SINK_WIDTH (ximagesink) != ximagesink->ximage->width) ||
- (GST_VIDEO_SINK_HEIGHT (ximagesink) != ximagesink->ximage->height))) {
- GST_DEBUG_OBJECT (ximagesink, "our image is not usable anymore, unref %p",
- ximagesink->ximage);
- gst_buffer_unref (GST_BUFFER_CAST (ximagesink->ximage));
- ximagesink->ximage = NULL;
+ /* create a new pool for the new configuration */
+ newpool = gst_ximage_buffer_pool_new (ximagesink);
+
+ structure = gst_buffer_pool_get_config (newpool);
+ gst_buffer_pool_config_set (structure, caps, 0, 0, 0, 0, 0, 16);
+ if (!gst_buffer_pool_set_config (newpool, structure))
+ goto config_failed;
+
+ if (!gst_buffer_pool_set_active (newpool, TRUE))
+ goto activate_failed;
+
+ oldpool = ximagesink->pool;
+ ximagesink->pool = newpool;
+
+ /* unref the old sink */
+ if (oldpool) {
+ /* deactivate */
+ gst_buffer_pool_set_active (oldpool, FALSE);
+ gst_object_unref (oldpool);
}
+ g_mutex_unlock (ximagesink->flow_lock);
return TRUE;
GST_INFO_OBJECT (ximagesink, "pixel aspect ratio does not match");
return FALSE;
}
+invalid_size:
+ {
+ GST_ELEMENT_ERROR (ximagesink, CORE, NEGOTIATION, (NULL),
+ ("Invalid image size."));
+ return FALSE;
+ }
+config_failed:
+ {
+ GST_ERROR_OBJECT (ximagesink, "failed to set config.");
+ g_mutex_unlock (ximagesink->flow_lock);
+ return FALSE;
+ }
+activate_failed:
+ {
+ GST_ERROR_OBJECT (ximagesink, "failed to activate bufferpool.");
+ g_mutex_unlock (ximagesink->flow_lock);
+ gst_object_unref (newpool);
+ return FALSE;
+ }
}
static GstStateChangeReturn
gst_ximagesink_change_state (GstElement * element, GstStateChange transition)
{
- GstXImageSink *ximagesink;
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+ GstXImageSink *ximagesink;
GstXContext *xcontext = NULL;
ximagesink = GST_XIMAGESINK (element);
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
-
/* Initializing the XContext */
if (ximagesink->xcontext == NULL) {
xcontext = gst_ximagesink_xcontext_get (ximagesink);
ximagesink->fps_d = 1;
GST_VIDEO_SINK_WIDTH (ximagesink) = 0;
GST_VIDEO_SINK_HEIGHT (ximagesink) = 0;
+ g_mutex_lock (ximagesink->flow_lock);
+ if (ximagesink->pool)
+ gst_buffer_pool_set_active (ximagesink->pool, FALSE);
+ g_mutex_unlock (ximagesink->flow_lock);
break;
case GST_STATE_CHANGE_READY_TO_NULL:
gst_ximagesink_reset (ximagesink);
static GstFlowReturn
gst_ximagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
{
+ GstFlowReturn res;
GstXImageSink *ximagesink;
-
- g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
+ GstMetaXImage *meta;
+ GstBuffer *temp;
+ gboolean unref;
ximagesink = GST_XIMAGESINK (vsink);
- /* This shouldn't really happen because state changes will fail
- * if the xcontext can't be allocated */
- if (!ximagesink->xcontext)
- return GST_FLOW_ERROR;
+ meta = gst_buffer_get_meta_ximage (buf);
- /* If this buffer has been allocated using our buffer management we simply
- put the ximage which is in the PRIVATE pointer */
- if (GST_IS_XIMAGE_BUFFER (buf)) {
+ if (meta) {
+ /* If this buffer has been allocated using our buffer management we simply
+ put the ximage which is in the PRIVATE pointer */
GST_LOG_OBJECT (ximagesink, "buffer from our pool, writing directly");
- if (!gst_ximagesink_ximage_put (ximagesink, GST_XIMAGE_BUFFER (buf)))
- goto no_window;
+ res = GST_FLOW_OK;
+ unref = FALSE;
} else {
+ guint8 *data;
+ gsize size;
+
/* Else we have to copy the data into our private image, */
/* if we have one... */
- GST_LOG_OBJECT (ximagesink, "normal buffer, copying from it");
- if (!ximagesink->ximage) {
- GST_DEBUG_OBJECT (ximagesink, "creating our ximage");
- ximagesink->ximage = gst_ximagesink_ximage_new (ximagesink,
- GST_BUFFER_CAPS (buf));
- if (!ximagesink->ximage)
- /* The create method should have posted an informative error */
- goto no_ximage;
-
- if (ximagesink->ximage->size < GST_BUFFER_SIZE (buf)) {
- GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE,
- ("Failed to create output image buffer of %dx%d pixels",
- ximagesink->ximage->width, ximagesink->ximage->height),
- ("XServer allocated buffer size did not match input buffer"));
-
- gst_ximagesink_ximage_destroy (ximagesink, ximagesink->ximage);
- ximagesink->ximage = NULL;
- goto no_ximage;
- }
- }
- memcpy (GST_BUFFER_DATA (ximagesink->ximage), GST_BUFFER_DATA (buf),
- MIN (GST_BUFFER_SIZE (buf), ximagesink->ximage->size));
- if (!gst_ximagesink_ximage_put (ximagesink, ximagesink->ximage))
- goto no_window;
+ GST_LOG_OBJECT (ximagesink, "buffer not from our pool, copying");
+
+ /* we should have a pool, configured in setcaps */
+ if (ximagesink->pool == NULL)
+ goto no_pool;
+
+ /* take a buffer form our pool */
+ res = gst_buffer_pool_acquire_buffer (ximagesink->pool, &temp, NULL);
+ if (res != GST_FLOW_OK)
+ goto no_buffer;
+
+ unref = TRUE;
+
+ if (gst_buffer_get_size (temp) < gst_buffer_get_size (buf))
+ goto wrong_size;
+
+ data = gst_buffer_map (temp, &size, NULL, GST_MAP_WRITE);
+ gst_buffer_extract (buf, 0, data, size);
+ gst_buffer_unmap (temp, data, size);
+
+ buf = temp;
}
- return GST_FLOW_OK;
+ if (!gst_ximagesink_ximage_put (ximagesink, buf))
+ goto no_window;
+
+done:
+ if (unref)
+ gst_buffer_unref (buf);
+
+ return res;
/* ERRORS */
-no_ximage:
+no_pool:
+ {
+ GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE,
+ ("Internal error: can't allocate images"),
+ ("We don't have a bufferpool negotiated"));
+ return GST_FLOW_ERROR;
+ }
+no_buffer:
{
/* No image available. That's very bad ! */
GST_WARNING_OBJECT (ximagesink, "could not create image");
- return GST_FLOW_ERROR;
+ return res;
+ }
+wrong_size:
+ {
+ GST_ELEMENT_ERROR (ximagesink, RESOURCE, WRITE,
+ ("Failed to create output image buffer"),
+ ("XServer allocated buffer size did not match input buffer %"
+ G_GSIZE_FORMAT " - %" G_GSIZE_FORMAT, gst_buffer_get_size (temp),
+ gst_buffer_get_size (buf)));
+ res = GST_FLOW_ERROR;
+ goto done;
}
no_window:
{
/* No Window available to put our image into */
GST_WARNING_OBJECT (ximagesink, "could not output image - no window");
- return GST_FLOW_ERROR;
+ res = GST_FLOW_ERROR;
+ goto done;
}
}
-
static gboolean
gst_ximagesink_event (GstBaseSink * sink, GstEvent * event)
{
return TRUE;
}
-
-/* Buffer management
- *
- * The buffer_alloc function must either return a buffer with given size and
- * caps or create a buffer with different caps attached to the buffer. This
- * last option is called reverse negotiation, ie, where the sink suggests a
- * different format from the upstream peer.
- *
- * We try to do reverse negotiation when our geometry changes and we like a
- * resized buffer.
- */
-static GstFlowReturn
-gst_ximagesink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size,
- GstCaps * caps, GstBuffer ** buf)
+static gboolean
+gst_ximagesink_sink_query (GstPad * sinkpad, GstQuery * query)
{
- GstXImageSink *ximagesink;
- GstXImageBuffer *ximage = NULL;
- GstStructure *structure = NULL;
- GstFlowReturn ret = GST_FLOW_OK;
- GstCaps *alloc_caps;
- gboolean alloc_unref = FALSE;
- gint width, height;
- GstVideoRectangle dst, src, result;
- gboolean caps_accepted = FALSE;
-
- ximagesink = GST_XIMAGESINK (bsink);
-
- if (G_UNLIKELY (!caps)) {
- GST_WARNING_OBJECT (ximagesink, "have no caps, doing fallback allocation");
- *buf = NULL;
- ret = GST_FLOW_OK;
- goto beach;
- }
+ GstXImageSink *ximagesink = GST_XIMAGESINK (GST_PAD_PARENT (sinkpad));
+ gboolean res = TRUE;
- /* This shouldn't really happen because state changes will fail
- * if the xcontext can't be allocated */
- if (!ximagesink->xcontext)
- return GST_FLOW_ERROR;
-
- GST_LOG_OBJECT (ximagesink,
- "a buffer of %d bytes was requested with caps %" GST_PTR_FORMAT
- " and offset %" G_GUINT64_FORMAT, size, caps, offset);
-
- /* assume we're going to alloc what was requested, keep track of
- * wheter we need to unref or not. When we suggest a new format
- * upstream we will create a new caps that we need to unref. */
- alloc_caps = caps;
- alloc_unref = FALSE;
-
- /* get struct to see what is requested */
- structure = gst_caps_get_structure (caps, 0);
- if (!gst_structure_get_int (structure, "width", &width) ||
- !gst_structure_get_int (structure, "height", &height)) {
- GST_WARNING_OBJECT (ximagesink, "invalid caps for buffer allocation %"
- GST_PTR_FORMAT, caps);
- ret = GST_FLOW_NOT_NEGOTIATED;
- goto beach;
- }
-
- src.w = width;
- src.h = height;
-
- /* We take the flow_lock because the window might go away */
- g_mutex_lock (ximagesink->flow_lock);
- if (!ximagesink->xwindow) {
- g_mutex_unlock (ximagesink->flow_lock);
- goto alloc;
- }
-
- /* What is our geometry */
- dst.w = ximagesink->xwindow->width;
- dst.h = ximagesink->xwindow->height;
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_ALLOCATION:
+ {
+ GstBufferPool *pool;
+ GstStructure *config;
+ GstCaps *caps;
+ guint size;
+ gboolean need_pool;
- g_mutex_unlock (ximagesink->flow_lock);
+ gst_query_parse_allocation (query, &caps, &need_pool);
- if (ximagesink->keep_aspect) {
- GST_LOG_OBJECT (ximagesink, "enforcing aspect ratio in reverse caps "
- "negotiation");
- gst_video_sink_center_rect (src, dst, &result, TRUE);
- } else {
- GST_LOG_OBJECT (ximagesink, "trying to resize to window geometry "
- "ignoring aspect ratio");
- result.x = result.y = 0;
- result.w = dst.w;
- result.h = dst.h;
- }
+ if (caps == NULL)
+ goto no_caps;
- /* We would like another geometry */
- if (width != result.w || height != result.h) {
- int nom, den;
- GstCaps *desired_caps;
- GstStructure *desired_struct;
+ g_mutex_lock (ximagesink->flow_lock);
+ if ((pool = ximagesink->pool))
+ gst_object_ref (pool);
+ g_mutex_unlock (ximagesink->flow_lock);
- /* make a copy of the incomming caps to create the new
- * suggestion. We can't use make_writable because we might
- * then destroy the original caps which we still need when the
- * peer does not accept the suggestion. */
- desired_caps = gst_caps_copy (caps);
- desired_struct = gst_caps_get_structure (desired_caps, 0);
+ if (pool != NULL) {
+ const GstCaps *pcaps;
+
+ /* we had a pool, check caps */
+ config = gst_buffer_pool_get_config (pool);
+ gst_buffer_pool_config_get (config, &pcaps, &size, NULL, NULL, NULL,
+ NULL, NULL);
+
+ GST_DEBUG_OBJECT (ximagesink,
+ "we had a pool with caps %" GST_PTR_FORMAT, pcaps);
+ if (!gst_caps_is_equal (caps, pcaps)) {
+ /* different caps, we can't use this pool */
+ GST_DEBUG_OBJECT (ximagesink, "pool has different caps");
+ gst_object_unref (pool);
+ pool = NULL;
+ }
+ }
+ if (pool == NULL && need_pool) {
+ GstVideoFormat format;
+ gint width, height;
- GST_DEBUG ("we would love to receive a %dx%d video", result.w, result.h);
- gst_structure_set (desired_struct, "width", G_TYPE_INT, result.w, NULL);
- gst_structure_set (desired_struct, "height", G_TYPE_INT, result.h, NULL);
+ GST_DEBUG_OBJECT (ximagesink, "create new pool");
+ pool = gst_ximage_buffer_pool_new (ximagesink);
- /* PAR property overrides the X calculated one */
- if (ximagesink->par) {
- nom = gst_value_get_fraction_numerator (ximagesink->par);
- den = gst_value_get_fraction_denominator (ximagesink->par);
- gst_structure_set (desired_struct, "pixel-aspect-ratio",
- GST_TYPE_FRACTION, nom, den, NULL);
- } else if (ximagesink->xcontext->par) {
- nom = gst_value_get_fraction_numerator (ximagesink->xcontext->par);
- den = gst_value_get_fraction_denominator (ximagesink->xcontext->par);
- gst_structure_set (desired_struct, "pixel-aspect-ratio",
- GST_TYPE_FRACTION, nom, den, NULL);
- }
+ if (!gst_video_format_parse_caps (caps, &format, &width, &height))
+ goto invalid_caps;
+ /* the normal size of a frame */
+ size = gst_video_format_get_size (format, width, height);
- /* see if peer accepts our new suggestion, if there is no peer, this
- * function returns true. */
- if (!ximagesink->xcontext->last_caps ||
- !gst_caps_is_equal (desired_caps, ximagesink->xcontext->last_caps)) {
- caps_accepted =
- gst_pad_peer_accept_caps (GST_VIDEO_SINK_PAD (ximagesink),
- desired_caps);
+ config = gst_buffer_pool_get_config (pool);
+ gst_buffer_pool_config_set (config, caps, size, 0, 0, 0, 0, 16);
+ if (!gst_buffer_pool_set_config (pool, config))
+ goto config_failed;
+ }
+ gst_query_set_allocation_params (query, size, 0, 0, 0, 16, pool);
- /* Suggestion failed, prevent future attempts for the same caps
- * to fail as well. */
- if (!caps_accepted)
- gst_caps_replace (&ximagesink->xcontext->last_caps, desired_caps);
- }
+ /* we also support various metadata */
+ gst_query_add_allocation_meta (query, GST_META_API_VIDEO);
- if (caps_accepted) {
- /* we will not alloc a buffer of the new suggested caps. Make sure
- * we also unref this new caps after we set it on the buffer. */
- alloc_caps = desired_caps;
- alloc_unref = TRUE;
- width = result.w;
- height = result.h;
- GST_DEBUG ("peer pad accepts our desired caps %" GST_PTR_FORMAT,
- desired_caps);
- } else {
- GST_DEBUG ("peer pad does not accept our desired caps %" GST_PTR_FORMAT,
- desired_caps);
- /* we alloc a buffer with the original incomming caps already in the
- * width and height variables */
- gst_caps_unref (desired_caps);
+ gst_object_unref (pool);
+ break;
}
+ default:
+ res = FALSE;
+ break;
}
+ return res;
-alloc:
- /* Inspect our buffer pool */
- g_mutex_lock (ximagesink->pool_lock);
- while (ximagesink->buffer_pool) {
- ximage = (GstXImageBuffer *) ximagesink->buffer_pool->data;
-
- if (ximage) {
- /* Removing from the pool */
- ximagesink->buffer_pool = g_slist_delete_link (ximagesink->buffer_pool,
- ximagesink->buffer_pool);
-
- /* If the ximage is invalid for our need, destroy */
- if ((ximage->width != width) || (ximage->height != height)) {
- gst_ximage_buffer_free (ximage);
- ximage = NULL;
- } else {
- /* We found a suitable ximage */
- break;
- }
- }
+ /* ERRORS */
+no_caps:
+ {
+ GST_DEBUG_OBJECT (sinkpad, "no caps specified");
+ return FALSE;
}
- g_mutex_unlock (ximagesink->pool_lock);
-
- /* We haven't found anything, creating a new one */
- if (!ximage) {
- ximage = gst_ximagesink_ximage_new (ximagesink, alloc_caps);
+invalid_caps:
+ {
+ GST_DEBUG_OBJECT (sinkpad, "invalid caps specified");
+ return FALSE;
}
- /* Now we should have a ximage, set appropriate caps on it */
- if (ximage) {
- /* Make sure the buffer is cleared of any previously used flags */
- GST_MINI_OBJECT_CAST (ximage)->flags = 0;
- gst_buffer_set_caps (GST_BUFFER_CAST (ximage), alloc_caps);
+config_failed:
+ {
+ GST_DEBUG_OBJECT (sinkpad, "failed setting config");
+ return FALSE;
}
-
- /* could be our new reffed suggestion or the original unreffed caps */
- if (alloc_unref)
- gst_caps_unref (alloc_caps);
-
- *buf = GST_BUFFER_CAST (ximage);
-
-beach:
- return ret;
}
/* Interfaces stuff */
if (thread)
g_thread_join (thread);
- if (ximagesink->ximage) {
- gst_buffer_unref (GST_BUFFER_CAST (ximagesink->ximage));
- ximagesink->ximage = NULL;
- }
if (ximagesink->cur_image) {
- gst_buffer_unref (GST_BUFFER_CAST (ximagesink->cur_image));
+ gst_buffer_unref (ximagesink->cur_image);
ximagesink->cur_image = NULL;
}
- gst_ximagesink_bufferpool_clear (ximagesink);
-
g_mutex_lock (ximagesink->flow_lock);
+
+ if (ximagesink->pool) {
+ gst_object_unref (ximagesink->pool);
+ ximagesink->pool = NULL;
+ }
+
if (ximagesink->xwindow) {
gst_ximagesink_xwindow_clear (ximagesink, ximagesink->xwindow);
gst_ximagesink_xwindow_destroy (ximagesink, ximagesink->xwindow);
g_mutex_free (ximagesink->flow_lock);
ximagesink->flow_lock = NULL;
}
- if (ximagesink->pool_lock) {
- g_mutex_free (ximagesink->pool_lock);
- ximagesink->pool_lock = NULL;
- }
g_free (ximagesink->media_title);
static void
gst_ximagesink_init (GstXImageSink * ximagesink)
{
+ /* for the ALLOCATION query */
+ gst_pad_set_query_function (GST_BASE_SINK (ximagesink)->sinkpad,
+ gst_ximagesink_sink_query);
+
ximagesink->display_name = NULL;
ximagesink->xcontext = NULL;
ximagesink->xwindow = NULL;
- ximagesink->ximage = NULL;
ximagesink->cur_image = NULL;
ximagesink->event_thread = NULL;
ximagesink->par = NULL;
- ximagesink->pool_lock = g_mutex_new ();
- ximagesink->buffer_pool = NULL;
+ ximagesink->pool = NULL;
ximagesink->synchronous = FALSE;
ximagesink->keep_aspect = FALSE;
}
static void
-gst_ximagesink_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_set_details_simple (element_class,
- "Video sink", "Sink/Video",
- "A standard X based videosink", "Julien Moutte <julien@moutte.net>");
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&gst_ximagesink_sink_template_factory));
-}
-
-static void
gst_ximagesink_class_init (GstXImageSinkClass * klass)
{
GObjectClass *gobject_class;
gstbasesink_class = (GstBaseSinkClass *) klass;
videosink_class = (GstVideoSinkClass *) klass;
- parent_class = g_type_class_peek_parent (klass);
-
gobject_class->finalize = gst_ximagesink_finalize;
gobject_class->set_property = gst_ximagesink_set_property;
gobject_class->get_property = gst_ximagesink_get_property;
"Height of the window", 0, G_MAXUINT64, 0,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+ gst_element_class_set_details_simple (gstelement_class,
+ "Video sink", "Sink/Video",
+ "A standard X based videosink", "Julien Moutte <julien@moutte.net>");
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_ximagesink_sink_template_factory));
+
gstelement_class->change_state = gst_ximagesink_change_state;
gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_ximagesink_getcaps);
gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_ximagesink_setcaps);
- gstbasesink_class->buffer_alloc =
- GST_DEBUG_FUNCPTR (gst_ximagesink_buffer_alloc);
gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_ximagesink_get_times);
gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_ximagesink_event);
videosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_ximagesink_show_frame);
}
-
-/* ============================================================= */
-/* */
-/* Public Methods */
-/* */
-/* ============================================================= */
-
-/* =========================================== */
-/* */
-/* Object typing & Creation */
-/* */
-/* =========================================== */
-
-GType
-gst_ximagesink_get_type (void)
-{
- static GType ximagesink_type = 0;
-
- if (!ximagesink_type) {
- static const GTypeInfo ximagesink_info = {
- sizeof (GstXImageSinkClass),
- gst_ximagesink_base_init,
- NULL,
- (GClassInitFunc) gst_ximagesink_class_init,
- NULL,
- NULL,
- sizeof (GstXImageSink), 0, (GInstanceInitFunc) gst_ximagesink_init,
- };
- static const GInterfaceInfo iface_info = {
- (GInterfaceInitFunc) gst_ximagesink_interface_init, NULL, NULL,
- };
- static const GInterfaceInfo navigation_info = {
- (GInterfaceInitFunc) gst_ximagesink_navigation_init, NULL, NULL,
- };
- static const GInterfaceInfo overlay_info = {
- (GInterfaceInitFunc) gst_ximagesink_xoverlay_init, NULL, NULL,
- };
-
- ximagesink_type = g_type_register_static (GST_TYPE_VIDEO_SINK,
- "GstXImageSink", &ximagesink_info, 0);
-
- g_type_add_interface_static (ximagesink_type, GST_TYPE_IMPLEMENTS_INTERFACE,
- &iface_info);
- g_type_add_interface_static (ximagesink_type, GST_TYPE_NAVIGATION,
- &navigation_info);
- g_type_add_interface_static (ximagesink_type, GST_TYPE_X_OVERLAY,
- &overlay_info);
-
- /* register type and create class in a more safe place instead of at
- * runtime since the type registration and class creation is not
- * threadsafe. */
- g_type_class_ref (gst_ximage_buffer_get_type ());
- }
-
- return ximagesink_type;
-}
(G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_XIMAGESINK))
#define GST_IS_XIMAGESINK_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_XIMAGESINK))
+
typedef struct _GstXContext GstXContext;
typedef struct _GstXWindow GstXWindow;
-typedef struct _GstXImageBuffer GstXImageBuffer;
-typedef struct _GstXImageBufferClass GstXImageBufferClass;
-
typedef struct _GstXImageSink GstXImageSink;
typedef struct _GstXImageSinkClass GstXImageSinkClass;
+#include "ximagepool.h"
+
/*
* GstXContext:
* @disp: the X11 Display of this context
};
/**
- * GstXImageBuffer:
- * @ximagesink: a reference to our #GstXImageSink
- * @ximage: the XImage of this buffer
- * @width: the width in pixels of XImage @ximage
- * @height: the height in pixels of XImage @ximage
- * @size: the size in bytes of XImage @ximage
- *
- * Subclass of #GstBuffer containing additional information about an XImage.
- */
-struct _GstXImageBuffer
-{
- GstBuffer buffer;
-
- /* Reference to the ximagesink we belong to */
- GstXImageSink *ximagesink;
-
- XImage *ximage;
-
-#ifdef HAVE_XSHM
- XShmSegmentInfo SHMInfo;
-#endif /* HAVE_XSHM */
-
- gint width, height;
- size_t size;
-};
-
-/**
* GstXImageSink:
* @display_name: the name of the Display we want to render to
* @xcontext: our instance's #GstXContext
GstXContext *xcontext;
GstXWindow *xwindow;
- GstXImageBuffer *ximage;
- GstXImageBuffer *cur_image;
+ GstBuffer *cur_image;
GThread *event_thread;
gboolean running;
/* object-set pixel aspect ratio */
GValue *par;
- GMutex *pool_lock;
- GSList *buffer_pool;
+ /* the buffer pool */
+ GstBufferPool *pool;
gboolean synchronous;
gboolean keep_aspect;
plugin_LTLIBRARIES = libgstxvimagesink.la
-libgstxvimagesink_la_SOURCES = xvimagesink.c
+libgstxvimagesink_la_SOURCES = xvimagesink.c xvimage.c xvimagepool.c
libgstxvimagesink_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(X_CFLAGS)
libgstxvimagesink_la_LIBADD = \
$(top_builddir)/gst-libs/gst/interfaces/libgstinterfaces-$(GST_MAJORMINOR).la \
libgstxvimagesink_la_DEPENDENCIES = $(top_builddir)/gst-libs/gst/video/libgstvideo-$(GST_MAJORMINOR).la
libgstxvimagesink_la_LIBTOOLFLAGS = --tag=disable-static
-noinst_HEADERS = xvimagesink.h
+noinst_HEADERS = xvimagesink.h xvimagepool.h
--- /dev/null
+/* GStreamer
+ * Copyright (C) <2003> Julien Moutte <julien@moutte.net>
+ *
+ * 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 "xvimagesink.h"
+
+GST_DEBUG_CATEGORY (gst_debug_xvimagepool);
+GST_DEBUG_CATEGORY (gst_debug_xvimagesink);
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE);
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ if (!gst_element_register (plugin, "xvimagesink",
+ GST_RANK_PRIMARY, GST_TYPE_XVIMAGESINK))
+ return FALSE;
+
+ GST_DEBUG_CATEGORY_INIT (gst_debug_xvimagesink, "xvimagesink", 0,
+ "xvimagesink element");
+ GST_DEBUG_CATEGORY_INIT (gst_debug_xvimagepool, "xvimagepool", 0,
+ "xvimagepool object");
+
+ GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE");
+
+ return TRUE;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "xvimagesink",
+ "XFree86 video output plugin using Xv extension",
+ plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
--- /dev/null
+/* GStreamer
+ * Copyright (C) <2005> Julien Moutte <julien@moutte.net>
+ *
+ * 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
+
+/* Object header */
+#include "xvimagesink.h"
+
+/* Debugging category */
+#include <gst/gstinfo.h>
+
+GST_DEBUG_CATEGORY_EXTERN (gst_debug_xvimagepool);
+#define GST_CAT_DEFAULT gst_debug_xvimagepool
+
+static void gst_meta_xvimage_free (GstMetaXvImage * meta, GstBuffer * buffer);
+
+/* xvimage metadata */
+const GstMetaInfo *
+gst_meta_xvimage_get_info (void)
+{
+ static const GstMetaInfo *meta_xvimage_info = NULL;
+
+ if (meta_xvimage_info == NULL) {
+ meta_xvimage_info = gst_meta_register ("GstMetaXvImage", "GstMetaXvImage",
+ sizeof (GstMetaXvImage),
+ (GstMetaInitFunction) NULL,
+ (GstMetaFreeFunction) gst_meta_xvimage_free,
+ (GstMetaCopyFunction) NULL, (GstMetaTransformFunction) NULL);
+ }
+ return meta_xvimage_info;
+}
+
+/* X11 stuff */
+static gboolean error_caught = FALSE;
+
+static int
+gst_xvimagesink_handle_xerror (Display * display, XErrorEvent * xevent)
+{
+ char error_msg[1024];
+
+ XGetErrorText (display, xevent->error_code, error_msg, 1024);
+ GST_DEBUG ("xvimagesink triggered an XError. error: %s", error_msg);
+ error_caught = TRUE;
+ return 0;
+}
+
+GstMetaXvImage *
+gst_buffer_add_meta_xvimage (GstBuffer * buffer, GstXvImageSink * xvimagesink,
+ gint width, gint height, gint im_format)
+{
+ int (*handler) (Display *, XErrorEvent *);
+ gboolean success = FALSE;
+ GstXContext *xcontext;
+ GstMetaXvImage *meta;
+
+ xcontext = xvimagesink->xcontext;
+
+ meta =
+ (GstMetaXvImage *) gst_buffer_add_meta (buffer, GST_META_INFO_XVIMAGE,
+ NULL);
+#ifdef HAVE_XSHM
+ meta->SHMInfo.shmaddr = ((void *) -1);
+ meta->SHMInfo.shmid = -1;
+#endif
+ meta->width = width;
+ meta->height = height;
+ meta->sink = gst_object_ref (xvimagesink);
+ meta->im_format = im_format;
+
+ GST_DEBUG_OBJECT (xvimagesink, "creating image %p (%dx%d)", buffer,
+ meta->width, meta->height);
+
+ g_mutex_lock (xvimagesink->x_lock);
+
+ /* Setting an error handler to catch failure */
+ error_caught = FALSE;
+ handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
+
+#ifdef HAVE_XSHM
+ if (xcontext->use_xshm) {
+ int expected_size;
+
+ meta->xvimage = XvShmCreateImage (xcontext->disp,
+ xcontext->xv_port_id,
+ meta->im_format, NULL, meta->width, meta->height, &meta->SHMInfo);
+ if (!meta->xvimage || error_caught) {
+ g_mutex_unlock (xvimagesink->x_lock);
+
+ /* Reset error flag */
+ error_caught = FALSE;
+
+ /* Push a warning */
+ GST_ELEMENT_WARNING (xvimagesink, RESOURCE, WRITE,
+ ("Failed to create output image buffer of %dx%d pixels",
+ meta->width, meta->height),
+ ("could not XShmCreateImage a %dx%d image",
+ meta->width, meta->height));
+
+ /* Retry without XShm */
+ xvimagesink->xcontext->use_xshm = FALSE;
+
+ /* Hold X mutex again to try without XShm */
+ g_mutex_lock (xvimagesink->x_lock);
+ goto no_xshm;
+ }
+
+ /* we have to use the returned data_size for our shm size */
+ meta->size = meta->xvimage->data_size;
+ GST_LOG_OBJECT (xvimagesink, "XShm image size is %" G_GSIZE_FORMAT,
+ meta->size);
+
+ /* calculate the expected size. This is only for sanity checking the
+ * number we get from X. */
+ switch (meta->im_format) {
+ case GST_MAKE_FOURCC ('I', '4', '2', '0'):
+ case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
+ {
+ gint pitches[3];
+ gint offsets[3];
+ guint plane;
+
+ offsets[0] = 0;
+ pitches[0] = GST_ROUND_UP_4 (meta->width);
+ offsets[1] = offsets[0] + pitches[0] * GST_ROUND_UP_2 (meta->height);
+ pitches[1] = GST_ROUND_UP_8 (meta->width) / 2;
+ offsets[2] =
+ offsets[1] + pitches[1] * GST_ROUND_UP_2 (meta->height) / 2;
+ pitches[2] = GST_ROUND_UP_8 (pitches[0]) / 2;
+
+ expected_size =
+ offsets[2] + pitches[2] * GST_ROUND_UP_2 (meta->height) / 2;
+
+ for (plane = 0; plane < meta->xvimage->num_planes; plane++) {
+ GST_DEBUG_OBJECT (xvimagesink,
+ "Plane %u has a expected pitch of %d bytes, " "offset of %d",
+ plane, pitches[plane], offsets[plane]);
+ }
+ break;
+ }
+ case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
+ case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
+ expected_size = meta->height * GST_ROUND_UP_4 (meta->width * 2);
+ break;
+ default:
+ expected_size = 0;
+ break;
+ }
+ if (expected_size != 0 && meta->size != expected_size) {
+ GST_WARNING_OBJECT (xvimagesink,
+ "unexpected XShm image size (got %" G_GSIZE_FORMAT ", expected %d)",
+ meta->size, expected_size);
+ }
+
+ /* Be verbose about our XvImage stride */
+ {
+ guint plane;
+
+ for (plane = 0; plane < meta->xvimage->num_planes; plane++) {
+ GST_DEBUG_OBJECT (xvimagesink, "Plane %u has a pitch of %d bytes, "
+ "offset of %d", plane, meta->xvimage->pitches[plane],
+ meta->xvimage->offsets[plane]);
+ }
+ }
+
+ /* get shared memory */
+ meta->SHMInfo.shmid = shmget (IPC_PRIVATE, meta->size, IPC_CREAT | 0777);
+ if (meta->SHMInfo.shmid == -1)
+ goto shmget_failed;
+
+ /* attach */
+ meta->SHMInfo.shmaddr = shmat (meta->SHMInfo.shmid, NULL, 0);
+ if (meta->SHMInfo.shmaddr == ((void *) -1))
+ goto shmat_failed;
+
+ /* now we can set up the image data */
+ meta->xvimage->data = meta->SHMInfo.shmaddr;
+ meta->SHMInfo.readOnly = FALSE;
+
+ if (XShmAttach (xcontext->disp, &meta->SHMInfo) == 0)
+ goto xattach_failed;
+
+ XSync (xcontext->disp, FALSE);
+
+ /* Delete the shared memory segment as soon as we everyone is attached.
+ * This way, it will be deleted as soon as we detach later, and not
+ * leaked if we crash. */
+ shmctl (meta->SHMInfo.shmid, IPC_RMID, NULL);
+
+ GST_DEBUG_OBJECT (xvimagesink, "XServer ShmAttached to 0x%x, id 0x%lx",
+ meta->SHMInfo.shmid, meta->SHMInfo.shmseg);
+ } else
+ no_xshm:
+#endif /* HAVE_XSHM */
+ {
+ meta->xvimage = XvCreateImage (xcontext->disp,
+ xcontext->xv_port_id, meta->im_format, NULL, meta->width, meta->height);
+ if (!meta->xvimage || error_caught)
+ goto create_failed;
+
+ /* we have to use the returned data_size for our image size */
+ meta->size = meta->xvimage->data_size;
+ meta->xvimage->data = g_malloc (meta->size);
+
+ XSync (xcontext->disp, FALSE);
+ }
+
+ /* Reset error handler */
+ error_caught = FALSE;
+ XSetErrorHandler (handler);
+
+ gst_buffer_take_memory (buffer,
+ gst_memory_new_wrapped (GST_MEMORY_FLAG_NO_SHARE, meta->xvimage->data,
+ NULL, meta->size, 0, meta->size));
+
+ g_mutex_unlock (xvimagesink->x_lock);
+
+ success = TRUE;
+
+beach:
+ if (!success)
+ meta = NULL;
+
+ return meta;
+
+ /* ERRORS */
+create_failed:
+ {
+ g_mutex_unlock (xvimagesink->x_lock);
+ /* Reset error handler */
+ error_caught = FALSE;
+ XSetErrorHandler (handler);
+ /* Push an error */
+ GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
+ ("Failed to create output image buffer of %dx%d pixels",
+ meta->width, meta->height),
+ ("could not XvShmCreateImage a %dx%d image", meta->width,
+ meta->height));
+ goto beach;
+ }
+shmget_failed:
+ {
+ g_mutex_unlock (xvimagesink->x_lock);
+ GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
+ ("Failed to create output image buffer of %dx%d pixels",
+ meta->width, meta->height),
+ ("could not get shared memory of %" G_GSIZE_FORMAT " bytes",
+ meta->size));
+ goto beach;
+ }
+shmat_failed:
+ {
+ g_mutex_unlock (xvimagesink->x_lock);
+ GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
+ ("Failed to create output image buffer of %dx%d pixels",
+ meta->width, meta->height),
+ ("Failed to shmat: %s", g_strerror (errno)));
+ /* Clean up the shared memory segment */
+ shmctl (meta->SHMInfo.shmid, IPC_RMID, NULL);
+ goto beach;
+ }
+xattach_failed:
+ {
+ /* Clean up the shared memory segment */
+ shmctl (meta->SHMInfo.shmid, IPC_RMID, NULL);
+ g_mutex_unlock (xvimagesink->x_lock);
+
+ GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
+ ("Failed to create output image buffer of %dx%d pixels",
+ meta->width, meta->height), ("Failed to XShmAttach"));
+ goto beach;
+ }
+}
+
+static void
+gst_meta_xvimage_free (GstMetaXvImage * meta, GstBuffer * buffer)
+{
+ GstXvImageSink *xvimagesink;
+
+ xvimagesink = meta->sink;
+
+ GST_DEBUG_OBJECT (xvimagesink, "free meta on buffer %p", buffer);
+
+ /* Hold the object lock to ensure the XContext doesn't disappear */
+ GST_OBJECT_LOCK (xvimagesink);
+ /* We might have some buffers destroyed after changing state to NULL */
+ if (xvimagesink->xcontext == NULL) {
+ GST_DEBUG_OBJECT (xvimagesink, "Destroying XvImage after Xcontext");
+#ifdef HAVE_XSHM
+ /* Need to free the shared memory segment even if the x context
+ * was already cleaned up */
+ if (meta->SHMInfo.shmaddr != ((void *) -1)) {
+ shmdt (meta->SHMInfo.shmaddr);
+ }
+#endif
+ goto beach;
+ }
+
+ g_mutex_lock (xvimagesink->x_lock);
+
+#ifdef HAVE_XSHM
+ if (xvimagesink->xcontext->use_xshm) {
+ if (meta->SHMInfo.shmaddr != ((void *) -1)) {
+ GST_DEBUG_OBJECT (xvimagesink, "XServer ShmDetaching from 0x%x id 0x%lx",
+ meta->SHMInfo.shmid, meta->SHMInfo.shmseg);
+ XShmDetach (xvimagesink->xcontext->disp, &meta->SHMInfo);
+ XSync (xvimagesink->xcontext->disp, FALSE);
+ shmdt (meta->SHMInfo.shmaddr);
+ meta->SHMInfo.shmaddr = (void *) -1;
+ }
+ if (meta->xvimage)
+ XFree (meta->xvimage);
+ } else
+#endif /* HAVE_XSHM */
+ {
+ if (meta->xvimage) {
+ g_free (meta->xvimage->data);
+ XFree (meta->xvimage);
+ }
+ }
+
+ XSync (xvimagesink->xcontext->disp, FALSE);
+
+ g_mutex_unlock (xvimagesink->x_lock);
+
+beach:
+ GST_OBJECT_UNLOCK (xvimagesink);
+
+ gst_object_unref (meta->sink);
+}
+
+GstBuffer *
+gst_xvimage_buffer_new (GstXvImageSink * xvimagesink, gint width, gint height,
+ gint im_format)
+{
+ GstBuffer *buffer;
+ GstMetaXvImage *meta;
+
+ buffer = gst_buffer_new ();
+ meta =
+ gst_buffer_add_meta_xvimage (buffer, xvimagesink, width, height,
+ im_format);
+ if (meta == NULL) {
+ gst_buffer_unref (buffer);
+ buffer = NULL;
+ }
+ return buffer;
+}
+
+#ifdef HAVE_XSHM
+/* This function checks that it is actually really possible to create an image
+ using XShm */
+gboolean
+gst_xvimagesink_check_xshm_calls (GstXvImageSink * xvimagesink,
+ GstXContext * xcontext)
+{
+ XvImage *xvimage;
+ XShmSegmentInfo SHMInfo;
+ size_t size;
+ int (*handler) (Display *, XErrorEvent *);
+ gboolean result = FALSE;
+ gboolean did_attach = FALSE;
+
+ g_return_val_if_fail (xcontext != NULL, FALSE);
+
+ /* Sync to ensure any older errors are already processed */
+ XSync (xcontext->disp, FALSE);
+
+ /* Set defaults so we don't free these later unnecessarily */
+ SHMInfo.shmaddr = ((void *) -1);
+ SHMInfo.shmid = -1;
+
+ /* Setting an error handler to catch failure */
+ error_caught = FALSE;
+ handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
+
+ /* Trying to create a 1x1 picture */
+ GST_DEBUG ("XvShmCreateImage of 1x1");
+ xvimage = XvShmCreateImage (xcontext->disp, xcontext->xv_port_id,
+ xcontext->im_format, NULL, 1, 1, &SHMInfo);
+
+ /* Might cause an error, sync to ensure it is noticed */
+ XSync (xcontext->disp, FALSE);
+ if (!xvimage || error_caught) {
+ GST_WARNING ("could not XvShmCreateImage a 1x1 image");
+ goto beach;
+ }
+ size = xvimage->data_size;
+
+ SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777);
+ if (SHMInfo.shmid == -1) {
+ GST_WARNING ("could not get shared memory of %" G_GSIZE_FORMAT " bytes",
+ size);
+ goto beach;
+ }
+
+ SHMInfo.shmaddr = shmat (SHMInfo.shmid, NULL, 0);
+ if (SHMInfo.shmaddr == ((void *) -1)) {
+ GST_WARNING ("Failed to shmat: %s", g_strerror (errno));
+ /* Clean up the shared memory segment */
+ shmctl (SHMInfo.shmid, IPC_RMID, NULL);
+ goto beach;
+ }
+
+ xvimage->data = SHMInfo.shmaddr;
+ SHMInfo.readOnly = FALSE;
+
+ if (XShmAttach (xcontext->disp, &SHMInfo) == 0) {
+ GST_WARNING ("Failed to XShmAttach");
+ /* Clean up the shared memory segment */
+ shmctl (SHMInfo.shmid, IPC_RMID, NULL);
+ goto beach;
+ }
+
+ /* Sync to ensure we see any errors we caused */
+ XSync (xcontext->disp, FALSE);
+
+ /* Delete the shared memory segment as soon as everyone is attached.
+ * This way, it will be deleted as soon as we detach later, and not
+ * leaked if we crash. */
+ shmctl (SHMInfo.shmid, IPC_RMID, NULL);
+
+ if (!error_caught) {
+ GST_DEBUG ("XServer ShmAttached to 0x%x, id 0x%lx", SHMInfo.shmid,
+ SHMInfo.shmseg);
+
+ did_attach = TRUE;
+ /* store whether we succeeded in result */
+ result = TRUE;
+ } else {
+ GST_WARNING ("MIT-SHM extension check failed at XShmAttach. "
+ "Not using shared memory.");
+ }
+
+beach:
+ /* Sync to ensure we swallow any errors we caused and reset error_caught */
+ XSync (xcontext->disp, FALSE);
+
+ error_caught = FALSE;
+ XSetErrorHandler (handler);
+
+ if (did_attach) {
+ GST_DEBUG ("XServer ShmDetaching from 0x%x id 0x%lx",
+ SHMInfo.shmid, SHMInfo.shmseg);
+ XShmDetach (xcontext->disp, &SHMInfo);
+ XSync (xcontext->disp, FALSE);
+ }
+ if (SHMInfo.shmaddr != ((void *) -1))
+ shmdt (SHMInfo.shmaddr);
+ if (xvimage)
+ XFree (xvimage);
+ return result;
+}
+#endif /* HAVE_XSHM */
+
+/* bufferpool */
+static void gst_xvimage_buffer_pool_finalize (GObject * object);
+
+#define GST_XVIMAGE_BUFFER_POOL_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_XVIMAGE_BUFFER_POOL, GstXvImageBufferPoolPrivate))
+
+struct _GstXvImageBufferPoolPrivate
+{
+ GstCaps *caps;
+ gint width, height;
+ gint im_format;
+};
+
+G_DEFINE_TYPE (GstXvImageBufferPool, gst_xvimage_buffer_pool,
+ GST_TYPE_BUFFER_POOL);
+
+static gboolean
+xvimage_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config)
+{
+ GstXvImageBufferPool *xvpool = GST_XVIMAGE_BUFFER_POOL_CAST (pool);
+ GstXvImageBufferPoolPrivate *priv = xvpool->priv;
+ GstStructure *structure;
+ gint width, height;
+ const GstCaps *caps;
+
+ if (!gst_buffer_pool_config_get (config, &caps, NULL, NULL, NULL, NULL,
+ NULL, NULL))
+ goto wrong_config;
+
+ if (caps == NULL)
+ goto no_caps;
+
+ /* now parse the caps from the config */
+ structure = gst_caps_get_structure (caps, 0);
+
+ if (!gst_structure_get_int (structure, "width", &width) ||
+ !gst_structure_get_int (structure, "height", &height))
+ goto wrong_caps;
+
+ GST_LOG_OBJECT (pool, "%dx%d, caps %" GST_PTR_FORMAT, width, height, caps);
+
+ /* keep track of the width and height and caps */
+ if (priv->caps)
+ gst_caps_unref (priv->caps);
+ priv->caps = gst_caps_copy (caps);
+ priv->width = width;
+ priv->height = height;
+ priv->im_format =
+ gst_xvimagesink_get_format_from_caps (xvpool->sink, (GstCaps *) caps);
+
+ if (priv->im_format == -1) {
+ GST_WARNING_OBJECT (xvpool->sink, "failed to get format from caps %"
+ GST_PTR_FORMAT, caps);
+ GST_ELEMENT_ERROR (xvpool->sink, RESOURCE, WRITE,
+ ("Failed to create output image buffer of %dx%d pixels",
+ priv->width, priv->height), ("Invalid input caps"));
+ goto wrong_config;
+ }
+
+ return TRUE;
+
+ /* ERRORS */
+wrong_config:
+ {
+ GST_WARNING_OBJECT (pool, "invalid config");
+ return FALSE;
+ }
+no_caps:
+ {
+ GST_WARNING_OBJECT (pool, "no caps in config");
+ return FALSE;
+ }
+wrong_caps:
+ {
+ GST_WARNING_OBJECT (pool,
+ "failed getting geometry from caps %" GST_PTR_FORMAT, caps);
+ return FALSE;
+ }
+}
+
+/* This function handles GstXImageBuffer creation depending on XShm availability */
+static GstFlowReturn
+xvimage_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer,
+ GstBufferPoolParams * params)
+{
+ GstXvImageBufferPool *xvpool = GST_XVIMAGE_BUFFER_POOL_CAST (pool);
+ GstXvImageBufferPoolPrivate *priv = xvpool->priv;
+ GstBuffer *xvimage;
+
+ xvimage =
+ gst_xvimage_buffer_new (xvpool->sink, priv->width, priv->height,
+ priv->im_format);
+ if (xvimage == NULL)
+ goto no_buffer;
+
+ *buffer = xvimage;
+
+ return GST_FLOW_OK;
+
+ /* ERROR */
+no_buffer:
+ {
+ GST_WARNING_OBJECT (pool, "can't create image");
+ return GST_FLOW_ERROR;
+ }
+}
+
+static void
+xvimage_buffer_pool_free (GstBufferPool * pool, GstBuffer * buffer)
+{
+ gst_buffer_unref (buffer);
+}
+
+GstBufferPool *
+gst_xvimage_buffer_pool_new (GstXvImageSink * xvimagesink)
+{
+ GstXvImageBufferPool *pool;
+
+ g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
+
+ pool = g_object_new (GST_TYPE_XVIMAGE_BUFFER_POOL, NULL);
+ pool->sink = gst_object_ref (xvimagesink);
+
+ GST_LOG_OBJECT (pool, "new XvImage buffer pool %p", pool);
+
+ return GST_BUFFER_POOL_CAST (pool);
+}
+
+static void
+gst_xvimage_buffer_pool_class_init (GstXvImageBufferPoolClass * klass)
+{
+ GObjectClass *gobject_class = (GObjectClass *) klass;
+ GstBufferPoolClass *gstbufferpool_class = (GstBufferPoolClass *) klass;
+
+ g_type_class_add_private (klass, sizeof (GstXvImageBufferPoolPrivate));
+
+ gobject_class->finalize = gst_xvimage_buffer_pool_finalize;
+
+ gstbufferpool_class->set_config = xvimage_buffer_pool_set_config;
+ gstbufferpool_class->alloc_buffer = xvimage_buffer_pool_alloc;
+ gstbufferpool_class->free_buffer = xvimage_buffer_pool_free;
+}
+
+static void
+gst_xvimage_buffer_pool_init (GstXvImageBufferPool * pool)
+{
+ pool->priv = GST_XVIMAGE_BUFFER_POOL_GET_PRIVATE (pool);
+}
+
+static void
+gst_xvimage_buffer_pool_finalize (GObject * object)
+{
+ GstXvImageBufferPool *pool = GST_XVIMAGE_BUFFER_POOL_CAST (object);
+ GstXvImageBufferPoolPrivate *priv = pool->priv;
+
+ GST_LOG_OBJECT (pool, "finalize XvImage buffer pool %p", pool);
+
+ if (priv->caps)
+ gst_caps_unref (priv->caps);
+ gst_object_unref (pool->sink);
+
+ G_OBJECT_CLASS (gst_xvimage_buffer_pool_parent_class)->finalize (object);
+}
+
+/* This function tries to get a format matching with a given caps in the
+ supported list of formats we generated in gst_xvimagesink_get_xv_support */
+gint
+gst_xvimagesink_get_format_from_caps (GstXvImageSink * xvimagesink,
+ GstCaps * caps)
+{
+ GList *list = NULL;
+
+ g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), 0);
+
+ list = xvimagesink->xcontext->formats_list;
+
+ while (list) {
+ GstXvImageFormat *format = list->data;
+
+ if (format) {
+ if (gst_caps_can_intersect (caps, format->caps)) {
+ return format->format;
+ }
+ }
+ list = g_list_next (list);
+ }
+
+ return -1;
+}
--- /dev/null
+/* GStreamer
+ * Copyright (C) <2005> Julien Moutte <julien@moutte.net>
+ *
+ * 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_XVIMAGEPOOL_H__
+#define __GST_XVIMAGEPOOL_H__
+
+#ifdef HAVE_XSHM
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#endif /* HAVE_XSHM */
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#ifdef HAVE_XSHM
+#include <X11/extensions/XShm.h>
+#endif /* HAVE_XSHM */
+
+#include <string.h>
+#include <math.h>
+
+
+G_BEGIN_DECLS
+
+typedef struct _GstMetaXvImage GstMetaXvImage;
+
+typedef struct _GstXvImageBufferPool GstXvImageBufferPool;
+typedef struct _GstXvImageBufferPoolClass GstXvImageBufferPoolClass;
+typedef struct _GstXvImageBufferPoolPrivate GstXvImageBufferPoolPrivate;
+
+#include "xvimagesink.h"
+
+const GstMetaInfo * gst_meta_xvimage_get_info (void);
+#define GST_META_INFO_XVIMAGE (gst_meta_xvimage_get_info())
+
+#define gst_buffer_get_meta_xvimage(b) ((GstMetaXvImage*)gst_buffer_get_meta((b),GST_META_INFO_XVIMAGE))
+GstMetaXvImage * gst_buffer_add_meta_xvimage (GstBuffer *buffer, GstXvImageSink * xvimagesink,
+ gint width, gint height, gint im_format);
+
+/**
+ * GstMetaXvImage:
+ * @sink: a reference to the our #GstXvImageSink
+ * @xvimage: the XvImage of this buffer
+ * @width: the width in pixels of XvImage @xvimage
+ * @height: the height in pixels of XvImage @xvimage
+ * @im_format: the format of XvImage @xvimage
+ * @size: the size in bytes of XvImage @xvimage
+ *
+ * Subclass of #GstMeta containing additional information about an XvImage.
+ */
+struct _GstMetaXvImage
+{
+ GstMeta meta;
+
+ /* Reference to the xvimagesink we belong to */
+ GstXvImageSink *sink;
+
+ XvImage *xvimage;
+
+#ifdef HAVE_XSHM
+ XShmSegmentInfo SHMInfo;
+#endif /* HAVE_XSHM */
+
+ gint width, height, im_format;
+ size_t size;
+};
+
+GstBuffer *gst_xvimage_buffer_new (GstXvImageSink *xvimagesink, gint width, gint height,
+ gint in_format);
+
+/* buffer pool functions */
+#define GST_TYPE_XVIMAGE_BUFFER_POOL (gst_xvimage_buffer_pool_get_type())
+#define GST_IS_XVIMAGE_BUFFER_POOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_XVIMAGE_BUFFER_POOL))
+#define GST_XVIMAGE_BUFFER_POOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_XVIMAGE_BUFFER_POOL, GstXvImageBufferPool))
+#define GST_XVIMAGE_BUFFER_POOL_CAST(obj) ((GstXvImageBufferPool*)(obj))
+
+struct _GstXvImageBufferPool
+{
+ GstBufferPool bufferpool;
+
+ GstXvImageSink *sink;
+
+ GstXvImageBufferPoolPrivate *priv;
+};
+
+struct _GstXvImageBufferPoolClass
+{
+ GstBufferPoolClass parent_class;
+};
+
+GType gst_xvimage_buffer_pool_get_type (void);
+
+GstBufferPool *gst_xvimage_buffer_pool_new (GstXvImageSink * xvimagesink);
+
+gboolean gst_xvimagesink_check_xshm_calls (GstXvImageSink * xvimagesink,
+ GstXContext * xcontext);
+
+gint gst_xvimagesink_get_format_from_caps (GstXvImageSink * xvimagesink,
+ GstCaps * caps);
+
+G_END_DECLS
+
+#endif /*__GST_XVIMAGEPOOL_H__*/
#include <gst/interfaces/propertyprobe.h>
/* Helper functions */
#include <gst/video/video.h>
+#include <gst/video/gstmetavideo.h>
/* Object header */
#include "xvimagesink.h"
/* Debugging category */
#include <gst/gstinfo.h>
-GST_DEBUG_CATEGORY_STATIC (gst_debug_xvimagesink);
+
+GST_DEBUG_CATEGORY_EXTERN (gst_debug_xvimagesink);
+GST_DEBUG_CATEGORY_EXTERN (GST_CAT_PERFORMANCE);
#define GST_CAT_DEFAULT gst_debug_xvimagesink
-GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE);
typedef struct
{
#define MWM_HINTS_DECORATIONS (1L << 1)
static void gst_xvimagesink_reset (GstXvImageSink * xvimagesink);
-
-static GstBufferClass *xvimage_buffer_parent_class = NULL;
-static void gst_xvimage_buffer_finalize (GstXvImageBuffer * xvimage);
-
static void gst_xvimagesink_xwindow_update_geometry (GstXvImageSink *
xvimagesink);
-static gint gst_xvimagesink_get_format_from_caps (GstXvImageSink * xvimagesink,
- GstCaps * caps);
static void gst_xvimagesink_expose (GstXOverlay * overlay);
/* Default template - initiated with class struct to allow gst-register to work
PROP_WINDOW_HEIGHT
};
-static void gst_xvimagesink_init_interfaces (GType type);
-
-GST_BOILERPLATE_FULL (GstXvImageSink, gst_xvimagesink, GstVideoSink,
- GST_TYPE_VIDEO_SINK, gst_xvimagesink_init_interfaces);
-
-
/* ============================================================= */
/* */
-/* Private Methods */
+/* Public Methods */
/* */
/* ============================================================= */
-/* xvimage buffers */
-
-#define GST_TYPE_XVIMAGE_BUFFER (gst_xvimage_buffer_get_type())
-
-#define GST_IS_XVIMAGE_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_XVIMAGE_BUFFER))
-#define GST_XVIMAGE_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_XVIMAGE_BUFFER, GstXvImageBuffer))
-#define GST_XVIMAGE_BUFFER_CAST(obj) ((GstXvImageBuffer *)(obj))
-
-/* This function destroys a GstXvImage handling XShm availability */
-static void
-gst_xvimage_buffer_destroy (GstXvImageBuffer * xvimage)
-{
- GstXvImageSink *xvimagesink;
-
- GST_DEBUG_OBJECT (xvimage, "Destroying buffer");
-
- xvimagesink = xvimage->xvimagesink;
- if (G_UNLIKELY (xvimagesink == NULL))
- goto no_sink;
-
- g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
-
- GST_OBJECT_LOCK (xvimagesink);
-
- /* If the destroyed image is the current one we destroy our reference too */
- if (xvimagesink->cur_image == xvimage)
- xvimagesink->cur_image = NULL;
-
- /* We might have some buffers destroyed after changing state to NULL */
- if (xvimagesink->xcontext == NULL) {
- GST_DEBUG_OBJECT (xvimagesink, "Destroying XvImage after Xcontext");
-#ifdef HAVE_XSHM
- /* Need to free the shared memory segment even if the x context
- * was already cleaned up */
- if (xvimage->SHMInfo.shmaddr != ((void *) -1)) {
- shmdt (xvimage->SHMInfo.shmaddr);
- }
-#endif
- goto beach;
- }
-
- g_mutex_lock (xvimagesink->x_lock);
-
-#ifdef HAVE_XSHM
- if (xvimagesink->xcontext->use_xshm) {
- if (xvimage->SHMInfo.shmaddr != ((void *) -1)) {
- GST_DEBUG_OBJECT (xvimagesink, "XServer ShmDetaching from 0x%x id 0x%lx",
- xvimage->SHMInfo.shmid, xvimage->SHMInfo.shmseg);
- XShmDetach (xvimagesink->xcontext->disp, &xvimage->SHMInfo);
- XSync (xvimagesink->xcontext->disp, FALSE);
-
- shmdt (xvimage->SHMInfo.shmaddr);
- }
- if (xvimage->xvimage)
- XFree (xvimage->xvimage);
- } else
-#endif /* HAVE_XSHM */
- {
- if (xvimage->xvimage) {
- if (xvimage->xvimage->data) {
- g_free (xvimage->xvimage->data);
- }
- XFree (xvimage->xvimage);
- }
- }
-
- XSync (xvimagesink->xcontext->disp, FALSE);
-
- g_mutex_unlock (xvimagesink->x_lock);
-
-beach:
- GST_OBJECT_UNLOCK (xvimagesink);
- xvimage->xvimagesink = NULL;
- gst_object_unref (xvimagesink);
-
- GST_MINI_OBJECT_CLASS (xvimage_buffer_parent_class)->finalize (GST_MINI_OBJECT
- (xvimage));
-
- return;
-
-no_sink:
- {
- GST_WARNING ("no sink found");
- return;
- }
-}
-
-static void
-gst_xvimage_buffer_finalize (GstXvImageBuffer * xvimage)
-{
- GstXvImageSink *xvimagesink;
- gboolean running;
-
- xvimagesink = xvimage->xvimagesink;
- if (G_UNLIKELY (xvimagesink == NULL))
- goto no_sink;
-
- g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink));
-
- GST_OBJECT_LOCK (xvimagesink);
- running = xvimagesink->running;
- GST_OBJECT_UNLOCK (xvimagesink);
-
- /* If our geometry changed we can't reuse that image. */
- if (running == FALSE) {
- GST_LOG_OBJECT (xvimage, "destroy image as sink is shutting down");
- gst_xvimage_buffer_destroy (xvimage);
- } else if ((xvimage->width != xvimagesink->video_width) ||
- (xvimage->height != xvimagesink->video_height)) {
- GST_LOG_OBJECT (xvimage,
- "destroy image as its size changed %dx%d vs current %dx%d",
- xvimage->width, xvimage->height,
- xvimagesink->video_width, xvimagesink->video_height);
- gst_xvimage_buffer_destroy (xvimage);
- } else {
- /* In that case we can reuse the image and add it to our image pool. */
- GST_LOG_OBJECT (xvimage, "recycling image in pool");
- /* need to increment the refcount again to recycle */
- gst_buffer_ref (GST_BUFFER_CAST (xvimage));
- g_mutex_lock (xvimagesink->pool_lock);
- xvimagesink->image_pool = g_slist_prepend (xvimagesink->image_pool,
- xvimage);
- g_mutex_unlock (xvimagesink->pool_lock);
- }
- return;
-
-no_sink:
- {
- GST_WARNING ("no sink found");
- return;
- }
-}
-
-static void
-gst_xvimage_buffer_free (GstXvImageBuffer * xvimage)
-{
- /* make sure it is not recycled */
- xvimage->width = -1;
- xvimage->height = -1;
- gst_buffer_unref (GST_BUFFER (xvimage));
-}
-
-static void
-gst_xvimage_buffer_init (GstXvImageBuffer * xvimage, gpointer g_class)
-{
-#ifdef HAVE_XSHM
- xvimage->SHMInfo.shmaddr = ((void *) -1);
- xvimage->SHMInfo.shmid = -1;
-#endif
-}
-
+/* =========================================== */
+/* */
+/* Object typing & Creation */
+/* */
+/* =========================================== */
+static void gst_xvimagesink_interface_init (GstImplementsInterfaceClass *
+ klass);
+static void gst_xvimagesink_navigation_init (GstNavigationInterface * iface);
+static void gst_xvimagesink_xoverlay_init (GstXOverlayClass * iface);
+static void gst_xvimagesink_colorbalance_init (GstColorBalanceClass * iface);
static void
-gst_xvimage_buffer_class_init (gpointer g_class, gpointer class_data)
-{
- GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
-
- xvimage_buffer_parent_class = g_type_class_peek_parent (g_class);
-
- mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
- gst_xvimage_buffer_finalize;
-}
-
-static GType
-gst_xvimage_buffer_get_type (void)
-{
- static GType _gst_xvimage_buffer_type;
-
- if (G_UNLIKELY (_gst_xvimage_buffer_type == 0)) {
- static const GTypeInfo xvimage_buffer_info = {
- sizeof (GstBufferClass),
- NULL,
- NULL,
- gst_xvimage_buffer_class_init,
- NULL,
- NULL,
- sizeof (GstXvImageBuffer),
- 0,
- (GInstanceInitFunc) gst_xvimage_buffer_init,
- NULL
- };
- _gst_xvimage_buffer_type = g_type_register_static (GST_TYPE_BUFFER,
- "GstXvImageBuffer", &xvimage_buffer_info, 0);
- }
- return _gst_xvimage_buffer_type;
-}
-
-/* X11 stuff */
-
-static gboolean error_caught = FALSE;
-
-static int
-gst_xvimagesink_handle_xerror (Display * display, XErrorEvent * xevent)
-{
- char error_msg[1024];
-
- XGetErrorText (display, xevent->error_code, error_msg, 1024);
- GST_DEBUG ("xvimagesink triggered an XError. error: %s", error_msg);
- error_caught = TRUE;
- return 0;
-}
-
-#ifdef HAVE_XSHM
-/* This function checks that it is actually really possible to create an image
- using XShm */
-static gboolean
-gst_xvimagesink_check_xshm_calls (GstXContext * xcontext)
-{
- XvImage *xvimage;
- XShmSegmentInfo SHMInfo;
- gint size;
- int (*handler) (Display *, XErrorEvent *);
- gboolean result = FALSE;
- gboolean did_attach = FALSE;
-
- g_return_val_if_fail (xcontext != NULL, FALSE);
-
- /* Sync to ensure any older errors are already processed */
- XSync (xcontext->disp, FALSE);
-
- /* Set defaults so we don't free these later unnecessarily */
- SHMInfo.shmaddr = ((void *) -1);
- SHMInfo.shmid = -1;
-
- /* Setting an error handler to catch failure */
- error_caught = FALSE;
- handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
-
- /* Trying to create a 1x1 picture */
- GST_DEBUG ("XvShmCreateImage of 1x1");
- xvimage = XvShmCreateImage (xcontext->disp, xcontext->xv_port_id,
- xcontext->im_format, NULL, 1, 1, &SHMInfo);
-
- /* Might cause an error, sync to ensure it is noticed */
- XSync (xcontext->disp, FALSE);
- if (!xvimage || error_caught) {
- GST_WARNING ("could not XvShmCreateImage a 1x1 image");
- goto beach;
- }
- size = xvimage->data_size;
-
- SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777);
- if (SHMInfo.shmid == -1) {
- GST_WARNING ("could not get shared memory of %d bytes", size);
- goto beach;
- }
-
- SHMInfo.shmaddr = shmat (SHMInfo.shmid, NULL, 0);
- if (SHMInfo.shmaddr == ((void *) -1)) {
- GST_WARNING ("Failed to shmat: %s", g_strerror (errno));
- /* Clean up the shared memory segment */
- shmctl (SHMInfo.shmid, IPC_RMID, NULL);
- goto beach;
- }
-
- xvimage->data = SHMInfo.shmaddr;
- SHMInfo.readOnly = FALSE;
-
- if (XShmAttach (xcontext->disp, &SHMInfo) == 0) {
- GST_WARNING ("Failed to XShmAttach");
- /* Clean up the shared memory segment */
- shmctl (SHMInfo.shmid, IPC_RMID, NULL);
- goto beach;
- }
-
- /* Sync to ensure we see any errors we caused */
- XSync (xcontext->disp, FALSE);
-
- /* Delete the shared memory segment as soon as everyone is attached.
- * This way, it will be deleted as soon as we detach later, and not
- * leaked if we crash. */
- shmctl (SHMInfo.shmid, IPC_RMID, NULL);
-
- if (!error_caught) {
- GST_DEBUG ("XServer ShmAttached to 0x%x, id 0x%lx", SHMInfo.shmid,
- SHMInfo.shmseg);
-
- did_attach = TRUE;
- /* store whether we succeeded in result */
- result = TRUE;
- } else {
- GST_WARNING ("MIT-SHM extension check failed at XShmAttach. "
- "Not using shared memory.");
- }
-
-beach:
- /* Sync to ensure we swallow any errors we caused and reset error_caught */
- XSync (xcontext->disp, FALSE);
-
- error_caught = FALSE;
- XSetErrorHandler (handler);
-
- if (did_attach) {
- GST_DEBUG ("XServer ShmDetaching from 0x%x id 0x%lx",
- SHMInfo.shmid, SHMInfo.shmseg);
- XShmDetach (xcontext->disp, &SHMInfo);
- XSync (xcontext->disp, FALSE);
- }
- if (SHMInfo.shmaddr != ((void *) -1))
- shmdt (SHMInfo.shmaddr);
- if (xvimage)
- XFree (xvimage);
- return result;
-}
-#endif /* HAVE_XSHM */
-
-/* This function handles GstXvImage creation depending on XShm availability */
-static GstXvImageBuffer *
-gst_xvimagesink_xvimage_new (GstXvImageSink * xvimagesink, GstCaps * caps)
-{
- GstXvImageBuffer *xvimage = NULL;
- GstStructure *structure = NULL;
- gboolean succeeded = FALSE;
- int (*handler) (Display *, XErrorEvent *);
-
- g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL);
-
- if (caps == NULL)
- return NULL;
-
- xvimage = (GstXvImageBuffer *) gst_mini_object_new (GST_TYPE_XVIMAGE_BUFFER);
- GST_DEBUG_OBJECT (xvimage, "Creating new XvImageBuffer");
-
- structure = gst_caps_get_structure (caps, 0);
-
- if (!gst_structure_get_int (structure, "width", &xvimage->width) ||
- !gst_structure_get_int (structure, "height", &xvimage->height)) {
- GST_WARNING ("failed getting geometry from caps %" GST_PTR_FORMAT, caps);
- }
-
- GST_LOG_OBJECT (xvimagesink, "creating %dx%d", xvimage->width,
- xvimage->height);
-
- xvimage->im_format = gst_xvimagesink_get_format_from_caps (xvimagesink, caps);
- if (xvimage->im_format == -1) {
- GST_WARNING_OBJECT (xvimagesink, "failed to get format from caps %"
- GST_PTR_FORMAT, caps);
- GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
- ("Failed to create output image buffer of %dx%d pixels",
- xvimage->width, xvimage->height), ("Invalid input caps"));
- goto beach_unlocked;
- }
- xvimage->xvimagesink = gst_object_ref (xvimagesink);
-
- g_mutex_lock (xvimagesink->x_lock);
-
- /* Setting an error handler to catch failure */
- error_caught = FALSE;
- handler = XSetErrorHandler (gst_xvimagesink_handle_xerror);
-
-#ifdef HAVE_XSHM
- if (xvimagesink->xcontext->use_xshm) {
- int expected_size;
-
- xvimage->xvimage = XvShmCreateImage (xvimagesink->xcontext->disp,
- xvimagesink->xcontext->xv_port_id,
- xvimage->im_format, NULL,
- xvimage->width, xvimage->height, &xvimage->SHMInfo);
- if (!xvimage->xvimage || error_caught) {
- g_mutex_unlock (xvimagesink->x_lock);
-
- /* Reset error flag */
- error_caught = FALSE;
-
- /* Push a warning */
- GST_ELEMENT_WARNING (xvimagesink, RESOURCE, WRITE,
- ("Failed to create output image buffer of %dx%d pixels",
- xvimage->width, xvimage->height),
- ("could not XvShmCreateImage a %dx%d image",
- xvimage->width, xvimage->height));
-
- /* Retry without XShm */
- xvimagesink->xcontext->use_xshm = FALSE;
-
- /* Hold X mutex again to try without XShm */
- g_mutex_lock (xvimagesink->x_lock);
- goto no_xshm;
- }
-
- /* we have to use the returned data_size for our shm size */
- xvimage->size = xvimage->xvimage->data_size;
- GST_LOG_OBJECT (xvimagesink, "XShm image size is %" G_GSIZE_FORMAT,
- xvimage->size);
-
- /* calculate the expected size. This is only for sanity checking the
- * number we get from X. */
- switch (xvimage->im_format) {
- case GST_MAKE_FOURCC ('I', '4', '2', '0'):
- case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
- {
- gint pitches[3];
- gint offsets[3];
- guint plane;
-
- offsets[0] = 0;
- pitches[0] = GST_ROUND_UP_4 (xvimage->width);
- offsets[1] = offsets[0] + pitches[0] * GST_ROUND_UP_2 (xvimage->height);
- pitches[1] = GST_ROUND_UP_8 (xvimage->width) / 2;
- offsets[2] =
- offsets[1] + pitches[1] * GST_ROUND_UP_2 (xvimage->height) / 2;
- pitches[2] = GST_ROUND_UP_8 (pitches[0]) / 2;
-
- expected_size =
- offsets[2] + pitches[2] * GST_ROUND_UP_2 (xvimage->height) / 2;
-
- for (plane = 0; plane < xvimage->xvimage->num_planes; plane++) {
- GST_DEBUG_OBJECT (xvimagesink,
- "Plane %u has a expected pitch of %d bytes, " "offset of %d",
- plane, pitches[plane], offsets[plane]);
- }
- break;
- }
- case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
- case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
- expected_size = xvimage->height * GST_ROUND_UP_4 (xvimage->width * 2);
- break;
- default:
- expected_size = 0;
- break;
- }
- if (expected_size != 0 && xvimage->size != expected_size) {
- GST_WARNING_OBJECT (xvimagesink,
- "unexpected XShm image size (got %" G_GSIZE_FORMAT ", expected %d)",
- xvimage->size, expected_size);
- }
-
- /* Be verbose about our XvImage stride */
- {
- guint plane;
-
- for (plane = 0; plane < xvimage->xvimage->num_planes; plane++) {
- GST_DEBUG_OBJECT (xvimagesink, "Plane %u has a pitch of %d bytes, "
- "offset of %d", plane, xvimage->xvimage->pitches[plane],
- xvimage->xvimage->offsets[plane]);
- }
- }
-
- xvimage->SHMInfo.shmid = shmget (IPC_PRIVATE, xvimage->size,
- IPC_CREAT | 0777);
- if (xvimage->SHMInfo.shmid == -1) {
- g_mutex_unlock (xvimagesink->x_lock);
- GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
- ("Failed to create output image buffer of %dx%d pixels",
- xvimage->width, xvimage->height),
- ("could not get shared memory of %" G_GSIZE_FORMAT " bytes",
- xvimage->size));
- goto beach_unlocked;
- }
-
- xvimage->SHMInfo.shmaddr = shmat (xvimage->SHMInfo.shmid, NULL, 0);
- if (xvimage->SHMInfo.shmaddr == ((void *) -1)) {
- g_mutex_unlock (xvimagesink->x_lock);
- GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
- ("Failed to create output image buffer of %dx%d pixels",
- xvimage->width, xvimage->height),
- ("Failed to shmat: %s", g_strerror (errno)));
- /* Clean up the shared memory segment */
- shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL);
- goto beach_unlocked;
- }
-
- xvimage->xvimage->data = xvimage->SHMInfo.shmaddr;
- xvimage->SHMInfo.readOnly = FALSE;
-
- if (XShmAttach (xvimagesink->xcontext->disp, &xvimage->SHMInfo) == 0) {
- /* Clean up the shared memory segment */
- shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL);
-
- g_mutex_unlock (xvimagesink->x_lock);
- GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
- ("Failed to create output image buffer of %dx%d pixels",
- xvimage->width, xvimage->height), ("Failed to XShmAttach"));
- goto beach_unlocked;
- }
-
- XSync (xvimagesink->xcontext->disp, FALSE);
-
- /* Delete the shared memory segment as soon as we everyone is attached.
- * This way, it will be deleted as soon as we detach later, and not
- * leaked if we crash. */
- shmctl (xvimage->SHMInfo.shmid, IPC_RMID, NULL);
-
- GST_DEBUG_OBJECT (xvimagesink, "XServer ShmAttached to 0x%x, id 0x%lx",
- xvimage->SHMInfo.shmid, xvimage->SHMInfo.shmseg);
- } else
- no_xshm:
-#endif /* HAVE_XSHM */
- {
- xvimage->xvimage = XvCreateImage (xvimagesink->xcontext->disp,
- xvimagesink->xcontext->xv_port_id,
- xvimage->im_format, NULL, xvimage->width, xvimage->height);
- if (!xvimage->xvimage || error_caught) {
- g_mutex_unlock (xvimagesink->x_lock);
- /* Reset error handler */
- error_caught = FALSE;
- XSetErrorHandler (handler);
- /* Push an error */
- GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
- ("Failed to create outputimage buffer of %dx%d pixels",
- xvimage->width, xvimage->height),
- ("could not XvCreateImage a %dx%d image",
- xvimage->width, xvimage->height));
- goto beach_unlocked;
- }
-
- /* we have to use the returned data_size for our image size */
- xvimage->size = xvimage->xvimage->data_size;
- xvimage->xvimage->data = g_malloc (xvimage->size);
-
- XSync (xvimagesink->xcontext->disp, FALSE);
- }
-
- /* Reset error handler */
- error_caught = FALSE;
- XSetErrorHandler (handler);
-
- succeeded = TRUE;
-
- GST_BUFFER_DATA (xvimage) = (guchar *) xvimage->xvimage->data;
- GST_BUFFER_SIZE (xvimage) = xvimage->size;
+gst_xvimagesink_property_probe_interface_init (GstPropertyProbeInterface *
+ iface);
+#define gst_xvimagesink_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstXvImageSink, gst_xvimagesink, GST_TYPE_VIDEO_SINK,
+ G_IMPLEMENT_INTERFACE (GST_TYPE_IMPLEMENTS_INTERFACE,
+ gst_xvimagesink_interface_init);
+ G_IMPLEMENT_INTERFACE (GST_TYPE_NAVIGATION,
+ gst_xvimagesink_navigation_init);
+ G_IMPLEMENT_INTERFACE (GST_TYPE_X_OVERLAY, gst_xvimagesink_xoverlay_init);
+ G_IMPLEMENT_INTERFACE (GST_TYPE_COLOR_BALANCE,
+ gst_xvimagesink_colorbalance_init);
+ G_IMPLEMENT_INTERFACE (GST_TYPE_PROPERTY_PROBE,
+ gst_xvimagesink_property_probe_interface_init));
- g_mutex_unlock (xvimagesink->x_lock);
-beach_unlocked:
- if (!succeeded) {
- gst_xvimage_buffer_free (xvimage);
- xvimage = NULL;
- }
+/* ============================================================= */
+/* */
+/* Private Methods */
+/* */
+/* ============================================================= */
- return xvimage;
-}
/* We are called with the x_lock taken */
static void
/* This function puts a GstXvImage on a GstXvImageSink's window. Returns FALSE
* if no window was available */
static gboolean
-gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink,
- GstXvImageBuffer * xvimage)
+gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink, GstBuffer * xvimage)
{
+ GstMetaXvImage *meta;
GstVideoRectangle result;
gboolean draw_border = FALSE;
if (xvimage && xvimagesink->cur_image != xvimage) {
if (xvimagesink->cur_image) {
GST_LOG_OBJECT (xvimagesink, "unreffing %p", xvimagesink->cur_image);
- gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->cur_image));
+ gst_buffer_unref (xvimagesink->cur_image);
}
GST_LOG_OBJECT (xvimagesink, "reffing %p as our current image", xvimage);
- xvimagesink->cur_image =
- GST_XVIMAGE_BUFFER_CAST (gst_buffer_ref (GST_BUFFER_CAST (xvimage)));
+ xvimagesink->cur_image = gst_buffer_ref (xvimage);
}
/* Expose sends a NULL image, we take the latest frame */
}
}
+ meta = gst_buffer_get_meta_xvimage (xvimage);
+
if (xvimagesink->keep_aspect) {
GstVideoRectangle src, dst;
result);
xvimagesink->redraw_border = FALSE;
}
-
- /* We scale to the window's geometry */
#ifdef HAVE_XSHM
if (xvimagesink->xcontext->use_xshm) {
GST_LOG_OBJECT (xvimagesink,
"XvShmPutImage with image %dx%d and window %dx%d, from xvimage %"
- GST_PTR_FORMAT,
- xvimage->width, xvimage->height,
+ GST_PTR_FORMAT, meta->width, meta->height,
xvimagesink->render_rect.w, xvimagesink->render_rect.h, xvimage);
XvShmPutImage (xvimagesink->xcontext->disp,
xvimagesink->xcontext->xv_port_id,
xvimagesink->xwindow->win,
- xvimagesink->xwindow->gc, xvimage->xvimage,
+ xvimagesink->xwindow->gc, meta->xvimage,
xvimagesink->disp_x, xvimagesink->disp_y,
xvimagesink->disp_width, xvimagesink->disp_height,
result.x, result.y, result.w, result.h, FALSE);
XvPutImage (xvimagesink->xcontext->disp,
xvimagesink->xcontext->xv_port_id,
xvimagesink->xwindow->win,
- xvimagesink->xwindow->gc, xvimage->xvimage,
+ xvimagesink->xwindow->gc, meta->xvimage,
xvimagesink->disp_x, xvimagesink->disp_y,
xvimagesink->disp_width, xvimagesink->disp_height,
result.x, result.y, result.w, result.h);
g_mutex_lock (xvimagesink->flow_lock);
g_mutex_lock (xvimagesink->x_lock);
}
+
if (pointer_moved) {
g_mutex_unlock (xvimagesink->x_lock);
g_mutex_unlock (xvimagesink->flow_lock);
}
break;
default:
- GST_DEBUG ("xvimagesink unhandled X event (%d)", e.type);
+ GST_DEBUG_OBJECT (xvimagesink, "xvimagesink unhandled X event (%d)",
+ e.type);
}
g_mutex_lock (xvimagesink->flow_lock);
g_mutex_lock (xvimagesink->x_lock);
ratio = 4.0 * 576 / (3.0 * 720);
}
GST_DEBUG ("calculated pixel aspect ratio: %f", ratio);
+
/* now find the one from par[][2] with the lowest delta to the real one */
delta = DELTA (0);
index = 0;
xcontext->caps = gst_xvimagesink_get_xv_support (xvimagesink, xcontext);
- if (!xcontext->caps) {
- XCloseDisplay (xcontext->disp);
- g_mutex_unlock (xvimagesink->x_lock);
- g_free (xcontext->par);
- g_free (xcontext);
- /* GST_ELEMENT_ERROR is thrown by gst_xvimagesink_get_xv_support */
- return NULL;
- }
-#ifdef HAVE_XSHM
/* Search for XShm extension support */
+#ifdef HAVE_XSHM
if (XShmQueryExtension (xcontext->disp) &&
- gst_xvimagesink_check_xshm_calls (xcontext)) {
+ gst_xvimagesink_check_xshm_calls (xvimagesink, xcontext)) {
xcontext->use_xshm = TRUE;
GST_DEBUG ("xvimagesink is using XShm extension");
} else
GST_DEBUG ("xvimagesink is not using XShm extension");
}
+ if (!xcontext->caps) {
+ XCloseDisplay (xcontext->disp);
+ g_mutex_unlock (xvimagesink->x_lock);
+ g_free (xcontext->par);
+ g_free (xcontext);
+ /* GST_ELEMENT_ERROR is thrown by gst_xvimagesink_get_xv_support */
+ return NULL;
+ }
+
xv_attr = XvQueryPortAttributes (xcontext->disp,
xcontext->xv_port_id, &N_attr);
channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL);
channel->label = g_strdup (channels[i]);
- channel->min_value = matching_attr->min_value;
- channel->max_value = matching_attr->max_value;
+ channel->min_value = matching_attr ? matching_attr->min_value : -1000;
+ channel->max_value = matching_attr ? matching_attr->max_value : 1000;
xcontext->channels_list = g_list_append (xcontext->channels_list,
channel);
g_free (xcontext);
}
-static void
-gst_xvimagesink_imagepool_clear (GstXvImageSink * xvimagesink)
-{
- g_mutex_lock (xvimagesink->pool_lock);
-
- while (xvimagesink->image_pool) {
- GstXvImageBuffer *xvimage = xvimagesink->image_pool->data;
-
- xvimagesink->image_pool = g_slist_delete_link (xvimagesink->image_pool,
- xvimagesink->image_pool);
- gst_xvimage_buffer_free (xvimage);
- }
-
- g_mutex_unlock (xvimagesink->pool_lock);
-}
-
/* Element stuff */
-/* This function tries to get a format matching with a given caps in the
- supported list of formats we generated in gst_xvimagesink_get_xv_support */
-static gint
-gst_xvimagesink_get_format_from_caps (GstXvImageSink * xvimagesink,
- GstCaps * caps)
-{
- GList *list = NULL;
-
- g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), 0);
-
- list = xvimagesink->xcontext->formats_list;
-
- while (list) {
- GstXvImageFormat *format = list->data;
-
- if (format) {
- if (gst_caps_can_intersect (caps, format->caps)) {
- return format->format;
- }
- }
- list = g_list_next (list);
- }
-
- return -1;
-}
-
static GstCaps *
-gst_xvimagesink_getcaps (GstBaseSink * bsink)
+gst_xvimagesink_getcaps (GstBaseSink * bsink, GstCaps * filter)
{
GstXvImageSink *xvimagesink;
+ GstCaps *caps;
xvimagesink = GST_XVIMAGESINK (bsink);
- if (xvimagesink->xcontext)
- return gst_caps_ref (xvimagesink->xcontext->caps);
+ if (xvimagesink->xcontext) {
+ if (filter)
+ return gst_caps_intersect_full (filter, xvimagesink->xcontext->caps,
+ GST_CAPS_INTERSECT_FIRST);
+ else
+ return gst_caps_ref (xvimagesink->xcontext->caps);
+ }
+
+ caps = gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD (xvimagesink));
+ if (filter) {
+ GstCaps *intersection;
- return
- gst_caps_copy (gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD
- (xvimagesink)));
+ intersection =
+ gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+ gst_caps_unref (caps);
+ caps = intersection;
+ }
+ return caps;
}
static gboolean
{
GstXvImageSink *xvimagesink;
GstStructure *structure;
- guint32 im_format = 0;
+ GstBufferPool *newpool, *oldpool;
gboolean ret;
+ guint32 im_format = 0;
gint video_width, video_height;
gint disp_x, disp_y;
gint disp_width, disp_height;
* doesn't cover the same area */
xvimagesink->redraw_border = TRUE;
- /* We renew our xvimage only if size or format changed;
- * the xvimage is the same size as the video pixel size */
- if ((xvimagesink->xvimage) &&
- ((im_format != xvimagesink->xvimage->im_format) ||
- (video_width != xvimagesink->xvimage->width) ||
- (video_height != xvimagesink->xvimage->height))) {
- GST_DEBUG_OBJECT (xvimagesink,
- "old format %" GST_FOURCC_FORMAT ", new format %" GST_FOURCC_FORMAT,
- GST_FOURCC_ARGS (xvimagesink->xvimage->im_format),
- GST_FOURCC_ARGS (im_format));
- GST_DEBUG_OBJECT (xvimagesink, "renewing xvimage");
- gst_buffer_unref (GST_BUFFER (xvimagesink->xvimage));
- xvimagesink->xvimage = NULL;
- }
+ /* create a new pool for the new configuration */
+ newpool = gst_xvimage_buffer_pool_new (xvimagesink);
+ structure = gst_buffer_pool_get_config (newpool);
+ gst_buffer_pool_config_set (structure, caps, 0, 0, 0, 0, 0, 16);
+ if (!gst_buffer_pool_set_config (newpool, structure))
+ goto config_failed;
+
+ if (!gst_buffer_pool_set_active (newpool, TRUE))
+ goto activate_failed;
+
+ oldpool = xvimagesink->pool;
+ xvimagesink->pool = newpool;
g_mutex_unlock (xvimagesink->flow_lock);
+ /* unref the old sink */
+ if (oldpool) {
+ /* deactivate */
+ gst_buffer_pool_set_active (oldpool, FALSE);
+ gst_object_unref (oldpool);
+ }
+
return TRUE;
/* ERRORS */
("Error calculating the output display ratio of the video."));
return FALSE;
}
+config_failed:
+ {
+ GST_ERROR_OBJECT (xvimagesink, "failed to set config.");
+ g_mutex_unlock (xvimagesink->flow_lock);
+ return FALSE;
+ }
+activate_failed:
+ {
+ GST_ERROR_OBJECT (xvimagesink, "failed to activate bufferpool.");
+ g_mutex_unlock (xvimagesink->flow_lock);
+ gst_object_unref (newpool);
+ return FALSE;
+ }
}
static GstStateChangeReturn
/* Initializing the XContext */
if (xvimagesink->xcontext == NULL) {
xcontext = gst_xvimagesink_xcontext_get (xvimagesink);
- if (xcontext == NULL)
- return GST_STATE_CHANGE_FAILURE;
+ if (xcontext == NULL) {
+ ret = GST_STATE_CHANGE_FAILURE;
+ goto beach;
+ }
GST_OBJECT_LOCK (xvimagesink);
if (xcontext)
xvimagesink->xcontext = xcontext;
gst_xvimagesink_manage_event_thread (xvimagesink);
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
- g_mutex_lock (xvimagesink->pool_lock);
- xvimagesink->pool_invalid = FALSE;
- g_mutex_unlock (xvimagesink->pool_lock);
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
- g_mutex_lock (xvimagesink->pool_lock);
- xvimagesink->pool_invalid = TRUE;
- g_mutex_unlock (xvimagesink->pool_lock);
break;
default:
break;
xvimagesink->fps_d = 1;
GST_VIDEO_SINK_WIDTH (xvimagesink) = 0;
GST_VIDEO_SINK_HEIGHT (xvimagesink) = 0;
+ g_mutex_lock (xvimagesink->flow_lock);
+ if (xvimagesink->pool)
+ gst_buffer_pool_set_active (xvimagesink->pool, FALSE);
+ g_mutex_unlock (xvimagesink->flow_lock);
break;
case GST_STATE_CHANGE_READY_TO_NULL:
gst_xvimagesink_reset (xvimagesink);
break;
}
+beach:
return ret;
}
static GstFlowReturn
gst_xvimagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf)
{
+ GstFlowReturn res;
GstXvImageSink *xvimagesink;
+ GstMetaXvImage *meta;
+ GstBuffer *to_put;
xvimagesink = GST_XVIMAGESINK (vsink);
- /* If this buffer has been allocated using our buffer management we simply
- put the ximage which is in the PRIVATE pointer */
- if (GST_IS_XVIMAGE_BUFFER (buf)) {
- GST_LOG_OBJECT (xvimagesink, "fast put of bufferpool buffer %p", buf);
- if (!gst_xvimagesink_xvimage_put (xvimagesink,
- GST_XVIMAGE_BUFFER_CAST (buf)))
- goto no_window;
+ meta = gst_buffer_get_meta_xvimage (buf);
+
+ if (meta) {
+ /* If this buffer has been allocated using our buffer management we simply
+ put the ximage which is in the PRIVATE pointer */
+ GST_LOG_OBJECT (xvimagesink, "buffer %p from our pool, writing directly",
+ buf);
+ res = GST_FLOW_OK;
+ to_put = buf;
} else {
- GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, xvimagesink,
- "slow copy into bufferpool buffer %p", buf);
+ guint8 *data;
+ gsize size;
+
/* Else we have to copy the data into our private image, */
/* if we have one... */
- if (!xvimagesink->xvimage) {
- GST_DEBUG_OBJECT (xvimagesink, "creating our xvimage");
+ GST_LOG_OBJECT (xvimagesink, "buffer %p not from our pool, copying", buf);
- xvimagesink->xvimage = gst_xvimagesink_xvimage_new (xvimagesink,
- GST_BUFFER_CAPS (buf));
+ /* we should have a pool, configured in setcaps */
+ if (xvimagesink->pool == NULL)
+ goto no_pool;
- if (!xvimagesink->xvimage)
- /* The create method should have posted an informative error */
- goto no_image;
+ /* take a buffer form our pool */
+ res = gst_buffer_pool_acquire_buffer (xvimagesink->pool, &to_put, NULL);
+ if (res != GST_FLOW_OK)
+ goto no_buffer;
- if (xvimagesink->xvimage->size < GST_BUFFER_SIZE (buf)) {
- GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
- ("Failed to create output image buffer of %dx%d pixels",
- xvimagesink->xvimage->width, xvimagesink->xvimage->height),
- ("XServer allocated buffer size did not match input buffer"));
+ if (gst_buffer_get_size (to_put) < gst_buffer_get_size (buf))
+ goto wrong_size;
- gst_xvimage_buffer_destroy (xvimagesink->xvimage);
- xvimagesink->xvimage = NULL;
- goto no_image;
- }
- }
-
- memcpy (xvimagesink->xvimage->xvimage->data,
- GST_BUFFER_DATA (buf),
- MIN (GST_BUFFER_SIZE (buf), xvimagesink->xvimage->size));
+ GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, xvimagesink,
+ "slow copy into bufferpool buffer %p", to_put);
- if (!gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage))
- goto no_window;
+ data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
+ gst_buffer_fill (to_put, 0, data, size);
+ gst_buffer_unmap (buf, data, size);
}
- return GST_FLOW_OK;
+ if (!gst_xvimagesink_xvimage_put (xvimagesink, to_put))
+ goto no_window;
+
+done:
+ if (to_put != buf)
+ gst_buffer_unref (to_put);
+
+ return res;
/* ERRORS */
-no_image:
+no_pool:
+ {
+ GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
+ ("Internal error: can't allocate images"),
+ ("We don't have a bufferpool negotiated"));
+ return GST_FLOW_ERROR;
+ }
+no_buffer:
{
/* No image available. That's very bad ! */
GST_WARNING_OBJECT (xvimagesink, "could not create image");
- return GST_FLOW_ERROR;
+ return res;
+ }
+wrong_size:
+ {
+ GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE,
+ ("Failed to create output image buffer"),
+ ("XServer allocated buffer size did not match input buffer %"
+ G_GSIZE_FORMAT " - %" G_GSIZE_FORMAT, gst_buffer_get_size (to_put),
+ gst_buffer_get_size (buf)));
+ res = GST_FLOW_ERROR;
+ goto done;
}
no_window:
{
/* No Window available to put our image into */
GST_WARNING_OBJECT (xvimagesink, "could not output image - no window");
- return GST_FLOW_ERROR;
+ res = GST_FLOW_ERROR;
+ goto done;
}
}
return TRUE;
}
-/* Buffer management */
-
-static GstCaps *
-gst_xvimage_sink_different_size_suggestion (GstXvImageSink * xvimagesink,
- GstCaps * caps)
-{
- GstCaps *intersection;
- GstCaps *new_caps;
- GstStructure *s;
- gint width, height;
- gint par_n = 1, par_d = 1;
- gint dar_n, dar_d;
- gint w, h;
-
- new_caps = gst_caps_copy (caps);
-
- s = gst_caps_get_structure (new_caps, 0);
-
- gst_structure_get_int (s, "width", &width);
- gst_structure_get_int (s, "height", &height);
- gst_structure_get_fraction (s, "pixel-aspect-ratio", &par_n, &par_d);
-
- gst_structure_remove_field (s, "width");
- gst_structure_remove_field (s, "height");
- gst_structure_remove_field (s, "pixel-aspect-ratio");
-
- intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps);
- gst_caps_unref (new_caps);
-
- if (gst_caps_is_empty (intersection))
- return intersection;
-
- s = gst_caps_get_structure (intersection, 0);
-
- gst_util_fraction_multiply (width, height, par_n, par_d, &dar_n, &dar_d);
-
- /* xvimagesink supports all PARs */
-
- gst_structure_fixate_field_nearest_int (s, "width", width);
- gst_structure_fixate_field_nearest_int (s, "height", height);
- gst_structure_get_int (s, "width", &w);
- gst_structure_get_int (s, "height", &h);
-
- gst_util_fraction_multiply (h, w, dar_n, dar_d, &par_n, &par_d);
- gst_structure_set (s, "pixel-aspect-ratio", GST_TYPE_FRACTION, par_n, par_d,
- NULL);
-
- return intersection;
-}
-
-static GstFlowReturn
-gst_xvimagesink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size,
- GstCaps * caps, GstBuffer ** buf)
+static gboolean
+gst_xvimagesink_sink_query (GstPad * sinkpad, GstQuery * query)
{
- GstFlowReturn ret = GST_FLOW_OK;
- GstXvImageSink *xvimagesink;
- GstXvImageBuffer *xvimage = NULL;
- GstCaps *intersection = NULL;
- GstStructure *structure = NULL;
- gint width, height, image_format;
+ GstXvImageSink *xvimagesink = GST_XVIMAGESINK (GST_PAD_PARENT (sinkpad));
+ gboolean res = TRUE;
- xvimagesink = GST_XVIMAGESINK (bsink);
-
- if (G_UNLIKELY (!caps))
- goto no_caps;
-
- g_mutex_lock (xvimagesink->pool_lock);
- if (G_UNLIKELY (xvimagesink->pool_invalid))
- goto invalid;
-
- if (G_LIKELY (xvimagesink->xcontext->last_caps &&
- gst_caps_is_equal (caps, xvimagesink->xcontext->last_caps))) {
- GST_LOG_OBJECT (xvimagesink,
- "buffer alloc for same last_caps, reusing caps");
- intersection = gst_caps_ref (caps);
- image_format = xvimagesink->xcontext->last_format;
- width = xvimagesink->xcontext->last_width;
- height = xvimagesink->xcontext->last_height;
-
- goto reuse_last_caps;
- }
-
- GST_DEBUG_OBJECT (xvimagesink, "buffer alloc requested size %d with caps %"
- GST_PTR_FORMAT ", intersecting with our caps %" GST_PTR_FORMAT, size,
- caps, xvimagesink->xcontext->caps);
-
- /* Check the caps against our xcontext */
- intersection = gst_caps_intersect (xvimagesink->xcontext->caps, caps);
-
- GST_DEBUG_OBJECT (xvimagesink, "intersection in buffer alloc returned %"
- GST_PTR_FORMAT, intersection);
-
- if (gst_caps_is_empty (intersection)) {
- GstCaps *new_caps;
-
- gst_caps_unref (intersection);
-
- /* So we don't support this kind of buffer, let's define one we'd like */
- new_caps = gst_caps_copy (caps);
-
- structure = gst_caps_get_structure (new_caps, 0);
- if (!gst_structure_has_field (structure, "width") ||
- !gst_structure_has_field (structure, "height")) {
- gst_caps_unref (new_caps);
- goto invalid;
- }
-
- /* Try different dimensions */
- intersection =
- gst_xvimage_sink_different_size_suggestion (xvimagesink, new_caps);
-
- if (gst_caps_is_empty (intersection)) {
- /* Try with different YUV formats first */
- gst_structure_set_name (structure, "video/x-raw-yuv");
-
- /* Remove format specific fields */
- gst_structure_remove_field (structure, "format");
- gst_structure_remove_field (structure, "endianness");
- gst_structure_remove_field (structure, "depth");
- gst_structure_remove_field (structure, "bpp");
- gst_structure_remove_field (structure, "red_mask");
- gst_structure_remove_field (structure, "green_mask");
- gst_structure_remove_field (structure, "blue_mask");
- gst_structure_remove_field (structure, "alpha_mask");
-
- /* Reuse intersection with Xcontext */
- intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps);
- }
-
- if (gst_caps_is_empty (intersection)) {
- /* Try with different dimensions and YUV formats */
- intersection =
- gst_xvimage_sink_different_size_suggestion (xvimagesink, new_caps);
- }
-
- if (gst_caps_is_empty (intersection)) {
- /* Now try with RGB */
- gst_structure_set_name (structure, "video/x-raw-rgb");
- /* And interset again */
- gst_caps_unref (intersection);
- intersection = gst_caps_intersect (xvimagesink->xcontext->caps, new_caps);
- }
-
- if (gst_caps_is_empty (intersection)) {
- /* Try with different dimensions and RGB formats */
- intersection =
- gst_xvimage_sink_different_size_suggestion (xvimagesink, new_caps);
- }
-
- /* Clean this copy */
- gst_caps_unref (new_caps);
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_ALLOCATION:
+ {
+ GstBufferPool *pool;
+ GstStructure *config;
+ GstCaps *caps;
+ guint size;
+ gboolean need_pool;
- if (gst_caps_is_empty (intersection))
- goto incompatible;
- }
+ gst_query_parse_allocation (query, &caps, &need_pool);
- /* Ensure the returned caps are fixed */
- gst_caps_truncate (intersection);
+ if (caps == NULL)
+ goto no_caps;
- GST_DEBUG_OBJECT (xvimagesink, "allocating a buffer with caps %"
- GST_PTR_FORMAT, intersection);
- if (gst_caps_is_equal (intersection, caps)) {
- /* Things work better if we return a buffer with the same caps ptr
- * as was asked for when we can */
- gst_caps_replace (&intersection, caps);
- }
+ g_mutex_lock (xvimagesink->flow_lock);
+ if ((pool = xvimagesink->pool))
+ gst_object_ref (pool);
+ g_mutex_unlock (xvimagesink->flow_lock);
- /* Get image format from caps */
- image_format = gst_xvimagesink_get_format_from_caps (xvimagesink,
- intersection);
+ if (pool != NULL) {
+ const GstCaps *pcaps;
- /* Get geometry from caps */
- structure = gst_caps_get_structure (intersection, 0);
- if (!gst_structure_get_int (structure, "width", &width) ||
- !gst_structure_get_int (structure, "height", &height) ||
- image_format == -1)
- goto invalid_caps;
+ /* we had a pool, check caps */
+ config = gst_buffer_pool_get_config (pool);
+ gst_buffer_pool_config_get (config, &pcaps, &size, NULL, NULL, NULL,
+ NULL, NULL);
- /* Store our caps and format as the last_caps to avoid expensive
- * caps intersection next time */
- gst_caps_replace (&xvimagesink->xcontext->last_caps, intersection);
- xvimagesink->xcontext->last_format = image_format;
- xvimagesink->xcontext->last_width = width;
- xvimagesink->xcontext->last_height = height;
+ if (!gst_caps_is_equal (caps, pcaps)) {
+ GST_DEBUG_OBJECT (xvimagesink, "pool has different caps");
+ /* different caps, we can't use this pool */
+ gst_object_unref (pool);
+ pool = NULL;
+ }
+ }
+ if (pool == NULL && need_pool) {
+ GstVideoFormat format;
+ gint width, height;
-reuse_last_caps:
+ GST_DEBUG_OBJECT (xvimagesink, "create new pool");
+ pool = gst_xvimage_buffer_pool_new (xvimagesink);
- /* Walking through the pool cleaning unusable images and searching for a
- suitable one */
- while (xvimagesink->image_pool) {
- xvimage = xvimagesink->image_pool->data;
+ if (!gst_video_format_parse_caps (caps, &format, &width, &height))
+ goto invalid_caps;
- if (xvimage) {
- /* Removing from the pool */
- xvimagesink->image_pool = g_slist_delete_link (xvimagesink->image_pool,
- xvimagesink->image_pool);
+ /* the normal size of a frame */
+ size = gst_video_format_get_size (format, width, height);
- /* We check for geometry or image format changes */
- if ((xvimage->width != width) ||
- (xvimage->height != height) || (xvimage->im_format != image_format)) {
- /* This image is unusable. Destroying... */
- gst_xvimage_buffer_free (xvimage);
- xvimage = NULL;
- } else {
- /* We found a suitable image */
- GST_LOG_OBJECT (xvimagesink, "found usable image in pool");
- break;
+ config = gst_buffer_pool_get_config (pool);
+ gst_buffer_pool_config_set (config, caps, size, 0, 0, 0, 0, 16);
+ if (!gst_buffer_pool_set_config (pool, config))
+ goto config_failed;
}
- }
- }
+ gst_query_set_allocation_params (query, size, 0, 0, 0, 16, pool);
- if (!xvimage) {
- /* We found no suitable image in the pool. Creating... */
- GST_DEBUG_OBJECT (xvimagesink, "no usable image in pool, creating xvimage");
- xvimage = gst_xvimagesink_xvimage_new (xvimagesink, intersection);
- }
- g_mutex_unlock (xvimagesink->pool_lock);
+ /* we also support various metadata */
+ gst_query_add_allocation_meta (query, GST_META_API_VIDEO);
- if (xvimage) {
- /* Make sure the buffer is cleared of any previously used flags */
- GST_MINI_OBJECT_CAST (xvimage)->flags = 0;
- gst_buffer_set_caps (GST_BUFFER_CAST (xvimage), intersection);
- }
-
- *buf = GST_BUFFER_CAST (xvimage);
-
-beach:
- if (intersection) {
- gst_caps_unref (intersection);
+ gst_object_unref (pool);
+ break;
+ }
+ default:
+ res = FALSE;
+ break;
}
-
- return ret;
+ return res;
/* ERRORS */
-invalid:
- {
- GST_DEBUG_OBJECT (xvimagesink, "the pool is flushing");
- ret = GST_FLOW_WRONG_STATE;
- g_mutex_unlock (xvimagesink->pool_lock);
- goto beach;
- }
-incompatible:
+no_caps:
{
- GST_WARNING_OBJECT (xvimagesink, "we were requested a buffer with "
- "caps %" GST_PTR_FORMAT ", but our xcontext caps %" GST_PTR_FORMAT
- " are completely incompatible with those caps", caps,
- xvimagesink->xcontext->caps);
- ret = GST_FLOW_NOT_NEGOTIATED;
- g_mutex_unlock (xvimagesink->pool_lock);
- goto beach;
+ GST_DEBUG_OBJECT (sinkpad, "no caps specified");
+ return FALSE;
}
invalid_caps:
{
- GST_WARNING_OBJECT (xvimagesink, "invalid caps for buffer allocation %"
- GST_PTR_FORMAT, intersection);
- ret = GST_FLOW_NOT_NEGOTIATED;
- g_mutex_unlock (xvimagesink->pool_lock);
- goto beach;
+ GST_DEBUG_OBJECT (sinkpad, "invalid caps specified");
+ return FALSE;
}
-no_caps:
+config_failed:
{
- GST_WARNING_OBJECT (xvimagesink, "have no caps, doing fallback allocation");
- *buf = NULL;
- ret = GST_FLOW_OK;
- goto beach;
+ GST_DEBUG_OBJECT (sinkpad, "failed setting config");
+ return FALSE;
}
}
gst_xvimagesink_update_colorbalance (xvimagesink);
- /* Clear image pool as the images are unusable anyway */
- gst_xvimagesink_imagepool_clear (xvimagesink);
-
- /* Clear the xvimage */
- if (xvimagesink->xvimage) {
- gst_xvimage_buffer_free (xvimagesink->xvimage);
- xvimagesink->xvimage = NULL;
- }
-
/* If a window is there already we destroy it */
if (xvimagesink->xwindow) {
gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow);
{
GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay);
+ GST_DEBUG ("doing expose");
gst_xvimagesink_xwindow_update_geometry (xvimagesink);
gst_xvimagesink_xvimage_put (xvimagesink, NULL);
}
xvimagesink->event_thread = NULL;
GST_OBJECT_UNLOCK (xvimagesink);
- /* invalidate the pool, current allocations continue, new buffer_alloc fails
- * with wrong_state */
- g_mutex_lock (xvimagesink->pool_lock);
- xvimagesink->pool_invalid = TRUE;
- g_mutex_unlock (xvimagesink->pool_lock);
-
/* Wait for our event thread to finish before we clean up our stuff. */
if (thread)
g_thread_join (thread);
if (xvimagesink->cur_image) {
- gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->cur_image));
+ gst_buffer_unref (xvimagesink->cur_image);
xvimagesink->cur_image = NULL;
}
- if (xvimagesink->xvimage) {
- gst_buffer_unref (GST_BUFFER_CAST (xvimagesink->xvimage));
- xvimagesink->xvimage = NULL;
- }
- gst_xvimagesink_imagepool_clear (xvimagesink);
+ g_mutex_lock (xvimagesink->flow_lock);
+
+ if (xvimagesink->pool) {
+ gst_object_unref (xvimagesink->pool);
+ xvimagesink->pool = NULL;
+ }
if (xvimagesink->xwindow) {
gst_xvimagesink_xwindow_clear (xvimagesink, xvimagesink->xwindow);
gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow);
xvimagesink->xwindow = NULL;
}
+ g_mutex_unlock (xvimagesink->flow_lock);
xvimagesink->render_rect.x = xvimagesink->render_rect.y =
xvimagesink->render_rect.w = xvimagesink->render_rect.h = 0;
g_mutex_free (xvimagesink->flow_lock);
xvimagesink->flow_lock = NULL;
}
- if (xvimagesink->pool_lock) {
- g_mutex_free (xvimagesink->pool_lock);
- xvimagesink->pool_lock = NULL;
- }
g_free (xvimagesink->media_title);
}
static void
-gst_xvimagesink_init (GstXvImageSink * xvimagesink,
- GstXvImageSinkClass * xvimagesinkclass)
+gst_xvimagesink_init (GstXvImageSink * xvimagesink)
{
+ /* for the ALLOCATION query */
+ gst_pad_set_query_function (GST_BASE_SINK (xvimagesink)->sinkpad,
+ gst_xvimagesink_sink_query);
+
xvimagesink->display_name = NULL;
xvimagesink->adaptor_no = 0;
xvimagesink->xcontext = NULL;
xvimagesink->xwindow = NULL;
- xvimagesink->xvimage = NULL;
xvimagesink->cur_image = NULL;
xvimagesink->hue = xvimagesink->saturation = 0;
xvimagesink->x_lock = g_mutex_new ();
xvimagesink->flow_lock = g_mutex_new ();
- xvimagesink->image_pool = NULL;
- xvimagesink->pool_lock = g_mutex_new ();
+ xvimagesink->pool = NULL;
xvimagesink->synchronous = FALSE;
xvimagesink->double_buffer = TRUE;
}
static void
-gst_xvimagesink_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_set_details_simple (element_class,
- "Video sink", "Sink/Video",
- "A Xv based videosink", "Julien Moutte <julien@moutte.net>");
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&gst_xvimagesink_sink_template_factory));
-}
-
-static void
gst_xvimagesink_class_init (GstXvImageSinkClass * klass)
{
GObjectClass *gobject_class;
gstbasesink_class = (GstBaseSinkClass *) klass;
videosink_class = (GstVideoSinkClass *) klass;
+ parent_class = g_type_class_peek_parent (klass);
+
gobject_class->set_property = gst_xvimagesink_set_property;
gobject_class->get_property = gst_xvimagesink_get_property;
gobject_class->finalize = gst_xvimagesink_finalize;
+ gst_element_class_set_details_simple (gstelement_class,
+ "Video sink", "Sink/Video",
+ "A Xv based videosink", "Julien Moutte <julien@moutte.net>");
+
+ gst_element_class_add_pad_template (gstelement_class,
+ gst_static_pad_template_get (&gst_xvimagesink_sink_template_factory));
+
gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_xvimagesink_change_state);
gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_xvimagesink_getcaps);
gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_xvimagesink_setcaps);
- gstbasesink_class->buffer_alloc =
- GST_DEBUG_FUNCPTR (gst_xvimagesink_buffer_alloc);
gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_xvimagesink_get_times);
gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_xvimagesink_event);
videosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_xvimagesink_show_frame);
}
-
-/* ============================================================= */
-/* */
-/* Public Methods */
-/* */
-/* ============================================================= */
-
-/* =========================================== */
-/* */
-/* Object typing & Creation */
-/* */
-/* =========================================== */
-static void
-gst_xvimagesink_init_interfaces (GType type)
-{
- static const GInterfaceInfo iface_info = {
- (GInterfaceInitFunc) gst_xvimagesink_interface_init,
- NULL,
- NULL,
- };
- static const GInterfaceInfo navigation_info = {
- (GInterfaceInitFunc) gst_xvimagesink_navigation_init,
- NULL,
- NULL,
- };
- static const GInterfaceInfo overlay_info = {
- (GInterfaceInitFunc) gst_xvimagesink_xoverlay_init,
- NULL,
- NULL,
- };
- static const GInterfaceInfo colorbalance_info = {
- (GInterfaceInitFunc) gst_xvimagesink_colorbalance_init,
- NULL,
- NULL,
- };
- static const GInterfaceInfo propertyprobe_info = {
- (GInterfaceInitFunc) gst_xvimagesink_property_probe_interface_init,
- NULL,
- NULL,
- };
-
- g_type_add_interface_static (type,
- GST_TYPE_IMPLEMENTS_INTERFACE, &iface_info);
- g_type_add_interface_static (type, GST_TYPE_NAVIGATION, &navigation_info);
- g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &overlay_info);
- g_type_add_interface_static (type, GST_TYPE_COLOR_BALANCE,
- &colorbalance_info);
- g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE,
- &propertyprobe_info);
-
- /* register type and create class in a more safe place instead of at
- * runtime since the type registration and class creation is not
- * threadsafe. */
- g_type_class_ref (gst_xvimage_buffer_get_type ());
-}
-
-static gboolean
-plugin_init (GstPlugin * plugin)
-{
- if (!gst_element_register (plugin, "xvimagesink",
- GST_RANK_PRIMARY, GST_TYPE_XVIMAGESINK))
- return FALSE;
-
- GST_DEBUG_CATEGORY_INIT (gst_debug_xvimagesink, "xvimagesink", 0,
- "xvimagesink element");
- GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE");
-
- return TRUE;
-}
-
-GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
- GST_VERSION_MINOR,
- "xvimagesink",
- "XFree86 video output plugin using Xv extension",
- plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
#include <stdlib.h>
G_BEGIN_DECLS
-
#define GST_TYPE_XVIMAGESINK \
(gst_xvimagesink_get_type())
#define GST_XVIMAGESINK(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_XVIMAGESINK))
#define GST_IS_XVIMAGESINK_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_XVIMAGESINK))
-
typedef struct _GstXContext GstXContext;
typedef struct _GstXWindow GstXWindow;
typedef struct _GstXvImageFormat GstXvImageFormat;
-typedef struct _GstXvImageBuffer GstXvImageBuffer;
-typedef struct _GstXvImageBufferClass GstXvImageBufferClass;
typedef struct _GstXvImageSink GstXvImageSink;
typedef struct _GstXvImageSinkClass GstXvImageSinkClass;
+#include "xvimagepool.h"
+
/*
* GstXContext:
* @disp: the X11 Display of this context
* Structure used to store various informations collected/calculated for a
* Display.
*/
-struct _GstXContext {
+struct _GstXContext
+{
Display *disp;
Screen *screen;
XvPortID xv_port_id;
guint nb_adaptors;
- gchar ** adaptors;
+ gchar **adaptors;
gint im_format;
GList *formats_list;
*
* Structure used to store informations about a Window.
*/
-struct _GstXWindow {
+struct _GstXWindow
+{
Window win;
gint width, height;
gboolean internal;
*
* Structure storing image format to #GstCaps association.
*/
-struct _GstXvImageFormat {
+struct _GstXvImageFormat
+{
gint format;
GstCaps *caps;
};
-/**
- * GstXImageBuffer:
- * @xvimagesink: a reference to our #GstXvImageSink
- * @xvimage: the XvImage of this buffer
- * @width: the width in pixels of XvImage @xvimage
- * @height: the height in pixels of XvImage @xvimage
- * @im_format: the image format of XvImage @xvimage
- * @size: the size in bytes of XvImage @xvimage
- *
- * Subclass of #GstBuffer containing additional information about an XvImage.
- */
-struct _GstXvImageBuffer {
- GstBuffer buffer;
-
- /* Reference to the xvimagesink we belong to */
- GstXvImageSink *xvimagesink;
-
- XvImage *xvimage;
-
-#ifdef HAVE_XSHM
- XShmSegmentInfo SHMInfo;
-#endif /* HAVE_XSHM */
-
- gint width, height, im_format;
- size_t size;
-};
/**
* GstXvImageSink:
* @display_name: the name of the Display we want to render to
* @xcontext: our instance's #GstXContext
* @xwindow: the #GstXWindow we are rendering to
- * @xvimage: internal #GstXvImage used to store incoming buffers and render when
- * not using the buffer_alloc optimization mechanism
* @cur_image: a reference to the last #GstXvImage that was put to @xwindow. It
* is used when Expose events are received to redraw the latest video frame
* @event_thread: a thread listening for events on @xwindow and handling them
*
* The #GstXvImageSink data structure.
*/
-struct _GstXvImageSink {
+struct _GstXvImageSink
+{
/* Our element stuff */
GstVideoSink videosink;
GstXContext *xcontext;
GstXWindow *xwindow;
- GstXvImageBuffer *xvimage;
- GstXvImageBuffer *cur_image;
+ GstBuffer *cur_image;
GThread *event_thread;
gboolean running;
+ /* Framerate numerator and denominator */
gint fps_n;
gint fps_d;
/* object-set pixel aspect ratio */
GValue *par;
- GMutex *pool_lock;
- gboolean pool_invalid;
- GSList *image_pool;
+ /* the buffer pool */
+ GstBufferPool *pool;
gboolean synchronous;
gboolean double_buffer;
/* port attributes */
gboolean autopaint_colorkey;
gint colorkey;
-
+
gboolean draw_borders;
-
+
/* port features */
gboolean have_autopaint_colorkey;
gboolean have_colorkey;
gboolean have_double_buffer;
-
+
/* stream metadata */
gchar *media_title;
gboolean have_render_rect;
};
-struct _GstXvImageSinkClass {
+struct _GstXvImageSinkClass
+{
GstVideoSinkClass parent_class;
};
-GType gst_xvimagesink_get_type(void);
+GType gst_xvimagesink_get_type (void);
G_END_DECLS
-
#endif /* __GST_XVIMAGESINK_H__ */
static GstBufferList *mylist;
static GstCaps *mycaps;
+static gint values[] = { 1, 2, 4 };
+
static GstBufferList *
create_buffer_list (void)
{
- GstBufferListIterator *it;
+ guint len;
GstBuffer *buffer;
mylist = gst_buffer_list_new ();
mycaps = gst_caps_from_string ("application/x-gst-check");
fail_if (mycaps == NULL);
- it = gst_buffer_list_iterate (mylist);
- fail_if (it == NULL);
-
- gst_buffer_list_iterator_add_group (it);
+ len = gst_buffer_list_len (mylist);
+ fail_if (len != 0);
buffer = gst_buffer_new_and_alloc (sizeof (gint));
- *(gint *) GST_BUFFER_DATA (buffer) = 1;
+ gst_buffer_fill (buffer, 0, &values[0], sizeof (gint));
gst_buffer_set_caps (buffer, mycaps);
- gst_buffer_list_iterator_add (it, buffer);
-
- gst_buffer_list_iterator_add_group (it);
+ gst_buffer_list_add (mylist, buffer);
buffer = gst_buffer_new_and_alloc (sizeof (gint));
- *(gint *) GST_BUFFER_DATA (buffer) = 2;
+ gst_buffer_fill (buffer, 0, &values[1], sizeof (gint));
gst_buffer_set_caps (buffer, mycaps);
- gst_buffer_list_iterator_add (it, buffer);
+ gst_buffer_list_add (mylist, buffer);
buffer = gst_buffer_new_and_alloc (sizeof (gint));
- *(gint *) GST_BUFFER_DATA (buffer) = 4;
+ gst_buffer_fill (buffer, 0, &values[2], sizeof (gint));
gst_buffer_set_caps (buffer, mycaps);
- gst_buffer_list_iterator_add (it, buffer);
-
- gst_buffer_list_iterator_free (it);
+ gst_buffer_list_add (mylist, buffer);
return mylist;
}
static void
check_buffer_list (GstBufferList * list)
{
- GstBufferListIterator *it;
+ guint len;
GstBuffer *buf;
GstCaps *caps;
fail_unless (list == mylist);
- fail_unless (gst_buffer_list_n_groups (list) == 2);
+ fail_unless (gst_buffer_list_len (list) == 3);
- it = gst_buffer_list_iterate (list);
- fail_if (it == NULL);
+ len = gst_buffer_list_len (list);
- fail_unless (gst_buffer_list_iterator_next_group (it));
- fail_unless (gst_buffer_list_iterator_n_buffers (it) == 1);
- buf = gst_buffer_list_iterator_next (it);
+ buf = gst_buffer_list_get (list, 0);
fail_if (buf == NULL);
- fail_unless (*(gint *) GST_BUFFER_DATA (buf) == 1);
+ gst_check_buffer_data (buf, &values[0], sizeof (gint));
caps = gst_buffer_get_caps (buf);
fail_unless (caps == mycaps);
fail_unless (gst_caps_is_equal (caps, mycaps));
gst_caps_unref (caps);
- fail_unless (gst_buffer_list_iterator_next_group (it));
- fail_unless (gst_buffer_list_iterator_n_buffers (it) == 2);
- buf = gst_buffer_list_iterator_next (it);
+ buf = gst_buffer_list_get (list, 1);
fail_if (buf == NULL);
- fail_unless (*(gint *) GST_BUFFER_DATA (buf) == 2);
+ gst_check_buffer_data (buf, &values[1], sizeof (gint));
caps = gst_buffer_get_caps (buf);
fail_unless (caps == mycaps);
gst_caps_unref (caps);
- buf = gst_buffer_list_iterator_next (it);
+ buf = gst_buffer_list_get (list, 2);
fail_if (buf == NULL);
- fail_unless (*(gint *) GST_BUFFER_DATA (buf) == 4);
+ gst_check_buffer_data (buf, &values[2], sizeof (gint));
caps = gst_buffer_get_caps (buf);
fail_unless (caps == mycaps);
gst_caps_unref (caps);
-
- gst_buffer_list_iterator_free (it);
}
static GstFlowReturn
/* buffer list has 3 buffers in two groups */
switch (*p_int_counter) {
case 0:
- fail_unless_equals_int (GST_BUFFER_SIZE (buf), sizeof (gint));
- fail_unless_equals_int ((((gint *) GST_BUFFER_DATA (buf))[0]), 1);
+ fail_unless_equals_int (gst_buffer_get_size (buf), sizeof (gint));
+ gst_check_buffer_data (buf, &values[0], sizeof (gint));
break;
case 1:
- fail_unless_equals_int (GST_BUFFER_SIZE (buf), 2 * sizeof (gint));
- fail_unless_equals_int ((((gint *) GST_BUFFER_DATA (buf))[0]), 2);
- fail_unless_equals_int ((((gint *) GST_BUFFER_DATA (buf))[1]), 4);
+ fail_unless_equals_int (gst_buffer_get_size (buf), sizeof (gint));
+ gst_check_buffer_data (buf, &values[1], sizeof (gint));
+ break;
+ case 2:
+ fail_unless_equals_int (gst_buffer_get_size (buf), sizeof (gint));
+ gst_check_buffer_data (buf, &values[2], sizeof (gint));
break;
default:
g_warn_if_reached ();
list = create_buffer_list ();
fail_unless (gst_pad_push_list (mysrcpad, list) == GST_FLOW_OK);
- fail_unless_equals_int (counter, 2);
+ fail_unless_equals_int (counter, 3);
ASSERT_SET_STATE (sink, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
cleanup_appsink (sink);
list = create_buffer_list ();
fail_unless (gst_pad_push_list (mysrcpad, list) == GST_FLOW_OK);
- fail_unless_equals_int (counter, 2);
+ fail_unless_equals_int (counter, 3);
ASSERT_SET_STATE (sink, GST_STATE_NULL, GST_STATE_CHANGE_SUCCESS);
cleanup_appsink (sink);
GST_DEBUG ("Creating buffer of %d bytes", inlength);
inbuffer = gst_buffer_new_and_alloc (inlength);
- memcpy (GST_BUFFER_DATA (inbuffer), in, inlength);
+ gst_buffer_fill (inbuffer, 0, in, inlength);
gst_buffer_set_caps (inbuffer, incaps);
ASSERT_CAPS_REFCOUNT (incaps, "incaps", 2);
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
- fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer), outlength);
+ fail_unless_equals_int (gst_buffer_get_size (outbuffer), outlength);
+ gst_check_buffer_data (outbuffer, out, outlength);
+#if 0
if (memcmp (GST_BUFFER_DATA (outbuffer), out, outlength) != 0) {
g_print ("\nInput data:\n");
gst_util_dump_mem (in, inlength);
}
fail_unless (memcmp (GST_BUFFER_DATA (outbuffer), out, outlength) == 0,
"failed converting %s", which);
+#endif
/* make sure that the channel positions are not lost */
{
typedef GstElementClass TestInjectorClass;
GType test_injector_get_type (void);
-GST_BOILERPLATE (TestInjector, test_injector, GstElement, GST_TYPE_ELEMENT);
+G_DEFINE_TYPE (TestInjector, test_injector, GST_TYPE_ELEMENT);
#define INJECTOR_CAPS \
"audio/x-raw-float, " \
GST_STATIC_CAPS (INJECTOR_CAPS));
static void
-test_injector_base_init (gpointer g_class)
+test_injector_class_init (TestInjectorClass * klass)
{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&src_template));
gst_static_pad_template_get (&sink_template));
}
-static void
-test_injector_class_init (TestInjectorClass * klass)
-{
- /* nothing to do here */
-}
-
static GstFlowReturn
test_injector_chain (GstPad * pad, GstBuffer * buf)
{
}
static void
-test_injector_init (TestInjector * injector, TestInjectorClass * klass)
+test_injector_init (TestInjector * injector)
{
GstPad *pad;
}
/* check buffer size for sanity */
- fail_unless_equals_int (GST_BUFFER_SIZE (buf) % (width / 8), 0);
+ fail_unless_equals_int (gst_buffer_get_size (buf) % (width / 8), 0);
/* check there is actually as much data as there should be */
num_samples = GST_BUFFER_OFFSET_END (buf) - GST_BUFFER_OFFSET (buf);
- fail_unless_equals_int (GST_BUFFER_SIZE (buf), num_samples * (width / 8));
+ fail_unless_equals_int (gst_buffer_get_size (buf),
+ num_samples * (width / 8));
next_time = GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf);
next_offset = GST_BUFFER_OFFSET_END (buf);
GstBuffer *inbuffer, *outbuffer;
GstCaps *caps;
guint64 offset = 0;
-
int i, j;
- gint16 *p;
+ gint16 *p, *data;
audioresample = setup_audioresample (2, inrate, outrate, 16, FALSE);
caps = gst_pad_get_negotiated_caps (mysrcpad);
gst_buffer_set_caps (inbuffer, caps);
- p = (gint16 *) GST_BUFFER_DATA (inbuffer);
+ p = data = gst_buffer_map (inbuffer, NULL, NULL, GST_MAP_WRITE);
/* create a 16 bit signed ramp */
for (i = 0; i < samples; ++i) {
*p = -32767 + i * (65535 / samples);
++p;
}
+ gst_buffer_unmap (inbuffer, data, samples * 4);
/* pushing gives away my reference ... */
fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
GstClockTime ints;
int i, j;
- gint16 *p;
+ gint16 *p, *data;
GST_DEBUG ("inrate:%d outrate:%d samples:%d numbuffers:%d",
inrate, outrate, samples, numbuffers);
gst_buffer_set_caps (inbuffer, caps);
- p = (gint16 *) GST_BUFFER_DATA (inbuffer);
-
+ p = data = gst_buffer_map (inbuffer, NULL, NULL, GST_MAP_WRITE);
/* create a 16 bit signed ramp */
for (i = 0; i < samples; ++i) {
*p = -32767 + i * (65535 / samples);
*p = -32767 + i * (65535 / samples);
++p;
}
+ gst_buffer_unmap (inbuffer, data, samples * 4);
GST_DEBUG ("Sending Buffer time:%" G_GUINT64_FORMAT " duration:%"
G_GINT64_FORMAT " discont:%d offset:%" G_GUINT64_FORMAT " offset_end:%"
GstEvent *newseg;
GstBuffer *inbuffer;
GstCaps *caps;
+ guint8 *data;
audioresample = setup_audioresample (1, 9343, 48000, 16, FALSE);
caps = gst_pad_get_negotiated_caps (mysrcpad);
fail_unless (gst_pad_push_event (mysrcpad, newseg) != FALSE);
inbuffer = gst_buffer_new_and_alloc (9343 * 4);
- memset (GST_BUFFER_DATA (inbuffer), 0, GST_BUFFER_SIZE (inbuffer));
+ data = gst_buffer_map (inbuffer, NULL, NULL, GST_MAP_WRITE);
+ memset (data, 0, 9343 * 4);
+ gst_buffer_unmap (inbuffer, data, 9343 * 4);
GST_BUFFER_DURATION (inbuffer) = GST_SECOND;
GST_BUFFER_TIMESTAMP (inbuffer) = 0;
GST_BUFFER_OFFSET (inbuffer) = 0;
fail_unless (gst_pad_push_event (mysrcpad, newseg) != FALSE);
inbuffer = gst_buffer_new_and_alloc (9343 * 4);
- memset (GST_BUFFER_DATA (inbuffer), 0, GST_BUFFER_SIZE (inbuffer));
+ data = gst_buffer_map (inbuffer, NULL, NULL, GST_MAP_WRITE);
+ memset (data, 0, 9343 * 4);
+ gst_buffer_unmap (inbuffer, data, 9343 * 4);
GST_BUFFER_DURATION (inbuffer) = GST_SECOND;
GST_BUFFER_TIMESTAMP (inbuffer) = 0;
GST_BUFFER_OFFSET (inbuffer) = 0;
GST_END_TEST;
+#if 0
static GstFlowReturn
live_switch_alloc_only_48000 (GstPad * pad, guint64 offset,
guint size, GstCaps * caps, GstBuffer ** buf)
return GST_FLOW_OK;
}
+#endif
static GstCaps *
live_switch_get_sink_caps (GstPad * pad)
GstBuffer *inbuffer;
GstCaps *desired;
GList *l;
+ guint8 *data;
desired = gst_caps_copy (caps);
gst_caps_set_simple (desired, "rate", G_TYPE_INT, rate, NULL);
gst_pad_set_caps (mysrcpad, desired);
+#if 0
fail_unless (gst_pad_alloc_buffer_and_set_caps (mysrcpad,
GST_BUFFER_OFFSET_NONE, rate * 4, desired, &inbuffer) == GST_FLOW_OK);
+#endif
+ inbuffer = gst_buffer_new_and_alloc (rate * 4);
+ gst_buffer_set_caps (inbuffer, desired);
/* When the basetransform hits the non-configured case it always
* returns a buffer with exactly the same caps as we requested so the actual
desired, GST_BUFFER_CAPS (inbuffer));
fail_unless (gst_caps_is_equal (desired, GST_BUFFER_CAPS (inbuffer)));
- memset (GST_BUFFER_DATA (inbuffer), 0, GST_BUFFER_SIZE (inbuffer));
+ data = gst_buffer_map (inbuffer, NULL, NULL, GST_MAP_WRITE);
+ memset (data, 0, rate * 4);
+ gst_buffer_unmap (inbuffer, data, rate * 4);
+
GST_BUFFER_DURATION (inbuffer) = GST_SECOND;
GST_BUFFER_TIMESTAMP (inbuffer) = 0;
GST_BUFFER_OFFSET (inbuffer) = 0;
* rate 48000- and can only allocate buffers for that rate, but if someone
* tries to get a buffer with a rate higher then 48000 tries to renegotiate
* */
- gst_pad_set_bufferalloc_function (mysinkpad, live_switch_alloc_only_48000);
+ //gst_pad_set_bufferalloc_function (mysinkpad, live_switch_alloc_only_48000);
gst_pad_set_getcaps_function (mysinkpad, live_switch_get_sink_caps);
gst_pad_use_fixed_caps (mysrcpad);
ctx->out_buffer_count++;
if (ctx->latency == GST_CLOCK_TIME_NONE) {
- ctx->latency = 1000 - GST_BUFFER_SIZE (buffer) / 8;
+ ctx->latency = 1000 - gst_buffer_get_size (buffer) / 8;
}
/* Check if we have a perfectly timestampped stream */
/* Check if we have a perfectly offsetted stream */
fail_unless (GST_BUFFER_OFFSET_END (buffer) ==
- GST_BUFFER_OFFSET (buffer) + GST_BUFFER_SIZE (buffer) / 8,
+ GST_BUFFER_OFFSET (buffer) + gst_buffer_get_size (buffer) / 8,
"expected offset end %" G_GUINT64_FORMAT " got offset end %"
G_GUINT64_FORMAT,
- GST_BUFFER_OFFSET (buffer) + GST_BUFFER_SIZE (buffer) / 8,
+ GST_BUFFER_OFFSET (buffer) + gst_buffer_get_size (buffer) / 8,
GST_BUFFER_OFFSET_END (buffer));
if (ctx->next_out_off != GST_BUFFER_OFFSET_NONE) {
fail_unless (GST_BUFFER_OFFSET (buffer) == ctx->next_out_off,
"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)
+src_need_data_cb (GstElement * src, guint size, gpointer data)
{
- GST_BUFFER_DATA (buf) = (guint8 *) dummytext;
- GST_BUFFER_SIZE (buf) = sizeof (dummytext);
+ GstBuffer *buf;
+ GstFlowReturn ret;
+
+ buf = gst_buffer_new ();
+ gst_buffer_take_memory (buf,
+ gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
+ (gpointer) dummytext, NULL, sizeof (dummytext), 0,
+ sizeof (dummytext)));
+
GST_BUFFER_OFFSET (buf) = 0;
- GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_READONLY);
+
+ g_signal_emit_by_name (src, "push-buffer", buf, &ret);
+
+ fail_unless (ret == GST_FLOW_OK);
}
static void
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");
+ src = gst_element_factory_make ("appsrc", "src");
+ fail_unless (src != NULL, "Failed to create appsrc element");
- g_object_set (src, "signal-handoffs", TRUE, NULL);
+ g_object_set (src, "emit-signals", 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);
+ g_signal_connect (src, "need-data", G_CALLBACK (src_need_data_cb), NULL);
decodebin = gst_element_factory_make ("decodebin", "decodebin");
fail_unless (decodebin != NULL, "Failed to create decodebin element");
"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)
+src_need_data_cb (GstElement * src, guint size, gpointer data)
{
- GST_BUFFER_DATA (buf) = (guint8 *) dummytext;
- GST_BUFFER_SIZE (buf) = sizeof (dummytext);
+ GstBuffer *buf;
+ GstFlowReturn ret;
+
+ buf = gst_buffer_new ();
+ gst_buffer_take_memory (buf,
+ gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
+ (gpointer) dummytext, NULL, sizeof (dummytext), 0,
+ sizeof (dummytext)));
+
GST_BUFFER_OFFSET (buf) = 0;
- GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_READONLY);
+
+ g_signal_emit_by_name (src, "push-buffer", buf, &ret);
+
+ fail_unless (ret == GST_FLOW_OK);
}
static void
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");
+ src = gst_element_factory_make ("appsrc", "src");
+ fail_unless (src != NULL, "Failed to create appsrc element");
- g_object_set (src, "signal-handoffs", TRUE, NULL);
+ g_object_set (src, "emit-signals", 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);
+ g_signal_connect (src, "need-data", G_CALLBACK (src_need_data_cb), NULL);
decodebin = gst_element_factory_make ("decodebin2", "decodebin");
fail_unless (decodebin != NULL, "Failed to create decodebin element");
"black", 2, 0x00, 0x00, 0x00}
};
GstElement *pipeline, *src, *filter1, *csp, *filter2, *sink;
- const GstCaps *template_caps;
+ GstCaps *template_caps;
GstBuffer *buf = NULL;
GstPad *srcpad;
GList *conversions, *l;
GstStateChangeReturn state_ret;
RGBFormat *from = &conv->from_fmt;
RGBFormat *to = &conv->to_fmt;
+ guint8 *data;
+ gsize size;
/* trick compiler into thinking from is used, might throw warning
* otherwise if the debugging system is disabled */
}
/* now check the top-left pixel */
- check_rgb_buf (GST_BUFFER_DATA (buf), to->red_mask,
+ data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
+ check_rgb_buf (data, to->red_mask,
to->green_mask, to->blue_mask, to->alpha_mask,
test_patterns[p].r_expected, test_patterns[p].g_expected,
test_patterns[p].b_expected, to->endianness, to->bpp, to->depth);
+ gst_buffer_unmap (buf, data, size);
gst_buffer_unref (buf);
buf = NULL;
}
}
+ gst_caps_unref (template_caps);
+
g_list_foreach (conversions, (GFunc) rgb_conversion_free, NULL);
g_list_free (conversions);
}
static void
-gdpdepay_push_per_byte (const gchar * reason, guint8 * bytes, guint length)
+gdpdepay_push_per_byte (const gchar * reason, const guint8 * bytes,
+ guint length)
{
int i;
GstBuffer *inbuffer;
for (i = 0; i < length; ++i) {
inbuffer = gst_buffer_new_and_alloc (1);
- GST_BUFFER_DATA (inbuffer)[0] = bytes[i];
+ gst_buffer_fill (inbuffer, 0, &bytes[i], 1);
fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK,
"%s: failed pushing byte buffer", reason);
}
g_free (payload);
buffer = gst_buffer_new_and_alloc (4);
- memcpy (GST_BUFFER_DATA (buffer), "f00d", 4);
+ gst_buffer_fill (buffer, 0, "f00d", 4);
GST_BUFFER_TIMESTAMP (buffer) = GST_SECOND;
GST_BUFFER_DURATION (buffer) = GST_SECOND / 10;
fail_unless (pk->header_from_buffer (buffer, 0, &len, &header));
gdpdepay_push_per_byte ("buffer header", header, len);
fail_unless_equals_int (g_list_length (buffers), 0);
- gdpdepay_push_per_byte ("buffer payload", GST_BUFFER_DATA (buffer),
+ gdpdepay_push_per_byte ("buffer payload", (const guint8 *) "f00d",
gst_dp_header_payload_length (header));
g_free (header);
gst_buffer_unref (buffer);
&caps_payload));
buffer = gst_buffer_new_and_alloc (4);
- memcpy (GST_BUFFER_DATA (buffer), "f00d", 4);
+ gst_buffer_fill (buffer, 0, "f00d", 4);
fail_unless (pk->header_from_buffer (buffer, 0, &header_len, &buf_header));
payload_len = gst_dp_header_payload_length (caps_header);
inbuffer = gst_buffer_new_and_alloc (2 * GST_DP_HEADER_LENGTH +
- payload_len + GST_BUFFER_SIZE (buffer));
- memcpy (GST_BUFFER_DATA (inbuffer), caps_header, GST_DP_HEADER_LENGTH);
+ payload_len + gst_buffer_get_size (buffer));
+ gst_buffer_fill (inbuffer, 0, caps_header, GST_DP_HEADER_LENGTH);
i = GST_DP_HEADER_LENGTH;
- memcpy (GST_BUFFER_DATA (inbuffer) + i, caps_payload, payload_len);
+ gst_buffer_fill (inbuffer, i, caps_payload, payload_len);
i += payload_len;
- memcpy (GST_BUFFER_DATA (inbuffer) + i, buf_header, GST_DP_HEADER_LENGTH);
+ gst_buffer_fill (inbuffer, i, buf_header, GST_DP_HEADER_LENGTH);
i += GST_DP_HEADER_LENGTH;
- memcpy (GST_BUFFER_DATA (inbuffer) + i, GST_BUFFER_DATA (buffer),
- GST_BUFFER_SIZE (buffer));
+ gst_buffer_fill (inbuffer, i, "f00d", 4);
gst_caps_unref (caps);
gst_buffer_unref (buffer);
GstPad *srcpad;
GstElement *gdpdepay;
GstBuffer *buffer, *inbuffer, *outbuffer, *shbuffer;
- guint8 *caps_header, *caps_payload, *buf_header;
+ guint8 *caps_header, *caps_payload, *buf_header, *data;
+ gsize size;
guint header_len, payload_len;
guint i;
GstStructure *structure;
caps = gst_caps_from_string ("application/x-gst-test-streamheader");
structure = gst_caps_get_structure (caps, 0);
buffer = gst_buffer_new_and_alloc (4);
- memcpy (GST_BUFFER_DATA (buffer), "f00d", 4);
+ gst_buffer_fill (buffer, 0, "f00d", 4);
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_IN_CAPS);
g_value_init (&array, GST_TYPE_ARRAY);
g_value_init (&value, GST_TYPE_BUFFER);
payload_len = gst_dp_header_payload_length (caps_header);
+ data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
inbuffer = gst_buffer_new_and_alloc (2 * GST_DP_HEADER_LENGTH +
- payload_len + GST_BUFFER_SIZE (buffer));
- memcpy (GST_BUFFER_DATA (inbuffer), caps_header, GST_DP_HEADER_LENGTH);
+ payload_len + size);
+ gst_buffer_fill (inbuffer, 0, caps_header, GST_DP_HEADER_LENGTH);
i = GST_DP_HEADER_LENGTH;
- memcpy (GST_BUFFER_DATA (inbuffer) + i, caps_payload, payload_len);
+ gst_buffer_fill (inbuffer, i, caps_payload, payload_len);
i += payload_len;
- memcpy (GST_BUFFER_DATA (inbuffer) + i, buf_header, GST_DP_HEADER_LENGTH);
+ gst_buffer_fill (inbuffer, i, buf_header, GST_DP_HEADER_LENGTH);
i += GST_DP_HEADER_LENGTH;
- memcpy (GST_BUFFER_DATA (inbuffer) + i, GST_BUFFER_DATA (buffer),
- GST_BUFFER_SIZE (buffer));
+ gst_buffer_fill (inbuffer, i, data, size);
+ gst_buffer_unmap (buffer, data, size);
gst_caps_unref (caps);
gst_buffer_unref (buffer);
buffers = g_list_remove (buffers, outbuffer);
ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 2);
length = GST_DP_HEADER_LENGTH + (strlen (caps_string) + 1);
- fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer), length);
+ fail_unless_equals_int (gst_buffer_get_size (outbuffer), length);
gst_buffer_unref (outbuffer);
/* the third buffer is the GDP buffer for our pushed buffer */
buffers = g_list_remove (buffers, outbuffer);
ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
length = GST_DP_HEADER_LENGTH + 4;
- fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer), length);
+ fail_unless_equals_int (gst_buffer_get_size (outbuffer), length);
gst_buffer_unref (outbuffer);
/* second buffer */
/* the third output buffer is data */
length = GST_DP_HEADER_LENGTH + 4;
- fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer), length);
+ fail_unless_equals_int (gst_buffer_get_size (outbuffer), length);
gst_buffer_unref (outbuffer);
/* a third buffer without caps set explicitly; should work */
/* the fourth output buffer is data */
length = GST_DP_HEADER_LENGTH + 4;
- fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer), length);
+ fail_unless_equals_int (gst_buffer_get_size (outbuffer), length);
gst_buffer_unref (outbuffer);
GST_DEBUG ("first buffer");
inbuffer = gst_buffer_new_and_alloc (4);
- memcpy (GST_BUFFER_DATA (inbuffer), "head", 4);
+ gst_buffer_fill (inbuffer, 0, "head", 4);
caps = gst_caps_from_string ("application/x-gst-test-streamheader");
structure = gst_caps_get_structure (caps, 0);
GST_BUFFER_FLAG_SET (inbuffer, GST_BUFFER_FLAG_IN_CAPS);
buffers = g_list_remove (buffers, outbuffer);
ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 2);
length = GST_DP_HEADER_LENGTH + (strlen (caps_string) + 1);
- fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer), length);
+ fail_unless_equals_int (gst_buffer_get_size (outbuffer), length);
gst_buffer_unref (outbuffer);
/* the third buffer is the GDP buffer for our pushed buffer */
buffers = g_list_remove (buffers, outbuffer);
ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
length = GST_DP_HEADER_LENGTH + 4;
- fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer), length);
+ fail_unless_equals_int (gst_buffer_get_size (outbuffer), length);
gst_buffer_unref (outbuffer);
/* second buffer */
/* the third output buffer is data */
length = GST_DP_HEADER_LENGTH + 4;
- fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer), length);
+ fail_unless_equals_int (gst_buffer_get_size (outbuffer), length);
gst_buffer_unref (outbuffer);
/* a third buffer without caps set explicitly; should work */
/* the fourth output buffer is data */
length = GST_DP_HEADER_LENGTH + 4;
- fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer), length);
+ fail_unless_equals_int (gst_buffer_get_size (outbuffer), length);
gst_buffer_unref (outbuffer);
GstEvent *event;
gchar *caps_string;
gint length;
+ guint8 *data;
+ gsize size;
guint16 crc_calculated, crc_read;
gdppay = setup_gdppay ();
/* verify the header checksum */
/* CRC's start at 58 in the header */
- crc_calculated = gst_dp_crc (GST_BUFFER_DATA (outbuffer), 58);
- crc_read = GST_READ_UINT16_BE (GST_BUFFER_DATA (outbuffer) + 58);
+ outbuffer = gst_buffer_make_writable (outbuffer);
+ data = gst_buffer_map (outbuffer, &size, NULL, GST_MAP_READWRITE);
+ crc_calculated = gst_dp_crc (data, 58);
+ crc_read = GST_READ_UINT16_BE (data + 58);
fail_unless_equals_int (crc_calculated, crc_read);
/* change a byte in the header and verify that the checksum now fails */
- GST_BUFFER_DATA (outbuffer)[0] = 0xff;
- crc_calculated = gst_dp_crc (GST_BUFFER_DATA (outbuffer), 58);
+ data[0] = 0xff;
+ crc_calculated = gst_dp_crc (data, 58);
fail_if (crc_calculated == crc_read,
"Introducing a byte error in the header should make the checksum fail");
+ gst_buffer_unmap (outbuffer, data, size);
gst_buffer_unref (outbuffer);
/* second buffer is the serialized caps;
buffers = g_list_remove (buffers, outbuffer);
ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 2);
length = GST_DP_HEADER_LENGTH + (strlen (caps_string) + 1);
- fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer), length);
+ fail_unless_equals_int (gst_buffer_get_size (outbuffer), length);
gst_buffer_unref (outbuffer);
/* the third buffer is the GDP buffer for our pushed buffer */
buffers = g_list_remove (buffers, outbuffer);
ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
length = GST_DP_HEADER_LENGTH + 4;
- fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer), length);
+ fail_unless_equals_int (gst_buffer_get_size (outbuffer), length);
gst_buffer_unref (outbuffer);
fail_unless (gst_element_set_state (gdppay,
G_STMT_START { \
GstBuffer *buf = gst_buffer_new_and_alloc(num_bytes); \
GRand *rand = g_rand_new_with_seed (num_bytes); \
- guint i; \
+ gsize i; \
+ guint8 *data; \
+ data = gst_buffer_map (buf, NULL, NULL, GST_MAP_WRITE); \
for (i = 0; i < num_bytes; ++i) \
- GST_BUFFER_DATA(buf)[i] = (g_rand_int (rand) >> 24) & 0xff; \
+ data[i] = (g_rand_int (rand) >> 24) & 0xff; \
+ gst_buffer_unmap (buf, data, num_bytes); \
fail_unless_equals_int (gst_pad_push (mysrcpad, buf), GST_FLOW_OK); \
g_rand_free (rand); \
} G_STMT_END
static gboolean
filter_func (GstPluginFeature * feature, gpointer user_data)
{
- return (g_str_has_prefix (GST_PLUGIN_FEATURE_NAME (feature), "libvisual_"));
+ return (g_str_has_prefix (GST_OBJECT_NAME (feature), "libvisual_"));
}
static void
return;
}
for (l = list; l != NULL; l = l->next) {
- test_shutdown_for_factory (GST_PLUGIN_FEATURE_NAME (l->data));
+ test_shutdown_for_factory (GST_OBJECT_NAME (l->data));
}
gst_plugin_feature_list_free (list);
} else {
buffer = gst_buffer_new_and_alloc (4);
gst_buffer_set_caps (buffer, caps);
ASSERT_CAPS_REFCOUNT (caps, "caps", 2);
- memcpy (GST_BUFFER_DATA (buffer), "dead", 4);
+ gst_buffer_fill (buffer, 0, "dead", 4);
fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
GST_DEBUG ("reading");
* buffers */
*hbuf1 = gst_buffer_new_and_alloc (size1);
GST_BUFFER_FLAG_SET (*hbuf1, GST_BUFFER_FLAG_IN_CAPS);
- memcpy (GST_BUFFER_DATA (*hbuf1), data1, size1);
+ gst_buffer_fill (*hbuf1, 0, data1, size1);
*hbuf2 = gst_buffer_new_and_alloc (size2);
GST_BUFFER_FLAG_SET (*hbuf2, GST_BUFFER_FLAG_IN_CAPS);
- memcpy (GST_BUFFER_DATA (*hbuf2), data2, size2);
+ gst_buffer_fill (*hbuf2, 0, data2, size2);
g_value_init (&array, GST_TYPE_ARRAY);
/* push a non-IN_CAPS buffer, this should trigger the client receiving the
* first three buffers */
buf = gst_buffer_new_and_alloc (4);
- memcpy (GST_BUFFER_DATA (buf), "f00d", 4);
+ gst_buffer_fill (buf, 0, "f00d", 4);
gst_pad_push (mysrcpad, buf);
fail_unless_read ("first client", pfd1[0], 4, "babe");
/* now push another buffer, which will trigger streamheader for second
* client */
buf = gst_buffer_new_and_alloc (4);
- memcpy (GST_BUFFER_DATA (buf), "deaf", 4);
+ gst_buffer_fill (buf, 0, "deaf", 4);
gst_pad_push (mysrcpad, buf);
fail_unless_read ("first client", pfd1[0], 4, "deaf");
/* now push a buffer and read */
buf = gst_buffer_new_and_alloc (4);
- memcpy (GST_BUFFER_DATA (buf), "f00d", 4);
+ gst_buffer_fill (buf, 0, "f00d", 4);
gst_pad_push (mysrcpad, buf);
fail_unless_read ("change: first client", pfd1[0], 5, "first");
/* now push another buffer, which will trigger streamheader for second
* client, but should also send new streamheaders to first client */
buf = gst_buffer_new_and_alloc (8);
- memcpy (GST_BUFFER_DATA (buf), "deadbabe", 8);
+ gst_buffer_fill (buf, 0, "deadbabe", 8);
gst_pad_push (mysrcpad, buf);
fail_unless_read ("first client", pfd1[0], 6, "second");
gst_buffer_set_caps (buffer, caps);
/* copy some id */
- data = (gchar *) GST_BUFFER_DATA (buffer);
+ data = gst_buffer_map (buffer, NULL, NULL, GST_MAP_WRITE);
g_snprintf (data, 16, "deadbee%08x", i);
+ gst_buffer_unmap (buffer, data, 16);
fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
}
gst_buffer_set_caps (buffer, caps);
/* copy some id */
- data = (gchar *) GST_BUFFER_DATA (buffer);
+ data = gst_buffer_map (buffer, NULL, NULL, GST_MAP_WRITE);
g_snprintf (data, 16, "deadbee%08x", i);
+ gst_buffer_unmap (buffer, data, 16);
fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
}
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
/* copy some id */
- data = (gchar *) GST_BUFFER_DATA (buffer);
+ data = gst_buffer_map (buffer, NULL, NULL, GST_MAP_WRITE);
g_snprintf (data, 16, "deadbee%08x", i);
+ gst_buffer_unmap (buffer, data, 16);
fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
}
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
/* copy some id */
- data = (gchar *) GST_BUFFER_DATA (buffer);
+ data = gst_buffer_map (buffer, NULL, NULL, GST_MAP_WRITE);
g_snprintf (data, 16, "deadbee%08x", i);
+ gst_buffer_unmap (buffer, data, 16);
fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
}
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
/* copy some id */
- data = (gchar *) GST_BUFFER_DATA (buffer);
+ data = gst_buffer_map (buffer, NULL, NULL, GST_MAP_WRITE);
g_snprintf (data, 16, "deadbee%08x", i);
+ gst_buffer_unmap (buffer, data, 16);
fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
}
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
/* copy some id */
- data = (gchar *) GST_BUFFER_DATA (buffer);
+ data = gst_buffer_map (buffer, NULL, NULL, GST_MAP_WRITE);
g_snprintf (data, 16, "deadbee%08x", i);
+ gst_buffer_unmap (buffer, data, 16);
fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
}
gst_buffer_set_caps (buffer, caps);
/* copy some id */
- data = (gchar *) GST_BUFFER_DATA (buffer);
+ data = gst_buffer_map (buffer, NULL, NULL, GST_MAP_WRITE);
g_snprintf (data, 16, "deadbee%08x", i);
+ gst_buffer_unmap (buffer, data, 16);
if (i > 0)
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT);
typedef GstPushSrc GstRedVideoSrc;
typedef GstPushSrcClass GstRedVideoSrcClass;
-GST_BOILERPLATE_FULL (GstRedVideoSrc, gst_red_video_src, GstPushSrc,
- GST_TYPE_PUSH_SRC, gst_red_video_src_init_type);
-
-static void
-gst_red_video_src_base_init (gpointer klass)
-{
- static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
- GST_PAD_SRC, GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("video/x-raw-yuv, format=(fourcc)I420")
- );
- GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&src_templ));
- gst_element_class_set_details_simple (element_class,
- "Red Video Src", "Source/Video", "yep", "me");
-}
+G_DEFINE_TYPE_WITH_CODE (GstRedVideoSrc, gst_red_video_src,
+ GST_TYPE_PUSH_SRC, gst_red_video_src_init_type (g_define_type_id));
static GstFlowReturn
gst_red_video_src_create (GstPushSrc * src, GstBuffer ** p_buf)
GstCaps *caps;
guint8 *data;
guint w = 64, h = 64;
- guint size;
+ gsize size;
size = w * h * 3 / 2;
buf = gst_buffer_new_and_alloc (size);
- data = GST_BUFFER_DATA (buf);
+ data = gst_buffer_map (buf, NULL, NULL, GST_MAP_WRITE);
memset (data, 76, w * h);
memset (data + (w * h), 85, (w * h) / 4);
memset (data + (w * h) + ((w * h) / 4), 255, (w * h) / 4);
+ gst_buffer_unmap (buf, data, size);
caps = gst_caps_new_simple ("video/x-raw-yuv", "format", GST_TYPE_FOURCC,
GST_MAKE_FOURCC ('I', '4', '2', '0'), "width", G_TYPE_INT, w, "height",
gst_red_video_src_class_init (GstRedVideoSrcClass * klass)
{
GstPushSrcClass *pushsrc_class = GST_PUSH_SRC_CLASS (klass);
+ static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC, GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-raw-yuv, format=(fourcc)I420")
+ );
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&src_templ));
+ gst_element_class_set_details_simple (element_class,
+ "Red Video Src", "Source/Video", "yep", "me");
pushsrc_class->create = gst_red_video_src_create;
}
static void
-gst_red_video_src_init (GstRedVideoSrc * src, GstRedVideoSrcClass * klass)
+gst_red_video_src_init (GstRedVideoSrc * src)
{
}
typedef GstPushSrc GstCodecSrc;
typedef GstPushSrcClass GstCodecSrcClass;
-GST_BOILERPLATE_FULL (GstCodecSrc, gst_codec_src, GstPushSrc,
- GST_TYPE_PUSH_SRC, gst_codec_src_init_type);
-
-static void
-gst_codec_src_base_init (gpointer klass)
-{
- static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
- GST_PAD_SRC, GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("application/x-codec")
- );
- GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&src_templ));
- gst_element_class_set_details_simple (element_class,
- "Codec Src", "Source/Video", "yep", "me");
-}
+G_DEFINE_TYPE_WITH_CODE (GstCodecSrc, gst_codec_src,
+ GST_TYPE_PUSH_SRC, gst_codec_src_init_type (g_define_type_id));
static GstFlowReturn
gst_codec_src_create (GstPushSrc * src, GstBuffer ** p_buf)
{
GstBuffer *buf;
GstCaps *caps;
+ guint8 *data;
buf = gst_buffer_new_and_alloc (20);
- memset (GST_BUFFER_DATA (buf), 0, GST_BUFFER_SIZE (buf));
+ data = gst_buffer_map (buf, NULL, NULL, GST_MAP_WRITE);
+ memset (data, 0, 20);
+ gst_buffer_unmap (buf, data, 20);
caps = gst_caps_new_simple ("application/x-codec", NULL);
gst_buffer_set_caps (buf, caps);
gst_codec_src_class_init (GstCodecSrcClass * klass)
{
GstPushSrcClass *pushsrc_class = GST_PUSH_SRC_CLASS (klass);
+ static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC, GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-codec")
+ );
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&src_templ));
+ gst_element_class_set_details_simple (element_class,
+ "Codec Src", "Source/Video", "yep", "me");
pushsrc_class->create = gst_codec_src_create;
}
static void
-gst_codec_src_init (GstCodecSrc * src, GstCodecSrcClass * klass)
+gst_codec_src_init (GstCodecSrc * src)
{
}
typedef GstPushSrc GstRedVideoSrc;
typedef GstPushSrcClass GstRedVideoSrcClass;
-GST_BOILERPLATE_FULL (GstRedVideoSrc, gst_red_video_src, GstPushSrc,
- GST_TYPE_PUSH_SRC, gst_red_video_src_init_type);
-
-static void
-gst_red_video_src_base_init (gpointer klass)
-{
- static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
- GST_PAD_SRC, GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("video/x-raw-yuv, format=(fourcc)I420")
- );
- GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&src_templ));
- gst_element_class_set_details_simple (element_class,
- "Red Video Src", "Source/Video", "yep", "me");
-}
+G_DEFINE_TYPE_WITH_CODE (GstRedVideoSrc, gst_red_video_src,
+ GST_TYPE_PUSH_SRC, gst_red_video_src_init_type (g_define_type_id));
static GstFlowReturn
gst_red_video_src_create (GstPushSrc * src, GstBuffer ** p_buf)
size = w * h * 3 / 2;
buf = gst_buffer_new_and_alloc (size);
- data = GST_BUFFER_DATA (buf);
+ data = gst_buffer_map (buf, NULL, NULL, GST_MAP_WRITE);
memset (data, 76, w * h);
memset (data + (w * h), 85, (w * h) / 4);
memset (data + (w * h) + ((w * h) / 4), 255, (w * h) / 4);
+ gst_buffer_unmap (buf, data, size);
caps = gst_caps_new_simple ("video/x-raw-yuv", "format", GST_TYPE_FOURCC,
GST_MAKE_FOURCC ('I', '4', '2', '0'), "width", G_TYPE_INT, w, "height",
gst_red_video_src_class_init (GstRedVideoSrcClass * klass)
{
GstPushSrcClass *pushsrc_class = GST_PUSH_SRC_CLASS (klass);
+ static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC, GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-raw-yuv, format=(fourcc)I420")
+ );
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&src_templ));
+ gst_element_class_set_details_simple (element_class,
+ "Red Video Src", "Source/Video", "yep", "me");
pushsrc_class->create = gst_red_video_src_create;
}
static void
-gst_red_video_src_init (GstRedVideoSrc * src, GstRedVideoSrcClass * klass)
+gst_red_video_src_init (GstRedVideoSrc * src)
{
}
typedef GstPushSrc GstCodecSrc;
typedef GstPushSrcClass GstCodecSrcClass;
-GST_BOILERPLATE_FULL (GstCodecSrc, gst_codec_src, GstPushSrc,
- GST_TYPE_PUSH_SRC, gst_codec_src_init_type);
-
-static void
-gst_codec_src_base_init (gpointer klass)
-{
- static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
- GST_PAD_SRC, GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("application/x-codec")
- );
- GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&src_templ));
- gst_element_class_set_details_simple (element_class,
- "Codec Src", "Source/Video", "yep", "me");
-}
+G_DEFINE_TYPE_WITH_CODE (GstCodecSrc, gst_codec_src,
+ GST_TYPE_PUSH_SRC, gst_codec_src_init_type (g_define_type_id));
static GstFlowReturn
gst_codec_src_create (GstPushSrc * src, GstBuffer ** p_buf)
{
GstBuffer *buf;
GstCaps *caps;
+ guint8 *data;
buf = gst_buffer_new_and_alloc (20);
- memset (GST_BUFFER_DATA (buf), 0, GST_BUFFER_SIZE (buf));
+ data = gst_buffer_map (buf, NULL, NULL, GST_MAP_WRITE);
+ memset (data, 0, 20);
+ gst_buffer_unmap (buf, data, 20);
caps = gst_caps_new_simple ("application/x-codec", NULL);
gst_buffer_set_caps (buf, caps);
gst_codec_src_class_init (GstCodecSrcClass * klass)
{
GstPushSrcClass *pushsrc_class = GST_PUSH_SRC_CLASS (klass);
+ static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC, GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-codec")
+ );
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&src_templ));
+ gst_element_class_set_details_simple (element_class,
+ "Codec Src", "Source/Video", "yep", "me");
pushsrc_class->create = gst_codec_src_create;
}
static void
-gst_codec_src_init (GstCodecSrc * src, GstCodecSrcClass * klass)
+gst_codec_src_init (GstCodecSrc * src)
{
}
buffer_from_static_string (const gchar * s)
{
GstBuffer *buf;
+ gsize len;
+
+ len = strlen (s);
buf = gst_buffer_new ();
- GST_BUFFER_DATA (buf) = (guint8 *) s;
- GST_BUFFER_SIZE (buf) = strlen (s);
- GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_READONLY);
+ gst_buffer_take_memory (buf,
+ gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
+ (gpointer) s, NULL, len, 0, len));
return buf;
}
const GstStructure *buffer_caps_struct;
GstBuffer *buf;
gchar *out;
- guint out_size;
+ gsize out_size;
buf = g_list_nth_data (buffers, n - start_idx);
fail_unless (buf != NULL);
fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (buf), input[n].from_ts);
fail_unless_equals_uint64 (GST_BUFFER_DURATION (buf),
input[n].to_ts - input[n].from_ts);
- out = (gchar *) GST_BUFFER_DATA (buf);
- out_size = GST_BUFFER_SIZE (buf);
- /* shouldn't have trailing newline characters */
- fail_if (out_size > 0 && out[out_size - 1] == '\n');
- /* shouldn't include NUL-terminator in data size */
- fail_if (out_size > 0 && out[out_size - 1] == '\0');
- /* but should still have a NUL-terminator behind the declared data */
- fail_unless_equals_int (out[out_size], '\0');
- /* make sure out string matches expected string */
- fail_unless_equals_string (out, input[n].out);
+
+ out = gst_buffer_map (buf, &out_size, NULL, GST_MAP_READ);
+ /* can be NULL */
+ if (out != NULL) {
+ /* shouldn't have trailing newline characters */
+ fail_if (out_size > 0 && out[out_size - 1] == '\n');
+ /* shouldn't include NUL-terminator in data size */
+ fail_if (out_size > 0 && out[out_size - 1] == '\0');
+ /* but should still have a NUL-terminator behind the declared data */
+ fail_unless_equals_int (out[out_size], '\0');
+ /* make sure out string matches expected string */
+ fail_unless_equals_string (out, input[n].out);
+ }
+ gst_buffer_unmap (buf, out, out_size);
/* check caps */
fail_unless (GST_BUFFER_CAPS (buf) != NULL);
buffer_caps_struct = gst_caps_get_structure (GST_BUFFER_CAPS (buf), 0);
const GstStructure *buffer_caps_struct;
GstBuffer *buf;
gchar *out;
- guint out_size;
+ gsize out_size;
buf = g_list_nth_data (buffers, n);
fail_unless (buf != NULL);
input[n].to_ts - input[n].from_ts);
}
- out = (gchar *) GST_BUFFER_DATA (buf);
- out_size = GST_BUFFER_SIZE (buf);
- /* shouldn't have trailing newline characters */
- fail_if (out_size > 0 && out[out_size - 1] == '\n');
- /* shouldn't include NUL-terminator in data size */
- fail_if (out_size > 0 && out[out_size - 1] == '\0');
- /* but should still have a NUL-terminator behind the declared data */
- fail_unless_equals_int (out[out_size], '\0');
- /* make sure out string matches expected string */
- fail_unless_equals_string (out, input[n].out);
+ out = gst_buffer_map (buf, &out_size, NULL, GST_MAP_READ);
+ /* can be NULL */
+ if (out != NULL) {
+ /* shouldn't have trailing newline characters */
+ fail_if (out_size > 0 && out[out_size - 1] == '\n');
+ /* shouldn't include NUL-terminator in data size */
+ fail_if (out_size > 0 && out[out_size - 1] == '\0');
+ /* but should still have a NUL-terminator behind the declared data */
+ fail_unless_equals_int (out[out_size], '\0');
+ /* make sure out string matches expected string */
+ fail_unless_equals_string (out, input[n].out);
+ }
+ gst_buffer_unmap (buf, out, out_size);
/* check caps */
fail_unless (GST_BUFFER_CAPS (buf) != NULL);
buffer_caps_struct = gst_caps_get_structure (GST_BUFFER_CAPS (buf), 0);
{
GstStructure *s;
gint x, y, w, h;
+ guint8 *data;
+ gsize size;
fail_unless (buf != NULL);
fail_unless (GST_BUFFER_CAPS (buf) != NULL);
fail_unless (gst_structure_get_int (s, "width", &w));
fail_unless (gst_structure_get_int (s, "height", &h));
+ data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
for (y = 0; y < h; ++y) {
- guint8 *data = GST_BUFFER_DATA (buf) + (y * GST_ROUND_UP_4 (w));
+ guint8 *ptr = data + (y * GST_ROUND_UP_4 (w));
for (x = 0; x < w; ++x) {
- if (data[x] != 0x00) {
+ if (ptr[x] != 0x00) {
GST_LOG ("non-black pixel at (x,y) %d,%d", x, y);
return FALSE;
}
}
}
+ gst_buffer_unmap (buf, data, size);
return TRUE;
}
GstBuffer *buffer;
GstCaps *caps;
gint w, h, size;
+ guint8 *data;
fail_unless (caps_string != NULL);
GST_LOG ("creating buffer (%dx%d)", w, h);
size = I420_SIZE (w, h);
buffer = gst_buffer_new_and_alloc (size);
+
+ data = gst_buffer_map (buffer, NULL, NULL, GST_MAP_WRITE);
/* we're only checking the Y plane later, so just zero it all out,
* even if it's not the blackest black there is */
- memset (GST_BUFFER_DATA (buffer), 0, size);
+ memset (data, 0, size);
+ gst_buffer_unmap (buffer, data, size);
gst_buffer_set_caps (buffer, caps);
gst_caps_unref (caps);
txt_len = strlen (txt);
buffer = gst_buffer_new_and_alloc (txt_len);
- memcpy (GST_BUFFER_DATA (buffer), txt, txt_len);
+ gst_buffer_fill (buffer, 0, txt, txt_len);
GST_BUFFER_TIMESTAMP (buffer) = ts;
GST_BUFFER_DURATION (buffer) = duration;
/* pushing gives away one of the two references we have ... */
fail_unless (gst_pad_push (myvideosrcpad, inbuffer) == GST_FLOW_OK);
- /* should be the parent for a new subbuffer for the stamp fix-up */
- ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 2);
+ /* should be a new buffer for the stamp fix-up */
+ ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
fail_unless_equals_int (g_list_length (buffers), 1);
fail_unless (GST_BUFFER_CAST (buffers->data) != inbuffer);
fail_unless (GST_BUFFER_TIMESTAMP (GST_BUFFER_CAST (buffers->data)) ==
fail_unless (buffer_is_all_black (GST_BUFFER_CAST (buffers->data)));
/* now, another video buffer */
- inbuffer = gst_buffer_make_metadata_writable (inbuffer);
+ inbuffer = gst_buffer_make_writable (inbuffer);
GST_BUFFER_TIMESTAMP (inbuffer) = GST_SECOND;
GST_BUFFER_DURATION (inbuffer) = GST_SECOND / 2;
FALSE);
/* a third video buffer */
- inbuffer = gst_buffer_make_metadata_writable (inbuffer);
+ inbuffer = gst_buffer_make_writable (inbuffer);
GST_BUFFER_TIMESTAMP (inbuffer) = 30 * GST_SECOND;
GST_BUFFER_DURATION (inbuffer) = GST_SECOND / 2;
next->data)));
/* a fourth video buffer */
- inbuffer = gst_buffer_make_metadata_writable (inbuffer);
+ inbuffer = gst_buffer_make_writable (inbuffer);
GST_BUFFER_TIMESTAMP (inbuffer) = 35 * GST_SECOND;
GST_BUFFER_DURATION (inbuffer) = GST_SECOND;
gst_check_teardown_element (videorate);
}
+static void
+buffer_memset (GstBuffer * buffer, gint val, gsize size)
+{
+ guint8 *data;
+
+ data = gst_buffer_map (buffer, NULL, NULL, GST_MAP_WRITE);
+ memset (data, val, size);
+ gst_buffer_unmap (buffer, data, size);
+}
+
+static guint8
+buffer_get_byte (GstBuffer * buffer, gint offset)
+{
+ guint8 res;
+
+ gst_buffer_extract (buffer, offset, &res, 1);
+
+ return res;
+}
+
GST_START_TEST (test_one)
{
GstElement *videorate;
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (4);
- memset (GST_BUFFER_DATA (inbuffer), 0, 4);
+ buffer_memset (inbuffer, 0, 4);
caps = gst_caps_from_string (VIDEO_CAPS_STRING);
gst_buffer_set_caps (inbuffer, caps);
GST_BUFFER_TIMESTAMP (inbuffer) = 0;
streams */
GST_BUFFER_OFFSET (first) = g_rand_int (rand);
GST_BUFFER_OFFSET_END (first) = g_rand_int (rand);
- memset (GST_BUFFER_DATA (first), 1, 4);
+ buffer_memset (first, 1, 4);
caps = gst_caps_from_string (VIDEO_CAPS_STRING);
gst_buffer_set_caps (first, caps);
gst_caps_unref (caps);
GST_BUFFER_TIMESTAMP (second) = GST_SECOND * 3 / 50;
GST_BUFFER_OFFSET (first) = g_rand_int (rand);
GST_BUFFER_OFFSET_END (first) = g_rand_int (rand);
- memset (GST_BUFFER_DATA (second), 2, 4);
+ buffer_memset (second, 2, 4);
caps = gst_caps_from_string (VIDEO_CAPS_STRING);
gst_buffer_set_caps (second, caps);
gst_caps_unref (caps);
/* ... and the first one is pushed out, with timestamp 0 */
fail_unless_equals_int (g_list_length (buffers), 1);
assert_videorate_stats (videorate, "second buffer", 2, 1, 0, 0);
- ASSERT_BUFFER_REFCOUNT (first, "first", 2);
+ ASSERT_BUFFER_REFCOUNT (first, "first", 1);
outbuffer = buffers->data;
fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (outbuffer), 0);
GST_BUFFER_TIMESTAMP (third) = GST_SECOND * 12 / 50;
GST_BUFFER_OFFSET (first) = g_rand_int (rand);
GST_BUFFER_OFFSET_END (first) = g_rand_int (rand);
- memset (GST_BUFFER_DATA (third), 3, 4);
+ buffer_memset (third, 3, 4);
caps = gst_caps_from_string (VIDEO_CAPS_STRING);
gst_buffer_set_caps (third, caps);
gst_caps_unref (caps);
/* check timestamp and source correctness */
l = buffers;
fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (l->data), 0);
- fail_unless_equals_int (GST_BUFFER_DATA (l->data)[0], 1);
+ fail_unless_equals_int (buffer_get_byte (l->data, 0), 1);
fail_unless_equals_uint64 (GST_BUFFER_OFFSET (l->data), 0);
fail_unless_equals_uint64 (GST_BUFFER_OFFSET_END (l->data), 1);
l = g_list_next (l);
fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (l->data), GST_SECOND / 25);
- fail_unless_equals_int (GST_BUFFER_DATA (l->data)[0], 2);
+ fail_unless_equals_int (buffer_get_byte (l->data, 0), 2);
fail_unless_equals_uint64 (GST_BUFFER_OFFSET (l->data), 1);
fail_unless_equals_uint64 (GST_BUFFER_OFFSET_END (l->data), 2);
l = g_list_next (l);
fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (l->data),
GST_SECOND * 2 / 25);
- fail_unless_equals_int (GST_BUFFER_DATA (l->data)[0], 2);
+ fail_unless_equals_int (buffer_get_byte (l->data, 0), 2);
fail_unless_equals_uint64 (GST_BUFFER_OFFSET (l->data), 2);
fail_unless_equals_uint64 (GST_BUFFER_OFFSET_END (l->data), 3);
l = g_list_next (l);
fail_unless_equals_uint64 (GST_BUFFER_TIMESTAMP (l->data),
GST_SECOND * 3 / 25);
- fail_unless_equals_int (GST_BUFFER_DATA (l->data)[0], 2);
+ fail_unless_equals_int (buffer_get_byte (l->data, 0), 2);
fail_unless_equals_uint64 (GST_BUFFER_OFFSET (l->data), 3);
fail_unless_equals_uint64 (GST_BUFFER_OFFSET_END (l->data), 4);
fail_unless_equals_int (g_list_length (buffers), 4);
/* one held by us, three held by each output frame taken from the second */
- ASSERT_BUFFER_REFCOUNT (second, "second", 4);
+ ASSERT_BUFFER_REFCOUNT (second, "second", 1);
/* now send EOS */
fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
/* first buffer */
first = gst_buffer_new_and_alloc (4);
GST_BUFFER_TIMESTAMP (first) = GST_SECOND;
- memset (GST_BUFFER_DATA (first), 0, 4);
+ buffer_memset (first, 0, 4);
caps = gst_caps_from_string (VIDEO_CAPS_STRING);
gst_buffer_set_caps (first, caps);
gst_caps_unref (caps);
/* second buffer */
second = gst_buffer_new_and_alloc (4);
GST_BUFFER_TIMESTAMP (second) = 0;
- memset (GST_BUFFER_DATA (second), 0, 4);
+ buffer_memset (second, 0, 4);
caps = gst_caps_from_string (VIDEO_CAPS_STRING);
gst_buffer_set_caps (second, caps);
gst_caps_unref (caps);
/* third buffer */
third = gst_buffer_new_and_alloc (4);
GST_BUFFER_TIMESTAMP (third) = 2 * GST_SECOND;
- memset (GST_BUFFER_DATA (third), 0, 4);
+ buffer_memset (third, 0, 4);
caps = gst_caps_from_string (VIDEO_CAPS_STRING);
gst_buffer_set_caps (third, caps);
gst_caps_unref (caps);
/* and now the first one should be pushed once and dupped 24 + 13 times, to
* reach the half point between 1 s (first) and 2 s (third) */
fail_unless_equals_int (g_list_length (buffers), 38);
- ASSERT_BUFFER_REFCOUNT (first, "first", 39);
+ ASSERT_BUFFER_REFCOUNT (first, "first", 1);
ASSERT_BUFFER_REFCOUNT (second, "second", 1);
ASSERT_BUFFER_REFCOUNT (third, "third", 2);
assert_videorate_stats (videorate, "third", 3, 38, 1, 37);
/* first buffer */
first = gst_buffer_new_and_alloc (4);
GST_BUFFER_TIMESTAMP (first) = 0;
- memset (GST_BUFFER_DATA (first), 0, 4);
+ buffer_memset (first, 0, 4);
caps = gst_caps_from_string (VIDEO_CAPS_STRING);
gst_buffer_set_caps (first, caps);
gst_caps_unref (caps);
/* second buffer */
second = gst_buffer_new_and_alloc (4);
GST_BUFFER_TIMESTAMP (second) = GST_SECOND;
- memset (GST_BUFFER_DATA (second), 0, 4);
+ buffer_memset (second, 0, 4);
caps = gst_caps_from_string (VIDEO_CAPS_STRING);
gst_buffer_set_caps (second, caps);
gst_caps_unref (caps);
/* and it created 13 output buffers as copies of the first frame */
fail_unless_equals_int (g_list_length (buffers), 13);
assert_videorate_stats (videorate, "second", 2, 13, 0, 12);
- ASSERT_BUFFER_REFCOUNT (first, "first", 14);
+ ASSERT_BUFFER_REFCOUNT (first, "first", 1);
/* third buffer */
third = gst_buffer_new_and_alloc (4);
GST_BUFFER_TIMESTAMP (third) = 2 * GST_SECOND;
- memset (GST_BUFFER_DATA (third), 0, 4);
+ buffer_memset (third, 0, 4);
caps = gst_caps_from_string (VIDEO_CAPS_STRING);
gst_buffer_set_caps (third, caps);
gst_caps_unref (caps);
/* submitting a frame with 2 seconds triggers output of 25 more frames */
fail_unless_equals_int (g_list_length (buffers), 38);
- ASSERT_BUFFER_REFCOUNT (first, "first", 14);
- ASSERT_BUFFER_REFCOUNT (second, "second", 26);
+ ASSERT_BUFFER_REFCOUNT (first, "first", 1);
+ ASSERT_BUFFER_REFCOUNT (second, "second", 1);
/* three frames submitted; two of them output as is, and 36 duplicated */
assert_videorate_stats (videorate, "third", 3, 38, 0, 36);
/* fourth buffer */
fourth = gst_buffer_new_and_alloc (4);
GST_BUFFER_TIMESTAMP (fourth) = 0;
- memset (GST_BUFFER_DATA (fourth), 0, 4);
+ buffer_memset (fourth, 0, 4);
caps = gst_caps_from_string (VIDEO_CAPS_STRING);
gst_buffer_set_caps (fourth, caps);
gst_caps_unref (caps);
ASSERT_BUFFER_REFCOUNT (fourth, "fourth", 1);
fail_unless_equals_int (g_list_length (buffers), 38);
- ASSERT_BUFFER_REFCOUNT (first, "first", 14);
- ASSERT_BUFFER_REFCOUNT (second, "second", 26);
+ ASSERT_BUFFER_REFCOUNT (first, "first", 1);
+ ASSERT_BUFFER_REFCOUNT (second, "second", 1);
assert_videorate_stats (videorate, "fourth", 4, 38, 1, 36);
/* verify last buffer */
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (4);
- memset (GST_BUFFER_DATA (inbuffer), 0, 4);
+ buffer_memset (inbuffer, 0, 4);
caps = gst_caps_from_string (VIDEO_CAPS_NO_FRAMERATE_STRING);
gst_buffer_set_caps (inbuffer, caps);
gst_caps_unref (caps);
fail_unless (gst_pad_push_event (mysrcpad, newsegment) == TRUE);
first = gst_buffer_new_and_alloc (4);
- memset (GST_BUFFER_DATA (first), 0, 4);
+ buffer_memset (first, 0, 4);
caps = gst_caps_from_string (VIDEO_CAPS_STRING);
GST_BUFFER_TIMESTAMP (first) = 0;
gst_buffer_set_caps (first, caps);
/* second buffer */
second = gst_buffer_new_and_alloc (4);
GST_BUFFER_TIMESTAMP (second) = GST_SECOND / 25;
- memset (GST_BUFFER_DATA (second), 0, 4);
+ buffer_memset (second, 0, 4);
gst_buffer_set_caps (second, caps);
fail_unless (gst_pad_push (mysrcpad, second) == GST_FLOW_OK);
/* third buffer with new size */
third = gst_buffer_new_and_alloc (4);
GST_BUFFER_TIMESTAMP (third) = 2 * GST_SECOND / 25;
- memset (GST_BUFFER_DATA (third), 0, 4);
+ buffer_memset (third, 0, 4);
caps_newsize = gst_caps_from_string (VIDEO_CAPS_NEWSIZE_STRING);
gst_buffer_set_caps (third, caps_newsize);
/* fourth buffer with original size */
fourth = gst_buffer_new_and_alloc (4);
GST_BUFFER_TIMESTAMP (fourth) = 3 * GST_SECOND / 25;
- memset (GST_BUFFER_DATA (fourth), 0, 4);
+ buffer_memset (fourth, 0, 4);
gst_buffer_set_caps (fourth, caps);
fail_unless (gst_pad_push (mysrcpad, fourth) == GST_FLOW_OK);
/* fifth buffer with original size */
fifth = gst_buffer_new_and_alloc (4);
GST_BUFFER_TIMESTAMP (fifth) = 4 * GST_SECOND / 25;
- memset (GST_BUFFER_DATA (fifth), 0, 4);
+ buffer_memset (fifth, 0, 4);
gst_buffer_set_caps (fifth, caps);
fail_unless (gst_pad_push (mysrcpad, fifth) == GST_FLOW_OK);
"could not set to playing");
buf = gst_buffer_new_and_alloc (4);
- memset (GST_BUFFER_DATA (buf), 0, 4);
+ buffer_memset (buf, 0, 4);
caps = gst_caps_from_string (VIDEO_CAPS_STRING);
gst_buffer_set_caps (buf, caps);
gst_caps_unref (caps);
gst_pad_set_active (mysinkpad, FALSE);
/* push buffer on deactivated pad */
- fail_unless (gst_buffer_is_metadata_writable (buf));
+ fail_unless (gst_buffer_is_writable (buf));
GST_BUFFER_TIMESTAMP (buf) = ts;
/* pushing gives away our reference */
gst_caps_append_structure (ret[i], gst_structure_copy (s));
}
+ gst_caps_unref (caps);
gst_object_unref (scale);
return ret;
l1 = l1->next, l2 = l2->next) {
GstBuffer *a = l1->data;
GstBuffer *b = l2->data;
+ gsize sa, sb;
+ guint8 *pa, *pb;
- fail_unless_equals_int (GST_BUFFER_SIZE (a), GST_BUFFER_SIZE (b));
- fail_unless (GST_BUFFER_DATA (a) == GST_BUFFER_DATA (b));
+ pa = gst_buffer_map (a, &sa, NULL, GST_MAP_READ);
+ pb = gst_buffer_map (b, &sb, NULL, GST_MAP_READ);
+ fail_unless_equals_int (sa, sb);
+ fail_unless (pa == pb);
+ gst_buffer_unmap (b, pb, sb);
+ gst_buffer_unmap (a, pa, sa);
gst_buffer_unref (a);
gst_buffer_unref (b);
GType gst_test_reverse_negotiation_sink_get_type (void);
-GST_BOILERPLATE (GstTestReverseNegotiationSink,
- gst_test_reverse_negotiation_sink, GstBaseSink, GST_TYPE_BASE_SINK);
+G_DEFINE_TYPE (GstTestReverseNegotiationSink,
+ gst_test_reverse_negotiation_sink, GST_TYPE_BASE_SINK);
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_VIDEO_CAPS_xRGB));
+#if 0
static GstFlowReturn
gst_test_reverse_negotiation_sink_buffer_alloc (GstBaseSink * bsink,
guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf)
return GST_FLOW_OK;
}
+#endif
static GstFlowReturn
gst_test_reverse_negotiation_sink_render (GstBaseSink * bsink,
}
static void
-gst_test_reverse_negotiation_sink_base_init (gpointer g_class)
+gst_test_reverse_negotiation_sink_class_init (GstTestReverseNegotiationSinkClass
+ * klass)
{
- GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
+ GstElementClass *gstelement_class;
+ GstBaseSinkClass *gstbase_sink_class;
+
+ gstelement_class = GST_ELEMENT_CLASS (klass);
+ gstbase_sink_class = GST_BASE_SINK_CLASS (klass);
gst_element_class_set_details_simple (gstelement_class,
"Test Reverse Negotiation Sink",
"Some test sink", "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&sinktemplate));
-}
-
-static void
-gst_test_reverse_negotiation_sink_class_init (GstTestReverseNegotiationSinkClass
- * klass)
-{
- GstBaseSinkClass *gstbase_sink_class;
-
- gstbase_sink_class = GST_BASE_SINK_CLASS (klass);
+#if 0
gstbase_sink_class->buffer_alloc =
GST_DEBUG_FUNCPTR (gst_test_reverse_negotiation_sink_buffer_alloc);
+#endif
gstbase_sink_class->render =
GST_DEBUG_FUNCPTR (gst_test_reverse_negotiation_sink_render);
}
static void
-gst_test_reverse_negotiation_sink_init (GstTestReverseNegotiationSink * sink,
- GstTestReverseNegotiationSinkClass * g_class)
+gst_test_reverse_negotiation_sink_init (GstTestReverseNegotiationSink * sink)
{
sink->nbuffers = 0;
}
"xRGB1555", 16, 15, 0x00007c00, 0x000003e0, 0x0000001f, 0x0000000}
};
GstElement *pipeline, *src, *filter, *sink;
- const GstCaps *template_caps;
+ GstCaps *template_caps;
GstBuffer *buf = NULL;
GstPad *srcpad;
gint p, i, e;
/* caps are supported, let's run some tests then ... */
for (p = 0; p < G_N_ELEMENTS (test_patterns); ++p) {
GstStateChangeReturn state_ret;
+ guint8 *data;
+ gsize size;
g_object_set (src, "pattern", test_patterns[p].pattern_enum, NULL);
/* now check the first pixel */
- check_rgb_buf (GST_BUFFER_DATA (buf), rgb_formats[i].red_mask,
+ data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
+ check_rgb_buf (data, rgb_formats[i].red_mask,
rgb_formats[i].green_mask, rgb_formats[i].blue_mask,
rgb_formats[i].alpha_mask, test_patterns[p].r_expected,
test_patterns[p].g_expected, test_patterns[p].b_expected,
endianness, rgb_formats[i].bpp, rgb_formats[i].depth);
+ gst_buffer_unmap (buf, data, size);
gst_buffer_unref (buf);
buf = NULL;
gst_caps_unref (caps);
}
}
+ gst_caps_unref (template_caps);
gst_object_unref (pipeline);
}
GstCaps *caps;
gint8 in[2] = { 64, -16 };
gint8 *res;
+ gsize size;
volume = setup_volume ();
fail_unless (gst_element_set_state (volume,
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (2);
- memcpy (GST_BUFFER_DATA (inbuffer), in, 2);
+ gst_buffer_fill (inbuffer, 0, in, 2);
caps = gst_caps_from_string (VOLUME_CAPS_STRING_S8);
gst_buffer_set_caps (inbuffer, caps);
gst_caps_unref (caps);
fail_unless_equals_int (g_list_length (buffers), 1);
fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
fail_unless (inbuffer == outbuffer);
- res = (gint8 *) GST_BUFFER_DATA (outbuffer);
+ res = gst_buffer_map (outbuffer, &size, NULL, GST_MAP_READ);
GST_INFO ("expected %+5d %+5d real %+5d %+5d", in[0], in[1], res[0], res[1]);
- fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 2) == 0);
+ fail_unless (memcmp (res, in, 2) == 0);
+ gst_buffer_unmap (outbuffer, res, size);
/* cleanup */
cleanup_volume (volume);
gint8 in[2] = { 64, -16 };
gint8 out[2] = { 32, -8 };
gint8 *res;
+ gsize size;
volume = setup_volume ();
g_object_set (G_OBJECT (volume), "volume", 0.5, NULL);
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (2);
- memcpy (GST_BUFFER_DATA (inbuffer), in, 2);
- fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 2) == 0);
+ gst_buffer_fill (inbuffer, 0, in, 2);
caps = gst_caps_from_string (VOLUME_CAPS_STRING_S8);
gst_buffer_set_caps (inbuffer, caps);
gst_caps_unref (caps);
fail_unless_equals_int (g_list_length (buffers), 1);
fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
fail_unless (inbuffer == outbuffer);
- res = (gint8 *) GST_BUFFER_DATA (outbuffer);
+ res = gst_buffer_map (outbuffer, &size, NULL, GST_MAP_READ);
GST_INFO ("expected %+5d %+5d real %+5d %+5d", out[0], out[1], res[0],
res[1]);
- fail_unless (memcmp (GST_BUFFER_DATA (outbuffer), out, 2) == 0);
+ fail_unless (memcmp (res, out, 2) == 0);
+ gst_buffer_unmap (outbuffer, res, size);
/* cleanup */
cleanup_volume (volume);
gint8 in[2] = { 64, -16 };
gint8 out[2] = { 127, -32 }; /* notice the clamped sample */
gint8 *res;
+ gsize size;
volume = setup_volume ();
g_object_set (G_OBJECT (volume), "volume", 2.0, NULL);
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (2);
- memcpy (GST_BUFFER_DATA (inbuffer), in, 2);
- fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 2) == 0);
+ gst_buffer_fill (inbuffer, 0, in, 2);
caps = gst_caps_from_string (VOLUME_CAPS_STRING_S8);
gst_buffer_set_caps (inbuffer, caps);
gst_caps_unref (caps);
fail_unless_equals_int (g_list_length (buffers), 1);
fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
fail_unless (inbuffer == outbuffer);
- res = (gint8 *) GST_BUFFER_DATA (outbuffer);
+ res = gst_buffer_map (outbuffer, &size, NULL, GST_MAP_READ);
GST_INFO ("expected %+5d %+5d real %+5d %+5d", out[0], out[1], res[0],
res[1]);
- fail_unless (memcmp (GST_BUFFER_DATA (outbuffer), out, 2) == 0);
+ fail_unless (memcmp (res, out, 2) == 0);
+ gst_buffer_unmap (outbuffer, res, size);
/* cleanup */
cleanup_volume (volume);
gint8 in[2] = { 64, -16 };
gint8 out[2] = { 0, 0 };
gint8 *res;
+ gsize size;
volume = setup_volume ();
g_object_set (G_OBJECT (volume), "mute", TRUE, NULL);
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (2);
- memcpy (GST_BUFFER_DATA (inbuffer), in, 2);
- fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 2) == 0);
+ gst_buffer_fill (inbuffer, 0, in, 2);
caps = gst_caps_from_string (VOLUME_CAPS_STRING_S8);
gst_buffer_set_caps (inbuffer, caps);
gst_caps_unref (caps);
fail_unless_equals_int (g_list_length (buffers), 1);
fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
fail_unless (inbuffer == outbuffer);
- res = (gint8 *) GST_BUFFER_DATA (outbuffer);
+ res = gst_buffer_map (outbuffer, &size, NULL, GST_MAP_READ);
GST_INFO ("expected %+5d %+5d real %+5d %+5d", out[0], out[1], res[0],
res[1]);
- fail_unless (memcmp (GST_BUFFER_DATA (outbuffer), out, 2) == 0);
+ fail_unless (memcmp (res, out, 2) == 0);
+ gst_buffer_unmap (outbuffer, res, size);
/* cleanup */
cleanup_volume (volume);
GstCaps *caps;
gint16 in[2] = { 16384, -256 };
gint16 *res;
+ gsize size;
volume = setup_volume ();
fail_unless (gst_element_set_state (volume,
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (4);
- memcpy (GST_BUFFER_DATA (inbuffer), in, 4);
+ gst_buffer_fill (inbuffer, 0, in, 4);
caps = gst_caps_from_string (VOLUME_CAPS_STRING_S16);
gst_buffer_set_caps (inbuffer, caps);
gst_caps_unref (caps);
fail_unless_equals_int (g_list_length (buffers), 1);
fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
fail_unless (inbuffer == outbuffer);
- res = (gint16 *) GST_BUFFER_DATA (outbuffer);
+ res = gst_buffer_map (outbuffer, &size, NULL, GST_MAP_READ);
GST_INFO ("expected %+5d %+5d real %+5d %+5d", in[0], in[1], res[0], res[1]);
- fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 4) == 0);
+ fail_unless (memcmp (res, in, 4) == 0);
+ gst_buffer_unmap (outbuffer, res, size);
/* cleanup */
cleanup_volume (volume);
gint16 in[2] = { 16384, -256 };
gint16 out[2] = { 8192, -128 };
gint16 *res;
+ gsize size;
volume = setup_volume ();
g_object_set (G_OBJECT (volume), "volume", 0.5, NULL);
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (4);
- memcpy (GST_BUFFER_DATA (inbuffer), in, 4);
- fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 4) == 0);
+ gst_buffer_fill (inbuffer, 0, in, 4);
caps = gst_caps_from_string (VOLUME_CAPS_STRING_S16);
gst_buffer_set_caps (inbuffer, caps);
gst_caps_unref (caps);
fail_unless_equals_int (g_list_length (buffers), 1);
fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
fail_unless (inbuffer == outbuffer);
- res = (gint16 *) GST_BUFFER_DATA (outbuffer);
+ res = gst_buffer_map (outbuffer, &size, NULL, GST_MAP_READ);
GST_INFO ("expected %+5d %+5d real %+5d %+5d", out[0], out[1], res[0],
res[1]);
- fail_unless (memcmp (GST_BUFFER_DATA (outbuffer), out, 4) == 0);
+ fail_unless (memcmp (res, out, 4) == 0);
+ gst_buffer_unmap (outbuffer, res, size);
/* cleanup */
cleanup_volume (volume);
gint16 in[2] = { 16384, -256 };
gint16 out[2] = { 32767, -512 }; /* notice the clamped sample */
gint16 *res;
+ gsize size;
volume = setup_volume ();
g_object_set (G_OBJECT (volume), "volume", 2.0, NULL);
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (4);
- memcpy (GST_BUFFER_DATA (inbuffer), in, 4);
- fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 4) == 0);
+ gst_buffer_fill (inbuffer, 0, in, 4);
caps = gst_caps_from_string (VOLUME_CAPS_STRING_S16);
gst_buffer_set_caps (inbuffer, caps);
gst_caps_unref (caps);
fail_unless_equals_int (g_list_length (buffers), 1);
fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
fail_unless (inbuffer == outbuffer);
- res = (gint16 *) GST_BUFFER_DATA (outbuffer);
+ res = gst_buffer_map (outbuffer, &size, NULL, GST_MAP_READ);
GST_INFO ("expected %+5d %+5d real %+5d %+5d", out[0], out[1], res[0],
res[1]);
- fail_unless (memcmp (GST_BUFFER_DATA (outbuffer), out, 4) == 0);
+ fail_unless (memcmp (res, out, 4) == 0);
+ gst_buffer_unmap (outbuffer, res, size);
/* cleanup */
cleanup_volume (volume);
gint16 in[2] = { 16384, -256 };
gint16 out[2] = { 0, 0 };
gint16 *res;
+ gsize size;
volume = setup_volume ();
g_object_set (G_OBJECT (volume), "mute", TRUE, NULL);
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (4);
- memcpy (GST_BUFFER_DATA (inbuffer), in, 4);
- fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 4) == 0);
+ gst_buffer_fill (inbuffer, 0, in, 4);
caps = gst_caps_from_string (VOLUME_CAPS_STRING_S16);
gst_buffer_set_caps (inbuffer, caps);
gst_caps_unref (caps);
fail_unless_equals_int (g_list_length (buffers), 1);
fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
fail_unless (inbuffer == outbuffer);
- res = (gint16 *) GST_BUFFER_DATA (outbuffer);
+ res = gst_buffer_map (outbuffer, &size, NULL, GST_MAP_READ);
GST_INFO ("expected %+5d %+5d real %+5d %+5d", out[0], out[1], res[0],
res[1]);
- fail_unless (memcmp (GST_BUFFER_DATA (outbuffer), out, 4) == 0);
+ fail_unless (memcmp (res, out, 4) == 0);
+ gst_buffer_unmap (outbuffer, res, size);
/* cleanup */
cleanup_volume (volume);
guint8 in[6];
guint8 *res;
gint32 res_32[2];
-
+ gsize size;
write_unaligned_u24 (in, in_32[0]);
write_unaligned_u24 (in + 3, in_32[1]);
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (6);
- memcpy (GST_BUFFER_DATA (inbuffer), in, 6);
+ gst_buffer_fill (inbuffer, 0, in, 6);
caps = gst_caps_from_string (VOLUME_CAPS_STRING_S24);
gst_buffer_set_caps (inbuffer, caps);
gst_caps_unref (caps);
fail_unless_equals_int (g_list_length (buffers), 1);
fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
fail_unless (inbuffer == outbuffer);
- res = GST_BUFFER_DATA (outbuffer);
+ res = gst_buffer_map (outbuffer, &size, NULL, GST_MAP_READ);
res_32[0] = get_unaligned_i24 (res);
res_32[1] = get_unaligned_i24 ((res + 3));
GST_INFO ("expected %+5d %+5d real %+5d %+5d", in_32[0], in_32[1], res_32[0],
res_32[1]);
- fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 6) == 0);
+ fail_unless (memcmp (res, in, 6) == 0);
+ gst_buffer_unmap (outbuffer, res, size);
/* cleanup */
cleanup_volume (volume);
guint8 *res;
gint32 res_32[2];
gint32 out_32[2] = { 2097152, -2048 };
+ gsize size;
write_unaligned_u24 (in, in_32[0]);
write_unaligned_u24 (in + 3, in_32[1]);
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (6);
- memcpy (GST_BUFFER_DATA (inbuffer), in, 6);
- fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 6) == 0);
+ gst_buffer_fill (inbuffer, 0, in, 6);
caps = gst_caps_from_string (VOLUME_CAPS_STRING_S24);
gst_buffer_set_caps (inbuffer, caps);
gst_caps_unref (caps);
fail_unless_equals_int (g_list_length (buffers), 1);
fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
fail_unless (inbuffer == outbuffer);
- res = GST_BUFFER_DATA (outbuffer);
+ res = gst_buffer_map (outbuffer, &size, NULL, GST_MAP_READ);
res_32[0] = get_unaligned_i24 (res);
res_32[1] = get_unaligned_i24 ((res + 3));
GST_INFO ("expected %+5d %+5d real %+5d %+5d", out_32[0], out_32[1],
res_32[0], res_32[1]);
fail_unless (memcmp (res_32, out_32, 8) == 0);
+ gst_buffer_unmap (outbuffer, res, size);
/* cleanup */
cleanup_volume (volume);
guint8 *res;
gint32 res_32[2];
gint32 out_32[2] = { 8388607, -8192 }; /* notice the clamped sample */
+ gsize size;
write_unaligned_u24 (in, in_32[0]);
write_unaligned_u24 (in + 3, in_32[1]);
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (6);
- memcpy (GST_BUFFER_DATA (inbuffer), in, 6);
- fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 6) == 0);
+ gst_buffer_fill (inbuffer, 0, in, 6);
caps = gst_caps_from_string (VOLUME_CAPS_STRING_S24);
gst_buffer_set_caps (inbuffer, caps);
gst_caps_unref (caps);
fail_unless_equals_int (g_list_length (buffers), 1);
fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
fail_unless (inbuffer == outbuffer);
- res = GST_BUFFER_DATA (outbuffer);
+ res = gst_buffer_map (outbuffer, &size, NULL, GST_MAP_READ);
res_32[0] = get_unaligned_i24 (res);
res_32[1] = get_unaligned_i24 ((res + 3));
GST_INFO ("expected %+5d %+5d real %+5d %+5d", out_32[0], out_32[1],
res_32[0], res_32[1]);
fail_unless (memcmp (res_32, out_32, 8) == 0);
+ gst_buffer_unmap (outbuffer, res, size);
/* cleanup */
cleanup_volume (volume);
guint8 *res;
gint32 res_32[2];
gint32 out_32[2] = { 0, 0 }; /* notice the clamped sample */
+ gsize size;
write_unaligned_u24 (in, in_32[0]);
write_unaligned_u24 (in + 3, in_32[1]);
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (6);
- memcpy (GST_BUFFER_DATA (inbuffer), in, 6);
- fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 6) == 0);
+ gst_buffer_fill (inbuffer, 0, in, 6);
caps = gst_caps_from_string (VOLUME_CAPS_STRING_S24);
gst_buffer_set_caps (inbuffer, caps);
gst_caps_unref (caps);
fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
fail_unless (inbuffer == outbuffer);
- res = GST_BUFFER_DATA (outbuffer);
+ res = gst_buffer_map (outbuffer, &size, NULL, GST_MAP_READ);
res_32[0] = get_unaligned_i24 (res);
res_32[1] = get_unaligned_i24 ((res + 3));
GST_INFO ("expected %+5d %+5d real %+5d %+5d", out_32[0], out_32[1],
res_32[0], res_32[1]);
fail_unless (memcmp (res_32, out_32, 8) == 0);
+ gst_buffer_unmap (outbuffer, res, size);
/* cleanup */
cleanup_volume (volume);
GstCaps *caps;
gint32 in[2] = { 1073741824, -65536 };
gint32 *res;
+ gsize size;
volume = setup_volume ();
fail_unless (gst_element_set_state (volume,
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (8);
- memcpy (GST_BUFFER_DATA (inbuffer), in, 8);
+ gst_buffer_fill (inbuffer, 0, in, 8);
caps = gst_caps_from_string (VOLUME_CAPS_STRING_S32);
gst_buffer_set_caps (inbuffer, caps);
gst_caps_unref (caps);
fail_unless_equals_int (g_list_length (buffers), 1);
fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
fail_unless (inbuffer == outbuffer);
- res = (gint32 *) GST_BUFFER_DATA (outbuffer);
+ res = gst_buffer_map (outbuffer, &size, NULL, GST_MAP_READ);
GST_INFO ("expected %+5d %+5d real %+5d %+5d", in[0], in[1], res[0], res[1]);
- fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 8) == 0);
+ fail_unless (memcmp (res, in, 8) == 0);
+ gst_buffer_unmap (outbuffer, res, size);
/* cleanup */
cleanup_volume (volume);
gint32 in[2] = { 1073741824, -65536 };
gint32 out[2] = { 536870912, -32768 };
gint32 *res;
+ gsize size;
volume = setup_volume ();
g_object_set (G_OBJECT (volume), "volume", 0.5, NULL);
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (8);
- memcpy (GST_BUFFER_DATA (inbuffer), in, 8);
- fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 8) == 0);
+ gst_buffer_fill (inbuffer, 0, in, 8);
caps = gst_caps_from_string (VOLUME_CAPS_STRING_S32);
gst_buffer_set_caps (inbuffer, caps);
gst_caps_unref (caps);
fail_unless_equals_int (g_list_length (buffers), 1);
fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
fail_unless (inbuffer == outbuffer);
- res = (gint32 *) GST_BUFFER_DATA (outbuffer);
+ res = gst_buffer_map (outbuffer, &size, NULL, GST_MAP_READ);
GST_INFO ("expected %+5d %+5d real %+5d %+5d", out[0], out[1], res[0],
res[1]);
- fail_unless (memcmp (GST_BUFFER_DATA (outbuffer), out, 8) == 0);
+ fail_unless (memcmp (res, out, 8) == 0);
+ gst_buffer_unmap (outbuffer, res, size);
/* cleanup */
cleanup_volume (volume);
gint32 in[2] = { 1073741824, -65536 };
gint32 out[2] = { 2147483647, -131072 }; /* notice the clamped sample */
gint32 *res;
+ gsize size;
volume = setup_volume ();
g_object_set (G_OBJECT (volume), "volume", 2.0, NULL);
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (8);
- memcpy (GST_BUFFER_DATA (inbuffer), in, 8);
- fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 8) == 0);
+ gst_buffer_fill (inbuffer, 0, in, 8);
caps = gst_caps_from_string (VOLUME_CAPS_STRING_S32);
gst_buffer_set_caps (inbuffer, caps);
gst_caps_unref (caps);
fail_unless_equals_int (g_list_length (buffers), 1);
fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
fail_unless (inbuffer == outbuffer);
- res = (gint32 *) GST_BUFFER_DATA (outbuffer);
+ res = gst_buffer_map (outbuffer, &size, NULL, GST_MAP_READ);
GST_INFO ("expected %+5d %+5d real %+5d %+5d", out[0], out[1], res[0],
res[1]);
- fail_unless (memcmp (GST_BUFFER_DATA (outbuffer), out, 8) == 0);
+ fail_unless (memcmp (res, out, 8) == 0);
+ gst_buffer_unmap (outbuffer, res, size);
/* cleanup */
cleanup_volume (volume);
gint32 in[2] = { 1073741824, -65536 };
gint32 out[2] = { 0, 0 };
gint32 *res;
+ gsize size;
volume = setup_volume ();
g_object_set (G_OBJECT (volume), "mute", TRUE, NULL);
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (8);
- memcpy (GST_BUFFER_DATA (inbuffer), in, 8);
- fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 8) == 0);
+ gst_buffer_fill (inbuffer, 0, in, 8);
caps = gst_caps_from_string (VOLUME_CAPS_STRING_S32);
gst_buffer_set_caps (inbuffer, caps);
gst_caps_unref (caps);
fail_unless_equals_int (g_list_length (buffers), 1);
fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
fail_unless (inbuffer == outbuffer);
- res = (gint32 *) GST_BUFFER_DATA (outbuffer);
+ res = gst_buffer_map (outbuffer, &size, NULL, GST_MAP_READ);
GST_INFO ("expected %+5d %+5d real %+5d %+5d", out[0], out[1], res[0],
res[1]);
- fail_unless (memcmp (GST_BUFFER_DATA (outbuffer), out, 8) == 0);
+ fail_unless (memcmp (res, out, 8) == 0);
+ gst_buffer_unmap (outbuffer, res, size);
/* cleanup */
cleanup_volume (volume);
GstCaps *caps;
gfloat in[2] = { 0.75, -0.25 };
gfloat *res;
+ gsize size;
volume = setup_volume ();
fail_unless (gst_element_set_state (volume,
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (8);
- memcpy (GST_BUFFER_DATA (inbuffer), in, 8);
+ gst_buffer_fill (inbuffer, 0, in, 8);
caps = gst_caps_from_string (VOLUME_CAPS_STRING_F32);
gst_buffer_set_caps (inbuffer, caps);
gst_caps_unref (caps);
fail_unless_equals_int (g_list_length (buffers), 1);
fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
fail_unless (inbuffer == outbuffer);
- res = (gfloat *) GST_BUFFER_DATA (outbuffer);
+ res = gst_buffer_map (outbuffer, &size, NULL, GST_MAP_READ);
GST_INFO ("expected %+1.4f %+1.4f real %+1.4f %+1.4f", in[0], in[1], res[0],
res[1]);
fail_unless_equals_float (res[0], in[0]);
gfloat in[2] = { 0.75, -0.25 };
gfloat out[2] = { 0.375, -0.125 };
gfloat *res;
+ gsize size;
volume = setup_volume ();
g_object_set (G_OBJECT (volume), "volume", 0.5, NULL);
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (8);
- memcpy (GST_BUFFER_DATA (inbuffer), in, 8);
- fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 8) == 0);
+ gst_buffer_fill (inbuffer, 0, in, 8);
caps = gst_caps_from_string (VOLUME_CAPS_STRING_F32);
gst_buffer_set_caps (inbuffer, caps);
gst_caps_unref (caps);
fail_unless_equals_int (g_list_length (buffers), 1);
fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
fail_unless (inbuffer == outbuffer);
- res = (gfloat *) GST_BUFFER_DATA (outbuffer);
+ res = gst_buffer_map (outbuffer, &size, NULL, GST_MAP_READ);
GST_INFO ("expected %+1.4f %+1.4f real %+1.4f %+1.4f", out[0], out[1],
res[0], res[1]);
fail_unless_equals_float (res[0], out[0]);
fail_unless_equals_float (res[1], out[1]);
+ gst_buffer_unmap (outbuffer, res, size);
/* cleanup */
cleanup_volume (volume);
gfloat in[2] = { 0.75, -0.25 };
gfloat out[2] = { 1.5, -0.5 }; /* nothing is clamped */
gfloat *res;
+ gsize size;
volume = setup_volume ();
g_object_set (G_OBJECT (volume), "volume", 2.0, NULL);
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (8);
- memcpy (GST_BUFFER_DATA (inbuffer), in, 8);
- fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 8) == 0);
+ gst_buffer_fill (inbuffer, 0, in, 8);
caps = gst_caps_from_string (VOLUME_CAPS_STRING_F32);
gst_buffer_set_caps (inbuffer, caps);
gst_caps_unref (caps);
fail_unless_equals_int (g_list_length (buffers), 1);
fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
fail_unless (inbuffer == outbuffer);
- res = (gfloat *) GST_BUFFER_DATA (outbuffer);
+ res = gst_buffer_map (outbuffer, &size, NULL, GST_MAP_READ);
GST_INFO ("expected %+1.4f %+1.4f real %+1.4f %+1.4f", out[0], out[1],
res[0], res[1]);
fail_unless_equals_float (res[0], out[0]);
fail_unless_equals_float (res[1], out[1]);
+ gst_buffer_unmap (outbuffer, res, size);
/* cleanup */
cleanup_volume (volume);
gfloat in[2] = { 0.75, -0.25 };
gfloat out[2] = { 0, 0 };
gfloat *res;
+ gsize size;
volume = setup_volume ();
g_object_set (G_OBJECT (volume), "mute", TRUE, NULL);
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (8);
- memcpy (GST_BUFFER_DATA (inbuffer), in, 8);
- fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 8) == 0);
+ gst_buffer_fill (inbuffer, 0, in, 8);
caps = gst_caps_from_string (VOLUME_CAPS_STRING_F32);
gst_buffer_set_caps (inbuffer, caps);
gst_caps_unref (caps);
fail_unless_equals_int (g_list_length (buffers), 1);
fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
fail_unless (inbuffer == outbuffer);
- res = (gfloat *) GST_BUFFER_DATA (outbuffer);
+ res = gst_buffer_map (outbuffer, &size, NULL, GST_MAP_READ);
GST_INFO ("expected %+1.4f %+1.4f real %+1.4f %+1.4f", out[0], out[1],
res[0], res[1]);
fail_unless_equals_float (res[0], out[0]);
fail_unless_equals_float (res[1], out[1]);
+ gst_buffer_unmap (outbuffer, res, size);
/* cleanup */
cleanup_volume (volume);
GstCaps *caps;
gdouble in[2] = { 0.75, -0.25 };
gdouble *res;
+ gsize size;
volume = setup_volume ();
fail_unless (gst_element_set_state (volume,
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (16);
- memcpy (GST_BUFFER_DATA (inbuffer), in, 16);
+ gst_buffer_fill (inbuffer, 0, in, 16);
caps = gst_caps_from_string (VOLUME_CAPS_STRING_F64);
gst_buffer_set_caps (inbuffer, caps);
gst_caps_unref (caps);
fail_unless_equals_int (g_list_length (buffers), 1);
fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
fail_unless (inbuffer == outbuffer);
- res = (gdouble *) GST_BUFFER_DATA (outbuffer);
+ res = gst_buffer_map (outbuffer, &size, NULL, GST_MAP_READ);
GST_INFO ("expected %+1.4f %+1.4f real %+1.4f %+1.4f", in[0], in[1], res[0],
res[1]);
fail_unless_equals_float (res[0], in[0]);
gdouble in[2] = { 0.75, -0.25 };
gdouble out[2] = { 0.375, -0.125 };
gdouble *res;
+ gsize size;
volume = setup_volume ();
g_object_set (G_OBJECT (volume), "volume", 0.5, NULL);
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (16);
- memcpy (GST_BUFFER_DATA (inbuffer), in, 16);
- fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 16) == 0);
+ gst_buffer_fill (inbuffer, 0, in, 16);
caps = gst_caps_from_string (VOLUME_CAPS_STRING_F64);
gst_buffer_set_caps (inbuffer, caps);
gst_caps_unref (caps);
fail_unless_equals_int (g_list_length (buffers), 1);
fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
fail_unless (inbuffer == outbuffer);
- res = (gdouble *) GST_BUFFER_DATA (outbuffer);
+ res = gst_buffer_map (outbuffer, &size, NULL, GST_MAP_READ);
GST_INFO ("expected %+1.4f %+1.4f real %+1.4f %+1.4f", out[0], out[1],
res[0], res[1]);
fail_unless_equals_float (res[0], out[0]);
fail_unless_equals_float (res[1], out[1]);
+ gst_buffer_unmap (outbuffer, res, size);
/* cleanup */
cleanup_volume (volume);
gdouble in[2] = { 0.75, -0.25 };
gdouble out[2] = { 1.5, -0.5 }; /* nothing is clamped */
gdouble *res;
+ gsize size;
volume = setup_volume ();
g_object_set (G_OBJECT (volume), "volume", 2.0, NULL);
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (16);
- memcpy (GST_BUFFER_DATA (inbuffer), in, 16);
- fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 16) == 0);
+ gst_buffer_fill (inbuffer, 0, in, 16);
caps = gst_caps_from_string (VOLUME_CAPS_STRING_F64);
gst_buffer_set_caps (inbuffer, caps);
gst_caps_unref (caps);
fail_unless_equals_int (g_list_length (buffers), 1);
fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
fail_unless (inbuffer == outbuffer);
- res = (gdouble *) GST_BUFFER_DATA (outbuffer);
+ res = gst_buffer_map (outbuffer, &size, NULL, GST_MAP_READ);
GST_INFO ("expected %+1.4f %+1.4f real %+1.4f %+1.4f", out[0], out[1],
res[0], res[1]);
fail_unless_equals_float (res[0], out[0]);
fail_unless_equals_float (res[1], out[1]);
+ gst_buffer_unmap (outbuffer, res, size);
/* cleanup */
cleanup_volume (volume);
gdouble in[2] = { 0.75, -0.25 };
gdouble out[2] = { 0, 0 };
gdouble *res;
+ gsize size;
volume = setup_volume ();
g_object_set (G_OBJECT (volume), "mute", TRUE, NULL);
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (16);
- memcpy (GST_BUFFER_DATA (inbuffer), in, 16);
- fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 16) == 0);
+ gst_buffer_fill (inbuffer, 0, in, 16);
caps = gst_caps_from_string (VOLUME_CAPS_STRING_F64);
gst_buffer_set_caps (inbuffer, caps);
gst_caps_unref (caps);
fail_unless_equals_int (g_list_length (buffers), 1);
fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
fail_unless (inbuffer == outbuffer);
- res = (gdouble *) GST_BUFFER_DATA (outbuffer);
+ res = gst_buffer_map (outbuffer, &size, NULL, GST_MAP_READ);
GST_INFO ("expected %+1.4f %+1.4f real %+1.4f %+1.4f", out[0], out[1],
res[0], res[1]);
fail_unless_equals_float (res[0], out[0]);
fail_unless_equals_float (res[1], out[1]);
+ gst_buffer_unmap (outbuffer, res, size);
/* cleanup */
cleanup_volume (volume);
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (4);
- memcpy (GST_BUFFER_DATA (inbuffer), in, 4);
+ gst_buffer_fill (inbuffer, 0, in, 4);
caps = gst_caps_from_string (VOLUME_WRONG_CAPS_STRING);
gst_buffer_set_caps (inbuffer, caps);
gst_caps_unref (caps);
GstCaps *caps;
gint16 in[2] = { 16384, -256 };
gint16 *res;
+ gsize size;
volume = setup_volume ();
g_object_set (G_OBJECT (volume), "volume", 1.0, NULL);
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (4);
- memcpy (GST_BUFFER_DATA (inbuffer), in, 4);
+ gst_buffer_fill (inbuffer, 0, in, 4);
caps = gst_caps_from_string (VOLUME_CAPS_STRING_S16);
gst_buffer_set_caps (inbuffer, caps);
gst_caps_unref (caps);
fail_unless_equals_int (g_list_length (buffers), 1);
fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
fail_unless (inbuffer == outbuffer);
- res = (gint16 *) GST_BUFFER_DATA (outbuffer);
+ res = gst_buffer_map (outbuffer, &size, NULL, GST_MAP_READ);
GST_INFO ("expected %+5d %+5d real %+5d %+5d", in[0], in[1], res[0], res[1]);
- fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 4) == 0);
+ fail_unless (memcmp (res, in, 4) == 0);
+ gst_buffer_unmap (outbuffer, res, size);
/* cleanup */
cleanup_volume (volume);
GstCaps *caps;
gint16 in[2] = { 16384, -256 };
gint16 *res;
+ gsize size;
volume = setup_volume ();
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (4);
- memcpy (GST_BUFFER_DATA (inbuffer), in, 4);
+ gst_buffer_fill (inbuffer, 0, in, 4);
caps = gst_caps_from_string (VOLUME_CAPS_STRING_S16);
gst_buffer_set_caps (inbuffer, caps);
GST_BUFFER_TIMESTAMP (inbuffer) = 0;
fail_unless_equals_int (g_list_length (buffers), 1);
fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL);
fail_unless (inbuffer == outbuffer);
- res = (gint16 *) GST_BUFFER_DATA (outbuffer);
+ res = gst_buffer_map (outbuffer, &size, NULL, GST_MAP_READ);
GST_INFO ("expected %+5d %+5d real %+5d %+5d", in[0], in[1], res[0], res[1]);
- fail_unless (memcmp (GST_BUFFER_DATA (inbuffer), in, 4) == 0);
+ fail_unless (memcmp (res, in, 4) == 0);
+ gst_buffer_unmap (outbuffer, res, size);
g_object_unref (c);
bus = gst_bus_new ();
inbuffer = gst_buffer_new_and_alloc (30);
- memcpy (GST_BUFFER_DATA (inbuffer), identification_header, 30);
+ gst_buffer_fill (inbuffer, 0, identification_header, 30);
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
gst_buffer_ref (inbuffer);
fail_if ((message = gst_bus_pop (bus)) != NULL);
inbuffer = gst_buffer_new_and_alloc (sizeof (comment_header));
- memcpy (GST_BUFFER_DATA (inbuffer), comment_header, sizeof (comment_header));
+ gst_buffer_fill (inbuffer, 0, comment_header, sizeof (comment_header));
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
gst_buffer_ref (inbuffer);
vorbis_analysis_headerout (&vd, &vc, &header, &header_comm, &header_code);
buffer = gst_buffer_new_and_alloc (header_code.bytes);
- memcpy (GST_BUFFER_DATA (buffer), header_code.packet, header_code.bytes);
+ gst_buffer_fill (buffer, 0, header_code.packet, header_code.bytes);
return buffer;
}
vorbis_bitrate_addblock (&vb);
vorbis_bitrate_flushpacket (&vd, &packet);
buffer = gst_buffer_new_and_alloc (packet.bytes);
- memcpy (GST_BUFFER_DATA (buffer), packet.packet, packet.bytes);
+ gst_buffer_fill (buffer, 0, packet.packet, packet.bytes);
vorbis_comment_clear (&vc);
vorbis_block_clear (&vb);
bus = gst_bus_new ();
inbuffer = gst_buffer_new_and_alloc (30);
- memcpy (GST_BUFFER_DATA (inbuffer), identification_header, 30);
+ gst_buffer_fill (inbuffer, 0, identification_header, 30);
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
gst_buffer_ref (inbuffer);
fail_if ((message = gst_bus_pop (bus)) != NULL);
inbuffer = gst_buffer_new_and_alloc (sizeof (comment_header));
- memcpy (GST_BUFFER_DATA (inbuffer), comment_header, sizeof (comment_header));
+ gst_buffer_fill (inbuffer, 0, comment_header, sizeof (comment_header));
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
gst_buffer_ref (inbuffer);
pending_buffers = NULL;
}
+static void
+compare_buffer (GstBuffer * buf, const guint8 * data, gsize size)
+{
+ guint8 *bdata;
+ gsize bsize;
+
+ bdata = gst_buffer_map (buf, &bsize, NULL, GST_MAP_READ);
+ fail_unless_equals_int (bsize, size);
+ fail_unless_equals_int (memcmp (bdata, data, size), 0);
+ gst_buffer_unmap (buf, bdata, bsize);
+}
+
static vorbis_comment vc;
static vorbis_dsp_state vd;
static vorbis_info vi;
vorbis_analysis_headerout (&vd, &vc, &header, &header_comm, &header_code);
buffer = gst_buffer_new_and_alloc (header_code.bytes);
- memcpy (GST_BUFFER_DATA (buffer), header_code.packet, header_code.bytes);
+ gst_buffer_fill (buffer, 0, header_code.packet, header_code.bytes);
return buffer;
}
vorbis_bitrate_addblock (&vb);
vorbis_bitrate_flushpacket (&vd, &packet);
buffer = gst_buffer_new_and_alloc (packet.bytes);
- memcpy (GST_BUFFER_DATA (buffer), packet.packet, packet.bytes);
+ gst_buffer_fill (buffer, 0, packet.packet, packet.bytes);
vorbis_comment_clear (&vc);
vorbis_block_clear (&vb);
/* send identification header */
inbuffer = gst_buffer_new_and_alloc (sizeof (identification_header));
- memcpy (GST_BUFFER_DATA (inbuffer), identification_header,
+ gst_buffer_fill (inbuffer, 0, identification_header,
sizeof (identification_header));
fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK);
/* send empty comment buffer */
inbuffer = gst_buffer_new_and_alloc (sizeof (empty_comment_header));
- memcpy (GST_BUFFER_DATA (inbuffer), empty_comment_header,
+ gst_buffer_fill (inbuffer, 0, empty_comment_header,
sizeof (empty_comment_header));
fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK);
/* check identification header is unchanged */
outbuffer = get_buffer ();
- fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer),
+ compare_buffer (outbuffer, identification_header,
sizeof (identification_header));
- fail_unless_equals_int (memcmp (GST_BUFFER_DATA (outbuffer),
- identification_header, sizeof (identification_header)), 0);
gst_buffer_unref (outbuffer);
/* check comment header is correct */
outbuffer = get_buffer ();
- fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer),
+ compare_buffer (outbuffer, title_comment_header,
sizeof (title_comment_header));
- fail_unless_equals_int (memcmp (GST_BUFFER_DATA (outbuffer),
- title_comment_header, sizeof (title_comment_header)), 0);
gst_buffer_unref (outbuffer);
stop_pipeline (vorbistag);
/* send identification header */
inbuffer = gst_buffer_new_and_alloc (sizeof (identification_header));
- memcpy (GST_BUFFER_DATA (inbuffer), identification_header,
+ gst_buffer_fill (inbuffer, 0, identification_header,
sizeof (identification_header));
fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK);
/* send empty comment buffer */
inbuffer = gst_buffer_new_and_alloc (sizeof (title_comment_header));
- memcpy (GST_BUFFER_DATA (inbuffer), title_comment_header,
+ gst_buffer_fill (inbuffer, 0, title_comment_header,
sizeof (title_comment_header));
fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK);
/* check identification header is unchanged */
outbuffer = get_buffer ();
- fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer),
+ compare_buffer (outbuffer, identification_header,
sizeof (identification_header));
- fail_unless_equals_int (memcmp (GST_BUFFER_DATA (outbuffer),
- identification_header, sizeof (identification_header)), 0);
gst_buffer_unref (outbuffer);
/* check comment header is correct */
outbuffer = get_buffer ();
- fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer),
+ compare_buffer (outbuffer, empty_comment_header,
sizeof (empty_comment_header));
- fail_unless_equals_int (memcmp (GST_BUFFER_DATA (outbuffer),
- empty_comment_header, sizeof (empty_comment_header)), 0);
gst_buffer_unref (outbuffer);
stop_pipeline (vorbistag);
/* send identification header */
inbuffer = gst_buffer_new_and_alloc (sizeof (identification_header));
- memcpy (GST_BUFFER_DATA (inbuffer), identification_header,
+ gst_buffer_fill (inbuffer, 0, identification_header,
sizeof (identification_header));
fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK);
/* send empty comment buffer */
inbuffer = gst_buffer_new_and_alloc (sizeof (artist_comment_header));
- memcpy (GST_BUFFER_DATA (inbuffer), artist_comment_header,
+ gst_buffer_fill (inbuffer, 0, artist_comment_header,
sizeof (artist_comment_header));
fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), GST_FLOW_OK);
/* check identification header is unchanged */
outbuffer = get_buffer ();
- fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer),
+ compare_buffer (outbuffer, identification_header,
sizeof (identification_header));
- fail_unless_equals_int (memcmp (GST_BUFFER_DATA (outbuffer),
- identification_header, sizeof (identification_header)), 0);
gst_buffer_unref (outbuffer);
/* check comment header is correct */
outbuffer = get_buffer ();
- fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer),
+ compare_buffer (outbuffer, title_comment_header,
sizeof (title_comment_header));
- fail_unless_equals_int (memcmp (GST_BUFFER_DATA (outbuffer),
- title_comment_header, sizeof (title_comment_header)), 0);
gst_buffer_unref (outbuffer);
stop_pipeline (vorbistag);
GstCaps *caps = NULL;
buf = gst_buffer_new ();
- GST_BUFFER_DATA (buf) = (guint8 *) qt_redirect_396042;
- GST_BUFFER_SIZE (buf) = sizeof (qt_redirect_396042);
+ gst_buffer_take_memory (buf,
+ gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
+ (gpointer) qt_redirect_396042, NULL,
+ sizeof (qt_redirect_396042), 0, sizeof (qt_redirect_396042)));
+
GST_BUFFER_OFFSET (buf) = 0;
caps = gst_type_find_helper_for_buffer (NULL, buf, &prob);
GstCaps *caps = NULL;
buf = gst_buffer_new ();
- GST_BUFFER_DATA (buf) = (guint8 *) flac_id_packet;
- GST_BUFFER_SIZE (buf) = sizeof (flac_id_packet);
+ gst_buffer_take_memory (buf,
+ gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
+ (gpointer) flac_id_packet, NULL,
+ sizeof (flac_id_packet), 0, sizeof (flac_id_packet)));
+
GST_BUFFER_OFFSET (buf) = 0;
caps = gst_type_find_helper_for_buffer (NULL, buf, &prob);
}
buf = gst_buffer_new ();
- GST_BUFFER_DATA (buf) = (guint8 *) data;
- GST_BUFFER_SIZE (buf) = data_len;
+ gst_buffer_take_memory (buf,
+ gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
+ (gpointer) data, NULL, data_len, 0, data_len));
+
GST_BUFFER_OFFSET (buf) = 0;
caps = gst_type_find_helper_for_buffer (NULL, buf, NULL);
GstBuffer *buf;
GstCaps *caps = NULL;
guint bsid;
+ guint8 *data;
for (bsid = 0; bsid < 32; bsid++) {
buf = gst_buffer_new_and_alloc ((256 + 640) * 2);
- make_ac3_packet (GST_BUFFER_DATA (buf), 256 * 2, bsid);
- make_ac3_packet (GST_BUFFER_DATA (buf) + 256 * 2, 640 * 2, bsid);
+ data = gst_buffer_map (buf, NULL, NULL, GST_MAP_WRITE);
+ make_ac3_packet (data, 256 * 2, bsid);
+ make_ac3_packet (data + 256 * 2, 640 * 2, bsid);
+ gst_buffer_unmap (buf, data, (256 + 640) * 2);
caps = gst_type_find_helper_for_buffer (NULL, buf, &prob);
if (bsid <= 8) {
GstBuffer *buf;
GstCaps *caps = NULL;
guint bsid;
+ guint8 *data;
for (bsid = 0; bsid <= 32; bsid++) {
buf = gst_buffer_new_and_alloc (558 + 384);
- make_eac3_packet (GST_BUFFER_DATA (buf), 558, bsid);
- make_eac3_packet (GST_BUFFER_DATA (buf) + 558, 384, bsid);
+ data = gst_buffer_map (buf, NULL, NULL, GST_MAP_WRITE);
+ make_eac3_packet (data, 558, bsid);
+ make_eac3_packet (data + 558, 384, bsid);
+ gst_buffer_unmap (buf, data, 558 + 384);
caps = gst_type_find_helper_for_buffer (NULL, buf, &prob);
if (bsid > 10 && bsid <= 16) {
data[i] = g_random_int () & 0xff;
buf = gst_buffer_new ();
- GST_BUFFER_DATA (buf) = (guint8 *) data;
- GST_BUFFER_SIZE (buf) = TEST_RANDOM_DATA_SIZE;
+ gst_buffer_take_memory (buf,
+ gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
+ data, NULL, TEST_RANDOM_DATA_SIZE, 0, TEST_RANDOM_DATA_SIZE));
+
GST_BUFFER_OFFSET (buf) = 0;
caps = gst_type_find_helper_for_buffer (NULL, buf, &prob);
GST_START_TEST (test_buffer_clipping_time)
{
GstSegment s;
-
GstBuffer *buf;
-
GstBuffer *ret;
-
- guint8 *data;
+ guint8 *data, *sdata;
+ gsize ssize;
/* Clip start and end */
buf = gst_buffer_new ();
data = (guint8 *) g_malloc (1000);
- GST_BUFFER_SIZE (buf) = 1000;
- GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = data;
+ gst_buffer_take_memory (buf,
+ gst_memory_new_wrapped (0, data, g_free, 1000, 0, 1000));
gst_segment_init (&s, GST_FORMAT_TIME);
gst_segment_set_newsegment (&s, FALSE, 1.0, GST_FORMAT_TIME, 4 * GST_SECOND,
fail_unless (GST_BUFFER_DURATION (ret) == 4 * GST_SECOND);
fail_unless (GST_BUFFER_OFFSET (ret) == 400);
fail_unless (GST_BUFFER_OFFSET_END (ret) == 800);
- fail_unless (GST_BUFFER_DATA (ret) == data + 200);
- fail_unless (GST_BUFFER_SIZE (ret) == 400);
+ sdata = gst_buffer_map (ret, &ssize, NULL, GST_MAP_READ);
+ fail_unless (sdata == data + 200);
+ fail_unless (ssize == 400);
+ gst_buffer_unmap (ret, sdata, ssize);
gst_buffer_unref (ret);
/* Clip only start */
buf = gst_buffer_new ();
data = (guint8 *) g_malloc (1000);
- GST_BUFFER_SIZE (buf) = 1000;
- GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = data;
+ gst_buffer_take_memory (buf,
+ gst_memory_new_wrapped (0, data, g_free, 1000, 0, 1000));
gst_segment_init (&s, GST_FORMAT_TIME);
gst_segment_set_newsegment (&s, FALSE, 1.0, GST_FORMAT_TIME, 4 * GST_SECOND,
fail_unless (GST_BUFFER_DURATION (ret) == 8 * GST_SECOND);
fail_unless (GST_BUFFER_OFFSET (ret) == 400);
fail_unless (GST_BUFFER_OFFSET_END (ret) == 1200);
- fail_unless (GST_BUFFER_DATA (ret) == data + 200);
- fail_unless (GST_BUFFER_SIZE (ret) == 800);
+ sdata = gst_buffer_map (ret, &ssize, NULL, GST_MAP_READ);
+ fail_unless (sdata == data + 200);
+ fail_unless (ssize == 800);
+ gst_buffer_unmap (ret, sdata, ssize);
gst_buffer_unref (ret);
/* Clip only stop */
buf = gst_buffer_new ();
data = (guint8 *) g_malloc (1000);
- GST_BUFFER_SIZE (buf) = 1000;
- GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = data;
+ gst_buffer_take_memory (buf,
+ gst_memory_new_wrapped (0, data, g_free, 1000, 0, 1000));
gst_segment_init (&s, GST_FORMAT_TIME);
gst_segment_set_newsegment (&s, FALSE, 1.0, GST_FORMAT_TIME, 2 * GST_SECOND,
fail_unless (GST_BUFFER_DURATION (ret) == 8 * GST_SECOND);
fail_unless (GST_BUFFER_OFFSET (ret) == 200);
fail_unless (GST_BUFFER_OFFSET_END (ret) == 1000);
- fail_unless (GST_BUFFER_DATA (ret) == data);
- fail_unless (GST_BUFFER_SIZE (ret) == 800);
+ sdata = gst_buffer_map (ret, &ssize, NULL, GST_MAP_READ);
+ fail_unless (sdata == data);
+ fail_unless (ssize == 800);
+ gst_buffer_unmap (ret, sdata, ssize);
gst_buffer_unref (ret);
/* Buffer outside segment */
buf = gst_buffer_new ();
data = (guint8 *) g_malloc (1000);
- GST_BUFFER_SIZE (buf) = 1000;
- GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = data;
+ gst_buffer_take_memory (buf,
+ gst_memory_new_wrapped (0, data, g_free, 1000, 0, 1000));
gst_segment_init (&s, GST_FORMAT_TIME);
gst_segment_set_newsegment (&s, FALSE, 1.0, GST_FORMAT_TIME, 12 * GST_SECOND,
/* Clip start and end but don't touch duration and offset_end */
buf = gst_buffer_new ();
data = (guint8 *) g_malloc (1000);
- GST_BUFFER_SIZE (buf) = 1000;
- GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = data;
+ gst_buffer_take_memory (buf,
+ gst_memory_new_wrapped (0, data, g_free, 1000, 0, 1000));
gst_segment_init (&s, GST_FORMAT_TIME);
gst_segment_set_newsegment (&s, FALSE, 1.0, GST_FORMAT_TIME, 4 * GST_SECOND,
fail_unless (GST_BUFFER_DURATION (ret) == GST_CLOCK_TIME_NONE);
fail_unless (GST_BUFFER_OFFSET (ret) == 400);
fail_unless (GST_BUFFER_OFFSET_END (ret) == GST_BUFFER_OFFSET_NONE);
- fail_unless (GST_BUFFER_DATA (ret) == data + 200);
- fail_unless (GST_BUFFER_SIZE (ret) == 400);
+ sdata = gst_buffer_map (ret, &ssize, NULL, GST_MAP_READ);
+ fail_unless (sdata == data + 200);
+ fail_unless (ssize == 400);
+ gst_buffer_unmap (ret, sdata, ssize);
gst_buffer_unref (ret);
*/
buf = gst_buffer_new ();
data = (guint8 *) g_malloc (1000);
- GST_BUFFER_SIZE (buf) = 1000;
- GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = data;
+ gst_buffer_take_memory (buf,
+ gst_memory_new_wrapped (0, data, g_free, 1000, 0, 1000));
gst_segment_init (&s, GST_FORMAT_TIME);
gst_segment_set_newsegment (&s, FALSE, 1.0, GST_FORMAT_TIME, 0 * GST_SECOND,
*/
buf = gst_buffer_new ();
data = (guint8 *) g_malloc (1000);
- GST_BUFFER_SIZE (buf) = 1000;
- GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = data;
+ gst_buffer_take_memory (buf,
+ gst_memory_new_wrapped (0, data, g_free, 1000, 0, 1000));
gst_segment_init (&s, GST_FORMAT_PERCENT);
gst_segment_set_newsegment (&s, FALSE, 1.0, GST_FORMAT_PERCENT, 0, 10, 0);
GST_START_TEST (test_buffer_clipping_samples)
{
GstSegment s;
-
GstBuffer *buf;
-
GstBuffer *ret;
-
- guint8 *data;
+ guint8 *data, *sdata;
+ gsize ssize;
/* Clip start and end */
buf = gst_buffer_new ();
data = (guint8 *) g_malloc (1000);
- GST_BUFFER_SIZE (buf) = 1000;
- GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = data;
+ gst_buffer_take_memory (buf,
+ gst_memory_new_wrapped (0, data, g_free, 1000, 0, 1000));
gst_segment_init (&s, GST_FORMAT_DEFAULT);
gst_segment_set_newsegment (&s, FALSE, 1.0, GST_FORMAT_DEFAULT, 400,
fail_unless (GST_BUFFER_DURATION (ret) == 4 * GST_SECOND);
fail_unless (GST_BUFFER_OFFSET (ret) == 400);
fail_unless (GST_BUFFER_OFFSET_END (ret) == 800);
- fail_unless (GST_BUFFER_DATA (ret) == data + 200);
- fail_unless (GST_BUFFER_SIZE (ret) == 400);
+ sdata = gst_buffer_map (ret, &ssize, NULL, GST_MAP_READ);
+ fail_unless (sdata == data + 200);
+ fail_unless (ssize == 400);
+ gst_buffer_unmap (ret, sdata, ssize);
gst_buffer_unref (ret);
/* Clip only start */
buf = gst_buffer_new ();
data = (guint8 *) g_malloc (1000);
- GST_BUFFER_SIZE (buf) = 1000;
- GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = data;
+ gst_buffer_take_memory (buf,
+ gst_memory_new_wrapped (0, data, g_free, 1000, 0, 1000));
gst_segment_init (&s, GST_FORMAT_DEFAULT);
gst_segment_set_newsegment (&s, FALSE, 1.0, GST_FORMAT_DEFAULT, 400,
fail_unless (GST_BUFFER_DURATION (ret) == 8 * GST_SECOND);
fail_unless (GST_BUFFER_OFFSET (ret) == 400);
fail_unless (GST_BUFFER_OFFSET_END (ret) == 1200);
- fail_unless (GST_BUFFER_DATA (ret) == data + 200);
- fail_unless (GST_BUFFER_SIZE (ret) == 800);
+ sdata = gst_buffer_map (ret, &ssize, NULL, GST_MAP_READ);
+ fail_unless (sdata == data + 200);
+ fail_unless (ssize == 800);
+ gst_buffer_unmap (ret, sdata, ssize);
gst_buffer_unref (ret);
/* Clip only stop */
buf = gst_buffer_new ();
data = (guint8 *) g_malloc (1000);
- GST_BUFFER_SIZE (buf) = 1000;
- GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = data;
+ gst_buffer_take_memory (buf,
+ gst_memory_new_wrapped (0, data, g_free, 1000, 0, 1000));
gst_segment_init (&s, GST_FORMAT_DEFAULT);
gst_segment_set_newsegment (&s, FALSE, 1.0, GST_FORMAT_DEFAULT, 200,
fail_unless (GST_BUFFER_DURATION (ret) == 8 * GST_SECOND);
fail_unless (GST_BUFFER_OFFSET (ret) == 200);
fail_unless (GST_BUFFER_OFFSET_END (ret) == 1000);
- fail_unless (GST_BUFFER_DATA (ret) == data);
- fail_unless (GST_BUFFER_SIZE (ret) == 800);
+ sdata = gst_buffer_map (ret, &ssize, NULL, GST_MAP_READ);
+ fail_unless (sdata == data);
+ fail_unless (ssize == 800);
+ gst_buffer_unmap (ret, sdata, ssize);
gst_buffer_unref (ret);
/* Buffer outside segment */
buf = gst_buffer_new ();
data = (guint8 *) g_malloc (1000);
- GST_BUFFER_SIZE (buf) = 1000;
- GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = data;
+ gst_buffer_take_memory (buf,
+ gst_memory_new_wrapped (0, data, g_free, 1000, 0, 1000));
gst_segment_init (&s, GST_FORMAT_DEFAULT);
gst_segment_set_newsegment (&s, FALSE, 1.0, GST_FORMAT_DEFAULT, 1200,
/* Clip start and end but don't touch duration and offset_end */
buf = gst_buffer_new ();
data = (guint8 *) g_malloc (1000);
- GST_BUFFER_SIZE (buf) = 1000;
- GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = data;
+ gst_buffer_take_memory (buf,
+ gst_memory_new_wrapped (0, data, g_free, 1000, 0, 1000));
gst_segment_init (&s, GST_FORMAT_DEFAULT);
gst_segment_set_newsegment (&s, FALSE, 1.0, GST_FORMAT_DEFAULT, 400,
fail_unless (GST_BUFFER_DURATION (ret) == GST_CLOCK_TIME_NONE);
fail_unless (GST_BUFFER_OFFSET (ret) == 400);
fail_unless (GST_BUFFER_OFFSET_END (ret) == GST_BUFFER_OFFSET_NONE);
- fail_unless (GST_BUFFER_DATA (ret) == data + 200);
- fail_unless (GST_BUFFER_SIZE (ret) == 400);
+ sdata = gst_buffer_map (ret, &ssize, NULL, GST_MAP_READ);
+ fail_unless (sdata == data + 200);
+ fail_unless (ssize == 400);
+ gst_buffer_unmap (ret, sdata, ssize);
gst_buffer_unref (ret);
*/
buf = gst_buffer_new ();
data = (guint8 *) g_malloc (1000);
- GST_BUFFER_SIZE (buf) = 1000;
- GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = data;
+ gst_buffer_take_memory (buf,
+ gst_memory_new_wrapped (0, data, g_free, 1000, 0, 1000));
gst_segment_init (&s, GST_FORMAT_DEFAULT);
gst_segment_set_newsegment (&s, FALSE, 1.0, GST_FORMAT_DEFAULT, 0, 10, 0);
};
GType gst_cd_foo_src_get_type (void);
-GST_BOILERPLATE (GstCdFooSrc, gst_cd_foo_src, GstCddaBaseSrc,
- GST_TYPE_CDDA_BASE_SRC);
+G_DEFINE_TYPE (GstCdFooSrc, gst_cd_foo_src, GST_TYPE_CDDA_BASE_SRC);
static GstBuffer *gst_cd_foo_src_read_sector (GstCddaBaseSrc * src,
gint sector);
static void gst_cd_foo_src_close (GstCddaBaseSrc * src);
static void
-gst_cd_foo_src_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_set_details_simple (element_class,
- "CD Audio (cdda) Source, FooBar", "Source/File",
- "Read audio from CD", "Foo Bar <foo@bar.com>");
-}
-
-static void
-gst_cd_foo_src_init (GstCdFooSrc * src, GstCdFooSrcClass * klass)
+gst_cd_foo_src_init (GstCdFooSrc * src)
{
src->cur_disc = 0;
}
gst_cd_foo_src_class_init (GstCdFooSrcClass * klass)
{
GstCddaBaseSrcClass *cddabasesrc_class = GST_CDDA_BASE_SRC_CLASS (klass);
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+ gst_element_class_set_details_simple (element_class,
+ "CD Audio (cdda) Source, FooBar", "Source/File",
+ "Read audio from CD", "Foo Bar <foo@bar.com>");
cddabasesrc_class->open = gst_cd_foo_src_open;
cddabasesrc_class->close = gst_cd_foo_src_close;
gst_cd_foo_src_read_sector (GstCddaBaseSrc * cddabasesrc, gint sector)
{
GstBuffer *buf;
+ guint8 *data;
buf = gst_buffer_new_and_alloc (CD_FRAMESIZE_RAW);
- memset (GST_BUFFER_DATA (buf), 0, CD_FRAMESIZE_RAW);
+ data = gst_buffer_map (buf, NULL, NULL, GST_MAP_WRITE);
+ memset (data, 0, CD_FRAMESIZE_RAW);
+ gst_buffer_unmap (buf, data, CD_FRAMESIZE_RAW);
return buf;
}
#include <gst/gst.h>
#include <gst/check/gstcheck.h>
-#include <gst/app/gstappbuffer.h>
#include <gst/app/gstapp-marshal.h>
#include <gst/app/gstappsink.h>
#include <gst/app/gstappsrc.h>
#include <config.h>
#include <gst/check/gstcheck.h>
-#include <gst/app/gstappbuffer.h>
#include <gst/app/gstappsrc.h>
#include <gst/app/gstappsink.h>
#include <gst/audio/audio.h>
#endif
#endif
+/* disabled for 0.11 */
+#undef HAVE_ABI_SIZES
+#define HAVE_ABI_SIZES FALSE
+
GST_START_TEST (test_ABI)
{
gst_check_abi_list (list, HAVE_ABI_SIZES);
static void init_interface (GType type);
static void gst_implements_interface_init (GstImplementsInterfaceClass * klass);
-GST_BOILERPLATE_FULL (TestElement, test_element, GstElement, GST_TYPE_ELEMENT,
- init_interface);
+G_DEFINE_TYPE_WITH_CODE (TestElement, test_element, GST_TYPE_ELEMENT,
+ init_interface (g_define_type_id));
static void
test_element_mixer_interface_init (GstMixerClass * klass)
}
static void
-test_element_base_init (gpointer klass)
-{
-}
-
-static void
test_element_class_init (TestElementClass * klass)
{
}
}
static void
-test_element_init (TestElement * this, TestElementClass * klass)
+test_element_init (TestElement * this)
{
}
static void nav_send_event (GstNavigation * navigation,
GstStructure * structure);
-GST_BOILERPLATE_FULL (TestElement, test_element, GstElement, GST_TYPE_ELEMENT,
- init_interface);
+G_DEFINE_TYPE_WITH_CODE (TestElement, test_element, GST_TYPE_ELEMENT,
+ init_interface (g_define_type_id));
static void
test_element_navigation_interface_init (GstNavigationInterface * klass)
}
static void
-test_element_base_init (gpointer klass)
-{
-}
-
-static void
test_element_class_init (TestElementClass * klass)
{
}
}
static void
-test_element_init (TestElement * this, TestElementClass * klass)
+test_element_init (TestElement * this)
{
}
GST_START_TEST (test_netbuffer_copy)
{
- GstNetBuffer *netbuf, *copy;
+ GstBuffer *netbuf, *copy;
guint8 ipv6_addr[16] = { 0xff, 0x11, 0xee, 0x22, 0xdd, 0x33, 0xcc,
0x44, 0xbb, 0x55, 0xaa, 0x66, 0x00, 0x77, 0x99, 0x88
};
guint16 ipv6_port = 3490;
guint16 ipv4_port = 5678;
guint16 port;
+ GstMetaNetAddress *meta, *cmeta;
+ gsize len;
+ guint8 *data1, *data2;
+ gsize size1, size2;
- netbuf = gst_netbuffer_new ();
+ netbuf = gst_buffer_new ();
fail_unless (netbuf != NULL, "failed to create net buffer");
+ meta = gst_buffer_add_meta_net_address (netbuf);
- gst_netaddress_set_ip4_address (&netbuf->from, ipv4_addr, ipv4_port);
- gst_netaddress_set_ip6_address (&netbuf->to, ipv6_addr, ipv6_port);
+ gst_netaddress_set_ip4_address (&meta->naddr, ipv4_addr, ipv4_port);
+
+ len = strlen (DATA_STRING);
+ gst_buffer_take_memory (netbuf,
+ gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
+ (gpointer) DATA_STRING, NULL, len, 0, len));
- GST_BUFFER_DATA (netbuf) = (guint8 *) DATA_STRING;
- GST_BUFFER_SIZE (netbuf) = strlen (DATA_STRING);
GST_BUFFER_FLAG_SET (netbuf, GST_BUFFER_FLAG_DISCONT);
- GST_BUFFER_FLAG_SET (netbuf, GST_BUFFER_FLAG_READONLY);
- copy = (GstNetBuffer *) gst_buffer_copy (GST_BUFFER_CAST (netbuf));
+ copy = gst_buffer_copy (netbuf);
fail_unless (copy != NULL, "failed to copy net buffer");
- fail_unless (GST_IS_NETBUFFER (copy), "copied buffer is not a GstNetBuffer!");
+
+ cmeta = gst_buffer_get_meta_net_address (copy);
+ fail_unless (cmeta != NULL, "copied buffer is not a GstNetBuffer!");
fail_unless_equals_int (GST_MINI_OBJECT_REFCOUNT_VALUE (copy), 1);
- fail_unless_equals_int (GST_BUFFER_SIZE (copy), GST_BUFFER_SIZE (netbuf));
- fail_unless (memcmp (GST_BUFFER_DATA (copy), GST_BUFFER_DATA (netbuf),
- GST_BUFFER_SIZE (copy)) == 0);
+ data1 = gst_buffer_map (netbuf, &size1, NULL, GST_MAP_READ);
+ data2 = gst_buffer_map (copy, &size2, NULL, GST_MAP_READ);
+ fail_unless_equals_int (size1, size2);
+ fail_unless (memcmp (data1, data2, size1) == 0);
+ gst_buffer_unmap (copy, data2, size2);
+ gst_buffer_unmap (netbuf, data1, size1);
- fail_if (GST_BUFFER_FLAG_IS_SET (copy, GST_BUFFER_FLAG_READONLY));
fail_unless (GST_BUFFER_FLAG_IS_SET (copy, GST_BUFFER_FLAG_DISCONT));
- fail_unless (gst_netaddress_get_ip4_address (©->from, &ipv4_copy, &port));
+ fail_unless (gst_netaddress_get_ip4_address (&cmeta->naddr, &ipv4_copy,
+ &port));
fail_unless (ipv4_copy == ipv4_addr,
"Copied buffer has wrong IPV4 from address");
fail_unless (port == ipv4_port, "Copied buffer has wrong IPV4 from port");
+ gst_buffer_unref (netbuf);
+ gst_buffer_unref (copy);
+
+ netbuf = gst_buffer_new ();
+ fail_unless (netbuf != NULL, "failed to create net buffer");
+ meta = gst_buffer_add_meta_net_address (netbuf);
+
+ gst_netaddress_set_ip6_address (&meta->naddr, ipv6_addr, ipv6_port);
+
+ len = strlen (DATA_STRING);
+ gst_buffer_take_memory (netbuf,
+ gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
+ (gpointer) DATA_STRING, NULL, len, 0, len));
+
+ GST_BUFFER_FLAG_SET (netbuf, GST_BUFFER_FLAG_DISCONT);
+
+ copy = gst_buffer_copy (netbuf);
+ fail_unless (copy != NULL, "failed to copy net buffer");
+
+ cmeta = gst_buffer_get_meta_net_address (copy);
+ fail_unless (cmeta != NULL, "copied buffer is not a GstNetBuffer!");
+
+ fail_unless_equals_int (GST_MINI_OBJECT_REFCOUNT_VALUE (copy), 1);
+
+ data1 = gst_buffer_map (netbuf, &size1, NULL, GST_MAP_READ);
+ data2 = gst_buffer_map (copy, &size2, NULL, GST_MAP_READ);
+ fail_unless_equals_int (size1, size2);
+ fail_unless (memcmp (data1, data2, size1) == 0);
+ gst_buffer_unmap (copy, data2, size2);
+ gst_buffer_unmap (netbuf, data1, size1);
+
+ fail_unless (GST_BUFFER_FLAG_IS_SET (copy, GST_BUFFER_FLAG_DISCONT));
- fail_unless (gst_netaddress_get_ip6_address (©->to, ipv6_copy, &port));
+ fail_unless (gst_netaddress_get_ip6_address (&cmeta->naddr, ipv6_copy,
+ &port));
fail_unless (memcmp (ipv6_copy, ipv6_addr, 16) == 0,
"Copied buffer has wrong IPv6 destination address");
fail_unless (port == ipv6_port,
"Copied buffer has wrong IPv6 destination port");
+ gst_buffer_unref (netbuf);
+ gst_buffer_unref (copy);
- gst_buffer_unref (GST_BUFFER_CAST (netbuf));
- gst_buffer_unref (GST_BUFFER_CAST (copy));
}
GST_END_TEST;
/* uri source */
detail1 = gst_missing_uri_source_installer_detail_new ("http");
fail_unless (detail1 != NULL);
- fail_unless (g_str_has_prefix (detail1, "gstreamer|0.10|"));
+ fail_unless (g_str_has_prefix (detail1, "gstreamer|0.11|"));
fail_unless (g_str_has_suffix (detail1, "|urisource-http"));
msg = gst_missing_uri_source_message_new (el, "http");
fail_unless (msg != NULL);
/* uri sink */
detail1 = gst_missing_uri_sink_installer_detail_new ("http");
fail_unless (detail1 != NULL);
- fail_unless (g_str_has_prefix (detail1, "gstreamer|0.10|"));
+ fail_unless (g_str_has_prefix (detail1, "gstreamer|0.11|"));
fail_unless (g_str_has_suffix (detail1, "|urisink-http"));
msg = gst_missing_uri_sink_message_new (el, "http");
fail_unless (msg != NULL);
/* element */
detail1 = gst_missing_element_installer_detail_new ("deinterlace");
fail_unless (detail1 != NULL);
- fail_unless (g_str_has_prefix (detail1, "gstreamer|0.10|"));
+ fail_unless (g_str_has_prefix (detail1, "gstreamer|0.11|"));
fail_unless (g_str_has_suffix (detail1, "|element-deinterlace"));
msg = gst_missing_element_message_new (el, "deinterlace");
fail_unless (msg != NULL);
2, "channels", G_TYPE_INT, 6, NULL);
detail1 = gst_missing_decoder_installer_detail_new (caps);
fail_unless (detail1 != NULL);
- fail_unless (g_str_has_prefix (detail1, "gstreamer|0.10|"));
+ fail_unless (g_str_has_prefix (detail1, "gstreamer|0.11|"));
fail_unless (g_str_has_suffix (detail1,
"|decoder-audio/x-spiffy, spiffyversion=(int)2"));
msg = gst_missing_decoder_message_new (el, caps);
caps = gst_caps_new_simple ("audio/x-spiffy", "spiffyversion", G_TYPE_INT,
2, "channels", G_TYPE_INT, 6, NULL);
detail1 = gst_missing_encoder_installer_detail_new (caps);
- fail_unless (g_str_has_prefix (detail1, "gstreamer|0.10|"));
+ fail_unless (g_str_has_prefix (detail1, "gstreamer|0.11|"));
fail_unless (g_str_has_suffix (detail1,
"|encoder-audio/x-spiffy, spiffyversion=(int)2"));
fail_unless (detail1 != NULL);
fail_unless (gst_encoding_target_save (orig, NULL));
/* Check we can load it */
- profile_file_name = g_build_filename (g_get_home_dir (), ".gstreamer-0.10",
+ profile_file_name =
+ g_build_filename (g_get_user_data_dir (), "gstreamer-0.11",
"encoding-profiles", "herding", "myponytarget2.gep", NULL);
GST_DEBUG ("Loading target from '%s'", profile_file_name);
loaded = gst_encoding_target_load_from_file (profile_file_name, NULL);
GstEncodingProfile *profile;
GstCaps *tmpcaps;
GValue strvalue = { 0, };
- GValue miniobjectvalue = { 0, };
+ GValue objectvalue = { 0, };
/* Test loading using short method and all arguments */
target = gst_encoding_target_load ("myponytarget", "herding", NULL);
gst_encoding_target_unref (target);
/* Test loading using fully specified path */
- profile_file_name = g_build_filename (g_get_home_dir (), ".gstreamer-0.10",
+ profile_file_name =
+ g_build_filename (g_get_user_data_dir (), "gstreamer-0.11",
"encoding-profiles", "herding", "myponytarget.gep", NULL);
GST_DEBUG ("Loading target from '%s'", profile_file_name);
/* For my next trick, I will need the assistance of a GValue */
g_value_init (&strvalue, G_TYPE_STRING);
- g_value_init (&miniobjectvalue, GST_TYPE_ENCODING_PROFILE);
+ g_value_init (&objectvalue, GST_TYPE_ENCODING_PROFILE);
g_value_set_static_string (&strvalue, "myponytarget/pony");
- fail_unless (g_value_transform (&strvalue, &miniobjectvalue));
- profile = (GstEncodingProfile *) gst_value_dup_mini_object (&miniobjectvalue);
+ fail_unless (g_value_transform (&strvalue, &objectvalue));
+ profile = (GstEncodingProfile *) g_value_dup_object (&objectvalue);
fail_if (profile == NULL);
g_value_unset (&strvalue);
- g_value_unset (&miniobjectvalue);
+ g_value_unset (&objectvalue);
tmpcaps = gst_caps_from_string ("animal/x-pony");
CHECK_PROFILE (profile, "pony", "I don't want a description !", tmpcaps, NULL,
0, 0);
/* If tmp is NULL, it means we iterated the whole list without finding
* our target */
fail_if (tmp == NULL);
- g_list_foreach (targets, (GFunc) gst_mini_object_unref, NULL);
+ g_list_foreach (targets, (GFunc) g_object_unref, NULL);
g_list_free (targets);
/* Try getting all available targets without a specified category */
/* If tmp is NULL, it means we iterated the whole list without finding
* our target */
fail_if (tmp == NULL);
- g_list_foreach (targets, (GFunc) gst_mini_object_unref, NULL);
+ g_list_foreach (targets, (GFunc) g_object_unref, NULL);
g_list_free (targets);
}
{
gchar *profile_file_name;
- profile_file_name = g_build_filename (g_get_home_dir (), ".gstreamer-0.10",
+ profile_file_name =
+ g_build_filename (g_get_user_data_dir (), "gstreamer-0.11",
"encoding-profiles", "herding", "myponytarget.gep", NULL);
g_unlink (profile_file_name);
g_free (profile_file_name);
- profile_file_name = g_build_filename (g_get_home_dir (), ".gstreamer-0.10",
+ profile_file_name =
+ g_build_filename (g_get_user_data_dir (), "gstreamer-0.11",
"encoding-profiles", "herding", "myponytarget2.gep", NULL);
g_unlink (profile_file_name);
g_free (profile_file_name);
GError *error = NULL;
profile_dir =
- g_build_filename (g_get_home_dir (), ".gstreamer-0.10",
+ g_build_filename (g_get_user_data_dir (), "gstreamer-0.11",
"encoding-profiles", "herding", NULL);
profile_file_name =
- g_build_filename (g_get_home_dir (), ".gstreamer-0.10",
+ g_build_filename (g_get_user_data_dir (), "gstreamer-0.11",
"encoding-profiles", "herding", "myponytarget.gep", NULL);
g_mkdir_with_parents (profile_dir, S_IRUSR | S_IWUSR | S_IXUSR);
if (!g_file_set_contents (profile_file_name, profile_string,
gchar *gst_dir;
/* cehck if we can create profiles */
- gst_dir = g_build_filename (g_get_home_dir (), ".gstreamer-0.10", NULL);
+ gst_dir = g_build_filename (g_get_user_data_dir (), "gstreamer-0.11", NULL);
can_write = (g_access (gst_dir, R_OK | W_OK | X_OK) == 0);
g_free (gst_dir);
{
GstBuffer *buf;
guint8 *data;
+ gsize size;
+ GstRTPBuffer rtp = { NULL, };
/* check GstRTPHeader structure alignment and packing */
buf = gst_rtp_buffer_new_allocate (16, 4, 0);
fail_unless (buf != NULL);
- fail_unless_equals_int (GST_BUFFER_SIZE (buf), RTP_HEADER_LEN + 16 + 4);
- data = GST_BUFFER_DATA (buf);
+ data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
+ fail_unless_equals_int (size, RTP_HEADER_LEN + 16 + 4);
+
+ gst_rtp_buffer_map (buf, GST_MAP_READWRITE, &rtp);
/* check defaults */
- fail_unless_equals_int (gst_rtp_buffer_get_version (buf), 2);
- fail_unless (gst_rtp_buffer_get_padding (buf) == FALSE);
- fail_unless (gst_rtp_buffer_get_extension (buf) == FALSE);
- fail_unless_equals_int (gst_rtp_buffer_get_csrc_count (buf), 0);
- fail_unless (gst_rtp_buffer_get_marker (buf) == FALSE);
- fail_unless (gst_rtp_buffer_get_payload_type (buf) == 0);
+ fail_unless_equals_int (gst_rtp_buffer_get_version (&rtp), 2);
+ fail_unless (gst_rtp_buffer_get_padding (&rtp) == FALSE);
+ fail_unless (gst_rtp_buffer_get_extension (&rtp) == FALSE);
+ fail_unless_equals_int (gst_rtp_buffer_get_csrc_count (&rtp), 0);
+ fail_unless (gst_rtp_buffer_get_marker (&rtp) == FALSE);
+ fail_unless (gst_rtp_buffer_get_payload_type (&rtp) == 0);
fail_unless_equals_int (GST_READ_UINT16_BE (data), 0x8000);
/* check version in bitfield */
- gst_rtp_buffer_set_version (buf, 3);
- fail_unless_equals_int (gst_rtp_buffer_get_version (buf), 3);
+ gst_rtp_buffer_set_version (&rtp, 3);
+ fail_unless_equals_int (gst_rtp_buffer_get_version (&rtp), 3);
fail_unless_equals_int ((data[0] & 0xC0) >> 6, 3);
- gst_rtp_buffer_set_version (buf, 2);
- fail_unless_equals_int (gst_rtp_buffer_get_version (buf), 2);
+ gst_rtp_buffer_set_version (&rtp, 2);
+ fail_unless_equals_int (gst_rtp_buffer_get_version (&rtp), 2);
fail_unless_equals_int ((data[0] & 0xC0) >> 6, 2);
/* check padding bit */
- gst_rtp_buffer_set_padding (buf, TRUE);
- fail_unless (gst_rtp_buffer_get_padding (buf) == TRUE);
+ gst_rtp_buffer_set_padding (&rtp, TRUE);
+ fail_unless (gst_rtp_buffer_get_padding (&rtp) == TRUE);
fail_unless_equals_int ((data[0] & 0x20) >> 5, 1);
- gst_rtp_buffer_set_padding (buf, FALSE);
- fail_unless (gst_rtp_buffer_get_padding (buf) == FALSE);
+ gst_rtp_buffer_set_padding (&rtp, FALSE);
+ fail_unless (gst_rtp_buffer_get_padding (&rtp) == FALSE);
fail_unless_equals_int ((data[0] & 0x20) >> 5, 0);
/* check marker bit */
- gst_rtp_buffer_set_marker (buf, TRUE);
- fail_unless (gst_rtp_buffer_get_marker (buf) == TRUE);
+ gst_rtp_buffer_set_marker (&rtp, TRUE);
+ fail_unless (gst_rtp_buffer_get_marker (&rtp) == TRUE);
fail_unless_equals_int ((data[1] & 0x80) >> 7, 1);
- gst_rtp_buffer_set_marker (buf, FALSE);
- fail_unless (gst_rtp_buffer_get_marker (buf) == FALSE);
+ gst_rtp_buffer_set_marker (&rtp, FALSE);
+ fail_unless (gst_rtp_buffer_get_marker (&rtp) == FALSE);
fail_unless_equals_int ((data[1] & 0x80) >> 7, 0);
/* check sequence offset */
- gst_rtp_buffer_set_seq (buf, 0xF2C9);
- fail_unless_equals_int (gst_rtp_buffer_get_seq (buf), 0xF2C9);
+ gst_rtp_buffer_set_seq (&rtp, 0xF2C9);
+ fail_unless_equals_int (gst_rtp_buffer_get_seq (&rtp), 0xF2C9);
fail_unless_equals_int (GST_READ_UINT16_BE (data + 2), 0xF2C9);
- gst_rtp_buffer_set_seq (buf, 0);
- fail_unless_equals_int (gst_rtp_buffer_get_seq (buf), 0);
+ gst_rtp_buffer_set_seq (&rtp, 0);
+ fail_unless_equals_int (gst_rtp_buffer_get_seq (&rtp), 0);
fail_unless_equals_int (GST_READ_UINT16_BE (data + 2), 0);
/* check timestamp offset */
- gst_rtp_buffer_set_timestamp (buf, 432191);
+ gst_rtp_buffer_set_timestamp (&rtp, 432191);
fail_unless_equals_int (GST_READ_UINT32_BE (data + 4), 432191);
- fail_unless_equals_int (gst_rtp_buffer_get_timestamp (buf), 432191);
- gst_rtp_buffer_set_timestamp (buf, 0);
- fail_unless_equals_int (gst_rtp_buffer_get_timestamp (buf), 0);
+ fail_unless_equals_int (gst_rtp_buffer_get_timestamp (&rtp), 432191);
+ gst_rtp_buffer_set_timestamp (&rtp, 0);
+ fail_unless_equals_int (gst_rtp_buffer_get_timestamp (&rtp), 0);
fail_unless_equals_int (GST_READ_UINT32_BE (data + 4), 0);
/* check ssrc offset */
- gst_rtp_buffer_set_ssrc (buf, 0xf04043C2);
- fail_unless_equals_int (gst_rtp_buffer_get_ssrc (buf), (gint) 0xf04043c2);
+ gst_rtp_buffer_set_ssrc (&rtp, 0xf04043C2);
+ fail_unless_equals_int (gst_rtp_buffer_get_ssrc (&rtp), (gint) 0xf04043c2);
fail_unless_equals_int (GST_READ_UINT32_BE (data + 4 + 4), (gint) 0xf04043c2);
- gst_rtp_buffer_set_ssrc (buf, 0);
- fail_unless_equals_int (gst_rtp_buffer_get_ssrc (buf), 0);
+ gst_rtp_buffer_set_ssrc (&rtp, 0);
+ fail_unless_equals_int (gst_rtp_buffer_get_ssrc (&rtp), 0);
fail_unless_equals_int (GST_READ_UINT32_BE (data + 4 + 4), 0);
/* check csrc bits */
- fail_unless_equals_int (gst_rtp_buffer_get_csrc_count (buf), 0);
- ASSERT_CRITICAL (gst_rtp_buffer_get_csrc (buf, 0));
+ fail_unless_equals_int (gst_rtp_buffer_get_csrc_count (&rtp), 0);
+ ASSERT_CRITICAL (gst_rtp_buffer_get_csrc (&rtp, 0));
fail_unless_equals_int (data[0] & 0xf, 0);
+
+ gst_rtp_buffer_unmap (&rtp);
+ gst_buffer_unmap (buf, data, size);
gst_buffer_unref (buf);
/* and again, this time with CSRCs */
buf = gst_rtp_buffer_new_allocate (16, 4, 3);
fail_unless (buf != NULL);
- fail_unless_equals_int (GST_BUFFER_SIZE (buf),
- RTP_HEADER_LEN + 16 + 4 + 4 * 3);
+ data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
+ fail_unless_equals_int (size, RTP_HEADER_LEN + 16 + 4 + 4 * 3);
- data = GST_BUFFER_DATA (buf);
+ gst_rtp_buffer_map (buf, GST_MAP_READWRITE, &rtp);
- fail_unless_equals_int (gst_rtp_buffer_get_csrc_count (buf), 3);
- ASSERT_CRITICAL (gst_rtp_buffer_get_csrc (buf, 3));
+ fail_unless_equals_int (gst_rtp_buffer_get_csrc_count (&rtp), 3);
+ ASSERT_CRITICAL (gst_rtp_buffer_get_csrc (&rtp, 3));
fail_unless_equals_int (data[0] & 0xf, 3);
- fail_unless_equals_int (gst_rtp_buffer_get_csrc (buf, 0), 0);
- fail_unless_equals_int (gst_rtp_buffer_get_csrc (buf, 1), 0);
- fail_unless_equals_int (gst_rtp_buffer_get_csrc (buf, 2), 0);
+ fail_unless_equals_int (gst_rtp_buffer_get_csrc (&rtp, 0), 0);
+ fail_unless_equals_int (gst_rtp_buffer_get_csrc (&rtp, 1), 0);
+ fail_unless_equals_int (gst_rtp_buffer_get_csrc (&rtp, 2), 0);
data += RTP_HEADER_LEN; /* skip the other header stuff */
- gst_rtp_buffer_set_csrc (buf, 0, 0xf7c0);
+ gst_rtp_buffer_set_csrc (&rtp, 0, 0xf7c0);
fail_unless_equals_int (GST_READ_UINT32_BE (data + 0 * 4), 0xf7c0);
- gst_rtp_buffer_set_csrc (buf, 1, 0xf7c1);
+ gst_rtp_buffer_set_csrc (&rtp, 1, 0xf7c1);
fail_unless_equals_int (GST_READ_UINT32_BE (data + 1 * 4), 0xf7c1);
- gst_rtp_buffer_set_csrc (buf, 2, 0xf7c2);
+ gst_rtp_buffer_set_csrc (&rtp, 2, 0xf7c2);
fail_unless_equals_int (GST_READ_UINT32_BE (data + 2 * 4), 0xf7c2);
- ASSERT_CRITICAL (gst_rtp_buffer_set_csrc (buf, 3, 0xf123));
+ ASSERT_CRITICAL (gst_rtp_buffer_set_csrc (&rtp, 3, 0xf123));
+
+ gst_rtp_buffer_unmap (&rtp);
+ gst_buffer_unmap (buf, data, size);
gst_buffer_unref (buf);
}
0xb0, 0x97, 0x63, 0x08, 0x10, 0x4b, 0x43, 0x85, 0x37, 0x2c
};
- buf = gst_buffer_new ();
- GST_BUFFER_DATA (buf) = corrupt_rtp_packet;
- GST_BUFFER_SIZE (buf) = sizeof (corrupt_rtp_packet);
+ buf = gst_buffer_new_and_alloc (sizeof (corrupt_rtp_packet));
+ gst_buffer_fill (buf, 0, corrupt_rtp_packet, sizeof (corrupt_rtp_packet));
fail_if (gst_rtp_buffer_validate (buf));
gst_buffer_unref (buf);
}
GST_END_TEST;
+#if 0
GST_START_TEST (test_rtp_buffer_list)
{
GstBuffer *rtp_header;
}
GST_END_TEST;
+#endif
GST_START_TEST (test_rtp_buffer_set_extension_data)
{
guint8 misc_data[4] = { 1, 2, 3, 4 };
gpointer pointer;
guint8 appbits;
+ gsize bsize;
+ GstRTPBuffer rtp = { NULL, };
/* check GstRTPHeader structure alignment and packing */
buf = gst_rtp_buffer_new_allocate (4, 0, 0);
- data = GST_BUFFER_DATA (buf);
+ data = gst_buffer_map (buf, &bsize, NULL, GST_MAP_READ);
+
+ gst_rtp_buffer_map (buf, GST_MAP_READWRITE, &rtp);
/* should be impossible to set the extension data */
- ASSERT_WARNING (fail_unless (gst_rtp_buffer_set_extension_data (buf, 0,
+ ASSERT_WARNING (fail_unless (gst_rtp_buffer_set_extension_data (&rtp, 0,
4) == FALSE));
- fail_unless (gst_rtp_buffer_get_extension (buf) == FALSE);
+ fail_unless (gst_rtp_buffer_get_extension (&rtp) == FALSE);
/* should be possible to set the extension data */
- fail_unless (gst_rtp_buffer_set_extension_data (buf, 270, 0) == TRUE);
- fail_unless (gst_rtp_buffer_get_extension (buf) == TRUE);
- gst_rtp_buffer_get_extension_data (buf, &bits, &pointer, &size);
+ fail_unless (gst_rtp_buffer_set_extension_data (&rtp, 270, 0) == TRUE);
+ fail_unless (gst_rtp_buffer_get_extension (&rtp) == TRUE);
+ gst_rtp_buffer_get_extension_data (&rtp, &bits, &pointer, &size);
fail_unless (bits == 270);
fail_unless (size == 0);
- fail_unless (pointer == GST_BUFFER_DATA (buf) + 16);
- pointer = gst_rtp_buffer_get_payload (buf);
- fail_unless (pointer == GST_BUFFER_DATA (buf) + 16);
+ fail_unless (pointer == data + 16);
+ pointer = gst_rtp_buffer_get_payload (&rtp);
+ fail_unless (pointer == data + 16);
+
+ gst_buffer_unmap (buf, data, bsize);
+ gst_rtp_buffer_unmap (&rtp);
gst_buffer_unref (buf);
buf = gst_rtp_buffer_new_allocate (20, 0, 0);
- data = GST_BUFFER_DATA (buf);
- fail_unless (gst_rtp_buffer_get_extension (buf) == FALSE);
- fail_unless (gst_rtp_buffer_set_extension_data (buf, 333, 2) == TRUE);
- fail_unless (gst_rtp_buffer_get_extension (buf) == TRUE);
- gst_rtp_buffer_get_extension_data (buf, &bits, &pointer, &size);
+ data = gst_buffer_map (buf, &bsize, NULL, GST_MAP_READ);
+ gst_rtp_buffer_map (buf, GST_MAP_READWRITE, &rtp);
+
+ fail_unless (gst_rtp_buffer_get_extension (&rtp) == FALSE);
+ fail_unless (gst_rtp_buffer_set_extension_data (&rtp, 333, 2) == TRUE);
+ fail_unless (gst_rtp_buffer_get_extension (&rtp) == TRUE);
+ gst_rtp_buffer_get_extension_data (&rtp, &bits, &pointer, &size);
fail_unless (bits == 333);
fail_unless (size == 2);
- fail_unless (pointer == GST_BUFFER_DATA (buf) + 16);
- pointer = gst_rtp_buffer_get_payload (buf);
- fail_unless (pointer == GST_BUFFER_DATA (buf) + 24);
+ fail_unless (pointer == data + 16);
+ pointer = gst_rtp_buffer_get_payload (&rtp);
+ fail_unless (pointer == data + 24);
+
+ gst_buffer_unmap (buf, data, bsize);
+ gst_rtp_buffer_unmap (&rtp);
gst_buffer_unref (buf);
/* Test header extensions with a one byte header */
buf = gst_rtp_buffer_new_allocate (20, 0, 0);
- fail_unless (gst_rtp_buffer_get_extension (buf) == FALSE);
+ data = gst_buffer_map (buf, &bsize, NULL, GST_MAP_READ);
+ gst_rtp_buffer_map (buf, GST_MAP_READWRITE, &rtp);
- fail_unless (gst_rtp_buffer_add_extension_onebyte_header (buf, 5,
+ fail_unless (gst_rtp_buffer_get_extension (&rtp) == FALSE);
+
+ fail_unless (gst_rtp_buffer_add_extension_onebyte_header (&rtp, 5,
misc_data, 2) == TRUE);
- fail_unless (gst_rtp_buffer_get_extension_data (buf, &bits, &pointer, &size));
+ fail_unless (gst_rtp_buffer_get_extension_data (&rtp, &bits, &pointer,
+ &size));
fail_unless (bits == 0xBEDE);
fail_unless (size == 1);
data = (guint8 *) pointer;
fail_unless (data[0] == ((5 << 4) | 1));
- fail_unless (gst_rtp_buffer_get_extension_onebyte_header (buf, 2,
+ fail_unless (gst_rtp_buffer_get_extension_onebyte_header (&rtp, 2,
1, &pointer, &size) == FALSE);
- fail_unless (gst_rtp_buffer_get_extension_onebyte_header (buf, 5,
+ fail_unless (gst_rtp_buffer_get_extension_onebyte_header (&rtp, 5,
1, &pointer, &size) == FALSE);
- fail_unless (gst_rtp_buffer_get_extension_onebyte_header (buf, 5,
+ fail_unless (gst_rtp_buffer_get_extension_onebyte_header (&rtp, 5,
0, &pointer, &size) == TRUE);
fail_unless (size == 2);
fail_unless (memcmp (pointer, misc_data, 2) == 0);
- fail_unless (gst_rtp_buffer_add_extension_onebyte_header (buf, 5,
+ fail_unless (gst_rtp_buffer_add_extension_onebyte_header (&rtp, 5,
misc_data, 4) == TRUE);
- fail_unless (gst_rtp_buffer_get_extension_onebyte_header (buf, 5,
+ fail_unless (gst_rtp_buffer_get_extension_onebyte_header (&rtp, 5,
0, &pointer, &size) == TRUE);
fail_unless (size == 2);
fail_unless (memcmp (pointer, misc_data, 2) == 0);
- fail_unless (gst_rtp_buffer_get_extension_onebyte_header (buf, 5,
+ fail_unless (gst_rtp_buffer_get_extension_onebyte_header (&rtp, 5,
1, &pointer, &size) == TRUE);
fail_unless (size == 4);
fail_unless (memcmp (pointer, misc_data, 4) == 0);
- fail_unless (gst_rtp_buffer_get_extension_onebyte_header (buf, 5,
+ fail_unless (gst_rtp_buffer_get_extension_onebyte_header (&rtp, 5,
2, &pointer, &size) == FALSE);
- fail_unless (gst_rtp_buffer_get_extension_onebyte_header (buf, 2,
+ fail_unless (gst_rtp_buffer_get_extension_onebyte_header (&rtp, 2,
1, &pointer, &size) == FALSE);
- fail_unless (gst_rtp_buffer_add_extension_onebyte_header (buf, 6,
+ fail_unless (gst_rtp_buffer_add_extension_onebyte_header (&rtp, 6,
misc_data, 2) == TRUE);
- fail_unless (gst_rtp_buffer_get_extension_onebyte_header (buf, 5,
+ fail_unless (gst_rtp_buffer_get_extension_onebyte_header (&rtp, 5,
0, &pointer, &size) == TRUE);
fail_unless (size == 2);
fail_unless (memcmp (pointer, misc_data, 2) == 0);
- fail_unless (gst_rtp_buffer_get_extension_onebyte_header (buf, 5,
+ fail_unless (gst_rtp_buffer_get_extension_onebyte_header (&rtp, 5,
1, &pointer, &size) == TRUE);
fail_unless (size == 4);
fail_unless (memcmp (pointer, misc_data, 4) == 0);
- fail_unless (gst_rtp_buffer_get_extension_onebyte_header (buf, 5,
+ fail_unless (gst_rtp_buffer_get_extension_onebyte_header (&rtp, 5,
3, &pointer, &size) == FALSE);
- fail_unless (gst_rtp_buffer_get_extension_onebyte_header (buf, 2,
+ fail_unless (gst_rtp_buffer_get_extension_onebyte_header (&rtp, 2,
1, &pointer, &size) == FALSE);
- fail_unless (gst_rtp_buffer_get_extension_onebyte_header (buf, 6,
+ fail_unless (gst_rtp_buffer_get_extension_onebyte_header (&rtp, 6,
2, &pointer, &size) == FALSE);
- fail_unless (gst_rtp_buffer_get_extension_onebyte_header (buf, 5,
+ fail_unless (gst_rtp_buffer_get_extension_onebyte_header (&rtp, 5,
0, &pointer, &size) == TRUE);
fail_unless (size == 2);
fail_unless (memcmp (pointer, misc_data, 2) == 0);
+
+ gst_buffer_unmap (buf, data, bsize);
+ gst_rtp_buffer_unmap (&rtp);
gst_buffer_unref (buf);
/* Test header extensions with a two bytes header */
buf = gst_rtp_buffer_new_allocate (20, 0, 0);
- fail_unless (gst_rtp_buffer_get_extension (buf) == FALSE);
+ data = gst_buffer_map (buf, &bsize, NULL, GST_MAP_READ);
+ gst_rtp_buffer_map (buf, GST_MAP_READWRITE, &rtp);
+
+ fail_unless (gst_rtp_buffer_get_extension (&rtp) == FALSE);
- fail_unless (gst_rtp_buffer_add_extension_twobytes_header (buf, 0, 5,
+ fail_unless (gst_rtp_buffer_add_extension_twobytes_header (&rtp, 0, 5,
misc_data, 2) == TRUE);
- fail_unless (gst_rtp_buffer_get_extension_data (buf, &bits, &pointer, &size));
+ fail_unless (gst_rtp_buffer_get_extension_data (&rtp, &bits, &pointer,
+ &size));
fail_unless (bits == 0x100 << 4);
fail_unless (size == 1);
data = (guint8 *) pointer;
fail_unless (data[0] == 5);
fail_unless (data[1] == 2);
- fail_unless (gst_rtp_buffer_get_extension_twobytes_header (buf, &appbits, 2,
+ fail_unless (gst_rtp_buffer_get_extension_twobytes_header (&rtp, &appbits, 2,
0, &pointer, &size) == FALSE);
- fail_unless (gst_rtp_buffer_get_extension_twobytes_header (buf, &appbits, 5,
+ fail_unless (gst_rtp_buffer_get_extension_twobytes_header (&rtp, &appbits, 5,
1, &pointer, &size) == FALSE);
- fail_unless (gst_rtp_buffer_get_extension_twobytes_header (buf, &appbits, 5,
+ fail_unless (gst_rtp_buffer_get_extension_twobytes_header (&rtp, &appbits, 5,
0, &pointer, &size) == TRUE);
fail_unless (size == 2);
fail_unless (memcmp (pointer, misc_data, 2) == 0);
- fail_unless (gst_rtp_buffer_add_extension_twobytes_header (buf, 0, 5,
+ fail_unless (gst_rtp_buffer_add_extension_twobytes_header (&rtp, 0, 5,
misc_data, 4) == TRUE);
- fail_unless (gst_rtp_buffer_get_extension_twobytes_header (buf, &appbits, 5,
+ fail_unless (gst_rtp_buffer_get_extension_twobytes_header (&rtp, &appbits, 5,
0, &pointer, &size) == TRUE);
fail_unless (size == 2);
fail_unless (memcmp (pointer, misc_data, 2) == 0);
- fail_unless (gst_rtp_buffer_get_extension_twobytes_header (buf, &appbits, 5,
+ fail_unless (gst_rtp_buffer_get_extension_twobytes_header (&rtp, &appbits, 5,
1, &pointer, &size) == TRUE);
fail_unless (size == 4);
fail_unless (memcmp (pointer, misc_data, 4) == 0);
- fail_unless (gst_rtp_buffer_get_extension_twobytes_header (buf, &appbits, 5,
+ fail_unless (gst_rtp_buffer_get_extension_twobytes_header (&rtp, &appbits, 5,
2, &pointer, &size) == FALSE);
- fail_unless (gst_rtp_buffer_get_extension_twobytes_header (buf, &appbits, 2,
+ fail_unless (gst_rtp_buffer_get_extension_twobytes_header (&rtp, &appbits, 2,
0, &pointer, &size) == FALSE);
- fail_unless (gst_rtp_buffer_add_extension_twobytes_header (buf, 0, 6,
+ fail_unless (gst_rtp_buffer_add_extension_twobytes_header (&rtp, 0, 6,
misc_data, 2) == TRUE);
- fail_unless (gst_rtp_buffer_get_extension_twobytes_header (buf, &appbits, 5,
+ fail_unless (gst_rtp_buffer_get_extension_twobytes_header (&rtp, &appbits, 5,
0, &pointer, &size) == TRUE);
fail_unless (size == 2);
fail_unless (memcmp (pointer, misc_data, 2) == 0);
- fail_unless (gst_rtp_buffer_get_extension_twobytes_header (buf, &appbits, 5,
+ fail_unless (gst_rtp_buffer_get_extension_twobytes_header (&rtp, &appbits, 5,
1, &pointer, &size) == TRUE);
fail_unless (size == 4);
fail_unless (memcmp (pointer, misc_data, 4) == 0);
- fail_unless (gst_rtp_buffer_get_extension_twobytes_header (buf, &appbits, 5,
+ fail_unless (gst_rtp_buffer_get_extension_twobytes_header (&rtp, &appbits, 5,
2, &pointer, &size) == FALSE);
- fail_unless (gst_rtp_buffer_get_extension_twobytes_header (buf, &appbits, 2,
+ fail_unless (gst_rtp_buffer_get_extension_twobytes_header (&rtp, &appbits, 2,
0, &pointer, &size) == FALSE);
- fail_unless (gst_rtp_buffer_get_extension_twobytes_header (buf, &appbits, 6,
+ fail_unless (gst_rtp_buffer_get_extension_twobytes_header (&rtp, &appbits, 6,
1, &pointer, &size) == FALSE);
- fail_unless (gst_rtp_buffer_get_extension_twobytes_header (buf, &appbits, 5,
+ fail_unless (gst_rtp_buffer_get_extension_twobytes_header (&rtp, &appbits, 5,
0, &pointer, &size) == TRUE);
fail_unless (size == 2);
fail_unless (memcmp (pointer, misc_data, 2) == 0);
+
+ gst_buffer_unmap (buf, data, bsize);
+ gst_rtp_buffer_unmap (&rtp);
gst_buffer_unref (buf);
}
GST_END_TEST;
+#if 0
GST_START_TEST (test_rtp_buffer_list_set_extension)
{
GstBufferList *list;
}
GST_END_TEST;
+#endif
GST_START_TEST (test_rtp_seqnum_compare)
{
GstBuffer *buf;
GstRTCPPacket packet;
guint8 *data;
+ gsize size;
+ GstRTCPBuffer rtcp = { NULL, };
buf = gst_rtcp_buffer_new (1400);
fail_unless (buf != NULL);
- fail_unless_equals_int (GST_BUFFER_SIZE (buf), 1400);
- data = GST_BUFFER_DATA (buf);
+ data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
+ fail_unless_equals_int (size, 1400);
+
+ gst_rtcp_buffer_map (buf, GST_MAP_READWRITE, &rtcp);
- fail_unless (gst_rtcp_buffer_get_first_packet (buf, &packet) == FALSE);
- fail_unless (gst_rtcp_buffer_get_packet_count (buf) == 0);
fail_unless (gst_rtcp_buffer_validate (buf) == FALSE);
+ fail_unless (gst_rtcp_buffer_get_first_packet (&rtcp, &packet) == FALSE);
+ fail_unless (gst_rtcp_buffer_get_packet_count (&rtcp) == 0);
/* add an SR packet */
- fail_unless (gst_rtcp_buffer_add_packet (buf, GST_RTCP_TYPE_SR,
+ fail_unless (gst_rtcp_buffer_add_packet (&rtcp, GST_RTCP_TYPE_SR,
&packet) == TRUE);
fail_unless (gst_rtcp_packet_get_padding (&packet) == 0);
}
/* go to first packet, this should be the packet we just added */
- fail_unless (gst_rtcp_buffer_get_first_packet (buf, &packet) == TRUE);
+ fail_unless (gst_rtcp_buffer_get_first_packet (&rtcp, &packet) == TRUE);
fail_unless (gst_rtcp_packet_get_padding (&packet) == 0);
fail_unless (gst_rtcp_packet_get_count (&packet) == 0);
fail_unless (gst_rtcp_packet_move_to_next (&packet) == FALSE);
/* add some SDES */
- fail_unless (gst_rtcp_buffer_add_packet (buf, GST_RTCP_TYPE_SDES,
+ fail_unless (gst_rtcp_buffer_add_packet (&rtcp, GST_RTCP_TYPE_SDES,
&packet) == TRUE);
fail_unless (gst_rtcp_packet_sdes_add_item (&packet, 0xff658743) == TRUE);
fail_unless (gst_rtcp_packet_sdes_add_entry (&packet, GST_RTCP_SDES_CNAME,
sizeof ("test@foo.bar"), (guint8 *) "test@foo.bar") == TRUE);
/* add some BYE */
- fail_unless (gst_rtcp_buffer_add_packet (buf, GST_RTCP_TYPE_BYE,
+ fail_unless (gst_rtcp_buffer_add_packet (&rtcp, GST_RTCP_TYPE_BYE,
&packet) == TRUE);
fail_unless (gst_rtcp_packet_bye_add_ssrc (&packet, 0x5613212f) == TRUE);
fail_unless (gst_rtcp_packet_bye_add_ssrc (&packet, 0x00112233) == TRUE);
fail_unless (gst_rtcp_packet_get_length (&packet) == 2);
/* move to SDES */
- fail_unless (gst_rtcp_buffer_get_first_packet (buf, &packet) == TRUE);
+ fail_unless (gst_rtcp_buffer_get_first_packet (&rtcp, &packet) == TRUE);
fail_unless (gst_rtcp_packet_move_to_next (&packet) == TRUE);
fail_unless (gst_rtcp_packet_get_padding (&packet) == 0);
fail_unless (gst_rtcp_packet_get_length (&packet) == 2);
/* close and validate */
- gst_rtcp_buffer_end (buf);
+ gst_rtcp_buffer_unmap (&rtcp);
fail_unless (gst_rtcp_buffer_validate (buf) == TRUE);
gst_buffer_unref (buf);
}
tcase_add_test (tc_chain, test_rtp_buffer);
tcase_add_test (tc_chain, test_rtp_buffer_validate_corrupt);
tcase_add_test (tc_chain, test_rtp_buffer_set_extension_data);
- tcase_add_test (tc_chain, test_rtp_buffer_list_set_extension);
+ //tcase_add_test (tc_chain, test_rtp_buffer_list_set_extension);
tcase_add_test (tc_chain, test_rtp_seqnum_compare);
tcase_add_test (tc_chain, test_rtcp_buffer);
- tcase_add_test (tc_chain, test_rtp_buffer_list);
+ //tcase_add_test (tc_chain, test_rtp_buffer_list);
return s;
}
GstCheckABIStruct list[] = {
- {"GstAppBufferClass", sizeof (GstAppBufferClass), 16},
- {"GstAppBuffer", sizeof (GstAppBuffer), 88},
{"GstAppSinkCallbacks", sizeof (GstAppSinkCallbacks), 28},
{"GstAppSinkClass", sizeof (GstAppSinkClass), 404},
{"GstAppSink", sizeof (GstAppSink), 404},
{"GstMixerTrack", sizeof (GstMixerTrack), 32},
{"GstNavigationInterface", sizeof (GstNavigationInterface), 28},
{"GstNetAddress", sizeof (GstNetAddress), 40},
- {"GstNetBufferClass", sizeof (GstNetBufferClass), 32},
- {"GstNetBuffer", sizeof (GstNetBuffer), 176},
{"GstPropertyProbeInterface", sizeof (GstPropertyProbeInterface), 44},
{"gst_riff_acid", sizeof (gst_riff_acid), 24},
{"gst_riff_dmlh", sizeof (gst_riff_dmlh), 4},
GstCheckABIStruct list[] = {
- {"GstAppBufferClass", sizeof (GstAppBufferClass), 32},
- {"GstAppBuffer", sizeof (GstAppBuffer), 136},
{"GstAppSinkCallbacks", sizeof (GstAppSinkCallbacks), 56},
{"GstAppSinkClass", sizeof (GstAppSinkClass), 800},
{"GstAppSink", sizeof (GstAppSink), 640},
{"GstMixerTrack", sizeof (GstMixerTrack), 48},
{"GstNavigationInterface", sizeof (GstNavigationInterface), 56},
{"GstNetAddress", sizeof (GstNetAddress), 56},
- {"GstNetBufferClass", sizeof (GstNetBufferClass), 64},
- {"GstNetBuffer", sizeof (GstNetBuffer), 264},
{"GstPropertyProbeInterface", sizeof (GstPropertyProbeInterface), 88},
{"gst_riff_acid", sizeof (gst_riff_acid), 24},
{"gst_riff_dmlh", sizeof (gst_riff_dmlh), 4},
/* now, while we still have a taglist, test _to_vorbiscomment_buffer() */
{
GstBuffer *buf1, *buf2;
+ guint8 *data1, *data2;
+ gsize size1, size2;
ASSERT_CRITICAL (gst_tag_list_to_vorbiscomment_buffer (NULL,
(const guint8 *) "x", 1, "x"));
(const guint8 *) "foo", 3, NULL);
fail_unless (buf2 != NULL);
- fail_unless (memcmp (GST_BUFFER_DATA (buf1), GST_BUFFER_DATA (buf2) + 3,
- GST_BUFFER_SIZE (buf1)) == 0);
+ data1 = gst_buffer_map (buf1, &size1, NULL, GST_MAP_READ);
+ data2 = gst_buffer_map (buf2, &size2, NULL, GST_MAP_READ);
+
+ fail_unless (memcmp (data1, data2 + 3, size1) == 0);
+
+ gst_buffer_unmap (buf2, data2, size2);
+ gst_buffer_unmap (buf1, data1, size1);
gst_buffer_unref (buf1);
gst_buffer_unref (buf2);
gchar *vendor = NULL;
buf = gst_buffer_new ();
- GST_BUFFER_DATA (buf) = (guint8 *) speex_comments_buf1;
- GST_BUFFER_SIZE (buf) = sizeof (speex_comments_buf1);
+ gst_buffer_take_memory (buf,
+ gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
+ (gpointer) speex_comments_buf1, NULL,
+ sizeof (speex_comments_buf1), 0, sizeof (speex_comments_buf1)));
/* make sure it doesn't memcmp over the end of the buffer */
fail_unless (gst_tag_list_from_vorbiscomment_buffer (buf,
gchar *vendor = NULL;
buf = gst_buffer_new ();
- GST_BUFFER_DATA (buf) = (guint8 *) vorbis_comments_buf;
- GST_BUFFER_SIZE (buf) = sizeof (vorbis_comments_buf);
+ gst_buffer_take_memory (buf,
+ gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
+ (gpointer) vorbis_comments_buf, NULL,
+ sizeof (vorbis_comments_buf), 0, sizeof (vorbis_comments_buf)));
/* make sure it doesn't memcmp over the end of the buffer */
fail_unless (gst_tag_list_from_vorbiscomment_buffer (buf,
GstTagList *list;
GstBuffer *buf;
const gchar *text;
- guint len;
+ gsize len;
/* test data */
list = gst_tag_list_new_full (GST_TAG_TITLE, "test title",
buf = gst_tag_list_to_xmp_buffer (list, FALSE);
fail_unless (buf != NULL);
- text = (const gchar *) GST_BUFFER_DATA (buf);
- len = GST_BUFFER_SIZE (buf);
+ text = gst_buffer_map (buf, &len, NULL, GST_MAP_READ);
/* check the content */
fail_unless (g_strrstr_len (text, len, "<?xpacket begin") == text);
fail_unless (g_strrstr_len (text, len, ">keyword1<") != NULL);
fail_unless (g_strrstr_len (text, len, ">keyword2<") != NULL);
fail_unless (g_strrstr_len (text, len, "<?xpacket end") != NULL);
+ gst_buffer_unmap (buf, (gpointer) text, len);
gst_buffer_unref (buf);
gst_tag_list_free (list);
};
/* test data */
- buf = gst_buffer_new ();
-
i = 0;
while (test_data[i].xmp_data) {
+ gsize len;
+
GST_DEBUG ("trying test-data %u", i);
text = g_strconcat (xmp_header, test_data[i].xmp_data, xmp_footer, NULL);
- GST_BUFFER_DATA (buf) = (guint8 *) text;
- GST_BUFFER_SIZE (buf) = strlen (text) + 1;
+ buf = gst_buffer_new ();
+ len = strlen (text) + 1;
+ gst_buffer_take_memory (buf,
+ gst_memory_new_wrapped (0, text, NULL, len, 0, len));
list = gst_tag_list_from_xmp_buffer (buf);
if (test_data[i].result_size >= 0) {
if (list)
gst_tag_list_free (list);
+ gst_buffer_unref (buf);
g_free (text);
i++;
}
-
- gst_buffer_unref (buf);
}
GST_END_TEST;
GstBuffer *buf = NULL;
gint i;
GstTagList *taglist;
+ guint8 *data;
gst_tag_register_musicbrainz_tags ();
g_value_init (&value, GST_TYPE_BUFFER);
buf = gst_buffer_new_and_alloc (1024);
+ data = gst_buffer_map (buf, NULL, NULL, GST_MAP_WRITE);
for (i = 0; i < 1024; i++)
- GST_BUFFER_DATA (buf)[i] = i % 255;
+ data[i] = i % 255;
+ gst_buffer_unmap (buf, data, 1024);
gst_value_set_buffer (&value, buf);
gst_buffer_unref (buf);
do_simple_exif_tag_serialization_deserialization (GST_TAG_APPLICATION_DATA,
guint8 *data;
from_buffer = gst_buffer_new_and_alloc (640 * 480 * 4);
- data = GST_BUFFER_DATA (from_buffer);
+ data = gst_buffer_map (from_buffer, NULL, NULL, GST_MAP_WRITE);
for (i = 0; i < 640 * 480; i++) {
data[4 * i + 0] = 0; /* x */
data[4 * i + 1] = 255; /* R */
data[4 * i + 2] = 0; /* G */
data[4 * i + 3] = 0; /* B */
}
+ gst_buffer_unmap (from_buffer, data, 640 * 480 * 4);
+
from_caps = gst_video_format_new_caps (GST_VIDEO_FORMAT_xRGB,
640, 480, 25, 1, 1, 1);
gst_buffer_set_caps (from_buffer, from_caps);
ConvertFrameContext cf_data = { NULL, NULL, NULL };
from_buffer = gst_buffer_new_and_alloc (640 * 480 * 4);
- data = GST_BUFFER_DATA (from_buffer);
+ data = gst_buffer_map (from_buffer, NULL, NULL, GST_MAP_WRITE);
for (i = 0; i < 640 * 480; i++) {
data[4 * i + 0] = 0; /* x */
data[4 * i + 1] = 255; /* R */
data[4 * i + 2] = 0; /* G */
data[4 * i + 3] = 0; /* B */
}
+ gst_buffer_unmap (from_buffer, data, 640 * 480 * 4);
+
from_caps = gst_video_format_new_caps (GST_VIDEO_FORMAT_xRGB,
640, 480, 25, 1, 1, 1);
gst_buffer_set_caps (from_buffer, from_caps);
static void init_interface (GType type);
-GST_BOILERPLATE_FULL (TestElement, test_element, GstElement, GST_TYPE_ELEMENT,
- init_interface);
+G_DEFINE_TYPE_WITH_CODE (TestElement, test_element, GST_TYPE_ELEMENT,
+ init_interface (g_define_type_id));
static void
init_interface (GType type)
}
static void
-test_element_base_init (gpointer klass)
-{
-}
-
-static void
test_element_class_init (TestElementClass * klass)
{
}
static void
-test_element_init (TestElement * this, TestElementClass * klass)
+test_element_init (TestElement * this)
{
}
static gboolean
gst_buffer_equals (GstBuffer * buf_a, GstBuffer * buf_b)
{
- if (GST_BUFFER_SIZE (buf_a) != GST_BUFFER_SIZE (buf_b))
- return FALSE;
+ gboolean res;
+ gpointer data1, data2;
+ gsize size1, size2;
+
+ data1 = gst_buffer_map (buf_a, &size1, NULL, GST_MAP_READ);
+ data2 = gst_buffer_map (buf_b, &size2, NULL, GST_MAP_READ);
+
+ if (size1 == size2) {
+ res = memcmp (data1, data2, size1) == 0;
+ } else {
+ res = FALSE;
+ }
+ gst_buffer_unmap (buf_a, data1, size1);
+ gst_buffer_unmap (buf_b, data2, size2);
- return memcmp (GST_BUFFER_DATA (buf_a), GST_BUFFER_DATA (buf_b),
- GST_BUFFER_SIZE (buf_a)) == 0;
+ return res;
}
static GstTagList *
return TRUE;
}
-GST_START_TEST (test_capsfilter_renegotiation)
+/* launch line is a pipeline that must have a capsfilter named 'cf' that
+ * will be used to trigger the renegotiation */
+static void
+run_capsfilter_renegotiation (const gchar * launch_line)
{
GstElement *capsfilter;
GstElement *sink;
gst_caps_unref (current_caps);
current_caps = NULL;
- pipeline = gst_parse_launch ("videotestsrc num-buffers=200 ! capsfilter "
- "caps=\"" FIRST_CAPS "\" name=cf ! fakesink name=sink", NULL);
+ pipeline = gst_parse_launch (launch_line, NULL);
g_assert (pipeline);
capsfilter = gst_bin_get_by_name (GST_BIN (pipeline), "cf");
GST_MESSAGE_EOS | GST_MESSAGE_ERROR);
g_assert (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_EOS);
-
g_assert (caps_change == 4);
gst_element_set_state (pipeline, GST_STATE_NULL);
if (current_caps)
gst_caps_unref (current_caps);
+ current_caps = NULL;
gst_message_unref (msg);
g_object_unref (bus);
g_object_unref (G_OBJECT (pipeline));
}
+GST_START_TEST (test_capsfilter_renegotiation)
+{
+ run_capsfilter_renegotiation ("videotestsrc num-buffers=200 peer-alloc=true"
+ " ! capsfilter caps=\"" FIRST_CAPS "\" name=cf ! fakesink name=sink");
+ run_capsfilter_renegotiation ("videotestsrc num-buffers=200 peer-alloc=false"
+ " ! capsfilter caps=\"" FIRST_CAPS "\" name=cf ! fakesink name=sink");
+ run_capsfilter_renegotiation ("videotestsrc num-buffers=200 peer-alloc=false"
+ " ! capsfilter caps=\"video/x-raw-yuv, format=(fourcc)I420, width=(int)100, height=(int)100\" "
+ " ! ffmpegcolorspace ! videoscale ! capsfilter caps=\"" FIRST_CAPS
+ "\" name=cf " " ! fakesink name=sink");
+}
+
GST_END_TEST;
static Suite *
{
gint ret;
gint size;
- guint8 *data;
gchar *oggbuffer;
ChainState *state = NULL;
gboolean has_video = FALSE;
- size = GST_BUFFER_SIZE (buffer);
- data = GST_BUFFER_DATA (buffer);
+ size = gst_buffer_get_size (buffer);
oggbuffer = ogg_sync_buffer (&oggsync, size);
- memcpy (oggbuffer, data, size);
+ gst_buffer_extract (buffer, 0, oggbuffer, size);
ogg_sync_wrote (&oggsync, size);
do {
static gboolean
buffer_probe_cb (GstPad * pad, GstBuffer * buffer)
{
+ guint8 *data;
+ gsize size;
+
+ data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
+
if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_IN_CAPS)) {
GstCaps *caps;
GstStructure *s;
for (i = 0; i < 3; ++i) {
GValue *val;
+ guint8 *data2;
+ gsize size2;
val = &g_array_index (buffers, GValue, i);
buf = g_value_peek_pointer (val);
fail_unless (GST_IS_BUFFER (buf));
- if (GST_BUFFER_SIZE (buf) == GST_BUFFER_SIZE (buffer)) {
- if (memcmp (GST_BUFFER_DATA (buf), GST_BUFFER_DATA (buffer),
- GST_BUFFER_SIZE (buffer)) == 0) {
+
+ data2 = gst_buffer_map (buf, &size2, NULL, GST_MAP_READ);
+ if (size2 == size) {
+ if (memcmp (data2, data, size) == 0) {
found = TRUE;
}
}
+ gst_buffer_unmap (buf, data2, size2);
}
fail_unless (found, "Did not find incoming IN_CAPS buffer %p on caps",
buffer);
gst_caps_unref (caps);
}
+ gst_buffer_unmap (buffer, data, size);
return TRUE;
}
static gboolean
drop_second_data_buffer (GstPad * droppad, GstBuffer * buffer, gpointer unused)
{
- return !(GST_BUFFER_OFFSET (buffer) == 1024);
+ gboolean res;
+
+ res = !(GST_BUFFER_OFFSET (buffer) == 1024);
+ GST_DEBUG ("dropping %d", res);
+
+ return res;
}
GST_START_TEST (test_discontinuity)
* samples (because of the overlap/add), so it won't increment the
* granulepos, which should be 2048 after the discontinuity.
*/
+ fail_unless (GST_BUFFER_IS_DISCONT (buffer),
+ "expected discontinuous buffer");
fail_unless (GST_BUFFER_OFFSET_END (buffer) == 2048,
"expected granulepos after gap: %" G_GUINT64_FORMAT,
GST_BUFFER_OFFSET_END (buffer));
- fail_unless (GST_BUFFER_IS_DISCONT (buffer),
- "expected discontinuous buffer");
gst_buffer_unref (buffer);
}
#include <gst/app/gstappsrc.h>
#include <gst/app/gstappsink.h>
-#include <gst/app/gstappbuffer.h>
/* these are the caps we are going to pass through the appsink and appsrc */
const gchar *audio_caps =
on_new_buffer_from_source (GstElement * elt, ProgramData * data)
{
guint size;
- gpointer raw_buffer;
GstBuffer *app_buffer, *buffer;
GstElement *source;
/* turn it into an app buffer, it's not really needed, we could simply push
* the retrieved buffer from appsink into appsrc just fine. */
- size = GST_BUFFER_SIZE (buffer);
+ size = gst_buffer_get_size (buffer);
g_print ("Pushing a buffer of size %d\n", size);
- raw_buffer = g_malloc0 (size);
- memcpy (raw_buffer, GST_BUFFER_DATA (buffer), size);
- app_buffer = gst_app_buffer_new (raw_buffer, size, g_free, raw_buffer);
+ app_buffer = gst_buffer_new_and_alloc (size);
- /* newer basesrc will set caps for use automatically but it does not really
- * hurt to set it on the buffer again */
- gst_buffer_set_caps (app_buffer, GST_BUFFER_CAPS (buffer));
+ gst_buffer_copy_into (app_buffer, buffer, GST_BUFFER_COPY_MEMORY, 0, size);
/* we don't need the appsink buffer anymore */
gst_buffer_unref (buffer);
if (app->offset + size > app->length)
size = app->length - app->offset;
- GST_BUFFER_DATA (buffer) = app->data + app->offset;
- GST_BUFFER_SIZE (buffer) = size;
+ gst_buffer_take_memory (buffer,
+ gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
+ app->data, NULL, app->length, app->offset, size));
+
/* we need to set an offset for random access */
GST_BUFFER_OFFSET (buffer) = app->offset;
GST_BUFFER_OFFSET_END (buffer) = app->offset + size;
if (app->offset + len > app->length)
len = app->length - app->offset;
- GST_BUFFER_DATA (buffer) = app->data + app->offset;
- GST_BUFFER_SIZE (buffer) = len;
+ gst_buffer_take_memory (buffer,
+ gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
+ app->data, NULL, app->length, app->offset, len));
GST_DEBUG ("feed buffer %p, offset %" G_GUINT64_FORMAT "-%u", buffer,
app->offset, len);
if (app->offset + len > app->length)
len = app->length - app->offset;
- GST_BUFFER_DATA (buffer) = app->data + app->offset;
- GST_BUFFER_SIZE (buffer) = len;
+ gst_buffer_take_memory (buffer,
+ gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
+ app->data, NULL, app->length, app->offset, len));
GST_DEBUG ("feed buffer %p, offset %" G_GUINT64_FORMAT "-%u", buffer,
app->offset, len);
if (app->offset + len > app->length)
len = app->length - app->offset;
- GST_BUFFER_DATA (buffer) = app->data + app->offset;
- GST_BUFFER_SIZE (buffer) = len;
+ gst_buffer_take_memory (buffer,
+ gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
+ app->data, NULL, app->length, app->offset, len));
GST_DEBUG ("feed buffer %p, offset %" G_GUINT64_FORMAT "-%u", buffer,
app->offset, len);
#include <gst/gst.h>
#include <gst/app/gstappsrc.h>
-#include <gst/app/gstappbuffer.h>
#include <gst/app/gstappsink.h>
#include <stdio.h>
App s_app;
-static void dont_eat_my_chicken_wings (void *priv);
-
int
main (int argc, char *argv[])
{
GstBuffer *buf;
void *data;
- data = malloc (100);
+ buf = gst_buffer_new_and_alloc (100);
+ data = gst_buffer_map (buf, NULL, NULL, GST_MAP_WRITE);
memset (data, i, 100);
+ gst_buffer_unmap (buf, data, 100);
- buf = gst_app_buffer_new (data, 100, dont_eat_my_chicken_wings, data);
- printf ("%d: creating buffer for pointer %p, %p\n", i, data, buf);
+ printf ("%d: pushing buffer for pointer %p, %p\n", i, data, buf);
gst_app_src_push_buffer (GST_APP_SRC (app->src), buf);
}
return 0;
}
-
-static void
-dont_eat_my_chicken_wings (void *priv)
-{
- printf ("freeing buffer for pointer %p\n", priv);
- free (priv);
-}
GstCaps *caps;
/* Ask encodebin for a compatible pad */
- caps = gst_pad_get_caps (pad);
+ caps = gst_pad_get_caps (pad, NULL);
g_signal_emit_by_name (encodebin, "request-pad", caps, &sinkpad);
if (caps)
gst_caps_unref (caps);
if (strcmp (name, "not-mounted") == 0) {
GMountOperation *mop = gtk_mount_operation_new (NULL);
GFile *file =
- G_FILE (g_value_get_object (gst_structure_get_value
- (message->structure, "file")));
+ G_FILE (g_value_get_object (gst_structure_get_value (s, "file")));
g_print ("not-mounted\n");
gst_element_set_state (pipeline, GST_STATE_NULL);
gint width, height;
GdkPixbuf *pixbuf;
GError *error = NULL;
+ gsize size;
+ guint8 *data;
/* get the snapshot buffer format now. We set the caps on the appsink so
* that it can only be an rgb buffer. The only thing we have not specified
* on the caps is the height, which is dependant on the pixel-aspect-ratio
* of the source material */
+#if 0
caps = GST_BUFFER_CAPS (buffer);
+#endif
+ /* FIXME, get the caps on the buffer somehow */
+ caps = NULL;
if (!caps) {
g_warning ("could not get snapshot format\n");
goto done;
/* create pixmap from buffer and save, gstreamer video buffers have a stride
* that is rounded up to the nearest multiple of 4 */
- pixbuf = gdk_pixbuf_new_from_data (GST_BUFFER_DATA (buffer),
+ data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
+ pixbuf = gdk_pixbuf_new_from_data (data,
GDK_COLORSPACE_RGB, FALSE, 8, width, height,
GST_ROUND_UP_4 (width * 3), NULL, NULL);
/* save the pixbuf */
gdk_pixbuf_save (pixbuf, "snapshot.png", "png", &error, NULL);
+ gst_buffer_unmap (buffer, data, size);
+
+ /* save the pixbuf */
+ gdk_pixbuf_save (pixbuf, "snapshot.png", "png", &error, NULL);
done:
gst_buffer_unref (buffer);
bus_sync_handler (GstBus * bus, GstMessage * message, GstPipeline * data)
{
if ((GST_MESSAGE_TYPE (message) == GST_MESSAGE_ELEMENT) &&
- gst_structure_has_name (message->structure, "prepare-xwindow-id")) {
+ gst_message_has_name (message, "prepare-xwindow-id")) {
GstElement *element = GST_ELEMENT (GST_MESSAGE_SRC (message));
g_print ("got prepare-xwindow-id, setting XID %lu\n", embed_xid);
gint width, height;
GdkPixbuf *pixbuf;
GError *error = NULL;
+ guint8 *data;
+ gsize size;
/* get the snapshot buffer format now. We set the caps on the appsink so
* that it can only be an rgb buffer. The only thing we have not specified
* on the caps is the height, which is dependant on the pixel-aspect-ratio
* of the source material */
+#if 0
caps = GST_BUFFER_CAPS (buffer);
+#endif
+ /* FIXME, need to get the caps of the buffer somehow */
+ caps = NULL;
if (!caps) {
g_warning ("could not get snapshot format\n");
goto done;
/* create pixmap from buffer and save, gstreamer video buffers have a stride
* that is rounded up to the nearest multiple of 4 */
- pixbuf = gdk_pixbuf_new_from_data (GST_BUFFER_DATA (buffer),
+ data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
+ pixbuf = gdk_pixbuf_new_from_data (data,
GDK_COLORSPACE_RGB, FALSE, 8, width, height,
GST_ROUND_UP_4 (width * 3), NULL, NULL);
/* save the pixbuf */
gdk_pixbuf_save (pixbuf, "snapshot.png", "png", &error, NULL);
+ gst_buffer_unmap (buffer, data, size);
done:
gst_buffer_unref (buffer);
bus_sync_handler (GstBus * bus, GstMessage * message, GstPipeline * data)
{
if ((GST_MESSAGE_TYPE (message) == GST_MESSAGE_ELEMENT) &&
- gst_structure_has_name (message->structure, "prepare-xwindow-id")) {
+ gst_message_has_name (message, "prepare-xwindow-id")) {
GstElement *element = GST_ELEMENT (GST_MESSAGE_SRC (message));
g_print ("got prepare-xwindow-id, setting XID %lu\n", embed_xid);
GstFormat format;
GstStateChangeReturn ret;
gboolean res;
+ guint8 *data;
+ gsize size;
gst_init (&argc, &argv);
* that it can only be an rgb buffer. The only thing we have not specified
* on the caps is the height, which is dependant on the pixel-aspect-ratio
* of the source material */
+#if 0
caps = GST_BUFFER_CAPS (buffer);
+#endif
+ /* FIXME, get buffer caps somehow */
+ caps = NULL;
if (!caps) {
g_print ("could not get snapshot format\n");
exit (-1);
/* create pixmap from buffer and save, gstreamer video buffers have a stride
* that is rounded up to the nearest multiple of 4 */
- pixbuf = gdk_pixbuf_new_from_data (GST_BUFFER_DATA (buffer),
+ data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
+ pixbuf = gdk_pixbuf_new_from_data (data,
GDK_COLORSPACE_RGB, FALSE, 8, width, height,
GST_ROUND_UP_4 (width * 3), NULL, NULL);
/* save the pixbuf */
gdk_pixbuf_save (pixbuf, "snapshot.png", "png", &error, NULL);
+ gst_buffer_unmap (buffer, data, size);
+
+ /* save the pixbuf */
+ gdk_pixbuf_save (pixbuf, "snapshot.png", "png", &error, NULL);
} else {
g_print ("could not make snapshot\n");
}
GstPadLinkReturn lret;
/* check media type */
- caps = gst_pad_get_caps (pad);
+ caps = gst_pad_get_caps (pad, NULL);
str = gst_caps_get_structure (caps, 0);
name = gst_structure_get_name (str);
dump_element_stats (GstElement * element)
{
GstIterator *it;
- gpointer data;
+ GValue data = { 0, };
it = gst_element_iterate_src_pads (element);
while (gst_iterator_next (it, &data) == GST_ITERATOR_OK) {
- GstPad *pad = GST_PAD (data);
+ GstPad *pad = g_value_get_object (&data);
GstCaps *caps;
gchar *str;
GstQuery *query;
g_print ("stream %s:\n", GST_OBJECT_NAME (pad));
- caps = gst_pad_get_caps (pad);
+ caps = gst_pad_get_caps (pad, NULL);
str = gst_caps_to_string (caps);
g_print (" caps: %s\n", str);
g_free (str);
}
gst_query_unref (query);
- gst_object_unref (pad);
+ g_value_reset (&data);
}
+ g_value_unset (&data);
gst_iterator_free (it);
}
GstStateChangeReturn res;
GstIterator *it;
GstBus *bus;
- gpointer data;
+ GValue data = { 0, };
gst_init (&argc, &argv);
it = gst_element_iterate_src_pads (decodebin);
while (gst_iterator_next (it, &data) == GST_ITERATOR_OK) {
- GstPad *pad = GST_PAD (data);
+ GstPad *pad = g_value_get_object (&data);
GstCaps *caps;
gchar *str;
GstQuery *query;
g_print ("stream %s:\n", GST_OBJECT_NAME (pad));
- caps = gst_pad_get_caps (pad);
+ caps = gst_pad_get_caps (pad, NULL);
str = gst_caps_to_string (caps);
g_print (" caps: %s\n", str);
g_free (str);
}
gst_query_unref (query);
- gst_object_unref (pad);
+ g_value_reset (&data);
}
+ g_value_unset (&data);
gst_iterator_free (it);
return 0;
if (buffer) {
guint8 *data;
- guint size;
+ gsize size;
GstFormat format;
gint64 position;
GstClock *clock;
", running_time %" GST_TIME_FORMAT, GST_TIME_ARGS (position),
GST_TIME_ARGS (running_time));
- data = GST_BUFFER_DATA (buffer);
- size = GST_BUFFER_SIZE (buffer);
-
+ data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
gst_util_dump_mem (data, size);
+ gst_buffer_unmap (buffer, data, size);
}
}
ser = g_value_dup_string (value);
else if (GST_VALUE_HOLDS_BUFFER (value)) {
GstBuffer *buf = gst_value_get_buffer (value);
- ser = g_strdup_printf ("<GstBuffer [%d bytes]>", GST_BUFFER_SIZE (buf));
+ ser =
+ g_strdup_printf ("<GstBuffer [%" G_GSIZE_FORMAT " bytes]>",
+ gst_buffer_get_size (buf));
} else
ser = gst_value_serialize (value);
EXPORTS
- gst_app_buffer_get_type
- gst_app_buffer_new
gst_app_sink_get_caps
gst_app_sink_get_drop
gst_app_sink_get_emit_signals
EXPORTS
+ gst_meta_net_address_get_info
gst_netaddress_equal
gst_netaddress_get_address_bytes
gst_netaddress_get_ip4_address
gst_netaddress_set_ip4_address
gst_netaddress_set_ip6_address
gst_netaddress_to_string
- gst_netbuffer_get_type
- gst_netbuffer_new
gst_basertppayload_set_options
gst_basertppayload_set_outcaps
gst_rtcp_buffer_add_packet
- gst_rtcp_buffer_end
gst_rtcp_buffer_get_first_packet
gst_rtcp_buffer_get_packet_count
+ gst_rtcp_buffer_map
gst_rtcp_buffer_new
gst_rtcp_buffer_new_copy_data
gst_rtcp_buffer_new_take_data
+ gst_rtcp_buffer_unmap
gst_rtcp_buffer_validate
gst_rtcp_buffer_validate_data
gst_rtcp_ntp_to_unix
gst_rtp_buffer_get_ssrc
gst_rtp_buffer_get_timestamp
gst_rtp_buffer_get_version
- gst_rtp_buffer_list_add_extension_onebyte_header
- gst_rtp_buffer_list_add_extension_twobytes_header
- gst_rtp_buffer_list_from_buffer
- gst_rtp_buffer_list_get_extension_onebyte_header
- gst_rtp_buffer_list_get_extension_twobytes_header
- gst_rtp_buffer_list_get_payload_len
- gst_rtp_buffer_list_get_payload_type
- gst_rtp_buffer_list_get_seq
- gst_rtp_buffer_list_get_ssrc
- gst_rtp_buffer_list_get_timestamp
- gst_rtp_buffer_list_set_payload_type
- gst_rtp_buffer_list_set_seq
- gst_rtp_buffer_list_set_ssrc
- gst_rtp_buffer_list_set_timestamp
- gst_rtp_buffer_list_validate
+ gst_rtp_buffer_map
gst_rtp_buffer_new_allocate
gst_rtp_buffer_new_allocate_len
gst_rtp_buffer_new_copy_data
gst_rtp_buffer_set_ssrc
gst_rtp_buffer_set_timestamp
gst_rtp_buffer_set_version
+ gst_rtp_buffer_unmap
gst_rtp_buffer_validate
gst_rtp_buffer_validate_data
gst_rtp_payload_info_for_name
gst_tag_list_add_id3_image
gst_tag_list_from_exif_buffer
gst_tag_list_from_exif_buffer_with_tiff_header
+ gst_tag_list_from_vorbiscomment
gst_tag_list_from_vorbiscomment_buffer
gst_tag_list_from_xmp_buffer
gst_tag_list_new_from_id3v1
EXPORTS
+ gst_buffer_add_meta_video
+ gst_buffer_add_meta_video_full
+ gst_meta_video_get_info
+ gst_meta_video_map
+ gst_meta_video_unmap
gst_video_calculate_display_ratio
gst_video_convert_frame
gst_video_convert_frame_async